This commit is contained in:
Apeksha_2022 2026-11-05 19:45:23 +00:00 • committed by GitHub
commit 01bb71be01
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 49 additions and 5 deletions

View file

@ -35,7 +35,6 @@ from litellm.litellm_core_utils.core_helpers import (
filter_exceptions_from_params,
filter_internal_params,
map_finish_reason,
safe_deep_copy,
)
from litellm.litellm_core_utils.litellm_logging import Logging
from litellm.litellm_core_utils.prompt_templates.common_utils import (
@ -1823,10 +1822,13 @@ class AmazonConverseConfig(BaseConfig):
# ``_handle_reasoning_effort_parameter`` so it does not linger on the
# caller's ``optional_params`` after the transformation returns.
anthropic_output_config_already_normalized = bool(optional_params.pop("_output_config_normalized", False))
# Filter out exception objects before deepcopy to prevent deepcopy failures
# Exceptions should not be stored in optional_params (this is a defensive fix)
cleaned_params: Final = filter_exceptions_from_params(optional_params)
inference_params = safe_deep_copy(cleaned_params)
# Filter out exception objects (they should not be stored in optional_params; this is a
# defensive fix). The filter rebuilds every dict and list, so its result is already
# independent of the caller's params: deep-copying it again only doubles the allocation,
# which for large tool lists triggers long garbage-collection pauses on the event loop.
inference_params: dict = filter_exceptions_from_params( # pyright: ignore[reportMissingTypeArgument] # mutable-ok: popped and split below, untyped like the deep copy it replaces
optional_params
)
supported_converse_params: Final = list(AmazonConverseConfig.__annotations__.keys()) + ["top_k"]
supported_tool_call_params: Final = ["tools", "tool_choice"]
supported_config_params: Final = list(self.get_config_blocks().keys())

View file

@ -426,6 +426,48 @@ def test_bedrock_empty_text_block_is_removed_from_converse_request() -> None:
assert request["messages"] == [{"role": "user", "content": [{"text": "Hey, how's it going?"}]}]
class _DeepCopyCountingStr(str):
deep_copies = 0
def __deepcopy__(self, memo: dict) -> "_DeepCopyCountingStr":
type(self).deep_copies += 1
return self
def test_bedrock_converse_request_copies_params_once() -> None:
description: Final = _DeepCopyCountingStr("City to look up")
tools: Final = [
{
"type": "function",
"function": {
"name": "get_weather",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string", "description": description}},
"required": ["city"],
},
},
}
]
snapshot: Final = copy.deepcopy(tools)
_DeepCopyCountingStr.deep_copies = 0
request: Final = AmazonConverseConfig()._transform_request(
model="us.anthropic.claude-sonnet-4-5-20250929-v1:0",
messages=[{"role": "user", "content": "Weather in Paris?"}],
optional_params={"maxTokens": 10, "tools": tools},
litellm_params={},
headers={},
)
# one copy, by the tool converter that edits the schema; none for the params as a whole
assert _DeepCopyCountingStr.deep_copies == 1
tool_spec: Final = request["toolConfig"]["tools"][0]["toolSpec"]
assert tool_spec["name"] == "get_weather"
assert tool_spec["inputSchema"]["json"]["properties"]["city"]["description"] == "City to look up"
assert tools == snapshot
@pytest.mark.asyncio
async def test_bedrock_max_completion_tokens_become_converse_max_tokens() -> None:
requests: Final[list[httpx.Request]] = []