Skip to content

fix(ai): round-trip Anthropic tool_search_tool_result blocks - #48485

Open
lu-zero wants to merge 1 commit into
anomalyco:betafrom
lu-zero:luca/beta-tool-search-roundtrip
Open

fix(ai): round-trip Anthropic tool_search_tool_result blocks#48485
lu-zero wants to merge 1 commit into
anomalyco:betafrom
lu-zero:luca/beta-tool-search-roundtrip

Conversation

@lu-zero

@lu-zero lu-zero commented Sep 11, 2026

Copy link
Copy Markdown

Issue for this PR

Fixes #45527.

Scope note: this is the protocol half only — the wire round-trip for Anthropic tool-search blocks. It does not add the config seam (defer_loading passthrough, declaring a provider-defined tool) that #45527 also asks for; happy to keep that issue open if maintainers prefer.

Targets beta. The same fix against dev is #48466, where the file lives at packages/llm/src/protocols/anthropic-messages.ts; beta has the identical gap at packages/ai/src/protocols/anthropic-messages.ts.

Type of change

  • Bug fix

What does this PR do?

The native Anthropic protocol dropped tool_search_tool_result content blocks at stream-decode time and refused to lower them back onto the wire. Both gaps keyed off the same hardcoded three-entry server-tool list, which predates Anthropic's tool-search server tools.

A tool search puts signed thinking, server_tool_use, tool_search_tool_result and tool_use in one assistant turn. Dropping the result block means the replayed turn no longer matches the original response, and Anthropic rejects the signed thinking block:

`thinking` or `redacted_thinking` blocks in the latest assistant message cannot be modified.

One unhandled block type turns into a hard 400 for the rest of the conversation.

File Change
ai/src/protocols/anthropic-messages.ts Accept and re-emit tool_search_tool_result; record server_tool_use id → name in parser state, because tool_search_tool_bm25 and tool_search_tool_regex both report through one result block type that carries no name of its own.
ai/test/provider/anthropic-messages.test.ts Round-trip coverage: decode the tool-search turn, then recompile it and assert every sibling of the signed thinking block survives.

How did you verify your code works?

Check Result
bun test test/provider/anthropic-messages.test.ts 70 pass, 0 fail
Same test with the source change reverted fails — the tool-result event is absent entirely
bun turbo typecheck 35/35 tasks pass

Screenshots / recordings

N/A — provider wire-format change.

Checklist

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

🤖 Generated with Claude Code

The native Anthropic protocol dropped `tool_search_tool_result` content
blocks at stream-decode time and refused to lower them back onto the
wire. Both gaps keyed off the same hardcoded three-entry server-tool
list, which predates Anthropic's tool-search server tools.

A tool search puts signed `thinking`, `server_tool_use`,
`tool_search_tool_result` and `tool_use` in a single assistant turn.
Dropping the result block means the replayed turn no longer matches the
original response, and Anthropic rejects the signed thinking block:
"`thinking` or `redacted_thinking` blocks in the latest assistant
message cannot be modified."

Also records `server_tool_use` id -> name in the parser state, because
`tool_search_tool_bm25` and `tool_search_tool_regex` both report through
one `tool_search_tool_result` block type and the result block carries no
name of its own.

Port of the same fix made against `dev` in anomalyco#48466,
where the file lives at `packages/llm/src/protocols/anthropic-messages.ts`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions

Copy link
Copy Markdown
Contributor

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

Found one related PR:

This is not a duplicate of the current PR (#48485). According to the PR description, #48466 is the companion fix against the dev branch (in packages/llm), while #48485 is the same fix against the beta branch (in packages/ai). These are parallel changes to address the same underlying issue in two different code locations.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant