From e7c53ca5df956386973de6eb2cae651226ef68f7 Mon Sep 17 00:00:00 2001 From: ZanzyTHEbar Date: Thu, 19 Feb 2026 15:48:38 +0000 Subject: [PATCH] fix(tools): improve error handling and search result formatting - focus: log warnings on DeleteKV and corrupt knowledge block instead of silently swallowing errors - retrieval: include search method (keyword/semantic) in result messages for clearer agent context - subagent test: respect iterator yield protocol by checking return value --- pkg/tools/focus.go | 9 ++++++--- pkg/tools/retrieval.go | 10 +++++----- pkg/tools/retrieval_test.go | 4 ++-- pkg/tools/subagent_tool_test.go | 4 +++- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/pkg/tools/focus.go b/pkg/tools/focus.go index e85515dda..c50200200 100644 --- a/pkg/tools/focus.go +++ b/pkg/tools/focus.go @@ -197,8 +197,9 @@ func (t *CompleteFocusTool) Execute(ctx context.Context, args map[string]interfa pruned := t.pruneHistory(history, state.CheckpointIndex) t.sessions.SetHistory(sk, pruned) - // Clean up focus state - _ = t.delegate.DeleteKV(ctx, focusAgentID, focusKey) + if err := t.delegate.DeleteKV(ctx, focusAgentID, focusKey); err != nil { + logger.WarnCF("focus", "failed to clean up focus state", map[string]interface{}{"error": err, "session": sk}) + } msgsBefore := len(history) msgsAfter := len(pruned) @@ -252,7 +253,9 @@ func (t *CompleteFocusTool) appendKnowledge(ctx context.Context, sessionKey, top kb := &KnowledgeBlock{} raw, err := t.delegate.GetKV(ctx, focusAgentID, kvKey) if err == nil && raw != "" { - _ = jsonv2.Unmarshal([]byte(raw), kb) + if uerr := jsonv2.Unmarshal([]byte(raw), kb); uerr != nil { + logger.WarnCF("focus", "corrupt knowledge block, resetting", map[string]interface{}{"error": uerr, "key": kvKey}) + } } kb.Entries = append(kb.Entries, KnowledgeEntry{ diff --git a/pkg/tools/retrieval.go b/pkg/tools/retrieval.go index 8886241e1..6ae057ef6 100644 --- a/pkg/tools/retrieval.go +++ b/pkg/tools/retrieval.go @@ -66,7 +66,7 @@ func (t *KeywordSearchTool) Execute(ctx context.Context, args map[string]interfa return ErrorResult(fmt.Sprintf("keyword search failed: %v", err)) } - return SilentResult(formatSearchResults("keyword_search", query, results)) + return SilentResult(formatSearchResults("keyword", query, results)) } // SemanticSearchTool performs vector ANN search using embeddings. @@ -136,7 +136,7 @@ func (t *SemanticSearchTool) Execute(ctx context.Context, args map[string]interf return ErrorResult(fmt.Sprintf("semantic search failed: %v", err)) } - return SilentResult(formatSearchResults("semantic_search", query, results)) + return SilentResult(formatSearchResults("semantic", query, results)) } // ChunkReadTool loads full document/chunk content by ID. @@ -185,13 +185,13 @@ func (t *ChunkReadTool) Execute(ctx context.Context, args map[string]interface{} return SilentResult(content) } -func formatSearchResults(source, query string, results []memory.SearchResult) string { +func formatSearchResults(method, query string, results []memory.SearchResult) string { if len(results) == 0 { - return fmt.Sprintf("No results found for: %s", query) + return fmt.Sprintf("No %s results found for: %s", method, query) } var sb strings.Builder - fmt.Fprintf(&sb, "Found %d results for '%s':\n\n", len(results), query) + fmt.Fprintf(&sb, "Found %d %s results for '%s':\n\n", len(results), method, query) for i, r := range results { fmt.Fprintf(&sb, "%d. [%s] (score: %.2f) id=%s\n", i+1, r.Source, r.Score, r.ID) diff --git a/pkg/tools/retrieval_test.go b/pkg/tools/retrieval_test.go index a41668b16..6fe7e9078 100644 --- a/pkg/tools/retrieval_test.go +++ b/pkg/tools/retrieval_test.go @@ -55,8 +55,8 @@ func TestChunkReadTool_MissingID(t *testing.T) { } func TestFormatSearchResults_Empty(t *testing.T) { - output := formatSearchResults("test", "query", nil) - assert.Contains(t, output, "No results found") + output := formatSearchResults("keyword", "query", nil) + assert.Contains(t, output, "No keyword results found") } func TestFormatSearchResults_WithResults(t *testing.T) { diff --git a/pkg/tools/subagent_tool_test.go b/pkg/tools/subagent_tool_test.go index 4aad3efe8..fd8f7fd2d 100644 --- a/pkg/tools/subagent_tool_test.go +++ b/pkg/tools/subagent_tool_test.go @@ -39,7 +39,9 @@ func (m *MockLanguageModel) Stream(_ context.Context, call fantasy.Call) (fantas return nil, err } return func(yield func(fantasy.StreamPart) bool) { - yield(fantasy.StreamPart{Type: fantasy.StreamPartTypeTextDelta, Delta: resp.Content.Text()}) + if !yield(fantasy.StreamPart{Type: fantasy.StreamPartTypeTextDelta, Delta: resp.Content.Text()}) { + return + } yield(fantasy.StreamPart{Type: fantasy.StreamPartTypeFinish, FinishReason: fantasy.FinishReasonStop}) }, nil }