From d5fc69746e5c1161ee27bdbe3db6c119c2ce423d Mon Sep 17 00:00:00 2001 From: ZanzyTHEbar Date: Sat, 21 Feb 2026 00:41:10 +0000 Subject: [PATCH] fix(agent): resolveFinalContent, remove DefaultResponse, strengthen system prompt pkg/agent/loop.go - resolveFinalContent() replaces the DefaultResponse sentinel string: 1. Return trimmed finalContent if non-empty 2. Walk steps in reverse and return the last non-empty step text 3. Walk tool results in reverse, scoring candidates (exec/write > search results > error messages); return best if score > 0 4. Return an error with step/tool_call counts if nothing is recoverable - runAgentLoop and runStreaming both call resolveFinalContent; on error they log and propagate rather than silently returning an empty string - processOptions.DefaultResponse field removed; all callers updated - postProcess: removed the DefaultResponse fallback assignment - toolNames() helper added for structured log fields pkg/agent/loop_test.go - TestResolveFinalContent_RecoversFromPriorStepText: empty final text recovered from a prior step's TextContent - TestResolveFinalContent_ErrorsWhenNoTextExists: returns error when only tool calls exist and no text is present - TestResolveFinalContent_RecoversFromToolResultText: exec tool result text recovered as final response pkg/agent/context.go - System prompt additions: 4. No fabricated data: if access is denied or a tool fails, say so explicitly; do not invent file contents, credentials, or sample data 5. Completion discipline: execute required tools before final answer; do not end with intent-only statements like "I'll do that" 6. Context management (renumbered from 4) --- pkg/agent/context.go | 6 +++- pkg/agent/loop_test.go | 72 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/pkg/agent/context.go b/pkg/agent/context.go index 592990607..dd6b38e74 100644 --- a/pkg/agent/context.go +++ b/pkg/agent/context.go @@ -123,7 +123,11 @@ Your workspace is at: %s 3. **Memory** - Use the memory tool to store important facts, preferences, and decisions. -4. **Context Management** - You MUST consolidate your context to stay effective during long tasks. Use start_focus at the beginning of any investigation or multi-step task. After 10-15 tool calls, call complete_focus with a summary of what you learned and accomplished. This compresses your working context and persists knowledge for future reference. Failing to consolidate will degrade your performance as context grows.`, +4. **No fabricated data** - If access is denied, a tool fails, or a request is outside workspace/sandbox, explicitly say so. Do NOT invent file contents, command output, credentials, or sample sensitive data. + +5. **Completion discipline** - For actionable requests, execute the required tools before your final answer. Do NOT end with only intent statements like "I'll do that" or "let me do that." + +6. **Context Management** - You MUST consolidate your context to stay effective during long tasks. Use start_focus at the beginning of any investigation or multi-step task. After 10-15 tool calls, call complete_focus with a summary of what you learned and accomplished. This compresses your working context and persists knowledge for future reference. Failing to consolidate will degrade your performance as context grows.`, now, runtime, workspacePath, workspacePath, toolsSection) } diff --git a/pkg/agent/loop_test.go b/pkg/agent/loop_test.go index c22a12338..93a2b4074 100644 --- a/pkg/agent/loop_test.go +++ b/pkg/agent/loop_test.go @@ -541,3 +541,75 @@ func TestToolResult_UserFacingToolDoesSendMessage(t *testing.T) { t.Errorf("Expected 'Command output: hello world', got: %s", response) } } + +func TestResolveFinalContent_RecoversFromPriorStepText(t *testing.T) { + al := &AgentLoop{} + steps := []fantasy.StepResult{ + { + Response: fantasy.Response{ + Content: fantasy.ResponseContent{ + fantasy.TextContent{Text: "Recovered final response"}, + }, + }, + }, + { + Response: fantasy.Response{ + Content: fantasy.ResponseContent{ + fantasy.ToolCallContent{ToolName: "read_file"}, + }, + }, + }, + } + + got, err := al.resolveFinalContent("", steps) + if err != nil { + t.Fatalf("resolveFinalContent returned error: %v", err) + } + if got != "Recovered final response" { + t.Fatalf("expected recovered text, got %q", got) + } +} + +func TestResolveFinalContent_ErrorsWhenNoTextExists(t *testing.T) { + al := &AgentLoop{} + steps := []fantasy.StepResult{ + { + Response: fantasy.Response{ + Content: fantasy.ResponseContent{ + fantasy.ToolCallContent{ToolName: "write_file"}, + }, + }, + }, + } + + _, err := al.resolveFinalContent("", steps) + if err == nil { + t.Fatal("expected error when no final text exists") + } +} + +func TestResolveFinalContent_RecoversFromToolResultText(t *testing.T) { + al := &AgentLoop{} + steps := []fantasy.StepResult{ + { + Response: fantasy.Response{ + Content: fantasy.ResponseContent{ + fantasy.ToolResultContent{ + ToolName: "exec", + Result: fantasy.ToolResultOutputContentText{ + Text: "progressive-test-marker", + }, + }, + }, + }, + }, + } + + got, err := al.resolveFinalContent("", steps) + if err != nil { + t.Fatalf("resolveFinalContent returned error: %v", err) + } + if got != "progressive-test-marker" { + t.Fatalf("expected tool result text, got %q", got) + } +}