From ea1c0d464efd19cde604e1461f9efee7cb2dff49 Mon Sep 17 00:00:00 2001 From: jquinter Date: Sat, 31 Jan 2026 20:09:32 -0300 Subject: [PATCH] Fix Nova grounding web_search_options={} not applying systemTool (#20044) * Fix Nova grounding web_search_options={} not applying systemTool Two bugs prevented web_search_options={} from working for Nova grounding: 1. Empty dict falsy check: The condition `value and isinstance(value, dict)` short-circuits to False when value is {} (empty dict is falsy in Python). Changed to `isinstance(value, dict)` to match Anthropic's implementation. 2. Pre-formatted tools mangled by _bedrock_tools_pt: The systemTool (already in Bedrock format) was added to optional_params["tools"], but _process_tools_and_beta passed all tools through _bedrock_tools_pt which expects OpenAI-format tools. This corrupted the systemTool into an empty toolSpec. Fixed by separating systemTool blocks before transformation and appending them after. Fixes follow-up to #19598 Co-Authored-By: Claude Opus 4.5 * Fix python-multipart Python version constraint for Poetry lock python-multipart ^0.0.22 requires Python >=3.10 but the project supports >=3.9. Add python = ">=3.10" marker so Poetry can resolve dependencies for Python 3.9. Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: Claude Opus 4.5 --- .../bedrock/chat/converse_transformation.py | 13 ++++++++-- poetry.lock | 26 ++++++++++++++++--- pyproject.toml | 2 +- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/litellm/llms/bedrock/chat/converse_transformation.py b/litellm/llms/bedrock/chat/converse_transformation.py index 0d29c1f01aa..e701454f45c 100644 --- a/litellm/llms/bedrock/chat/converse_transformation.py +++ b/litellm/llms/bedrock/chat/converse_transformation.py @@ -805,7 +805,7 @@ class AmazonConverseConfig(BaseConfig): if bedrock_tier in ("default", "flex", "priority"): optional_params["serviceTier"] = {"type": bedrock_tier} - if param == "web_search_options" and value and isinstance(value, dict): + if param == "web_search_options" and isinstance(value, dict): grounding_tool = self._map_web_search_options(value, model) if grounding_tool is not None: optional_params = self._add_tools_to_optional_params( @@ -1079,10 +1079,16 @@ class AmazonConverseConfig(BaseConfig): user_betas = get_anthropic_beta_from_headers(headers) anthropic_beta_list.extend(user_betas) - # Filter out tool search tools - Bedrock Converse API doesn't support them + # Separate pre-formatted Bedrock tools (e.g. systemTool from web_search_options) + # from OpenAI-format tools that need transformation via _bedrock_tools_pt filtered_tools = [] + pre_formatted_tools: List[ToolBlock] = [] if original_tools: for tool in original_tools: + # Already-formatted Bedrock tools (e.g. systemTool for Nova grounding) + if "systemTool" in tool: + pre_formatted_tools.append(tool) + continue tool_type = tool.get("type", "") if tool_type in ( "tool_search_tool_regex_20251119", @@ -1114,6 +1120,9 @@ class AmazonConverseConfig(BaseConfig): # No computer use tools, process all tools as regular tools bedrock_tools = _bedrock_tools_pt(filtered_tools) + # Append pre-formatted tools (systemTool etc.) after transformation + bedrock_tools.extend(pre_formatted_tools) + # Set anthropic_beta in additional_request_params if we have any beta features # ONLY apply to Anthropic/Claude models - other models (e.g., Qwen, Llama) don't support this field # and will error with "unknown variant anthropic_beta" if included diff --git a/poetry.lock b/poetry.lock index 9ded0c773c8..9d528366e83 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.2.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. [[package]] name = "a2a-sdk" @@ -5686,6 +5686,24 @@ pytest = ">=6.2.5" [package.extras] dev = ["pre-commit", "pytest-asyncio", "tox"] +[[package]] +name = "pytest-retry" +version = "1.7.0" +description = "Adds the ability to retry flaky tests in CI environments" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest_retry-1.7.0-py3-none-any.whl", hash = "sha256:a2dac85b79a4e2375943f1429479c65beb6c69553e7dae6b8332be47a60954f4"}, + {file = "pytest_retry-1.7.0.tar.gz", hash = "sha256:f8d52339f01e949df47c11ba9ee8d5b362f5824dff580d3870ec9ae0057df80f"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[package.extras] +dev = ["black", "flake8", "isort", "mypy"] + [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -5722,9 +5740,9 @@ name = "python-multipart" version = "0.0.22" description = "A streaming multipart parser for Python" optional = true -python-versions = ">=3.8" +python-versions = ">=3.10" groups = ["main"] -markers = "extra == \"proxy\"" +markers = "python_version >= \"3.10\" and extra == \"proxy\"" files = [ {file = "python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155"}, {file = "python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58"}, @@ -8472,4 +8490,4 @@ utils = ["numpydoc"] [metadata] lock-version = "2.1" python-versions = ">=3.9,<4.0" -content-hash = "73b5e1ab0badbee6c564d5e056e4f9c320c2f722bf176ce97d42e77110e37d60" +content-hash = "19a339dd5b4c21a06f7b725361a2e2692c05c56fa47e71513c5712dbdec7f61d" diff --git a/pyproject.toml b/pyproject.toml index 6c3ab08ce02..f2eee212394 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,7 @@ orjson = {version = "^3.9.7", optional = true} apscheduler = {version = "^3.10.4", optional = true} fastapi-sso = { version = "^0.16.0", optional = true } PyJWT = { version = "^2.10.1", optional = true, python = ">=3.9" } -python-multipart = { version = "^0.0.22", optional = true} +python-multipart = { version = "^0.0.22", optional = true, python = ">=3.10"} cryptography = {version = "*", optional = true} prisma = {version = "0.11.0", optional = true} azure-identity = {version = "^1.15.0", optional = true, python = ">=3.9"}