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
323 lines
11 KiB
Markdown
323 lines
11 KiB
Markdown
# 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` |
|