Compare commits
6 Commits
atom_actio
...
c4f851d387
| Author | SHA1 | Date | |
|---|---|---|---|
| c4f851d387 | |||
| a6c2027caa | |||
| ab6e09423b | |||
| d32520d83f | |||
| afd170c451 | |||
| fd89745950 |
128
README.md
128
README.md
@@ -19,6 +19,7 @@
|
||||
│ │ │ └── classifier_prompt.txt # 指令简单/复杂分类提示词
|
||||
│ │ ├── ...
|
||||
│ ├── generated_visualizations/ # 存放最新生成的py_tree可视化图像
|
||||
│ ├── generated_reasoning_content/ # 存放最新推理链Markdown(<plan_id>.md)
|
||||
│ └── requirements.txt # 后端服务的Python依赖
|
||||
│
|
||||
├── tools/
|
||||
@@ -26,7 +27,8 @@
|
||||
│ ├── knowledge_base/ # 【处理后】存放build_knowledge_base.py生成的.ndjson文件
|
||||
│ ├── vector_store/ # 【数据库】存放最终的ChromaDB向量数据库
|
||||
│ ├── build_knowledge_base.py # 【步骤1】用于将原始数据转换为自然语言知识
|
||||
│ └── ingest.py # 【步骤2】用于将自然语言知识摄入向量数据库
|
||||
│ ├── ingest.py # 【步骤2】用于将自然语言知识摄入向量数据库
|
||||
│ └── test_llama_server.py # 直接调用本地8081端口llama-server,支持 --system / --system-file
|
||||
│
|
||||
├── / # ROS2接口定义 (保持不变)
|
||||
└── docs/
|
||||
@@ -61,18 +63,6 @@
|
||||
```bash
|
||||
./llama-server -m ~/models/gguf/Qwen/Qwen3-8B-GGUF/Qwen3-8B-Q4_K_M.gguf --port 8081 --gpu-layers 36 --host 0.0.0.0 -c 8192
|
||||
```
|
||||
至此llama.cpp推理框架就完成了,无需进一步即可启动后端
|
||||
|
||||
如果使用vllm后端,则执行以下命令
|
||||
```bash
|
||||
vllm serve Qwen3-4B-AWQ --host=0.0.0.0 --port=8081 --dtype=auto --max-num-seqs=1 --max-model-len=16384 --served-model-name "qwen3-4b-awq" --trust-remote-code --gpu-memory-utilization=0.75 --uvicorn-log-level=debug
|
||||
```
|
||||
由于调用vllm时,在发送HTTP请求时需要指定模型名称,所以在启动后端服务前需要添加环境变量,执行以下命令
|
||||
```bash
|
||||
export CLASSIFIER_MODEL="qwen3-4b-awq"
|
||||
export SIMPLE_MODEL="qwen3-4b-awq"
|
||||
export COMPLEX_MODEL="qwen3-4b-awq"
|
||||
```
|
||||
|
||||
2. **Embedding模型部署**
|
||||
|
||||
@@ -107,6 +97,10 @@
|
||||
|
||||
通用API Key:`OPENAI_API_KEY`
|
||||
|
||||
推理链捕获相关:
|
||||
- `ENABLE_REASONING_CAPTURE`:是否允许模型返回含有 <think> 的原文以便捕获推理链;默认 true。
|
||||
- `REASONING_PREVIEW_LINES`:在后端日志中打印推理链预览的行数;默认 20。
|
||||
|
||||
示例:
|
||||
```bash
|
||||
export CLASSIFIER_MODEL="qwen2.5-1.8b-instruct"
|
||||
@@ -116,6 +110,10 @@ export CLASSIFIER_BASE_URL="http://$ORIN_IP:8081/v1"
|
||||
export SIMPLE_BASE_URL="http://$ORIN_IP:8081/v1"
|
||||
export COMPLEX_BASE_URL="http://$ORIN_IP:8081/v1"
|
||||
export OPENAI_API_KEY="sk-no-key-required"
|
||||
|
||||
# 推理链捕获(可选)
|
||||
export ENABLE_REASONING_CAPTURE=true # 默认已为true;如需关闭,设置为 false
|
||||
export REASONING_PREVIEW_LINES=30 # 调整日志预览行数
|
||||
```
|
||||
|
||||
### 测试简单模式
|
||||
@@ -129,6 +127,22 @@ python test_api.py
|
||||
|
||||
示例输入:“简单模式,起飞” 或 “起飞到10米”。返回结果为简单JSON(无 `root`):包含 `mode`、`action`、`plan_id`、`visualization_url`。
|
||||
|
||||
### 直接调用 llama-server(绕过后端)
|
||||
|
||||
当仅需测试本地 8081 端口的推理服务(OpenAI 兼容接口)时,可使用内置脚本:
|
||||
|
||||
```bash
|
||||
python tools/test_llama_server.py \
|
||||
--system-file backend_service/src/prompts/system_prompt.txt \
|
||||
--user "起飞到10米然后降落" \
|
||||
--base-url "http://127.0.0.1:8081/v1" \
|
||||
--verbose
|
||||
```
|
||||
|
||||
说明:
|
||||
- 支持 `--system` 或 `--system-file` 自定义提示词文件;`--system-file` 优先。
|
||||
- 默认解析 OpenAI 风格返回,若包含 `<think>` 推理内容会显示在输出中(具体取决于模型和服务配置)。
|
||||
|
||||
---
|
||||
|
||||
## 工作流程
|
||||
@@ -214,14 +228,96 @@ python ingest.py
|
||||
|
||||
完成前两个阶段后,即可启动并测试后端服务。
|
||||
|
||||
#### 1. 启动后端服务
|
||||
#### 1. 启动所有服务(推荐方式:一键启动脚本)
|
||||
|
||||
启动服务的关键在于**按顺序激活环境**:先激活ROS 2工作空间,再激活Conda环境。
|
||||
我们提供了一个一键启动脚本 `start_all.sh`,可以自动启动所有必需的服务:
|
||||
|
||||
```bash
|
||||
# 1. 切换到项目根目录
|
||||
cd /path/to/your/drone
|
||||
|
||||
# 2. 使用一键启动脚本(推荐)
|
||||
./start_all.sh start
|
||||
|
||||
# 或者直接运行(start是默认命令)
|
||||
./start_all.sh
|
||||
```
|
||||
|
||||
**脚本功能:**
|
||||
- 自动启动推理模型服务(llama-server,端口8081)
|
||||
- 自动启动Embedding模型服务(llama-server,端口8090)
|
||||
- 自动启动FastAPI后端服务(端口8000)
|
||||
- 自动检查端口占用、模型文件、环境配置等
|
||||
- 自动等待服务就绪
|
||||
- 统一管理日志文件(保存在 `logs/` 目录)
|
||||
|
||||
**环境变量配置(可选):**
|
||||
|
||||
在运行脚本前,可以通过环境变量自定义配置:
|
||||
|
||||
```bash
|
||||
# 设置llama-server路径(如果不在默认位置)
|
||||
export LLAMA_SERVER_DIR="/path/to/llama.cpp/build/bin"
|
||||
|
||||
# 设置模型路径(如果不在默认位置)
|
||||
export INFERENCE_MODEL="~/models/gguf/Qwen/Qwen3-8B-GGUF/Qwen3-8B-Q4_K_M.gguf"
|
||||
export EMBEDDING_MODEL="~/models/gguf/Qwen/Qwen3-embedding-4B/Qwen3-Embedding-4B-Q4_K_M.gguf"
|
||||
|
||||
# 设置Conda环境名称(如果使用不同的环境名)
|
||||
export CONDA_ENV="backend"
|
||||
|
||||
# 然后运行脚本
|
||||
./start_all.sh
|
||||
```
|
||||
|
||||
**脚本命令:**
|
||||
|
||||
```bash
|
||||
./start_all.sh start # 启动所有服务(默认)
|
||||
./start_all.sh stop # 停止所有服务
|
||||
./start_all.sh restart # 重启所有服务
|
||||
./start_all.sh status # 查看服务状态
|
||||
```
|
||||
|
||||
**日志查看:**
|
||||
|
||||
所有服务的日志都保存在 `logs/` 目录下:
|
||||
```bash
|
||||
# 查看所有日志
|
||||
tail -f logs/*.log
|
||||
|
||||
# 查看特定服务日志
|
||||
tail -f logs/inference_model.log # 推理模型
|
||||
tail -f logs/embedding_model.log # Embedding模型
|
||||
tail -f logs/fastapi.log # FastAPI服务
|
||||
```
|
||||
|
||||
#### 2. 手动启动服务(备选方式)
|
||||
|
||||
如果您需要手动控制每个服务的启动,可以按照以下步骤操作:
|
||||
|
||||
**启动推理模型服务:**
|
||||
|
||||
```bash
|
||||
cd /llama.cpp/build/bin
|
||||
./llama-server -m ~/models/gguf/Qwen/Qwen3-8B-GGUF/Qwen3-8B-Q4_K_M.gguf --port 8081 --gpu-layers 36 --host 0.0.0.0 -c 8192
|
||||
```
|
||||
|
||||
**启动Embedding模型服务:**
|
||||
|
||||
在另一个终端中:
|
||||
```bash
|
||||
cd /llama.cpp/build/bin
|
||||
./llama-server -m ~/models/gguf/Qwen/Qwen3-embedding-4B/Qwen3-Embedding-4B-Q4_K_M.gguf --gpu-layers 36 --port 8090 --embeddings --pooling last --host 0.0.0.0
|
||||
```
|
||||
|
||||
**启动FastAPI后端服务:**
|
||||
|
||||
在第三个终端中:
|
||||
```bash
|
||||
# 1. 切换到项目根目录
|
||||
cd /path/to/your/drone
|
||||
|
||||
# 2. 激活ROS 2编译环境
|
||||
# 作用:将我们编译好的`drone_interfaces`包的路径告知系统,否则Python会报`ModuleNotFoundError`。
|
||||
# 注意:此命令必须在每次打开新终端时执行一次。
|
||||
@@ -232,9 +328,9 @@ conda activate backend
|
||||
|
||||
# 4. 启动FastAPI服务
|
||||
cd backend_service/
|
||||
# 如果使用vllm后端此时还应当指定使用的模型名称
|
||||
uvicorn src.main:app --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
当您看到日志中出现 `Uvicorn running on http://0.0.0.0:8000` 时,表示服务已成功启动。
|
||||
|
||||
#### 2. 运行API接口测试
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
好的,我现在需要处理用户的任务指令,生成一个符合要求的行为树JSON。首先,我得仔细阅读用户的指令和参考知识,确保理解所有要求。
|
||||
|
||||
用户的目标是搜索并锁定危险性最高的气球(红色>蓝色>绿色),然后跟踪30秒后进行打击。参考知识中提到了三个地点,但用户可能希望搜索的区域是这些地点附近,或者需要根据这些坐标来规划路径。
|
||||
|
||||
首先,我需要确定无人机的起降点。参考知识中的地点坐标可能作为搜索区域的中心。比如,用户提到的“学生宿舍”坐标是(5,3,2),但可能需要选择一个合适的中心点进行搜索。不过用户没有明确指定搜索区域,可能需要使用search_pattern来覆盖这些区域,或者直接在某个中心点周围搜索。
|
||||
|
||||
接下来,任务流程应该是:起飞→飞往搜索区域→搜索目标→检测到目标后跟踪→打击。同时必须包含安全监控。
|
||||
|
||||
根据用户提供的参考知识,可能需要将搜索区域设置为某个中心点。比如,用户提到的“跷跷板”在(x:15, y:-8.5, z:1.2),但z坐标需要调整到至少1米,这里已经是1.2,没问题。或者可能选择其他地点作为搜索中心。但用户没有明确说明,可能需要假设搜索区域是这些地点附近,或者使用一个综合的中心点。
|
||||
|
||||
不过用户可能希望无人机先飞往某个特定的搜索区。比如,参考知识中的“学生宿舍”可能是一个可能的区域,但需要确认。或者用户可能希望无人机在某个中心点周围进行搜索。例如,使用search_pattern的中心点可能选在某个已知地点,比如“跷跷板”附近,或者综合多个点。
|
||||
|
||||
但用户没有明确指定搜索区域,所以可能需要使用search_pattern的中心点为某个已知地点,比如“跷跷板”的坐标,或者选择一个合理的中心点。例如,假设搜索区域是“跷跷板”所在的位置,那么中心坐标为(15, -8.5, 1.2)。或者可能需要将搜索区域设置为多个地点的组合,但用户没有说明,所以可能需要选择一个中心点。
|
||||
|
||||
接下来,考虑使用search_pattern来搜索,因为目标位置未知。参数中需要指定pattern_type,比如spiral或grid。假设选择spiral模式,覆盖更大的区域。中心点可能选在某个已知地点,比如“跷跷板”的坐标,或者综合多个点。但用户没有明确,所以可能需要选择一个合理的中心点,比如“跷跷板”的坐标。
|
||||
|
||||
然后,检测到目标后,需要跟踪30秒,再打击。所以流程是:起飞→飞往搜索区→搜索→检测→跟踪→打击→降落。
|
||||
|
||||
安全监控必须包含在Parallel节点中,监控电池和GPS,并在紧急情况下返航。
|
||||
|
||||
现在,构建行为树的结构:
|
||||
|
||||
根节点是Parallel,包含主任务和安全监控。主任务是Sequence,包含起飞、飞往搜索区、搜索、检测、跟踪、打击、降落。安全监控是Selector,包含电池和GPS条件,以及紧急处理Sequence。
|
||||
|
||||
在搜索部分,使用search_pattern,参数包括pattern_type为spiral,中心点选在某个已知地点,比如“跷跷板”的坐标(15, -8.5, 1.2),半径可能设为50米,覆盖较大区域。目标类别是balloon,描述为“红色气球危险性高于蓝色气球高于绿色气球”,但参数中description需要描述目标属性,比如“红>蓝>绿”。
|
||||
|
||||
检测到目标后,使用track_object,参数target_class为balloon,description为“红>蓝>绿”,track_time为30秒。然后strike_target,最后评估战损。
|
||||
|
||||
需要确保所有参数符合约束,比如z坐标在1-5000米之间,半径在5-1000米之间,速度等参数在合理范围。
|
||||
|
||||
现在,将各个步骤的参数填入JSON中。例如,起飞到2米,飞往搜索区的中心点可能选在“跷跷板”的坐标(15, -8.5, 1.2),但z需要调整到至少1米,这里已经是1.2。所以fly_to_waypoint的参数x=15,y=-8.5,z=1.2,接受半径2米。
|
||||
|
||||
搜索使用search_pattern,pattern_type为spiral,中心点为(15, -8.5, 1.2),半径设为50米,覆盖区域。目标类别是balloon,description为“红>蓝>绿”。
|
||||
|
||||
检测到目标后,使用track_object,参数target_class为balloon,description为“红>蓝>绿”,track_time为30秒,min_confidence设为0.7,safe_distance设为15米。
|
||||
|
||||
然后strike_target,参数target_class为balloon,description为“红>蓝>绿”,count为1。
|
||||
|
||||
最后,降落。
|
||||
|
||||
安全监控部分,电池阈值设为0.35,GPS的min_satellites设为8,紧急处理Sequence包括emergency_return和land。
|
||||
|
||||
现在,将所有步骤的参数填入JSON中,确保符合所有规则。
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 224 KiB After Width: | Height: | Size: 233 KiB |
@@ -15,8 +15,8 @@ chromadb>=0.4.0
|
||||
# Visualization
|
||||
graphviz>=0.20.0
|
||||
|
||||
# ROS 2 Python Client
|
||||
rclpy>=0.0.1
|
||||
# ROS 2 Python Client - 已注释,项目已与ROS2解耦
|
||||
# rclpy>=0.0.1
|
||||
|
||||
# Document Processing
|
||||
unstructured[all]>=0.11.0
|
||||
@@ -30,10 +30,10 @@ rich>=13.7.0
|
||||
# Type Hints Support
|
||||
typing-extensions>=4.8.0
|
||||
|
||||
# ROS 2 Build Dependencies
|
||||
empy==3.3.4
|
||||
catkin-pkg>=0.4.0
|
||||
lark>=1.1.0
|
||||
colcon-common-extensions>=0.3.0
|
||||
vcstool>=0.2.0
|
||||
rosdep>=0.22.0
|
||||
# ROS 2 Build Dependencies - 已注释,项目已与ROS2解耦
|
||||
# empy==3.3.4
|
||||
# catkin-pkg>=0.4.0
|
||||
# lark>=1.1.0
|
||||
# colcon-common-extensions>=0.3.0
|
||||
# vcstool>=0.2.0
|
||||
# rosdep>=0.22.0
|
||||
|
||||
Binary file not shown.
@@ -3,13 +3,13 @@ import os
|
||||
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
import logging
|
||||
import threading
|
||||
import rclpy
|
||||
# import threading # ROS2相关,已注释
|
||||
# import rclpy # ROS2相关,已注释
|
||||
|
||||
from .models import GeneratePlanRequest, ExecuteMissionRequest
|
||||
from .websocket_manager import websocket_manager
|
||||
from .py_tree_generator import py_tree_generator
|
||||
from .ros2_client import MissionActionClient
|
||||
# from .ros2_client import MissionActionClient # ROS2相关,已注释
|
||||
|
||||
# --- Application Setup ---
|
||||
app = FastAPI(
|
||||
@@ -23,14 +23,15 @@ static_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'gene
|
||||
app.mount("/static", StaticFiles(directory=static_dir), name="static")
|
||||
|
||||
# --- ROS2 Node and Client Initialization ---
|
||||
rclpy.init()
|
||||
ros2_client = MissionActionClient()
|
||||
# ROS2相关代码已注释,项目已与ROS2解耦
|
||||
# rclpy.init()
|
||||
# ros2_client = MissionActionClient()
|
||||
|
||||
def run_ros2_node():
|
||||
"""Spins the ROS2 node in a dedicated thread."""
|
||||
logging.info("Starting to spin ROS2 node...")
|
||||
rclpy.spin(ros2_client)
|
||||
logging.info("ROS2 node has stopped spinning.")
|
||||
# def run_ros2_node():
|
||||
# """Spins the ROS2 node in a dedicated thread."""
|
||||
# logging.info("Starting to spin ROS2 node...")
|
||||
# rclpy.spin(ros2_client)
|
||||
# logging.info("ROS2 node has stopped spinning.")
|
||||
|
||||
# --- API Endpoints ---
|
||||
|
||||
@@ -49,9 +50,12 @@ async def generate_plan_endpoint(request: GeneratePlanRequest):
|
||||
async def execute_mission_endpoint(request: ExecuteMissionRequest):
|
||||
"""
|
||||
Receives a `py_tree.json` and sends it to the drone for execution.
|
||||
ROS2相关功能已注释,项目已与ROS2解耦。
|
||||
"""
|
||||
ros2_client.send_goal(request.py_tree)
|
||||
return {"status": "execution_started"}
|
||||
# ROS2相关代码已注释
|
||||
# ros2_client.send_goal(request.py_tree)
|
||||
logging.warning("execute_mission endpoint called but ROS2 is disabled. Mission execution is not available.")
|
||||
return {"status": "execution_disabled", "message": "ROS2 integration is disabled. Mission execution is not available."}
|
||||
|
||||
@app.websocket("/ws/status")
|
||||
async def websocket_endpoint(websocket: WebSocket):
|
||||
@@ -73,21 +77,23 @@ async def websocket_endpoint(websocket: WebSocket):
|
||||
async def startup_event():
|
||||
"""
|
||||
On startup, get the current asyncio event loop and pass it to the websocket manager.
|
||||
Also, start the ROS2 node in a background thread.
|
||||
ROS2相关功能已注释,项目已与ROS2解耦。
|
||||
"""
|
||||
# Configure WebSocket Manager
|
||||
loop = asyncio.get_running_loop()
|
||||
websocket_manager.set_loop(loop)
|
||||
logging.info("WebSocket event loop configured.")
|
||||
|
||||
# ROS2相关代码已注释
|
||||
# Start ROS2 node in a background thread
|
||||
ros2_thread = threading.Thread(target=run_ros2_node, daemon=True)
|
||||
ros2_thread.start()
|
||||
logging.info("ROS2 node thread started.")
|
||||
# ros2_thread = threading.Thread(target=run_ros2_node, daemon=True)
|
||||
# ros2_thread.start()
|
||||
# logging.info("ROS2 node thread started.")
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown_event():
|
||||
logging.info("Backend service shutting down.")
|
||||
ros2_client.destroy_node()
|
||||
rclpy.shutdown()
|
||||
logging.info("ROS2 node shut down successfully.")
|
||||
# ROS2相关代码已注释
|
||||
# ros2_client.destroy_node()
|
||||
# rclpy.shutdown()
|
||||
# logging.info("ROS2 node shut down successfully.")
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**,需严格适配后端节点解析与Schema验证逻辑。
|
||||
任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。
|
||||
|
||||
|
||||
## 一、核心规则:确保后端能解析允许的节点(必严格遵守)
|
||||
后端会从提示词中解析允许的节点列表,以下节点定义部分**格式不可修改**,否则会导致解析失败(进而触发节点非法错误)。
|
||||
|
||||
#### 2. 可用节点定义 (必须遵守)
|
||||
你必须严格从以下JSON定义的列表中选择节点来构建行为树。不允许使用任何未定义的节点(如"lock_target"等)。
|
||||
## 一、核心节点定义(格式不可修改,确保后端解析)
|
||||
#### 1. 可用节点定义 (必须遵守)
|
||||
你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:
|
||||
```json
|
||||
{
|
||||
"actions": [
|
||||
{"name":"takeoff","params":{"altitude":"float, 范围[1,100],默认2"}},
|
||||
{"name":"land","params":{"mode":"string, 'current'/'home'"}},
|
||||
{"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":"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":"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","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":"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"}}
|
||||
@@ -28,33 +25,31 @@
|
||||
"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"}},
|
||||
{"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"}},
|
||||
{"name":"time_elapsed","params":{"duration":"[1,2700]秒"}},
|
||||
{"name":"gps_status","params":{"min_satellites":"int, 范围[6,15],必传(如8)"}}
|
||||
{"name":"gps_status","params":{"min_satellites":"int[6,15],必传(如8)"}}
|
||||
],
|
||||
"control_flow": [
|
||||
{"name":"Sequence","params":{},"children":"子节点数组(按序执行,全成功则成功)"},
|
||||
{"name":"Selector","params":{"memory":"默认true"},"children":"子节点数组(执行到成功为止)"},
|
||||
{"name":"Parallel","params":{"policy":"all_success/one_success"},"children":"子节点数组(同时执行)"}
|
||||
{"name":"Parallel","params":{"policy":"all_success"},"children":"子节点数组(同时执行,严禁用'one_success')"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 二、节点必填字段(后端Schema强制要求,缺一验证失败)
|
||||
每个节点必须包含以下字段,字段名不可自定义:
|
||||
1. **`type`**:节点类型(严格匹配)
|
||||
- 动作节点:`"action"`
|
||||
- 条件节点:`"condition"`
|
||||
- 控制流节点:`"Sequence"`/`"Selector"`/`"Parallel"`(与`name`字段值完全一致)
|
||||
2. **`name`**:节点名称(必须是上述JSON中`actions`/`conditions`/`control_flow`下的`name`值,如"gps_status"而非其他)
|
||||
3. **`params`**:参数对象(严格匹配上述JSON中对应节点的`params`定义,不可加自定义参数,如`object_detected`不可加"color",需用"description")
|
||||
4. **`children`**:子节点数组(仅控制流节点必含,动作/条件节点无此字段)
|
||||
每个节点必须包含以下字段,字段名/类型不可自定义:
|
||||
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`**:仅控制流节点必含(子节点数组),动作/条件节点无此字段。
|
||||
|
||||
|
||||
## 三、根节点与安全监控固定结构(后端安全验证必含)
|
||||
根节点必须是`Parallel`,且`children`包含`MainTask`(Sequence)和`SafetyMonitor`(Selector),结构不可修改:
|
||||
## 三、行为树固定结构(通用不变,确保安全验证)
|
||||
根节点必须是`Parallel`,`children`含`MainTask`(Sequence)和`SafetyMonitor`(Selector),结构不随任务类型(含优先级排序)修改:
|
||||
```json
|
||||
{
|
||||
"root": {
|
||||
@@ -67,15 +62,14 @@
|
||||
"name": "MainTask",
|
||||
"params": {},
|
||||
"children": [
|
||||
// 主任务步骤:按用户指令分解(如preflight_checks→takeoff→fly_to_waypoint→...→land)
|
||||
// 示例步骤(需替换为用户任务):
|
||||
// 通用主任务步骤(含优先级排序任务示例,需按用户指令替换):
|
||||
{"type":"action","name":"preflight_checks","params":{"check_level":"comprehensive"}},
|
||||
{"type":"action","name":"takeoff","params":{"altitude":2.0}},
|
||||
{"type":"action","name":"fly_to_waypoint","params":{"x":100.0,"y":80.0,"z":10.0}},
|
||||
{"type":"action","name":"object_detect","params":{"target_class":"person","description":"穿黑色衣服"}},
|
||||
{"type":"condition","name":"object_detected","params":{"target_class":"person","description":"穿黑色衣服"}},
|
||||
{"type":"action","name":"track_object","params":{"target_class":"person","description":"穿黑色衣服","track_time":30.0}},
|
||||
{"type":"action","name":"strike_target","params":{"target_class":"person","description":"穿黑色衣服"}},
|
||||
{"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"}}
|
||||
]
|
||||
},
|
||||
@@ -84,7 +78,6 @@
|
||||
"name": "SafetyMonitor",
|
||||
"params": {"memory": true},
|
||||
"children": [
|
||||
// 必含:电池监控(battery_above)、GPS监控(gps_status)、紧急处理(EmergencyHandler)
|
||||
{"type":"condition","name":"battery_above","params":{"threshold":0.3}},
|
||||
{"type":"condition","name":"gps_status","params":{"min_satellites":8}},
|
||||
{
|
||||
@@ -104,15 +97,21 @@
|
||||
```
|
||||
|
||||
|
||||
## 四、高频错误规避(后端验证常失败点)
|
||||
1. **禁止自定义节点**:如"lock_target"是未定义节点,必须删除,用"object_detect"+"object_detected"替代锁定逻辑。
|
||||
2. **参数名严格匹配**:
|
||||
- `track_object`用`track_time`(不可用`duration`);
|
||||
- `object_detected`描述目标属性用`description`(不可用`color`/`target`等);
|
||||
- `gps_status`必传`min_satellites`(范围6-15,如8)。
|
||||
3. **条件节点`object_detected`必含`target_class`**:值必须是上述JSON中`object_detect`的`target_class`列表中的值(如"person")。
|
||||
4. **控制流节点`name`与`type`一致**:如`type:"Sequence"`则`name:"Sequence"`,不可自定义`name`。
|
||||
## 四、优先级排序任务通用示例
|
||||
当用户指令中明确提出有多个待考察且具有优先级关系的物体时,节点描述须为优先级关系。比如当指令为已知有三个气球,危险级关系为红色气球大于蓝色气球大于绿色气球,要求优先跟踪最危险的气球时,节点的描述参考下表情形。
|
||||
| 用户指令场景 | `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":"(军用卡车>民用卡车>面包车)"}}` |
|
||||
|
||||
|
||||
## 五、输出要求
|
||||
仅输出1个严格符合上述所有规则的JSON对象,**确保后端能解析到所有节点(尤其是conditions中的gps_status),且无任何冗余内容**。
|
||||
## 五、高频错误规避(确保验证通过)
|
||||
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个严格符合上述所有规则的JSON对象,**确保:1. 优先级排序逻辑正确填入`description`;2. `target_class`匹配预定义列表;3. 行为树结构不变;4. 后端解析与Schema验证无错误**,无任何冗余内容。
|
||||
|
||||
@@ -201,7 +201,7 @@ 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"
|
||||
"clock", "vase", "scissors", "teddy_bear", "hair_drier", "toothbrush","balloon"
|
||||
]
|
||||
|
||||
# 递归节点定义
|
||||
@@ -337,35 +337,28 @@ def _generate_pytree_schema(allowed_actions: set, allowed_conditions: set) -> di
|
||||
|
||||
def _generate_simple_mode_schema(allowed_actions: set) -> dict:
|
||||
"""
|
||||
生成简单模式JSON Schema:{"root":{"type":"action","name":"<action_name>","params":{...}}}
|
||||
生成简单模式JSON Schema:{"mode":"simple","action":{...}}
|
||||
仅校验动作名称在允许集合内,以及基本结构完整性;参数按对象形状放宽,由上游提示词与运行时再约束。
|
||||
"""
|
||||
# 使用复杂模式Schema中的node定义,但限制root节点必须是action类型
|
||||
node_definition = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {"type": "string", "const": "action"},
|
||||
"name": {"type": "string", "enum": sorted(list(allowed_actions))},
|
||||
"params": {"type": "object"}
|
||||
},
|
||||
"required": ["type", "name"],
|
||||
"additionalProperties": False
|
||||
}
|
||||
|
||||
schema = {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "SimpleMode",
|
||||
"definitions": {
|
||||
"node": node_definition
|
||||
},
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"root": { "$ref": "#/definitions/node" }
|
||||
"mode": {"type": "string", "const": "simple"},
|
||||
"action": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string", "enum": sorted(list(allowed_actions))},
|
||||
"params": {"type": "object"}
|
||||
},
|
||||
"required": ["name"],
|
||||
"additionalProperties": True
|
||||
}
|
||||
},
|
||||
"required": ["root"],
|
||||
"required": ["mode", "action"],
|
||||
"additionalProperties": False
|
||||
}
|
||||
|
||||
return schema
|
||||
|
||||
def _validate_pytree_with_schema(pytree_instance: dict, schema: dict) -> bool:
|
||||
@@ -555,6 +548,16 @@ class PyTreeGenerator:
|
||||
# Updated output directory for visualizations
|
||||
self.vis_dir = os.path.abspath(os.path.join(self.base_dir, '..', 'generated_visualizations'))
|
||||
os.makedirs(self.vis_dir, exist_ok=True)
|
||||
# Reasoning content output directory (Markdown files)
|
||||
self.reasoning_dir = os.path.abspath(os.path.join(self.base_dir, '..', 'generated_reasoning_content'))
|
||||
os.makedirs(self.reasoning_dir, exist_ok=True)
|
||||
# 控制是否允许模型返回含 <think> 的原文(不强制JSON),以便提取推理链
|
||||
self.enable_reasoning_capture = os.getenv("ENABLE_REASONING_CAPTURE", "true").lower() in ("1", "true", "yes")
|
||||
# 终端预览的最大行数
|
||||
try:
|
||||
self.reasoning_preview_lines = int(os.getenv("REASONING_PREVIEW_LINES", "20"))
|
||||
except Exception:
|
||||
self.reasoning_preview_lines = 20
|
||||
# 加载提示词:复杂模式复用现有 system_prompt.txt;简单模式与分类器独立提示词
|
||||
self.complex_prompt = self._load_prompt("system_prompt.txt")
|
||||
self.simple_prompt = self._load_prompt("simple_mode_prompt.txt")
|
||||
@@ -571,6 +574,10 @@ class PyTreeGenerator:
|
||||
self.simple_base_url = os.getenv("SIMPLE_BASE_URL", f"http://{self.orin_ip}:8081/v1")
|
||||
self.complex_base_url = os.getenv("COMPLEX_BASE_URL", f"http://{self.orin_ip}:8081/v1")
|
||||
self.api_key = os.getenv("OPENAI_API_KEY", "sk-no-key-required")
|
||||
# 直接在代码中指定最大输出token数(不通过环境变量)
|
||||
self.classifier_max_tokens = 512
|
||||
self.simple_max_tokens = 8192
|
||||
self.complex_max_tokens = 8192
|
||||
|
||||
# 为不同用途分别创建客户端
|
||||
self.classifier_client = openai.OpenAI(api_key=self.api_key, base_url=self.classifier_base_url)
|
||||
@@ -612,6 +619,8 @@ class PyTreeGenerator:
|
||||
return None
|
||||
context_str = "\n\n".join(retrieved_docs)
|
||||
logging.info("--- 成功检索到上下文信息 ---")
|
||||
# 打印检索到的上下文内容
|
||||
logging.info(f"📚 检索到的上下文内容:\n{context_str}")
|
||||
return context_str
|
||||
except Exception as e:
|
||||
logging.error(f"从向量数据库检索时发生错误: {e}")
|
||||
@@ -633,7 +642,11 @@ class PyTreeGenerator:
|
||||
{"role": "user", "content": user_prompt}
|
||||
],
|
||||
temperature=0.0,
|
||||
response_format={"type": "json_object"}
|
||||
response_format={"type": "json_object"}, # 强制JSON输出,禁用思考功能
|
||||
max_tokens=self.classifier_max_tokens,
|
||||
# 禁用 Qwen3 模型的思考功能(通过 extra_body 传递)
|
||||
# 注意:如果 API 服务器不支持此参数,会忽略
|
||||
extra_body={"chat_template_kwargs": {"enable_thinking": False}}
|
||||
)
|
||||
class_str = classifier_resp.choices[0].message.content
|
||||
class_obj = json.loads(class_str)
|
||||
@@ -662,27 +675,102 @@ class PyTreeGenerator:
|
||||
final_user_prompt += augmentation
|
||||
else:
|
||||
logging.warning("未检索到上下文或检索失败,将使用原始用户提示词。")
|
||||
|
||||
# 构建完整的 final_prompt(准确反映实际发送给大模型的内容结构)
|
||||
# 注意:RAG检索结果被添加到 user prompt 中,而不是 system prompt
|
||||
# System Prompt: use_prompt(不包含RAG结果)
|
||||
# User Prompt: final_user_prompt(包含原始user_prompt + RAG检索结果)
|
||||
final_prompt = f"=== System Prompt ===\n{use_prompt}\n\n=== User Prompt ===\n{final_user_prompt}"
|
||||
for attempt in range(3):
|
||||
logging.info(f"--- 第 {attempt + 1}/3 次尝试生成Pytree ---")
|
||||
try:
|
||||
# 简单/复杂分流到不同模型与提示词
|
||||
client = self.simple_llm_client if mode == "simple" else self.complex_llm_client
|
||||
model_name = self.simple_model if mode == "simple" else self.complex_model
|
||||
response = client.chat.completions.create(
|
||||
model=model_name,
|
||||
messages=[
|
||||
# 始终强制JSON响应并禁用思考功能
|
||||
response_kwargs = {
|
||||
"model": model_name,
|
||||
"messages": [
|
||||
{"role": "system", "content": use_prompt},
|
||||
{"role": "user", "content": final_user_prompt}
|
||||
],
|
||||
temperature=0.1 if mode == "complex" else 0.0,
|
||||
response_format={"type": "json_object"}
|
||||
)
|
||||
pytree_str = response.choices[0].message.content
|
||||
"temperature": 0.1 if mode == "complex" else 0.0,
|
||||
"response_format": {"type": "json_object"}, # 始终强制JSON输出,禁用思考功能
|
||||
# 禁用 Qwen3 模型的思考功能(通过 extra_body 传递)
|
||||
# 注意:如果 API 服务器不支持此参数,会忽略
|
||||
"extra_body": {"chat_template_kwargs": {"enable_thinking": False}}
|
||||
}
|
||||
# 基于模式设定最大输出token数(直接在代码中配置)
|
||||
response_kwargs["max_tokens"] = self.simple_max_tokens if mode == "simple" else self.complex_max_tokens
|
||||
response = client.chat.completions.create(**response_kwargs)
|
||||
# 兼容可能存在的 reasoning_content 字段
|
||||
try:
|
||||
msg = response.choices[0].message
|
||||
msg_content = getattr(msg, "content", None)
|
||||
msg_reasoning = getattr(msg, "reasoning_content", None)
|
||||
except Exception:
|
||||
msg = response.choices[0]["message"] if isinstance(response.choices[0], dict) else None
|
||||
msg_content = (msg or {}).get("content") if isinstance(msg, dict) else None
|
||||
msg_reasoning = (msg or {}).get("reasoning_content") if isinstance(msg, dict) else None
|
||||
|
||||
combined_text = ""
|
||||
if isinstance(msg_reasoning, str) and msg_reasoning.strip():
|
||||
# 将 reasoning_content 包装为 <think>,便于统一解析
|
||||
combined_text += f"<think>\n{msg_reasoning}\n</think>\n"
|
||||
if isinstance(msg_content, str) and msg_content.strip():
|
||||
combined_text += msg_content
|
||||
pytree_str = combined_text if combined_text else (msg_content or "")
|
||||
raw_full_text_for_logging = pytree_str # 保存完整原文(含 <think>)以便失败时完整打印
|
||||
|
||||
# 提取 <think> 推理链内容(若存在)
|
||||
reasoning_text = None
|
||||
try:
|
||||
think_match = re.search(r"<think>([\s\S]*?)</think>", pytree_str)
|
||||
if think_match:
|
||||
reasoning_text = think_match.group(1).strip()
|
||||
# 去除推理文本后再尝试解析JSON
|
||||
pytree_str = re.sub(r"<think>[\s\S]*?</think>", "", pytree_str).strip()
|
||||
except Exception:
|
||||
reasoning_text = None
|
||||
# 单独捕获JSON解析错误并打印原始响应
|
||||
try:
|
||||
pytree_dict = json.loads(pytree_str)
|
||||
except json.JSONDecodeError as e:
|
||||
logging.error(f"❌ JSON解析失败(第 {attempt + 1}/3 次)。原始响应如下:\n{pytree_str}")
|
||||
logging.error(f"❌ JSON解析失败(第 {attempt + 1}/3 次)。\n—— 完整原始文本(含<think>) ——\n{raw_full_text_for_logging}")
|
||||
# 尝试打印响应对象的完整结构
|
||||
try:
|
||||
raw_response_dump = None
|
||||
if hasattr(response, 'model_dump_json'):
|
||||
raw_response_dump = response.model_dump_json(indent=2, exclude_none=False)
|
||||
elif hasattr(response, 'dict'):
|
||||
raw_response_dump = json.dumps(response.dict(), ensure_ascii=False, indent=2, default=str)
|
||||
else:
|
||||
# 兜底:尝试将choices与关键字段展开
|
||||
safe_obj = {
|
||||
"id": getattr(response, 'id', None),
|
||||
"model": getattr(response, 'model', None),
|
||||
"object": getattr(response, 'object', None),
|
||||
"usage": getattr(response, 'usage', None),
|
||||
"choices": [
|
||||
{
|
||||
"index": getattr(c, 'index', None),
|
||||
"finish_reason": getattr(c, 'finish_reason', None),
|
||||
"message": {
|
||||
"role": getattr(getattr(c, 'message', None), 'role', None),
|
||||
"content": getattr(getattr(c, 'message', None), 'content', None),
|
||||
"reasoning_content": getattr(getattr(c, 'message', None), 'reasoning_content', None)
|
||||
} if getattr(c, 'message', None) is not None else None
|
||||
}
|
||||
for c in getattr(response, 'choices', [])
|
||||
] if hasattr(response, 'choices') else None
|
||||
}
|
||||
raw_response_dump = json.dumps(safe_obj, ensure_ascii=False, indent=2, default=str)
|
||||
logging.error(f"—— 完整响应对象 ——\n{raw_response_dump}")
|
||||
except Exception as dump_e:
|
||||
try:
|
||||
logging.error(f"响应对象转储失败,repr如下:\n{repr(response)}")
|
||||
except Exception:
|
||||
pass
|
||||
continue
|
||||
|
||||
# 简单/复杂分别验证与返回
|
||||
@@ -696,14 +784,40 @@ class PyTreeGenerator:
|
||||
# 附加元信息并生成简单可视化(单动作)
|
||||
plan_id = str(uuid.uuid4())
|
||||
pytree_dict['plan_id'] = plan_id
|
||||
# 简单模式可视化:直接使用root节点
|
||||
# 简单模式可视化:构造一个简化节点图
|
||||
try:
|
||||
vis_filename = "py_tree.png"
|
||||
vis_path = os.path.join(self.vis_dir, vis_filename)
|
||||
_visualize_pytree(pytree_dict['root'], os.path.splitext(vis_path)[0])
|
||||
simple_node = {
|
||||
"type": "action",
|
||||
"name": pytree_dict.get('action', {}).get('name', 'action'),
|
||||
"params": pytree_dict.get('action', {}).get('params', {})
|
||||
}
|
||||
_visualize_pytree(simple_node, os.path.splitext(vis_path)[0])
|
||||
pytree_dict['visualization_url'] = f"/static/{vis_filename}"
|
||||
except Exception as e:
|
||||
logging.warning(f"简单模式可视化失败: {e}")
|
||||
|
||||
# 保存推理链(若有)
|
||||
try:
|
||||
if reasoning_text:
|
||||
reasoning_path = os.path.join(self.reasoning_dir, "reasoning_content.md")
|
||||
with open(reasoning_path, 'w', encoding='utf-8') as rf:
|
||||
rf.write(reasoning_text)
|
||||
logging.info(f"📝 推理链已保存: {reasoning_path}")
|
||||
# 终端预览(最多N行)
|
||||
try:
|
||||
lines = reasoning_text.splitlines()
|
||||
preview = "\n".join(lines[: self.reasoning_preview_lines])
|
||||
logging.info("🧠 推理链预览(前%d行):\n%s", self.reasoning_preview_lines, preview)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
logging.info("未在模型输出中发现 <think> 推理链片段。若需捕获,请设置 ENABLE_REASONING_CAPTURE=true 以放宽JSON强制格式。")
|
||||
except Exception as e:
|
||||
logging.warning(f"保存推理链Markdown失败: {e}")
|
||||
# 添加 final_prompt 到返回结果
|
||||
pytree_dict['final_prompt'] = final_prompt
|
||||
return pytree_dict
|
||||
|
||||
# 复杂模式回退:若模型误返回简单结构,则自动包装为含安全监控的行为树
|
||||
@@ -756,6 +870,27 @@ class PyTreeGenerator:
|
||||
vis_path = os.path.join(self.vis_dir, vis_filename)
|
||||
_visualize_pytree(pytree_dict['root'], os.path.splitext(vis_path)[0])
|
||||
pytree_dict['visualization_url'] = f"/static/{vis_filename}"
|
||||
|
||||
# 保存推理链(若有)
|
||||
try:
|
||||
if reasoning_text:
|
||||
reasoning_path = os.path.join(self.reasoning_dir, "reasoning_content.md")
|
||||
with open(reasoning_path, 'w', encoding='utf-8') as rf:
|
||||
rf.write(reasoning_text)
|
||||
logging.info(f"📝 推理链已保存: {reasoning_path}")
|
||||
# 终端预览(最多N行)
|
||||
try:
|
||||
lines = reasoning_text.splitlines()
|
||||
preview = "\n".join(lines[: self.reasoning_preview_lines])
|
||||
logging.info("🧠 推理链预览(前%d行):\n%s", self.reasoning_preview_lines, preview)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
logging.info("未在模型输出中发现 <think> 推理链片段。若需捕获,请设置 ENABLE_REASONING_CAPTURE=true 以放宽JSON强制格式。")
|
||||
except Exception as e:
|
||||
logging.warning(f"保存推理链Markdown失败: {e}")
|
||||
# 添加 final_prompt 到返回结果
|
||||
pytree_dict['final_prompt'] = final_prompt
|
||||
return pytree_dict
|
||||
else:
|
||||
# 打印未通过验证的Pytree以便排查
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
import rclpy
|
||||
from rclpy.action import ActionClient
|
||||
from rclpy.node import Node
|
||||
import json
|
||||
from typing import Dict, Any
|
||||
import logging
|
||||
|
||||
from drone_interfaces.action import ExecuteMission
|
||||
from .websocket_manager import websocket_manager
|
||||
|
||||
class MissionActionClient(Node):
|
||||
"""
|
||||
Interfaces with the drone's `ExecuteMission` ROS2 Action Server.
|
||||
"""
|
||||
def __init__(self):
|
||||
super().__init__('mission_action_client')
|
||||
self._action_client = ActionClient(self, ExecuteMission, 'execute_mission')
|
||||
self.get_logger().info("MissionActionClient initialized.")
|
||||
|
||||
def send_goal(self, py_tree: Dict[str, Any]):
|
||||
"""
|
||||
Sends the mission (py_tree) to the action server.
|
||||
"""
|
||||
if not self._action_client.server_is_ready():
|
||||
self.get_logger().error("Action server not available, goal not sent.")
|
||||
# Optionally, you could broadcast a status update to the frontend here
|
||||
return
|
||||
|
||||
self.get_logger().info("Received request to send goal to drone.")
|
||||
goal_msg = ExecuteMission.Goal()
|
||||
goal_msg.py_tree_json = json.dumps(py_tree)
|
||||
|
||||
self.get_logger().info(f"Sending goal to action server...")
|
||||
send_goal_future = self._action_client.send_goal_async(
|
||||
goal_msg,
|
||||
feedback_callback=self.feedback_callback
|
||||
)
|
||||
|
||||
send_goal_future.add_done_callback(self.goal_response_callback)
|
||||
|
||||
def goal_response_callback(self, future):
|
||||
goal_handle = future.result()
|
||||
if not goal_handle.accepted:
|
||||
self.get_logger().info('Goal rejected :(')
|
||||
return
|
||||
|
||||
self.get_logger().info('Goal accepted :)')
|
||||
|
||||
self._get_result_future = goal_handle.get_result_async()
|
||||
self._get_result_future.add_done_callback(self.get_result_callback)
|
||||
|
||||
def get_result_callback(self, future):
|
||||
result = future.result().result
|
||||
self.get_logger().info(f'Result: {{success: {result.success}, message: {result.message}}}')
|
||||
# Optionally, you can broadcast the final result via WebSocket here
|
||||
|
||||
def feedback_callback(self, feedback_msg):
|
||||
"""
|
||||
This callback is triggered by the action server.
|
||||
It forwards the status to the QGC plugin via the WebSocket manager in a thread-safe manner.
|
||||
"""
|
||||
feedback = feedback_msg.feedback
|
||||
feedback_payload = json.dumps({"node_id": feedback.node_id, "status": feedback.status})
|
||||
self.get_logger().info(f"Received feedback: {feedback_payload}")
|
||||
websocket_manager.broadcast(feedback_payload)
|
||||
|
||||
# Note: The rclpy.init() and spinning of the node will be handled in main.py
|
||||
@@ -22,7 +22,8 @@ class ConnectionManager:
|
||||
def broadcast(self, message: str):
|
||||
"""
|
||||
Thread-safely broadcasts a message to all active WebSocket connections.
|
||||
This method is designed to be called from a different thread (e.g., a ROS2 callback).
|
||||
This method is designed to be called from a different thread.
|
||||
(Note: ROS2 callback support has been removed as the project is decoupled from ROS2)
|
||||
"""
|
||||
if not self.loop:
|
||||
logging.error("Event loop not set in ConnectionManager. Cannot broadcast.")
|
||||
|
||||
248
backend_service/venv/bin/Activate.ps1
Executable file
248
backend_service/venv/bin/Activate.ps1
Executable file
@@ -0,0 +1,248 @@
|
||||
<#
|
||||
.Synopsis
|
||||
Activate a Python virtual environment for the current PowerShell session.
|
||||
|
||||
.Description
|
||||
Pushes the python executable for a virtual environment to the front of the
|
||||
$Env:PATH environment variable and sets the prompt to signify that you are
|
||||
in a Python virtual environment. Makes use of the command line switches as
|
||||
well as the `pyvenv.cfg` file values present in the virtual environment.
|
||||
|
||||
.Parameter VenvDir
|
||||
Path to the directory that contains the virtual environment to activate. The
|
||||
default value for this is the parent of the directory that the Activate.ps1
|
||||
script is located within.
|
||||
|
||||
.Parameter Prompt
|
||||
The prompt prefix to display when this virtual environment is activated. By
|
||||
default, this prompt is the name of the virtual environment folder (VenvDir)
|
||||
surrounded by parentheses and followed by a single space (ie. '(.venv) ').
|
||||
|
||||
.Example
|
||||
Activate.ps1
|
||||
Activates the Python virtual environment that contains the Activate.ps1 script.
|
||||
|
||||
.Example
|
||||
Activate.ps1 -Verbose
|
||||
Activates the Python virtual environment that contains the Activate.ps1 script,
|
||||
and shows extra information about the activation as it executes.
|
||||
|
||||
.Example
|
||||
Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
|
||||
Activates the Python virtual environment located in the specified location.
|
||||
|
||||
.Example
|
||||
Activate.ps1 -Prompt "MyPython"
|
||||
Activates the Python virtual environment that contains the Activate.ps1 script,
|
||||
and prefixes the current prompt with the specified string (surrounded in
|
||||
parentheses) while the virtual environment is active.
|
||||
|
||||
.Notes
|
||||
On Windows, it may be required to enable this Activate.ps1 script by setting the
|
||||
execution policy for the user. You can do this by issuing the following PowerShell
|
||||
command:
|
||||
|
||||
PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
|
||||
For more information on Execution Policies:
|
||||
https://go.microsoft.com/fwlink/?LinkID=135170
|
||||
|
||||
#>
|
||||
Param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[String]
|
||||
$VenvDir,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[String]
|
||||
$Prompt
|
||||
)
|
||||
|
||||
<# Function declarations --------------------------------------------------- #>
|
||||
|
||||
<#
|
||||
.Synopsis
|
||||
Remove all shell session elements added by the Activate script, including the
|
||||
addition of the virtual environment's Python executable from the beginning of
|
||||
the PATH variable.
|
||||
|
||||
.Parameter NonDestructive
|
||||
If present, do not remove this function from the global namespace for the
|
||||
session.
|
||||
|
||||
#>
|
||||
function global:deactivate ([switch]$NonDestructive) {
|
||||
# Revert to original values
|
||||
|
||||
# The prior prompt:
|
||||
if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
|
||||
Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
|
||||
Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
|
||||
}
|
||||
|
||||
# The prior PYTHONHOME:
|
||||
if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
|
||||
Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
|
||||
Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
|
||||
}
|
||||
|
||||
# The prior PATH:
|
||||
if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
|
||||
Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
|
||||
Remove-Item -Path Env:_OLD_VIRTUAL_PATH
|
||||
}
|
||||
|
||||
# Just remove the VIRTUAL_ENV altogether:
|
||||
if (Test-Path -Path Env:VIRTUAL_ENV) {
|
||||
Remove-Item -Path env:VIRTUAL_ENV
|
||||
}
|
||||
|
||||
# Just remove VIRTUAL_ENV_PROMPT altogether.
|
||||
if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
|
||||
Remove-Item -Path env:VIRTUAL_ENV_PROMPT
|
||||
}
|
||||
|
||||
# Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
|
||||
if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
|
||||
Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
|
||||
}
|
||||
|
||||
# Leave deactivate function in the global namespace if requested:
|
||||
if (-not $NonDestructive) {
|
||||
Remove-Item -Path function:deactivate
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.Description
|
||||
Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
|
||||
given folder, and returns them in a map.
|
||||
|
||||
For each line in the pyvenv.cfg file, if that line can be parsed into exactly
|
||||
two strings separated by `=` (with any amount of whitespace surrounding the =)
|
||||
then it is considered a `key = value` line. The left hand string is the key,
|
||||
the right hand is the value.
|
||||
|
||||
If the value starts with a `'` or a `"` then the first and last character is
|
||||
stripped from the value before being captured.
|
||||
|
||||
.Parameter ConfigDir
|
||||
Path to the directory that contains the `pyvenv.cfg` file.
|
||||
#>
|
||||
function Get-PyVenvConfig(
|
||||
[String]
|
||||
$ConfigDir
|
||||
) {
|
||||
Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
|
||||
|
||||
# Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
|
||||
$pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
|
||||
|
||||
# An empty map will be returned if no config file is found.
|
||||
$pyvenvConfig = @{ }
|
||||
|
||||
if ($pyvenvConfigPath) {
|
||||
|
||||
Write-Verbose "File exists, parse `key = value` lines"
|
||||
$pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
|
||||
|
||||
$pyvenvConfigContent | ForEach-Object {
|
||||
$keyval = $PSItem -split "\s*=\s*", 2
|
||||
if ($keyval[0] -and $keyval[1]) {
|
||||
$val = $keyval[1]
|
||||
|
||||
# Remove extraneous quotations around a string value.
|
||||
if ("'""".Contains($val.Substring(0, 1))) {
|
||||
$val = $val.Substring(1, $val.Length - 2)
|
||||
}
|
||||
|
||||
$pyvenvConfig[$keyval[0]] = $val
|
||||
Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
|
||||
}
|
||||
}
|
||||
}
|
||||
return $pyvenvConfig
|
||||
}
|
||||
|
||||
|
||||
<# Begin Activate script --------------------------------------------------- #>
|
||||
|
||||
# Determine the containing directory of this script
|
||||
$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||
$VenvExecDir = Get-Item -Path $VenvExecPath
|
||||
|
||||
Write-Verbose "Activation script is located in path: '$VenvExecPath'"
|
||||
Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
|
||||
Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
|
||||
|
||||
# Set values required in priority: CmdLine, ConfigFile, Default
|
||||
# First, get the location of the virtual environment, it might not be
|
||||
# VenvExecDir if specified on the command line.
|
||||
if ($VenvDir) {
|
||||
Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
|
||||
}
|
||||
else {
|
||||
Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
|
||||
$VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
|
||||
Write-Verbose "VenvDir=$VenvDir"
|
||||
}
|
||||
|
||||
# Next, read the `pyvenv.cfg` file to determine any required value such
|
||||
# as `prompt`.
|
||||
$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
|
||||
|
||||
# Next, set the prompt from the command line, or the config file, or
|
||||
# just use the name of the virtual environment folder.
|
||||
if ($Prompt) {
|
||||
Write-Verbose "Prompt specified as argument, using '$Prompt'"
|
||||
}
|
||||
else {
|
||||
Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
|
||||
if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
|
||||
Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
|
||||
$Prompt = $pyvenvCfg['prompt'];
|
||||
}
|
||||
else {
|
||||
Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)"
|
||||
Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
|
||||
$Prompt = Split-Path -Path $venvDir -Leaf
|
||||
}
|
||||
}
|
||||
|
||||
Write-Verbose "Prompt = '$Prompt'"
|
||||
Write-Verbose "VenvDir='$VenvDir'"
|
||||
|
||||
# Deactivate any currently active virtual environment, but leave the
|
||||
# deactivate function in place.
|
||||
deactivate -nondestructive
|
||||
|
||||
# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
|
||||
# that there is an activated venv.
|
||||
$env:VIRTUAL_ENV = $VenvDir
|
||||
|
||||
$env:VIRTUAL_ENV_PROMPT = $Prompt
|
||||
|
||||
if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
|
||||
|
||||
Write-Verbose "Setting prompt to '$Prompt'"
|
||||
|
||||
# Set the prompt to include the env name
|
||||
# Make sure _OLD_VIRTUAL_PROMPT is global
|
||||
function global:_OLD_VIRTUAL_PROMPT { "" }
|
||||
Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
|
||||
New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
|
||||
|
||||
function global:prompt {
|
||||
Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
|
||||
_OLD_VIRTUAL_PROMPT
|
||||
}
|
||||
}
|
||||
|
||||
# Clear PYTHONHOME
|
||||
if (Test-Path -Path Env:PYTHONHOME) {
|
||||
Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
|
||||
Remove-Item -Path Env:PYTHONHOME
|
||||
}
|
||||
|
||||
# Add the venv to the PATH
|
||||
Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
|
||||
$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"
|
||||
76
backend_service/venv/bin/activate
Executable file
76
backend_service/venv/bin/activate
Executable file
@@ -0,0 +1,76 @@
|
||||
# This file must be used with "source bin/activate" *from bash*
|
||||
# You cannot run it directly
|
||||
|
||||
deactivate () {
|
||||
# reset old environment variables
|
||||
if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
|
||||
PATH="${_OLD_VIRTUAL_PATH:-}"
|
||||
export PATH
|
||||
unset _OLD_VIRTUAL_PATH
|
||||
fi
|
||||
if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
|
||||
PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
|
||||
export PYTHONHOME
|
||||
unset _OLD_VIRTUAL_PYTHONHOME
|
||||
fi
|
||||
|
||||
# Call hash to forget past locations. Without forgetting
|
||||
# past locations the $PATH changes we made may not be respected.
|
||||
# See "man bash" for more details. hash is usually a builtin of your shell
|
||||
hash -r 2> /dev/null
|
||||
|
||||
if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
|
||||
PS1="${_OLD_VIRTUAL_PS1:-}"
|
||||
export PS1
|
||||
unset _OLD_VIRTUAL_PS1
|
||||
fi
|
||||
|
||||
unset VIRTUAL_ENV
|
||||
unset VIRTUAL_ENV_PROMPT
|
||||
if [ ! "${1:-}" = "nondestructive" ] ; then
|
||||
# Self destruct!
|
||||
unset -f deactivate
|
||||
fi
|
||||
}
|
||||
|
||||
# unset irrelevant variables
|
||||
deactivate nondestructive
|
||||
|
||||
# on Windows, a path can contain colons and backslashes and has to be converted:
|
||||
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)
|
||||
export VIRTUAL_ENV
|
||||
;;
|
||||
*)
|
||||
# use the path as-is
|
||||
export VIRTUAL_ENV=/home/huangfukk/DronePlanning/backend_service/venv
|
||||
;;
|
||||
esac
|
||||
|
||||
_OLD_VIRTUAL_PATH="$PATH"
|
||||
PATH="$VIRTUAL_ENV/"bin":$PATH"
|
||||
export PATH
|
||||
|
||||
VIRTUAL_ENV_PROMPT=venv
|
||||
export VIRTUAL_ENV_PROMPT
|
||||
|
||||
# unset PYTHONHOME if set
|
||||
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
|
||||
# could use `if (set -u; : $PYTHONHOME) ;` in bash
|
||||
if [ -n "${PYTHONHOME:-}" ] ; then
|
||||
_OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
|
||||
unset PYTHONHOME
|
||||
fi
|
||||
|
||||
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
|
||||
_OLD_VIRTUAL_PS1="${PS1:-}"
|
||||
PS1="("venv") ${PS1:-}"
|
||||
export PS1
|
||||
fi
|
||||
|
||||
# Call hash to forget past commands. Without forgetting
|
||||
# past commands the $PATH changes we made may not be respected
|
||||
hash -r 2> /dev/null
|
||||
27
backend_service/venv/bin/activate.csh
Executable file
27
backend_service/venv/bin/activate.csh
Executable file
@@ -0,0 +1,27 @@
|
||||
# This file must be used with "source bin/activate.csh" *from csh*.
|
||||
# You cannot run it directly.
|
||||
|
||||
# Created by Davide Di Blasi <davidedb@gmail.com>.
|
||||
# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>
|
||||
|
||||
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate'
|
||||
|
||||
# Unset irrelevant variables.
|
||||
deactivate nondestructive
|
||||
|
||||
setenv VIRTUAL_ENV /home/huangfukk/DronePlanning/backend_service/venv
|
||||
|
||||
set _OLD_VIRTUAL_PATH="$PATH"
|
||||
setenv PATH "$VIRTUAL_ENV/"bin":$PATH"
|
||||
setenv VIRTUAL_ENV_PROMPT venv
|
||||
|
||||
|
||||
set _OLD_VIRTUAL_PROMPT="$prompt"
|
||||
|
||||
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
|
||||
set prompt = "("venv") $prompt:q"
|
||||
endif
|
||||
|
||||
alias pydoc python -m pydoc
|
||||
|
||||
rehash
|
||||
69
backend_service/venv/bin/activate.fish
Executable file
69
backend_service/venv/bin/activate.fish
Executable file
@@ -0,0 +1,69 @@
|
||||
# This file must be used with "source <venv>/bin/activate.fish" *from fish*
|
||||
# (https://fishshell.com/). You cannot run it directly.
|
||||
|
||||
function deactivate -d "Exit virtual environment and return to normal shell environment"
|
||||
# reset old environment variables
|
||||
if test -n "$_OLD_VIRTUAL_PATH"
|
||||
set -gx PATH $_OLD_VIRTUAL_PATH
|
||||
set -e _OLD_VIRTUAL_PATH
|
||||
end
|
||||
if test -n "$_OLD_VIRTUAL_PYTHONHOME"
|
||||
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
|
||||
set -e _OLD_VIRTUAL_PYTHONHOME
|
||||
end
|
||||
|
||||
if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
|
||||
set -e _OLD_FISH_PROMPT_OVERRIDE
|
||||
# prevents error when using nested fish instances (Issue #93858)
|
||||
if functions -q _old_fish_prompt
|
||||
functions -e fish_prompt
|
||||
functions -c _old_fish_prompt fish_prompt
|
||||
functions -e _old_fish_prompt
|
||||
end
|
||||
end
|
||||
|
||||
set -e VIRTUAL_ENV
|
||||
set -e VIRTUAL_ENV_PROMPT
|
||||
if test "$argv[1]" != "nondestructive"
|
||||
# Self-destruct!
|
||||
functions -e deactivate
|
||||
end
|
||||
end
|
||||
|
||||
# Unset irrelevant variables.
|
||||
deactivate nondestructive
|
||||
|
||||
set -gx VIRTUAL_ENV /home/huangfukk/DronePlanning/backend_service/venv
|
||||
|
||||
set -gx _OLD_VIRTUAL_PATH $PATH
|
||||
set -gx PATH "$VIRTUAL_ENV/"bin $PATH
|
||||
set -gx VIRTUAL_ENV_PROMPT venv
|
||||
|
||||
# Unset PYTHONHOME if set.
|
||||
if set -q PYTHONHOME
|
||||
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
|
||||
set -e PYTHONHOME
|
||||
end
|
||||
|
||||
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
|
||||
# fish uses a function instead of an env var to generate the prompt.
|
||||
|
||||
# Save the current fish_prompt function as the function _old_fish_prompt.
|
||||
functions -c fish_prompt _old_fish_prompt
|
||||
|
||||
# With the original prompt function renamed, we can override with our own.
|
||||
function fish_prompt
|
||||
# Save the return status of the last command.
|
||||
set -l old_status $status
|
||||
|
||||
# Output the venv prompt; color taken from the blue of the Python logo.
|
||||
printf "%s(%s)%s " (set_color 4B8BBE) venv (set_color normal)
|
||||
|
||||
# Restore the return status of the previous command.
|
||||
echo "exit $old_status" | .
|
||||
# Output the original/"old" prompt.
|
||||
_old_fish_prompt
|
||||
end
|
||||
|
||||
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
|
||||
end
|
||||
7
backend_service/venv/bin/chroma
Executable file
7
backend_service/venv/bin/chroma
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from chromadb.cli.cli import app
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(app())
|
||||
7
backend_service/venv/bin/coloredlogs
Executable file
7
backend_service/venv/bin/coloredlogs
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from coloredlogs.cli import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/dashscope
Executable file
7
backend_service/venv/bin/dashscope
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/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())
|
||||
7
backend_service/venv/bin/distro
Executable file
7
backend_service/venv/bin/distro
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from distro.distro import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/dotenv
Executable file
7
backend_service/venv/bin/dotenv
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from dotenv.__main__ import cli
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(cli())
|
||||
7
backend_service/venv/bin/f2py
Executable file
7
backend_service/venv/bin/f2py
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from numpy.f2py.f2py2e import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/fastapi
Executable file
7
backend_service/venv/bin/fastapi
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from fastapi.cli import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/hf
Executable file
7
backend_service/venv/bin/hf
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from huggingface_hub.cli.hf import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/httpx
Executable file
7
backend_service/venv/bin/httpx
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from httpx import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/humanfriendly
Executable file
7
backend_service/venv/bin/humanfriendly
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from humanfriendly.cli import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/isympy
Executable file
7
backend_service/venv/bin/isympy
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from isympy import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/json_repair
Executable file
7
backend_service/venv/bin/json_repair
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/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())
|
||||
7
backend_service/venv/bin/jsonschema
Executable file
7
backend_service/venv/bin/jsonschema
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from jsonschema.cli import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/markdown-it
Executable file
7
backend_service/venv/bin/markdown-it
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from markdown_it.cli.parse import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/mcp
Executable file
7
backend_service/venv/bin/mcp
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/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())
|
||||
7
backend_service/venv/bin/normalizer
Executable file
7
backend_service/venv/bin/normalizer
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from charset_normalizer.cli import cli_detect
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(cli_detect())
|
||||
7
backend_service/venv/bin/numpy-config
Executable file
7
backend_service/venv/bin/numpy-config
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from numpy._configtool import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/onnxruntime_test
Executable file
7
backend_service/venv/bin/onnxruntime_test
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from onnxruntime.tools.onnxruntime_test import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/openai
Executable file
7
backend_service/venv/bin/openai
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from openai.cli import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
8
backend_service/venv/bin/pip
Executable file
8
backend_service/venv/bin/pip
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from pip._internal.cli.main import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
8
backend_service/venv/bin/pip3
Executable file
8
backend_service/venv/bin/pip3
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from pip._internal.cli.main import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
8
backend_service/venv/bin/pip3.13
Executable file
8
backend_service/venv/bin/pip3.13
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from pip._internal.cli.main import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/pybase64
Executable file
7
backend_service/venv/bin/pybase64
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from pybase64.__main__ import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/pygmentize
Executable file
7
backend_service/venv/bin/pygmentize
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from pygments.cmdline import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/pyjson5
Executable file
7
backend_service/venv/bin/pyjson5
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/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())
|
||||
7
backend_service/venv/bin/pyproject-build
Executable file
7
backend_service/venv/bin/pyproject-build
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from build.__main__ import entrypoint
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(entrypoint())
|
||||
7
backend_service/venv/bin/pyrsa-decrypt
Executable file
7
backend_service/venv/bin/pyrsa-decrypt
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.cli import decrypt
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(decrypt())
|
||||
7
backend_service/venv/bin/pyrsa-encrypt
Executable file
7
backend_service/venv/bin/pyrsa-encrypt
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.cli import encrypt
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(encrypt())
|
||||
7
backend_service/venv/bin/pyrsa-keygen
Executable file
7
backend_service/venv/bin/pyrsa-keygen
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.cli import keygen
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(keygen())
|
||||
7
backend_service/venv/bin/pyrsa-priv2pub
Executable file
7
backend_service/venv/bin/pyrsa-priv2pub
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.util import private_to_public
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(private_to_public())
|
||||
7
backend_service/venv/bin/pyrsa-sign
Executable file
7
backend_service/venv/bin/pyrsa-sign
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.cli import sign
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(sign())
|
||||
7
backend_service/venv/bin/pyrsa-verify
Executable file
7
backend_service/venv/bin/pyrsa-verify
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.cli import verify
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(verify())
|
||||
1
backend_service/venv/bin/python
Symbolic link
1
backend_service/venv/bin/python
Symbolic link
@@ -0,0 +1 @@
|
||||
python3
|
||||
1
backend_service/venv/bin/python3
Symbolic link
1
backend_service/venv/bin/python3
Symbolic link
@@ -0,0 +1 @@
|
||||
/home/huangfukk/miniconda3/bin/python3
|
||||
1
backend_service/venv/bin/python3.13
Symbolic link
1
backend_service/venv/bin/python3.13
Symbolic link
@@ -0,0 +1 @@
|
||||
python3
|
||||
7
backend_service/venv/bin/shortuuid
Executable file
7
backend_service/venv/bin/shortuuid
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/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())
|
||||
7
backend_service/venv/bin/tiny-agents
Executable file
7
backend_service/venv/bin/tiny-agents
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from huggingface_hub.inference._mcp.cli import app
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(app())
|
||||
7
backend_service/venv/bin/tqdm
Executable file
7
backend_service/venv/bin/tqdm
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from tqdm.cli import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/typer
Executable file
7
backend_service/venv/bin/typer
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from typer.cli import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/uvicorn
Executable file
7
backend_service/venv/bin/uvicorn
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from uvicorn.main import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/watchfiles
Executable file
7
backend_service/venv/bin/watchfiles
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from watchfiles.cli import cli
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(cli())
|
||||
7
backend_service/venv/bin/websockets
Executable file
7
backend_service/venv/bin/websockets
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from websockets.cli import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
7
backend_service/venv/bin/wsdump
Executable file
7
backend_service/venv/bin/wsdump
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from websocket._wsdump import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
29
backend_service/venv/lib/python3.13/site-packages/COPYING
Normal file
29
backend_service/venv/lib/python3.13/site-packages/COPYING
Normal file
@@ -0,0 +1,29 @@
|
||||
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.
|
||||
@@ -0,0 +1,7 @@
|
||||
Authors
|
||||
=======
|
||||
|
||||
``pyjwt`` is currently written and maintained by `Jose Padilla <https://github.com/jpadilla>`_.
|
||||
Originally written and maintained by `Jeff Lindsay <https://github.com/progrium>`_.
|
||||
|
||||
A full list of contributors can be found on GitHub’s `overview <https://github.com/jpadilla/pyjwt/graphs/contributors>`_.
|
||||
@@ -0,0 +1 @@
|
||||
pip
|
||||
@@ -0,0 +1,21 @@
|
||||
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.
|
||||
@@ -0,0 +1,106 @@
|
||||
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
|
||||
@@ -0,0 +1,32 @@
|
||||
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
|
||||
@@ -0,0 +1,5 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: setuptools (75.6.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
jwt
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -0,0 +1,33 @@
|
||||
# This is a stub package designed to roughly emulate the _yaml
|
||||
# extension module, which previously existed as a standalone module
|
||||
# and has been moved into the `yaml` package namespace.
|
||||
# It does not perfectly mimic its old counterpart, but should get
|
||||
# close enough for anyone who's relying on it even when they shouldn't.
|
||||
import yaml
|
||||
|
||||
# in some circumstances, the yaml module we imoprted may be from a different version, so we need
|
||||
# to tread carefully when poking at it here (it may not have the attributes we expect)
|
||||
if not getattr(yaml, '__with_libyaml__', False):
|
||||
from sys import version_info
|
||||
|
||||
exc = ModuleNotFoundError if version_info >= (3, 6) else ImportError
|
||||
raise exc("No module named '_yaml'")
|
||||
else:
|
||||
from yaml._yaml import *
|
||||
import warnings
|
||||
warnings.warn(
|
||||
'The _yaml extension module is now located at yaml._yaml'
|
||||
' and its location is subject to change. To use the'
|
||||
' LibYAML-based parser and emitter, import from `yaml`:'
|
||||
' `from yaml import CLoader as Loader, CDumper as Dumper`.',
|
||||
DeprecationWarning
|
||||
)
|
||||
del warnings
|
||||
# Don't `del yaml` here because yaml is actually an existing
|
||||
# namespace member of _yaml.
|
||||
|
||||
__name__ = '_yaml'
|
||||
# If the module is top-level (i.e. not a part of any specific package)
|
||||
# then the attribute should be set to ''.
|
||||
# https://docs.python.org/3.8/library/types.html
|
||||
__package__ = ''
|
||||
@@ -0,0 +1 @@
|
||||
pip
|
||||
@@ -0,0 +1,547 @@
|
||||
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>
|
||||
@@ -0,0 +1,315 @@
|
||||
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
|
||||
@@ -0,0 +1,5 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: setuptools (80.9.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@@ -0,0 +1,391 @@
|
||||
|
||||
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.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
@@ -0,0 +1 @@
|
||||
agentscope
|
||||
@@ -0,0 +1,133 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The agentscope serialization module"""
|
||||
import os
|
||||
|
||||
import requests
|
||||
|
||||
from . import exception
|
||||
from . import module
|
||||
from . import message
|
||||
from . import model
|
||||
from . import tool
|
||||
from . import formatter
|
||||
from . import memory
|
||||
from . import agent
|
||||
from . import session
|
||||
from . import embedding
|
||||
from . import token
|
||||
from . import evaluate
|
||||
from . import pipeline
|
||||
from . import tracing
|
||||
from . import rag
|
||||
|
||||
from ._logging import (
|
||||
logger,
|
||||
setup_logger,
|
||||
)
|
||||
from .hooks import _equip_as_studio_hooks
|
||||
from ._version import __version__
|
||||
|
||||
|
||||
def init(
|
||||
project: str | None = None,
|
||||
name: str | None = None,
|
||||
logging_path: str | None = None,
|
||||
logging_level: str = "INFO",
|
||||
studio_url: str | None = None,
|
||||
tracing_url: str | None = None,
|
||||
) -> None:
|
||||
"""Initialize the agentscope library.
|
||||
|
||||
Args:
|
||||
project (`str | None`, optional):
|
||||
The project name.
|
||||
name (`str | None`, optional):
|
||||
The name of the run.
|
||||
logging_path (`str | None`, optional):
|
||||
The path to saving the log file. If not provided, logs will not be
|
||||
saved.
|
||||
logging_level (`str | None`, optional):
|
||||
The logging level. Defaults to "INFO".
|
||||
studio_url (`str | None`, optional):
|
||||
The URL of the AgentScope Studio to connect to.
|
||||
tracing_url (`str | None`, optional):
|
||||
The URL of the tracing endpoint, which can connect to third-party
|
||||
OpenTelemetry tracing platforms like Arize-Phoenix and Langfuse.
|
||||
If not provided and `studio_url` is provided, it will send traces
|
||||
to the AgentScope Studio's tracing endpoint.
|
||||
"""
|
||||
|
||||
from . import _config
|
||||
|
||||
if project:
|
||||
_config.project = project
|
||||
|
||||
if name:
|
||||
_config.name = name
|
||||
|
||||
setup_logger(logging_level, logging_path)
|
||||
|
||||
if studio_url:
|
||||
# Register the run
|
||||
data = {
|
||||
"id": _config.run_id,
|
||||
"project": _config.project,
|
||||
"name": _config.name,
|
||||
"timestamp": _config.created_at,
|
||||
"pid": os.getpid(),
|
||||
"status": "running",
|
||||
# Deprecated fields
|
||||
"run_dir": "",
|
||||
}
|
||||
response = requests.post(
|
||||
url=f"{studio_url}/trpc/registerRun",
|
||||
json=data,
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
from .agent import UserAgent, StudioUserInput
|
||||
|
||||
UserAgent.override_class_input_method(
|
||||
StudioUserInput(
|
||||
studio_url=studio_url,
|
||||
run_id=_config.run_id,
|
||||
max_retries=3,
|
||||
),
|
||||
)
|
||||
|
||||
_equip_as_studio_hooks(studio_url)
|
||||
|
||||
if tracing_url:
|
||||
endpoint = tracing_url
|
||||
else:
|
||||
endpoint = studio_url.strip("/") + "/v1/traces" if studio_url else None
|
||||
|
||||
if endpoint:
|
||||
from .tracing import setup_tracing
|
||||
|
||||
setup_tracing(endpoint=endpoint)
|
||||
|
||||
|
||||
__all__ = [
|
||||
# modules
|
||||
"exception",
|
||||
"module",
|
||||
"message",
|
||||
"model",
|
||||
"tool",
|
||||
"formatter",
|
||||
"memory",
|
||||
"agent",
|
||||
"session",
|
||||
"logger",
|
||||
"embedding",
|
||||
"token",
|
||||
"evaluate",
|
||||
"pipeline",
|
||||
"tracing",
|
||||
"rag",
|
||||
# functions
|
||||
"init",
|
||||
"setup_logger",
|
||||
"__version__",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
# -*- 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
|
||||
@@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The logger for agentscope."""
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
_DEFAULT_FORMAT = (
|
||||
"%(asctime)s | %(levelname)-7s | "
|
||||
"%(module)s:%(funcName)s:%(lineno)s - %(message)s"
|
||||
)
|
||||
|
||||
logger = logging.getLogger("as")
|
||||
|
||||
|
||||
def setup_logger(
|
||||
level: str,
|
||||
filepath: str | None = None,
|
||||
) -> None:
|
||||
"""Set up the agentscope logger.
|
||||
|
||||
Args:
|
||||
level (`str`):
|
||||
The logging level, chosen from "INFO", "DEBUG", "WARNING",
|
||||
"ERROR", "CRITICAL".
|
||||
filepath (`str | None`, optional):
|
||||
The filepath to save the logging output.
|
||||
"""
|
||||
if level not in ["INFO", "DEBUG", "WARNING", "ERROR", "CRITICAL"]:
|
||||
raise ValueError(
|
||||
f"Invalid logging level: {level}. Must be one of "
|
||||
f"'INFO', 'DEBUG', 'WARNING', 'ERROR', 'CRITICAL'.",
|
||||
)
|
||||
logger.handlers.clear()
|
||||
logger.setLevel(level)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setFormatter(logging.Formatter(_DEFAULT_FORMAT))
|
||||
logger.addHandler(handler)
|
||||
|
||||
if filepath:
|
||||
handler = logging.FileHandler(filepath)
|
||||
handler.setFormatter(logging.Formatter(_DEFAULT_FORMAT))
|
||||
logger.addHandler(handler)
|
||||
|
||||
logger.propagate = False
|
||||
|
||||
|
||||
setup_logger("INFO")
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,285 @@
|
||||
# -*- 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))
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The mixin for agentscope."""
|
||||
|
||||
|
||||
class DictMixin(dict):
|
||||
"""The dictionary mixin that allows attribute-style access."""
|
||||
|
||||
__setattr__ = dict.__setitem__
|
||||
__getattr__ = dict.__getitem__
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The version of agentscope."""
|
||||
|
||||
__version__ = "1.0.7"
|
||||
@@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The agent base class."""
|
||||
from ._agent_base import AgentBase
|
||||
from ._react_agent_base import ReActAgentBase
|
||||
from ._react_agent import ReActAgent
|
||||
from ._user_input import (
|
||||
UserInputBase,
|
||||
UserInputData,
|
||||
TerminalUserInput,
|
||||
StudioUserInput,
|
||||
)
|
||||
from ._user_agent import UserAgent
|
||||
|
||||
|
||||
__all__ = [
|
||||
"AgentBase",
|
||||
"ReActAgentBase",
|
||||
"ReActAgent",
|
||||
"UserInputData",
|
||||
"UserInputBase",
|
||||
"TerminalUserInput",
|
||||
"StudioUserInput",
|
||||
"UserAgent",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,703 @@
|
||||
# -*- 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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user