4 Commits

5460 changed files with 113958 additions and 381531 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

View File

@@ -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"}
]
}
```

View File

@@ -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`

View File

@@ -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对象。

View File

@@ -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
View File

4
backend_service/venv/bin/activate Executable file → Normal file
View 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
View 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
View 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

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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())

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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())

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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())

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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())

View File

@@ -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())

View File

@@ -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())

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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())

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -1 +1 @@
/home/huangfukk/miniconda3/bin/python3
/home/a/miniconda3/bin/python3

View File

@@ -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())

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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__':

View File

@@ -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.

View File

@@ -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 GitHubs `overview <https://github.com/jpadilla/pyjwt/graphs/contributors>`_.

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -1,5 +0,0 @@
Wheel-Version: 1.0
Generator: setuptools (75.6.0)
Root-Is-Purelib: true
Tag: py3-none-any

File diff suppressed because one or more lines are too long

View File

@@ -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>

View File

@@ -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

View File

@@ -1,5 +0,0 @@
Wheel-Version: 1.0
Generator: setuptools (80.9.0)
Root-Is-Purelib: true
Tag: py3-none-any

View File

@@ -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.
--------------------------------------------------------------------------------

View File

@@ -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__",
]

View File

@@ -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

View File

@@ -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")

View File

@@ -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))

View File

@@ -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__

View File

@@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
"""The version of agentscope."""
__version__ = "1.0.7"

View File

@@ -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",
]

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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