feat(agents): Phase 7-10 hook system, plugins, skills, orchestration
Phase 7: Built-in Hooks (audit_log, dangerous_confirmation, security_scan) Phase 8: Plugin system (PluginManager, PluginSandbox, PluginManifest) Phase 9: Skills registry (SkillRegistry, local/plugin/MCP loaders) Phase 10: TeamLeader, RemoteTransport, BackgroundTaskManager
This commit is contained in:
@@ -0,0 +1,322 @@
|
||||
# Phase 6:工具系统重构(Tool System Refactoring)
|
||||
|
||||
日期:2026-04-04
|
||||
状态:待开始
|
||||
Demo参考:claw-code-main — tools/, StreamingToolExecutor, toolOrchestration
|
||||
|
||||
---
|
||||
|
||||
## 1. 阶段目标
|
||||
|
||||
建立**分层工具执行架构**,从现有的扁平工具调用进化为具有注册表、编排层、Hook 拦截能力的工具系统。
|
||||
|
||||
**与现有系统的区别**:
|
||||
|
||||
| 现有 | 目标 |
|
||||
|------|------|
|
||||
| Sub-Commander 直接调用 Tools | ToolRegistry → ToolOrchestration → HookExecutor → ToolExecutor → Tools |
|
||||
| 工具集固定 | 工具注册表支持动态注册 |
|
||||
| 无流式工具执行 | StreamingToolExecutor 支持流式 |
|
||||
| 无工具拦截 | PreTool/PostTool Hook 机制 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 架构设计
|
||||
|
||||
### 2.1 新的工具执行架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Agent / Sub-Commander │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ToolOrchestration Layer │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
|
||||
│ │ ToolRegistry│ │HookExecutor │ │ StreamingToolExecutor │ │
|
||||
│ │ (注册表) │ │ (拦截层) │ │ (流式执行器) │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ToolExecutor │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ Built-in │ │ External │ │ MCP │ │ Plugin │ │
|
||||
│ │ Tools │ │ Tools │ │ Tools │ │ Tools │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 核心组件
|
||||
|
||||
#### ToolRegistry(工具注册表)
|
||||
|
||||
```python
|
||||
# backend/app/agents/tools/registry.py
|
||||
|
||||
@dataclass
|
||||
class ToolManifest:
|
||||
"""工具元数据"""
|
||||
name: str
|
||||
description: str
|
||||
category: ToolCategory
|
||||
parameters: dict # JSON Schema
|
||||
return_schema: dict
|
||||
permission_class: PermissionClass # READ/WRITE/EXTERNAL
|
||||
side_effect_scope: SideEffectScope # NONE/LOCAL_STATE/DB_WRITE/NETWORK
|
||||
requires_confirmation: bool
|
||||
is_streaming: bool = False
|
||||
tags: list[str] = field(default_factory=list)
|
||||
|
||||
class ToolRegistry:
|
||||
"""工具注册表"""
|
||||
|
||||
def __init__(self):
|
||||
self._tools: dict[str, ToolManifest] = {}
|
||||
self._executors: dict[str, Callable] = {}
|
||||
self._hooks: dict[str, list[HookConfig]] = defaultdict(list)
|
||||
|
||||
def register(
|
||||
self,
|
||||
manifest: ToolManifest,
|
||||
executor: Callable,
|
||||
hooks: list[HookConfig] | None = None
|
||||
):
|
||||
"""注册工具"""
|
||||
self._tools[manifest.name] = manifest
|
||||
self._executors[manifest.name] = executor
|
||||
if hooks:
|
||||
for hook in hooks:
|
||||
self._hooks[manifest.name].append(hook)
|
||||
|
||||
def get(self, name: str) -> ToolManifest | None:
|
||||
"""获取工具元数据"""
|
||||
return self._tools.get(name)
|
||||
|
||||
def get_executor(self, name: str) -> Callable | None:
|
||||
"""获取工具执行器"""
|
||||
return self._executors.get(name)
|
||||
|
||||
def list_by_category(self, category: ToolCategory) -> list[ToolManifest]:
|
||||
"""按类别列出工具"""
|
||||
return [t for t in self._tools.values() if t.category == category]
|
||||
|
||||
def list_all(self) -> list[ToolManifest]:
|
||||
"""列出所有工具"""
|
||||
return list(self._tools.values())
|
||||
```
|
||||
|
||||
#### HookExecutor(拦截执行器)
|
||||
|
||||
```python
|
||||
# backend/app/agents/tools/hook_executor.py
|
||||
|
||||
@dataclass
|
||||
class HookConfig:
|
||||
"""Hook 配置"""
|
||||
name: str
|
||||
hook_type: HookType # PRE_TOOL_USE / POST_TOOL_USE / TOOL_ERROR / TOOL_SKIP
|
||||
handler: Callable
|
||||
filter_names: list[str] | None = None # 只对特定工具生效,None 表示全部
|
||||
|
||||
class HookExecutor:
|
||||
"""工具 Hook 执行器"""
|
||||
|
||||
async def pre_execute(self, tool_name: str, arguments: dict) -> HookResult:
|
||||
"""PreToolUse - 工具执行前拦截"""
|
||||
hooks = self._get_hooks(tool_name, HookType.PRE_TOOL_USE)
|
||||
|
||||
ctx = HookContext(
|
||||
tool_name=tool_name,
|
||||
arguments=arguments,
|
||||
phase=HookPhase.PRE
|
||||
)
|
||||
|
||||
for hook in hooks:
|
||||
result = await hook.handler(ctx)
|
||||
if result.action == HookAction.DENY:
|
||||
return HookResult(
|
||||
action=HookAction.DENY,
|
||||
message=result.message,
|
||||
modified_args=None
|
||||
)
|
||||
elif result.action == HookAction.MODIFY:
|
||||
ctx.arguments = result.modified_args
|
||||
|
||||
return HookResult(action=HookAction.ALLOW, modified_args=ctx.arguments)
|
||||
|
||||
async def post_execute(
|
||||
self,
|
||||
tool_name: str,
|
||||
arguments: dict,
|
||||
result: Any
|
||||
) -> HookResult:
|
||||
"""PostToolUse - 工具执行后拦截"""
|
||||
hooks = self._get_hooks(tool_name, HookType.POST_TOOL_USE)
|
||||
|
||||
ctx = HookContext(
|
||||
tool_name=tool_name,
|
||||
arguments=arguments,
|
||||
result=result,
|
||||
phase=HookPhase.POST
|
||||
)
|
||||
|
||||
for hook in hooks:
|
||||
result = await hook.handler(ctx)
|
||||
if result.action == HookAction.MODIFY_RESULT:
|
||||
ctx.result = result.modified_result
|
||||
|
||||
return HookResult(action=HookAction.CONTINUE, modified_result=ctx.result)
|
||||
```
|
||||
|
||||
#### StreamingToolExecutor(流式工具执行器)
|
||||
|
||||
```python
|
||||
# backend/app/agents/tools/streaming_executor.py
|
||||
|
||||
class StreamingToolExecutor:
|
||||
"""流式工具执行器"""
|
||||
|
||||
async def execute_streaming(
|
||||
self,
|
||||
tool_name: str,
|
||||
arguments: dict,
|
||||
callback: Callable[[dict], Awaitable[None]]
|
||||
) -> Any:
|
||||
"""执行流式工具"""
|
||||
manifest = self.registry.get(tool_name)
|
||||
if not manifest.is_streaming:
|
||||
raise ValueError(f"Tool {tool_name} does not support streaming")
|
||||
|
||||
executor = self.registry.get_executor(tool_name)
|
||||
|
||||
# 使用 aiterator 进行流式执行
|
||||
async for chunk in executor(**arguments):
|
||||
event = {"type": "chunk", "data": chunk}
|
||||
await callback(event)
|
||||
yield chunk
|
||||
|
||||
final_event = {"type": "done", "tool": tool_name}
|
||||
await callback(final_event)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 新增工具集
|
||||
|
||||
### 3.1 文件操作工具
|
||||
|
||||
| 工具 | 描述 | 权限级别 |
|
||||
|------|------|---------|
|
||||
| GlobTool | 按模式匹配文件 | READ |
|
||||
| GrepTool | 在文件中搜索内容 | READ |
|
||||
| LintTool | 代码检查 | READ |
|
||||
| EditTool | 编辑文件 | WRITE |
|
||||
|
||||
### 3.2 开发工具
|
||||
|
||||
| 工具 | 描述 | 权限级别 |
|
||||
|------|------|---------|
|
||||
| LSPTool | Language Server Protocol | READ |
|
||||
| BashTool | 执行 Bash 命令 | EXTERNAL |
|
||||
| PowerShellTool | 执行 PowerShell | EXTERNAL |
|
||||
|
||||
### 3.3 系统工具
|
||||
|
||||
| 工具 | 描述 | 权限级别 |
|
||||
|------|------|---------|
|
||||
| ScheduleCronTool | Cron 定时任务 | WRITE |
|
||||
| ProcessTool | 进程管理 | EXTERNAL |
|
||||
|
||||
### 3.4 协作工具
|
||||
|
||||
| 工具 | 描述 | 权限级别 |
|
||||
|------|------|---------|
|
||||
| TeamAgentTool | 团队 Agent 协作 | EXTERNAL |
|
||||
| TaskBroadcastTool | 任务广播 | WRITE |
|
||||
|
||||
### 3.5 高级工具
|
||||
|
||||
| 工具 | 描述 | 权限级别 |
|
||||
|------|------|---------|
|
||||
| RemoteTriggerTool | 远程触发 | EXTERNAL |
|
||||
| MCPClientTool | MCP 客户端 | EXTERNAL |
|
||||
| AskUserQuestionTool | 向用户提问 | READ |
|
||||
|
||||
---
|
||||
|
||||
## 4. 文件结构变化
|
||||
|
||||
```
|
||||
backend/app/agents/tools/
|
||||
├── __init__.py # 现有 - 需重构
|
||||
├── registry.py # 新增 - 工具注册表
|
||||
├── manifest.py # 新增 - 工具元数据
|
||||
├── hook_executor.py # 新增 - Hook 执行器
|
||||
├── hook_config.py # 新增 - Hook 配置
|
||||
├── streaming_executor.py # 新增 - 流式执行器
|
||||
├── base.py # 新增 - 基础工具类
|
||||
│
|
||||
├── builtins/ # 新增 - 内置工具
|
||||
│ ├── __init__.py
|
||||
│ ├── file_tools.py # Glob, Grep, Edit, Lint
|
||||
│ ├── system_tools.py # Bash, PowerShell, Cron
|
||||
│ ├── dev_tools.py # LSP, Git
|
||||
│ └── collaboration_tools.py # Team, Broadcast
|
||||
│
|
||||
├── task.py # 现有 - 保留
|
||||
├── schedule.py # 现有 - 保留
|
||||
├── search.py # 现有 - 保留
|
||||
├── forum.py # 现有 - 保留
|
||||
└── time_reasoning.py # 现有 - 保留
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 迁移计划
|
||||
|
||||
### 阶段 6.1:基础设施(1-2周)
|
||||
- 创建 ToolRegistry 类
|
||||
- 创建 ToolManifest 数据类
|
||||
- 迁移现有工具到注册表
|
||||
|
||||
### 阶段 6.2:Hook 系统(2-3周)
|
||||
- 创建 HookExecutor
|
||||
- 实现 PreTool/PostTool 机制
|
||||
- 添加内置 Hook(确认危险操作、日志记录)
|
||||
|
||||
### 阶段 6.3:流式执行(1-2周)
|
||||
- 实现 StreamingToolExecutor
|
||||
- 为支持流式的工具添加 streaming 标志
|
||||
- 更新 AgentService 集成
|
||||
|
||||
### 阶段 6.4:新工具集(2-3周)
|
||||
- 实现新增的工具类
|
||||
- 添加完整的工具文档
|
||||
- 单元测试覆盖
|
||||
|
||||
---
|
||||
|
||||
## 6. 验收标准
|
||||
|
||||
| 检查点 | 标准 |
|
||||
|--------|------|
|
||||
| 工具注册 | 所有现有工具已在 Registry 中注册 |
|
||||
| Hook 执行 | PreTool/PostTool Hook 能正确拦截 |
|
||||
| 流式执行 | 标记为 streaming 的工具可流式返回 |
|
||||
| 新工具 | 新增工具集中每个工具可正常执行 |
|
||||
| 向后兼容 | 现有 Sub-Commander 工具调用不受影响 |
|
||||
|
||||
---
|
||||
|
||||
## 7. Demo 借鉴
|
||||
|
||||
| claw-code 实现 | Jarvis 对应 |
|
||||
|----------------|------------|
|
||||
| `src/tools/` | `backend/app/agents/tools/` |
|
||||
| `StreamingToolExecutor.ts` | `streaming_executor.py` |
|
||||
| `toolExecution.ts` | `hook_executor.py` |
|
||||
| `toolHooks.ts` | `hook_config.py` |
|
||||
| `ToolManifest` | `manifest.py` |
|
||||
Reference in New Issue
Block a user