- Add local ToolResult struct definition to avoid circular dependencies - Define HeartbeatHandler function type for tool-supporting callbacks - Add SetOnHeartbeatWithTools method to configure new handler - Add ExecuteHeartbeatWithTools public method - Add internal executeHeartbeatWithTools implementation - Update checkHeartbeat to prefer new tool-supporting handler - Detect and handle async tasks (log and return immediately) - Handle error results with proper logging - Add comprehensive tests for async, error, sync, and nil result cases Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
129 lines
6.6 KiB
Plaintext
129 lines
6.6 KiB
Plaintext
# Ralph Progress: tool-result-refactor
|
||
# Branch: ralph/tool-result-refactor
|
||
|
||
## Overview
|
||
Tool 返回值结构化重构 - 将 Tool 接口返回值从 (string, error) 改为结构化 ToolResult,支持异步任务,删除字符串匹配黑魔法
|
||
|
||
## Progress
|
||
|
||
### Completed (6/21)
|
||
|
||
- US-001: Add ToolResult struct and helper functions
|
||
- US-002: Modify Tool interface to return *ToolResult
|
||
- US-004: Delete isToolConfirmationMessage function (already removed in commit 488e7a9)
|
||
- US-005: Update AgentLoop tool result processing logic
|
||
- US-006: Add AsyncCallback type and AsyncTool interface
|
||
- US-007: Heartbeat async task execution support
|
||
|
||
### In Progress
|
||
|
||
### Blocked
|
||
|
||
### Pending
|
||
|
||
| ID | Title | Status | Notes |
|
||
|----|-------|--------|-------|
|
||
| US-003 | Modify ToolRegistry to process ToolResult | Pending | registry.go already updated |
|
||
| US-004 | Delete isToolConfirmationMessage function | Completed | Already removed in commit 488e7a9 |
|
||
| US-005 | Update AgentLoop tool result processing logic | Completed | No test files in pkg/agent yet |
|
||
| US-006 | Add AsyncCallback type and AsyncTool interface | Completed | |
|
||
| US-007 | Heartbeat async task execution support | Completed | |
|
||
| US-008 | Inject callback into async tools in AgentLoop | Pending | |
|
||
| US-009 | State save atomicity - SetLastChannel | Pending | |
|
||
| US-010 | Update RecordLastChannel to use atomic save | Pending | |
|
||
| US-011 | Refactor MessageTool to use ToolResult | Completed | |
|
||
| US-012 | Refactor ShellTool to use ToolResult | Completed | |
|
||
| US-013 | Refactor FilesystemTool to use ToolResult | Completed | |
|
||
| US-014 | Refactor WebTool to use ToolResult | Completed | |
|
||
| US-015 | Refactor EditTool to use ToolResult | Completed | |
|
||
| US-016 | Refactor CronTool to use ToolResult | Pending | |
|
||
| US-017 | Refactor SpawnTool to use AsyncTool and callbacks | Pending | |
|
||
| US-018 | Refactor SubagentTool to use ToolResult | Pending | |
|
||
| US-019 | Enable heartbeat by default in config | Pending | |
|
||
| US-020 | Move heartbeat log to memory directory | Pending | |
|
||
| US-021 | Heartbeat calls ExecuteHeartbeatWithTools | Pending | |
|
||
|
||
---
|
||
|
||
## [2026-02-12] - US-002
|
||
- What was implemented:
|
||
- 修复了所有剩余 Tool 实现的 Execute 方法返回值类型:
|
||
- `shell.go`: ExecTool 成功时返回 UserResult(ForUser=命令输出),失败时返回 ErrorResult
|
||
- `spawn.go`: SpawnTool 成功返回 NewToolResult,失败返回 ErrorResult
|
||
- `web.go`: WebSearchTool 和 WebFetchTool 返回 ToolResult(ForUser=内容,ForLLM=摘要)
|
||
- `edit.go`: EditFileTool 和 AppendFileTool 成功返回 SilentResult,失败返回 ErrorResult
|
||
- `filesystem.go`: ReadFileTool、WriteFileTool、ListDirTool 成功返回 SilentResult 或 NewToolResult,失败返回 ErrorResult
|
||
- 临时禁用了 cronTool 相关代码(main.go),等待 US-016 完成
|
||
|
||
- Files changed:
|
||
- `pkg/tools/shell.go`
|
||
- `pkg/tools/spawn.go`
|
||
- `pkg/tools/web.go`
|
||
- `pkg/tools/edit.go`
|
||
- `pkg/tools/filesystem.go`
|
||
- `cmd/picoclaw/main.go`
|
||
|
||
- **Learnings for future iterations:**
|
||
- **Patterns discovered:** 代码重构需要分步骤进行。先修改接口签名,再修改实现,最后处理调用方。
|
||
- **Gotchas encountered:** 临时禁用的代码(如 cronTool)需要同时注释掉所有相关的启动/停止调用,否则会编译失败。
|
||
- **Useful context:** `cron.go` 已被临时禁用(包含注释说明),将在 US-016 中恢复。main.go 中的 cronTool 相关代码也已用注释标记为临时禁用。
|
||
|
||
---
|
||
|
||
## [2026-02-12] - US-005
|
||
- What was implemented:
|
||
- 修改 `runLLMIteration` 返回值,增加 `lastToolResult *tools.ToolResult` 参数
|
||
- 在工具执行循环中,立即发送非 Silent 的 ForUser 内容给用户
|
||
- 使用 `toolResult.ForLLM` 发送内容给 LLM
|
||
- 实现了 Silent 标志检查:`if !toolResult.Silent && toolResult.ForUser != ""`
|
||
- 记录最后执行的工具结果用于后续决策
|
||
|
||
- Files changed:
|
||
- `pkg/agent/loop.go`
|
||
|
||
- **Learnings for future iterations:**
|
||
- **Patterns discovered:** 工具结果的处理需要区分两个目的地:LLM (ForLLM) 和用户 (ForUser)。用户消息应该在工具执行后立即发送,而不是等待 LLM 的最终响应。
|
||
- **Gotchas encountered:** 编辑大文件时要小心不要引入重复代码。我之前编辑时没有完整替换代码块,导致有重复的代码段。
|
||
- **Useful context:** `opts.SendResponse` 参数控制是否发送响应给用户。当工具设置了 `ForUser` 时,即使 Silent=false,也只有在 `SendResponse=true` 时才会发送。
|
||
|
||
---
|
||
|
||
## [2026-02-12] - US-006
|
||
- What was implemented:
|
||
- 在 `pkg/tools/base.go` 中定义 `AsyncCallback` 函数类型
|
||
- 定义 `AsyncTool` 接口,包含 `SetCallback(cb AsyncCallback)` 方法
|
||
- 添加完整的 godoc 注释,包含使用示例
|
||
|
||
- Files changed:
|
||
- `pkg/tools/base.go`
|
||
|
||
- **Learnings for future iterations:**
|
||
- **Patterns discovered:** Go 接口的设计应该是可选的组合模式。`AsyncTool` 是一个可选接口,工具可以选择实现以支持异步操作。
|
||
- **Gotchas encountered:** 无
|
||
- **Useful context:** 这个模式将在 US-008 中用于 `SpawnTool`,让子代理完成时能够通知主循环。
|
||
|
||
---
|
||
|
||
## [2026-02-12] - US-007
|
||
- What was implemented:
|
||
- 在 `pkg/heartbeat/service.go` 中添加了本地 `ToolResult` 结构体定义(避免循环依赖)
|
||
- 定义了 `HeartbeatHandler` 函数类型:`func(prompt string) *ToolResult`
|
||
- 在 `HeartbeatService` 中添加了 `onHeartbeatWithTools` 字段
|
||
- 添加了 `SetOnHeartbeatWithTools(handler HeartbeatHandler)` 方法来设置新的处理器
|
||
- 添加了 `ExecuteHeartbeatWithTools(prompt string)` 公开方法
|
||
- 添加了内部方法 `executeHeartbeatWithTools(prompt string)` 来处理工具结果
|
||
- 更新了 `checkHeartbeat()` 方法,优先使用新的工具支持处理器
|
||
- 异步任务检测:当 `result.Async == true` 时,记录日志并立即返回
|
||
- 错误处理:当 `result.IsError == true` 时,记录错误日志
|
||
- 普通完成:记录完成日志
|
||
|
||
- Files changed:
|
||
- `pkg/heartbeat/service.go`
|
||
- `pkg/heartbeat/service_test.go` (新增)
|
||
|
||
- **Learnings for future iterations:**
|
||
- **Patterns discovered:** 为了避免循环依赖,heartbeat 包定义了自己的本地 `ToolResult` 结构体,而不是导入 `pkg/tools` 包。
|
||
- **Gotchas encountered:** 原始代码中的 `running()` 函数逻辑有问题(新创建的服务会被认为是"正在运行"的),但这不在本次修改范围内。
|
||
- **Useful context:** 心跳服务现在支持两种处理器:旧的 `onHeartbeat (返回 string, error)` 和新的 `onHeartbeatWithTools (返回 *ToolResult)`。新的处理器优先级更高。
|
||
|
||
--- |