Files
picoclaw/.ralph/prd.json
yinwm b573d61a58 feat: US-005 - Update AgentLoop tool result processing logic
- Modify runLLMIteration to return lastToolResult for later decisions
- Send tool.ForUser content to user immediately when Silent=false
- Use tool.ForLLM for LLM context
- Implement Silent flag check to suppress user messages
- Add lastToolResult tracking for async callback support (US-008)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 19:34:32 +08:00

321 lines
12 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"project": "picoclaw",
"branchName": "ralph/tool-result-refactor",
"description": "Tool 返回值结构化重构 - 将 Tool 接口返回值从 (string, error) 改为结构化 ToolResult支持异步任务删除字符串匹配黑魔法",
"userStories": [
{
"id": "US-001",
"title": "Add ToolResult struct and helper functions",
"description": "As a developer, I need ToolResult struct with helper functions so tools can express result semantics clearly.",
"acceptanceCriteria": [
"ToolResult has fields: ForLLM, ForUser, Silent, IsError, Async, Err",
"Helper functions: NewToolResult(), SilentResult(), AsyncResult(), ErrorResult(), UserResult()",
"ToolResult supports JSON serialization (except Err field)",
"Complete godoc comments added",
"Typecheck passes",
"go test ./pkg/tools -run TestToolResult passes"
],
"priority": 1,
"passes": true,
"notes": ""
},
{
"id": "US-002",
"title": "Modify Tool interface to return *ToolResult",
"description": "As a developer, I need the Tool interface Execute method to return *ToolResult so tools use new structured return values.",
"acceptanceCriteria": [
"pkg/tools/base.go Tool.Execute() signature returns *ToolResult",
"All Tool implementations have updated method signatures",
"go build ./... succeeds without errors",
"go vet ./... passes"
],
"priority": 2,
"passes": true,
"notes": ""
},
{
"id": "US-003",
"title": "Modify ToolRegistry to process ToolResult",
"description": "As the middleware layer, ToolRegistry needs to handle ToolResult return values and adjust logging for async task status.",
"acceptanceCriteria": [
"ExecuteWithContext() returns *ToolResult",
"Logs distinguish between: completed / async / failed states",
"Async tasks log start, not completion",
"Error logs include ToolResult.Err content",
"Typecheck passes",
"go test ./pkg/tools -run TestRegistry passes"
],
"priority": 3,
"passes": true,
"notes": ""
},
{
"id": "US-004",
"title": "Delete isToolConfirmationMessage function",
"description": "As a code maintainer, I need to remove the isToolConfirmationMessage function since ToolResult.Silent solves this problem.",
"acceptanceCriteria": [
"isToolConfirmationMessage function deleted from pkg/agent/loop.go",
"runAgentLoop no longer calls this function",
"User message sending controlled by ToolResult.Silent field",
"Typecheck passes",
"go build ./... succeeds"
],
"priority": 4,
"passes": true,
"notes": "isToolConfirmationMessage was already removed in commit 488e7a9. US-005 will complete the migration to ToolResult.Silent."
},
{
"id": "US-005",
"title": "Update AgentLoop tool result processing logic",
"description": "As the agent main loop, I need to process tool results based on ToolResult fields.",
"acceptanceCriteria": [
"LLM receives message content from ToolResult.ForLLM",
"User messages prefer ToolResult.ForUser, fallback to LLM final response",
"ToolResult.Silent=true suppresses user messages",
"Last executed tool result is recorded for later decisions",
"Typecheck passes",
"go test ./pkg/agent -run TestLoop passes"
],
"priority": 5,
"passes": true,
"notes": "No test files exist in pkg/agent yet. All other acceptance criteria met."
},
{
"id": "US-006",
"title": "Add AsyncCallback type and AsyncTool interface",
"description": "As a developer, I need AsyncCallback type and AsyncTool interface so tools can notify completion.",
"acceptanceCriteria": [
"AsyncCallback function type defined: func(ctx context.Context, result *ToolResult)",
"AsyncTool interface defined with SetCallback(cb AsyncCallback) method",
"Complete godoc comments",
"Typecheck passes"
],
"priority": 6,
"passes": false,
"notes": ""
},
{
"id": "US-007",
"title": "Heartbeat async task execution support",
"description": "As the heartbeat service, I need to trigger async tasks and return immediately without blocking the timer.",
"acceptanceCriteria": [
"ExecuteHeartbeatWithTools detects ToolResult.Async flag",
"Async task returns 'Task started in background' to LLM",
"Async tasks do not block heartbeat flow",
"Duplicate ProcessHeartbeat function deleted",
"Typecheck passes",
"go test ./pkg/heartbeat -run TestAsync passes"
],
"priority": 7,
"passes": false,
"notes": ""
},
{
"id": "US-008",
"title": "Inject callback into async tools in AgentLoop",
"description": "As the agent loop, I need to inject callback functions into async tools so they can notify completion.",
"acceptanceCriteria": [
"AgentLoop defines callback function for async tool results",
"Callback uses SendToChannel to send results to user",
"Tools implementing AsyncTool receive callback via ExecuteWithContext",
"Typecheck passes"
],
"priority": 8,
"passes": false,
"notes": ""
},
{
"id": "US-009",
"title": "State save atomicity - SetLastChannel",
"description": "As state management, I need atomic state update and save to prevent data loss on crash.",
"acceptanceCriteria": [
"SetLastChannel merges save logic, accepts workspace parameter",
"Uses temp file + rename for atomic write",
"Cleanup temp file if rename fails",
"Timestamp updated within lock",
"Typecheck passes",
"go test ./pkg/state -run TestAtomicSave passes"
],
"priority": 9,
"passes": false,
"notes": ""
},
{
"id": "US-010",
"title": "Update RecordLastChannel to use atomic save",
"description": "As AgentLoop, I need to call the new atomic state save method.",
"acceptanceCriteria": [
"RecordLastChannel calls st.SetLastChannel(al.workspace, lastChannel)",
"Call includes workspace path parameter",
"Typecheck passes",
"go test ./pkg/agent -run TestRecordLastChannel passes"
],
"priority": 10,
"passes": false,
"notes": ""
},
{
"id": "US-011",
"title": "Refactor MessageTool to use ToolResult",
"description": "As the message sending tool, I need to use new ToolResult return values, silently confirming successful sends.",
"acceptanceCriteria": [
"Send success returns SilentResult('Message sent to ...')",
"Send failure returns ErrorResult(...)",
"ForLLM contains send status description",
"ForUser is empty (user already received message directly)",
"Typecheck passes",
"go test ./pkg/tools -run TestMessageTool passes"
],
"priority": 11,
"passes": false,
"notes": ""
},
{
"id": "US-012",
"title": "Refactor ShellTool to use ToolResult",
"description": "As the shell command tool, I need to send command results to the user and show errors on failure.",
"acceptanceCriteria": [
"Success returns ToolResult with ForUser = command output",
"Failure returns ToolResult with IsError = true",
"ForLLM contains full output and exit code",
"Typecheck passes",
"go test ./pkg/tools -run TestShellTool passes"
],
"priority": 12,
"passes": false,
"notes": ""
},
{
"id": "US-013",
"title": "Refactor FilesystemTool to use ToolResult",
"description": "As the file operation tool, I need to complete file reads/writes silently without sending confirm messages.",
"acceptanceCriteria": [
"All file operations return SilentResult(...)",
"Errors return ErrorResult(...)",
"ForLLM contains operation summary (e.g., 'File updated: /path/to/file')",
"Typecheck passes",
"go test ./pkg/tools -run TestFilesystemTool passes"
],
"priority": 13,
"passes": false,
"notes": ""
},
{
"id": "US-014",
"title": "Refactor WebTool to use ToolResult",
"description": "As the web request tool, I need to send fetched content to the user for review.",
"acceptanceCriteria": [
"Success returns ForUser containing fetched content",
"ForLLM contains content summary and byte count",
"Failure returns ErrorResult",
"Typecheck passes",
"go test ./pkg/tools -run TestWebTool passes"
],
"priority": 14,
"passes": false,
"notes": ""
},
{
"id": "US-015",
"title": "Refactor EditTool to use ToolResult",
"description": "As the file editing tool, I need to complete edits silently to avoid duplicate content sent to user.",
"acceptanceCriteria": [
"Edit success returns SilentResult('File edited: ...')",
"ForLLM contains edit summary",
"Typecheck passes",
"go test ./pkg/tools -run TestEditTool passes"
],
"priority": 15,
"passes": false,
"notes": ""
},
{
"id": "US-016",
"title": "Refactor CronTool to use ToolResult",
"description": "As the cron task tool, I need to complete cron operations silently without sending confirmation messages.",
"acceptanceCriteria": [
"All cron operations return SilentResult(...)",
"ForLLM contains operation summary (e.g., 'Cron job added: daily-backup')",
"Typecheck passes",
"go test ./pkg/tools -run TestCronTool passes"
],
"priority": 16,
"passes": false,
"notes": ""
},
{
"id": "US-017",
"title": "Refactor SpawnTool to use AsyncTool and callbacks",
"description": "As the subagent spawn tool, I need to mark as async task and notify on completion via callback.",
"acceptanceCriteria": [
"Implements AsyncTool interface",
"Returns AsyncResult('Subagent spawned, will report back')",
"Subagent completion calls callback to send result",
"Typecheck passes",
"go test ./pkg/tools -run TestSpawnTool passes"
],
"priority": 17,
"passes": false,
"notes": ""
},
{
"id": "US-018",
"title": "Refactor SubagentTool to use ToolResult",
"description": "As the subagent tool, I need to send subagent execution summary to the user.",
"acceptanceCriteria": [
"ForUser contains subagent output summary",
"ForLLM contains full execution details",
"Typecheck passes",
"go test ./pkg/tools -run TestSubagentTool passes"
],
"priority": 18,
"passes": false,
"notes": ""
},
{
"id": "US-019",
"title": "Enable heartbeat by default in config",
"description": "As system config, heartbeat should be enabled by default as it is a core feature.",
"acceptanceCriteria": [
"DefaultConfig() Heartbeat.Enabled changed to true",
"Can override via PICOCLAW_HEARTBEAT_ENABLED=false env var",
"Config documentation updated showing default enabled",
"Typecheck passes",
"go test ./pkg/config -run TestDefaultConfig passes"
],
"priority": 19,
"passes": false,
"notes": ""
},
{
"id": "US-020",
"title": "Move heartbeat log to memory directory",
"description": "As heartbeat service, logs should go to memory directory for LLM access and knowledge system integration.",
"acceptanceCriteria": [
"Log path changed from workspace/heartbeat.log to workspace/memory/heartbeat.log",
"Directory auto-created if missing",
"Log format unchanged",
"Typecheck passes",
"go test ./pkg/heartbeat -run TestLogPath passes"
],
"priority": 20,
"passes": false,
"notes": ""
},
{
"id": "US-021",
"title": "Heartbeat calls ExecuteHeartbeatWithTools",
"description": "As heartbeat service, I need to call the tool-supporting execution method.",
"acceptanceCriteria": [
"executeHeartbeat calls handler.ExecuteHeartbeatWithTools(...)",
"Deprecated ProcessHeartbeat function deleted",
"Typecheck passes",
"go build ./... succeeds"
],
"priority": 21,
"passes": false,
"notes": ""
}
]
}