643 lines
17 KiB
Markdown
643 lines
17 KiB
Markdown
|
|
# Phase T.4:高级特性
|
|||
|
|
|
|||
|
|
日期:2026-04-04
|
|||
|
|
状态:待开始
|
|||
|
|
依赖:T.3(待完成)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. 本阶段目的
|
|||
|
|
|
|||
|
|
实现 Jarvis 工具系统的高级特性:
|
|||
|
|
|
|||
|
|
- 多运行时支持(Python/JS/原生)
|
|||
|
|
- Agent 间协作
|
|||
|
|
- 定时任务
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 多运行时支持
|
|||
|
|
|
|||
|
|
### 2.1 运行时架构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────────────────┐
|
|||
|
|
│ Runtime Manager │
|
|||
|
|
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
|||
|
|
│ │ Python │ │ JS │ │ Native │ │ WASM │ │
|
|||
|
|
│ │ Runtime │ │ Runtime │ │ Runtime │ │ Runtime │ │
|
|||
|
|
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
|
|||
|
|
│ │ │ │ │ │
|
|||
|
|
│ └─────────────┴──────┬──────┴─────────────┘ │
|
|||
|
|
│ │ │
|
|||
|
|
│ ┌────────┴────────┐ │
|
|||
|
|
│ │ Tool Executor │ │
|
|||
|
|
│ │ (统一接口) │ │
|
|||
|
|
│ └─────────────────┘ │
|
|||
|
|
└─────────────────────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.2 运行时基类
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# tools/runtime/base.py
|
|||
|
|
from abc import ABC, abstractmethod
|
|||
|
|
from typing import Any, Dict, Optional
|
|||
|
|
|
|||
|
|
|
|||
|
|
class BaseRuntime(ABC):
|
|||
|
|
"""运行时基类"""
|
|||
|
|
|
|||
|
|
@abstractmethod
|
|||
|
|
async def execute(
|
|||
|
|
self,
|
|||
|
|
entry: str,
|
|||
|
|
command: str,
|
|||
|
|
parameters: Dict[str, Any],
|
|||
|
|
timeout: int,
|
|||
|
|
) -> Dict[str, Any]:
|
|||
|
|
"""执行工具"""
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
@abstractmethod
|
|||
|
|
async def validate(self, entry: str) -> bool:
|
|||
|
|
"""验证工具是否可用"""
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
@abstractmethod
|
|||
|
|
def get_name(self) -> str:
|
|||
|
|
"""获取运行时名称"""
|
|||
|
|
pass
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.3 Python 运行时
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# tools/runtime/python_runtime.py
|
|||
|
|
import asyncio
|
|||
|
|
from pathlib import Path
|
|||
|
|
from tools.runtime.base import BaseRuntime
|
|||
|
|
|
|||
|
|
|
|||
|
|
class PythonRuntime(BaseRuntime):
|
|||
|
|
"""Python 运行时"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
self._executors: Dict[str, Callable] = {}
|
|||
|
|
|
|||
|
|
def get_name(self) -> str:
|
|||
|
|
return "python"
|
|||
|
|
|
|||
|
|
async def validate(self, entry: str) -> bool:
|
|||
|
|
path = Path(entry)
|
|||
|
|
return path.exists() and path.suffix == ".py"
|
|||
|
|
|
|||
|
|
async def execute(
|
|||
|
|
self,
|
|||
|
|
entry: str,
|
|||
|
|
command: str,
|
|||
|
|
parameters: Dict[str, Any],
|
|||
|
|
timeout: int,
|
|||
|
|
) -> Dict[str, Any]:
|
|||
|
|
# 动态加载并执行
|
|||
|
|
# 或者通过 subprocess 调用
|
|||
|
|
pass
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.4 JavaScript 运行时
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# tools/runtime/js_runtime.py
|
|||
|
|
import asyncio
|
|||
|
|
import subprocess
|
|||
|
|
import json
|
|||
|
|
from tools.runtime.base import BaseRuntime
|
|||
|
|
|
|||
|
|
|
|||
|
|
class JavaScriptRuntime(BaseRuntime):
|
|||
|
|
"""JavaScript 运行时"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
self.node_path = "node" # 可配置
|
|||
|
|
|
|||
|
|
def get_name(self) -> str:
|
|||
|
|
return "javascript"
|
|||
|
|
|
|||
|
|
async def validate(self, entry: str) -> bool:
|
|||
|
|
# 检查 node 是否可用
|
|||
|
|
try:
|
|||
|
|
result = await asyncio.create_subprocess_exec(
|
|||
|
|
self.node_path, "--version",
|
|||
|
|
stdout=asyncio.subprocess.PIPE,
|
|||
|
|
)
|
|||
|
|
return result.returncode == 0
|
|||
|
|
except:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
async def execute(
|
|||
|
|
self,
|
|||
|
|
entry: str,
|
|||
|
|
command: str,
|
|||
|
|
parameters: Dict[str, Any],
|
|||
|
|
timeout: int,
|
|||
|
|
) -> Dict[str, Any]:
|
|||
|
|
# 通过 stdio 调用 Node.js 脚本
|
|||
|
|
input_data = json.dumps({
|
|||
|
|
"command": command,
|
|||
|
|
"parameters": parameters,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
process = await asyncio.create_subprocess_exec(
|
|||
|
|
self.node_path, entry,
|
|||
|
|
stdin=asyncio.subprocess.PIPE,
|
|||
|
|
stdout=asyncio.subprocess.PIPE,
|
|||
|
|
stderr=asyncio.subprocess.PIPE,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
stdout, stderr = await asyncio.wait_for(
|
|||
|
|
process.communicate(input=input_data.encode()),
|
|||
|
|
timeout=timeout / 1000,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if process.returncode != 0:
|
|||
|
|
return {
|
|||
|
|
"status": "error",
|
|||
|
|
"error": stderr.decode(),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return json.loads(stdout.decode())
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.5 原生运行时
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# tools/runtime/native_runtime.py
|
|||
|
|
import asyncio
|
|||
|
|
import subprocess
|
|||
|
|
from tools.runtime.base import BaseRuntime
|
|||
|
|
|
|||
|
|
|
|||
|
|
class NativeRuntime(BaseRuntime):
|
|||
|
|
"""原生二进制运行时"""
|
|||
|
|
|
|||
|
|
def get_name(self) -> str:
|
|||
|
|
return "native"
|
|||
|
|
|
|||
|
|
async def validate(self, entry: str) -> bool:
|
|||
|
|
from pathlib import Path
|
|||
|
|
path = Path(entry)
|
|||
|
|
return path.exists() and path.stat().st_mode & 0o111
|
|||
|
|
|
|||
|
|
async def execute(
|
|||
|
|
self,
|
|||
|
|
entry: str,
|
|||
|
|
command: str,
|
|||
|
|
parameters: Dict[str, Any],
|
|||
|
|
timeout: int,
|
|||
|
|
) -> Dict[str, Any]:
|
|||
|
|
# 调用原生可执行文件
|
|||
|
|
args = [entry, command] + self._format_args(parameters)
|
|||
|
|
|
|||
|
|
process = await asyncio.create_subprocess_exec(
|
|||
|
|
*args,
|
|||
|
|
stdout=asyncio.subprocess.PIPE,
|
|||
|
|
stderr=asyncio.subprocess.PIPE,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
stdout, stderr = await asyncio.wait_for(
|
|||
|
|
process.communicate(),
|
|||
|
|
timeout=timeout / 1000,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if process.returncode != 0:
|
|||
|
|
return {
|
|||
|
|
"status": "error",
|
|||
|
|
"error": stderr.decode(),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
"status": "success",
|
|||
|
|
"result": stdout.decode(),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
def _format_args(self, parameters: Dict[str, Any]) -> list:
|
|||
|
|
"""格式化参数"""
|
|||
|
|
args = []
|
|||
|
|
for key, value in parameters.items():
|
|||
|
|
args.extend([f"--{key}", str(value)])
|
|||
|
|
return args
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.6 运行时管理器
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# tools/runtime/manager.py
|
|||
|
|
from tools.runtime.base import BaseRuntime
|
|||
|
|
from tools.runtime.python_runtime import PythonRuntime
|
|||
|
|
from tools.runtime.js_runtime import JavaScriptRuntime
|
|||
|
|
from tools.runtime.native_runtime import NativeRuntime
|
|||
|
|
|
|||
|
|
|
|||
|
|
class RuntimeManager:
|
|||
|
|
"""运行时管理器"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
self._runtimes: Dict[str, BaseRuntime] = {
|
|||
|
|
"python": PythonRuntime(),
|
|||
|
|
"javascript": JavaScriptRuntime(),
|
|||
|
|
"native": NativeRuntime(),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
def get_runtime(self, name: str) -> BaseRuntime:
|
|||
|
|
return self._runtimes.get(name)
|
|||
|
|
|
|||
|
|
async def execute(
|
|||
|
|
self,
|
|||
|
|
runtime_name: str,
|
|||
|
|
entry: str,
|
|||
|
|
command: str,
|
|||
|
|
parameters: Dict[str, Any],
|
|||
|
|
timeout: int,
|
|||
|
|
) -> Dict[str, Any]:
|
|||
|
|
runtime = self.get_runtime(runtime_name)
|
|||
|
|
if not runtime:
|
|||
|
|
return {
|
|||
|
|
"status": "error",
|
|||
|
|
"error": f"未知运行时: {runtime_name}",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return await runtime.execute(entry, command, parameters, timeout)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Agent 间协作
|
|||
|
|
|
|||
|
|
### 3.1 协作协议
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# agents/tools/collaboration.py
|
|||
|
|
from typing import Dict, Any, Optional, List
|
|||
|
|
from dataclasses import dataclass
|
|||
|
|
from datetime import datetime
|
|||
|
|
from enum import Enum
|
|||
|
|
|
|||
|
|
|
|||
|
|
class MessageType(str, Enum):
|
|||
|
|
REQUEST = "request" # 请求协作
|
|||
|
|
RESPONSE = "response" # 响应结果
|
|||
|
|
PROGRESS = "progress" # 进度更新
|
|||
|
|
CANCEL = "cancel" # 取消请求
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dataclass
|
|||
|
|
class CollaborationMessage:
|
|||
|
|
"""协作消息"""
|
|||
|
|
id: str
|
|||
|
|
type: MessageType
|
|||
|
|
from_agent: str
|
|||
|
|
to_agent: str
|
|||
|
|
content: Any
|
|||
|
|
metadata: Dict[str, Any]
|
|||
|
|
timestamp: datetime = None
|
|||
|
|
|
|||
|
|
def __post_init__(self):
|
|||
|
|
if self.timestamp is None:
|
|||
|
|
self.timestamp = datetime.utcnow()
|
|||
|
|
|
|||
|
|
|
|||
|
|
class CollaborationProtocol:
|
|||
|
|
"""Agent 协作协议"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
self._pending_requests: Dict[str, CollaborationMessage] = {}
|
|||
|
|
self._handlers: Dict[str, callable] = {}
|
|||
|
|
|
|||
|
|
def register_handler(self, tool_name: str, handler: callable) -> None:
|
|||
|
|
"""注册工具处理器"""
|
|||
|
|
self._handlers[tool_name] = handler
|
|||
|
|
|
|||
|
|
async def request_collaboration(
|
|||
|
|
self,
|
|||
|
|
from_agent: str,
|
|||
|
|
to_agent: str,
|
|||
|
|
tool_name: str,
|
|||
|
|
parameters: Dict[str, Any],
|
|||
|
|
timeout: int = 30000,
|
|||
|
|
) -> Dict[str, Any]:
|
|||
|
|
"""请求协作"""
|
|||
|
|
import uuid
|
|||
|
|
|
|||
|
|
request_id = str(uuid.uuid4())
|
|||
|
|
|
|||
|
|
message = CollaborationMessage(
|
|||
|
|
id=request_id,
|
|||
|
|
type=MessageType.REQUEST,
|
|||
|
|
from_agent=from_agent,
|
|||
|
|
to_agent=to_agent,
|
|||
|
|
content={
|
|||
|
|
"tool": tool_name,
|
|||
|
|
"parameters": parameters,
|
|||
|
|
},
|
|||
|
|
metadata={"timeout": timeout},
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
self._pending_requests[request_id] = message
|
|||
|
|
|
|||
|
|
# 发送请求
|
|||
|
|
await self._send_message(message)
|
|||
|
|
|
|||
|
|
# 等待响应
|
|||
|
|
try:
|
|||
|
|
response = await self._wait_for_response(
|
|||
|
|
request_id,
|
|||
|
|
timeout,
|
|||
|
|
)
|
|||
|
|
return response
|
|||
|
|
except TimeoutError:
|
|||
|
|
return {
|
|||
|
|
"status": "error",
|
|||
|
|
"error": "协作请求超时",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async def handle_request(
|
|||
|
|
self,
|
|||
|
|
message: CollaborationMessage,
|
|||
|
|
) -> CollaborationMessage:
|
|||
|
|
"""处理协作请求"""
|
|||
|
|
tool_name = message.content["tool"]
|
|||
|
|
parameters = message.content["parameters"]
|
|||
|
|
|
|||
|
|
handler = self._handlers.get(tool_name)
|
|||
|
|
if not handler:
|
|||
|
|
return CollaborationMessage(
|
|||
|
|
id=str(uuid.uuid4()),
|
|||
|
|
type=MessageType.RESPONSE,
|
|||
|
|
from_agent=message.to_agent,
|
|||
|
|
to_agent=message.from_agent,
|
|||
|
|
content={
|
|||
|
|
"status": "error",
|
|||
|
|
"error": f"未知工具: {tool_name}",
|
|||
|
|
},
|
|||
|
|
metadata={},
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
result = await handler(**parameters)
|
|||
|
|
return CollaborationMessage(
|
|||
|
|
id=str(uuid.uuid4()),
|
|||
|
|
type=MessageType.RESPONSE,
|
|||
|
|
from_agent=message.to_agent,
|
|||
|
|
to_agent=message.from_agent,
|
|||
|
|
content={"status": "success", "result": result},
|
|||
|
|
metadata={},
|
|||
|
|
)
|
|||
|
|
except Exception as e:
|
|||
|
|
return CollaborationMessage(
|
|||
|
|
id=str(uuid.uuid4()),
|
|||
|
|
type=MessageType.RESPONSE,
|
|||
|
|
from_agent=message.to_agent,
|
|||
|
|
to_agent=message.from_agent,
|
|||
|
|
content={"status": "error", "error": str(e)},
|
|||
|
|
metadata={},
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def _send_message(self, message: CollaborationMessage) -> None:
|
|||
|
|
"""发送消息"""
|
|||
|
|
# TODO: 实现消息发送(WebSocket/消息队列)
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
async def _wait_for_response(
|
|||
|
|
self,
|
|||
|
|
request_id: str,
|
|||
|
|
timeout: int,
|
|||
|
|
) -> Dict[str, Any]:
|
|||
|
|
"""等待响应"""
|
|||
|
|
# TODO: 实现等待逻辑
|
|||
|
|
pass
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 定时任务
|
|||
|
|
|
|||
|
|
### 4.1 定时任务服务
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# tools/scheduler.py
|
|||
|
|
import asyncio
|
|||
|
|
from typing import Dict, Any, Callable, Optional
|
|||
|
|
from datetime import datetime, timedelta
|
|||
|
|
from dataclasses import dataclass, field
|
|||
|
|
from enum import Enum
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ScheduleType(str, Enum):
|
|||
|
|
ONCE = "once" # 单次
|
|||
|
|
INTERVAL = "interval" # 间隔
|
|||
|
|
CRON = "cron" # Cron 表达式
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dataclass
|
|||
|
|
class ScheduledTask:
|
|||
|
|
"""定时任务"""
|
|||
|
|
id: str
|
|||
|
|
name: str
|
|||
|
|
schedule_type: ScheduleType
|
|||
|
|
schedule_value: str # 时间/间隔/cron
|
|||
|
|
tool_name: str
|
|||
|
|
parameters: Dict[str, Any]
|
|||
|
|
enabled: bool = True
|
|||
|
|
last_run: Optional[datetime] = None
|
|||
|
|
next_run: Optional[datetime] = None
|
|||
|
|
run_count: int = 0
|
|||
|
|
callback: Optional[Callable] = field(default=None)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ToolScheduler:
|
|||
|
|
"""工具定时调度器"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
self._tasks: Dict[str, ScheduledTask] = {}
|
|||
|
|
self._running = False
|
|||
|
|
self._loop_task = None
|
|||
|
|
|
|||
|
|
async def schedule(
|
|||
|
|
self,
|
|||
|
|
name: str,
|
|||
|
|
schedule_type: ScheduleType,
|
|||
|
|
schedule_value: str,
|
|||
|
|
tool_name: str,
|
|||
|
|
parameters: Dict[str, Any],
|
|||
|
|
callback: Optional[Callable] = None,
|
|||
|
|
) -> str:
|
|||
|
|
"""创建定时任务"""
|
|||
|
|
import uuid
|
|||
|
|
|
|||
|
|
task_id = str(uuid.uuid4())[:8]
|
|||
|
|
|
|||
|
|
task = ScheduledTask(
|
|||
|
|
id=task_id,
|
|||
|
|
name=name,
|
|||
|
|
schedule_type=schedule_type,
|
|||
|
|
schedule_value=schedule_value,
|
|||
|
|
tool_name=tool_name,
|
|||
|
|
parameters=parameters,
|
|||
|
|
callback=callback,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
task.next_run = self._calculate_next_run(task)
|
|||
|
|
self._tasks[task_id] = task
|
|||
|
|
|
|||
|
|
# 启动调度器
|
|||
|
|
if not self._running:
|
|||
|
|
await self.start()
|
|||
|
|
|
|||
|
|
return task_id
|
|||
|
|
|
|||
|
|
def _calculate_next_run(self, task: ScheduledTask) -> datetime:
|
|||
|
|
"""计算下次运行时间"""
|
|||
|
|
now = datetime.utcnow()
|
|||
|
|
|
|||
|
|
if task.schedule_type == ScheduleType.ONCE:
|
|||
|
|
return datetime.fromisoformat(task.schedule_value)
|
|||
|
|
|
|||
|
|
elif task.schedule_type == ScheduleType.INTERVAL:
|
|||
|
|
seconds = int(task.schedule_value)
|
|||
|
|
return now + timedelta(seconds=seconds)
|
|||
|
|
|
|||
|
|
elif task.schedule_type == ScheduleType.CRON:
|
|||
|
|
# 解析 cron 表达式
|
|||
|
|
# TODO: 实现 cron 解析
|
|||
|
|
return now + timedelta(hours=1)
|
|||
|
|
|
|||
|
|
return now
|
|||
|
|
|
|||
|
|
async def start(self) -> None:
|
|||
|
|
"""启动调度器"""
|
|||
|
|
self._running = True
|
|||
|
|
self._loop_task = asyncio.create_task(self._run_loop())
|
|||
|
|
|
|||
|
|
async def stop(self) -> None:
|
|||
|
|
"""停止调度器"""
|
|||
|
|
self._running = False
|
|||
|
|
if self._loop_task:
|
|||
|
|
self._loop_task.cancel()
|
|||
|
|
|
|||
|
|
async def _run_loop(self) -> None:
|
|||
|
|
"""调度循环"""
|
|||
|
|
while self._running:
|
|||
|
|
now = datetime.utcnow()
|
|||
|
|
|
|||
|
|
for task in self._tasks.values():
|
|||
|
|
if not task.enabled:
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
if task.next_run and task.next_run <= now:
|
|||
|
|
await self._execute_task(task)
|
|||
|
|
|
|||
|
|
await asyncio.sleep(1) # 每秒检查一次
|
|||
|
|
|
|||
|
|
async def _execute_task(self, task: ScheduledTask) -> None:
|
|||
|
|
"""执行任务"""
|
|||
|
|
# 调用工具
|
|||
|
|
executor = get_executor(task.tool_name)
|
|||
|
|
result = await executor(
|
|||
|
|
command=task.parameters.get("command"),
|
|||
|
|
parameters=task.parameters,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 更新状态
|
|||
|
|
task.last_run = datetime.utcnow()
|
|||
|
|
task.run_count += 1
|
|||
|
|
|
|||
|
|
# 计算下次运行
|
|||
|
|
if task.schedule_type != ScheduleType.ONCE:
|
|||
|
|
task.next_run = self._calculate_next_run(task)
|
|||
|
|
else:
|
|||
|
|
task.enabled = False
|
|||
|
|
|
|||
|
|
# 调用回调
|
|||
|
|
if task.callback:
|
|||
|
|
await task.callback(task, result)
|
|||
|
|
|
|||
|
|
async def cancel(self, task_id: str) -> bool:
|
|||
|
|
"""取消任务"""
|
|||
|
|
if task_id in self._tasks:
|
|||
|
|
del self._tasks[task_id]
|
|||
|
|
return True
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
async def list_tasks(self) -> list:
|
|||
|
|
"""列出所有任务"""
|
|||
|
|
return [
|
|||
|
|
{
|
|||
|
|
"id": t.id,
|
|||
|
|
"name": t.name,
|
|||
|
|
"type": t.schedule_type.value,
|
|||
|
|
"enabled": t.enabled,
|
|||
|
|
"next_run": t.next_run.isoformat() if t.next_run else None,
|
|||
|
|
"run_count": t.run_count,
|
|||
|
|
}
|
|||
|
|
for t in self._tasks.values()
|
|||
|
|
]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 实现步骤
|
|||
|
|
|
|||
|
|
| 步骤 | 任务 | 优先级 |
|
|||
|
|
|------|------|--------|
|
|||
|
|
| 1 | 实现运行时基类 | 🟢 高 |
|
|||
|
|
| 2 | 实现 Python 运行时 | 🟢 高 |
|
|||
|
|
| 3 | 实现 JS 运行时 | 🟡 中 |
|
|||
|
|
| 4 | 实现原生运行时 | 🟡 中 |
|
|||
|
|
| 5 | 实现运行时管理器 | 🟢 高 |
|
|||
|
|
| 6 | 实现协作协议 | 🟡 中 |
|
|||
|
|
| 7 | 实现定时调度器 | 🟡 中 |
|
|||
|
|
| 8 | 单元测试 | 🟡 中 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 核心文件变更
|
|||
|
|
|
|||
|
|
| 文件 | 变更 |
|
|||
|
|
|------|------|
|
|||
|
|
| `tools/runtime/__init__.py` | 新增 |
|
|||
|
|
| `tools/runtime/base.py` | 新增 |
|
|||
|
|
| `tools/runtime/python_runtime.py` | 新增 |
|
|||
|
|
| `tools/runtime/js_runtime.py` | 新增 |
|
|||
|
|
| `tools/runtime/native_runtime.py` | 新增 |
|
|||
|
|
| `tools/runtime/manager.py` | 新增 |
|
|||
|
|
| `agents/tools/collaboration.py` | 新增 |
|
|||
|
|
| `tools/scheduler.py` | 新增 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. 工作量估算
|
|||
|
|
|
|||
|
|
| 任务 | 工作量 |
|
|||
|
|
|------|--------|
|
|||
|
|
| 运行时基类 | 0.5 天 |
|
|||
|
|
| Python 运行时 | 0.5 天 |
|
|||
|
|
| JS 运行时 | 0.5 天 |
|
|||
|
|
| 原生运行时 | 0.5 天 |
|
|||
|
|
| 运行时管理器 | 0.5 天 |
|
|||
|
|
| 协作协议 | 1 天 |
|
|||
|
|
| 定时调度器 | 0.5 天 |
|
|||
|
|
| 单元测试 | 0.5 天 |
|
|||
|
|
| **总计** | **4 天** |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. 验收标准
|
|||
|
|
|
|||
|
|
- [ ] Python 运行时可正常执行工具
|
|||
|
|
- [ ] JS 运行时可通过 stdio 调用
|
|||
|
|
- [ ] 原生运行时可执行二进制
|
|||
|
|
- [ ] 运行时管理器正确路由
|
|||
|
|
- [ ] 协作协议可正常请求/响应
|
|||
|
|
- [ ] 定时调度器可按计划执行任务
|
|||
|
|
- [ ] 单元测试通过
|