package engine // agent_executor.go 实现 AgentExecutor 接口. // // 这是连接 AgentTool(builtin 包)和 SubAgent 系统(engine 包)的桥梁. // AgentTool 通过 AgentExecutor 接口调用子 Agent, // 而 agent_executor.go 提供真正的实现,创建并运行 SubAgent. // // 升华改进(ELEVATED): 从"创建独立 Engine 实例"改为"fork 父 Engine". // 子 Agent 共享父 Engine 的 prompt cache,每次调用省 ~$0.018. // 替代方案:独立 Engine 实例(原设计),不共享缓存,每次重新加载系统提示. // // 设计动机:避免 builtin 包与 engine 包之间的循环依赖. // builtin 包定义 AgentExecutor 接口,engine 包实现它. import ( "context" "fmt" "os" "git.flytoex.net/yuanwei/flyto-agent/pkg/execenv" "git.flytoex.net/yuanwei/flyto-agent/pkg/tools" "git.flytoex.net/yuanwei/flyto-agent/pkg/tools/builtin" ) // agentExecutor 是 builtin.AgentExecutor 接口的实现. // 它持有父 Engine 的引用,用于 fork 子 Agent. type agentExecutor struct { parentEngine EngineRef registry *SubAgentRegistry taskStore *builtin.TaskStore agentRegistry *AgentRegistry // Agent 类型注册表(用于工具集解析) // executor 用于 RunSubAgentWorktree 路径下的 git 子进程 (方案 β). // 从 Engine.Config.Executor 透传, SetupAgentExecutor 读 engine.executor 字段. executor execenv.Executor } // newAgentExecutor 创建 AgentExecutor 实例. executor 不能为 nil (方案 β 严格 DI). func newAgentExecutor(parentEngine EngineRef, registry *SubAgentRegistry, taskStore *builtin.TaskStore, agentRegistry *AgentRegistry, executor execenv.Executor) *agentExecutor { if executor == nil { panic("engine.newAgentExecutor: executor is nil (方案 β 严格 DI)") } return &agentExecutor{ parentEngine: parentEngine, registry: registry, taskStore: taskStore, agentRegistry: agentRegistry, executor: executor, } } // RunSubAgent 同步运行一个子 Agent,阻塞直到完成,返回结果文本. // 实现 builtin.AgentExecutor 接口. // // 升华改进(ELEVATED): 使用 fork 模式而非独立 Engine 实例. // 工具过滤从 API 层裁剪改为运行时 canUseTool 拦截. // 若指定了 AgentType,通过 AgentRegistry 解析最终工具集(三层过滤). // 替代方案:创建独立 Engine 实例(不共享缓存,首轮加载全量系统提示). func (ae *agentExecutor) RunSubAgent(ctx context.Context, req builtin.AgentRunRequest, availableTools []tools.Tool) (string, error) { allowedMap := ae.resolveAllowedMap(req, availableTools) desc := req.Description if desc == "" { desc = "Sync sub-agent task" } // 创建子 Agent 配置(fork 模式) cfg := &SubAgentConfig{ Description: desc, Model: req.Model, AllowedTools: allowedMap, MaxTurns: 10, } // 传递 AllowedSubAgentTypes(来自 AgentDefinition,限制可 spawn 的子 Agent 类型) if ae.agentRegistry != nil && req.AgentType != "" { if def, ok := ae.agentRegistry.Get(req.AgentType); ok { cfg.AllowedSubAgentTypes = def.AllowedSubAgentTypes } } // fork 子 Agent(通过 EngineRef 接口,无需类型断言) // 升华改进(ELEVATED): 原方案 parentEngine.(*Engine) 类型断言 + SpawnSubAgent(eng, cfg)-- // 三处重复,且让 EngineRef 接口形同虚设(断言恒成立说明接口设计不完整). // 现在 ForkSubAgent 封装了内部调用,agentExecutor 完全面向接口编程. sa := ae.parentEngine.ForkSubAgent(cfg) // 注册到注册表 if ae.registry != nil { _ = ae.registry.Register(sa) defer ae.registry.Remove(sa.ID) } // 同步运行 result, err := sa.RunSync(ctx, req.Prompt) if err != nil { return "", fmt.Errorf("sub-agent failed: %w", err) } return result, nil } // RunSubAgentBackground 在后台运行一个子 Agent,立即返回任务 ID. // 实现 builtin.AgentExecutor 接口. func (ae *agentExecutor) RunSubAgentBackground(req builtin.AgentRunRequest, availableTools []tools.Tool) (string, error) { allowedMap := ae.resolveAllowedMap(req, availableTools) description := req.Description if description == "" { description = "Background sub-agent task" } // 创建子 Agent 配置(fork 模式) cfg := &SubAgentConfig{ Description: description, Model: req.Model, AllowedTools: allowedMap, MaxTurns: 10, } // 传递 AllowedSubAgentTypes(来自 AgentDefinition,限制可 spawn 的子 Agent 类型) if ae.agentRegistry != nil && req.AgentType != "" { if def, ok := ae.agentRegistry.Get(req.AgentType); ok { cfg.AllowedSubAgentTypes = def.AllowedSubAgentTypes } } sa := ae.parentEngine.ForkSubAgent(cfg) // 注册到注册表 if ae.registry != nil { if err := ae.registry.Register(sa); err != nil { return "", fmt.Errorf("register sub-agent: %w", err) } } // 在 TaskStore 中创建对应的任务(方便通过 TaskList 查看进度) if ae.taskStore != nil { task := ae.taskStore.Create( fmt.Sprintf("Sub-Agent: %s", description), fmt.Sprintf("Sub-Agent ID: %s\nPrompt: %s", sa.ID, truncate(req.Prompt, 200)), ) // 更新任务状态为进行中 ae.taskStore.Update(task.ID, builtin.TaskStatusInProgress) // 当子 Agent 完成时更新任务状态 go func() { err := sa.Wait() if err != nil { ae.taskStore.Update(task.ID, builtin.TaskStatusFailed) } else { ae.taskStore.Update(task.ID, builtin.TaskStatusDone) } }() } // 在后台运行 sa.RunBackground(req.Prompt) return sa.ID, nil } // RunSubAgentWorktree 在独立的 git worktree 中运行子 Agent. // 实现 builtin.AgentExecutor 接口. func (ae *agentExecutor) RunSubAgentWorktree(ctx context.Context, req builtin.AgentRunRequest, availableTools []tools.Tool) (string, error) { // 检测 git 仓库 repoRoot, ok := DetectGitRepo(ae.parentEngine.Cwd(), ae.executor) if !ok { return "", fmt.Errorf("worktree mode requires a git repository, but %s is not in a git repo", ae.parentEngine.Cwd()) } // 创建 worktree wtInfo, cleanup, err := CreateWorktree(repoRoot, req.BranchName, ae.executor) if err != nil { return "", fmt.Errorf("create worktree: %w", err) } // 确保在完成后清理 worktree defer func() { if cleanup != nil { if err := cleanup(); err != nil { fmt.Fprintf(os.Stderr, "agent_executor: worktree cleanup: %v\n", err) } } }() allowedMap := ae.resolveAllowedMap(req, availableTools) // 创建子 Agent 配置(fork 模式,使用 worktree 目录) cfg := &SubAgentConfig{ Description: fmt.Sprintf("Worktree sub-agent on branch %s", wtInfo.Branch), Model: req.Model, AllowedTools: allowedMap, MaxTurns: 10, Cwd: wtInfo.Path, } sa := ae.parentEngine.ForkSubAgent(cfg) // 注册到注册表 if ae.registry != nil { _ = ae.registry.Register(sa) defer ae.registry.Remove(sa.ID) } // 同步运行 result, err := sa.RunSync(ctx, req.Prompt) if err != nil { return "", fmt.Errorf("worktree sub-agent failed: %w", err) } // 在结果前添加 worktree 信息 wtResult := fmt.Sprintf("Worktree: %s\nBranch: %s\n\n%s", wtInfo.Path, wtInfo.Branch, result) return wtResult, nil } // resolveAllowedMap 根据请求中的 AgentType 解析最终可用工具集,返回 AllowedTools map. // // 精妙之处(CLEVER): AgentType 为空时退化为原有逻辑(FilterSubAgentTools), // 保证向后兼容.有 AgentType 时走三层过滤,工具集更精准. // 替代方案:始终走三层过滤(需要所有调用方都显式指定 AgentType). func (ae *agentExecutor) resolveAllowedMap(req builtin.AgentRunRequest, availableTools []tools.Tool) map[string]bool { // 若未指定 AgentType 或注册表为空,使用传统逻辑 if req.AgentType == "" || ae.agentRegistry == nil { return ToolsToAllowedMap(FilterSubAgentTools(availableTools)) } def, ok := ae.agentRegistry.Get(req.AgentType) if !ok { // 未知类型,退化为传统逻辑 return ToolsToAllowedMap(FilterSubAgentTools(availableTools)) } // 提取父工具集名称列表 parentToolNames := make([]string, 0, len(availableTools)) for _, t := range availableTools { parentToolNames = append(parentToolNames, t.Name()) } // 三层过滤 resolved := ae.agentRegistry.ResolveToolset(def, parentToolNames) if len(resolved) == 0 { return nil } m := make(map[string]bool, len(resolved)) for _, name := range resolved { m[name] = true } return m } // SetupAgentExecutor 为 Engine 设置 AgentExecutor. // 在 Engine 初始化后调用,连接 AgentTool 和 SubAgent 系统. // // 参数: // - engine: 父 Engine 实例 // - taskStore: 任务存储(用于后台模式的任务追踪) // - agentRegistry: Agent 类型注册表(用于工具集解析,可为 nil) // // 返回创建的 SubAgentRegistry(供外部使用). func SetupAgentExecutor(engine *Engine, taskStore *builtin.TaskStore, agentRegistry *AgentRegistry) *SubAgentRegistry { registry := NewSubAgentRegistry() executor := newAgentExecutor(engine, registry, taskStore, agentRegistry, engine.executor) // 查找并配置 AgentTool agentTool, ok := engine.tools.Get("Agent") if ok { if at, ok := agentTool.(*builtin.AgentTool); ok { at.SetExecutor(executor) } } return registry } // truncate 截断字符串到指定长度. func truncate(s string, maxLen int) string { if len(s) <= maxLen { return s } return s[:maxLen] + "..." }