mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
fix(bedrock): gate Invoke tool search on the model map's supports_tool_search flag
The Bedrock InvokeModel transformations decided whether to send the tool-search-tool-2025-10-19 beta from hardcoded model name lists (a pattern list on the messages path, an "opus-4" substring on the chat path), so Opus 4.8, Opus 5 and Sonnet 5 never got the beta on the messages path, Opus 5 and Sonnet 5 never got it on the chat path, Opus 4.1 got it without support, and /v1/model/info reported supports_tool_search as unset for all three. Both paths now read the model map through one shared helper: the Bedrock entries for Opus 4.8, Opus 5 and Sonnet 5 carry supports_tool_search explicitly, and a claude-tool-search fallback rule flags Claude 4.5 and newer for unmapped ids, inference-profile ARNs and mapped entries with no opinion, so the next Claude gets the beta with no code change. An explicit false on a resolved entry still wins.
This commit is contained in:
parent
a86be37aa6
commit
47b2479c94
9 changed files with 239 additions and 67 deletions
|
|
@ -18,6 +18,7 @@ from litellm.llms.bedrock.chat.invoke_transformations.base_invoke_transformation
|
|||
)
|
||||
from litellm.llms.bedrock.common_utils import (
|
||||
apply_bedrock_invoke_structured_output,
|
||||
bedrock_supports_tool_search,
|
||||
get_anthropic_beta_from_headers,
|
||||
normalize_bedrock_opus_output_config_effort,
|
||||
normalize_custom_field_on_tools,
|
||||
|
|
@ -265,7 +266,7 @@ class AmazonAnthropicClaudeConfig(AmazonInvokeConfig, AnthropicConfig):
|
|||
|
||||
if tool_search_used and not (programmatic_tool_calling_used or input_examples_used):
|
||||
beta_set.discard(ANTHROPIC_TOOL_SEARCH_BETA_HEADER)
|
||||
if "opus-4" in model.lower() or "opus_4" in model.lower():
|
||||
if bedrock_supports_tool_search(model):
|
||||
beta_set.add("tool-search-tool-2025-10-19")
|
||||
|
||||
auto_beta_list: Final = filter_and_transform_beta_headers(
|
||||
|
|
|
|||
|
|
@ -898,6 +898,20 @@ def bedrock_model_accepts_cache_points(model: str | None) -> bool:
|
|||
return any(entry.get("supports_prompt_caching") is True for entry in entries)
|
||||
|
||||
|
||||
def bedrock_supports_tool_search(model: str) -> bool:
|
||||
"""
|
||||
Whether Bedrock InvokeModel admits the ``tool_search_tool_*`` tool types on ``model``.
|
||||
|
||||
Backed by the ``supports_tool_search`` flag in ``model_prices_and_context_window.json``,
|
||||
an exact entry or the ``claude-tool-search`` fallback rule for Claude 4.5 and newer, so a
|
||||
newly released Claude carries the flag with no code change. An explicit ``false`` on the
|
||||
resolved entry wins over the rule.
|
||||
"""
|
||||
from litellm.llms.anthropic.common_utils import AnthropicModelInfo
|
||||
|
||||
return AnthropicModelInfo._supports_model_capability(model, "supports_tool_search", "bedrock")
|
||||
|
||||
|
||||
def is_claude_4_5_on_bedrock(model: str) -> bool:
|
||||
"""
|
||||
Check if the model supports Bedrock prompt caching with an extended '1h' TTL
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ from litellm.llms.bedrock.chat.invoke_transformations.base_invoke_transformation
|
|||
from litellm.llms.bedrock.common_utils import (
|
||||
BedrockError,
|
||||
apply_bedrock_invoke_structured_output,
|
||||
bedrock_supports_tool_search,
|
||||
ensure_bedrock_anthropic_messages_tool_names,
|
||||
get_anthropic_beta_from_headers,
|
||||
is_claude_4_5_on_bedrock,
|
||||
|
|
@ -386,9 +387,10 @@ class AmazonAnthropicClaudeMessagesConfig(
|
|||
"""
|
||||
Check if the model supports tool search on Bedrock.
|
||||
|
||||
The model map's ``supports_tool_search`` flag is authoritative when
|
||||
``model`` resolves to an entry that sets it; the name patterns below
|
||||
cover ids the map cannot resolve (ARNs, unlisted regional variants).
|
||||
The model map's ``supports_tool_search`` flag is authoritative: an exact
|
||||
entry, or the ``claude-tool-search`` fallback rule (Claude 4.5 and newer)
|
||||
for ids the map cannot resolve (ARNs, unlisted regional variants) and for
|
||||
mapped entries that carry no opinion.
|
||||
|
||||
Ref: https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-search-tool
|
||||
|
||||
|
|
@ -398,46 +400,7 @@ class AmazonAnthropicClaudeMessagesConfig(
|
|||
Returns:
|
||||
True if the model supports tool search on Bedrock
|
||||
"""
|
||||
catalog: Final = AnthropicModelInfo._get_provider_resolved_capability(model, "supports_tool_search", "bedrock")
|
||||
if catalog is not None:
|
||||
return catalog
|
||||
|
||||
model_lower: Final = model.lower()
|
||||
|
||||
supported_patterns: Final = [
|
||||
# Opus 4.5
|
||||
"opus-4.5",
|
||||
"opus_4.5",
|
||||
"opus-4-5",
|
||||
"opus_4_5",
|
||||
# Sonnet 4.5
|
||||
"sonnet-4.5",
|
||||
"sonnet_4.5",
|
||||
"sonnet-4-5",
|
||||
"sonnet_4_5",
|
||||
# Opus 4.6
|
||||
"opus-4.6",
|
||||
"opus_4.6",
|
||||
"opus-4-6",
|
||||
"opus_4_6",
|
||||
# sonnet 4.6
|
||||
"sonnet-4.6",
|
||||
"sonnet_4.6",
|
||||
"sonnet-4-6",
|
||||
"sonnet_4_6",
|
||||
# Opus 4.7
|
||||
"opus-4.7",
|
||||
"opus_4.7",
|
||||
"opus-4-7",
|
||||
"opus_4_7",
|
||||
# Haiku 4.5
|
||||
"haiku-4.5",
|
||||
"haiku_4.5",
|
||||
"haiku-4-5",
|
||||
"haiku_4_5",
|
||||
]
|
||||
|
||||
return any(pattern in model_lower for pattern in supported_patterns)
|
||||
return bedrock_supports_tool_search(model)
|
||||
|
||||
def _get_tool_search_beta_header_for_bedrock(
|
||||
self,
|
||||
|
|
@ -453,7 +416,8 @@ class AmazonAnthropicClaudeMessagesConfig(
|
|||
Bedrock requires a different beta header for tool search than the
|
||||
Anthropic API when tool search is used without programmatic tool
|
||||
calling or input examples: `tool-search-tool-2025-10-19`, and only on
|
||||
the models listed in `_supports_tool_search_on_bedrock`.
|
||||
the models the model map flags as `supports_tool_search`
|
||||
(`_supports_tool_search_on_bedrock`).
|
||||
|
||||
Ref: https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-search-tool
|
||||
|
||||
|
|
|
|||
|
|
@ -1810,6 +1810,7 @@
|
|||
"cache_read_input_token_cost": 5e-07,
|
||||
"input_cost_per_token": 5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -1847,6 +1848,7 @@
|
|||
"cache_read_input_token_cost": 5e-07,
|
||||
"input_cost_per_token": 5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -1884,6 +1886,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -1921,6 +1924,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -1957,6 +1961,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -1993,6 +1998,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2029,6 +2035,7 @@
|
|||
"cache_read_input_token_cost": 5e-07,
|
||||
"input_cost_per_token": 5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2067,6 +2074,7 @@
|
|||
"cache_read_input_token_cost": 5e-07,
|
||||
"input_cost_per_token": 5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2105,6 +2113,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2143,6 +2152,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2180,6 +2190,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2217,6 +2228,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2287,6 +2299,7 @@
|
|||
"cache_read_input_token_cost": 2e-07,
|
||||
"input_cost_per_token": 2e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2325,6 +2338,7 @@
|
|||
"cache_read_input_token_cost": 2e-07,
|
||||
"input_cost_per_token": 2e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2363,6 +2377,7 @@
|
|||
"cache_read_input_token_cost": 2.2e-07,
|
||||
"input_cost_per_token": 2.2e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2401,6 +2416,7 @@
|
|||
"cache_read_input_token_cost": 2.2e-07,
|
||||
"input_cost_per_token": 2.2e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2438,6 +2454,7 @@
|
|||
"cache_read_input_token_cost": 2.2e-07,
|
||||
"input_cost_per_token": 2.2e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2475,6 +2492,7 @@
|
|||
"cache_read_input_token_cost": 2.2e-07,
|
||||
"input_cost_per_token": 2.2e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -46114,6 +46132,7 @@
|
|||
"cache_read_input_token_cost": 2.4e-07,
|
||||
"input_cost_per_token": 2.4e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -46147,6 +46166,7 @@
|
|||
"cache_read_input_token_cost": 6e-07,
|
||||
"input_cost_per_token": 6e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -46179,6 +46199,7 @@
|
|||
"cache_read_input_token_cost": 6e-07,
|
||||
"input_cost_per_token": 6e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -59477,6 +59498,15 @@
|
|||
"supports_mid_conversation_system": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "claude-tool-search",
|
||||
"pattern": "claude-[a-z]+-(?:4[-._](?:[5-9]|[1-9]\\d)(?!\\d)|[5-9](?!\\d)(?:[-._]\\d{1,2}(?!\\d))?)",
|
||||
"fill_missing_for_providers": ["anthropic", "azure_ai", "bedrock", "bedrock_converse", "vertex_ai-anthropic_models"],
|
||||
"description": "Claude at version 4.5 or higher, in any id shape that contains claude-<family>-: minors 4.5 through 4.99, any later major-minor, and bare 5+ majors so a new family like claude-fable-5 matches. Two-digit majors are deliberately not matched so ids like claude-opus-41 (4.1) are not read as major 41. Anthropic shipped the tool search tool (tool_search_tool_regex, tool_search_tool_bm25) with Opus 4.5, Sonnet 4.5 and Haiku 4.5, and every newer Claude keeps it, so the flag follows the version instead of a per-model list. The Bedrock InvokeModel transformations read this flag to send the tool-search-tool-2025-10-19 beta, so a new Claude gets the beta with no code change.",
|
||||
"model_info": {
|
||||
"supports_tool_search": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "wandb-reasoning-baseline",
|
||||
"pattern": "^wandb/",
|
||||
|
|
@ -63214,6 +63244,7 @@
|
|||
"cache_read_input_token_cost": 2.4e-07,
|
||||
"input_cost_per_token": 2.4e-06,
|
||||
"litellm_provider": "bedrock",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -63246,6 +63277,7 @@
|
|||
"cache_read_input_token_cost": 6e-07,
|
||||
"input_cost_per_token": 6e-06,
|
||||
"litellm_provider": "bedrock",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -63277,6 +63309,7 @@
|
|||
"cache_read_input_token_cost": 6e-07,
|
||||
"input_cost_per_token": 6e-06,
|
||||
"litellm_provider": "bedrock",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -63417,6 +63450,7 @@
|
|||
"cache_read_input_token_cost": 2.4e-07,
|
||||
"input_cost_per_token": 2.4e-06,
|
||||
"litellm_provider": "bedrock",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -63449,6 +63483,7 @@
|
|||
"cache_read_input_token_cost": 6e-07,
|
||||
"input_cost_per_token": 6e-06,
|
||||
"litellm_provider": "bedrock",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -63480,6 +63515,7 @@
|
|||
"cache_read_input_token_cost": 6e-07,
|
||||
"input_cost_per_token": 6e-06,
|
||||
"litellm_provider": "bedrock",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
|
|||
|
|
@ -1810,6 +1810,7 @@
|
|||
"cache_read_input_token_cost": 5e-07,
|
||||
"input_cost_per_token": 5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -1847,6 +1848,7 @@
|
|||
"cache_read_input_token_cost": 5e-07,
|
||||
"input_cost_per_token": 5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -1884,6 +1886,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -1921,6 +1924,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -1957,6 +1961,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -1993,6 +1998,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2029,6 +2035,7 @@
|
|||
"cache_read_input_token_cost": 5e-07,
|
||||
"input_cost_per_token": 5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2067,6 +2074,7 @@
|
|||
"cache_read_input_token_cost": 5e-07,
|
||||
"input_cost_per_token": 5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2105,6 +2113,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2143,6 +2152,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2180,6 +2190,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2217,6 +2228,7 @@
|
|||
"cache_read_input_token_cost": 5.5e-07,
|
||||
"input_cost_per_token": 5.5e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2287,6 +2299,7 @@
|
|||
"cache_read_input_token_cost": 2e-07,
|
||||
"input_cost_per_token": 2e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2325,6 +2338,7 @@
|
|||
"cache_read_input_token_cost": 2e-07,
|
||||
"input_cost_per_token": 2e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2363,6 +2377,7 @@
|
|||
"cache_read_input_token_cost": 2.2e-07,
|
||||
"input_cost_per_token": 2.2e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2401,6 +2416,7 @@
|
|||
"cache_read_input_token_cost": 2.2e-07,
|
||||
"input_cost_per_token": 2.2e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2438,6 +2454,7 @@
|
|||
"cache_read_input_token_cost": 2.2e-07,
|
||||
"input_cost_per_token": 2.2e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -2475,6 +2492,7 @@
|
|||
"cache_read_input_token_cost": 2.2e-07,
|
||||
"input_cost_per_token": 2.2e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -46114,6 +46132,7 @@
|
|||
"cache_read_input_token_cost": 2.4e-07,
|
||||
"input_cost_per_token": 2.4e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -46147,6 +46166,7 @@
|
|||
"cache_read_input_token_cost": 6e-07,
|
||||
"input_cost_per_token": 6e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -46179,6 +46199,7 @@
|
|||
"cache_read_input_token_cost": 6e-07,
|
||||
"input_cost_per_token": 6e-06,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -59477,6 +59498,15 @@
|
|||
"supports_mid_conversation_system": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "claude-tool-search",
|
||||
"pattern": "claude-[a-z]+-(?:4[-._](?:[5-9]|[1-9]\\d)(?!\\d)|[5-9](?!\\d)(?:[-._]\\d{1,2}(?!\\d))?)",
|
||||
"fill_missing_for_providers": ["anthropic", "azure_ai", "bedrock", "bedrock_converse", "vertex_ai-anthropic_models"],
|
||||
"description": "Claude at version 4.5 or higher, in any id shape that contains claude-<family>-: minors 4.5 through 4.99, any later major-minor, and bare 5+ majors so a new family like claude-fable-5 matches. Two-digit majors are deliberately not matched so ids like claude-opus-41 (4.1) are not read as major 41. Anthropic shipped the tool search tool (tool_search_tool_regex, tool_search_tool_bm25) with Opus 4.5, Sonnet 4.5 and Haiku 4.5, and every newer Claude keeps it, so the flag follows the version instead of a per-model list. The Bedrock InvokeModel transformations read this flag to send the tool-search-tool-2025-10-19 beta, so a new Claude gets the beta with no code change.",
|
||||
"model_info": {
|
||||
"supports_tool_search": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "wandb-reasoning-baseline",
|
||||
"pattern": "^wandb/",
|
||||
|
|
@ -63214,6 +63244,7 @@
|
|||
"cache_read_input_token_cost": 2.4e-07,
|
||||
"input_cost_per_token": 2.4e-06,
|
||||
"litellm_provider": "bedrock",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -63246,6 +63277,7 @@
|
|||
"cache_read_input_token_cost": 6e-07,
|
||||
"input_cost_per_token": 6e-06,
|
||||
"litellm_provider": "bedrock",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -63277,6 +63309,7 @@
|
|||
"cache_read_input_token_cost": 6e-07,
|
||||
"input_cost_per_token": 6e-06,
|
||||
"litellm_provider": "bedrock",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -63417,6 +63450,7 @@
|
|||
"cache_read_input_token_cost": 2.4e-07,
|
||||
"input_cost_per_token": 2.4e-06,
|
||||
"litellm_provider": "bedrock",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -63449,6 +63483,7 @@
|
|||
"cache_read_input_token_cost": 6e-07,
|
||||
"input_cost_per_token": 6e-06,
|
||||
"litellm_provider": "bedrock",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
@ -63480,6 +63515,7 @@
|
|||
"cache_read_input_token_cost": 6e-07,
|
||||
"input_cost_per_token": 6e-06,
|
||||
"litellm_provider": "bedrock",
|
||||
"supports_tool_search": true,
|
||||
"max_input_tokens": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"max_tokens": 128000,
|
||||
|
|
|
|||
|
|
@ -206,6 +206,21 @@ def local_model_cost_map(monkeypatch):
|
|||
litellm.get_model_info.cache_clear()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def local_beta_headers_config(monkeypatch):
|
||||
"""Pin the bundled ``anthropic_beta_headers_config.json`` so beta header assertions
|
||||
do not depend on the network-fetched copy or on what earlier tests left cached."""
|
||||
from litellm.anthropic_beta_headers_manager import reload_beta_headers_config
|
||||
|
||||
monkeypatch.setenv("LITELLM_LOCAL_ANTHROPIC_BETA_HEADERS", "True")
|
||||
reload_beta_headers_config()
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
monkeypatch.delenv("LITELLM_LOCAL_ANTHROPIC_BETA_HEADERS", raising=False)
|
||||
reload_beta_headers_config()
|
||||
|
||||
|
||||
def _run_coroutine_if_needed(result):
|
||||
if not asyncio.iscoroutine(result):
|
||||
return
|
||||
|
|
|
|||
|
|
@ -997,5 +997,45 @@ def test_shipped_claude_thinking_rules_backfill_only_anthropic(shipped_cost_map)
|
|||
assert match_fill_missing_generalizations("claude-sonnet-4-6", "anthropic") == {
|
||||
"supports_adaptive_thinking": True,
|
||||
"supports_legacy_thinking": True,
|
||||
"supports_tool_search": True,
|
||||
}
|
||||
assert match_fill_missing_generalizations("claude-sonnet-4-6", "perplexity") is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model,provider,tool_search",
|
||||
[
|
||||
("us.anthropic.claude-opus-4-5", "bedrock", True),
|
||||
("claude-haiku-4-4", "anthropic", None),
|
||||
("claude-haiku-4-6", "anthropic", True),
|
||||
("claude-haiku-4-10", "anthropic", True),
|
||||
("claude-haiku-5-0", "anthropic", True),
|
||||
("claude-sonnet-5-1", "anthropic", True),
|
||||
("claude-newfam-6", "anthropic", True),
|
||||
("claude-haiku-4-20250514", "anthropic", None),
|
||||
],
|
||||
)
|
||||
def test_shipped_tool_search_rule_version_boundaries(shipped_cost_map, model, provider, tool_search):
|
||||
"""The claude-tool-search rule flags Claude 4.5 and newer in any family, bare major
|
||||
or major-minor, and leaves 4.4 and date-suffixed 4.x ids without an opinion."""
|
||||
assert model not in litellm.model_cost
|
||||
info = litellm.get_model_info(model, custom_llm_provider=provider)
|
||||
assert info.get("supports_tool_search") is tool_search, model
|
||||
|
||||
|
||||
def test_shipped_tool_search_rule_fills_mapped_claude_entries_without_flag(shipped_cost_map):
|
||||
"""A mapped Claude 4.5+ entry with no supports_tool_search key gets it from the rule
|
||||
on the Claude providers, a mapped pre-4.5 entry stays without one, and a reseller
|
||||
copy of the same model is not touched."""
|
||||
for key, model, provider in (
|
||||
("claude-opus-4-7", "claude-opus-4-7", "anthropic"),
|
||||
("azure_ai/claude-opus-5", "claude-opus-5", "azure_ai"),
|
||||
):
|
||||
assert "supports_tool_search" not in litellm.model_cost[key]
|
||||
assert litellm.get_model_info(model, custom_llm_provider=provider)["supports_tool_search"] is True
|
||||
|
||||
assert "supports_tool_search" not in litellm.model_cost["claude-opus-4-1"]
|
||||
assert litellm.get_model_info("claude-opus-4-1", custom_llm_provider="anthropic").get("supports_tool_search") is None
|
||||
|
||||
assert match_fill_missing_generalizations("claude-opus-5", "bedrock")["supports_tool_search"] is True
|
||||
assert match_fill_missing_generalizations("claude-opus-5", "perplexity") is None
|
||||
|
|
|
|||
|
|
@ -814,3 +814,48 @@ async def test_bedrock_invoke_claude_async_completion_inlines_document_url_sourc
|
|||
"type": "document",
|
||||
"source": {"type": "base64", "media_type": "application/pdf", "data": async_only_image_fetch.base64_png},
|
||||
} in captured["body"]["messages"][0]["content"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model, expected_betas",
|
||||
[
|
||||
pytest.param("us.anthropic.claude-opus-4-8", ["tool-search-tool-2025-10-19"], id="opus_4_8"),
|
||||
pytest.param("us.anthropic.claude-opus-5", ["tool-search-tool-2025-10-19"], id="opus_5"),
|
||||
pytest.param("us.anthropic.claude-sonnet-5", ["tool-search-tool-2025-10-19"], id="sonnet_5"),
|
||||
pytest.param("us.anthropic.claude-haiku-4-5-20251001-v1:0", ["tool-search-tool-2025-10-19"], id="haiku_4_5"),
|
||||
pytest.param("us.anthropic.claude-opus-4-1-20250805-v1:0", None, id="opus_4_1_unsupported"),
|
||||
],
|
||||
)
|
||||
def test_bedrock_chat_invoke_tool_search_beta_follows_model_map(
|
||||
local_model_cost_map, local_beta_headers_config, model, expected_betas
|
||||
):
|
||||
"""LIT-5851: the chat Invoke path used to add the ``tool-search-tool-2025-10-19``
|
||||
beta whenever the id contained ``opus-4``, so Opus 5 and Sonnet 5 lost it, Haiku
|
||||
4.5 never had it, and Opus 4.1 got it without support. The gate now follows the
|
||||
model map's ``supports_tool_search`` flag, shared with the messages path."""
|
||||
result = AmazonAnthropicClaudeConfig().transform_request(
|
||||
model=model,
|
||||
messages=[{"role": "user", "content": "Add 2 and 3"}],
|
||||
optional_params={
|
||||
"max_tokens": 64,
|
||||
"tools": [
|
||||
{"type": "tool_search_tool_regex_20251119", "name": "tool_search_tool_regex"},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "add_numbers",
|
||||
"description": "Add two integers",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {"a": {"type": "integer"}, "b": {"type": "integer"}},
|
||||
"required": ["a", "b"],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert result.get("anthropic_beta") == expected_betas
|
||||
|
|
|
|||
|
|
@ -2650,17 +2650,6 @@ def test_bedrock_clear_thinking_leaves_enabled_thinking_on_non_adaptive_model():
|
|||
assert "output_config" not in request
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def local_beta_headers_config(monkeypatch):
|
||||
from litellm.anthropic_beta_headers_manager import reload_beta_headers_config
|
||||
|
||||
monkeypatch.setenv("LITELLM_LOCAL_ANTHROPIC_BETA_HEADERS", "True")
|
||||
reload_beta_headers_config()
|
||||
yield
|
||||
monkeypatch.delenv("LITELLM_LOCAL_ANTHROPIC_BETA_HEADERS", raising=False)
|
||||
reload_beta_headers_config()
|
||||
|
||||
|
||||
def test_bedrock_messages_preserves_clear_tool_uses_context_management_and_adds_beta(
|
||||
local_beta_headers_config,
|
||||
):
|
||||
|
|
@ -2826,9 +2815,12 @@ def test_filter_and_transform_beta_headers_passes_context_management_for_bedrock
|
|||
"us.anthropic.claude-haiku-4-5-20251001-v1:0",
|
||||
"us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
"us.anthropic.claude-opus-4-7",
|
||||
"us.anthropic.claude-opus-4-8",
|
||||
"us.anthropic.claude-opus-5",
|
||||
"us.anthropic.claude-sonnet-5",
|
||||
],
|
||||
)
|
||||
def test_bedrock_messages_tool_search_adds_beta_header(local_beta_headers_config, model):
|
||||
def test_bedrock_messages_tool_search_adds_beta_header(local_model_cost_map, local_beta_headers_config, model):
|
||||
"""
|
||||
LIT-4522: Bedrock InvokeModel only admits ``tool_search_tool_*`` tool types
|
||||
when the request body carries the ``tool-search-tool-2025-10-19`` beta;
|
||||
|
|
@ -2838,6 +2830,11 @@ def test_bedrock_messages_tool_search_adds_beta_header(local_beta_headers_config
|
|||
Opus 4.7, so the beta was silently dropped for those models and every
|
||||
tool-search request failed. Verified live 2026-08-11: Bedrock returns 200
|
||||
with ``server_tool_use`` for all three models once the beta is sent.
|
||||
|
||||
LIT-5851: the same allowlist then missed Opus 4.8, Opus 5 and Sonnet 5, so
|
||||
the gate now reads the model map's ``supports_tool_search`` flag (explicit
|
||||
on the Bedrock entries, and the ``claude-tool-search`` rule for Claude 4.5
|
||||
and newer) instead of a per-model name list.
|
||||
"""
|
||||
from litellm.types.router import GenericLiteLLMParams
|
||||
|
||||
|
|
@ -2871,10 +2868,10 @@ def test_bedrock_messages_tool_search_adds_beta_header(local_beta_headers_config
|
|||
|
||||
|
||||
def test_bedrock_messages_tool_search_model_map_flag_is_authoritative(local_model_cost_map, monkeypatch):
|
||||
"""``supports_tool_search`` lives in the model map; the name patterns in
|
||||
``_supports_tool_search_on_bedrock`` are only a fallback for ids the map
|
||||
cannot resolve. Flipping the mapped entry's flag to ``False`` must win even
|
||||
though the model name still matches the ``haiku-4-5`` pattern."""
|
||||
"""``supports_tool_search`` lives in the model map; the ``claude-tool-search``
|
||||
rule only fills entries that carry no opinion. Flipping the mapped entry's
|
||||
flag to ``False`` must win even though the id is a Claude 4.5 the rule
|
||||
would flag."""
|
||||
import litellm
|
||||
from litellm.llms.anthropic.common_utils import AnthropicModelInfo
|
||||
|
||||
|
|
@ -2893,19 +2890,43 @@ def test_bedrock_messages_tool_search_model_map_flag_is_authoritative(local_mode
|
|||
@pytest.mark.parametrize(
|
||||
"model, expected",
|
||||
[
|
||||
pytest.param("us.anthropic.claude-opus-4-6-v99:9", True, id="unmapped_id_falls_back_to_patterns"),
|
||||
pytest.param("anthropic.claude-3-5-sonnet-20240620-v1:0", False, id="mapped_entry_without_flag_no_pattern"),
|
||||
pytest.param("us.anthropic.claude-opus-4-6-v99:9", True, id="unmapped_4_6_variant"),
|
||||
pytest.param("us.anthropic.claude-haiku-5-2", True, id="unmapped_future_minor"),
|
||||
pytest.param(
|
||||
"arn:aws:bedrock:us-east-1:123456789012:inference-profile/us.anthropic.claude-opus-5",
|
||||
True,
|
||||
id="inference_profile_arn",
|
||||
),
|
||||
pytest.param("anthropic.claude-3-5-sonnet-20240620-v1:0", False, id="mapped_claude_3_5_without_flag"),
|
||||
pytest.param("us.anthropic.claude-opus-4-1-20250805-v1:0", False, id="mapped_opus_4_1_without_flag"),
|
||||
pytest.param("us.anthropic.claude-sonnet-4-20250514-v1:0", False, id="mapped_dated_sonnet_4_without_flag"),
|
||||
],
|
||||
)
|
||||
def test_bedrock_messages_tool_search_pattern_fallback(local_model_cost_map, model, expected):
|
||||
"""Ids the model map cannot resolve (or resolves without a
|
||||
``supports_tool_search`` opinion) fall through to the name patterns, so
|
||||
ARNs and unlisted regional variants of supported families keep working."""
|
||||
def test_bedrock_messages_tool_search_follows_claude_tool_search_rule(local_model_cost_map, model, expected):
|
||||
"""Ids the model map cannot resolve, or resolves without a ``supports_tool_search``
|
||||
opinion, take the ``claude-tool-search`` fallback rule: Claude 4.5 and newer get
|
||||
the beta, ARNs and unlisted regional variants included, and older Claudes do not."""
|
||||
cfg = AmazonAnthropicClaudeMessagesConfig()
|
||||
|
||||
assert cfg._supports_tool_search_on_bedrock(model) is expected
|
||||
|
||||
|
||||
def test_bedrock_messages_tool_search_rule_fills_mapped_entry_without_flag(local_model_cost_map, monkeypatch):
|
||||
"""LIT-5851: a Bedrock entry that is in the map but carries no ``supports_tool_search``
|
||||
key, the state Opus 4.8, Opus 5 and Sonnet 5 shipped in, is filled by the
|
||||
``claude-tool-search`` rule instead of resolving to ``None`` and losing the beta."""
|
||||
import litellm
|
||||
|
||||
model = "us.anthropic.claude-opus-5"
|
||||
cfg = AmazonAnthropicClaudeMessagesConfig()
|
||||
|
||||
monkeypatch.delitem(litellm.model_cost[model], "supports_tool_search")
|
||||
litellm.get_model_info.cache_clear()
|
||||
|
||||
assert litellm.get_model_info(model, custom_llm_provider="bedrock")["supports_tool_search"] is True
|
||||
assert cfg._supports_tool_search_on_bedrock(model) is True
|
||||
|
||||
|
||||
def test_bedrock_messages_thinking_shape_follows_exact_bedrock_entry_flag(
|
||||
local_model_cost_map, monkeypatch
|
||||
):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue