Skip to content

fix(bedrock): send tool-search beta header for Haiku 4.5 on Invoke /v1/messages - #36502

Merged
mateo-berri merged 3 commits into
litellm_internal_stagingfrom
litellm_bedrock_invoke_tool_search_fix
Aug 11, 2026
Merged

fix(bedrock): send tool-search beta header for Haiku 4.5 on Invoke /v1/messages#36502
mateo-berri merged 3 commits into
litellm_internal_stagingfrom
litellm_bedrock_invoke_tool_search_fix

Conversation

@mateo-berri

@mateo-berri mateo-berri commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • Tool search on Bedrock Invoke Haiku 4.5 always returned 400
  • The tool-search beta allowlist omitted Haiku 4.5 and Opus 4.7
  • Without the beta, Bedrock rejects tool_search_tool_* tool types

How it solves it:

  • Records supports_tool_search on the Bedrock Claude 4.5/4.6/4.7 entries in the model cost map
  • The beta-header check reads that flag first, keeping its name patterns only as a fallback for ARNs and ids the map cannot resolve
  • Haiku 4.5 and Opus 4.7 requests now carry the tool-search-tool-2025-10-19 beta
  • Re-enables the skipped e2e compat cell that caught this

RCA doc: https://app.notion.com/p/3b943b8acdab81bd9e85d8c5c9cc8536

User Flow

Before: a Claude Code user on Haiku 4.5 via Bedrock (Invoke) gets a 400 whenever tool search is active

  1. They send POST http://localhost:4000/v1/messages with model claude-haiku-4-5-bedrock-invoke and a tools array containing {"type":"tool_search_tool_regex_20251119","name":"tool_search_tool_regex"} plus their own tools
  2. The response is HTTP 400 with Bedrock's error: tools.0: Input tag 'tool_search_tool_regex_20251119' found using 'type' does not match any of the expected tags
  3. The identical request with model claude-sonnet-4-5-bedrock-invoke returns 200, so only Haiku (and any tool-search request on Opus 4.7 relying on the documented beta path) is broken

After: the same request succeeds and the model invokes the discovery tool

  1. They send the same POST http://localhost:4000/v1/messages with model claude-haiku-4-5-bedrock-invoke and the same tools array
  2. The response is HTTP 200 with a server_tool_use content block named tool_search_tool_regex
  3. The identical request on claude-sonnet-4-5-bedrock-invoke and claude-opus-4-7-bedrock-invoke also returns 200

Relevant issues

RCA doc: https://app.notion.com/p/3b943b8acdab81bd9e85d8c5c9cc8536

Linear ticket

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

Live proxy against real AWS Bedrock in us-east-1, one fresh worktree, venv and proxy per leg, both booted with litellm --config tests/e2e/claude_code/test_config.yaml --host 127.0.0.1 --port <port>. Same curl both times

Before, at commit d8762bf (merge base), on port 41387:

$ curl -s -w "HTTP %{http_code}\n" -X POST http://127.0.0.1:41387/v1/messages \
  -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" \
  -d '{"model":"claude-haiku-4-5-bedrock-invoke","max_tokens":64,
       "messages":[{"role":"user","content":"If you have a tool to discover other tools, use it to find one. Otherwise reply with the word done."}],
       "tools":[{"type":"tool_search_tool_regex_20251119","name":"tool_search_tool_regex"},
                {"name":"add_numbers","description":"Add two integers","input_schema":{"type":"object","properties":{"a":{"type":"integer"},"b":{"type":"integer"}},"required":["a","b"]}}]}'
{"error":{"message":"{\"message\":\"tools.0: Input tag 'tool_search_tool_regex_20251119' found using 'type' does not
match any of the expected tags: 'bash_20250124', 'custom', 'memory_20250818', 'text_editor_20250124',
'text_editor_20250429', 'text_editor_20250728', 'web_search_20250305'\"}. Received Model
Group=claude-haiku-4-5-bedrock-invoke\nAvailable Model Group Fallbacks=None","type":"None","param":"None","code":"400"}}
HTTP 400

The identical request at d8762bf on the other two tiers already returns 200 with a server_tool_use block, so only haiku is broken at the merge base

After, at commit 7d4488d (this PR's head), identical request on port 42417:

{"model":"claude-haiku-4-5-bedrock-invoke","id":"msg_bdrk_011RS1AB1iyGEkcCf3RyLHLy","type":"message",
 "role":"assistant","content":[
   {"type":"text","text":"I'll use the tool discovery function to search for available tools."},
   {"type":"server_tool_use","id":"srvtoolu_bdrk_016p2qLyqcTAVnBVnnuTcztw",
    "name":"tool_search_tool_regex","input":{"pattern":".*"}}],
 "stop_reason":"max_tokens", ...}
HTTP 200

Same request at 7d4488d on the other two matrix tiers, to show no regression:

claude-sonnet-4-5-bedrock-invoke: HTTP 200, content types ['server_tool_use']
claude-opus-4-7-bedrock-invoke:   HTTP 200, content types ['text', 'server_tool_use']

The e2e compat cell this PR re-enables, run at 7d4488d against that same proxy:

$ LITELLM_PROXY_URL=http://127.0.0.1:42417 LITELLM_MASTER_KEY=*** \
    pytest tests/e2e/claude_code/tool_search/test_bedrock_invoke.py -q
[compat] session totals:
  pass             3
[compat] per-provider breakdown:
  bedrock_invoke       pass=3
1 passed in 6.83s

Commit df54256 landed after this run; it only declares the new key in the generated JSON schema and the test suite's inline copy (no runtime code), so it cannot change the proven behavior

Opus 4.7 was verified direct against AWS before touching its allowlist entry: POST https://bedrock-runtime.us-east-1.amazonaws.com/model/us.anthropic.claude-opus-4-7/invoke with "anthropic_beta":["tool-search-tool-2025-10-19"] returns 200 with a server_tool_use block, so the in-code note claiming Bedrock rejects tool search on Opus 4.7 was stale

The regression tests were verified in both directions: at d8762bf the haiku and opus-4-7 beta-header parametrizations fail (anthropic_beta missing) and sonnet passes. For the model-map read added in 7d4488d, flipping the mapped haiku entry's supports_tool_search to false makes the check return false even though the name still matches a pattern; with the map-first read reverted that test fails, and with it restored all 98 tests in the file pass

QA notes, observed live and left alone by this PR: at the merge base only haiku hard-fails while opus 4.7 already returns 200 with server_tool_use, matching the direct-AWS check above that the stale in-code claim about opus was wrong. Response shapes also differ slightly per tier: opus adds stop_details, output_tokens_details.thinking_tokens and service_tier and uses a longer message id format, while haiku carries none of those

Type

🐛 Bug Fix

Caveats (if any)

  • The /chat/completions Invoke path still gates this beta to Opus 4 only
  • Follow-up: share _supports_tool_search_on_bedrock with that path

QA runbook

  • tests/e2e/claude_code/tool_search/test_bedrock_invoke.py::test_tool_search_bedrock_invoke - the proxy forwards a tool_search discovery tool to Bedrock Invoke and every probed Claude tier accepts it (needs AWS Bedrock credentials in env)
    • Boot the proxy: litellm --config tests/e2e/claude_code/test_config.yaml --port 4000
    • POST /v1/messages with model claude-haiku-4-5-bedrock-invoke, a tool_search_tool_regex_20251119 tool plus one custom tool (exact body in Proof of Fix above)
    • Expect 200 with a server_tool_use content block, not a 400 naming the tool tag
    • Repeat with claude-sonnet-4-5-bedrock-invoke and claude-opus-4-7-bedrock-invoke, expect 200 each
    • Sanity check: this test makes sense to add and is not hand-wavey (e.g., assert actual expected spend instead of just spend > 0) or potentially flaky

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

Note

Medium Risk
Changes which Bedrock models get tool-search beta headers and can cause upstream 400s if flags are wrong; scope is limited to Bedrock Invoke messages transformation and catalog metadata.

Overview
Fixes Bedrock Invoke /v1/messages tool-search failures (e.g. Haiku 4.5 400s) by ensuring the tool-search-tool-2025-10-19 beta is attached when the request uses tool-search tools.

_supports_tool_search_on_bedrock now consults the model cost map’s supports_tool_search first (via _get_provider_resolved_capability), with name-pattern matching only as a fallback for unmapped ids. The allowlist is expanded to include Haiku 4.5 and Opus 4.7 (replacing the prior note that Opus 4.7 lacked support).

supports_tool_search: true is added on relevant Bedrock Claude 4.5/4.6/4.7 entries in the model price JSON, wired through ModelInfo / get_model_info, and the JSON schema. Unit tests cover beta injection, map authority, and pattern fallback; the skipped Bedrock Invoke tool-search e2e test is re-enabled.

Reviewed by Cursor Bugbot for commit df54256. Bugbot is set up for automated code reviews on this repo. Configure here.

…1/messages

Bedrock InvokeModel rejects tool_search_tool_* tool types unless the
request body carries the tool-search-tool-2025-10-19 beta. The model
allowlist gating that beta omitted Haiku 4.5 (and Opus 4.7, supported
since launch per live verification), so every tool-search request on
those models got a Bedrock 400. Add both to the allowlist and re-enable
the e2e compat cell that caught it.
@greptile-apps

greptile-apps Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds a model metadata capability for Bedrock tool search and uses it when constructing Invoke /v1/messages beta headers.

  • Marks supported Claude 4.5, 4.6, and 4.7 Bedrock catalog entries with supports_tool_search.
  • Threads the capability through model-info typing, lookup output, and schema validation.
  • Adds regression coverage and re-enables the Bedrock Invoke compatibility test.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py Reads tool-search support from resolved model metadata before constructing the Bedrock-specific beta header.
model_prices_and_context_window.json Adds tool-search capability metadata to supported Bedrock Claude model entries.
litellm/utils.py Exposes the new capability through returned model information.
model_prices_and_context_window.schema.json Adds boolean schema validation for the new model capability.
tests/test_litellm/llms/bedrock/messages/invoke_transformations/test_anthropic_claude3_transformation.py Covers beta-header generation and catalog capability precedence.
tests/e2e/claude_code/tool_search/test_bedrock_invoke.py Re-enables the Bedrock Invoke tool-search compatibility matrix.

Reviews (3): Last reviewed commit: "fix(schema): declare supports_tool_searc..." | Re-trigger Greptile

@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_bedrock_invoke_tool_search_fix (df54256) with litellm_internal_staging (b0fac57)

Open in CodSpeed

Record supports_tool_search on the Bedrock Claude entries in both cost
map files and have _supports_tool_search_on_bedrock read it first via
the provider-resolved capability lookup, keeping the name patterns as a
fallback for ARNs and ids the map cannot resolve. Threads the flag
through ModelInfoBase and drops a dated remark from the pattern list
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit df54256. Configure here.

@cursor cursor 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit df54256. Configure here.

@mateo-berri
mateo-berri merged commit 5c70405 into litellm_internal_staging Aug 11, 2026
84 checks passed
@mateo-berri
mateo-berri deleted the litellm_bedrock_invoke_tool_search_fix branch August 11, 2026 19:21
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.

2 participants