Fix empty tool results from resource content (e.g. auto visualiser)#7866
Fix empty tool results from resource content (e.g. auto visualiser)#7866DOsinga merged 3 commits intoblock:mainfrom
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5977877466
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if let rmcp::model::ResourceContents::TextResourceContents { text, .. } = &r.resource { | ||
| return Some(text.clone()); |
There was a problem hiding this comment.
Serialize blob tool resources in Anthropic tool_result content
fix_empty_tool_results now considers ResourceContents::BlobResourceContents non-empty via extract_text_from_resource, so blob-only tool results skip placeholder injection, but this formatter only extracts TextResourceContents and drops blob resources. In that case the emitted Anthropic tool_result content is still an empty string, which is the same payload shape Anthropic rejects for empty tool results; this will still fail requests when tools return blob-backed resources (for example base64-encoded file reads).
Useful? React with 👍 / 👎.
jh-block
left a comment
There was a problem hiding this comment.
lgtm but the build seems to be failing
5977877 to
27077db
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 27077dbcb0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if let Some(r) = c.as_resource() { | ||
| if let rmcp::model::ResourceContents::TextResourceContents { | ||
| text, | ||
| .. | ||
| } = &r.resource |
There was a problem hiding this comment.
Handle blob resources in Snowflake tool responses
This formatter only extracts TextResourceContents from Content::resource(...), so BlobResourceContents still produce an empty text payload here. Because fix_empty_tool_results now treats blob-backed resources as non-empty, those tool results no longer get a fallback placeholder, and Snowflake requests can silently drop blob-only tool responses (the message is skipped when text_content stays empty), so the model never sees the tool output.
Useful? React with 👍 / 👎.
crates/goose/src/conversation/mod.rs
Outdated
| let text = extract_tool_result_text(&result.content); | ||
| if text.is_empty() { | ||
| // Add a placeholder text content so the tool result isn't empty | ||
| result.content.push(Content::text("(empty result)")); |
There was a problem hiding this comment.
Avoid labeling image-only tool results as empty
The new empty-result repair path adds (empty result) whenever extracted text is empty, but extract_tool_result_text only looks at text/resource content and ignores image content. That means image-only tool results are now rewritten as “empty” even when they contain real data, which can mislead downstream model reasoning in providers that already serialize tool images (for example, Google/OpenAI formatters).
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f16674c4df
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
crates/goose/src/conversation/mod.rs
Outdated
| fn has_tool_result_content(content: &[Content]) -> bool { | ||
| content | ||
| .iter() | ||
| .any(|c| c.as_text().is_some() || c.as_resource().is_some() || c.as_image().is_some()) |
There was a problem hiding this comment.
Check tool result payload text, not just content variant
has_tool_result_content currently treats any Content::text(...) or Content::resource(...) as non-empty even when the extractable text is "", so fix_empty_tool_results skips adding the placeholder for cases like empty text output or an empty embedded text resource (e.g., reading a 0-byte file). The downstream formatter logic in format_messages (Anthropic and Snowflake) filters out empty extracted strings, so these responses still serialize to empty tool-result content and can still trigger Anthropic 400s or dropped Snowflake tool output.
Useful? React with 👍 / 👎.
- Use extract_text_from_resource in anthropic/snowflake formatters to handle BlobResourceContents (not just TextResourceContents) - Check for image content in fix_empty_tool_results so image-only tool results aren't incorrectly labeled as empty
f16674c to
0b67387
Compare
* origin/main: fix(openai): use Responses API for gpt-5.4 (#7982) Remove lead/worker provider (#7989) chore(release): release version 1.28.0 (#7991) Fix empty tool results from resource content (e.g. auto visualiser) (#7866) Separate SSE streaming from POST work submission (#7834) fix: include token usage in Databricks streaming responses (#7959) Optimize tool summarization (#7938)
* main: (22 commits) feat: add gemini-acp provider, update docs on subscription models + improvements to codex (#8000) fix(openai): use Responses API for gpt-5.4 (#7982) Remove lead/worker provider (#7989) chore(release): release version 1.28.0 (#7991) Fix empty tool results from resource content (e.g. auto visualiser) (#7866) Separate SSE streaming from POST work submission (#7834) fix: include token usage in Databricks streaming responses (#7959) Optimize tool summarization (#7938) fix: overwrite the deprecated googledrive extension config (#7974) refactor: remove unnecessary Arc<Mutex> from tool execution pipeline (#7979) Revert message flush & test (#7966) docs: add Remote Access section with Telegram Gateway documentation (#7955) fix: update webmcp blog post metadata image URL (#7967) fix: clean up OAuth token cache on provider deletion (#7908) fix: hard-coded tool call id in code mode callback (#7939) Fix SSE parsers to accept optional space after data: prefix (#7929) docs: add GOOSE_INPUT_LIMIT to config-files.md (#7961) Add WebMCP for Beginners blog post (#7957) Fix download manager (#7933) Improve the formatting of tool calls, show thinking, treat Reasoning and Thinking as the same thing (sorry Kant) (#7626) ...
…lock#7866) Co-authored-by: Douwe Osinga <[email protected]> Signed-off-by: esnyder <[email protected]>
…lock#7866) Co-authored-by: Douwe Osinga <[email protected]> Signed-off-by: esnyder <[email protected]>
Summary
Fixes #7613 — MCP tools that return
Content::resource(...)(like the Auto Visualiser extension) produce empty tool result strings when formatted for LLM APIs, because the formatters only extractedas_text()content. This causes:tool_resultblocks with empty contentChanges
Resource content extraction in provider formatters
Content::TextandContent::Resource(embedded text resources) in tool responsesEmpty tool result safety net in conversation repair
fix_empty_tool_resultspass to the conversation repair pipeline that adds a(empty result)placeholder to tool results with no extractable text contentextract_tool_result_texthelper that handles both Text and Resource content typesAgent loop cleanup
final_output_toollock patterns in the agent loop (cosmetic, same behavior)Testing
Content::embedded_text)CallToolResult::success(vec![])to use realistic content