已合并
initial commit #1
initial commit #1
已合并
王明琦创建于 3月16日
61 个文件变更+8727-0
A.gitignore+116-0
@@ -0,0 +1,116 @@
1+# Dependencies
2+node_modules
3+npm-debug.log*
4+yarn-debug.log*
5+yarn-error.log*
6+pnpm-debug.log*
7+ 
8+# Build outputs
9+dist/
10+build/
11+.next/
12+out/
13+ 
14+# Environment variables
15+.env
16+.env.local
17+.env.development.local
18+.env.test.local
19+.env.production.local
20+ 
21+# IDE and editor files
22+.vscode/
23+.idea/
24+*.swp
25+*.swo
26+*~
27+ 
28+# OS generated files
29+.DS_Store
30+.DS_Store?
31+._*
32+.Spotlight-V100
33+.Trashes
34+ehthumbs.db
35+Thumbs.db
36+ 
37+# Logs
38+logs
39+*.log
40+ 
41+# Runtime data
42+pids
43+*.pid
44+*.seed
45+*.pid.lock
46+ 
47+# Coverage directory used by tools like istanbul
48+coverage/
49+*.lcov
50+ 
51+# nyc test coverage
52+.nyc_output
53+ 
54+# Dependency directories
55+jspm_packages/
56+ 
57+# Optional npm cache directory
58+.npm
59+ 
60+# Optional eslint cache
61+.eslintcache
62+ 
63+# Optional REPL history
64+.node_repl_history
65+ 
66+# Output of 'npm pack'
67+*.tgz
68+ 
69+# Yarn Integrity file
70+.yarn-integrity
71+ 
72+# parcel-bundler cache (https://parceljs.org/)
73+.cache
74+.parcel-cache
75+ 
76+# Vite cache
77+.vite
78+ 
79+# TypeScript cache
80+*.tsbuildinfo
81+ 
82+# uv.lock (keep versioned)
83+uv.lock
84+ 
85+# Python
86+*.pyc
87+*.pyo
88+*.pyd
89+__pycache__/
90+*.so
91+.Python
92+*.db
93+backend/venv/*
94+.venv/*
95+venv/*
96+ENV/*
97+env/*
98+.conda/*
99+*.egg-info
100+.eggs/
101+dist/
102+build/
103+*.egg
104+ 
105+# uv temp files
106+tmpclaude-*
107+ 
108+# pytest
109+.pytest_cache/
110+.coverage
111+htmlcov/
112+ 
113+# mypy
114+.mypy_cache/
115+.dmypy.json
116+dmypy.json
@@ -0,0 +1,32 @@
1+[build-system]
2+requires = ["setuptools>=61.0", "wheel"]
3+build-backend = "setuptools.build_meta"
4+ 
5+[project]
6+name = "openjiuwen-runtime-examples-llm-agent"
7+version = "0.1.0"
8+description = "OpenJiuwen Runtime"
9+requires-python = ">=3.11.4"
10+dependencies = [
11+]
12+ 
13+[tool.uv]
14+default-groups = ['dev']
15+ 
16+[dependency-groups]
17+dev = [
18+ "coverage==7.8.0",
19+ "pytest==8.3.5",
20+ "pytest-asyncio==1.2.0",
21+ "pytest-mock==3.14.0",
22+ "ruff==0.9.10",
23+]
24+ 
25+[[tool.uv.index]]
26+url = "https://mirrors.aliyun.com/pypi/simple/"
27+ 
28+[tool.setuptools]
29+packages = ["openjiuwen_runtime.examples.llm_agent"]
30+ 
31+[tool.setuptools.package-dir]
32+"openjiuwen_runtime.examples.llm_agent" = "src"
The file is empty
@@ -0,0 +1,32 @@
1+[build-system]
2+requires = ["setuptools>=61.0", "wheel"]
3+build-backend = "setuptools.build_meta"
4+ 
5+[project]
6+name = "openjiuwen-runtime-examples-workflow-agent"
7+version = "0.1.0"
8+description = "OpenJiuwen Runtime"
9+requires-python = ">=3.11.4"
10+dependencies = [
11+]
12+ 
13+[tool.uv]
14+default-groups = ['dev']
15+ 
16+[dependency-groups]
17+dev = [
18+ "coverage==7.8.0",
19+ "pytest==8.3.5",
20+ "pytest-asyncio==1.2.0",
21+ "pytest-mock==3.14.0",
22+ "ruff==0.9.10",
23+]
24+ 
25+[[tool.uv.index]]
26+url = "https://mirrors.aliyun.com/pypi/simple/"
27+ 
28+[tool.setuptools]
29+packages = ["openjiuwen_runtime.examples.workflow_agent"]
30+ 
31+[tool.setuptools.package-dir]
32+"openjiuwen_runtime.examples.workflow_agent" = "src"
The file is empty
The file is empty
@@ -0,0 +1,59 @@
1+# Python
2+__pycache__/
3+*.py[cod]
4+*$py.class
5+*.so
6+.Python
7+build/
8+develop-eggs/
9+dist/
10+downloads/
11+eggs/
12+.eggs/
13+lib/
14+lib64/
15+parts/
16+sdist/
17+var/
18+wheels/
19+*.egg-info/
20+.installed.cfg
21+*.egg
22+ 
23+# Virtual environments
24+.venv/
25+venv/
26+ENV/
27+env/
28+ 
29+# IDE
30+.vscode/
31+.idea/
32+*.swp
33+*.swo
34+*~
35+ 
36+# Testing
37+.pytest_cache/
38+.coverage
39+htmlcov/
40+.tox/
41+ 
42+# Environment
43+.env
44+.env.local
45+ 
46+# Database
47+*.db
48+*.sqlite
49+*.sqlite3
50+ 
51+# Logs
52+*.log
53+ 
54+# OS
55+.DS_Store
56+Thumbs.db
57+ 
58+# Claude
59+.claude/
@@ -0,0 +1,294 @@
1+# Agent Runtime Manager
2+ 
3+**openjiuwen-runtime** 的部署管理系统,提供 Agent 和 Plugin 的部署、查询和管理功能。
4+ 
5+## 核心特性
6+ 
7+### 虚拟环境隔离
8+- 每个部署使用独立的虚拟环境,避免依赖冲突
9+- 删除部署时自动清理虚拟环境
10+- 支持跨平台(Windows/Linux/Mac)
11+ 
12+### WHL 包部署
13+- 标准化的 Python 包分发格式
14+- 自动解析包名,无需手动指定
15+- 自动安装 WHL 包依赖到独立虚拟环境
16+ 
17+### 灵活的管理方式
18+- **CLI 模式**: 命令行工具,适合本地开发测试
19+- **SDK 模式**: Python SDK,适合集成到其他系统
20+- **Server 模式**: REST API(预留,供 AgentStudio 调用)
21+ 
22+## 快速开始
23+ 
24+### 1. 安装 CLI
25+ 
26+```bash
27+# 进入 CLI 目录
28+cd cli
29+ 
30+# 创建虚拟环境并安装依赖
31+uv venv
32+uv sync
33+ 
34+# 安装 CLI(editable 模式)
35+uv pip install -e ./
36+```
37+ 
38+### 2. 准备 WHL 包
39+ 
40+```bash
41+# 构建示例 Agent WHL 包
42+cd examples/my_agent
43+py -m build --outdir ../../dist
44+```
45+ 
46+### 3. 部署 Agent
47+ 
48+```bash
49+# 部署(包名自动从 WHL 解析)
50+agent-runtime-manager agent deploy "E:/code/agent-runtime/src/manager/examples/dist/my_agent-1.0.0-py3-none-any.whl"
51+ 
52+# 查看部署列表
53+agent-runtime-manager agent list
54+ 
55+# 查看部署详情
56+agent-runtime-manager agent get <deployment_id>
57+ 
58+# 删除部署
59+agent-runtime-manager agent delete <deployment_id>
60+```
61+ 
62+## CLI 使用
63+ 
64+### Agent 命令
65+ 
66+```bash
67+# 部署 Agent(自动解析包名)
68+agent-runtime-manager agent deploy <whl_path> [--port PORT]
69+ 
70+# 查询列表
71+agent-runtime-manager agent list [--status STATUS]
72+ 
73+# 获取详情
74+agent-runtime-manager agent get <deployment_id>
75+ 
76+# 删除部署
77+agent-runtime-manager agent delete <deployment_id>
78+```
79+ 
80+### Plugin 命令
81+ 
82+```bash
83+# 部署 Plugin
84+agent-runtime-manager plugin deploy <whl_path> [--port PORT]
85+ 
86+# 查询列表
87+agent-runtime-manager plugin list [--status STATUS]
88+ 
89+# 获取详情
90+agent-runtime-manager plugin get <deployment_id>
91+ 
92+# 删除部署
93+agent-runtime-manager plugin delete <deployment_id>
94+```
95+ 
96+## SDK 使用
97+ 
98+```python
99+from openjiuwen_runtime.management.sdk import DeploymentManager
100+ 
101+manager = DeploymentManager()
102+ 
103+# 部署 Agent(包名自动解析)
104+result = await manager.deploy_agent(
105+ whl_path="./my_agent-1.0.0-py3-none-any.whl",
106+ port=8090
107+)
108+ 
109+# 查询列表
110+deployments = await manager.list_deployments(
111+ deployment_type=DeploymentType.AGENT,
112+ status=DeploymentStatus.RUNNING
113+)
114+ 
115+# 获取详情
116+deployment = await manager.get_deployment(deployment_id)
117+ 
118+# 删除部署
119+await manager.delete_deployment(deployment_id)
120+```
121+ 
122+## WHL 包规范
123+ 
124+### 命名规范
125+ 
126+```
127+{package_name}-{version}-{python_tag}-{abi_tag}-{platform_tag}.whl
128+ 
129+示例:
130+my_agent-1.0.0-py3-none-any.whl
131+weather_plugin-2.1.0-py3-none-any.whl
132+```
133+ 
134+### 目录结构
135+ 
136+```
137+my_agent/
138+├── my_agent/ # ✅ 包子目录(必须)
139+│ ├── __init__.py
140+│ └── __main__.py # ✅ 主入口文件(必须)
141+└── setup.py # ✅ 打包配置(必须)
142+```
143+ 
144+### __main__.py 要求
145+ 
146+```python
147+import argparse
148+ 
149+def main():
150+ # 1. 必须解析 --host 和 --port 参数
151+ parser = argparse.ArgumentParser()
152+ parser.add_argument("--host", default="127.0.0.1")
153+ parser.add_argument("--port", type=int, default=8090)
154+ args = parser.parse_args()
155+ 
156+ # 2. 必须实现长期运行的服务
157+ # 例如:FastAPI、Flask 等 HTTP 服务器
158+ run_server(host=args.host, port=args.port)
159+ 
160+if __name__ == "__main__":
161+ main()
162+```
163+ 
164+### setup.py 示例
165+ 
166+```python
167+from setuptools import setup, find_packages
168+ 
169+setup(
170+ name="my_agent",
171+ version="1.0.0",
172+ packages=find_packages(),
173+ install_requires=[
174+ "fastapi>=0.100.0",
175+ "uvicorn>=0.23.0",
176+ ],
177+ python_requires=">=3.8",
178+)
179+```
180+ 
181+## 虚拟环境管理
182+ 
183+### 目录结构
184+ 
185+```
186+venvs/
187+├── agent_20250129_abc123/ # Agent 部署虚拟环境
188+│ ├── Scripts/python.exe # Windows
189+│ ├── Lib/site-packages/ # 已安装的包
190+│ └── pyvenv.cfg
191+└── plugin_20250129_def456/ # Plugin 部署虚拟环境
192+ ├── bin/python # Linux/Mac
193+ └── ...
194+```
195+ 
196+### 自动清理
197+ 
198+- 部署成功后,虚拟环境会保留直到部署被删除
199+- 部署失败时,虚拟环境会自动清理
200+- 删除部署时,虚拟环境会自动清理
201+ 
202+## 配置选项
203+ 
204+### 环境变量 (.env)
205+ 
206+```bash
207+# MySQL 数据库
208+DB_HOST=124.71.229.79
209+DB_PORT=33306
210+DB_USER=root
211+DB_PASSWORD=root
212+DB_NAME=jiuwen_runtime
213+ 
214+# 虚拟环境
215+V_ENVS_ROOT=./venvs # 虚拟环境根目录(默认: ./venvs)
216+```
217+ 
218+## 项目架构
219+ 
220+```
221+Agent Runtime Manager
222+├── sdk/ # Manager SDK(核心共享组件)
223+│ ├── manager.py # DeploymentManager - 部署管理核心
224+│ ├── deployer/ # LocalSubprocessDeployer - WHL 包部署器
225+│ ├── database/ # MySQLDatabase - 数据持久化
226+│ ├── models/ # Deployment/DeploymentDB - 数据模型
227+│ └── utils/ # 工具类
228+│ ├── venv_manager.py # 虚拟环境管理
229+│ ├── whl_parser.py # WHL 包名解析
230+│ ├── port_manager.py # 端口分配
231+│ └── id_generator.py # ID 生成
232+├── cli/ # CLI 命令行工具
233+│ └── src/main.py # Click 命令(agent/plugin deploy/list/get/delete)
234+└── server/ # REST API Server(预留)
235+```
236+ 
237+## 开发指南
238+ 
239+### 构建示例包
240+ 
241+```bash
242+cd examples/my_agent
243+py -m build --outdir ../../dist
244+```
245+ 
246+### 运行测试
247+ 
248+```bash
249+cd cli
250+agent-runtime-manager agent deploy "../examples/dist/my_agent-1.0.0-py3-none-any.whl"
251+```
252+ 
253+## 常见问题
254+ 
255+### 1. Editable 安装问题
256+ 
257+**症状**: 修改代码后仍然使用旧版本
258+ 
259+**解决**:
260+```bash
261+cd cli
262+rm -rf .venv/Lib/site-packages/openjiuwen_runtime
263+uv pip install -e ../sdk
264+```
265+ 
266+### 2. WHL 包结构错误
267+ 
268+**症状**: `No module named xxx`
269+ 
270+**解决**: 确保 WHL 包内有正确的包子目录结构
271+ 
272+```bash
273+# 验证 WHL 包内容
274+python -m zipfile -l my_agent-1.0.0-py3-none-any.whl
275+```
276+ 
277+### 3. 进程立即退出
278+ 
279+**症状**: 部署后进程很快退出
280+ 
281+**解决**: `__main__.py` 必须实现长期运行的服务(如 HTTP 服务器)
282+ 
283+## 依赖项
284+ 
285+### SDK 依赖
286+- `sqlalchemy>=2.0.0` - ORM 框架
287+- `pymysql>=1.0.0` - MySQL 驱动
288+- `pydantic>=2.0.0` - 数据验证
289+- `cryptography>=42.0.0` - 加密工具
290+ 
291+### CLI 依赖
292+- `click>=8.0.0` - CLI 框架
293+- `python-dotenv>=1.0.0` - 环境变量
294+- `fastapi>=0.100.0` - Web 框架(Server 预留)
@@ -0,0 +1,37 @@
1+[build-system]
2+requires = ["setuptools>=61.0", "wheel"]
3+build-backend = "setuptools.build_meta"
4+ 
5+[project]
6+name = "agent-runtime-manager-cli"
7+version = "0.1.0"
8+description = "Agent Runtime Manager CLI"
9+requires-python = ">=3.11.4"
10+dependencies = [
11+ "click>=8.0.0",
12+ "python-dotenv>=1.0.0",
13+ "fastapi>=0.100.0",
14+ "uvicorn>=0.23.0",
15+ # SDK dependency (local path)
16+ "openjiuwen-runtime-management-sdk @ file:///${PROJECT_ROOT}/../sdk",
17+]
18+ 
19+[tool.uv]
20+default-groups = ['dev']
21+ 
22+[dependency-groups]
23+dev = [
24+ "ruff==0.9.10",
25+]
26+ 
27+[[tool.uv.index]]
28+url = "https://mirrors.aliyun.com/pypi/simple/"
29+ 
30+[tool.setuptools]
31+packages = ["openjiuwen_runtime.cli"]
32+ 
33+[tool.setuptools.package-dir]
34+"openjiuwen_runtime.cli" = "src"
35+ 
36+[project.scripts]
37+agent-runtime-manager = "openjiuwen_runtime.cli.main:cli"
@@ -0,0 +1,100 @@
1+@echo off
2+REM ========================================
3+REM Agent Runtime Manager - Rebuild Script
4+REM ========================================
5+REM 彻底清除缓存并重新编译 CLI 和 Server,解决 editable install 缓存问题
6+ 
7+set SCRIPT_DIR=%~dp0
8+set PROJECT_ROOT=%SCRIPT_DIR%..
9+ 
10+echo ========================================
11+echo 开始清理缓存...
12+echo ========================================
13+ 
14+REM 1. 清除 CLI venv 中的缓存
15+echo [1/7] 清除 CLI venv 缓存...
16+cd "%PROJECT_ROOT%\cli"
17+if exist ".venv\Lib\site-packages\openjiuwen_runtime" (
18+ rd /s /q ".venv\Lib\site-packages\openjiuwen_runtime"
19+ echo - 已删除 CLI venv 中的 openjiuwen_runtime
20+)
21+for /d /r .venv %%d in (__pycache__) do @if exist "%%d" (
22+ rd /s /q "%%d" 2>nul
23+)
24+for /r .venv %%f in (*.pyc) do @if exist "%%f" (
25+ del /f /q "%%f" 2>nul
26+)
27+ 
28+REM 2. 清除 Server venv 中的缓存
29+echo [2/7] 清除 Server venv 缓存...
30+cd "%PROJECT_ROOT%\server"
31+if exist ".venv\Lib\site-packages\openjiuwen_runtime" (
32+ rd /s /q ".venv\Lib\site-packages\openjiuwen_runtime"
33+ echo - 已删除 Server venv 中的 openjiuwen_runtime
34+)
35+for /d /r .venv %%d in (__pycache__) do @if exist "%%d" (
36+ rd /s /q "%%d" 2>nul
37+)
38+for /r .venv %%f in (*.pyc) do @if exist "%%f" (
39+ del /f /q "%%f" 2>nul
40+)
41+ 
42+REM 3. 清除 SDK 源码中的 pyc 缓存
43+echo [3/7] 清除 SDK 源码缓存...
44+cd "%PROJECT_ROOT%\sdk"
45+for /d /r %%d in (__pycache__) do @if exist "%%d" (
46+ rd /s /q "%%d" 2>nul
47+)
48+for /r %%f in (*.pyc) do @if exist "%%f" (
49+ del /f /q "%%f" 2>nul
50+)
51+ 
52+REM 4. 卸载旧版本 SDK (CLI)
53+echo [4/7] 卸载 CLI 旧版本包...
54+cd "%PROJECT_ROOT%\cli"
55+call uv pip uninstall openjiuwen-runtime-management-sdk 2>nul
56+call uv pip uninstall agent-runtime-manager-cli 2>nul
57+ 
58+REM 5. 重新安装 SDK (CLI)
59+echo [5/7] 安装 SDK 到 CLI (editable mode)...
60+call uv pip install -e "%PROJECT_ROOT%\sdk"
61+ 
62+REM 6. 重新安装 CLI
63+echo [6/7] 安装 CLI...
64+call uv pip install -e "./"
65+ 
66+REM 7. 重新安装 SDK (Server) - 使用 --python 指定Server的venv
67+echo [7/7] 安装 SDK 到 Server (editable mode)...
68+cd "%PROJECT_ROOT%\server"
69+if exist ".venv\Scripts\python.exe" (
70+ call uv pip install --python .venv\Scripts\python.exe -e "%PROJECT_ROOT%\sdk"
71+) else (
72+ echo ! Server venv 不存在,跳过
73+)
74+ 
75+echo ========================================
76+echo 编译完成!
77+echo ========================================
78+echo.
79+echo 验证 CLI 安装:
80+cd "%PROJECT_ROOT%\cli"
81+.venv\Scripts\python.exe -c "from openjiuwen_runtime.management.sdk import DeploymentManager; import inspect; print('SDK OK:', inspect.signature(DeploymentManager.deploy_agent))" 2>nul
82+if errorlevel 1 (
83+ echo ! CLI 验证失败
84+)
85+echo.
86+echo 验证 Server 安装:
87+cd "%PROJECT_ROOT%\server"
88+if exist ".venv\Scripts\python.exe" (
89+ .venv\Scripts\python.exe -c "from openjiuwen_runtime.management.sdk import DeploymentManager; import inspect; src=inspect.getsource(DeploymentManager.deploy_agent); print('SDK OK') if '\"name\"' in src and 'return' in src else print('SDK FAIL: missing name in return')" 2>nul
90+ if errorlevel 1 (
91+ echo ! Server 验证失败
92+ )
93+) else (
94+ echo ! Server venv 不存在,跳过验证
95+)
96+echo.
97+echo ========================================
98+echo 注意: 如果 Server 正在运行,请重启 Server 以加载新代码
99+echo ========================================
100+pause
@@ -0,0 +1,98 @@
1+#!/bin/bash
2+# ========================================
3+# Agent Runtime Manager - Rebuild Script
4+# ========================================
5+# 彻底清除缓存并重新编译 CLI 和 Server,解决 editable install 缓存问题
6+ 
7+set -e
8+ 
9+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10+PROJECT_ROOT="$SCRIPT_DIR/.."
11+ 
12+echo "========================================"
13+echo "开始清理缓存..."
14+echo "========================================"
15+ 
16+# 1. 清除 CLI venv 中的缓存
17+echo "[1/7] 清除 CLI venv 缓存..."
18+cd "$PROJECT_ROOT/cli"
19+if [ -d ".venv/lib/python*/site-packages/openjiuwen_runtime" ]; then
20+ rm -rf .venv/lib/python*/site-packages/openjiuwen_runtime
21+ echo " - 已删除 CLI venv 中的 openjiuwen_runtime"
22+fi
23+find .venv -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
24+find .venv -type f -name "*.pyc" -delete 2>/dev/null || true
25+ 
26+# 2. 清除 Server venv 中的缓存
27+echo "[2/7] 清除 Server venv 缓存..."
28+cd "$PROJECT_ROOT/server"
29+if [ -d ".venv/lib/python*/site-packages/openjiuwen_runtime" ]; then
30+ rm -rf .venv/lib/python*/site-packages/openjiuwen_runtime
31+ echo " - 已删除 Server venv 中的 openjiuwen_runtime"
32+fi
33+find .venv -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
34+find .venv -type f -name "*.pyc" -delete 2>/dev/null || true
35+ 
36+# 3. 清除 SDK 源码中的 pyc 缓存
37+echo "[3/7] 清除 SDK 源码缓存..."
38+cd "$PROJECT_ROOT/sdk"
39+find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
40+find . -type f -name "*.pyc" -delete 2>/dev/null || true
41+ 
42+# 4. 卸载旧版本 SDK (CLI)
43+echo "[4/7] 卸载 CLI 旧版本包..."
44+cd "$PROJECT_ROOT/cli"
45+uv pip uninstall openjiuwen-runtime-management-sdk 2>/dev/null || true
46+uv pip uninstall agent-runtime-manager-cli 2>/dev/null || true
47+ 
48+# 5. 重新安装 SDK (CLI)
49+echo "[5/7] 安装 SDK 到 CLI (editable mode)..."
50+uv pip install -e "$PROJECT_ROOT/sdk"
51+ 
52+# 6. 重新安装 CLI
53+echo "[6/7] 安装 CLI..."
54+uv pip install -e ./
55+ 
56+# 7. 重新安装 SDK (Server) - 使用 --python 指定Server的venv
57+echo "[7/7] 安装 SDK 到 Server (editable mode)..."
58+cd "$PROJECT_ROOT/server"
59+if [ -f ".venv/bin/python" ]; then
60+ uv pip install --python .venv/bin/python -e "$PROJECT_ROOT/sdk"
61+else
62+ echo " ! Server venv 不存在,跳过"
63+fi
64+ 
65+echo "========================================"
66+echo "编译完成!"
67+echo "========================================"
68+echo ""
69+echo "验证 CLI 安装:"
70+cd "$PROJECT_ROOT/cli"
71+if .venv/bin/python -c "from openjiuwen_runtime.management.sdk import DeploymentManager; import inspect; print('SDK OK:', inspect.signature(DeploymentManager.deploy_agent))" 2>/dev/null; then
72+ :
73+else
74+ echo " ! CLI 验证失败"
75+fi
76+ 
77+echo ""
78+echo "验证 Server 安装:"
79+cd "$PROJECT_ROOT/server"
80+if [ -f ".venv/bin/python" ]; then
81+ if .venv/bin/python -c "
82+from openjiuwen_runtime.management.sdk import DeploymentManager
83+import inspect
84+src = inspect.getsource(DeploymentManager.deploy_agent)
85+print('SDK OK') if '\"name\"' in src and 'return' in src else print('SDK FAIL: missing name in return')
86+" 2>/dev/null; then
87+ :
88+ else
89+ echo " ! Server 验证失败"
90+ fi
91+else
92+ echo " ! Server venv 不存在,跳过验证"
93+fi
94+ 
95+echo ""
96+echo "========================================"
97+echo "注意: 如果 Server 正在运行,请重启 Server 以加载新代码"
98+echo "========================================"
@@ -0,0 +1 @@
1+"""Agent Runtime Manager CLI"""
@@ -0,0 +1,251 @@
1+"""Agent Runtime Manager CLI v2.0
2+ 
3+使用WHL包部署Agent和Plugin,支持虚拟环境隔离。
4+"""
5+ 
6+import asyncio
7+import json
8+import logging
9+import sys
10+from pathlib import Path
11+ 
12+import click
13+from dotenv import load_dotenv
14+ 
15+from openjiuwen_runtime.management.sdk import (
16+ DeploymentManager,
17+ DeploymentType,
18+ DeploymentStatus,
19+)
20+ 
21+# 配置日志输出
22+logging.basicConfig(
23+ level=logging.INFO,
24+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
25+ datefmt='%Y-%m-%d %H:%M:%S'
26+)
27+ 
28+# 加载.env配置文件(固定位置:manager根目录)
29+_manager_root = Path(__file__).parent.parent.parent
30+_env_file = _manager_root / ".env"
31+load_dotenv(_env_file)
32+ 
33+ 
34+@click.group()
35+@click.pass_context
36+def cli(ctx):
37+ """Agent Runtime Manager CLI v2.0"""
38+ ctx.ensure_object(dict)
39+ 
40+ # 从环境变量读取配置
41+ ctx.obj["manager"] = DeploymentManager()
42+ 
43+ 
44+# ==================== Agent 命令 ====================
45+ 
46+@cli.group()
47+def agent():
48+ """Agent 管理"""
49+ pass
50+ 
51+ 
52+@agent.command()
53+@click.argument("python_file_path", type=click.Path(exists=True))
54+@click.option("--name", required=True, help="部署名称(=包名,用于打包和运行)")
55+@click.option("--port", type=int, help="服务端口(自动分配可用端口)")
56+@click.pass_context
57+def deploy(ctx, python_file_path, name, port):
58+ """部署 Agent(使用 Python 文件)
59+ 
60+ \b
61+ Manager SDK 内部自动将 Python 文件打包为 WHL 包。
62+ name 参数既是部署名称,也是打包的包名。
63+ 
64+ 示例:
65+ agent-runtime agent deploy ./my_agent.py --name my_agent
66+ agent-runtime agent deploy ./my_agent.py --name my_agent --port 8090
67+ """
68+ manager = ctx.obj["manager"]
69+ 
70+ async def _deploy():
71+ result = await manager.deploy_agent(
72+ python_file_path=python_file_path,
73+ name=name,
74+ port=port,
75+ )
76+ click.echo(json.dumps(result, indent=2, ensure_ascii=False))
77+ 
78+ asyncio.run(_deploy())
79+ 
80+ 
81+@agent.command()
82+@click.option("--status", type=click.Choice(["pending", "running", "stopped", "failed"]), help="过滤状态")
83+@click.pass_context
84+def list(ctx, status):
85+ """查询 Agent 列表"""
86+ manager = ctx.obj["manager"]
87+ 
88+ async def _list():
89+ deployments = await manager.list_deployments(
90+ deployment_type=DeploymentType.AGENT,
91+ status=DeploymentStatus(status) if status else None,
92+ )
93+ 
94+ if not deployments:
95+ click.echo("No deployments found")
96+ return
97+ 
98+ # 显示简略信息
99+ click.echo(f"{'ID':<30} {'Name':<20} {'Status':<10} {'Port':<6} {'Package':<20} {'URL'}")
100+ click.echo("-" * 120)
101+ for dep in deployments:
102+ name = dep.get('name') or '-'
103+ dep_status = dep['status'].value if hasattr(dep['status'], 'value') else str(dep['status'])
104+ package_name = dep.get('package_name') or '-'
105+ url = dep.get('url') or '-'
106+ click.echo(f"{dep['deployment_id']:<30} {name:<20} {dep_status:<10} {dep['port']:<6} {package_name:<20} {url:<30}")
107+ 
108+ asyncio.run(_list())
109+ 
110+ 
111+@agent.command()
112+@click.argument("deployment_id")
113+@click.pass_context
114+def get(ctx, deployment_id):
115+ """获取 Agent 详情"""
116+ manager = ctx.obj["manager"]
117+ 
118+ async def _get():
119+ deployment = await manager.get_deployment(deployment_id)
120+ if deployment:
121+ click.echo(json.dumps(deployment, indent=2, ensure_ascii=False))
122+ else:
123+ click.echo(f"Deployment {deployment_id} not found", err=True)
124+ sys.exit(1)
125+ 
126+ asyncio.run(_get())
127+ 
128+ 
129+@agent.command()
130+@click.argument("deployment_id")
131+@click.pass_context
132+def delete(ctx, deployment_id):
133+ """删除 Agent(会自动清理虚拟环境)"""
134+ manager = ctx.obj["manager"]
135+ 
136+ async def _delete():
137+ success = await manager.delete_deployment(deployment_id)
138+ if success:
139+ click.echo(f"Deployment {deployment_id} deleted")
140+ else:
141+ click.echo(f"Deployment {deployment_id} not found", err=True)
142+ sys.exit(1)
143+ 
144+ asyncio.run(_delete())
145+ 
146+ 
147+# ==================== Plugin 命令 ====================
148+ 
149+@cli.group()
150+def plugin():
151+ """Plugin 管理"""
152+ pass
153+ 
154+ 
155+@plugin.command()
156+@click.argument("python_file_path", type=click.Path(exists=True))
157+@click.option("--name", required=True, help="部署名称(=包名,用于打包和运行)")
158+@click.option("--port", type=int, help="服务端口(自动分配可用端口)")
159+@click.pass_context
160+def deploy(ctx, python_file_path, name, port):
161+ """部署 Plugin(使用 Python 文件)
162+ 
163+ \b
164+ Manager SDK 内部自动将 Python 文件打包为 WHL 包。
165+ name 参数既是部署名称,也是打包的包名。
166+ 
167+ 示例:
168+ agent-runtime plugin deploy ./my_plugin.py --name my_plugin
169+ agent-runtime plugin deploy ./my_plugin.py --name my_plugin --port 8091
170+ """
171+ manager = ctx.obj["manager"]
172+ 
173+ async def _deploy():
174+ result = await manager.deploy_plugin(
175+ python_file_path=python_file_path,
176+ name=name,
177+ port=port,
178+ )
179+ click.echo(json.dumps(result, indent=2, ensure_ascii=False))
180+ 
181+ asyncio.run(_deploy())
182+ 
183+ 
184+@plugin.command()
185+@click.option("--status", type=click.Choice(["pending", "running", "stopped", "failed"]), help="过滤状态")
186+@click.pass_context
187+def list(ctx, status):
188+ """查询 Plugin 列表"""
189+ manager = ctx.obj["manager"]
190+ 
191+ async def _list():
192+ deployments = await manager.list_deployments(
193+ deployment_type=DeploymentType.PLUGIN,
194+ status=DeploymentStatus(status) if status else None,
195+ )
196+ 
197+ if not deployments:
198+ click.echo("No deployments found")
199+ return
200+ 
201+ # 显示简略信息
202+ click.echo(f"{'ID':<30} {'Name':<20} {'Status':<10} {'Port':<6} {'Package':<20} {'URL'}")
203+ click.echo("-" * 120)
204+ for dep in deployments:
205+ name = dep.get('name') or '-'
206+ dep_status = dep['status'].value if hasattr(dep['status'], 'value') else str(dep['status'])
207+ package_name = dep.get('package_name') or '-'
208+ url = dep.get('url') or '-'
209+ click.echo(f"{dep['deployment_id']:<30} {name:<20} {dep_status:<10} {dep['port']:<6} {package_name:<20} {url:<30}")
210+ 
211+ asyncio.run(_list())
212+ 
213+ 
214+@plugin.command()
215+@click.argument("deployment_id")
216+@click.pass_context
217+def get(ctx, deployment_id):
218+ """获取 Plugin 详情"""
219+ manager = ctx.obj["manager"]
220+ 
221+ async def _get():
222+ deployment = await manager.get_deployment(deployment_id)
223+ if deployment:
224+ click.echo(json.dumps(deployment, indent=2, ensure_ascii=False))
225+ else:
226+ click.echo(f"Deployment {deployment_id} not found", err=True)
227+ sys.exit(1)
228+ 
229+ asyncio.run(_get())
230+ 
231+ 
232+@plugin.command()
233+@click.argument("deployment_id")
234+@click.pass_context
235+def delete(ctx, deployment_id):
236+ """删除 Plugin(会自动清理虚拟环境)"""
237+ manager = ctx.obj["manager"]
238+ 
239+ async def _delete():
240+ success = await manager.delete_deployment(deployment_id)
241+ if success:
242+ click.echo(f"Deployment {deployment_id} deleted")
243+ else:
244+ click.echo(f"Deployment {deployment_id} not found", err=True)
245+ sys.exit(1)
246+ 
247+ asyncio.run(_delete())
248+ 
249+ 
250+if __name__ == "__main__":
251+ cli(obj={})
@@ -0,0 +1,2 @@
1+fastapi>=0.100.0
2+uvicorn>=0.23.0
@@ -0,0 +1,49 @@
1+"""Simple FastAPI Agent Example
2+ 
3+A standalone Python file that can be deployed directly.
4+"""
5+ 
6+import argparse
7+import uvicorn
8+from fastapi import FastAPI
9+from fastapi.responses import JSONResponse
10+ 
11+# Create FastAPI app
12+app = FastAPI(title="Simple Agent", version="1.0.0")
13+ 
14+ 
15+@app.get("/")
16+async def root():
17+ """Root endpoint"""
18+ return JSONResponse({
19+ "message": "Hello World from simple_agent!",
20+ "status": "running"
21+ })
22+ 
23+ 
24+@app.get("/health")
25+async def health():
26+ """Health check"""
27+ return JSONResponse({
28+ "status": "healthy"
29+ })
30+ 
31+ 
32+def main():
33+ """Main entry point"""
34+ parser = argparse.ArgumentParser(description="Simple FastAPI Agent")
35+ parser.add_argument("--host", default="127.0.0.1", help="Host to bind to")
36+ parser.add_argument("--port", type=int, default=8090, help="Port to bind to")
37+ args = parser.parse_args()
38+ 
39+ # Start uvicorn server
40+ uvicorn.run(
41+ app,
42+ host=args.host,
43+ port=args.port,
44+ log_level="info"
45+ )
46+ 
47+ 
48+if __name__ == "__main__":
49+ main()
@@ -0,0 +1,62 @@
1+"""Simple FastAPI Plugin Example
2+ 
3+A standalone Python file that can be deployed directly as a plugin.
4+"""
5+ 
6+import argparse
7+import uvicorn
8+from fastapi import FastAPI
9+from fastapi.responses import JSONResponse
10+ 
11+# Create FastAPI app
12+app = FastAPI(title="Simple Plugin", version="1.0.0")
13+ 
14+ 
15+@app.get("/")
16+async def root():
17+ """Root endpoint"""
18+ return JSONResponse({
19+ "message": "Hello World from simple_plugin!",
20+ "type": "plugin",
21+ "status": "running"
22+ })
23+ 
24+ 
25+@app.get("/tools")
26+async def list_tools():
27+ """List available tools"""
28+ return JSONResponse({
29+ "tools": [
30+ {"name": "current_weather", "description": "Query current weather"},
31+ {"name": "weather_forecast", "description": "Query weather forecast"}
32+ ]
33+ })
34+ 
35+ 
36+@app.get("/tool/{tool_name}")
37+async def call_tool(tool_name: str):
38+ """Call a tool"""
39+ return JSONResponse({
40+ "tool": tool_name,
41+ "result": f"Executed {tool_name} successfully"
42+ })
43+ 
44+ 
45+def main():
46+ """Main entry point"""
47+ parser = argparse.ArgumentParser(description="Simple FastAPI Plugin")
48+ parser.add_argument("--host", default="127.0.0.1", help="Host to bind to")
49+ parser.add_argument("--port", type=int, default=8091, help="Port to bind to")
50+ args = parser.parse_args()
51+ 
52+ # Start uvicorn server
53+ uvicorn.run(
54+ app,
55+ host=args.host,
56+ port=args.port,
57+ log_level="info"
58+ )
59+ 
60+ 
61+if __name__ == "__main__":
62+ main()
@@ -0,0 +1,35 @@
1+"""Mock Agent for testing"""
2+ 
3+import asyncio
4+from fastapi import FastAPI
5+from uvicorn import Config, Server
6+ 
7+ 
8+app = FastAPI(title="TestAgent")
9+ 
10+ 
11+@app.get("/")
12+async def root():
13+ return {"message": "Hello World"}
14+ 
15+ 
16+@app.get("/health")
17+async def health():
18+ return {"status": "healthy"}
19+ 
20+ 
21+if __name__ == "__main__":
22+ import argparse
23+ import sys
24+ 
25+ parser = argparse.ArgumentParser()
26+ parser.add_argument("--host", default="127.0.0.1")
27+ parser.add_argument("--port", type=int, default=8090)
28+ args = parser.parse_args()
29+ 
30+ # 使用 uvicorn 运行
31+ config = Config(app=app, host=args.host, port=args.port, log_level="info")
32+ server = Server(config)
33+ 
34+ print(f"Starting TestAgent on http://{args.host}:{args.port}")
35+ asyncio.run(server.serve())
@@ -0,0 +1,45 @@
1+[build-system]
2+requires = ["setuptools>=61.0", "wheel"]
3+build-backend = "setuptools.build_meta"
4+ 
5+[project]
6+name = "openjiuwen-runtime-management-sdk"
7+version = "0.1.0"
8+description = "OpenJiuwen Runtime"
9+requires-python = ">=3.11.4"
10+dependencies = [
11+ "build>=1.0.0",
12+ "sqlalchemy>=2.0.0",
13+ "pymysql>=1.0.0",
14+ "pydantic>=2.0.0",
15+ "cryptography>=42.0.0",
16+]
17+ 
18+[tool.uv]
19+default-groups = ['dev']
20+ 
21+[dependency-groups]
22+dev = [
23+ "coverage==7.8.0",
24+ "pytest==8.3.5",
25+ "pytest-asyncio==1.2.0",
26+ "pytest-mock==3.14.0",
27+ "ruff==0.9.10",
28+]
29+ 
30+[[tool.uv.index]]
31+url = "https://mirrors.aliyun.com/pypi/simple/"
32+ 
33+[tool.setuptools]
34+packages = ["openjiuwen_runtime.management.sdk",
35+ "openjiuwen_runtime.management.sdk.models",
36+ "openjiuwen_runtime.management.sdk.database",
37+ "openjiuwen_runtime.management.sdk.deployer",
38+ "openjiuwen_runtime.management.sdk.utils"]
39+ 
40+[tool.setuptools.package-dir]
41+"openjiuwen_runtime.management.sdk" = "src"
42+"openjiuwen_runtime.management.sdk.models" = "src/models"
43+"openjiuwen_runtime.management.sdk.database" = "src/database"
44+"openjiuwen_runtime.management.sdk.deployer" = "src/deployer"
45+"openjiuwen_runtime.management.sdk.utils" = "src/utils"
@@ -0,0 +1,54 @@
1+"""SDK使用示例
2+ 
3+使用前请先初始化数据库:
4+ from openjiuwen_runtime.management.sdk import init_database
5+ init_database()
6+"""
7+ 
8+import asyncio
9+from pathlib import Path
10+from dotenv import load_dotenv
11+ 
12+from openjiuwen_runtime.management.sdk import DeploymentManager
13+ 
14+# 加载.env配置文件(manager根目录)
15+_manager_root = Path(__file__).parent.parent
16+_env_file = _manager_root / ".env"
17+load_dotenv(_env_file)
18+ 
19+ 
20+async def main():
21+ """SDK使用示例"""
22+ 
23+ # 创建部署管理器
24+ manager = DeploymentManager()
25+ 
26+ # 部署Agent
27+ print("Deploying agent...")
28+ result = await manager.deploy_agent(
29+ local_file_path=str(Path(__file__).parent / "mock_agent_app.py"),
30+ name="HelloAgent",
31+ port=9999,
32+ )
33+ print(f" Deployment ID: {result['deployment_id']}")
34+ print(f" URL: {result['url']}")
35+ print(f" Status: {result['status']}")
36+ 
37+ # 查询部署列表
38+ print("\nListing agents...")
39+ deployments = await manager.list_deployments()
40+ for dep in deployments:
41+ print(f" - {dep['deployment_id']}: {dep['status']}")
42+ 
43+ # 获取部署详情
44+ deployment = await manager.get_deployment(result['deployment_id'])
45+ print(f"\nDeployment details: {deployment['status']}")
46+ 
47+ # 删除部署
48+ print("\nDeleting deployment...")
49+ await manager.delete_deployment(result['deployment_id'])
50+ print(" Deleted!")
51+ 
52+ 
53+if __name__ == "__main__":
54+ asyncio.run(main())
Asrc/manager/sdk/src/__init__.py+18-0文件内容审核中,请稍后刷新重试
Asrc/manager/sdk/src/database/__init__.py+5-0文件内容审核中,请稍后刷新重试
Asrc/manager/sdk/src/database/mysql.py+204-0文件内容审核中,请稍后刷新重试
Asrc/manager/sdk/src/deployer/__init__.py+6-0文件内容审核中,请稍后刷新重试
Asrc/manager/sdk/src/deployer/base.py+54-0文件内容审核中,请稍后刷新重试
Asrc/manager/sdk/src/deployer/local_subprocess.py+218-0文件内容审核中,请稍后刷新重试
Asrc/manager/sdk/src/init_db.py+9-0文件内容审核中,请稍后刷新重试
Asrc/manager/sdk/src/manager.py+512-0文件内容审核中,请稍后刷新重试
Asrc/manager/sdk/src/models/__init__.py+6-0文件内容审核中,请稍后刷新重试
Asrc/manager/sdk/src/models/deployment.py+115-0文件内容审核中,请稍后刷新重试
@@ -0,0 +1,17 @@
1+"""枚举定义"""
2+ 
3+from enum import Enum
4+ 
5+ 
6+class DeploymentType(str, Enum):
7+ """部署类型"""
8+ AGENT = "agent"
9+ PLUGIN = "plugin"
10+ 
11+ 
12+class DeploymentStatus(str, Enum):
13+ """部署状态"""
14+ PENDING = "pending"
15+ RUNNING = "running"
16+ STOPPED = "stopped"
17+ FAILED = "failed"
Asrc/manager/sdk/src/utils/__init__.py+6-0文件内容审核中,请稍后刷新重试
Asrc/manager/sdk/src/utils/id_generator.py+12-0文件内容审核中,请稍后刷新重试
Asrc/manager/sdk/src/utils/port_manager.py+22-0文件内容审核中,请稍后刷新重试
Asrc/manager/sdk/src/utils/venv_manager.py+168-0文件内容审核中,请稍后刷新重试
Asrc/manager/sdk/src/utils/whl_parser.py+77-0文件内容审核中,请稍后刷新重试
@@ -0,0 +1,34 @@
1+[build-system]
2+requires = ["setuptools>=61.0", "wheel"]
3+build-backend = "setuptools.build_meta"
4+ 
5+[project]
6+name = "agent-runtime-manager-server"
7+version = "1.0.0"
8+description = "Agent Runtime Manager Server"
9+requires-python = ">=3.11.4"
10+dependencies = [
11+ "fastapi>=0.100.0",
12+ "uvicorn>=0.23.0",
13+ "python-dotenv>=1.0.0",
14+ "python-multipart>=0.0.6",
15+ # SDK dependency (local path)
16+ "openjiuwen-runtime-management-sdk @ file:///${PROJECT_ROOT}/../sdk",
17+]
18+ 
19+[tool.uv]
20+default-groups = ['dev']
21+ 
22+[dependency-groups]
23+dev = [
24+ "ruff==0.9.10",
25+]
26+ 
27+[[tool.uv.index]]
28+url = "https://mirrors.aliyun.com/pypi/simple/"
29+ 
30+[tool.setuptools]
31+packages = ["agent_runtime_manager.server"]
32+ 
33+[tool.setuptools.package-dir]
34+"agent_runtime_manager.server" = "src"
Asrc/manager/server/src/__init__.py+3-0文件内容审核中,请稍后刷新重试
@@ -0,0 +1,27 @@
1+"""Server Configuration"""
2+ 
3+import os
4+from dotenv import load_dotenv
5+ 
6+# 加载 .env 配置
7+load_dotenv()
8+ 
9+ 
10+class Settings:
11+ """服务器配置"""
12+ 
13+ # MySQL
14+ MYSQL_HOST: str = os.getenv("DB_HOST", "localhost")
15+ MYSQL_PORT: int = int(os.getenv("DB_PORT", "3306"))
16+ MYSQL_DATABASE: str = os.getenv("DB_NAME", "agent_runtime")
17+ MYSQL_USER: str = os.getenv("DB_USER", "root")
18+ MYSQL_PASSWORD: str = os.getenv("DB_PASSWORD", "")
19+ 
20+ # OSS
21+ OSS_ENDPOINT: str = os.getenv("OSS_ENDPOINT", "")
22+ OSS_BUCKET: str = os.getenv("OSS_BUCKET", "")
23+ OSS_ACCESS_KEY: str = os.getenv("OSS_ACCESS_KEY", "")
24+ OSS_SECRET_KEY: str = os.getenv("OSS_SECRET_KEY", "")
25+ 
26+ 
27+settings = Settings()
Asrc/manager/server/src/converter/__init__.py+5-0文件内容审核中,请稍后刷新重试
Asrc/manager/server/src/converter/agent_converter.py+77-0文件内容审核中,请稍后刷新重试
Asrc/manager/server/src/main.py+238-0文件内容审核中,请稍后刷新重试
Asrc/manager/server/src/middleware/tenant.py+70-0文件内容审核中,请稍后刷新重试
Asrc/sdk/examples/calculator_plugin_app.py+136-0文件内容审核中,请稍后刷新重试
Asrc/sdk/examples/multi_agent_group.py+105-0文件内容审核中,请稍后刷新重试
Asrc/sdk/examples/simple_agent_app.py+96-0文件内容审核中,请稍后刷新重试
Asrc/sdk/src/__init__.py+58-0文件内容审核中,请稍后刷新重试
Asrc/sdk/src/core/__init__.py+12-0文件内容审核中,请稍后刷新重试
Asrc/sdk/src/models/__init__.py+7-0文件内容审核中,请稍后刷新重试
Asrc/sdk/src/models/request.py+59-0文件内容审核中,请稍后刷新重试