Compare commits
4 Commits
pipeline-b
...
pipeline-l
| Author | SHA1 | Date | |
|---|---|---|---|
| fb473dcf1a | |||
| 10c5bb5a8a | |||
| 3eba1f962b | |||
| 6f990e645d |
Binary file not shown.
|
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 169 KiB |
BIN
backend_service/src/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
backend_service/src/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
backend_service/src/__pycache__/main.cpython-312.pyc
Normal file
BIN
backend_service/src/__pycache__/main.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,8 +1,8 @@
|
||||
你是一个严格的任务分类器。只输出一个JSON对象,不要输出解释或多余文本。
|
||||
根据用户指令与下述可用节点定义,判断其为“简单”或“复杂”。
|
||||
|
||||
- 简单:单一原子动作即可完成(例如“起飞”“飞机自检”“移动到某地(已给定坐标)”“对着某点环绕XY圈(如‘对着学生宿舍环绕三十两圈’)”等),且无需行为树与安全并行监控。
|
||||
- 复杂:需要多步流程、搜索/检测/跟踪/评估、战损确认、或需要模板化任务结构与安全并行监控。
|
||||
- 简单:单一原子动作即可完成(例如"起飞""飞机自检""移动到某地(已给定坐标)""对着某点环绕XY圈(如'对着学生宿舍环绕三十两圈')"等),且无需行为树。
|
||||
- 复杂:需要多步流程、搜索/检测/跟踪/评估、战损确认、或需要模板化任务结构。
|
||||
|
||||
输出格式(严格遵守):
|
||||
{"mode":"simple"} 或 {"mode":"complex"}
|
||||
@@ -14,11 +14,11 @@
|
||||
{"name": "takeoff"}, {"name": "land"}, {"name": "fly_to_waypoint"}, {"name": "move_direction"}, {"name": "orbit_around_point"}, {"name": "orbit_around_target"}, {"name": "loiter"},
|
||||
{"name": "object_detect"}, {"name": "strike_target"}, {"name": "battle_damage_assessment"},
|
||||
{"name": "search_pattern"}, {"name": "track_object"}, {"name": "deliver_payload"},
|
||||
{"name": "preflight_checks"}, {"name": "emergency_return"}
|
||||
{"name": "preflight_checks"}, {"name": "take_picture"}
|
||||
],
|
||||
"conditions": [
|
||||
{"name": "battery_above"}, {"name": "at_waypoint"}, {"name": "object_detected"},
|
||||
{"name": "target_destroyed"}, {"name": "time_elapsed"}, {"name": "gps_status"}
|
||||
{"name": "at_waypoint"}, {"name": "object_detected"},
|
||||
{"name": "target_destroyed"}, {"name": "time_elapsed"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -18,7 +18,11 @@
|
||||
{"name": "takeoff", "description": "无人机从当前位置垂直起飞到指定的海拔高度。", "params": {"altitude": "float, 目标海拔高度(米),范围[1, 100],默认为2"}},
|
||||
{"name": "land", "description": "降落无人机。可选择当前位置或返航点降落。", "params": {"mode": "string, 可选值: 'current'(当前位置), 'home'(返航点)"}},
|
||||
{"name": "fly_to_waypoint", "description": "导航至一个指定坐标点。使用相对坐标系(x,y,z),单位为米。", "params": {"x": "float", "y": "float", "z": "float", "acceptance_radius": "float, 可选,默认2.0"}},
|
||||
{"name": "move_direction", "description": "按指定方向直线移动。方向可为绝对方位或相对机体朝向。", "params": {"direction": "string: north|south|east|west|forward|backward|left|right", "distance": "float[1,10000], 可选, 不指定则持续移动"}},
|
||||
{"name": "move_direction", "description": "按指定方向直线移动。方向可为绝对方位或相对机体朝向。", "params": {"direction": "string: north|south|east|west|forward|backward|left|right", "distance": "float[1,10000], 可选, 不指定则持续移动", "speed": "float, 可选"}},
|
||||
{"name": "approach_target", "description": "快速趋近目标至固定距离。", "params": {"target_class": "string, 要趋近的目标类别", "description": "string, 可选", "stop_distance": "float, 期望的最终停止距离", "speed": "float, 可选"}},
|
||||
{"name": "rotate", "description": "旋转固定角度。", "params": {"angle": "float, 旋转角度(正数逆时针, 负数顺时针)", "angular_velocity": "rad/s, 旋转角速度"}},
|
||||
{"name": "rotate_search", "description": "原地旋转搜索目标。", "params": {"target_class": "string, 要搜寻的目标类别", "description": "string, 可选", "step_angle": "float, 可选, 每一步旋转的角度", "total_rotation": "float, 可选, 总共旋转搜索的角度"}},
|
||||
{"name": "manual_confirmation", "description": "前端弹窗是否继续执行后续任务。", "params": {}},
|
||||
{"name": "orbit_around_point", "description": "以给定中心点为中心,等速圆周飞行指定圈数。", "params": {"center_x": "float", "center_y": "float", "center_z": "float", "radius": "float[5,1000]", "laps": "int[1,20]", "clockwise": "boolean, 可选, 默认true", "speed_mps": "float[0.5,15], 可选", "gimbal_lock": "boolean, 可选, 默认true"}},
|
||||
{"name": "orbit_around_target", "description": "以目标为中心,等速圆周飞行指定圈数(需已有目标)。", "params": {"target_class": "string, 取值同object_detect列表", "description": "string, 可选", "radius": "float[5,1000]", "laps": "int[1,20]", "clockwise": "boolean, 可选, 默认true", "speed_mps": "float[0.5,15], 可选", "gimbal_lock": "boolean, 可选, 默认true"}},
|
||||
{"name": "loiter", "description": "在当前位置上空悬停一段时间或直到条件触发。", "params": {"duration": "float, 可选[1,600]", "until_condition": "string, 可选"}},
|
||||
@@ -29,15 +33,13 @@
|
||||
{"name": "track_object", "description": "持续跟踪目标。", "params": {"target_class": "string, 取值同object_detect列表", "description": "string, 可选", "track_time": "float[1,600], 默认30.0", "min_confidence": "float[0.5-1.0], 默认0.7", "safe_distance": "float[2-50], 默认10.0"}},
|
||||
{"name": "deliver_payload", "description": "投放物资。", "params": {"payload_type": "string", "release_altitude": "float[2,100], 默认5.0"}},
|
||||
{"name": "preflight_checks", "description": "飞行前系统自检。", "params": {"check_level": "string: basic|comprehensive"}},
|
||||
{"name": "emergency_return", "description": "执行紧急返航程序。", "params": {"reason": "string"}}
|
||||
{"name": "take_picture", "description": "使用机载相机拍摄照片。", "params": {}}
|
||||
],
|
||||
"conditions": [
|
||||
{"name": "battery_above", "description": "电池电量高于阈值。", "params": {"threshold": "float[0.0,1.0]"}},
|
||||
{"name": "at_waypoint", "description": "在指定坐标容差范围内。", "params": {"x": "float", "y": "float", "z": "float", "tolerance": "float, 可选, 默认3.0"}},
|
||||
{"name": "object_detected", "description": "检测到特定目标。", "params": {"target_class": "string", "description": "string, 可选", "count": "int, 可选, 默认1"}},
|
||||
{"name": "target_destroyed", "description": "目标已被摧毁。", "params": {"target_class": "string", "description": "string, 可选", "confidence": "float[0.5-1.0], 默认0.8"}},
|
||||
{"name": "time_elapsed", "description": "时间经过。", "params": {"duration": "float[1,2700]"}},
|
||||
{"name": "gps_status", "description": "GPS状态良好。", "params": {"min_satellites": "int[6,15], 默认10"}}
|
||||
{"name": "time_elapsed", "description": "时间经过。", "params": {"duration": "float[1,2700]"}}
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -58,4 +60,4 @@
|
||||
- “环绕X米Y圈” → 若有目标上下文则使用 `orbit_around_target`,否则根据是否给出中心坐标选择 `orbit_around_point`;`radius=X`,`laps=Y`,默认 `clockwise=true`,`gimbal_lock=true`
|
||||
- “顺时针/逆时针” → `clockwise=true/false`
|
||||
- “等速” → 若未给速度则 `speed_mps` 采用默认值(例如3.0);若口令指明速度,裁剪到[0.5,15]
|
||||
- “以(x,y,z)为中心”/“当前位置为中心” → 选择 `orbit_around_point` 并填充 `center_x/center_y/center_z`
|
||||
- “以(x,y,z)为中心”/“当前位置为中心” → 选择 `orbit_around_point` 并填充 `center_x/center_y/center_z`
|
||||
|
||||
@@ -9,21 +9,23 @@
|
||||
{"name":"takeoff","params":{"altitude":"float[1,100],默认2"}},
|
||||
{"name":"land","params":{"mode":"'current'/'home'"}},
|
||||
{"name":"fly_to_waypoint","params":{"x":"±10000","y":"±10000","z":"[1,5000]","acceptance_radius":"默认2.0"}},
|
||||
{"name":"move_direction","params":{"direction":"north/south/east/west/forward/backward/left/right","distance":"[1,10000],缺省持续移动"}},
|
||||
{"name":"orbit_around_point","params":{"center_x":"±10000","center_y":"±10000","center_z":"[1,5000]","radius":"[5,1000]","laps":"[1,20]","clockwise":"默认true","speed_mps":"[0.5,15]","gimbal_lock":"默认true"}},
|
||||
{"name":"orbit_around_target","params":{"target_class":"见object_detect列表","description":"可选,目标属性","radius":"[5,1000]","laps":"[1,20]","clockwise":"默认true","speed_mps":"[0.5,15]","gimbal_lock":"默认true"}},
|
||||
{"name":"move_direction","params":{"direction":"north/south/east/west/forward/backward/left/right","distance":"[1,10000],缺省持续移动","speed":"float,可选"}},
|
||||
{"name":"approach_target","params":{"target_class":"string,要趋近的目标类别","description":"string,可选,目标属性描述","stop_distance":"float,期望的最终停止距离","speed":"float,可选,期望的逼近速度"}},
|
||||
{"name":"rotate","params":{"angle":"float,无人机自身旋转角度(正数逆时针,负数顺时针)","angular_velocity":"rad/s,旋转角速度"}},
|
||||
{"name":"rotate_search","params":{"target_class":"string,要搜寻的目标类别","description":"string,可选,目标属性描述","step_angle":"float,可选,每一步旋转的角度","total_rotation":"float,可选,总共旋转搜索的角度"}},
|
||||
{"name":"manual_confirmation","params":{}},
|
||||
{"name":"loiter","params":{"duration":"[1,600]秒/until_condition:可选"}},
|
||||
{"name":"object_detect","params":{"target_class":"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush","description":"可选,","count":"默认1"}},
|
||||
{"name":"object_detect","params":{"target_class":"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage","description":"可选,","count":"默认1"}},
|
||||
{"name":"strike_target","params":{"target_class":"同object_detect","description":"可选,目标属性","count":"默认1"}},
|
||||
{"name":"battle_damage_assessment","params":{"target_class":"同object_detect","assessment_time":"[5,60],默认15"}},
|
||||
{"name":"search_pattern","params":{"pattern_type":"spiral/grid","center_x":"±10000","center_y":"±10000","center_z":"[1,5000]","radius":"[5,1000]","target_class":"同object_detect","description":"可选,目标属性","count":"默认1"}},
|
||||
{"name":"track_object","params":{"target_class":"同object_detect","description":"可选,目标属性","track_time":"[1,600]秒(必传,不可用'duration')","min_confidence":"[0.5,1.0]默认0.7","safe_distance":"[2,50]默认10"}},
|
||||
{"name":"deliver_payload","params":{"payload_type":"string","release_altitude":"[2,100]默认5"}},
|
||||
{"name":"preflight_checks","params":{"check_level":"basic/comprehensive"}},
|
||||
{"name":"emergency_return","params":{"reason":"string"}}
|
||||
{"name":"emergency_return","params":{"reason":"string"}},
|
||||
{"name":"take_photos","params":{"target_class":"同object_detect","description":"可选,目标属性","track_time":"[1,600]秒(必传,不可用'duration')","min_confidence":"[0.5,1.0]默认0.7","safe_distance":"[2,50]默认10"}}
|
||||
],
|
||||
"conditions": [
|
||||
{"name":"battery_above","params":{"threshold":"[0.0,1.0],必传"}},
|
||||
{"name":"at_waypoint","params":{"x":"±10000","y":"±10000","z":"[1,5000]","tolerance":"默认3.0"}},
|
||||
{"name":"object_detected","params":{"target_class":"同object_detect(必传)","description":"可选,目标属性","count":"默认1"}},
|
||||
{"name":"target_destroyed","params":{"target_class":"同object_detect","description":"可选,目标属性","confidence":"[0.5,1.0]默认0.8"}},
|
||||
@@ -34,6 +36,9 @@
|
||||
{"name":"Sequence","params":{},"children":"子节点数组(按序执行,全成功则成功)"},
|
||||
{"name":"Selector","params":{"memory":"默认true"},"children":"子节点数组(执行到成功为止)"},
|
||||
{"name":"Parallel","params":{"policy":"all_success"},"children":"子节点数组(同时执行,严禁用'one_success')"}
|
||||
],
|
||||
"decorators": [
|
||||
{"name":"SuccessIsFailure","params":{},"child":"单一子节点(将子节点的成功结果反转为失败)"}
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -42,53 +47,61 @@
|
||||
## 二、节点必填字段(后端Schema强制要求,缺一验证失败)
|
||||
每个节点必须包含以下字段,字段名/类型不可自定义:
|
||||
1. **`type`**:
|
||||
- 动作节点→`"action"`,条件节点→`"condition"`,控制流节点→`"Sequence"`/`"Selector"`/`"Parallel"`(与`name`字段值完全一致);
|
||||
2. **`name`**:必须是上述JSON中`actions`/`conditions`/`control_flow`下的`name`值(如“gps_status”不可错写为“gps_check”);
|
||||
3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数(如优先级排序不可加“priority”字段,仅用`description`);
|
||||
4. **`children`**:仅控制流节点必含(子节点数组),动作/条件节点无此字段。
|
||||
- 动作节点→`"action"`,条件节点→`"condition"`,控制流节点→`"Sequence"`/`"Selector"`/`"Parallel"`,装饰器节点→`"decorator"`;
|
||||
2. **`name`**:必须是上述JSON中定义的`name`值;
|
||||
3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;
|
||||
4. **`children`**:仅控制流节点必含(子节点数组);
|
||||
5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。
|
||||
|
||||
|
||||
## 三、行为树固定结构(通用不变,确保安全验证)
|
||||
根节点必须是`Parallel`,`children`含`MainTask`(Sequence)和`SafetyMonitor`(Selector),结构不随任务类型(含优先级排序)修改:
|
||||
## 三、标准任务结构模板(单次起降流程)
|
||||
大多数任务应遵循“起飞 -> 接近 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:
|
||||
```json
|
||||
{
|
||||
"root": {
|
||||
"type": "Parallel",
|
||||
"name": "MissionWithSafety",
|
||||
"params": {"policy": "all_success"},
|
||||
"type": "Sequence",
|
||||
"name": "MainTask",
|
||||
"children": [
|
||||
{
|
||||
"type": "Sequence",
|
||||
"name": "MainTask",
|
||||
"params": {},
|
||||
"children": [
|
||||
// 通用主任务步骤(含优先级排序任务示例,需按用户指令替换):
|
||||
{"type":"action","name":"preflight_checks","params":{"check_level":"comprehensive"}},
|
||||
{"type":"action","name":"takeoff","params":{"altitude":10.0}},
|
||||
{"type":"action","name":"fly_to_waypoint","params":{"x":200.0,"y":150.0,"z":10.0}}, // 搜索区坐标(用户未给时填合理值)
|
||||
{"type":"action","name":"search_pattern","params":{"pattern_type":"grid","center_x":200.0,"center_y":150.0,"center_z":10.0,"radius":50.0,"target_class":"balloon","description":"红色"}},
|
||||
{"type":"condition","name":"object_detected","params":{"target_class":"balloon","description":"红色"}}, // 确认高优先级目标
|
||||
{"type":"action","name":"track_object","params":{"target_class":"balloon","description":"红色","track_time":30.0}},
|
||||
{"type":"action","name":"strike_target","params":{"target_class":"balloon","description":"红色"}},
|
||||
{"type":"action","name":"land","params":{"mode":"home"}}
|
||||
]
|
||||
},
|
||||
{"type":"action","name":"preflight_checks","params":{"check_level":"comprehensive"}},
|
||||
{"type":"action","name":"takeoff","params":{"altitude":10.0}},
|
||||
{"type":"action","name":"fly_to_waypoint","params":{"x":100.0,"y":50.0,"z":10.0}}, // 接近目标区域
|
||||
// --- 核心任务区 (根据指令替换) ---
|
||||
{"type":"action","name":"rotate_search","params":{"target_class":"person","description":"目标描述"}},
|
||||
{"type":"action","name":"object_detect","params":{"target_class":"person","description":"目标描述"}},
|
||||
// -------------------------------
|
||||
// 默认不需要降落节点,除非用户明确要求
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 四、场景示例(请灵活参考)
|
||||
|
||||
#### 场景 1:线性搜索任务(Sequence + Selector)
|
||||
**指令**:“去研究所正大门,搜索扎辫子女子并拍照。”
|
||||
**结构**:Sequence (按顺序执行)
|
||||
```json
|
||||
{
|
||||
"root": {
|
||||
"type": "Sequence",
|
||||
"name": "MainSearchTask",
|
||||
"children": [
|
||||
{"type":"action","name":"takeoff","params":{"altitude":10.0}},
|
||||
{"type":"action","name":"fly_to_waypoint","params":{"x":100.0,"y":50.0,"z":10.0}},
|
||||
{"type":"action","name":"rotate_search","params":{"target_class":"person","description":"扎辫子女子"}},
|
||||
{
|
||||
"type": "Selector",
|
||||
"name": "SafetyMonitor",
|
||||
"params": {"memory": true},
|
||||
"name": "CheckAndPhoto",
|
||||
"children": [
|
||||
{"type":"condition","name":"battery_above","params":{"threshold":0.3}},
|
||||
{"type":"condition","name":"gps_status","params":{"min_satellites":8}},
|
||||
{
|
||||
"type":"Sequence",
|
||||
"name":"EmergencyHandler",
|
||||
"params": {},
|
||||
"type": "Sequence",
|
||||
"name": "PhotoIfFound",
|
||||
"children": [
|
||||
{"type":"action","name":"emergency_return","params":{"reason":"safety_breach"}},
|
||||
{"type":"action","name":"land","params":{"mode":"home"}}
|
||||
{"type":"condition","name":"object_detected","params":{"target_class":"person","description":"扎辫子女子"}},
|
||||
{"type":"action","name":"take_photos","params":{"target_class":"person","description":"扎辫子女子","track_time":10.0}}
|
||||
]
|
||||
}
|
||||
},
|
||||
{"type":"action","name":"loiter","params":{"duration":5.0}} // 未发现时的备选动作
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -96,22 +109,178 @@
|
||||
}
|
||||
```
|
||||
|
||||
#### 场景 2:带中断逻辑的巡逻(Selector 示例)
|
||||
**指令**:“飞往航点A。如果途中发现可疑人员,则悬停。”
|
||||
**结构**:
|
||||
```json
|
||||
{
|
||||
"root": {
|
||||
"type": "Sequence",
|
||||
"children": [
|
||||
{"type":"action","name":"takeoff","params":{"altitude":10.0}},
|
||||
{
|
||||
"type": "Selector",
|
||||
"name": "FlyOrDetect",
|
||||
"children": [
|
||||
{
|
||||
"type": "Sequence",
|
||||
"name": "InterruptionLogic",
|
||||
"children": [
|
||||
{"type":"action","name":"object_detect","params":{"target_class":"person"}},
|
||||
{"type":"action","name":"loiter","params":{"duration":5.0}}
|
||||
]
|
||||
},
|
||||
{"type":"action","name":"fly_to_waypoint","params":{"x":100.0,"y":50.0,"z":10.0}}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 四、优先级排序任务通用示例
|
||||
当用户指令中明确提出有多个待考察且具有优先级关系的物体时,节点描述须为优先级关系。比如当指令为已知有三个气球,危险级关系为红色气球大于蓝色气球大于绿色气球,要求优先跟踪最危险的气球时,节点的描述参考下表情形。
|
||||
| 用户指令场景 | `target_class` | `description` | 核心节点示例(search_pattern) |
|
||||
|-----------------------------|-----------------|-------------------------|------------------------------------------------------------------------------------------------|
|
||||
| 红气球>蓝气球>绿气球 | `balloon` | `(红>蓝>绿)` | `{"type":"action","name":"search_pattern","params":{"pattern_type":"grid","center_x":200,"center_y":150,"center_z":10,"radius":50,"target_class":"balloon","description":"(红>蓝>绿)"}}` |
|
||||
| 军用卡车>民用卡车>面包车 | `truck` | `(军用卡车>民用卡车>面包车)` | `{"type":"action","name":"object_detect","params":{"target_class":"truck","description":"(军用卡车>民用卡车>面包车)"}}` |
|
||||
#### 场景 3:环绕侦察类任务
|
||||
**指令**:“去面前的大楼三层/12米高,绕着外围看有没有打开的窗户,发现则进行拍照。”
|
||||
**参考知识**:{"text": "面前的大楼外围四个点坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。"}
|
||||
**结构**:Sequence (按顺序执行)
|
||||
```json
|
||||
{
|
||||
"root": {
|
||||
"type": "Sequence",
|
||||
"name": "SurroundAndInspect",
|
||||
"children": [
|
||||
{"type":"action","name":"takeoff","params":{"altitude":12.0}},
|
||||
// 移动到A点,并在此过程中持续检测
|
||||
{
|
||||
"type": "Parallel",
|
||||
"name": "FlyAndInspectToA",
|
||||
"children": [
|
||||
{"type":"action","name":"fly_to_waypoint","params":{"x":-24.0,"y":241.8,"z":12.0}},
|
||||
{
|
||||
"type": "Selector",
|
||||
"name": "OpportunisticPhoto",
|
||||
"children": [
|
||||
{
|
||||
"type": "decorator",
|
||||
"name": "SuccessIsFailure",
|
||||
"child": {
|
||||
"type": "Sequence",
|
||||
"name": "DetectAndCapture",
|
||||
"children": [
|
||||
{"type":"action","name":"object_detect","params":{"target_class":"window","description":"open window"}},
|
||||
{"type":"condition","name":"object_detected","params":{"target_class":"window","description":"open window"}},
|
||||
{"type":"action","name":"take_photos","params":{"target_class":"window","description":"open window","track_time":5.0}}
|
||||
]
|
||||
}
|
||||
},
|
||||
{"type":"action","name":"loiter","params":{"duration":0.1}} // 占位动作
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
// 移动到B点...
|
||||
{
|
||||
"type": "Parallel",
|
||||
"name": "FlyAndInspectToB",
|
||||
"children": [
|
||||
{"type":"action","name":"fly_to_waypoint","params":{"x":-108.5,"y":241.8,"z":12.0}},
|
||||
{
|
||||
"type": "Selector",
|
||||
"name": "OpportunisticPhoto",
|
||||
"children": [
|
||||
{
|
||||
"type": "decorator",
|
||||
"name": "SuccessIsFailure",
|
||||
"child": {
|
||||
"type": "Sequence",
|
||||
"name": "DetectAndCapture",
|
||||
"children": [
|
||||
{"type":"action","name":"object_detect","params":{"target_class":"window","description":"open window"}},
|
||||
{"type":"condition","name":"object_detected","params":{"target_class":"window","description":"open window"}},
|
||||
{"type":"action","name":"take_photos","params":{"target_class":"window","description":"open window","track_time":5.0}}
|
||||
]
|
||||
}
|
||||
},
|
||||
{"type":"action","name":"loiter","params":{"duration":0.1}}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
// 移动到C点...
|
||||
{
|
||||
"type": "Parallel",
|
||||
"name": "FlyAndInspectToC",
|
||||
"children": [
|
||||
{"type":"action","name":"fly_to_waypoint","params":{"x":-108.5,"y":289.8,"z":12.0}},
|
||||
{
|
||||
"type": "Selector",
|
||||
"name": "OpportunisticPhoto",
|
||||
"children": [
|
||||
{
|
||||
"type": "decorator",
|
||||
"name": "SuccessIsFailure",
|
||||
"child": {
|
||||
"type": "Sequence",
|
||||
"name": "DetectAndCapture",
|
||||
"children": [
|
||||
{"type":"action","name":"object_detect","params":{"target_class":"window","description":"open window"}},
|
||||
{"type":"condition","name":"object_detected","params":{"target_class":"window","description":"open window"}},
|
||||
{"type":"action","name":"take_photos","params":{"target_class":"window","description":"open window","track_time":5.0}}
|
||||
]
|
||||
}
|
||||
},
|
||||
{"type":"action","name":"loiter","params":{"duration":0.1}}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
// 移动到D点...
|
||||
{
|
||||
"type": "Parallel",
|
||||
"name": "FlyAndInspectToD",
|
||||
"children": [
|
||||
{"type":"action","name":"fly_to_waypoint","params":{"x":-24.0,"y":292.8,"z":12.0}},
|
||||
{
|
||||
"type": "Selector",
|
||||
"name": "OpportunisticPhoto",
|
||||
"children": [
|
||||
{
|
||||
"type": "decorator",
|
||||
"name": "SuccessIsFailure",
|
||||
"child": {
|
||||
"type": "Sequence",
|
||||
"name": "DetectAndCapture",
|
||||
"children": [
|
||||
{"type":"action","name":"object_detect","params":{"target_class":"window","description":"open window"}},
|
||||
{"type":"condition","name":"object_detected","params":{"target_class":"window","description":"open window"}},
|
||||
{"type":"action","name":"take_photos","params":{"target_class":"window","description":"open window","track_time":5.0}}
|
||||
]
|
||||
}
|
||||
},
|
||||
{"type":"action","name":"loiter","params":{"duration":0.1}}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 五、优先级排序任务通用示例
|
||||
当用户指令中明确提出有多个待考察且具有优先级关系的物体时,节点描述须为优先级关系。
|
||||
| 用户指令场景 | `target_class` | `description` |
|
||||
|-----------------------------|-----------------|-------------------------|
|
||||
| 红气球>蓝气球>绿气球 | `balloon` | `(红>蓝>绿)` |
|
||||
| 军用卡车>民用卡车>面包车 | `truck` | `(军用卡车>民用卡车>面包车)` |
|
||||
|
||||
## 五、高频错误规避(确保验证通过)
|
||||
1. 优先级排序不可修改`target_class`:如“民用卡车、面包车与军用卡车中,军用卡车优先”,`target_class`仍为`truck`,仅用`description`填排序规则;
|
||||
2. 在没有明确指出物体之间的优先级关系情况下,`description`字段只描述物体属性本身,严禁与用户指令中不存在的物体进行排序;
|
||||
3. `track_object`必传`track_time`:不可用`duration`替代(如跟踪30秒填`"track_time":30.0`);
|
||||
4. `gps_status`的`min_satellites`必须在6-15之间(如8,不可缺省);
|
||||
5. 无自定义节点:“锁定高优先级目标”需通过`object_detect`+`object_detected`实现,不可用“lock_high_risk_target”。
|
||||
## 六、高频错误规避
|
||||
1. 优先级排序不可修改`target_class`,仅用`description`填排序规则;
|
||||
2. `track_object`必传`track_time`;
|
||||
3. `gps_status`的`min_satellites`必须在6-15之间;
|
||||
4. 严禁输出 markdown 代码块标记,直接输出 JSON 纯文本;
|
||||
5. 控制流节点的 `type` 必须是 `"Sequence"`, `"Selector"` 或 `"Parallel"`;
|
||||
6. rotate与rotate_search动作节点意思是无人机以自身为原点旋转,而非围绕外部点旋转
|
||||
7. 当用户指令中要求执行动作前增加人工确认时,比如“我确认后拍照”,则必须在拍照动作前增加manual_confirmation节点
|
||||
|
||||
|
||||
## 六、输出要求
|
||||
仅输出1个严格符合上述所有规则的JSON对象,**确保:1. 优先级排序逻辑正确填入`description`;2. `target_class`匹配预定义列表;3. 行为树结构不变;4. 后端解析与Schema验证无错误**,无任何冗余内容。
|
||||
## 七、输出要求
|
||||
仅输出1个严格符合上述所有规则的JSON对象。
|
||||
|
||||
@@ -52,7 +52,7 @@ def _parse_allowed_nodes_from_prompt(prompt_text: str) -> tuple[Set[str], Set[st
|
||||
"""
|
||||
try:
|
||||
# 使用更精确的正则表达式匹配节点定义部分
|
||||
node_section_pattern = r"#### 2\. 可用节点定义.*?```json\s*({.*?})\s*```"
|
||||
node_section_pattern = r"#### 1\. 可用节点定义.*?```json\s*({.*?})\s*```"
|
||||
match = re.search(node_section_pattern, prompt_text, re.DOTALL | re.IGNORECASE)
|
||||
|
||||
if not match:
|
||||
@@ -144,51 +144,12 @@ def _fallback_parse_nodes(prompt_text: str) -> tuple[Set[str], Set[str]]:
|
||||
logging.error("在所有JSON代码块中都没有找到有效的节点定义结构。")
|
||||
return set(), set()
|
||||
|
||||
def _find_nodes_by_name(node: Dict, target_name: str) -> List[Dict]:
|
||||
"""递归查找所有指定名称的节点"""
|
||||
nodes_found = []
|
||||
|
||||
if node.get("name") == target_name:
|
||||
nodes_found.append(node)
|
||||
|
||||
# 递归搜索子节点
|
||||
for child in node.get("children", []):
|
||||
nodes_found.extend(_find_nodes_by_name(child, target_name))
|
||||
|
||||
return nodes_found
|
||||
|
||||
def _validate_safety_monitoring(pytree_instance: dict) -> bool:
|
||||
"""验证行为树是否包含必要的安全监控"""
|
||||
root_node = pytree_instance.get("root", {})
|
||||
|
||||
# 查找所有电池监控节点
|
||||
battery_nodes = _find_nodes_by_name(root_node, "battery_above")
|
||||
|
||||
# 检查是否包含安全监控结构
|
||||
safety_monitors = _find_nodes_by_name(root_node, "SafetyMonitor")
|
||||
|
||||
if not battery_nodes and not safety_monitors:
|
||||
logging.warning("⚠️ 安全警告: 行为树中没有发现电池监控节点或安全监控器")
|
||||
return False
|
||||
|
||||
# 检查电池阈值设置是否合理
|
||||
for battery_node in battery_nodes:
|
||||
threshold = battery_node.get("params", {}).get("threshold")
|
||||
if threshold is not None:
|
||||
if threshold < 0.25:
|
||||
logging.warning(f"⚠️ 安全警告: 电池阈值设置过低 ({threshold}),建议不低于0.25")
|
||||
elif threshold > 0.5:
|
||||
logging.warning(f"⚠️ 安全警告: 电池阈值设置过高 ({threshold}),可能影响任务执行")
|
||||
|
||||
logging.info("✅ 安全监控验证通过")
|
||||
return True
|
||||
|
||||
def _generate_pytree_schema(allowed_actions: set, allowed_conditions: set) -> dict:
|
||||
"""
|
||||
根据允许的行动和条件节点,动态生成一个JSON Schema。
|
||||
"""
|
||||
# 所有可能的节点类型
|
||||
node_types = ["action", "condition", "Sequence", "Selector", "Parallel"]
|
||||
node_types = ["action", "condition", "Sequence", "Selector", "Parallel", "decorator"]
|
||||
|
||||
# 目标检测相关的类别枚举
|
||||
target_classes = [
|
||||
@@ -201,38 +162,44 @@ def _generate_pytree_schema(allowed_actions: set, allowed_conditions: set) -> di
|
||||
"sandwich", "orange", "broccoli", "carrot", "hot_dog", "pizza", "donut", "cake", "chair",
|
||||
"couch", "potted_plant", "bed", "dining_table", "toilet", "tv", "laptop", "mouse", "remote",
|
||||
"keyboard", "cell_phone", "microwave", "oven", "toaster", "sink", "refrigerator", "book",
|
||||
"clock", "vase", "scissors", "teddy_bear", "hair_drier", "toothbrush","balloon"
|
||||
"clock", "vase", "scissors", "teddy_bear", "hair_drier", "toothbrush","balloon","trash","window","garbage"
|
||||
]
|
||||
|
||||
# 递归节点定义
|
||||
node_definition = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {"type": "string", "enum": node_types},
|
||||
# 修改:手动构造不区分大小写的正则,避免使用不支持的 (?i) 标志
|
||||
# 匹配: action, condition, sequence, selector, parallel, decorator (忽略大小写)
|
||||
"type": {
|
||||
"type": "string",
|
||||
"pattern": "^([Aa][Cc][Tt][Ii][Oo][Nn]|[Cc][Oo][Nn][Dd][Ii][Tt][Ii][Oo][Nn]|[Ss][Ee][Qq][Uu][Ee][Nn][Cc][Ee]|[Ss][Ee][Ll][Ee][Cc][Tt][Oo][Rr]|[Pp][Aa][Rr][Aa][Ll][Ll][Ee][Ll]|[Dd][Ee][Cc][Oo][Rr][Aa][Tt][Oo][Rr])$"
|
||||
},
|
||||
"name": {"type": "string"},
|
||||
"params": {"type": "object"},
|
||||
"children": {
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/definitions/node"}
|
||||
}
|
||||
},
|
||||
"child": {"$ref": "#/definitions/node"}
|
||||
},
|
||||
"required": ["type", "name"],
|
||||
"allOf": [
|
||||
# 动作节点验证
|
||||
# 动作节点验证 (忽略大小写)
|
||||
{
|
||||
"if": {"properties": {"type": {"const": "action"}}},
|
||||
"if": {"properties": {"type": {"pattern": "^[Aa][Cc][Tt][Ii][Oo][Nn]$"}}},
|
||||
"then": {"properties": {"name": {"enum": sorted(list(allowed_actions))}}}
|
||||
},
|
||||
# 条件节点验证
|
||||
# 条件节点验证 (忽略大小写)
|
||||
{
|
||||
"if": {"properties": {"type": {"const": "condition"}}},
|
||||
"if": {"properties": {"type": {"pattern": "^[Cc][Oo][Nn][Dd][Ii][Tt][Ii][Oo][Nn]$"}}},
|
||||
"then": {"properties": {"name": {"enum": sorted(list(allowed_conditions))}}}
|
||||
},
|
||||
# 目标检测动作节点的参数验证
|
||||
# 目标检测动作节点的参数验证 (忽略大小写)
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"type": {"const": "action"},
|
||||
"type": {"pattern": "^[Aa][Cc][Tt][Ii][Oo][Nn]$"},
|
||||
"name": {"const": "object_detect"}
|
||||
}
|
||||
},
|
||||
@@ -251,11 +218,11 @@ def _generate_pytree_schema(allowed_actions: set, allowed_conditions: set) -> di
|
||||
}
|
||||
}
|
||||
},
|
||||
# 目标检测条件节点的参数验证
|
||||
# 目标检测条件节点的参数验证 (忽略大小写)
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"type": {"const": "condition"},
|
||||
"type": {"pattern": "^[Cc][Oo][Nn][Dd][Ii][Tt][Ii][Oo][Nn]$"},
|
||||
"name": {"const": "object_detected"}
|
||||
}
|
||||
},
|
||||
@@ -274,11 +241,11 @@ def _generate_pytree_schema(allowed_actions: set, allowed_conditions: set) -> di
|
||||
}
|
||||
}
|
||||
},
|
||||
# 电池监控节点的参数验证
|
||||
# 电池监控节点的参数验证 (忽略大小写)
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"type": {"const": "condition"},
|
||||
"type": {"pattern": "^[Cc][Oo][Nn][Dd][Ii][Tt][Ii][Oo][Nn]$"},
|
||||
"name": {"const": "battery_above"}
|
||||
}
|
||||
},
|
||||
@@ -295,11 +262,11 @@ def _generate_pytree_schema(allowed_actions: set, allowed_conditions: set) -> di
|
||||
}
|
||||
}
|
||||
},
|
||||
# GPS状态节点的参数验证
|
||||
# GPS状态节点的参数验证 (忽略大小写)
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"type": {"const": "condition"},
|
||||
"type": {"pattern": "^[Cc][Oo][Nn][Dd][Ii][Tt][Ii][Oo][Nn]$"},
|
||||
"name": {"const": "gps_status"}
|
||||
}
|
||||
},
|
||||
@@ -372,10 +339,7 @@ def _validate_pytree_with_schema(pytree_instance: dict, schema: dict) -> bool:
|
||||
jsonschema.validate(instance=pytree_instance, schema=schema)
|
||||
logging.info("✅ JSON Schema验证成功")
|
||||
|
||||
# 额外验证安全监控
|
||||
safety_valid = _validate_safety_monitoring(pytree_instance)
|
||||
|
||||
return True and safety_valid
|
||||
return True
|
||||
except jsonschema.ValidationError as e:
|
||||
logging.warning("❌ Pytree验证失败")
|
||||
logging.warning(f"错误信息: {e.message}")
|
||||
@@ -503,6 +467,10 @@ def _add_nodes_and_edges(node: dict, dot, parent_id: str | None = None) -> str:
|
||||
shape = 'ellipse'
|
||||
style = 'filled'
|
||||
fillcolor = '#e1d5e7' # 紫色
|
||||
elif node_type == 'decorator':
|
||||
shape = 'doubleoctagon'
|
||||
style = 'filled'
|
||||
fillcolor = '#f8cecc' # 浅红
|
||||
|
||||
# 特别标记安全相关节点
|
||||
if node.get('name') in ['battery_above', 'gps_status', 'SafetyMonitor']:
|
||||
@@ -515,28 +483,33 @@ def _add_nodes_and_edges(node: dict, dot, parent_id: str | None = None) -> str:
|
||||
if parent_id:
|
||||
dot.edge(parent_id, current_id)
|
||||
|
||||
# 递归处理子节点
|
||||
# 递归处理子节点 (Sequence, Selector, Parallel 等)
|
||||
children = node.get("children", [])
|
||||
if not children:
|
||||
return current_id
|
||||
|
||||
# 记录所有子节点的ID
|
||||
child_ids = []
|
||||
|
||||
# 正确的递归连接:每个子节点都连接到当前节点
|
||||
for child in children:
|
||||
child_id = _add_nodes_and_edges(child, dot, current_id)
|
||||
child_ids.append(child_id)
|
||||
|
||||
# 子节点同级排列(横向排布,更直观地表现同层)
|
||||
if len(child_ids) > 1:
|
||||
with dot.subgraph(name=f"rank_{current_id}") as s:
|
||||
s.attr(rank='same')
|
||||
for cid in child_ids:
|
||||
s.node(cid)
|
||||
|
||||
# 行为树中,所有类型的节点都只是父连子,不需要子节点间的额外连接
|
||||
# Sequence、Selector、Parallel 的执行逻辑由行为树引擎处理,不需要在可视化中体现
|
||||
# 兼容 decorator 类型的 child 字段 (处理为单元素列表以便统一逻辑)
|
||||
if node_type == 'decorator' and 'child' in node:
|
||||
children = [node['child']]
|
||||
|
||||
if children:
|
||||
# 记录所有子节点的ID
|
||||
child_ids = []
|
||||
|
||||
# 正确的递归连接:每个子节点都连接到当前节点
|
||||
for child in children:
|
||||
child_id = _add_nodes_and_edges(child, dot, current_id)
|
||||
child_ids.append(child_id)
|
||||
|
||||
# 子节点同级排列(横向排布,更直观地表现同层)
|
||||
if len(child_ids) > 1:
|
||||
with dot.subgraph(name=f"rank_{current_id}") as s:
|
||||
s.attr(rank='same')
|
||||
for cid in child_ids:
|
||||
s.node(cid)
|
||||
|
||||
# 递归处理单子节点 (Decorator) - 已合并到 children 处理逻辑中,此处删除旧逻辑
|
||||
# child = node.get("child")
|
||||
# if child:
|
||||
# _add_nodes_and_edges(child, dot, current_id)
|
||||
|
||||
return current_id
|
||||
|
||||
@@ -588,7 +561,7 @@ class PyTreeGenerator:
|
||||
self.complex_llm_client = openai.OpenAI(api_key=self.api_key, base_url=self.complex_base_url)
|
||||
|
||||
# --- ChromaDB Client Setup ---
|
||||
vector_store_path = os.path.abspath(os.path.join(self.base_dir, '..', '..', 'tools', 'vector_store'))
|
||||
vector_store_path = os.path.abspath(os.path.join(self.base_dir, '..', '..', 'tools', 'rag','vector_store'))
|
||||
self.chroma_client = chromadb.PersistentClient(path=vector_store_path)
|
||||
|
||||
# Explicitly use the remote embedding function for queries
|
||||
@@ -725,7 +698,7 @@ class PyTreeGenerator:
|
||||
pytree_str = combined_text if combined_text else (msg_content or "")
|
||||
raw_full_text_for_logging = pytree_str # 保存完整原文(含 <think>)以便失败时完整打印
|
||||
|
||||
# 提取 <think> 推理链内容(若存在)
|
||||
# 提取 <think> 推理链内容(若有)
|
||||
reasoning_text = None
|
||||
try:
|
||||
think_match = re.search(r"<think>([\s\S]*?)</think>", pytree_str)
|
||||
@@ -827,49 +800,7 @@ class PyTreeGenerator:
|
||||
pytree_dict['final_prompt'] = final_prompt
|
||||
return pytree_dict
|
||||
|
||||
# 复杂模式回退:若模型误返回简单结构(root是单个action),则自动包装为含安全监控的行为树
|
||||
if mode == "complex" and isinstance(pytree_dict, dict) and 'root' in pytree_dict:
|
||||
root_node = pytree_dict.get('root', {})
|
||||
# 检查是否是简单结构(root是单个action节点,没有children)
|
||||
if (root_node.get('type') == 'action' and
|
||||
('children' not in root_node or not root_node.get('children'))):
|
||||
try:
|
||||
jsonschema.validate(instance=pytree_dict, schema=self.simple_schema)
|
||||
logging.warning("⚠️ 复杂模式生成了简单结构(单个action),触发自动包装为完整行为树的回退逻辑。")
|
||||
action_name = root_node.get('name')
|
||||
action_params = root_node.get('params') if isinstance(root_node.get('params'), dict) else {}
|
||||
|
||||
safety_selector = {
|
||||
"type": "Selector",
|
||||
"name": "SafetyMonitor",
|
||||
"params": {"memory": True},
|
||||
"children": [
|
||||
{"type": "condition", "name": "battery_above", "params": {"threshold": 0.3}},
|
||||
{"type": "condition", "name": "gps_status", "params": {"min_satellites": 8}},
|
||||
{"type": "Sequence", "name": "EmergencyHandler", "children": [
|
||||
{"type": "action", "name": "emergency_return", "params": {"reason": "safety_breach"}},
|
||||
{"type": "action", "name": "land", "params": {"mode": "home"}}
|
||||
]}
|
||||
]
|
||||
}
|
||||
|
||||
main_children = [{"type": "action", "name": action_name, "params": action_params}]
|
||||
if action_name != "land":
|
||||
main_children.append({"type": "action", "name": "land", "params": {"mode": "home"}})
|
||||
|
||||
root_parallel = {
|
||||
"type": "Parallel",
|
||||
"name": "MissionWithSafety",
|
||||
"params": {"policy": "all_success"},
|
||||
"children": [
|
||||
{"type": "Sequence", "name": "MainTask", "children": main_children},
|
||||
safety_selector
|
||||
]
|
||||
}
|
||||
pytree_dict = {"root": root_parallel}
|
||||
except jsonschema.ValidationError:
|
||||
# 不符合简单结构,按正常复杂验证继续
|
||||
pass
|
||||
# 验证生成的复杂行为树
|
||||
if _validate_pytree_with_schema(pytree_dict, self.schema):
|
||||
logging.info("✅ 成功生成并验证了Pytree")
|
||||
plan_id = str(uuid.uuid4())
|
||||
|
||||
0
backend_service/venv/bin/Activate.ps1
Executable file → Normal file
0
backend_service/venv/bin/Activate.ps1
Executable file → Normal file
4
backend_service/venv/bin/activate
Executable file → Normal file
4
backend_service/venv/bin/activate
Executable file → Normal file
@@ -41,12 +41,12 @@ case "$(uname)" in
|
||||
CYGWIN*|MSYS*|MINGW*)
|
||||
# transform D:\path\to\venv to /d/path/to/venv on MSYS and MINGW
|
||||
# and to /cygdrive/d/path/to/venv on Cygwin
|
||||
VIRTUAL_ENV=$(cygpath /home/huangfukk/DronePlanning/backend_service/venv)
|
||||
VIRTUAL_ENV=$(cygpath /home/a/DronePlanning/backend_service/venv)
|
||||
export VIRTUAL_ENV
|
||||
;;
|
||||
*)
|
||||
# use the path as-is
|
||||
export VIRTUAL_ENV=/home/huangfukk/DronePlanning/backend_service/venv
|
||||
export VIRTUAL_ENV=/home/a/DronePlanning/backend_service/venv
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
2
backend_service/venv/bin/activate.csh
Executable file → Normal file
2
backend_service/venv/bin/activate.csh
Executable file → Normal file
@@ -9,7 +9,7 @@ alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PA
|
||||
# Unset irrelevant variables.
|
||||
deactivate nondestructive
|
||||
|
||||
setenv VIRTUAL_ENV /home/huangfukk/DronePlanning/backend_service/venv
|
||||
setenv VIRTUAL_ENV /home/a/DronePlanning/backend_service/venv
|
||||
|
||||
set _OLD_VIRTUAL_PATH="$PATH"
|
||||
setenv PATH "$VIRTUAL_ENV/"bin":$PATH"
|
||||
|
||||
2
backend_service/venv/bin/activate.fish
Executable file → Normal file
2
backend_service/venv/bin/activate.fish
Executable file → Normal file
@@ -33,7 +33,7 @@ end
|
||||
# Unset irrelevant variables.
|
||||
deactivate nondestructive
|
||||
|
||||
set -gx VIRTUAL_ENV /home/huangfukk/DronePlanning/backend_service/venv
|
||||
set -gx VIRTUAL_ENV /home/a/DronePlanning/backend_service/venv
|
||||
|
||||
set -gx _OLD_VIRTUAL_PATH $PATH
|
||||
set -gx PATH "$VIRTUAL_ENV/"bin $PATH
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from chromadb.cli.cli import app
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from coloredlogs.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from dashscope.cli import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from distro.distro import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from dotenv.__main__ import cli
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from numpy.f2py.f2py2e import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from fastapi.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from huggingface_hub.cli.hf import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from httpx import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from humanfriendly.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from isympy import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from json_repair.__main__ import cli
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(cli())
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from jsonschema.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from markdown_it.cli.parse import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from mcp.cli import app
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(app())
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from charset_normalizer.cli import cli_detect
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from numpy._configtool import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from onnxruntime.tools.onnxruntime_test import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from openai.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from pip._internal.cli.main import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from pip._internal.cli.main import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from pip._internal.cli.main import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from pybase64.__main__ import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from pygments.cmdline import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from json5.tool import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from build.__main__ import entrypoint
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.cli import decrypt
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.cli import encrypt
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.cli import keygen
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.util import private_to_public
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.cli import sign
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.cli import verify
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1 +1 @@
|
||||
/home/huangfukk/miniconda3/bin/python3
|
||||
/home/a/miniconda3/bin/python3
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from shortuuid.cli import cli
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(cli())
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from huggingface_hub.inference._mcp.cli import app
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from tqdm.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from typer.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from uvicorn.main import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from watchfiles.cli import cli
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from websockets.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from websocket._wsdump import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
Copyright (c) 2011, Stavros Korokithakis
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
Neither the name of Stochastic Technologies nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -1,7 +0,0 @@
|
||||
Authors
|
||||
=======
|
||||
|
||||
``pyjwt`` is currently written and maintained by `Jose Padilla <https://github.com/jpadilla>`_.
|
||||
Originally written and maintained by `Jeff Lindsay <https://github.com/progrium>`_.
|
||||
|
||||
A full list of contributors can be found on GitHub’s `overview <https://github.com/jpadilla/pyjwt/graphs/contributors>`_.
|
||||
@@ -1 +0,0 @@
|
||||
pip
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2022 José Padilla
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,106 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: PyJWT
|
||||
Version: 2.10.1
|
||||
Summary: JSON Web Token implementation in Python
|
||||
Author-email: Jose Padilla <hello@jpadilla.com>
|
||||
License: MIT
|
||||
Project-URL: Homepage, https://github.com/jpadilla/pyjwt
|
||||
Keywords: json,jwt,security,signing,token,web
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3 :: Only
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3.11
|
||||
Classifier: Programming Language :: Python :: 3.12
|
||||
Classifier: Programming Language :: Python :: 3.13
|
||||
Classifier: Topic :: Utilities
|
||||
Requires-Python: >=3.9
|
||||
Description-Content-Type: text/x-rst
|
||||
License-File: LICENSE
|
||||
License-File: AUTHORS.rst
|
||||
Provides-Extra: crypto
|
||||
Requires-Dist: cryptography>=3.4.0; extra == "crypto"
|
||||
Provides-Extra: dev
|
||||
Requires-Dist: coverage[toml]==5.0.4; extra == "dev"
|
||||
Requires-Dist: cryptography>=3.4.0; extra == "dev"
|
||||
Requires-Dist: pre-commit; extra == "dev"
|
||||
Requires-Dist: pytest<7.0.0,>=6.0.0; extra == "dev"
|
||||
Requires-Dist: sphinx; extra == "dev"
|
||||
Requires-Dist: sphinx-rtd-theme; extra == "dev"
|
||||
Requires-Dist: zope.interface; extra == "dev"
|
||||
Provides-Extra: docs
|
||||
Requires-Dist: sphinx; extra == "docs"
|
||||
Requires-Dist: sphinx-rtd-theme; extra == "docs"
|
||||
Requires-Dist: zope.interface; extra == "docs"
|
||||
Provides-Extra: tests
|
||||
Requires-Dist: coverage[toml]==5.0.4; extra == "tests"
|
||||
Requires-Dist: pytest<7.0.0,>=6.0.0; extra == "tests"
|
||||
|
||||
PyJWT
|
||||
=====
|
||||
|
||||
.. image:: https://github.com/jpadilla/pyjwt/workflows/CI/badge.svg
|
||||
:target: https://github.com/jpadilla/pyjwt/actions?query=workflow%3ACI
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/pyjwt.svg
|
||||
:target: https://pypi.python.org/pypi/pyjwt
|
||||
|
||||
.. image:: https://codecov.io/gh/jpadilla/pyjwt/branch/master/graph/badge.svg
|
||||
:target: https://codecov.io/gh/jpadilla/pyjwt
|
||||
|
||||
.. image:: https://readthedocs.org/projects/pyjwt/badge/?version=stable
|
||||
:target: https://pyjwt.readthedocs.io/en/stable/
|
||||
|
||||
A Python implementation of `RFC 7519 <https://tools.ietf.org/html/rfc7519>`_. Original implementation was written by `@progrium <https://github.com/progrium>`_.
|
||||
|
||||
Sponsor
|
||||
-------
|
||||
|
||||
.. |auth0-logo| image:: https://github.com/user-attachments/assets/ee98379e-ee76-4bcb-943a-e25c4ea6d174
|
||||
:width: 160px
|
||||
|
||||
+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |auth0-logo| | If you want to quickly add secure token-based authentication to Python projects, feel free to check Auth0's Python SDK and free plan at `auth0.com/signup <https://auth0.com/signup?utm_source=external_sites&utm_medium=pyjwt&utm_campaign=devn_signup>`_. |
|
||||
+--------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Installing
|
||||
----------
|
||||
|
||||
Install with **pip**:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install PyJWT
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import jwt
|
||||
>>> encoded = jwt.encode({"some": "payload"}, "secret", algorithm="HS256")
|
||||
>>> print(encoded)
|
||||
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg
|
||||
>>> jwt.decode(encoded, "secret", algorithms=["HS256"])
|
||||
{'some': 'payload'}
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
View the full docs online at https://pyjwt.readthedocs.io/en/stable/
|
||||
|
||||
|
||||
Tests
|
||||
-----
|
||||
|
||||
You can run tests from the project root after cloning with:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ tox
|
||||
@@ -1,32 +0,0 @@
|
||||
PyJWT-2.10.1.dist-info/AUTHORS.rst,sha256=klzkNGECnu2_VY7At89_xLBF3vUSDruXk3xwgUBxzwc,322
|
||||
PyJWT-2.10.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
PyJWT-2.10.1.dist-info/LICENSE,sha256=eXp6ICMdTEM-nxkR2xcx0GtYKLmPSZgZoDT3wPVvXOU,1085
|
||||
PyJWT-2.10.1.dist-info/METADATA,sha256=EkewF6D6KU8SGaaQzVYfxUUU1P_gs_dp1pYTkoYvAx8,3990
|
||||
PyJWT-2.10.1.dist-info/RECORD,,
|
||||
PyJWT-2.10.1.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
||||
PyJWT-2.10.1.dist-info/top_level.txt,sha256=RP5DHNyJbMq2ka0FmfTgoSaQzh7e3r5XuCWCO8a00k8,4
|
||||
jwt/__init__.py,sha256=VB2vFKuboTjcDGeZ8r-UqK_dz3NsQSQEqySSICby8Xg,1711
|
||||
jwt/__pycache__/__init__.cpython-313.pyc,,
|
||||
jwt/__pycache__/algorithms.cpython-313.pyc,,
|
||||
jwt/__pycache__/api_jwk.cpython-313.pyc,,
|
||||
jwt/__pycache__/api_jws.cpython-313.pyc,,
|
||||
jwt/__pycache__/api_jwt.cpython-313.pyc,,
|
||||
jwt/__pycache__/exceptions.cpython-313.pyc,,
|
||||
jwt/__pycache__/help.cpython-313.pyc,,
|
||||
jwt/__pycache__/jwk_set_cache.cpython-313.pyc,,
|
||||
jwt/__pycache__/jwks_client.cpython-313.pyc,,
|
||||
jwt/__pycache__/types.cpython-313.pyc,,
|
||||
jwt/__pycache__/utils.cpython-313.pyc,,
|
||||
jwt/__pycache__/warnings.cpython-313.pyc,,
|
||||
jwt/algorithms.py,sha256=cKr-XEioe0mBtqJMCaHEswqVOA1Z8Purt5Sb3Bi-5BE,30409
|
||||
jwt/api_jwk.py,sha256=6F1r7rmm8V5qEnBKA_xMjS9R7VoANe1_BL1oD2FrAjE,4451
|
||||
jwt/api_jws.py,sha256=aM8vzqQf6mRrAw7bRy-Moj_pjWsKSVQyYK896AfMjJU,11762
|
||||
jwt/api_jwt.py,sha256=OGT4hok1l5A6FH_KdcrU5g6u6EQ8B7em0r9kGM9SYgA,14512
|
||||
jwt/exceptions.py,sha256=bUIOJ-v9tjopTLS-FYOTc3kFx5WP5IZt7ksN_HE1G9Q,1211
|
||||
jwt/help.py,sha256=vFdNzjQoAch04XCMYpCkyB2blaqHAGAqQrtf9nSPkdk,1808
|
||||
jwt/jwk_set_cache.py,sha256=hBKmN-giU7-G37L_XKgc_OZu2ah4wdbj1ZNG_GkoSE8,959
|
||||
jwt/jwks_client.py,sha256=p9b-IbQqo2tEge9Zit3oSPBFNePqwho96VLbnUrHUWs,4259
|
||||
jwt/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
jwt/types.py,sha256=VnhGv_VFu5a7_mrPoSCB7HaNLrJdhM8Sq1sSfEg0gLU,99
|
||||
jwt/utils.py,sha256=hxOjvDBheBYhz-RIPiEz7Q88dSUSTMzEdKE_Ww2VdJw,3640
|
||||
jwt/warnings.py,sha256=50XWOnyNsIaqzUJTk6XHNiIDykiL763GYA92MjTKmok,59
|
||||
@@ -1,5 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: setuptools (75.6.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
jwt
|
||||
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
pip
|
||||
@@ -1,547 +0,0 @@
|
||||
Metadata-Version: 2.4
|
||||
Name: agentscope
|
||||
Version: 1.0.7
|
||||
Summary: AgentScope: A Flexible yet Robust Multi-Agent Platform.
|
||||
Author-email: SysML team of Alibaba Tongyi Lab <gaodawei.gdw@alibaba-inc.com>
|
||||
License-Expression: Apache-2.0
|
||||
Project-URL: Homepage, https://github.com/agentscope-ai/agentscope
|
||||
Project-URL: Documentation, https://doc.agentscope.io/
|
||||
Project-URL: Repository, https://github.com/agentscope-ai/agentscope
|
||||
Keywords: deep-learning,multi agents,agents
|
||||
Classifier: Development Status :: 4 - Beta
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: Science/Research
|
||||
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
||||
Requires-Python: >=3.10
|
||||
Description-Content-Type: text/markdown
|
||||
License-File: LICENSE
|
||||
Requires-Dist: aioitertools
|
||||
Requires-Dist: anthropic
|
||||
Requires-Dist: dashscope
|
||||
Requires-Dist: docstring_parser
|
||||
Requires-Dist: json5
|
||||
Requires-Dist: json_repair
|
||||
Requires-Dist: mcp>=1.13
|
||||
Requires-Dist: numpy
|
||||
Requires-Dist: openai
|
||||
Requires-Dist: python-datauri
|
||||
Requires-Dist: opentelemetry-api
|
||||
Requires-Dist: opentelemetry-sdk
|
||||
Requires-Dist: opentelemetry-exporter-otlp
|
||||
Requires-Dist: python-socketio
|
||||
Requires-Dist: shortuuid
|
||||
Requires-Dist: tiktoken
|
||||
Requires-Dist: sounddevice
|
||||
Provides-Extra: full
|
||||
Requires-Dist: ollama>=0.5.4; extra == "full"
|
||||
Requires-Dist: google-genai; extra == "full"
|
||||
Requires-Dist: Pillow; extra == "full"
|
||||
Requires-Dist: transformers; extra == "full"
|
||||
Requires-Dist: jinja2; extra == "full"
|
||||
Requires-Dist: ray; extra == "full"
|
||||
Requires-Dist: mem0ai; extra == "full"
|
||||
Requires-Dist: packaging; extra == "full"
|
||||
Requires-Dist: pypdf; extra == "full"
|
||||
Requires-Dist: python-docx; extra == "full"
|
||||
Requires-Dist: nltk; extra == "full"
|
||||
Requires-Dist: qdrant-client; extra == "full"
|
||||
Provides-Extra: dev
|
||||
Requires-Dist: agentscope[full]; extra == "dev"
|
||||
Requires-Dist: pre-commit; extra == "dev"
|
||||
Requires-Dist: pytest; extra == "dev"
|
||||
Requires-Dist: sphinx-gallery; extra == "dev"
|
||||
Requires-Dist: furo; extra == "dev"
|
||||
Requires-Dist: myst_parser; extra == "dev"
|
||||
Requires-Dist: matplotlib; extra == "dev"
|
||||
Requires-Dist: pymilvus[milvus_lite]; extra == "dev"
|
||||
Requires-Dist: reme-ai>=0.1.10.7; python_full_version >= "3.12" and extra == "dev"
|
||||
Dynamic: license-file
|
||||
|
||||
[**中文主页**](https://github.com/agentscope-ai/agentscope/blob/main/README_zh.md) | [**Tutorial**](https://doc.agentscope.io/) | [**Roadmap**](https://github.com/agentscope-ai/agentscope/blob/main/docs/roadmap.md) | [**FAQ**](https://doc.agentscope.io/tutorial/faq.html)
|
||||
|
||||
<p align="center">
|
||||
<img
|
||||
src="https://img.alicdn.com/imgextra/i1/O1CN01nTg6w21NqT5qFKH1u_!!6000000001621-55-tps-550-550.svg"
|
||||
alt="AgentScope Logo"
|
||||
width="200"
|
||||
/>
|
||||
</p>
|
||||
|
||||
<h2 align="center">AgentScope: Agent-Oriented Programming for Building LLM Applications</h2>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://arxiv.org/abs/2402.14034">
|
||||
<img
|
||||
src="https://img.shields.io/badge/cs.MA-2402.14034-B31C1C?logo=arxiv&logoColor=B31C1C"
|
||||
alt="arxiv"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://pypi.org/project/agentscope/">
|
||||
<img
|
||||
src="https://img.shields.io/badge/python-3.10+-blue?logo=python"
|
||||
alt="pypi"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://pypi.org/project/agentscope/">
|
||||
<img
|
||||
src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fpypi.org%2Fpypi%2Fagentscope%2Fjson&query=%24.info.version&prefix=v&logo=pypi&label=version"
|
||||
alt="pypi"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://doc.agentscope.io/">
|
||||
<img
|
||||
src="https://img.shields.io/badge/Docs-English%7C%E4%B8%AD%E6%96%87-blue?logo=markdown"
|
||||
alt="docs"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://agentscope.io/">
|
||||
<img
|
||||
src="https://img.shields.io/badge/GUI-AgentScope_Studio-blue?logo=look&logoColor=green&color=dark-green"
|
||||
alt="workstation"
|
||||
/>
|
||||
</a>
|
||||
<a href="./LICENSE">
|
||||
<img
|
||||
src="https://img.shields.io/badge/license-Apache--2.0-black"
|
||||
alt="license"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://trendshift.io/api/badge/repositories/10079" alt="modelscope%2Fagentscope | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/>
|
||||
</p>
|
||||
|
||||
## ✨ Why AgentScope?
|
||||
|
||||
Easy for beginners, powerful for experts.
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/images/agentscope_v1_0822.png" alt="AgentScope Framework" width="80%"/>
|
||||
</p>
|
||||
|
||||
- **Transparent to Developers**: Transparent is our **FIRST principle**. Prompt engineering, API invocation, agent building, workflow orchestration, all are visible and controllable for developers. No deep encapsulation or implicit magic.
|
||||
- **[Realtime Steering](https://doc.agentscope.io/tutorial/task_agent.html#realtime-steering)**: Native support for realtime interruption and customized handling.
|
||||
- **More Agentic**: Support [agentic tools management](https://doc.agentscope.io/tutorial/task_tool.html), [agentic long-term memory control](https://doc.agentscope.io/tutorial/task_long_term_memory.html) and agentic RAG, etc.
|
||||
- **Model Agnostic**: Programming once, run with all models.
|
||||
- **LEGO-style Agent Building**: All components are **modular** and **independent**.
|
||||
- **Multi-Agent Oriented**: Designed for **multi-agent**, **explicit** message passing and workflow orchestration, NO deep encapsulation.
|
||||
- **Highly Customizable**: Tools, prompt, agent, workflow, third-party libs & visualization, customization is encouraged everywhere.
|
||||
|
||||
Quick overview of important features in **AgentScope 1.0**:
|
||||
|
||||
| Module | Feature | Tutorial |
|
||||
|------------|------------------------------------------------------------------------------------|-------------------------------------------------------------------------|
|
||||
| model | Support async invocation | [Model](https://doc.agentscope.io/tutorial/task_model.html) |
|
||||
| | Support reasoning model | |
|
||||
| | Support streaming/non-streaming returns | |
|
||||
| tool | Support async/sync tool functions | [Tool](https://doc.agentscope.io/tutorial/task_tool.html) |
|
||||
| | Support streaming/non-streaming returns | |
|
||||
| | Support user interruption | |
|
||||
| | Support post-processing | |
|
||||
| | Support group-wise tools management | |
|
||||
| | Support agentic tools management by meta tool | |
|
||||
| MCP | Support streamable HTTP/SSE/StdIO transport | [MCP](https://doc.agentscope.io/tutorial/task_mcp.html) |
|
||||
| | Support both **stateful** and **stateless** mode MCP Client | |
|
||||
| | Support client- & function-level fine-grained control | |
|
||||
| agent | Support async execution | |
|
||||
| | Support parallel tool calls | |
|
||||
| | Support realtime steering interruption and customized handling | |
|
||||
| | Support automatic state management | |
|
||||
| | Support agent-controlled long-term memory | |
|
||||
| | Support agent hooks | |
|
||||
| tracing | Support OpenTelemetry-based tracing in LLM, tools, agent and formatter | [Tracing](https://doc.agentscope.io/tutorial/task_tracing.html) |
|
||||
| | Support connecting to third-party tracing platforms (e.g. Arize-Phoenix, Langfuse) | |
|
||||
| memory | Support long-term memory | [Memory](https://doc.agentscope.io/tutorial/task_long_term_memory.html) |
|
||||
| session | Provide session/application-level automatic state management | [Session](https://doc.agentscope.io/tutorial/task_state.html) |
|
||||
| evaluation | Provide distributed and parallel evaluation | [Evaluation](https://doc.agentscope.io/tutorial/task_eval.html) |
|
||||
| formatter | Support multi-agent prompt formatting with tools API | [Prompt Formatter](https://doc.agentscope.io/tutorial/task_prompt.html) |
|
||||
| | Support truncation-based formatter strategy | |
|
||||
| plan | Support ReAct-based long-term planning | [Plan](https://doc.agentscope.io/tutorial/task_plan.html) |
|
||||
| | Support manual plan specification | |
|
||||
| RAG | Support agentic RAG | [RAG](https://doc.agentscope.io/tutorial/task_rag.html) |
|
||||
| | Support multimodal RAG | |
|
||||
| ... | | |
|
||||
|
||||
## 📢 News
|
||||
- **[2025-11]** [Contributing Guide](./CONTRIBUTING.md) is online now! Welcome to contribute to AgentScope.
|
||||
- **[2025-09]** **RAG** module in AgentScope 1.0 is online now! Check our [tutorial](https://doc.agentscope.io/tutorial/task_rag.html) and [example](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/rag) for more details.
|
||||
- **[2025-09]** **Voice agent** is online! `ReActAgent` supports Qwen-Omni and GPT-Audio natively now, check our [new example](https://github.com/agentscope-ai/agentscope/tree/main/examples/agent/voice_agent) and [roadmap](https://github.com/agentscope-ai/agentscope/issues/773).
|
||||
- **[2025-09]** A new powerful 📋**Plan** module is online now! Check out the [tutorial](https://doc.agentscope.io/tutorial/task_plan.html) for more details.
|
||||
- **[2025-09]** **AgentScope Runtime** is open-sourced now! Enabling effective agent deployment with sandboxed tool execution for production-ready AI applications. Check out the [GitHub repo](https://github.com/agentscope-ai/agentscope-runtime).
|
||||
- **[2025-09]** **AgentScope Studio** is open-sourced now! Check out the [GitHub repo](https://github.com/agentscope-ai/agentscope-studio).
|
||||
- **[2025-08]** The new tutorial of v1 is online now! Check out the [tutorial](https://doc.agentscope.io) for more details.
|
||||
- **[2025-08]** 🎉🎉 AgentScope v1 is released now! This version fully embraces the asynchronous execution, providing many new features and improvements. Check out [changelog](https://github.com/agentscope-ai/agentscope/blob/main/docs/changelog.md) for detailed changes.
|
||||
|
||||
## 💬 Contact
|
||||
|
||||
Welcome to join our community on
|
||||
|
||||
| [Discord](https://discord.gg/eYMpfnkG8h) | DingTalk |
|
||||
|----------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
||||
| <img src="https://gw.alicdn.com/imgextra/i1/O1CN01hhD1mu1Dd3BWVUvxN_!!6000000000238-2-tps-400-400.png" width="100" height="100"> | <img src="https://img.alicdn.com/imgextra/i1/O1CN01LxzZha1thpIN2cc2E_!!6000000005934-2-tps-497-477.png" width="100" height="100"> |
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
## 📑 Table of Contents
|
||||
|
||||
- [🚀 Quickstart](#-quickstart)
|
||||
- [💻 Installation](#-installation)
|
||||
- [🛠️ From source](#-from-source)
|
||||
- [🔄 Using uv (recommended for faster installs)](#-using-uv-recommended-for-faster-installs)
|
||||
- [📦 From PyPi](#-from-pypi)
|
||||
- [📝 Example](#-example)
|
||||
- [👋 Hello AgentScope!](#-hello-agentscope)
|
||||
- [🎯 Realtime Steering](#-realtime-steering)
|
||||
- [🛠️ Fine-Grained MCP Control](#-fine-grained-mcp-control)
|
||||
- [🧑🤝🧑 Multi-Agent Conversation](#-multi-agent-conversation)
|
||||
- [💻 AgentScope Studio](#-agentscope-studio)
|
||||
- [📖 Documentation](#-documentation)
|
||||
- [🤝 Contributing](#-contributing)
|
||||
- [⚖️ License](#-license)
|
||||
- [📚 Publications](#-publications)
|
||||
- [✨ Contributors](#-contributors)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
## 🚀 Quickstart
|
||||
|
||||
### 💻 Installation
|
||||
|
||||
> AgentScope requires **Python 3.10** or higher.
|
||||
|
||||
#### 🛠️ From source
|
||||
|
||||
```bash
|
||||
# Pull the source code from GitHub
|
||||
git clone -b main https://github.com/agentscope-ai/agentscope.git
|
||||
|
||||
# Install the package in editable mode
|
||||
cd agentscope
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
#### 🔄 Using uv (recommended for faster installs)
|
||||
|
||||
[uv](https://github.com/astral-sh/uv) is a fast Python package installer and resolver, written in Rust.
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone -b main https://github.com/agentscope-ai/agentscope.git
|
||||
cd agentscope
|
||||
|
||||
# Install with uv
|
||||
uv pip install -e .
|
||||
```
|
||||
|
||||
#### 📦 From PyPi
|
||||
|
||||
```bash
|
||||
pip install agentscope
|
||||
```
|
||||
|
||||
Or with uv:
|
||||
|
||||
```bash
|
||||
uv pip install agentscope
|
||||
```
|
||||
|
||||
## 📝 Example
|
||||
|
||||
### 👋 Hello AgentScope!
|
||||
|
||||
Start with a conversation between user and a ReAct agent 🤖 named "Friday"!
|
||||
|
||||
```python
|
||||
from agentscope.agent import ReActAgent, UserAgent
|
||||
from agentscope.model import DashScopeChatModel
|
||||
from agentscope.formatter import DashScopeChatFormatter
|
||||
from agentscope.memory import InMemoryMemory
|
||||
from agentscope.tool import Toolkit, execute_python_code, execute_shell_command
|
||||
import os, asyncio
|
||||
|
||||
|
||||
async def main():
|
||||
toolkit = Toolkit()
|
||||
toolkit.register_tool_function(execute_python_code)
|
||||
toolkit.register_tool_function(execute_shell_command)
|
||||
|
||||
agent = ReActAgent(
|
||||
name="Friday",
|
||||
sys_prompt="You're a helpful assistant named Friday.",
|
||||
model=DashScopeChatModel(
|
||||
model_name="qwen-max",
|
||||
api_key=os.environ["DASHSCOPE_API_KEY"],
|
||||
stream=True,
|
||||
),
|
||||
memory=InMemoryMemory(),
|
||||
formatter=DashScopeChatFormatter(),
|
||||
toolkit=toolkit,
|
||||
)
|
||||
|
||||
user = UserAgent(name="user")
|
||||
|
||||
msg = None
|
||||
while True:
|
||||
msg = await agent(msg)
|
||||
msg = await user(msg)
|
||||
if msg.get_text_content() == "exit":
|
||||
break
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
### 🎯 Realtime Steering
|
||||
|
||||
Natively support **realtime interruption** in ``ReActAgent`` with robust memory preservation, and convert interruption into an **observable event** for agent to seamlessly resume conversations.
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/images/realtime_steering_zh.gif" alt="Realtime Steering" width="49%"/>
|
||||
<img src="./assets/images/realtime_steering_en.gif" alt="Realtime Steering" width="49%"/>
|
||||
</p>
|
||||
|
||||
### 🛠️ Fine-Grained MCP Control
|
||||
|
||||
Developers can obtain the MCP tool as a **local callable function**, and use it anywhere (e.g. call directly, pass to agent, wrap into a more complex tool, etc.)
|
||||
|
||||
```python
|
||||
from agentscope.mcp import HttpStatelessClient
|
||||
from agentscope.tool import Toolkit
|
||||
import os
|
||||
|
||||
async def fine_grained_mcp_control():
|
||||
# Initialize the MCP client
|
||||
client = HttpStatelessClient(
|
||||
name="gaode_mcp",
|
||||
transport="streamable_http",
|
||||
url=f"https://mcp.amap.com/mcp?key={os.environ['GAODE_API_KEY']}",
|
||||
)
|
||||
|
||||
# Obtain the MCP tool as a **local callable function**, and use it anywhere
|
||||
func = await client.get_callable_function(func_name="maps_geo")
|
||||
|
||||
# Option 1: Call directly
|
||||
await func(address="Tiananmen Square", city="Beijing")
|
||||
|
||||
# Option 2: Pass to agent as a tool
|
||||
toolkit = Toolkit()
|
||||
toolkit.register_tool_function(func)
|
||||
# ...
|
||||
|
||||
# Option 3: Wrap into a more complex tool
|
||||
# ...
|
||||
```
|
||||
|
||||
### 🧑🤝🧑 Multi-Agent Conversation
|
||||
|
||||
AgentScope provides ``MsgHub`` and pipelines to streamline multi-agent conversations, offering efficient message routing and seamless information sharing
|
||||
|
||||
```python
|
||||
from agentscope.pipeline import MsgHub, sequential_pipeline
|
||||
from agentscope.message import Msg
|
||||
import asyncio
|
||||
|
||||
async def multi_agent_conversation():
|
||||
# Create agents
|
||||
agent1 = ...
|
||||
agent2 = ...
|
||||
agent3 = ...
|
||||
agent4 = ...
|
||||
|
||||
# Create a message hub to manage multi-agent conversation
|
||||
async with MsgHub(
|
||||
participants=[agent1, agent2, agent3],
|
||||
announcement=Msg("Host", "Introduce yourselves.", "assistant")
|
||||
) as hub:
|
||||
# Speak in a sequential manner
|
||||
await sequential_pipeline([agent1, agent2, agent3])
|
||||
# Dynamic manage the participants
|
||||
hub.add(agent4)
|
||||
hub.delete(agent3)
|
||||
await hub.broadcast(Msg("Host", "Goodbye!", "assistant"))
|
||||
|
||||
asyncio.run(multi_agent_conversation())
|
||||
```
|
||||
|
||||
### 💻 AgentScope Studio
|
||||
|
||||
Use the following command to install and start AgentScope Studio, to trace and visualize your agent application.
|
||||
|
||||
```bash
|
||||
npm install -g @agentscope/studio
|
||||
|
||||
as_studio
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<img
|
||||
src="./assets/images/home.gif"
|
||||
width="49%"
|
||||
alt="home"
|
||||
/>
|
||||
<img
|
||||
src="./assets/images/projects.gif"
|
||||
width="49%"
|
||||
alt="projects"
|
||||
/>
|
||||
<img
|
||||
src="./assets/images/runtime.gif"
|
||||
width="49%"
|
||||
alt="runtime"
|
||||
/>
|
||||
<img
|
||||
src="./assets/images/friday.gif"
|
||||
width="49%"
|
||||
alt="friday"
|
||||
/>
|
||||
</p>
|
||||
|
||||
|
||||
## 📖 Documentation
|
||||
|
||||
- Tutorial
|
||||
- [Installation](https://doc.agentscope.io/tutorial/quickstart_installation.html)
|
||||
- [Key Concepts](https://doc.agentscope.io/tutorial/quickstart_key_concept.html)
|
||||
- [Create Message](https://doc.agentscope.io/tutorial/quickstart_message.html)
|
||||
- [ReAct Agent](https://doc.agentscope.io/tutorial/quickstart_agent.html)
|
||||
- Workflow
|
||||
- [Conversation](https://doc.agentscope.io/tutorial/workflow_conversation.html)
|
||||
- [Multi-Agent Debate](https://doc.agentscope.io/tutorial/workflow_multiagent_debate.html)
|
||||
- [Concurrent Agents](https://doc.agentscope.io/tutorial/workflow_concurrent_agents.html)
|
||||
- [Routing](https://doc.agentscope.io/tutorial/workflow_routing.html)
|
||||
- [Handoffs](https://doc.agentscope.io/tutorial/workflow_handoffs.html)
|
||||
- FAQ
|
||||
- [FAQ](https://doc.agentscope.io/tutorial/faq.html)
|
||||
- Task Guides
|
||||
- [Model](https://doc.agentscope.io/tutorial/task_model.html)
|
||||
- [Prompt Formatter](https://doc.agentscope.io/tutorial/task_prompt.html)
|
||||
- [Tool](https://doc.agentscope.io/tutorial/task_tool.html)
|
||||
- [Memory](https://doc.agentscope.io/tutorial/task_memory.html)
|
||||
- [Long-Term Memory](https://doc.agentscope.io/tutorial/task_long_term_memory.html)
|
||||
- [Agent](https://doc.agentscope.io/tutorial/task_agent.html)
|
||||
- [Pipeline](https://doc.agentscope.io/tutorial/task_pipeline.html)
|
||||
- [Plan](https://doc.agentscope.io/tutorial/task_plan.html)
|
||||
- [State/Session Management](https://doc.agentscope.io/tutorial/task_state.html)
|
||||
- [Agent Hooks](https://doc.agentscope.io/tutorial/task_hook.html)
|
||||
- [MCP](https://doc.agentscope.io/tutorial/task_mcp.html)
|
||||
- [AgentScope Studio](https://doc.agentscope.io/tutorial/task_studio.html)
|
||||
- [Tracing](https://doc.agentscope.io/tutorial/task_tracing.html)
|
||||
- [Evaluation](https://doc.agentscope.io/tutorial/task_eval.html)
|
||||
- [Embedding](https://doc.agentscope.io/tutorial/task_embedding.html)
|
||||
- [Token](https://doc.agentscope.io/tutorial/task_token.html)
|
||||
- API
|
||||
- [API Docs](https://doc.agentscope.io/api/agentscope.html)
|
||||
- [Examples](https://github.com/agentscope-ai/agentscope/tree/main/examples)
|
||||
- Functionality
|
||||
- [MCP](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/mcp)
|
||||
- [Plan](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/plan)
|
||||
- [Structured Output](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/structured_output)
|
||||
- [RAG](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/rag)
|
||||
- [Long-Term Memory](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/long_term_memory)
|
||||
- [Session with SQLite](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/session_with_sqlite)
|
||||
- [Stream Printing Messages](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/stream_printing_messages)
|
||||
- Agent
|
||||
- [ReAct Agent](https://github.com/agentscope-ai/agentscope/tree/main/examples/agent/react_agent)
|
||||
- [Voice Agent](https://github.com/agentscope-ai/agentscope/tree/main/examples/agent/voice_agent)
|
||||
- [Deep Research Agent](https://github.com/agentscope-ai/agentscope/tree/main/examples/agent/deep_research_agent)
|
||||
- [Browser-use Agent](https://github.com/agentscope-ai/agentscope/tree/main/examples/agent/browser_agent)
|
||||
- [Meta Planner Agent](https://github.com/agentscope-ai/agentscope/tree/main/examples/agent/meta_planner_agent)
|
||||
- Game
|
||||
- [Nine-player Werewolves](https://github.com/agentscope-ai/agentscope/tree/main/examples/game/werewolves)
|
||||
- Workflow
|
||||
- [Multi-agent Debate](https://github.com/agentscope-ai/agentscope/tree/main/examples/workflows/multiagent_debate)
|
||||
- [Multi-agent Conversation](https://github.com/agentscope-ai/agentscope/tree/main/examples/workflows/multiagent_conversation)
|
||||
- [Multi-agent Concurrent](https://github.com/agentscope-ai/agentscope/tree/main/examples/workflows/multiagent_concurrent)
|
||||
- Evaluation
|
||||
- [ACEBench](https://github.com/agentscope-ai/agentscope/tree/main/examples/evaluation/ace_bench)
|
||||
- Training
|
||||
- [Reinforcement learning (RL) with Trinity-RFT](https://github.com/agentscope-ai/agentscope/tree/main/examples/training/react_agent)
|
||||
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
We welcome contributions from the community! Please refer to our [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines
|
||||
on how to contribute.
|
||||
|
||||
## ⚖️ License
|
||||
|
||||
AgentScope is released under Apache License 2.0.
|
||||
|
||||
## 📚 Publications
|
||||
|
||||
If you find our work helpful for your research or application, please cite our papers.
|
||||
|
||||
- [AgentScope 1.0: A Developer-Centric Framework for Building Agentic Applications](https://arxiv.org/abs/2508.16279)
|
||||
|
||||
- [AgentScope: A Flexible yet Robust Multi-Agent Platform](https://arxiv.org/abs/2402.14034)
|
||||
|
||||
```
|
||||
@article{agentscope_v1,
|
||||
author = {
|
||||
Dawei Gao,
|
||||
Zitao Li,
|
||||
Yuexiang Xie,
|
||||
Weirui Kuang,
|
||||
Liuyi Yao,
|
||||
Bingchen Qian,
|
||||
Zhijian Ma,
|
||||
Yue Cui,
|
||||
Haohao Luo,
|
||||
Shen Li,
|
||||
Lu Yi,
|
||||
Yi Yu,
|
||||
Shiqi He,
|
||||
Zhiling Luo,
|
||||
Wenmeng Zhou,
|
||||
Zhicheng Zhang,
|
||||
Xuguang He,
|
||||
Ziqian Chen,
|
||||
Weikai Liao,
|
||||
Farruh Isakulovich Kushnazarov,
|
||||
Yaliang Li,
|
||||
Bolin Ding,
|
||||
Jingren Zhou}
|
||||
title = {AgentScope 1.0: A Developer-Centric Framework for Building Agentic Applications},
|
||||
journal = {CoRR},
|
||||
volume = {abs/2508.16279},
|
||||
year = {2025},
|
||||
}
|
||||
|
||||
@article{agentscope,
|
||||
author = {
|
||||
Dawei Gao,
|
||||
Zitao Li,
|
||||
Xuchen Pan,
|
||||
Weirui Kuang,
|
||||
Zhijian Ma,
|
||||
Bingchen Qian,
|
||||
Fei Wei,
|
||||
Wenhao Zhang,
|
||||
Yuexiang Xie,
|
||||
Daoyuan Chen,
|
||||
Liuyi Yao,
|
||||
Hongyi Peng,
|
||||
Zeyu Zhang,
|
||||
Lin Zhu,
|
||||
Chen Cheng,
|
||||
Hongzhu Shi,
|
||||
Yaliang Li,
|
||||
Bolin Ding,
|
||||
Jingren Zhou}
|
||||
title = {AgentScope: A Flexible yet Robust Multi-Agent Platform},
|
||||
journal = {CoRR},
|
||||
volume = {abs/2402.14034},
|
||||
year = {2024},
|
||||
}
|
||||
```
|
||||
|
||||
## ✨ Contributors
|
||||
|
||||
All thanks to our contributors:
|
||||
|
||||
<a href="https://github.com/agentscope-ai/agentscope/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=agentscope-ai/agentscope&max=999&columns=12&anon=1" />
|
||||
</a>
|
||||
@@ -1,315 +0,0 @@
|
||||
agentscope-1.0.7.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
agentscope-1.0.7.dist-info/METADATA,sha256=HD2a1imJIVJ1oFh55nhcZTP0Li5q-9o1ZDg-K73SVh8,25920
|
||||
agentscope-1.0.7.dist-info/RECORD,,
|
||||
agentscope-1.0.7.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
agentscope-1.0.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
||||
agentscope-1.0.7.dist-info/licenses/LICENSE,sha256=QYa8rfNYxgCABgMJdp22sqNScg1zU9gnu1dMYA_umRM,20637
|
||||
agentscope-1.0.7.dist-info/top_level.txt,sha256=uYSDqkiAOqFFfMz9DGnkhn0_nNVwo1uaFYZQikHbWNM,11
|
||||
agentscope/__init__.py,sha256=MkP1MQ4hMFmRQF8qeUUVuBcCGvLS4fa-eqvogl8aj84,3220
|
||||
agentscope/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/__pycache__/_config.cpython-313.pyc,,
|
||||
agentscope/__pycache__/_logging.cpython-313.pyc,,
|
||||
agentscope/__pycache__/_version.cpython-313.pyc,,
|
||||
agentscope/_config.py,sha256=W1Y2lQbTXj1esxwm_sK2yFqztacz-L1OzRJsaei04GM,767
|
||||
agentscope/_logging.py,sha256=XzcUTb7MfRZkc-B3N1IV-jpHaZG0yFirZyfuGa7HOA4,1223
|
||||
agentscope/_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
agentscope/_utils/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/_utils/__pycache__/_common.cpython-313.pyc,,
|
||||
agentscope/_utils/__pycache__/_mixin.cpython-313.pyc,,
|
||||
agentscope/_utils/_common.py,sha256=ghJITFirhNAwTl_ifi9cI6Oc_Fsvlimiv_sxwi4JXZE,8169
|
||||
agentscope/_utils/_mixin.py,sha256=9co2GJyiShSq6HiQ1KwGABr3mfYw2tyvlzCMgI8L0-w,219
|
||||
agentscope/_version.py,sha256=KpA_lRRXOAnkM0n8CqdbV0FanoevNyEft5-YZ-i1-wI,80
|
||||
agentscope/agent/__init__.py,sha256=fxBL1RmxC__kHPRVYkEj03EJ1mYO32vKsbY5wDIV_x8,496
|
||||
agentscope/agent/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/agent/__pycache__/_agent_base.cpython-313.pyc,,
|
||||
agentscope/agent/__pycache__/_agent_meta.cpython-313.pyc,,
|
||||
agentscope/agent/__pycache__/_react_agent.cpython-313.pyc,,
|
||||
agentscope/agent/__pycache__/_react_agent_base.cpython-313.pyc,,
|
||||
agentscope/agent/__pycache__/_user_agent.cpython-313.pyc,,
|
||||
agentscope/agent/__pycache__/_user_input.cpython-313.pyc,,
|
||||
agentscope/agent/_agent_base.py,sha256=gxF0tuQN0XebkWR-uVM-a_RTR6eKoJnJOvJT90UegKI,24299
|
||||
agentscope/agent/_agent_meta.py,sha256=Ilda4Fonq29oeQ3kUDTIs8db655MQqWIhzvxGiGUrSw,5730
|
||||
agentscope/agent/_react_agent.py,sha256=zQKd9L19k3hjJmCRZYp2GjqedHh5-A45k-8xWcGSDoI,28676
|
||||
agentscope/agent/_react_agent_base.py,sha256=haWRx93D7A_zmhVVJLlJ_YD8I2pCM7g77vok761DOug,3707
|
||||
agentscope/agent/_user_agent.py,sha256=50kYNXWSfYE7L0x8D1Vmzsl1-mg20nSaCDYROzEusPI,4219
|
||||
agentscope/agent/_user_input.py,sha256=oXtHQ8XapV0ov_8S40MAt2EWDHmvC-_zAEZsR9lUt8g,13105
|
||||
agentscope/embedding/__init__.py,sha256=aiGzcY4qzX7a-ieseIH86_8zhry5yaII5Wdkg-hKjXY,871
|
||||
agentscope/embedding/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_cache_base.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_dashscope_embedding.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_dashscope_multimodal_embedding.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_embedding_base.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_embedding_response.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_embedding_usage.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_file_cache.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_gemini_embedding.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_ollama_embedding.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_openai_embedding.cpython-313.pyc,,
|
||||
agentscope/embedding/_cache_base.py,sha256=QV_D9Q1Rbtts1BporJVomFwaLyG6nsy9GxhLQNxh4lY,1800
|
||||
agentscope/embedding/_dashscope_embedding.py,sha256=r0qbxhs1kfNgPkgWIvcPXKDdKfVFhKKERpqW9DyfRtM,5905
|
||||
agentscope/embedding/_dashscope_multimodal_embedding.py,sha256=XQ3Dx7sXC18fTXW6kkudhMwJKqiVSfrPOJrGeYpXFEg,8682
|
||||
agentscope/embedding/_embedding_base.py,sha256=sgt_GsFGiuzSCt1-gzhLKJ3Cn4usYbGfHqliHIWMZg8,1191
|
||||
agentscope/embedding/_embedding_response.py,sha256=naEqlewn6J5UyteBewwknH6HlZVTo2SRhN714JhOk2U,1093
|
||||
agentscope/embedding/_embedding_usage.py,sha256=Z1q5yPXuGR8BpB7yUxcn-vPfmRP7gqnGmBjsSGC2f1w,579
|
||||
agentscope/embedding/_file_cache.py,sha256=2MZpiurcVgqkCTIq2U_8Z0n_D0I1Z87owXY0K-Fqfvk,7126
|
||||
agentscope/embedding/_gemini_embedding.py,sha256=5WgGi9iJK6OSbCO_2mG_JbgSxUotR44grNo9CF6yaL0,3549
|
||||
agentscope/embedding/_ollama_embedding.py,sha256=XRAicJgcD8DDHHy0W5du_Jsio4JC3L6pqvctexUOFKA,3379
|
||||
agentscope/embedding/_openai_embedding.py,sha256=ZWcyLR_a9DuekdmHkxD93ck6Hk3ZmytNsLYognCFacE,3491
|
||||
agentscope/evaluate/__init__.py,sha256=8FWPPEnQh95u9TxN8Forj8-b-in2a4_yxn_5F-yMeV8,861
|
||||
agentscope/evaluate/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/evaluate/__pycache__/_benchmark_base.cpython-313.pyc,,
|
||||
agentscope/evaluate/__pycache__/_metric_base.cpython-313.pyc,,
|
||||
agentscope/evaluate/__pycache__/_solution.cpython-313.pyc,,
|
||||
agentscope/evaluate/__pycache__/_task.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/__init__.py,sha256=ZtgAiBvYaSJOmUPXX2P5hf_cJdECxJiMgEtyt99pI38,331
|
||||
agentscope/evaluate/_ace_benchmark/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/__pycache__/_ace_benchmark.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/__pycache__/_ace_metric.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/__pycache__/_ace_tools_zh.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/_ace_benchmark.py,sha256=8MV9V0FMSV3YfymVKd_ybJRt_dzybKBTJMeivZ393FI,8151
|
||||
agentscope/evaluate/_ace_benchmark/_ace_metric.py,sha256=6_VBBJ50v7aL6OdwJXRRUrqx2gdWtnpM6jlcZMHP6cQ,4225
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/__init__.py,sha256=DFWSvwmPolmgqEbqwmkvO05mTr2QNoneO_eXFjEw7ac,327
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/__pycache__/_food_platform_api.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/__pycache__/_message_api.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/__pycache__/_reminder_api.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/__pycache__/_shared_state.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/__pycache__/_travel_api.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/_food_platform_api.py,sha256=TUQD6gR2VzjtUDK9pZKoWr-H9U0opKcUjvqRmP3q58c,9871
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/_message_api.py,sha256=oJcSfj5Kw_BIMI3eC3LsxB5ZI_nN4o_wd0jOX6OXPGA,11784
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/_reminder_api.py,sha256=ObmgAI4UnpoZmgiRpGvqwXL2Bs5YH1KQG1JVBM9AXmM,7082
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/_shared_state.py,sha256=sLkWasNv57-YxeMEj-GIj6mB6LN0RmsIpOaL3fjImmg,551
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/_travel_api.py,sha256=aa5ixysqx6mO3Msueyv_vrJ3yJbdMBKkBmyaKoozJoU,28644
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_zh.py,sha256=f10Vu8N82BYe5aBVo8hi2FkC1f0VKMqrNouWEG8DsQM,4052
|
||||
agentscope/evaluate/_benchmark_base.py,sha256=YqFeDn6G-e8njE48Yso5-tRSeE5dZzDRhwvJKCnriQQ,1263
|
||||
agentscope/evaluate/_evaluator/__init__.py,sha256=2g3K8cHhugTwf64ywiF-yLFihpvlrBMX01bUNTQ-yik,280
|
||||
agentscope/evaluate/_evaluator/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/evaluate/_evaluator/__pycache__/_evaluator_base.cpython-313.pyc,,
|
||||
agentscope/evaluate/_evaluator/__pycache__/_general_evaluator.cpython-313.pyc,,
|
||||
agentscope/evaluate/_evaluator/__pycache__/_ray_evaluator.cpython-313.pyc,,
|
||||
agentscope/evaluate/_evaluator/_evaluator_base.py,sha256=Y7LWZDTLmKyiq4WvpLj6dSMJSZw4N80ty-BFEAg5Wxg,7317
|
||||
agentscope/evaluate/_evaluator/_general_evaluator.py,sha256=GSMdijP5a8KPVvc6QrAqOI7pRFyXhd-n3yKekgqSHB0,3817
|
||||
agentscope/evaluate/_evaluator/_ray_evaluator.py,sha256=CS_Hng_j2lY5nlaN5Fb1Uq5hL99dcNyzu2OaGl_HLk0,6075
|
||||
agentscope/evaluate/_evaluator_storage/__init__.py,sha256=bSdhxI83A-2OVMX6L-ZO8EwYytyBQy6XwGIFQbdTod4,262
|
||||
agentscope/evaluate/_evaluator_storage/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/evaluate/_evaluator_storage/__pycache__/_evaluator_storage_base.cpython-313.pyc,,
|
||||
agentscope/evaluate/_evaluator_storage/__pycache__/_file_evaluator_storage.cpython-313.pyc,,
|
||||
agentscope/evaluate/_evaluator_storage/_evaluator_storage_base.py,sha256=IW4A6WkBGf43uGj59f7Eu5ySTiX1rmPbpjX1iYjCl8A,5459
|
||||
agentscope/evaluate/_evaluator_storage/_file_evaluator_storage.py,sha256=xPBZ6GXCSL3YMJJNsqH0-bzCxo4_FhZDEqLJcGXLexA,11096
|
||||
agentscope/evaluate/_metric_base.py,sha256=ksYBDhjmE8vTv8cMy31HBhbvkGgIYhUBiC8Qw4zpOAE,2663
|
||||
agentscope/evaluate/_solution.py,sha256=CDbGtYOerCd_o2WgKMnFUPrzF51tXeAcMRu2-poyyho,1194
|
||||
agentscope/evaluate/_task.py,sha256=RJw6GbBTZmYN7bZY3DR6qEDKB4bgV3zwNbWt5vZZEhU,1585
|
||||
agentscope/exception/__init__.py,sha256=eaWWszusA4Lm3CaPmyZCpLBkjwxc17IAPq0MioznbQQ,361
|
||||
agentscope/exception/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/exception/__pycache__/_exception_base.cpython-313.pyc,,
|
||||
agentscope/exception/__pycache__/_tool.cpython-313.pyc,,
|
||||
agentscope/exception/_exception_base.py,sha256=o0VAg5seb9GnJNs_eZMrlmxqbI7UEyzwr7B1gwA48oQ,660
|
||||
agentscope/exception/_tool.py,sha256=AsCWmwM7HF5fFKD6JhI6ohRGMZG7i8H1cwWj3xfiPUc,512
|
||||
agentscope/formatter/__init__.py,sha256=mgg0ZCZsk-beTELeVU9HVaU9T38w3u5gMyA4LT-wwag,1184
|
||||
agentscope/formatter/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_anthropic_formatter.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_dashscope_formatter.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_deepseek_formatter.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_formatter_base.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_gemini_formatter.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_ollama_formatter.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_openai_formatter.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_truncated_formatter_base.cpython-313.pyc,,
|
||||
agentscope/formatter/_anthropic_formatter.py,sha256=yJMg6IZX538aKmC6JqYzddhVeLSGz92X9ubjg9MNvaA,8226
|
||||
agentscope/formatter/_dashscope_formatter.py,sha256=FWkX2_zHXCaq4sK_o6NH5b_qcXin_tODDhFqAk0x78A,14548
|
||||
agentscope/formatter/_deepseek_formatter.py,sha256=5Ewi8c99qYL5ZCyE6oKek1x3cqNMfHDtXay43Goohi0,8143
|
||||
agentscope/formatter/_formatter_base.py,sha256=FQKf_3KrydfzuAIL5m5YbC36pfz7lXjnnjG_VI25Cm0,3690
|
||||
agentscope/formatter/_gemini_formatter.py,sha256=n6okME8L623zoLayNXG1uf-UEDgB3xydmpuWipUm4kY,13036
|
||||
agentscope/formatter/_ollama_formatter.py,sha256=fqGKIdhPyMizYSBLj-YwtcbIPBriXolEvrPQuR-ZeiY,10290
|
||||
agentscope/formatter/_openai_formatter.py,sha256=6wrcmO7mqba1X-VWMbYEGjWIv7NfhW-4nctLqvuDaU0,13214
|
||||
agentscope/formatter/_truncated_formatter_base.py,sha256=xKqBL-qiDZSLaHq1ls9fUZZY8xSikdpLqC85hVSWbDM,10211
|
||||
agentscope/hooks/__init__.py,sha256=gn0gD6IUtvlN8fGSy9YZRcS3ANpewvyPjQZuHo2SylU,670
|
||||
agentscope/hooks/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/hooks/__pycache__/_studio_hooks.cpython-313.pyc,,
|
||||
agentscope/hooks/_studio_hooks.py,sha256=fxGjYIwqQ1vs0Yr3zrcfAwO1ZWLyoSvG_0MCmjLnBog,1143
|
||||
agentscope/mcp/__init__.py,sha256=8_x7Loaxt1PVh5h5ubr_RdnyF9wRJOhSsBYMHWaPFRw,587
|
||||
agentscope/mcp/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/mcp/__pycache__/_client_base.cpython-313.pyc,,
|
||||
agentscope/mcp/__pycache__/_http_stateful_client.cpython-313.pyc,,
|
||||
agentscope/mcp/__pycache__/_http_stateless_client.cpython-313.pyc,,
|
||||
agentscope/mcp/__pycache__/_mcp_function.cpython-313.pyc,,
|
||||
agentscope/mcp/__pycache__/_stateful_client_base.cpython-313.pyc,,
|
||||
agentscope/mcp/__pycache__/_stdio_stateful_client.cpython-313.pyc,,
|
||||
agentscope/mcp/_client_base.py,sha256=XzYjrxwSzIEbAVO5IzUlbKTtzdr41fTfBtSUnISpGvY,3274
|
||||
agentscope/mcp/_http_stateful_client.py,sha256=Ekwd1KUJ2RX9oWvv3ZEqDy1FQaXa-hZbSp019K_eR_M,3186
|
||||
agentscope/mcp/_http_stateless_client.py,sha256=LotK9FgzXtSi7VSSGxF0PwYagARBd72P2derYe2Itmg,5223
|
||||
agentscope/mcp/_mcp_function.py,sha256=b_bK9chwTriE7pbncuzG3j46HZkG8BSugvpBr8Z90bI,2604
|
||||
agentscope/mcp/_stateful_client_base.py,sha256=l01VBdAsPNtwR50TnJtwx7NqcIB89V6xpiSN-QUFBeU,5206
|
||||
agentscope/mcp/_stdio_stateful_client.py,sha256=IjDjvha_82RCJgQ8eOitQfPnBVdWzy-ljzzYxnpAgvo,2950
|
||||
agentscope/memory/__init__.py,sha256=PlElb2Rt9lL9JcNZ6ADCvCJwaMPlhPdZIaaBkUlOHfs,555
|
||||
agentscope/memory/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/memory/__pycache__/_in_memory_memory.cpython-313.pyc,,
|
||||
agentscope/memory/__pycache__/_long_term_memory_base.cpython-313.pyc,,
|
||||
agentscope/memory/__pycache__/_mem0_long_term_memory.cpython-313.pyc,,
|
||||
agentscope/memory/__pycache__/_mem0_utils.cpython-313.pyc,,
|
||||
agentscope/memory/__pycache__/_memory_base.cpython-313.pyc,,
|
||||
agentscope/memory/_in_memory_memory.py,sha256=wEpxEqJ0rKui4AVrPz4Bs7JYLc4FmZmp6brUxm9U9nw,3694
|
||||
agentscope/memory/_long_term_memory_base.py,sha256=PQj1W7cLZVyO6gEbaqCeJm_uGG4oa6kRb_3PNgtwbBA,2976
|
||||
agentscope/memory/_mem0_long_term_memory.py,sha256=UsETvCSdwdaP59CphU5SB_BmOvCUHVkmDdFd0POFScs,21243
|
||||
agentscope/memory/_mem0_utils.py,sha256=9cKMy6KUKfAT5CF5oaIrJp90-qFaOZRMbLVg1VZvyMA,7617
|
||||
agentscope/memory/_memory_base.py,sha256=HcM23pIsXULYX6lT1DsGODG72ZWo3EA2TE6kbJEXQG4,1218
|
||||
agentscope/memory/_reme/__init__.py,sha256=mIuY8wRbVVYrQk_S05RBLivY0cnWDfq7Ere-oASf0G0,364
|
||||
agentscope/memory/_reme/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/memory/_reme/__pycache__/_reme_long_term_memory_base.cpython-313.pyc,,
|
||||
agentscope/memory/_reme/__pycache__/_reme_personal_long_term_memory.cpython-313.pyc,,
|
||||
agentscope/memory/_reme/__pycache__/_reme_task_long_term_memory.cpython-313.pyc,,
|
||||
agentscope/memory/_reme/__pycache__/_reme_tool_long_term_memory.cpython-313.pyc,,
|
||||
agentscope/memory/_reme/_reme_long_term_memory_base.py,sha256=o9bvTq1Zz4OESBifog0rX-Pax1N4dkcEgbxMknLCnz4,13747
|
||||
agentscope/memory/_reme/_reme_personal_long_term_memory.py,sha256=y4BpRymoNjw4ZHTYE6ThflwDgKroeHOLotgrpCNd5n8,13818
|
||||
agentscope/memory/_reme/_reme_task_long_term_memory.py,sha256=QHqLJojl98JO9Gv4Q6QrJGtyUvffRAIOkY0w0zNkcVo,14324
|
||||
agentscope/memory/_reme/_reme_tool_long_term_memory.py,sha256=DyKOJQYKm5eAhiqd91Xb7bBl23RO6jf0_k98P_AuK7Q,17675
|
||||
agentscope/message/__init__.py,sha256=Bxh_L9v-eHVe4_vrhXhMfaNsk5TN45i0PwuKiIju1I0,519
|
||||
agentscope/message/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/message/__pycache__/_message_base.cpython-313.pyc,,
|
||||
agentscope/message/__pycache__/_message_block.cpython-313.pyc,,
|
||||
agentscope/message/_message_base.py,sha256=sYw8MiuErVEcqaS6mPAoqTwsrJAyb9UqP-hZyqltNYY,6895
|
||||
agentscope/message/_message_block.py,sha256=oJQsnqm2exxIZjUn3j6CV77rlwL-QIbSf15PCGiTOgg,2651
|
||||
agentscope/model/__init__.py,sha256=BrUp6U4Tn7GwuaKvJ4rC3GIwrNXZe9jxBYxftJV7OZA,603
|
||||
agentscope/model/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_anthropic_model.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_dashscope_model.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_gemini_model.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_model_base.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_model_response.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_model_usage.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_ollama_model.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_openai_model.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_trinity_model.cpython-313.pyc,,
|
||||
agentscope/model/_anthropic_model.py,sha256=DPPI6WF1MD6ApSpu-tFXjM620GE8X3NqF4fpfuquA6U,18902
|
||||
agentscope/model/_dashscope_model.py,sha256=dCY6Z8xYyyMU2Y3HBUHaNaesBBCUW1FDBy_11VIm7dE,19329
|
||||
agentscope/model/_gemini_model.py,sha256=KUCZZelXec7ZXAo_XM8nyjrus7ATY2OYxXRPX0Uze5Y,17453
|
||||
agentscope/model/_model_base.py,sha256=9lRp9WT-NyOsoHLw2pKvr-aBOqsoFp_PLziXz9Jvsho,2039
|
||||
agentscope/model/_model_response.py,sha256=aER8B2-rg_Uu0MRSxknTIO_J0Q5yzyvH1aKfNdaW35k,1295
|
||||
agentscope/model/_model_usage.py,sha256=o9OvCM4CwYqqfa_w2oz80poIU8a2x9tf4jrkynr0g3o,560
|
||||
agentscope/model/_ollama_model.py,sha256=1l2fSIs2AakdZCV6rFVHANpokpZ0ZjAUFheY4sy6Eq0,12319
|
||||
agentscope/model/_openai_model.py,sha256=DA3LspB1X_Z-z9HNsZK_-df6oJjwvUNso1GzpgiRwhw,20201
|
||||
agentscope/model/_trinity_model.py,sha256=aq0pCGcDZfd3OX2bqM0RLhcsD2Dguom2QrwcB3CRjMw,2362
|
||||
agentscope/module/__init__.py,sha256=zhS2IA0PzSZalXiyu1jUXnz32ESQNn7RJKJJuSInE5o,130
|
||||
agentscope/module/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/module/__pycache__/_state_module.cpython-313.pyc,,
|
||||
agentscope/module/_state_module.py,sha256=nI1cm1Sa2ycFiFxs_tpo9aOnxWSqXGr8gVCTlRw5bVI,5644
|
||||
agentscope/pipeline/__init__.py,sha256=KwzeVx8Ugl0Ljk9B_ziRrR-5YfBHtDW5fjdM3CVJmgc,496
|
||||
agentscope/pipeline/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/pipeline/__pycache__/_class.cpython-313.pyc,,
|
||||
agentscope/pipeline/__pycache__/_functional.cpython-313.pyc,,
|
||||
agentscope/pipeline/__pycache__/_msghub.cpython-313.pyc,,
|
||||
agentscope/pipeline/_class.py,sha256=NQS56cj3eOK2j5F28-V3Sdh1cMaOT3N68y10hqH24MY,2594
|
||||
agentscope/pipeline/_functional.py,sha256=lVtm7UijSV7qyJ9C-aR_4dpmTON88nxZ8oUKxpvOoyU,5903
|
||||
agentscope/pipeline/_msghub.py,sha256=P2QqwvwJeiSE82eI_NDszeKHRHV4bOseisTnLwVUT34,5227
|
||||
agentscope/plan/__init__.py,sha256=TZ48k6DSZh5t9piWMl90R-gCBnY0ipLe875ZMfDtKts,418
|
||||
agentscope/plan/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/plan/__pycache__/_in_memory_storage.cpython-313.pyc,,
|
||||
agentscope/plan/__pycache__/_plan_model.cpython-313.pyc,,
|
||||
agentscope/plan/__pycache__/_plan_notebook.cpython-313.pyc,,
|
||||
agentscope/plan/__pycache__/_storage_base.cpython-313.pyc,,
|
||||
agentscope/plan/_in_memory_storage.py,sha256=I32B4nJCu7BYyb1Tgm4QLRI_K0Q27kMNRt96N-y0wLM,2094
|
||||
agentscope/plan/_plan_model.py,sha256=yb4KK_JL1C3QVoX4gCeiSghHFaE39ijq4lxbGm_viZI,6418
|
||||
agentscope/plan/_plan_notebook.py,sha256=LmZOJxQj862Bp4TR_gZU_lqF14uhPHVnENjVLVIOVas,32621
|
||||
agentscope/plan/_storage_base.py,sha256=M1BFqDIiHthFJQFi3gDZNaO12S9FZ_snTFMbqtTipIw,725
|
||||
agentscope/rag/__init__.py,sha256=ZCXDDkeHqYGyl-HuPpWzVj_5mP24fUXSDLpHRc0Hz-U,674
|
||||
agentscope/rag/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/rag/__pycache__/_document.cpython-313.pyc,,
|
||||
agentscope/rag/__pycache__/_knowledge_base.cpython-313.pyc,,
|
||||
agentscope/rag/__pycache__/_simple_knowledge.cpython-313.pyc,,
|
||||
agentscope/rag/_document.py,sha256=9UvKeKu0WBz2nwNj3cgvx6fouVzBa7LJFcDvpVXxw8A,1199
|
||||
agentscope/rag/_knowledge_base.py,sha256=pswLgq1VPKD9UiHns1I_dlI0m6A-9GNyAI67Pm_aJ2A,4441
|
||||
agentscope/rag/_reader/__init__.py,sha256=IvJ2FAphm5CgWoaI1CEPmJPArveQtZv5-Shfkf3yitg,413
|
||||
agentscope/rag/_reader/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/rag/_reader/__pycache__/_image_reader.cpython-313.pyc,,
|
||||
agentscope/rag/_reader/__pycache__/_pdf_reader.cpython-313.pyc,,
|
||||
agentscope/rag/_reader/__pycache__/_reader_base.cpython-313.pyc,,
|
||||
agentscope/rag/_reader/__pycache__/_text_reader.cpython-313.pyc,,
|
||||
agentscope/rag/_reader/__pycache__/_word_reader.cpython-313.pyc,,
|
||||
agentscope/rag/_reader/_image_reader.py,sha256=kY-jLuzaUyILsviOaO4Fzejupa7I_OJGCRVheo-D0YA,1902
|
||||
agentscope/rag/_reader/_pdf_reader.py,sha256=auptyMvJ6CFDOHqF-Z8s6gHoYtA5mldnQsz3k7AfSv8,2758
|
||||
agentscope/rag/_reader/_reader_base.py,sha256=qY5xkACT1H28lWLjUUFB-Dn_xqpUexPwJu-pMViTmVI,900
|
||||
agentscope/rag/_reader/_text_reader.py,sha256=Loq0fFMhj53mhZPcezG_hxIx3LQSD5FaTsxQmXDqZos,5046
|
||||
agentscope/rag/_reader/_word_reader.py,sha256=0eh_7d_Fa5_6g5xsMq7koSWz4Uv6y3fCPY3LoZ958TI,17385
|
||||
agentscope/rag/_simple_knowledge.py,sha256=rMqMEy6QInrjUOX85g8NRlG7LHSrip4hkYVcv17lOMA,2580
|
||||
agentscope/rag/_store/__init__.py,sha256=u7qAWDjacgKxfzIPD7LeDXb9pbvWX6WjgDrdvMyQzJM,305
|
||||
agentscope/rag/_store/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/rag/_store/__pycache__/_milvuslite_store.cpython-313.pyc,,
|
||||
agentscope/rag/_store/__pycache__/_qdrant_store.cpython-313.pyc,,
|
||||
agentscope/rag/_store/__pycache__/_store_base.cpython-313.pyc,,
|
||||
agentscope/rag/_store/_milvuslite_store.py,sha256=1FUs6zlVoOjwz3YLc-oFqyXqSQjEdKD_uNhCDjURqHI,9059
|
||||
agentscope/rag/_store/_qdrant_store.py,sha256=04Xsfr9WM7g7MNRyPO1hEd_-hbIqPkvexYKMY9ukR80,6250
|
||||
agentscope/rag/_store/_store_base.py,sha256=RaXNmcGu6kZMJjM7pfSjVWcv4iCxMt9LMbJpSMrI0ZM,1658
|
||||
agentscope/session/__init__.py,sha256=GY2Skir_T7y19pnywNVBZ3H3ePqsnShva-ljgeiCLiQ,196
|
||||
agentscope/session/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/session/__pycache__/_json_session.cpython-313.pyc,,
|
||||
agentscope/session/__pycache__/_session_base.cpython-313.pyc,,
|
||||
agentscope/session/_json_session.py,sha256=4NvJPK4qplKdASSHeu7BugpCSxO8BNHRbSNPzna6g-s,3820
|
||||
agentscope/session/_session_base.py,sha256=pKbEHnOHJuxaccGobPo2z984W3OrZS3Rl9oCwrpibMY,859
|
||||
agentscope/token/__init__.py,sha256=0PyydmrOKp-Al3CUqM_1WiCSZc9hSR3XEXV7mXCv48k,487
|
||||
agentscope/token/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/token/__pycache__/_anthropic_token_counter.cpython-313.pyc,,
|
||||
agentscope/token/__pycache__/_gemini_token_counter.cpython-313.pyc,,
|
||||
agentscope/token/__pycache__/_huggingface_token_counter.cpython-313.pyc,,
|
||||
agentscope/token/__pycache__/_openai_token_counter.cpython-313.pyc,,
|
||||
agentscope/token/__pycache__/_token_base.cpython-313.pyc,,
|
||||
agentscope/token/_anthropic_token_counter.py,sha256=-1c-OrsfaNvSCEHzgRNSFL7HUQCAuoe9q3nNEk4J9YE,1853
|
||||
agentscope/token/_gemini_token_counter.py,sha256=vcWHo8iHR1JLhDTM3pS6-mpxEUWCKceVll_ypq7mKhU,1385
|
||||
agentscope/token/_huggingface_token_counter.py,sha256=ksxFpqPde16VptiSV8RmHasgld1bp_fz16j6t4baWtk,2846
|
||||
agentscope/token/_openai_token_counter.py,sha256=Aq2YCnCOvPUOfr4r5OeQqqom_VRAPyUdckqIbx3giiQ,11365
|
||||
agentscope/token/_token_base.py,sha256=ukxfNg8nBL_MLd9rzkpy5aP8s-uqEKbeZGtAYZyCBzA,388
|
||||
agentscope/tool/__init__.py,sha256=lXMHKD91iPK2rSY53cDg39kMXwQsedG-rf39gFRd0Go,1020
|
||||
agentscope/tool/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/tool/__pycache__/_async_wrapper.cpython-313.pyc,,
|
||||
agentscope/tool/__pycache__/_registered_tool_function.cpython-313.pyc,,
|
||||
agentscope/tool/__pycache__/_response.cpython-313.pyc,,
|
||||
agentscope/tool/__pycache__/_toolkit.cpython-313.pyc,,
|
||||
agentscope/tool/_async_wrapper.py,sha256=tfv6edszdHC03IsL0Z3EvVAII0zEdYavD3wBI__L-zM,3474
|
||||
agentscope/tool/_coding/__init__.py,sha256=e_XNdZZo6-gS7EvY_AEM2h0q3XtYm1voCKbojypfwn4,232
|
||||
agentscope/tool/_coding/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/tool/_coding/__pycache__/_python.cpython-313.pyc,,
|
||||
agentscope/tool/_coding/__pycache__/_shell.cpython-313.pyc,,
|
||||
agentscope/tool/_coding/_python.py,sha256=FwnidjGPYBRsLGX0FPICjlApISg7eL4GZoVBvFrObik,2714
|
||||
agentscope/tool/_coding/_shell.py,sha256=pgivhc2CSs8mBWSh5ax9NgWI07q_b7WoKV7hdI8h448,2266
|
||||
agentscope/tool/_multi_modality/__init__.py,sha256=H9VpqWCV0V7WXvqqYWjbpwmafJHtq_pDm-RV7P3vG0s,678
|
||||
agentscope/tool/_multi_modality/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/tool/_multi_modality/__pycache__/_dashscope_tools.cpython-313.pyc,,
|
||||
agentscope/tool/_multi_modality/__pycache__/_openai_tools.cpython-313.pyc,,
|
||||
agentscope/tool/_multi_modality/_dashscope_tools.py,sha256=6piJ5fjVaQTYaq4w3UQXGS0ANY29lkCqyc3_keomlbY,8908
|
||||
agentscope/tool/_multi_modality/_openai_tools.py,sha256=UaZOHHAWEi7Y_uG_n23Q8OTh45Cb-hD4t5-oR6o4K_Q,20873
|
||||
agentscope/tool/_registered_tool_function.py,sha256=jI8VMSeWlj-EGq7IKlydBQcC2jjOZEDQTdnkxEm7jng,3449
|
||||
agentscope/tool/_response.py,sha256=3WdPFj1uRdxvkrECfMlUjzPVg-PseeSVNF5SWn1dCOs,938
|
||||
agentscope/tool/_text_file/__init__.py,sha256=tnQP6RCS1wHff65ycZkXE4Fxcw5OXZe50_6dD5hfa9o,276
|
||||
agentscope/tool/_text_file/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/tool/_text_file/__pycache__/_utils.cpython-313.pyc,,
|
||||
agentscope/tool/_text_file/__pycache__/_view_text_file.cpython-313.pyc,,
|
||||
agentscope/tool/_text_file/__pycache__/_write_text_file.cpython-313.pyc,,
|
||||
agentscope/tool/_text_file/_utils.py,sha256=vizy7C6rNmp8z5aiNbrrsMdoeX8bws4FnnyEixlo0jU,2645
|
||||
agentscope/tool/_text_file/_view_text_file.py,sha256=MHq0eiNiBMSDY7Dne8Ch6-YqIS0i8alP3dX2gzxi-nA,2280
|
||||
agentscope/tool/_text_file/_write_text_file.py,sha256=zZcafaRg53o2DT1Q1t9en4Z8sRxaRwREAbsfdLfSpOI,7333
|
||||
agentscope/tool/_toolkit.py,sha256=2iSCpI9zRmNgD_g_PVE-N8K060_DU4S9NDzQ7tvnW30,34654
|
||||
agentscope/tracing/__init__.py,sha256=R7Xegg62pD5UDey0w4ZyAJ6LVt6_qSkjlrOIoV3mHpk,382
|
||||
agentscope/tracing/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/tracing/__pycache__/_attributes.cpython-313.pyc,,
|
||||
agentscope/tracing/__pycache__/_setup.cpython-313.pyc,,
|
||||
agentscope/tracing/__pycache__/_trace.cpython-313.pyc,,
|
||||
agentscope/tracing/__pycache__/_types.cpython-313.pyc,,
|
||||
agentscope/tracing/_attributes.py,sha256=-R_z4rI17u4pOyK9RWtWPmKX0uEL1YmffcJhAEJanvM,1774
|
||||
agentscope/tracing/_setup.py,sha256=QwhHf_NyR-4lBJChNa616pze7CV7HPFq0mNoWxUnCQg,874
|
||||
agentscope/tracing/_trace.py,sha256=Iclrx0Uxpjq4OwrGfCvl_TADn7eSm85R2ZhJiwYdG-w,21677
|
||||
agentscope/tracing/_types.py,sha256=EE-Y6btCihsNuC27XiLlTdqLy1C4CCoENthPDerw8mU,528
|
||||
agentscope/tune/__init__.py,sha256=VpKbNhHLr6GAQ4zJJ-hEy9IOCqLB7YQTNt3DKQKbq0g,195
|
||||
agentscope/tune/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/tune/__pycache__/_tune.cpython-313.pyc,,
|
||||
agentscope/tune/__pycache__/_workflow.cpython-313.pyc,,
|
||||
agentscope/tune/_tune.py,sha256=elVcwVuRRlPghcaYQZAYhiwchV4VqIL-PDb86HaV_ws,2520
|
||||
agentscope/tune/_workflow.py,sha256=TLrri2aRfVamTzDK8FaeHUDDSZZnfhos8JvseeFoHiU,2125
|
||||
agentscope/types/__init__.py,sha256=_AX5wH9fPHkNEwCOQb2ycdh62J6IRXqYYcplJOcWjFQ,408
|
||||
agentscope/types/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/types/__pycache__/_hook.cpython-313.pyc,,
|
||||
agentscope/types/__pycache__/_json.cpython-313.pyc,,
|
||||
agentscope/types/__pycache__/_object.cpython-313.pyc,,
|
||||
agentscope/types/__pycache__/_tool.cpython-313.pyc,,
|
||||
agentscope/types/_hook.py,sha256=st--2oBVuLwNaNk5DQXkYA7xp8X4HaqTaXf2lVDAPM0,427
|
||||
agentscope/types/_json.py,sha256=MXTFO_TufiyRy0X_OuEfuoPqWLRUYRRwurKu-o-m5oI,308
|
||||
agentscope/types/_object.py,sha256=dHR84mJvBFesbYj46mQO9ssw38dPuKpJaCbySprLWZE,111
|
||||
agentscope/types/_tool.py,sha256=J22DtLNDoMTZp_cOkGfrjpmG-qFPWgqaKhcXsyomC58,845
|
||||
@@ -1,5 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: setuptools (80.9.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@@ -1,391 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2024 Alibaba
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
Some codes of tests/run.py is modified from
|
||||
https://github.com/alibaba/FederatedScope/blob/master/tests/run.py, which is
|
||||
also licensed under the terms of the Apache 2.0.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Code in src/agentscope/web/static/js/socket.io.js is adapted from
|
||||
https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.3/socket.io.js (MIT License)
|
||||
|
||||
Copyright (c) 2014-2021 Guillermo Rauch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Code in src/agentscope/web/static/js/jquery-3.3.1.min.js is adapted from
|
||||
https://code.jquery.com/jquery-3.3.1.min.js (MIT License)
|
||||
|
||||
Copyright (c) JS Foundation and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Code in src/agentscope/web/static/js/bootstrap.bundle.min.js is adapted from
|
||||
https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/js/bootstrap.bundle.min.js
|
||||
(MIT License)
|
||||
|
||||
Copyright (c) 2011-2019 The Bootstrap Authors (https://github
|
||||
.com/twbs/bootstrap/graphs/contributors)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Code in src/agentscope/web/static/js/bootstrap-table.min.js is adapted from
|
||||
https://unpkg.com/bootstrap-table@1.18.0/dist/bootstrap-table.min.js (MIT
|
||||
License)
|
||||
|
||||
Copyright (c) wenzhixin <wenzhixin2010@gmail.com> (http://wenzhixin.net.cn/)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Code in src/agentscope/web/static/css/bootstrap.min.css is adapted from
|
||||
https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css (MIT
|
||||
License)
|
||||
|
||||
Copyright 2011-2019 The Bootstrap Authors
|
||||
Copyright 2011-2019 Twitter, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Fonts in src/agentscope/web/static/fonts/KRYPTON.ttf is adapted from
|
||||
https://github.com/githubnext/monaspace (SIL Open Font License 1.1). These
|
||||
fonts are distributed with their original license. See https://github
|
||||
.com/githubnext/monaspace/blob/main/LICENSE for the full text of the license.
|
||||
The following font families are included:
|
||||
|
||||
- Monaspace (with subfamilies: Krypton)
|
||||
|
||||
Copyright (c) 2023, GitHub https://github.com/githubnext/monaspace
|
||||
with Reserved Font Name "Monaspace", including subfamilies: "Argon", "Neon",
|
||||
"Xenon", "Radon", and "Krypton"
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Fonts in src/agentscope/web/static/fonts/OSWALD.ttf is adapted from
|
||||
https://fonts.google.com/specimen/Oswald (SIL Open Font License 1.1). These
|
||||
fonts are distributed with their original license. See https://github
|
||||
.com/googlefonts/OswaldFont/blob/main/OFL.txt for the full text of the license.
|
||||
|
||||
Copyright 2016 The Oswald Project Authors (https://github
|
||||
.com/googlefonts/OswaldFont)
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
@@ -1 +0,0 @@
|
||||
agentscope
|
||||
@@ -1,133 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The agentscope serialization module"""
|
||||
import os
|
||||
|
||||
import requests
|
||||
|
||||
from . import exception
|
||||
from . import module
|
||||
from . import message
|
||||
from . import model
|
||||
from . import tool
|
||||
from . import formatter
|
||||
from . import memory
|
||||
from . import agent
|
||||
from . import session
|
||||
from . import embedding
|
||||
from . import token
|
||||
from . import evaluate
|
||||
from . import pipeline
|
||||
from . import tracing
|
||||
from . import rag
|
||||
|
||||
from ._logging import (
|
||||
logger,
|
||||
setup_logger,
|
||||
)
|
||||
from .hooks import _equip_as_studio_hooks
|
||||
from ._version import __version__
|
||||
|
||||
|
||||
def init(
|
||||
project: str | None = None,
|
||||
name: str | None = None,
|
||||
logging_path: str | None = None,
|
||||
logging_level: str = "INFO",
|
||||
studio_url: str | None = None,
|
||||
tracing_url: str | None = None,
|
||||
) -> None:
|
||||
"""Initialize the agentscope library.
|
||||
|
||||
Args:
|
||||
project (`str | None`, optional):
|
||||
The project name.
|
||||
name (`str | None`, optional):
|
||||
The name of the run.
|
||||
logging_path (`str | None`, optional):
|
||||
The path to saving the log file. If not provided, logs will not be
|
||||
saved.
|
||||
logging_level (`str | None`, optional):
|
||||
The logging level. Defaults to "INFO".
|
||||
studio_url (`str | None`, optional):
|
||||
The URL of the AgentScope Studio to connect to.
|
||||
tracing_url (`str | None`, optional):
|
||||
The URL of the tracing endpoint, which can connect to third-party
|
||||
OpenTelemetry tracing platforms like Arize-Phoenix and Langfuse.
|
||||
If not provided and `studio_url` is provided, it will send traces
|
||||
to the AgentScope Studio's tracing endpoint.
|
||||
"""
|
||||
|
||||
from . import _config
|
||||
|
||||
if project:
|
||||
_config.project = project
|
||||
|
||||
if name:
|
||||
_config.name = name
|
||||
|
||||
setup_logger(logging_level, logging_path)
|
||||
|
||||
if studio_url:
|
||||
# Register the run
|
||||
data = {
|
||||
"id": _config.run_id,
|
||||
"project": _config.project,
|
||||
"name": _config.name,
|
||||
"timestamp": _config.created_at,
|
||||
"pid": os.getpid(),
|
||||
"status": "running",
|
||||
# Deprecated fields
|
||||
"run_dir": "",
|
||||
}
|
||||
response = requests.post(
|
||||
url=f"{studio_url}/trpc/registerRun",
|
||||
json=data,
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
from .agent import UserAgent, StudioUserInput
|
||||
|
||||
UserAgent.override_class_input_method(
|
||||
StudioUserInput(
|
||||
studio_url=studio_url,
|
||||
run_id=_config.run_id,
|
||||
max_retries=3,
|
||||
),
|
||||
)
|
||||
|
||||
_equip_as_studio_hooks(studio_url)
|
||||
|
||||
if tracing_url:
|
||||
endpoint = tracing_url
|
||||
else:
|
||||
endpoint = studio_url.strip("/") + "/v1/traces" if studio_url else None
|
||||
|
||||
if endpoint:
|
||||
from .tracing import setup_tracing
|
||||
|
||||
setup_tracing(endpoint=endpoint)
|
||||
|
||||
|
||||
__all__ = [
|
||||
# modules
|
||||
"exception",
|
||||
"module",
|
||||
"message",
|
||||
"model",
|
||||
"tool",
|
||||
"formatter",
|
||||
"memory",
|
||||
"agent",
|
||||
"session",
|
||||
"logger",
|
||||
"embedding",
|
||||
"token",
|
||||
"evaluate",
|
||||
"pipeline",
|
||||
"tracing",
|
||||
"rag",
|
||||
# functions
|
||||
"init",
|
||||
"setup_logger",
|
||||
"__version__",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,23 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The runtime configuration in agentscope.
|
||||
|
||||
.. note:: You should import this module as ``import ._config``, then use the
|
||||
variables defined in this module, instead of ``from ._config import xxx``.
|
||||
Because when the variables are changed, the changes will not be reflected in
|
||||
the imported module.
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
import shortuuid
|
||||
|
||||
|
||||
def _generate_random_suffix(length: int) -> str:
|
||||
"""Generate a random suffix."""
|
||||
return shortuuid.uuid()[:length]
|
||||
|
||||
|
||||
project = "UnnamedProject_At" + datetime.now().strftime("%Y%m%d")
|
||||
name = datetime.now().strftime("%H%M%S_") + _generate_random_suffix(4)
|
||||
run_id: str = shortuuid.uuid()
|
||||
created_at: str = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
|
||||
trace_enabled: bool = False
|
||||
@@ -1,47 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The logger for agentscope."""
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
_DEFAULT_FORMAT = (
|
||||
"%(asctime)s | %(levelname)-7s | "
|
||||
"%(module)s:%(funcName)s:%(lineno)s - %(message)s"
|
||||
)
|
||||
|
||||
logger = logging.getLogger("as")
|
||||
|
||||
|
||||
def setup_logger(
|
||||
level: str,
|
||||
filepath: str | None = None,
|
||||
) -> None:
|
||||
"""Set up the agentscope logger.
|
||||
|
||||
Args:
|
||||
level (`str`):
|
||||
The logging level, chosen from "INFO", "DEBUG", "WARNING",
|
||||
"ERROR", "CRITICAL".
|
||||
filepath (`str | None`, optional):
|
||||
The filepath to save the logging output.
|
||||
"""
|
||||
if level not in ["INFO", "DEBUG", "WARNING", "ERROR", "CRITICAL"]:
|
||||
raise ValueError(
|
||||
f"Invalid logging level: {level}. Must be one of "
|
||||
f"'INFO', 'DEBUG', 'WARNING', 'ERROR', 'CRITICAL'.",
|
||||
)
|
||||
logger.handlers.clear()
|
||||
logger.setLevel(level)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setFormatter(logging.Formatter(_DEFAULT_FORMAT))
|
||||
logger.addHandler(handler)
|
||||
|
||||
if filepath:
|
||||
handler = logging.FileHandler(filepath)
|
||||
handler.setFormatter(logging.Formatter(_DEFAULT_FORMAT))
|
||||
logger.addHandler(handler)
|
||||
|
||||
logger.propagate = False
|
||||
|
||||
|
||||
setup_logger("INFO")
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,285 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The common utilities for agentscope library."""
|
||||
import asyncio
|
||||
import base64
|
||||
import functools
|
||||
import inspect
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
import types
|
||||
import typing
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Union, Any, Callable, Type, Dict
|
||||
|
||||
import requests
|
||||
from json_repair import repair_json
|
||||
from pydantic import BaseModel
|
||||
|
||||
from .._logging import logger
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from mcp.types import Tool
|
||||
else:
|
||||
Tool = "mcp.types.Tool"
|
||||
|
||||
|
||||
def _json_loads_with_repair(
|
||||
json_str: str,
|
||||
) -> Union[dict, list, str, float, int, bool, None]:
|
||||
"""The given json_str maybe incomplete, e.g. '{"key', so we need to
|
||||
repair and load it into a Python object.
|
||||
"""
|
||||
repaired = json_str
|
||||
try:
|
||||
repaired = repair_json(json_str)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
return json.loads(repaired)
|
||||
except json.JSONDecodeError as e:
|
||||
raise ValueError(
|
||||
f"Failed to decode JSON string `{json_str}` after repairing it "
|
||||
f"into `{repaired}`. Error: {e}",
|
||||
) from e
|
||||
|
||||
|
||||
def _is_accessible_local_file(url: str) -> bool:
|
||||
"""Check if the given URL is a local URL."""
|
||||
return os.path.isfile(url)
|
||||
|
||||
|
||||
def _get_timestamp(add_random_suffix: bool = False) -> str:
|
||||
"""Get the current timestamp in the format YYYY-MM-DD HH:MM:SS.sss."""
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
|
||||
|
||||
if add_random_suffix:
|
||||
# Add a random suffix to the timestamp
|
||||
timestamp += f"_{os.urandom(3).hex()}"
|
||||
|
||||
return timestamp
|
||||
|
||||
|
||||
async def _is_async_func(func: Callable) -> bool:
|
||||
"""Check if the given function is an async function, including
|
||||
coroutine functions, async generators, and coroutine objects.
|
||||
"""
|
||||
|
||||
return (
|
||||
inspect.iscoroutinefunction(func)
|
||||
or inspect.isasyncgenfunction(func)
|
||||
or isinstance(func, types.CoroutineType)
|
||||
or isinstance(func, types.GeneratorType)
|
||||
and asyncio.iscoroutine(func)
|
||||
or isinstance(func, functools.partial)
|
||||
and await _is_async_func(func.func)
|
||||
)
|
||||
|
||||
|
||||
async def _execute_async_or_sync_func(
|
||||
func: Callable,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Execute an async or sync function based on its type.
|
||||
|
||||
Args:
|
||||
func (`Callable`):
|
||||
The function to be executed, which can be either async or sync.
|
||||
*args (`Any`):
|
||||
Positional arguments to be passed to the function.
|
||||
**kwargs (`Any`):
|
||||
Keyword arguments to be passed to the function.
|
||||
|
||||
Returns:
|
||||
`Any`:
|
||||
The result of the function execution.
|
||||
"""
|
||||
|
||||
if await _is_async_func(func):
|
||||
return await func(*args, **kwargs)
|
||||
|
||||
return func(*args, **kwargs)
|
||||
|
||||
|
||||
def _get_bytes_from_web_url(
|
||||
url: str,
|
||||
max_retries: int = 3,
|
||||
) -> str:
|
||||
"""Get the bytes from a given URL.
|
||||
|
||||
Args:
|
||||
url (`str`):
|
||||
The URL to fetch the bytes from.
|
||||
max_retries (`int`, defaults to `3`):
|
||||
The maximum number of retries.
|
||||
"""
|
||||
for _ in range(max_retries):
|
||||
try:
|
||||
response = requests.get(url)
|
||||
response.raise_for_status()
|
||||
return response.content.decode("utf-8")
|
||||
|
||||
except UnicodeDecodeError:
|
||||
return base64.b64encode(response.content).decode("ascii")
|
||||
|
||||
except Exception as e:
|
||||
logger.info(
|
||||
"Failed to fetch bytes from URL %s. Error %s. Retrying...",
|
||||
url,
|
||||
str(e),
|
||||
)
|
||||
|
||||
raise RuntimeError(
|
||||
f"Failed to fetch bytes from URL `{url}` after {max_retries} retries.",
|
||||
)
|
||||
|
||||
|
||||
def _save_base64_data(
|
||||
media_type: str,
|
||||
base64_data: str,
|
||||
) -> str:
|
||||
"""Save the base64 data to a temp file and return the file path. The
|
||||
extension is guessed from the MIME type.
|
||||
|
||||
Args:
|
||||
media_type (`str`):
|
||||
The MIME type of the data, e.g. "image/png", "audio/mpeg".
|
||||
base64_data (`str):
|
||||
The base64 data to be saved.
|
||||
"""
|
||||
extension = "." + media_type.split("/")[-1]
|
||||
|
||||
with tempfile.NamedTemporaryFile(
|
||||
suffix=f".{extension}",
|
||||
delete=False,
|
||||
) as temp_file:
|
||||
decoded_data = base64.b64decode(base64_data)
|
||||
temp_file.write(decoded_data)
|
||||
temp_file.close()
|
||||
return temp_file.name
|
||||
|
||||
|
||||
def _extract_json_schema_from_mcp_tool(tool: Tool) -> dict[str, Any]:
|
||||
"""Extract JSON schema from MCP tool."""
|
||||
|
||||
return {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": tool.name,
|
||||
"description": tool.description,
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": tool.inputSchema.get(
|
||||
"properties",
|
||||
{},
|
||||
),
|
||||
"required": tool.inputSchema.get(
|
||||
"required",
|
||||
[],
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _remove_title_field(schema: dict) -> None:
|
||||
"""Remove the title field from the JSON schema to avoid
|
||||
misleading the LLM."""
|
||||
# The top level title field
|
||||
if "title" in schema:
|
||||
schema.pop("title")
|
||||
|
||||
# properties
|
||||
if "properties" in schema:
|
||||
for prop in schema["properties"].values():
|
||||
if isinstance(prop, dict):
|
||||
_remove_title_field(prop)
|
||||
|
||||
# items
|
||||
if "items" in schema and isinstance(schema["items"], dict):
|
||||
_remove_title_field(schema["items"])
|
||||
|
||||
# additionalProperties
|
||||
if "additionalProperties" in schema and isinstance(
|
||||
schema["additionalProperties"],
|
||||
dict,
|
||||
):
|
||||
_remove_title_field(
|
||||
schema["additionalProperties"],
|
||||
)
|
||||
|
||||
|
||||
def _create_tool_from_base_model(
|
||||
structured_model: Type[BaseModel],
|
||||
tool_name: str = "generate_structured_output",
|
||||
) -> Dict[str, Any]:
|
||||
"""Create a function tool definition from a Pydantic BaseModel.
|
||||
This function converts a Pydantic BaseModel class into a tool definition
|
||||
that can be used with function calling API. The resulting tool
|
||||
definition includes the model's JSON schema as parameters, enabling
|
||||
structured output generation by forcing the model to call this function
|
||||
with properly formatted data.
|
||||
|
||||
Args:
|
||||
structured_model (`Type[BaseModel]`):
|
||||
A Pydantic BaseModel class that defines the expected structure
|
||||
for the tool's output.
|
||||
tool_name (`str`, default `"generate_structured_output"`):
|
||||
The tool name that used to force the LLM to generate structured
|
||||
output by calling this function.
|
||||
|
||||
Returns:
|
||||
`Dict[str, Any]`: A tool definition dictionary compatible with
|
||||
function calling API, containing type ("function") and
|
||||
function dictionary with name, description, and parameters
|
||||
(JSON schema).
|
||||
|
||||
.. code-block:: python
|
||||
:caption: Example usage
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
class PersonInfo(BaseModel):
|
||||
name: str
|
||||
age: int
|
||||
email: str
|
||||
|
||||
tool = _create_tool_from_base_model(PersonInfo, "extract_person")
|
||||
print(tool["function"]["name"]) # extract_person
|
||||
print(tool["type"]) # function
|
||||
|
||||
.. note:: The function automatically removes the 'title' field from
|
||||
the JSON schema to ensure compatibility with function calling
|
||||
format. This is handled by the internal ``_remove_title_field()``
|
||||
function.
|
||||
"""
|
||||
schema = structured_model.model_json_schema()
|
||||
|
||||
_remove_title_field(schema)
|
||||
tool_definition = {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": tool_name,
|
||||
"description": "Generate the required structured output with "
|
||||
"this function",
|
||||
"parameters": schema,
|
||||
},
|
||||
}
|
||||
return tool_definition
|
||||
|
||||
|
||||
def _map_text_to_uuid(text: str) -> str:
|
||||
"""Map the given text to a deterministic UUID string.
|
||||
|
||||
Args:
|
||||
text (`str`):
|
||||
The input text to be mapped to a UUID.
|
||||
|
||||
Returns:
|
||||
`str`:
|
||||
A deterministic UUID string derived from the input text.
|
||||
"""
|
||||
return str(uuid.uuid3(uuid.NAMESPACE_DNS, text))
|
||||
@@ -1,9 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The mixin for agentscope."""
|
||||
|
||||
|
||||
class DictMixin(dict):
|
||||
"""The dictionary mixin that allows attribute-style access."""
|
||||
|
||||
__setattr__ = dict.__setitem__
|
||||
__getattr__ = dict.__getitem__
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The version of agentscope."""
|
||||
|
||||
__version__ = "1.0.7"
|
||||
@@ -1,24 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The agent base class."""
|
||||
from ._agent_base import AgentBase
|
||||
from ._react_agent_base import ReActAgentBase
|
||||
from ._react_agent import ReActAgent
|
||||
from ._user_input import (
|
||||
UserInputBase,
|
||||
UserInputData,
|
||||
TerminalUserInput,
|
||||
StudioUserInput,
|
||||
)
|
||||
from ._user_agent import UserAgent
|
||||
|
||||
|
||||
__all__ = [
|
||||
"AgentBase",
|
||||
"ReActAgentBase",
|
||||
"ReActAgent",
|
||||
"UserInputData",
|
||||
"UserInputBase",
|
||||
"TerminalUserInput",
|
||||
"StudioUserInput",
|
||||
"UserAgent",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,703 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The agent base class in agentscope."""
|
||||
import asyncio
|
||||
import io
|
||||
import json
|
||||
from asyncio import Task, Queue
|
||||
from collections import OrderedDict
|
||||
from copy import deepcopy
|
||||
from typing import Callable, Any
|
||||
import base64
|
||||
import shortuuid
|
||||
import numpy as np
|
||||
from typing_extensions import deprecated
|
||||
|
||||
from ._agent_meta import _AgentMeta
|
||||
from .._logging import logger
|
||||
from ..module import StateModule
|
||||
from ..message import (
|
||||
Msg,
|
||||
AudioBlock,
|
||||
ToolUseBlock,
|
||||
ToolResultBlock,
|
||||
ImageBlock,
|
||||
VideoBlock,
|
||||
)
|
||||
from ..types import AgentHookTypes
|
||||
|
||||
|
||||
class AgentBase(StateModule, metaclass=_AgentMeta):
|
||||
"""Base class for asynchronous agents."""
|
||||
|
||||
id: str
|
||||
"""The agent's unique identifier, generated using shortuuid."""
|
||||
|
||||
supported_hook_types: list[str] = [
|
||||
"pre_reply",
|
||||
"post_reply",
|
||||
"pre_print",
|
||||
"post_print",
|
||||
"pre_observe",
|
||||
"post_observe",
|
||||
]
|
||||
"""Supported hook types for the agent base class."""
|
||||
|
||||
_class_pre_reply_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"AgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
],
|
||||
dict[str, Any] | None, # The modified kwargs or None
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level hook functions that will be called before the reply
|
||||
function, taking `self` object, the input arguments as input, and
|
||||
generating the modified arguments (if needed). Then input arguments of the
|
||||
reply function will be re-organized into a keyword arguments dictionary.
|
||||
If the one hook returns a new dictionary, the modified arguments will be
|
||||
passed to the next hook or the original reply function."""
|
||||
|
||||
_class_post_reply_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"AgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
Msg, # output, the output message
|
||||
],
|
||||
Msg | None,
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level hook functions that will be called after the reply
|
||||
function, which takes the `self` object and deep copied
|
||||
positional and keyword arguments (args and kwargs), and the output message
|
||||
as input. If the hook returns a message, the new message will be passed
|
||||
to the next hook or the original reply function. Otherwise, the original
|
||||
output will be passed instead."""
|
||||
|
||||
_class_pre_print_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"AgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
],
|
||||
dict[str, Any] | None, # The modified kwargs or None
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level hook functions that will be called before printing,
|
||||
which takes the `self` object, a deep copied arguments dictionary as input,
|
||||
and output the modified arguments (if needed). """
|
||||
|
||||
_class_post_print_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"AgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
Any, # output, `None` if no output
|
||||
],
|
||||
Any,
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level hook functions that will be called after the speak
|
||||
function, which takes the `self` object as input."""
|
||||
|
||||
_class_pre_observe_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"AgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
],
|
||||
dict[str, Any] | None, # The modified kwargs or None
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level hook functions that will be called before the observe
|
||||
function, which takes the `self` object and a deep copied input
|
||||
arguments dictionary as input. To change the input arguments, the hook
|
||||
function needs to output the modified arguments dictionary, which will be
|
||||
used as the input of the next hook function or the original observe
|
||||
function."""
|
||||
|
||||
_class_post_observe_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"AgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
None, # The output, `None` if no output
|
||||
],
|
||||
None,
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level hook functions that will be called after the observe
|
||||
function, which takes the `self` object as input."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize the agent."""
|
||||
super().__init__()
|
||||
|
||||
self.id = shortuuid.uuid()
|
||||
|
||||
# The replying task and identify of the current replying
|
||||
self._reply_task: Task | None = None
|
||||
self._reply_id: str | None = None
|
||||
|
||||
# Initialize the instance-level hooks
|
||||
self._instance_pre_print_hooks = OrderedDict()
|
||||
self._instance_post_print_hooks = OrderedDict()
|
||||
|
||||
self._instance_pre_reply_hooks = OrderedDict()
|
||||
self._instance_post_reply_hooks = OrderedDict()
|
||||
|
||||
self._instance_pre_observe_hooks = OrderedDict()
|
||||
self._instance_post_observe_hooks = OrderedDict()
|
||||
|
||||
# The prefix used in streaming printing, which will save the
|
||||
# accumulated text and audio streaming data for each message id.
|
||||
# e.g. {"text": "xxx", "audio": (stream_obj, "{base64_data}")}
|
||||
self._stream_prefix = {}
|
||||
|
||||
# The subscribers that will receive the reply message by their
|
||||
# `observe` method. The key is the MsgHub id, and the value is the
|
||||
# list of agents.
|
||||
self._subscribers: dict[str, list[AgentBase]] = {}
|
||||
|
||||
# We add this variable in case developers want to disable the console
|
||||
# output of the agent, e.g., in a production environment.
|
||||
self._disable_console_output: bool = False
|
||||
|
||||
# The streaming message queue used to export the messages as a
|
||||
# generator
|
||||
self._disable_msg_queue: bool = True
|
||||
self.msg_queue = None
|
||||
|
||||
async def observe(self, msg: Msg | list[Msg] | None) -> None:
|
||||
"""Receive the given message(s) without generating a reply.
|
||||
|
||||
Args:
|
||||
msg (`Msg | list[Msg] | None`):
|
||||
The message(s) to be observed.
|
||||
"""
|
||||
raise NotImplementedError(
|
||||
f"The observe function is not implemented in"
|
||||
f" {self.__class__.__name__} class.",
|
||||
)
|
||||
|
||||
async def reply(self, *args: Any, **kwargs: Any) -> Msg:
|
||||
"""The main logic of the agent, which generates a reply based on the
|
||||
current state and input arguments."""
|
||||
raise NotImplementedError(
|
||||
"The reply function is not implemented in "
|
||||
f"{self.__class__.__name__} class.",
|
||||
)
|
||||
|
||||
async def print(self, msg: Msg, last: bool = True) -> None:
|
||||
"""The function to display the message.
|
||||
|
||||
Args:
|
||||
msg (`Msg`):
|
||||
The message object to be printed.
|
||||
last (`bool`, defaults to `True`):
|
||||
Whether this is the last one in streaming messages. For
|
||||
non-streaming message, this should always be `True`.
|
||||
"""
|
||||
if not self._disable_msg_queue:
|
||||
await self.msg_queue.put((deepcopy(msg), last))
|
||||
|
||||
if self._disable_console_output:
|
||||
return
|
||||
|
||||
# The accumulated textual content to print, including the text blocks
|
||||
# and the thinking blocks
|
||||
thinking_and_text_to_print = []
|
||||
|
||||
for block in msg.get_content_blocks():
|
||||
if block["type"] == "audio":
|
||||
self._process_audio_block(msg.id, block)
|
||||
|
||||
elif block["type"] == "text":
|
||||
self._print_text_block(
|
||||
msg.id,
|
||||
name_prefix=msg.name,
|
||||
text_content=block["text"],
|
||||
thinking_and_text_to_print=thinking_and_text_to_print,
|
||||
)
|
||||
|
||||
elif block["type"] == "thinking":
|
||||
self._print_text_block(
|
||||
msg.id,
|
||||
name_prefix=f"{msg.name}(thinking)",
|
||||
text_content=block["thinking"],
|
||||
thinking_and_text_to_print=thinking_and_text_to_print,
|
||||
)
|
||||
|
||||
elif last:
|
||||
self._print_last_block(block, msg)
|
||||
|
||||
# Clean up resources if this is the last message in streaming
|
||||
if last and msg.id in self._stream_prefix:
|
||||
if "audio" in self._stream_prefix[msg.id]:
|
||||
player, _ = self._stream_prefix[msg.id]["audio"]
|
||||
# Close the miniaudio player
|
||||
player.close()
|
||||
stream_prefix = self._stream_prefix.pop(msg.id)
|
||||
if "text" in stream_prefix and not stream_prefix["text"].endswith(
|
||||
"\n",
|
||||
):
|
||||
print()
|
||||
|
||||
def _process_audio_block(
|
||||
self,
|
||||
msg_id: str,
|
||||
audio_block: AudioBlock,
|
||||
) -> None:
|
||||
"""Process audio block content.
|
||||
|
||||
Args:
|
||||
msg_id (`str`):
|
||||
The unique identifier of the message
|
||||
audio_block (`AudioBlock`):
|
||||
The audio content block
|
||||
"""
|
||||
if "source" not in audio_block:
|
||||
raise ValueError(
|
||||
"The audio block must contain the 'source' field.",
|
||||
)
|
||||
|
||||
if audio_block["source"]["type"] == "url":
|
||||
import urllib.request
|
||||
import wave
|
||||
import sounddevice as sd
|
||||
|
||||
url = audio_block["source"]["url"]
|
||||
try:
|
||||
with urllib.request.urlopen(url) as response:
|
||||
audio_data = response.read()
|
||||
|
||||
with wave.open(io.BytesIO(audio_data), "rb") as wf:
|
||||
samplerate = wf.getframerate()
|
||||
n_frames = wf.getnframes()
|
||||
audio_frames = wf.readframes(n_frames)
|
||||
|
||||
# Convert byte data to numpy array
|
||||
audio_np = np.frombuffer(audio_frames, dtype=np.int16)
|
||||
|
||||
# Play audio
|
||||
sd.play(audio_np, samplerate)
|
||||
sd.wait()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Failed to play audio from url %s: %s",
|
||||
url,
|
||||
str(e),
|
||||
)
|
||||
|
||||
elif audio_block["source"]["type"] == "base64":
|
||||
data = audio_block["source"]["data"]
|
||||
|
||||
if msg_id not in self._stream_prefix:
|
||||
self._stream_prefix[msg_id] = {}
|
||||
|
||||
audio_prefix = self._stream_prefix[msg_id].get("audio", None)
|
||||
|
||||
import sounddevice as sd
|
||||
|
||||
# The player and the prefix data is cached for streaming audio
|
||||
if audio_prefix:
|
||||
player, audio_prefix_data = audio_prefix
|
||||
else:
|
||||
player = sd.OutputStream(
|
||||
samplerate=24000,
|
||||
channels=1,
|
||||
dtype=np.float32,
|
||||
blocksize=1024,
|
||||
latency="low",
|
||||
)
|
||||
player.start()
|
||||
audio_prefix_data = ""
|
||||
|
||||
# play the audio data
|
||||
new_audio_data = data[len(audio_prefix_data) :]
|
||||
if new_audio_data:
|
||||
audio_bytes = base64.b64decode(new_audio_data)
|
||||
audio_np = np.frombuffer(audio_bytes, dtype=np.int16)
|
||||
audio_float = audio_np.astype(np.float32) / 32768.0
|
||||
|
||||
# Write to the audio output stream
|
||||
player.write(audio_float)
|
||||
|
||||
# save the player and the prefix data
|
||||
self._stream_prefix[msg_id]["audio"] = (
|
||||
player,
|
||||
data,
|
||||
)
|
||||
|
||||
else:
|
||||
raise ValueError(
|
||||
"Unsupported audio source type: "
|
||||
f"{audio_block['source']['type']}",
|
||||
)
|
||||
|
||||
def _print_text_block(
|
||||
self,
|
||||
msg_id: str,
|
||||
name_prefix: str,
|
||||
text_content: str,
|
||||
thinking_and_text_to_print: list[str],
|
||||
) -> None:
|
||||
"""Print the text block and thinking block content.
|
||||
|
||||
Args:
|
||||
msg_id (`str`):
|
||||
The unique identifier of the message
|
||||
name_prefix (`str`):
|
||||
The prefix for the message, e.g. "{name}: " for text block and
|
||||
"{name}(thinking): " for thinking block.
|
||||
text_content (`str`):
|
||||
The textual content to be printed.
|
||||
thinking_and_text_to_print (`list[str]`):
|
||||
A list of textual content to be printed together. Here we
|
||||
gather the text and thinking blocks to print them together.
|
||||
"""
|
||||
thinking_and_text_to_print.append(
|
||||
f"{name_prefix}: {text_content}",
|
||||
)
|
||||
# The accumulated text and thinking blocks to print
|
||||
to_print = "\n".join(thinking_and_text_to_print)
|
||||
|
||||
# The text prefix that has been printed
|
||||
if msg_id not in self._stream_prefix:
|
||||
self._stream_prefix[msg_id] = {}
|
||||
|
||||
text_prefix = self._stream_prefix[msg_id].get("text", "")
|
||||
|
||||
# Only print when there is new text content
|
||||
if len(to_print) > len(text_prefix):
|
||||
print(to_print[len(text_prefix) :], end="")
|
||||
|
||||
# Save the printed text prefix
|
||||
self._stream_prefix[msg_id]["text"] = to_print
|
||||
|
||||
def _print_last_block(
|
||||
self,
|
||||
block: ToolUseBlock | ToolResultBlock | ImageBlock | VideoBlock,
|
||||
msg: Msg,
|
||||
) -> None:
|
||||
"""Process and print the last content block, and the block type
|
||||
is not audio, text, or thinking.
|
||||
|
||||
Args:
|
||||
block (`ToolUseBlock | ToolResultBlock | ImageBlock | VideoBlock`):
|
||||
The content block to be printed
|
||||
msg (`Msg`):
|
||||
The message object
|
||||
"""
|
||||
text_prefix = self._stream_prefix.get(msg.id, {}).get("text", "")
|
||||
|
||||
if text_prefix:
|
||||
# Add a newline to separate from previous text content
|
||||
print_newline = "" if text_prefix.endswith("\n") else "\n"
|
||||
print(
|
||||
f"{print_newline}"
|
||||
f"{json.dumps(block, indent=4, ensure_ascii=False)}",
|
||||
)
|
||||
else:
|
||||
print(
|
||||
f"{msg.name}:"
|
||||
f" {json.dumps(block, indent=4, ensure_ascii=False)}",
|
||||
)
|
||||
|
||||
async def __call__(self, *args: Any, **kwargs: Any) -> Msg:
|
||||
"""Call the reply function with the given arguments."""
|
||||
self._reply_id = shortuuid.uuid()
|
||||
|
||||
reply_msg: Msg | None = None
|
||||
try:
|
||||
self._reply_task = asyncio.current_task()
|
||||
reply_msg = await self.reply(*args, **kwargs)
|
||||
|
||||
# The interruption is triggered by calling the interrupt method
|
||||
except asyncio.CancelledError:
|
||||
reply_msg = await self.handle_interrupt(*args, **kwargs)
|
||||
|
||||
finally:
|
||||
# Broadcast the reply message to all subscribers
|
||||
if reply_msg:
|
||||
await self._broadcast_to_subscribers(reply_msg)
|
||||
self._reply_task = None
|
||||
|
||||
return reply_msg
|
||||
|
||||
async def _broadcast_to_subscribers(
|
||||
self,
|
||||
msg: Msg | list[Msg] | None,
|
||||
) -> None:
|
||||
"""Broadcast the message to all subscribers."""
|
||||
for subscribers in self._subscribers.values():
|
||||
for subscriber in subscribers:
|
||||
await subscriber.observe(msg)
|
||||
|
||||
async def handle_interrupt(
|
||||
self,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> Msg:
|
||||
"""The post-processing logic when the reply is interrupted by the
|
||||
user or something else."""
|
||||
raise NotImplementedError(
|
||||
f"The handle_interrupt function is not implemented in "
|
||||
f"{self.__class__.__name__}",
|
||||
)
|
||||
|
||||
async def interrupt(self, msg: Msg | list[Msg] | None = None) -> None:
|
||||
"""Interrupt the current reply process."""
|
||||
if self._reply_task and not self._reply_task.done():
|
||||
self._reply_task.cancel(msg)
|
||||
|
||||
def register_instance_hook(
|
||||
self,
|
||||
hook_type: AgentHookTypes,
|
||||
hook_name: str,
|
||||
hook: Callable,
|
||||
) -> None:
|
||||
"""Register a hook to the agent instance, which only takes effect
|
||||
for the current instance.
|
||||
|
||||
Args:
|
||||
hook_type (`str`):
|
||||
The type of the hook, indicating where the hook is to be
|
||||
triggered.
|
||||
hook_name (`str`):
|
||||
The name of the hook. If the name is already registered, the
|
||||
hook will be overwritten.
|
||||
hook (`Callable`):
|
||||
The hook function.
|
||||
"""
|
||||
if not isinstance(self, AgentBase):
|
||||
raise TypeError(
|
||||
"The register_instance_hook method should be called on an "
|
||||
f"instance of AsyncAgentBase, but got {self} of "
|
||||
f"type {type(self)}.",
|
||||
)
|
||||
hooks = getattr(self, f"_instance_{hook_type}_hooks")
|
||||
hooks[hook_name] = hook
|
||||
|
||||
def remove_instance_hook(
|
||||
self,
|
||||
hook_type: AgentHookTypes,
|
||||
hook_name: str,
|
||||
) -> None:
|
||||
"""Remove an instance-level hook from the agent instance.
|
||||
|
||||
Args:
|
||||
hook_type (`AgentHookTypes`):
|
||||
The type of the hook, indicating where the hook is to be
|
||||
triggered.
|
||||
hook_name (`str`):
|
||||
The name of the hook to remove.
|
||||
"""
|
||||
if not isinstance(self, AgentBase):
|
||||
raise TypeError(
|
||||
"The remove_instance_hook method should be called on an "
|
||||
f"instance of AsyncAgentBase, but got {self} of "
|
||||
f"type {type(self)}.",
|
||||
)
|
||||
hooks = getattr(self, f"_instance_{hook_type}_hooks")
|
||||
if hook_name in hooks:
|
||||
del hooks[hook_name]
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Hook '{hook_name}' not found in '{hook_type}' hooks of "
|
||||
f"{self.__class__.__name__} instance.",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def register_class_hook(
|
||||
cls,
|
||||
hook_type: AgentHookTypes,
|
||||
hook_name: str,
|
||||
hook: Callable,
|
||||
) -> None:
|
||||
"""The universal function to register a hook to the agent class, which
|
||||
will take effect for all instances of the class.
|
||||
|
||||
Args:
|
||||
hook_type (`AgentHookTypes`):
|
||||
The type of the hook, indicating where the hook is to be
|
||||
triggered.
|
||||
hook_name (`str`):
|
||||
The name of the hook. If the name is already registered, the
|
||||
hook will be overwritten.
|
||||
hook (`Callable`):
|
||||
The hook function.
|
||||
"""
|
||||
|
||||
assert (
|
||||
hook_type in cls.supported_hook_types
|
||||
), f"Invalid hook type: {hook_type}"
|
||||
|
||||
hooks = getattr(cls, f"_class_{hook_type}_hooks")
|
||||
hooks[hook_name] = hook
|
||||
|
||||
@classmethod
|
||||
def remove_class_hook(
|
||||
cls,
|
||||
hook_type: AgentHookTypes,
|
||||
hook_name: str,
|
||||
) -> None:
|
||||
"""Remove a class-level hook from the agent class.
|
||||
|
||||
Args:
|
||||
hook_type (`AgentHookTypes`):
|
||||
The type of the hook, indicating where the hook is to be
|
||||
triggered.
|
||||
hook_name (`str`):
|
||||
The name of the hook to remove.
|
||||
"""
|
||||
|
||||
assert (
|
||||
hook_type in cls.supported_hook_types
|
||||
), f"Invalid hook type: {hook_type}"
|
||||
hooks = getattr(cls, f"_class_{hook_type}_hooks")
|
||||
if hook_name in hooks:
|
||||
del hooks[hook_name]
|
||||
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Hook '{hook_name}' not found in '{hook_type}' hooks of "
|
||||
f"{cls.__name__} class.",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def clear_class_hooks(
|
||||
cls,
|
||||
hook_type: AgentHookTypes | None = None,
|
||||
) -> None:
|
||||
"""Clear all class-level hooks.
|
||||
|
||||
Args:
|
||||
hook_type (`AgentHookTypes`, optional):
|
||||
The type of the hook to clear. If not specified, all
|
||||
class-level hooks will be cleared.
|
||||
"""
|
||||
|
||||
if hook_type is None:
|
||||
for typ in cls.supported_hook_types:
|
||||
hooks = getattr(cls, f"_class_{typ}_hooks")
|
||||
hooks.clear()
|
||||
else:
|
||||
assert (
|
||||
hook_type in cls.supported_hook_types
|
||||
), f"Invalid hook type: {hook_type}"
|
||||
hooks = getattr(cls, f"_class_{hook_type}_hooks")
|
||||
hooks.clear()
|
||||
|
||||
def clear_instance_hooks(
|
||||
self,
|
||||
hook_type: AgentHookTypes | None = None,
|
||||
) -> None:
|
||||
"""If `hook_type` is not specified, clear all instance-level hooks.
|
||||
Otherwise, clear the specified type of instance-level hooks."""
|
||||
if hook_type is None:
|
||||
for typ in self.supported_hook_types:
|
||||
if not hasattr(self, f"_instance_{typ}_hooks"):
|
||||
raise ValueError(
|
||||
f"Call super().__init__() in the constructor "
|
||||
f"to initialize the instance-level hooks for "
|
||||
f"{self.__class__.__name__}.",
|
||||
)
|
||||
hooks = getattr(self, f"_instance_{typ}_hooks")
|
||||
hooks.clear()
|
||||
|
||||
else:
|
||||
assert (
|
||||
hook_type in self.supported_hook_types
|
||||
), f"Invalid hook type: {hook_type}"
|
||||
if not hasattr(self, f"_instance_{hook_type}_hooks"):
|
||||
raise ValueError(
|
||||
f"Call super().__init__() in the constructor "
|
||||
f"to initialize the instance-level hooks for "
|
||||
f"{self.__class__.__name__}.",
|
||||
)
|
||||
hooks = getattr(self, f"_instance_{hook_type}_hooks")
|
||||
hooks.clear()
|
||||
|
||||
def reset_subscribers(
|
||||
self,
|
||||
msghub_name: str,
|
||||
subscribers: list["AgentBase"],
|
||||
) -> None:
|
||||
"""Reset the subscribers of the agent.
|
||||
|
||||
Args:
|
||||
msghub_name (`str`):
|
||||
The name of the MsgHub that manages the subscribers.
|
||||
subscribers (`list[AgentBase]`):
|
||||
A list of agents that will receive the reply message from
|
||||
this agent via their `observe` method.
|
||||
"""
|
||||
self._subscribers[msghub_name] = [_ for _ in subscribers if _ != self]
|
||||
|
||||
def remove_subscribers(self, msghub_name: str) -> None:
|
||||
"""Remove the msghub subscribers by the given msg hub name.
|
||||
|
||||
Args:
|
||||
msghub_name (`str`):
|
||||
The name of the MsgHub that manages the subscribers.
|
||||
"""
|
||||
if msghub_name not in self._subscribers:
|
||||
logger.warning(
|
||||
"MsgHub named '%s' not found",
|
||||
msghub_name,
|
||||
)
|
||||
else:
|
||||
self._subscribers.pop(msghub_name)
|
||||
|
||||
@deprecated("Please use set_console_output_enabled() instead.")
|
||||
def disable_console_output(self) -> None:
|
||||
"""This function will disable the console output of the agent, e.g.
|
||||
in a production environment to avoid messy logs."""
|
||||
self._disable_console_output = True
|
||||
|
||||
def set_console_output_enabled(self, enabled: bool) -> None:
|
||||
"""Enable or disable the console output of the agent. E.g. in a
|
||||
production environment, you may want to disable the console output to
|
||||
avoid messy logs.
|
||||
|
||||
Args:
|
||||
enabled (`bool`):
|
||||
If `True`, enable the console output. If `False`, disable
|
||||
the console output.
|
||||
"""
|
||||
self._disable_console_output = not enabled
|
||||
|
||||
def set_msg_queue_enabled(
|
||||
self,
|
||||
enabled: bool,
|
||||
queue: Queue | None = None,
|
||||
) -> None:
|
||||
"""Enable or disable the message queue for streaming outputs.
|
||||
|
||||
Args:
|
||||
enabled (`bool`):
|
||||
If `True`, enable the message queue to allow streaming
|
||||
outputs. If `False`, disable the message queue.
|
||||
queue (`Queue | None`, optional):
|
||||
The queue instance that will be used to initialize the
|
||||
message queue when `enable` is `True`.
|
||||
"""
|
||||
if enabled:
|
||||
if queue is None:
|
||||
if self.msg_queue is None:
|
||||
self.msg_queue = asyncio.Queue(maxsize=100)
|
||||
else:
|
||||
self.msg_queue = queue
|
||||
else:
|
||||
self.msg_queue = None
|
||||
|
||||
self._disable_msg_queue = not enabled
|
||||
@@ -1,180 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The metaclass for agents in agentscope."""
|
||||
import inspect
|
||||
from copy import deepcopy
|
||||
from functools import wraps
|
||||
from typing import (
|
||||
Any,
|
||||
Dict,
|
||||
TYPE_CHECKING,
|
||||
Callable,
|
||||
)
|
||||
|
||||
from .._utils._common import _execute_async_or_sync_func
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ._agent_base import AgentBase
|
||||
else:
|
||||
AgentBase = "AgentBase"
|
||||
|
||||
|
||||
def _normalize_to_kwargs(
|
||||
func: Callable,
|
||||
self: Any,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> dict:
|
||||
"""Normalize the provided positional and keyword arguments into a
|
||||
keyword arguments dictionary that matches the function signature."""
|
||||
sig = inspect.signature(func)
|
||||
try:
|
||||
# Bind the provided arguments to the function signature
|
||||
bound = sig.bind(self, *args, **kwargs)
|
||||
# Apply the default values for parameters
|
||||
bound.apply_defaults()
|
||||
|
||||
# Return the arguments in a dictionary format
|
||||
res = dict(bound.arguments)
|
||||
res.pop("self")
|
||||
return res
|
||||
|
||||
except TypeError as e:
|
||||
# If failed to bind, we raise a TypeError with more context
|
||||
param_names = list(sig.parameters.keys())
|
||||
provided_args = len(args)
|
||||
provided_kwargs = list(kwargs.keys())
|
||||
|
||||
raise TypeError(
|
||||
f"Failed to bind parameters for function '{func.__name__}': {e}\n"
|
||||
f"Expected parameters: {param_names}\n"
|
||||
f"Provided {provided_args} positional args and kwargs: "
|
||||
f"{provided_kwargs}",
|
||||
) from e
|
||||
|
||||
|
||||
def _wrap_with_hooks(
|
||||
original_func: Callable,
|
||||
) -> Callable:
|
||||
"""A decorator to wrap the original async function with pre- and post-hooks
|
||||
|
||||
Args:
|
||||
original_func (`Callable`):
|
||||
The original async function to be wrapped with hooks.
|
||||
"""
|
||||
func_name = original_func.__name__.replace("_", "")
|
||||
|
||||
@wraps(original_func)
|
||||
async def async_wrapper(
|
||||
self: AgentBase,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""The wrapped function, which call the pre- and post-hooks before and
|
||||
after the original function."""
|
||||
|
||||
# Unify all positional and keyword arguments into a keyword arguments
|
||||
normalized_kwargs = _normalize_to_kwargs(
|
||||
original_func,
|
||||
self,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
current_normalized_kwargs = normalized_kwargs
|
||||
assert (
|
||||
hasattr(self, f"_instance_pre_{func_name}_hooks")
|
||||
and hasattr(self, f"_instance_post_{func_name}_hooks")
|
||||
and hasattr(self.__class__, f"_class_pre_{func_name}_hooks")
|
||||
and hasattr(self.__class__, f"_class_post_{func_name}_hooks")
|
||||
), f"Hooks for {func_name} not found in {self.__class__.__name__}"
|
||||
|
||||
# pre-hooks
|
||||
pre_hooks = list(
|
||||
getattr(self, f"_instance_pre_{func_name}_hooks").values(),
|
||||
) + list(
|
||||
getattr(self, f"_class_pre_{func_name}_hooks").values(),
|
||||
)
|
||||
for pre_hook in pre_hooks:
|
||||
modified_keywords = await _execute_async_or_sync_func(
|
||||
pre_hook,
|
||||
self,
|
||||
deepcopy(current_normalized_kwargs),
|
||||
)
|
||||
if modified_keywords is not None:
|
||||
assert isinstance(modified_keywords, dict), (
|
||||
f"Pre-hook must return a dict of keyword arguments, rather"
|
||||
f" than {type(modified_keywords)} from hook "
|
||||
f"{pre_hook.__name__}"
|
||||
)
|
||||
current_normalized_kwargs = modified_keywords
|
||||
|
||||
# original function
|
||||
# handle positional and keyword arguments specifically
|
||||
args = current_normalized_kwargs.get("args", [])
|
||||
kwargs = current_normalized_kwargs.get("kwargs", {})
|
||||
others = {
|
||||
k: v
|
||||
for k, v in current_normalized_kwargs.items()
|
||||
if k not in ["args", "kwargs"]
|
||||
}
|
||||
current_output = await original_func(
|
||||
self,
|
||||
*args,
|
||||
**others,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
# post_hooks
|
||||
post_hooks = list(
|
||||
getattr(self, f"_instance_post_{func_name}_hooks").values(),
|
||||
) + list(
|
||||
getattr(self, f"_class_post_{func_name}_hooks").values(),
|
||||
)
|
||||
for post_hook in post_hooks:
|
||||
modified_output = await _execute_async_or_sync_func(
|
||||
post_hook,
|
||||
self,
|
||||
deepcopy(current_normalized_kwargs),
|
||||
deepcopy(current_output),
|
||||
)
|
||||
if modified_output is not None:
|
||||
current_output = modified_output
|
||||
return current_output
|
||||
|
||||
return async_wrapper
|
||||
|
||||
|
||||
class _AgentMeta(type):
|
||||
"""The agent metaclass that wraps the agent's reply, observe and print
|
||||
functions with pre- and post-hooks."""
|
||||
|
||||
def __new__(mcs, name: Any, bases: Any, attrs: Dict) -> Any:
|
||||
"""Wrap the agent's functions with hooks."""
|
||||
|
||||
for func_name in [
|
||||
"reply",
|
||||
"print",
|
||||
"observe",
|
||||
]:
|
||||
if func_name in attrs:
|
||||
attrs[func_name] = _wrap_with_hooks(attrs[func_name])
|
||||
|
||||
return super().__new__(mcs, name, bases, attrs)
|
||||
|
||||
|
||||
class _ReActAgentMeta(_AgentMeta):
|
||||
"""The ReAct metaclass that adds pre- and post-hooks for the _reasoning
|
||||
and _acting functions."""
|
||||
|
||||
def __new__(mcs, name: Any, bases: Any, attrs: Dict) -> Any:
|
||||
"""Wrap the ReAct agent's _reasoning and _acting functions with
|
||||
hooks."""
|
||||
|
||||
for func_name in [
|
||||
"_reasoning",
|
||||
"_acting",
|
||||
]:
|
||||
if func_name in attrs:
|
||||
attrs[func_name] = _wrap_with_hooks(attrs[func_name])
|
||||
|
||||
return super().__new__(mcs, name, bases, attrs)
|
||||
@@ -1,767 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=not-an-iterable
|
||||
# mypy: disable-error-code="list-item"
|
||||
"""ReAct agent class in agentscope."""
|
||||
import asyncio
|
||||
from typing import Type, Any, AsyncGenerator, Literal
|
||||
|
||||
import shortuuid
|
||||
from pydantic import BaseModel, ValidationError, Field
|
||||
|
||||
from ._react_agent_base import ReActAgentBase
|
||||
from .._logging import logger
|
||||
from ..formatter import FormatterBase
|
||||
from ..memory import MemoryBase, LongTermMemoryBase, InMemoryMemory
|
||||
from ..message import Msg, ToolUseBlock, ToolResultBlock, TextBlock
|
||||
from ..model import ChatModelBase
|
||||
from ..rag import KnowledgeBase, Document
|
||||
from ..plan import PlanNotebook
|
||||
from ..tool import Toolkit, ToolResponse
|
||||
from ..tracing import trace_reply
|
||||
|
||||
|
||||
class _QueryRewriteModel(BaseModel):
|
||||
"""The structured model used for query rewriting."""
|
||||
|
||||
rewritten_query: str = Field(
|
||||
description=(
|
||||
"The rewritten query, which should be specific and concise. "
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def finish_function_pre_print_hook(
|
||||
self: "ReActAgent",
|
||||
kwargs: dict[str, Any],
|
||||
) -> dict[str, Any] | None:
|
||||
"""A pre-speak hook function that check if finish_function is called. If
|
||||
so, it will wrap the response argument into a message and return it to
|
||||
replace the original message. By this way, the calling of the finish
|
||||
function will be displayed as a text reply instead of a tool call."""
|
||||
|
||||
msg = kwargs["msg"]
|
||||
|
||||
if isinstance(msg.content, str):
|
||||
return None
|
||||
|
||||
if isinstance(msg.content, list):
|
||||
for i, block in enumerate(msg.content):
|
||||
if (
|
||||
block["type"] == "tool_use"
|
||||
and block["name"] == self.finish_function_name
|
||||
):
|
||||
# Convert the response argument into a text block for
|
||||
# displaying
|
||||
try:
|
||||
msg.content[i] = TextBlock(
|
||||
type="text",
|
||||
text=block["input"].get("response", ""),
|
||||
)
|
||||
return kwargs
|
||||
except Exception:
|
||||
print("Error in block input", block["input"])
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class ReActAgent(ReActAgentBase):
|
||||
"""A ReAct agent implementation in AgentScope, which supports
|
||||
|
||||
- Realtime steering
|
||||
- API-based (parallel) tool calling
|
||||
- Hooks around reasoning, acting, reply, observe and print functions
|
||||
- Structured output generation
|
||||
"""
|
||||
|
||||
finish_function_name: str = "generate_response"
|
||||
"""The function name used to finish replying and return a response to
|
||||
the user."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
sys_prompt: str,
|
||||
model: ChatModelBase,
|
||||
formatter: FormatterBase,
|
||||
toolkit: Toolkit | None = None,
|
||||
memory: MemoryBase | None = None,
|
||||
long_term_memory: LongTermMemoryBase | None = None,
|
||||
long_term_memory_mode: Literal[
|
||||
"agent_control",
|
||||
"static_control",
|
||||
"both",
|
||||
] = "both",
|
||||
enable_meta_tool: bool = False,
|
||||
parallel_tool_calls: bool = False,
|
||||
knowledge: KnowledgeBase | list[KnowledgeBase] | None = None,
|
||||
enable_rewrite_query: bool = True,
|
||||
plan_notebook: PlanNotebook | None = None,
|
||||
print_hint_msg: bool = False,
|
||||
max_iters: int = 10,
|
||||
) -> None:
|
||||
"""Initialize the ReAct agent
|
||||
|
||||
Args:
|
||||
name (`str`):
|
||||
The name of the agent.
|
||||
sys_prompt (`str`):
|
||||
The system prompt of the agent.
|
||||
model (`ChatModelBase`):
|
||||
The chat model used by the agent.
|
||||
formatter (`FormatterBase`):
|
||||
The formatter used to format the messages into the required
|
||||
format of the model API provider.
|
||||
toolkit (`Toolkit | None`, optional):
|
||||
A `Toolkit` object that contains the tool functions. If not
|
||||
provided, a default empty `Toolkit` will be created.
|
||||
memory (`MemoryBase | None`, optional):
|
||||
The memory used to store the dialogue history. If not provided,
|
||||
a default `InMemoryMemory` will be created, which stores
|
||||
messages in a list in memory.
|
||||
long_term_memory (`LongTermMemoryBase | None`, optional):
|
||||
The optional long-term memory, which will provide two tool
|
||||
functions: `retrieve_from_memory` and `record_to_memory`, and
|
||||
will attach the retrieved information to the system prompt
|
||||
before each reply.
|
||||
enable_meta_tool (`bool`, defaults to `False`):
|
||||
If `True`, a meta tool function `reset_equipped_tools` will be
|
||||
added to the toolkit, which allows the agent to manage its
|
||||
equipped tools dynamically.
|
||||
long_term_memory_mode (`Literal['agent_control', 'static_control',\
|
||||
'both']`, defaults to `both`):
|
||||
The mode of the long-term memory. If `agent_control`, two
|
||||
tool functions `retrieve_from_memory` and `record_to_memory`
|
||||
will be registered in the toolkit to allow the agent to
|
||||
manage the long-term memory. If `static_control`, retrieving
|
||||
and recording will happen in the beginning and end of
|
||||
each reply respectively.
|
||||
parallel_tool_calls (`bool`, defaults to `False`):
|
||||
When LLM generates multiple tool calls, whether to execute
|
||||
them in parallel.
|
||||
knowledge (`KnowledgeBase | list[KnowledgeBase] | None`, optional):
|
||||
The knowledge object(s) used by the agent to retrieve
|
||||
relevant documents at the beginning of each reply.
|
||||
enable_rewrite_query (`bool`, defaults to `True`):
|
||||
Whether ask the agent to rewrite the user input query before
|
||||
retrieving from the knowledge base(s), e.g. rewrite "Who am I"
|
||||
to "{user's name}" to get more relevant documents. Only works
|
||||
when the knowledge base(s) is provided.
|
||||
plan_notebook (`PlanNotebook | None`, optional):
|
||||
The plan notebook instance, allow the agent to finish the
|
||||
complex task by decomposing it into a sequence of subtasks.
|
||||
print_hint_msg (`bool`, defaults to `False`):
|
||||
Whether to print the hint messages, including the reasoning
|
||||
hint from the plan notebook, the retrieved information from
|
||||
the long-term memory and knowledge base(s).
|
||||
max_iters (`int`, defaults to `10`):
|
||||
The maximum number of iterations of the reasoning-acting loops.
|
||||
"""
|
||||
super().__init__()
|
||||
|
||||
assert long_term_memory_mode in [
|
||||
"agent_control",
|
||||
"static_control",
|
||||
"both",
|
||||
]
|
||||
|
||||
# Static variables in the agent
|
||||
self.name = name
|
||||
self._sys_prompt = sys_prompt
|
||||
self.max_iters = max_iters
|
||||
self.model = model
|
||||
self.formatter = formatter
|
||||
|
||||
# -------------- Memory management --------------
|
||||
# Record the dialogue history in the memory
|
||||
self.memory = memory or InMemoryMemory()
|
||||
# If provide the long-term memory, it will be used to retrieve info
|
||||
# in the beginning of each reply, and the result will be added to the
|
||||
# system prompt
|
||||
self.long_term_memory = long_term_memory
|
||||
|
||||
# The long-term memory mode
|
||||
self._static_control = long_term_memory and long_term_memory_mode in [
|
||||
"static_control",
|
||||
"both",
|
||||
]
|
||||
self._agent_control = long_term_memory and long_term_memory_mode in [
|
||||
"agent_control",
|
||||
"both",
|
||||
]
|
||||
|
||||
# -------------- Tool management --------------
|
||||
# If None, a default Toolkit will be created
|
||||
self.toolkit = toolkit or Toolkit()
|
||||
self.toolkit.register_tool_function(
|
||||
getattr(self, self.finish_function_name),
|
||||
)
|
||||
if self._agent_control:
|
||||
# Adding two tool functions into the toolkit to allow self-control
|
||||
self.toolkit.register_tool_function(
|
||||
long_term_memory.record_to_memory,
|
||||
)
|
||||
self.toolkit.register_tool_function(
|
||||
long_term_memory.retrieve_from_memory,
|
||||
)
|
||||
# Add a meta tool function to allow agent-controlled tool management
|
||||
if enable_meta_tool or plan_notebook:
|
||||
self.toolkit.register_tool_function(
|
||||
self.toolkit.reset_equipped_tools,
|
||||
)
|
||||
|
||||
self.parallel_tool_calls = parallel_tool_calls
|
||||
|
||||
# -------------- RAG management --------------
|
||||
# The knowledge base(s) used by the agent
|
||||
if isinstance(knowledge, KnowledgeBase):
|
||||
knowledge = [knowledge]
|
||||
self.knowledge: list[KnowledgeBase] = knowledge or []
|
||||
self.enable_rewrite_query = enable_rewrite_query
|
||||
|
||||
# -------------- Plan management --------------
|
||||
# Equipped the plan-related tools provided by the plan notebook as
|
||||
# a tool group named "plan_related". So that the agent can activate
|
||||
# the plan tools by the meta tool function
|
||||
self.plan_notebook = None
|
||||
if plan_notebook:
|
||||
self.plan_notebook = plan_notebook
|
||||
# When enable_meta_tool is True, plan tools are in plan_related
|
||||
# group and active by agent.
|
||||
# Otherwise, plan tools in bassic group and always active.
|
||||
if enable_meta_tool:
|
||||
self.toolkit.create_tool_group(
|
||||
"plan_related",
|
||||
description=self.plan_notebook.description,
|
||||
)
|
||||
for tool in plan_notebook.list_tools():
|
||||
self.toolkit.register_tool_function(
|
||||
tool,
|
||||
group_name="plan_related",
|
||||
)
|
||||
else:
|
||||
for tool in plan_notebook.list_tools():
|
||||
self.toolkit.register_tool_function(
|
||||
tool,
|
||||
)
|
||||
|
||||
# If print the reasoning hint messages
|
||||
self.print_hint_msg = print_hint_msg
|
||||
|
||||
# The maximum number of iterations of the reasoning-acting loops
|
||||
self.max_iters = max_iters
|
||||
|
||||
# The hint messages that will be attached to the prompt to guide the
|
||||
# agent's behavior before each reasoning step, and cleared after
|
||||
# each reasoning step, meaning the hint messages is one-time use only.
|
||||
# We use an InMemoryMemory instance to store the hint messages
|
||||
self._reasoning_hint_msgs = InMemoryMemory()
|
||||
|
||||
# Variables to record the intermediate state
|
||||
|
||||
# If required structured output model is provided
|
||||
self._required_structured_model: Type[BaseModel] | None = None
|
||||
|
||||
# -------------- State registration and hooks --------------
|
||||
# Register the status variables
|
||||
self.register_state("name")
|
||||
self.register_state("_sys_prompt")
|
||||
|
||||
self.register_instance_hook(
|
||||
"pre_print",
|
||||
"finish_function_pre_print_hook",
|
||||
finish_function_pre_print_hook,
|
||||
)
|
||||
|
||||
@property
|
||||
def sys_prompt(self) -> str:
|
||||
"""The dynamic system prompt of the agent."""
|
||||
return self._sys_prompt
|
||||
|
||||
@trace_reply
|
||||
async def reply(
|
||||
self,
|
||||
msg: Msg | list[Msg] | None = None,
|
||||
structured_model: Type[BaseModel] | None = None,
|
||||
) -> Msg:
|
||||
"""Generate a reply based on the current state and input arguments.
|
||||
|
||||
Args:
|
||||
msg (`Msg | list[Msg] | None`, optional):
|
||||
The input message(s) to the agent.
|
||||
structured_model (`Type[BaseModel] | None`, optional):
|
||||
The required structured output model. If provided, the agent
|
||||
is expected to generate structured output in the `metadata`
|
||||
field of the output message.
|
||||
|
||||
Returns:
|
||||
`Msg`:
|
||||
The output message generated by the agent.
|
||||
"""
|
||||
# Record the input message(s) in the memory
|
||||
await self.memory.add(msg)
|
||||
|
||||
# Retrieve relevant records from the long-term memory if activated
|
||||
await self._retrieve_from_long_term_memory(msg)
|
||||
# Retrieve relevant documents from the knowledge base(s) if any
|
||||
await self._retrieve_from_knowledge(msg)
|
||||
|
||||
self._required_structured_model = structured_model
|
||||
# Record structured output model if provided
|
||||
if structured_model:
|
||||
self.toolkit.set_extended_model(
|
||||
self.finish_function_name,
|
||||
structured_model,
|
||||
)
|
||||
|
||||
# The reasoning-acting loop
|
||||
reply_msg = None
|
||||
for _ in range(self.max_iters):
|
||||
msg_reasoning = await self._reasoning()
|
||||
|
||||
futures = [
|
||||
self._acting(tool_call)
|
||||
for tool_call in msg_reasoning.get_content_blocks(
|
||||
"tool_use",
|
||||
)
|
||||
]
|
||||
|
||||
# Parallel tool calls or not
|
||||
if self.parallel_tool_calls:
|
||||
acting_responses = await asyncio.gather(*futures)
|
||||
|
||||
else:
|
||||
# Sequential tool calls
|
||||
acting_responses = [await _ for _ in futures]
|
||||
|
||||
# Find the first non-None replying message from the acting
|
||||
for acting_msg in acting_responses:
|
||||
reply_msg = reply_msg or acting_msg
|
||||
|
||||
if reply_msg:
|
||||
break
|
||||
|
||||
# When the maximum iterations are reached
|
||||
if reply_msg is None:
|
||||
reply_msg = await self._summarizing()
|
||||
|
||||
# Post-process the memory, long-term memory
|
||||
if self._static_control:
|
||||
await self.long_term_memory.record(
|
||||
[
|
||||
*([*msg] if isinstance(msg, list) else [msg]),
|
||||
*await self.memory.get_memory(),
|
||||
reply_msg,
|
||||
],
|
||||
)
|
||||
|
||||
await self.memory.add(reply_msg)
|
||||
return reply_msg
|
||||
|
||||
async def _reasoning(
|
||||
self,
|
||||
) -> Msg:
|
||||
"""Perform the reasoning process."""
|
||||
if self.plan_notebook:
|
||||
# Insert the reasoning hint from the plan notebook
|
||||
hint_msg = await self.plan_notebook.get_current_hint()
|
||||
if self.print_hint_msg and hint_msg:
|
||||
await self.print(hint_msg)
|
||||
await self._reasoning_hint_msgs.add(hint_msg)
|
||||
|
||||
# Convert Msg objects into the required format of the model API
|
||||
prompt = await self.formatter.format(
|
||||
msgs=[
|
||||
Msg("system", self.sys_prompt, "system"),
|
||||
*await self.memory.get_memory(),
|
||||
# The hint messages to guide the agent's behavior, maybe empty
|
||||
*await self._reasoning_hint_msgs.get_memory(),
|
||||
],
|
||||
)
|
||||
# Clear the hint messages after use
|
||||
await self._reasoning_hint_msgs.clear()
|
||||
|
||||
res = await self.model(
|
||||
prompt,
|
||||
tools=self.toolkit.get_json_schemas(),
|
||||
)
|
||||
|
||||
# handle output from the model
|
||||
interrupted_by_user = False
|
||||
msg = None
|
||||
try:
|
||||
if self.model.stream:
|
||||
msg = Msg(self.name, [], "assistant")
|
||||
async for content_chunk in res:
|
||||
msg.content = content_chunk.content
|
||||
await self.print(msg, False)
|
||||
await self.print(msg, True)
|
||||
|
||||
# Add a tiny sleep to yield the last message object in the
|
||||
# message queue
|
||||
await asyncio.sleep(0.001)
|
||||
|
||||
else:
|
||||
msg = Msg(self.name, list(res.content), "assistant")
|
||||
await self.print(msg, True)
|
||||
|
||||
except asyncio.CancelledError as e:
|
||||
interrupted_by_user = True
|
||||
raise e from None
|
||||
|
||||
finally:
|
||||
if msg and not msg.has_content_blocks("tool_use"):
|
||||
# Turn plain text response into a tool call of the finish
|
||||
# function
|
||||
msg = Msg.from_dict(msg.to_dict())
|
||||
msg.content = [
|
||||
ToolUseBlock(
|
||||
id=shortuuid.uuid(),
|
||||
type="tool_use",
|
||||
name=self.finish_function_name,
|
||||
input={"response": msg.get_text_content()},
|
||||
),
|
||||
]
|
||||
|
||||
# None will be ignored by the memory
|
||||
await self.memory.add(msg)
|
||||
|
||||
# Post-process for user interruption
|
||||
if interrupted_by_user and msg:
|
||||
# Fake tool results
|
||||
tool_use_blocks: list = msg.get_content_blocks(
|
||||
"tool_use",
|
||||
)
|
||||
for tool_call in tool_use_blocks:
|
||||
msg_res = Msg(
|
||||
"system",
|
||||
[
|
||||
ToolResultBlock(
|
||||
type="tool_result",
|
||||
id=tool_call["id"],
|
||||
name=tool_call["name"],
|
||||
output="The tool call has been interrupted "
|
||||
"by the user.",
|
||||
),
|
||||
],
|
||||
"system",
|
||||
)
|
||||
await self.memory.add(msg_res)
|
||||
await self.print(msg_res, True)
|
||||
return msg
|
||||
|
||||
async def _acting(self, tool_call: ToolUseBlock) -> Msg | None:
|
||||
"""Perform the acting process.
|
||||
|
||||
Args:
|
||||
tool_call (`ToolUseBlock`):
|
||||
The tool use block to be executed.
|
||||
|
||||
Returns:
|
||||
`Union[Msg, None]`:
|
||||
Return a message to the user if the `finish_function` is
|
||||
called, otherwise return `None`.
|
||||
"""
|
||||
|
||||
tool_res_msg = Msg(
|
||||
"system",
|
||||
[
|
||||
ToolResultBlock(
|
||||
type="tool_result",
|
||||
id=tool_call["id"],
|
||||
name=tool_call["name"],
|
||||
output=[],
|
||||
),
|
||||
],
|
||||
"system",
|
||||
)
|
||||
try:
|
||||
# Execute the tool call
|
||||
tool_res = await self.toolkit.call_tool_function(tool_call)
|
||||
|
||||
response_msg = None
|
||||
# Async generator handling
|
||||
async for chunk in tool_res:
|
||||
# Turn into a tool result block
|
||||
tool_res_msg.content[0][ # type: ignore[index]
|
||||
"output"
|
||||
] = chunk.content
|
||||
|
||||
# Skip the printing of the finish function call
|
||||
if (
|
||||
tool_call["name"] != self.finish_function_name
|
||||
or tool_call["name"] == self.finish_function_name
|
||||
and (
|
||||
chunk.metadata is None
|
||||
or not chunk.metadata.get("success")
|
||||
)
|
||||
):
|
||||
await self.print(tool_res_msg, chunk.is_last)
|
||||
|
||||
# Raise the CancelledError to handle the interruption in the
|
||||
# handle_interrupt function
|
||||
if chunk.is_interrupted:
|
||||
raise asyncio.CancelledError()
|
||||
|
||||
# Return message if generate_response is called successfully
|
||||
if (
|
||||
tool_call["name"] == self.finish_function_name
|
||||
and chunk.metadata
|
||||
and chunk.metadata.get(
|
||||
"success",
|
||||
True,
|
||||
)
|
||||
):
|
||||
response_msg = chunk.metadata.get("response_msg")
|
||||
|
||||
return response_msg
|
||||
|
||||
finally:
|
||||
# Record the tool result message in the memory
|
||||
await self.memory.add(tool_res_msg)
|
||||
|
||||
async def observe(self, msg: Msg | list[Msg] | None) -> None:
|
||||
"""Receive observing message(s) without generating a reply.
|
||||
|
||||
Args:
|
||||
msg (`Msg | list[Msg] | None`):
|
||||
The message or messages to be observed.
|
||||
"""
|
||||
await self.memory.add(msg)
|
||||
|
||||
async def _summarizing(self) -> Msg:
|
||||
"""Generate a response when the agent fails to solve the problem in
|
||||
the maximum iterations."""
|
||||
hint_msg = Msg(
|
||||
"user",
|
||||
"You have failed to generate response within the maximum "
|
||||
"iterations. Now respond directly by summarizing the current "
|
||||
"situation.",
|
||||
role="user",
|
||||
)
|
||||
|
||||
# Generate a reply by summarizing the current situation
|
||||
prompt = await self.formatter.format(
|
||||
[
|
||||
Msg("system", self.sys_prompt, "system"),
|
||||
*await self.memory.get_memory(),
|
||||
hint_msg,
|
||||
],
|
||||
)
|
||||
# TODO: handle the structured output here, maybe force calling the
|
||||
# finish_function here
|
||||
res = await self.model(prompt)
|
||||
|
||||
res_msg = Msg(self.name, [], "assistant")
|
||||
if isinstance(res, AsyncGenerator):
|
||||
async for chunk in res:
|
||||
res_msg.content = chunk.content
|
||||
await self.print(res_msg, False)
|
||||
await self.print(res_msg, True)
|
||||
|
||||
else:
|
||||
res_msg.content = res.content
|
||||
await self.print(res_msg, True)
|
||||
|
||||
return res_msg
|
||||
|
||||
async def handle_interrupt(
|
||||
self,
|
||||
_msg: Msg | list[Msg] | None = None,
|
||||
) -> Msg:
|
||||
"""The post-processing logic when the reply is interrupted by the
|
||||
user or something else."""
|
||||
|
||||
response_msg = Msg(
|
||||
self.name,
|
||||
"I noticed that you have interrupted me. What can I "
|
||||
"do for you?",
|
||||
"assistant",
|
||||
metadata={
|
||||
# Expose this field to indicate the interruption
|
||||
"is_interrupted": True,
|
||||
},
|
||||
)
|
||||
|
||||
await self.print(response_msg, True)
|
||||
await self.memory.add(response_msg)
|
||||
return response_msg
|
||||
|
||||
def generate_response(
|
||||
self,
|
||||
response: str,
|
||||
**kwargs: Any,
|
||||
) -> ToolResponse:
|
||||
"""Generate a response. Note only the input argument `response` is
|
||||
visible to the others, you should include all the necessary
|
||||
information in the `response` argument.
|
||||
|
||||
Args:
|
||||
response (`str`):
|
||||
Your response to the user.
|
||||
"""
|
||||
response_msg = Msg(
|
||||
self.name,
|
||||
response,
|
||||
"assistant",
|
||||
)
|
||||
|
||||
# Prepare structured output
|
||||
if self._required_structured_model:
|
||||
try:
|
||||
# Use the metadata field of the message to store the
|
||||
# structured output
|
||||
response_msg.metadata = (
|
||||
self._required_structured_model.model_validate(
|
||||
kwargs,
|
||||
).model_dump()
|
||||
)
|
||||
|
||||
except ValidationError as e:
|
||||
return ToolResponse(
|
||||
content=[
|
||||
TextBlock(
|
||||
type="text",
|
||||
text=f"Arguments Validation Error: {e}",
|
||||
),
|
||||
],
|
||||
metadata={
|
||||
"success": False,
|
||||
"response_msg": None,
|
||||
},
|
||||
)
|
||||
|
||||
return ToolResponse(
|
||||
content=[
|
||||
TextBlock(
|
||||
type="text",
|
||||
text="Successfully generated response.",
|
||||
),
|
||||
],
|
||||
metadata={
|
||||
"success": True,
|
||||
"response_msg": response_msg,
|
||||
},
|
||||
is_last=True,
|
||||
)
|
||||
|
||||
async def _retrieve_from_long_term_memory(
|
||||
self,
|
||||
msg: Msg | list[Msg] | None,
|
||||
) -> None:
|
||||
"""Insert the retrieved information from the long-term memory into
|
||||
the short-term memory as a Msg object.
|
||||
|
||||
Args:
|
||||
msg (`Msg | list[Msg] | None`):
|
||||
The input message to the agent.
|
||||
"""
|
||||
if self._static_control and msg:
|
||||
# Retrieve information from the long-term memory if available
|
||||
retrieved_info = await self.long_term_memory.retrieve(msg)
|
||||
if retrieved_info:
|
||||
retrieved_msg = Msg(
|
||||
name="long_term_memory",
|
||||
content="<long_term_memory>The content below are "
|
||||
"retrieved from long-term memory, which maybe "
|
||||
f"useful:\n{retrieved_info}</long_term_memory>",
|
||||
role="user",
|
||||
)
|
||||
if self.print_hint_msg:
|
||||
await self.print(retrieved_msg, True)
|
||||
await self.memory.add(retrieved_msg)
|
||||
|
||||
async def _retrieve_from_knowledge(
|
||||
self,
|
||||
msg: Msg | list[Msg] | None,
|
||||
) -> None:
|
||||
"""Insert the retrieved documents from the RAG knowledge base(s) if
|
||||
available.
|
||||
|
||||
Args:
|
||||
msg (`Msg | list[Msg] | None`):
|
||||
The input message to the agent.
|
||||
"""
|
||||
if self.knowledge and msg:
|
||||
# Prepare the user input query
|
||||
query = None
|
||||
if isinstance(msg, Msg):
|
||||
query = msg.get_text_content()
|
||||
elif isinstance(msg, list):
|
||||
query = "\n".join(_.get_text_content() for _ in msg)
|
||||
|
||||
# Skip if the query is empty
|
||||
if not query:
|
||||
return
|
||||
|
||||
# Rewrite the query by the LLM if enabled
|
||||
if self.enable_rewrite_query:
|
||||
try:
|
||||
rewrite_prompt = await self.formatter.format(
|
||||
msgs=[
|
||||
Msg("system", self.sys_prompt, "system"),
|
||||
*await self.memory.get_memory(),
|
||||
Msg(
|
||||
"user",
|
||||
"<system-hint>Now you need to rewrite "
|
||||
"the above user query to be more specific and "
|
||||
"concise for knowledge retrieval. For "
|
||||
"example, rewrite the query 'what happened "
|
||||
"last day' to 'what happened on 2023-10-01' "
|
||||
"(assuming today is 2023-10-02)."
|
||||
"</system-hint>",
|
||||
"user",
|
||||
),
|
||||
],
|
||||
)
|
||||
stream_tmp = self.model.stream
|
||||
self.model.stream = False
|
||||
res = await self.model(
|
||||
rewrite_prompt,
|
||||
structured_model=_QueryRewriteModel,
|
||||
)
|
||||
self.model.stream = stream_tmp
|
||||
if res.metadata and res.metadata.get("rewritten_query"):
|
||||
query = res.metadata["rewritten_query"]
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
"Skipping the query rewriting due to error: %s",
|
||||
str(e),
|
||||
)
|
||||
|
||||
docs: list[Document] = []
|
||||
for kb in self.knowledge:
|
||||
# retrieve the user input query
|
||||
docs.extend(
|
||||
await kb.retrieve(query=query),
|
||||
)
|
||||
if docs:
|
||||
# Rerank by the relevance score
|
||||
docs = sorted(
|
||||
docs,
|
||||
key=lambda doc: doc.score or 0.0,
|
||||
reverse=True,
|
||||
)
|
||||
# Prepare the retrieved knowledge string
|
||||
retrieved_msg = Msg(
|
||||
name="user",
|
||||
content=[
|
||||
TextBlock(
|
||||
type="text",
|
||||
text=(
|
||||
"<retrieved_knowledge>Use the following "
|
||||
"content from the knowledge base(s) if it's "
|
||||
"helpful:\n"
|
||||
),
|
||||
),
|
||||
*[_.metadata.content for _ in docs],
|
||||
TextBlock(
|
||||
type="text",
|
||||
text="</retrieved_knowledge>",
|
||||
),
|
||||
],
|
||||
role="user",
|
||||
)
|
||||
if self.print_hint_msg:
|
||||
await self.print(retrieved_msg, True)
|
||||
await self.memory.add(retrieved_msg)
|
||||
@@ -1,116 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The base class for ReAct agent in agentscope."""
|
||||
from abc import abstractmethod
|
||||
from collections import OrderedDict
|
||||
from typing import Callable, Any
|
||||
|
||||
from ._agent_base import AgentBase
|
||||
from ._agent_meta import _ReActAgentMeta
|
||||
from ..message import Msg
|
||||
|
||||
|
||||
class ReActAgentBase(AgentBase, metaclass=_ReActAgentMeta):
|
||||
"""The ReAct agent base class.
|
||||
|
||||
To support ReAct algorithm, this class extends the AgentBase class by
|
||||
adding two abstract interfaces: reasoning and acting, while supporting
|
||||
hook functions at four positions: pre-reasoning, post-reasoning,
|
||||
pre-acting, and post-acting by the `_ReActAgentMeta` metaclass.
|
||||
"""
|
||||
|
||||
supported_hook_types: list[str] = [
|
||||
"pre_reply",
|
||||
"post_reply",
|
||||
"pre_print",
|
||||
"post_print",
|
||||
"pre_observe",
|
||||
"post_observe",
|
||||
"pre_reasoning",
|
||||
"post_reasoning",
|
||||
"pre_acting",
|
||||
"post_acting",
|
||||
]
|
||||
"""Supported hook types for the agent base class."""
|
||||
|
||||
_class_pre_reasoning_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"ReActAgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
],
|
||||
dict[str, Any] | None, # The modified kwargs or None
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level pre-reasoning hooks, taking `self` object, the input
|
||||
arguments as input"""
|
||||
|
||||
_class_post_reasoning_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"ReActAgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
Any, # output
|
||||
],
|
||||
Msg | None, # the modified output message or None
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level post-reasoning hooks, taking `self` object, the input
|
||||
arguments and the output message as input, and return the modified output
|
||||
message or None if no modification is needed."""
|
||||
|
||||
_class_pre_acting_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"ReActAgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
],
|
||||
dict[str, Any] | None, # The modified kwargs or None
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level pre-acting hooks, taking `self` object, the input
|
||||
arguments as input, and return the modified input arguments or None if no
|
||||
modification is needed."""
|
||||
|
||||
_class_post_acting_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"ReActAgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
Any, # output
|
||||
],
|
||||
Msg | None, # the modified output message or None
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level post-acting hooks, taking `self` object, the input
|
||||
arguments and the output message as input, and return the modified output
|
||||
message or None if no modification is needed."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
) -> None:
|
||||
"""Initialize the ReAct agent base class."""
|
||||
super().__init__()
|
||||
|
||||
# Init reasoning and acting hooks
|
||||
self._instance_pre_reasoning_hooks = OrderedDict()
|
||||
self._instance_post_reasoning_hooks = OrderedDict()
|
||||
self._instance_pre_acting_hooks = OrderedDict()
|
||||
self._instance_post_acting_hooks = OrderedDict()
|
||||
|
||||
@abstractmethod
|
||||
async def _reasoning(
|
||||
self,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""The reasoning process of the ReAct agent, which will be wrapped
|
||||
with pre- and post-hooks."""
|
||||
|
||||
@abstractmethod
|
||||
async def _acting(self, *args: Any, **kwargs: Any) -> Any:
|
||||
"""The acting process of the ReAct agent, which will be wrapped with
|
||||
pre- and post-hooks."""
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user