Files
JARVIS/development-doc/plan/agent-update/phase-6-tool-system-refactoring.md
WIN-JHFT4D3SIVT\caoxiaozhu a3fe4d24fc 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
2026-04-04 22:56:27 +08:00

11 KiB
Raw Blame History

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工具注册表

# 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拦截执行器

# 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流式工具执行器

# 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.2Hook 系统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