Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion litellm/llms/bedrock_mantle/responses/transformation.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@
)

# Per Bedrock Mantle Responses API validation errors.
_BEDROCK_MANTLE_SUPPORTED_RESPONSE_TOOL_TYPES = frozenset({"function", "mcp", "custom", "namespace", "tool_search"})
_BEDROCK_MANTLE_SUPPORTED_RESPONSE_TOOL_TYPES: Final = frozenset(
{"function", "mcp", "custom", "namespace", "tool_search", "web_search"}
)
Comment on lines +47 to +49

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.

P1 Web search bypasses model capability

When a Responses-capable Mantle model outside the five flagged GPT models receives a web_search tool, this provider-wide allowlist forwards it without checking supports_web_search, causing Mantle to reject the unsupported request instead of filtering the tool.

Rule Used: What: Do not hardcode model-specific flags in the ... (source)

Knowledge Base Used: LLM Provider Adapters

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Tried that: the remote cost map lags releases, so gating on supports_web_search silently disabled Web Search live. Mantle itself 400s with "Tool type 'web_search' is not supported for model".

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.

That's a fair point. The failure mode split here is:

  • Gating on supports_web_search: cost-map lag silently drops web_search on newly-supported models until the JSON is updated — same broken-but-quiet behavior as before this PR.
  • Allowlist approach (this PR): unsupported Mantle models get an explicit 400 from the server, which is noisier but honest.

A server-side 400 is strictly better UX than an ungrounded answer with no error, so the trade-off is reasonable.

I withdraw the concern.


_BEDROCK_MANTLE_SUPPORTED_SERVICE_TIERS: Final = frozenset({"auto", "default"})

Expand Down
15 changes: 10 additions & 5 deletions litellm/model_prices_and_context_window_backup.json
Original file line number Diff line number Diff line change
Expand Up @@ -45247,7 +45247,8 @@
"supports_reasoning": true,
"supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
"supports_vision": true,
"supports_web_search": true
},
"bedrock_mantle/openai.gpt-5.6-terra": {
"input_cost_per_token": 2.2e-06,
Expand Down Expand Up @@ -45275,7 +45276,8 @@
"supports_reasoning": true,
"supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
"supports_vision": true,
"supports_web_search": true
},
"bedrock_mantle/openai.gpt-5.6-luna": {
"input_cost_per_token": 2.2e-07,
Expand Down Expand Up @@ -45303,7 +45305,8 @@
"supports_reasoning": true,
"supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
"supports_vision": true,
"supports_web_search": true
},
"bedrock_mantle/openai.gpt-5.5": {
"input_cost_per_token": 5.5e-06,
Expand All @@ -45330,7 +45333,8 @@
"supports_reasoning": true,
"supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
"supports_vision": true,
"supports_web_search": true
},
"bedrock_mantle/openai.gpt-5.4": {
"input_cost_per_token": 2.75e-06,
Expand All @@ -45357,7 +45361,8 @@
"supports_reasoning": true,
"supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
"supports_vision": true,
"supports_web_search": true
},
"bedrock_mantle/google.gemma-4-31b": {
"input_cost_per_token": 1.4e-07,
Expand Down
15 changes: 10 additions & 5 deletions model_prices_and_context_window.json
Original file line number Diff line number Diff line change
Expand Up @@ -45368,7 +45368,8 @@
"supports_reasoning": true,
"supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
"supports_vision": true,
"supports_web_search": true
},
"bedrock_mantle/openai.gpt-5.6-terra": {
"input_cost_per_token": 2.2e-06,
Expand Down Expand Up @@ -45396,7 +45397,8 @@
"supports_reasoning": true,
"supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
"supports_vision": true,
"supports_web_search": true
},
"bedrock_mantle/openai.gpt-5.6-luna": {
"input_cost_per_token": 2.2e-07,
Expand Down Expand Up @@ -45424,7 +45426,8 @@
"supports_reasoning": true,
"supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
"supports_vision": true,
"supports_web_search": true
},
"bedrock_mantle/openai.gpt-5.5": {
"input_cost_per_token": 5.5e-06,
Expand All @@ -45451,7 +45454,8 @@
"supports_reasoning": true,
"supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
"supports_vision": true,
"supports_web_search": true
},
"bedrock_mantle/openai.gpt-5.4": {
"input_cost_per_token": 2.75e-06,
Expand All @@ -45478,7 +45482,8 @@
"supports_reasoning": true,
"supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
"supports_vision": true,
"supports_web_search": true
},
"bedrock_mantle/google.gemma-4-31b": {
"input_cost_per_token": 1.4e-07,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ def test_map_openai_params_drops_unsupported_tools(self):
params = cfg.map_openai_params(
response_api_optional_params={
"tools": [
{"type": "web_search"},
{"type": "file_search", "vector_store_ids": ["vs_123"]},
{"type": "function", "name": "exec_command"},
]
},
Expand All @@ -351,7 +351,7 @@ def test_map_openai_params_drops_unsupported_tools(self):
def test_map_openai_params_removes_tools_when_all_unsupported(self):
cfg = BedrockMantleResponsesAPIConfig()
params = cfg.map_openai_params(
response_api_optional_params={"tools": [{"type": "web_search"}]},
response_api_optional_params={"tools": [{"type": "file_search", "vector_store_ids": ["vs_123"]}]},
model="openai.gpt-5.5",
drop_params=False,
)
Expand All @@ -365,12 +365,86 @@ def test_dropped_tools_are_logged_at_warning_level(self):
"litellm.llms.bedrock_mantle.responses.transformation.verbose_logger.warning"
) as mock_warning:
cfg.map_openai_params(
response_api_optional_params={"tools": [{"type": "web_search"}]},
response_api_optional_params={"tools": [{"type": "file_search", "vector_store_ids": ["vs_123"]}]},
model="openai.gpt-5.5",
drop_params=False,
)
assert mock_warning.call_count == 1
assert "web_search" in str(mock_warning.call_args)
assert "file_search" in str(mock_warning.call_args)


class TestBedrockMantleResponsesWebSearch:
"""Web Search on Amazon Bedrock is a server-side built-in tool that Mantle runs
itself when the caller passes {"type": "web_search"} on the Responses path, so
the config must forward the tool and its options untouched instead of filtering
it out and returning an ungrounded answer."""

_WEB_SEARCH_TOOL = {"type": "web_search", "external_web_access": False}

def test_web_search_survives_map_openai_params_with_its_options(self):
cfg = BedrockMantleResponsesAPIConfig()
params = cfg.map_openai_params(
response_api_optional_params={"tools": [self._WEB_SEARCH_TOOL]},
model="openai.gpt-5.6-sol",
drop_params=False,
)
assert params["tools"] == [self._WEB_SEARCH_TOOL]

def test_web_search_reaches_outbound_body_alongside_function_tools(self):
cfg = BedrockMantleResponsesAPIConfig()
function_tool = {"type": "function", "name": "exec_command"}
params = cfg.map_openai_params(
response_api_optional_params={"tools": [self._WEB_SEARCH_TOOL, function_tool]},
model="openai.gpt-5.6-sol",
drop_params=False,
)
body = cfg.transform_responses_api_request(
model="openai.gpt-5.6-sol",
input="What did AWS announce today?",
response_api_optional_request_params=params,
litellm_params=GenericLiteLLMParams(),
headers={},
)
assert body["tools"] == [self._WEB_SEARCH_TOOL, function_tool]

def test_web_search_is_not_logged_as_dropped(self):
from unittest.mock import patch

cfg = BedrockMantleResponsesAPIConfig()
with patch("litellm.llms.bedrock_mantle.responses.transformation.verbose_logger.warning") as mock_warning:
cfg.map_openai_params(
response_api_optional_params={"tools": [self._WEB_SEARCH_TOOL]},
model="openai.gpt-5.6-sol",
drop_params=False,
)
assert mock_warning.call_count == 0

def test_hoisted_web_search_tool_survives(self):
cfg = BedrockMantleResponsesAPIConfig()
body = cfg.transform_responses_api_request(
model="openai.gpt-5.6-sol",
input=[
{"type": "additional_tools", "role": "developer", "tools": [self._WEB_SEARCH_TOOL]},
{"type": "message", "role": "user", "content": [{"type": "input_text", "text": "hi"}]},
],
response_api_optional_request_params={},
litellm_params=GenericLiteLLMParams(),
headers={},
)
assert body["tools"] == [self._WEB_SEARCH_TOOL]

@pytest.mark.parametrize(
"model",
[
"bedrock_mantle/openai.gpt-5.6-sol",
"bedrock_mantle/openai.gpt-5.6-terra",
"bedrock_mantle/openai.gpt-5.6-luna",
"bedrock_mantle/openai.gpt-5.5",
"bedrock_mantle/openai.gpt-5.4",
],
)
def test_cost_map_advertises_web_search_support(self, model):
assert litellm.supports_web_search(model=model) is True


def _codex_exec_tool():
Expand Down Expand Up @@ -558,7 +632,7 @@ def test_unsupported_hoisted_tool_types_are_dropped(self):
"type": "additional_tools",
"role": "developer",
"tools": [
{"type": "web_search"},
{"type": "file_search", "vector_store_ids": ["vs_123"]},
{"type": "function", "name": "wait"},
],
},
Expand All @@ -570,7 +644,11 @@ def test_unsupported_hoisted_tool_types_are_dropped(self):
def test_item_stripped_even_when_no_hoisted_tool_survives(self):
body = self._transform(
input=[
{"type": "additional_tools", "role": "developer", "tools": [{"type": "web_search"}]},
{
"type": "additional_tools",
"role": "developer",
"tools": [{"type": "file_search", "vector_store_ids": ["vs_123"]}],
},
self._USER_MESSAGE,
]
)
Expand Down
Loading