fix(web_fetch): include fetched page content in ForLLM response

The web_fetch tool's ForLLM field only returned metadata (byte count,
extractor type, truncation status) but omitted the actual extracted text.
This caused the LLM to never see fetched page content, making the tool
effectively useless and causing repeated fetch loops.

Append the extracted text content to ForLLM so the LLM can read and
reason about fetched web pages.

Fixes #388

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
CrisisAlpha 2026-02-20 14:44:40 +08:00
parent e599573ed4
commit 2a29a7eba9
2 changed files with 21 additions and 6 deletions

View file

@ -477,7 +477,7 @@ func (t *WebFetchTool) Execute(ctx context.Context, args map[string]interface{})
resultJSON, _ := json.MarshalIndent(result, "", " ") resultJSON, _ := json.MarshalIndent(result, "", " ")
return &ToolResult{ return &ToolResult{
ForLLM: fmt.Sprintf("Fetched %d bytes from %s (extractor: %s, truncated: %v)", len(text), urlStr, extractor, truncated), ForLLM: fmt.Sprintf("Fetched %d bytes from %s (extractor: %s, truncated: %v)\n\n%s", len(text), urlStr, extractor, truncated, text),
ForUser: string(resultJSON), ForUser: string(resultJSON),
} }
} }

View file

@ -36,9 +36,14 @@ func TestWebTool_WebFetch_Success(t *testing.T) {
t.Errorf("Expected ForUser to contain 'Test Page', got: %s", result.ForUser) t.Errorf("Expected ForUser to contain 'Test Page', got: %s", result.ForUser)
} }
// ForLLM should contain summary // ForLLM should contain summary metadata
if !strings.Contains(result.ForLLM, "bytes") && !strings.Contains(result.ForLLM, "extractor") { if !strings.Contains(result.ForLLM, "bytes") || !strings.Contains(result.ForLLM, "extractor") {
t.Errorf("Expected ForLLM to contain summary, got: %s", result.ForLLM) t.Errorf("Expected ForLLM to contain summary metadata, got: %s", result.ForLLM)
}
// ForLLM should contain the actual fetched page content
if !strings.Contains(result.ForLLM, "Test Page") {
t.Errorf("Expected ForLLM to contain actual page content 'Test Page', got: %s", result.ForLLM)
} }
} }
@ -68,9 +73,14 @@ func TestWebTool_WebFetch_JSON(t *testing.T) {
} }
// ForUser should contain formatted JSON // ForUser should contain formatted JSON
if !strings.Contains(result.ForUser, "key") && !strings.Contains(result.ForUser, "value") { if !strings.Contains(result.ForUser, "key") || !strings.Contains(result.ForUser, "value") {
t.Errorf("Expected ForUser to contain JSON data, got: %s", result.ForUser) t.Errorf("Expected ForUser to contain JSON data, got: %s", result.ForUser)
} }
// ForLLM should contain the actual JSON content, not just metadata
if !strings.Contains(result.ForLLM, "key") || !strings.Contains(result.ForLLM, "value") {
t.Errorf("Expected ForLLM to contain actual JSON content, got: %s", result.ForLLM)
}
} }
// TestWebTool_WebFetch_InvalidURL verifies error handling for invalid URL // TestWebTool_WebFetch_InvalidURL verifies error handling for invalid URL
@ -224,7 +234,7 @@ func TestWebTool_WebFetch_HTMLExtraction(t *testing.T) {
} }
// ForUser should contain extracted text (without script/style tags) // ForUser should contain extracted text (without script/style tags)
if !strings.Contains(result.ForUser, "Title") && !strings.Contains(result.ForUser, "Content") { if !strings.Contains(result.ForUser, "Title") || !strings.Contains(result.ForUser, "Content") {
t.Errorf("Expected ForUser to contain extracted text, got: %s", result.ForUser) t.Errorf("Expected ForUser to contain extracted text, got: %s", result.ForUser)
} }
@ -232,6 +242,11 @@ func TestWebTool_WebFetch_HTMLExtraction(t *testing.T) {
if strings.Contains(result.ForUser, "<script>") || strings.Contains(result.ForUser, "<style>") { if strings.Contains(result.ForUser, "<script>") || strings.Contains(result.ForUser, "<style>") {
t.Errorf("Expected script/style tags to be removed, got: %s", result.ForUser) t.Errorf("Expected script/style tags to be removed, got: %s", result.ForUser)
} }
// ForLLM should also contain the extracted text content
if !strings.Contains(result.ForLLM, "Title") || !strings.Contains(result.ForLLM, "Content") {
t.Errorf("Expected ForLLM to contain extracted text content, got: %s", result.ForLLM)
}
} }
// TestWebFetchTool_extractText verifies text extraction preserves newlines // TestWebFetchTool_extractText verifies text extraction preserves newlines