Skip to content

fix(ai): degrade unknown provider-executed tool calls to text on Anthropic Messages - #55560

Open
nic-lan wants to merge 2 commits into
anomalyco:devfrom
nic-lan:fix/anthropic-degrade-unknown-server-tool-results
Open

nic-lan wants to merge 2 commits into
anomalyco:devfrom
nic-lan:fix/anthropic-degrade-unknown-server-tool-results

Conversation

@nic-lan

@nic-lan nic-lan commented Oct 14, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #53633

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

When a conversation starts on claude-code/* (tools run natively, providerExecuted: true) and is later continued on an Anthropic Messages route (e.g. google-vertex/claude-*), lowering the history threw: server_tool_use.name in the Anthropic SDK is a closed literal union covering only web_search, code_execution, and web_fetch, and tools like read aren't in it. Both lowerServerToolResult and the assistant tool-call branch in packages/ai/src/protocols/anthropic-messages.ts threw/produced an invalid block for anything outside that set.

Fix: for a providerExecuted tool-call or tool-result whose name isn't one of the three recognized server tools, emit a plain text block instead of server_tool_use / *_tool_result. Recognized server tools are untouched. Both the call and result sides had to change together — fixing only the result side would have left the call side emitting a server_tool_use block with a name the SDK's type doesn't allow, trading one failure for a malformed request.

Out of scope, left for follow-up: four additional Anthropic server tools (bash_code_execution, text_editor_code_execution, tool_search_tool_regex, tool_search_tool_bm25) hit this same code path and are also unmapped. Adding them is a separate, unrelated change.

How did you verify your code works?

Added a regression test reproducing the original failure (assistant message with a read tool-call + result, both providerExecuted: true, lowered for an Anthropic Messages route) and confirmed it failed before the fix and passes after. Updated an existing test that had asserted the old throw-on-unknown-tool behavior, since that's exactly what this PR changes. Full packages/ai test file for this route: bun test test/provider/anthropic-messages.test.ts — 76/76 pass.

Screenshots / recordings

N/A — no UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label Oct 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Oct 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@nic-lan
nic-lan marked this pull request as ready for review October 14, 2026 23:07
@nic-lan

nic-lan commented Oct 14, 2026

Copy link
Copy Markdown
Author

whenever this PR gets accepted, I leave to maintainers responsibility to update the branch once the time comes. :-)

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix works. I compiled an Anthropic Messages request whose history holds a provider-executed read (and tool_search_tool_regex) call/result pair. On the base it fails with "does not know how to round-trip server tool result". With this PR it compiles, and web_search still round-trips as server tool blocks. anthropic-messages.test.ts passes (76/76) and packages/ai type-checks. Turning unknown provider-executed results into text is consistent with what open-responses.ts already does.

Public API: unchanged.

One thing worth fixing, noted inline: results of type content are JSON-encoded whole, so file or image parts (for example a provider-executed read of an image) are sent to the model as raw base64 text.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v2: Anthropic Messages transform throws on round-trip of provider-executed tool results it doesn't recognize, instead of degrading

1 participant