mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-13 08:52:02 +00:00
fix(responses): forward only message cache points through the bridge on native-config routes
Routes with their own Responses config keep only chat completion request fields on the way into the bridge. Forwarding every injection point there let a tool_config point reach the provider body through the generic unknown-param copy, where no transformation reads it. Forward only the location: message points the bridge's second pass places.
This commit is contained in:
parent
8af15814f1
commit
008e91a5c6
3 changed files with 22 additions and 8 deletions
|
|
@ -100,7 +100,6 @@ from litellm.types.utils import (
|
|||
all_litellm_params,
|
||||
)
|
||||
from litellm.utils import (
|
||||
LITELLM_ONLY_PARAMS,
|
||||
ProviderConfigManager,
|
||||
client,
|
||||
)
|
||||
|
|
@ -644,12 +643,20 @@ def _chat_completion_request_fields(allowed_openai_params: Sequence[str] | None)
|
|||
*DEFAULT_CHAT_COMPLETION_PARAM_VALUES,
|
||||
*all_litellm_params,
|
||||
*GenericLiteLLMParams.model_fields,
|
||||
*LITELLM_ONLY_PARAMS,
|
||||
*(allowed_openai_params or ()),
|
||||
)
|
||||
).difference(_RESPONSES_ONLY_REQUEST_FIELDS_NEVER_BRIDGED)
|
||||
|
||||
|
||||
def _message_cache_control_points(kwargs: Mapping[str, object]) -> Mapping[str, object]:
|
||||
points: Final = tuple(
|
||||
point
|
||||
for point in configured_injection_points(kwargs.get("cache_control_injection_points"))
|
||||
if point.get("location") == "message"
|
||||
)
|
||||
return {"cache_control_injection_points": points} if points else {}
|
||||
|
||||
|
||||
_ADDITIONAL_DROP_PARAMS: Final = TypeAdapter(list[str])
|
||||
|
||||
|
||||
|
|
@ -667,7 +674,12 @@ def _bridge_kwargs(
|
|||
) -> Mapping[str, object] | _UntranslatableResponsesFields:
|
||||
forwarded_keys: Final = _chat_completion_request_fields(allowed_openai_params)
|
||||
if responses_api_provider_config is not None:
|
||||
return MappingProxyType({key: value for key, value in kwargs.items() if key in forwarded_keys})
|
||||
return MappingProxyType(
|
||||
{
|
||||
**{key: value for key, value in kwargs.items() if key in forwarded_keys},
|
||||
**_message_cache_control_points(kwargs),
|
||||
}
|
||||
)
|
||||
candidate_keys: Final = _RESPONSES_REQUEST_FIELDS.difference(forwarded_keys, _explicitly_dropped_fields(kwargs))
|
||||
untranslatable: Final = tuple(sorted(key for key in candidate_keys if kwargs.get(key) is not None))
|
||||
if untranslatable and not drops_unsupported_params(kwargs.get("drop_params")):
|
||||
|
|
|
|||
|
|
@ -412,17 +412,18 @@ class TestUseResponsesApiBridgeFlag:
|
|||
{"type": "function_call_output", "call_id": "call_a", "output": "contents of a"},
|
||||
],
|
||||
use_chat_completions_api=True,
|
||||
cache_control_injection_points=[{"location": "message", "index": -1}],
|
||||
cache_control_injection_points=[{"location": "tool_config"}, {"location": "message", "index": -1}],
|
||||
api_key="fake-provider-api-key",
|
||||
num_retries=0,
|
||||
)
|
||||
|
||||
sent_messages: Final = json.loads(upstream.calls[0].request.read())["messages"]
|
||||
sent_body: Final = json.loads(upstream.calls[0].request.read())
|
||||
assert [
|
||||
message.get("tool_call_id") or message["role"]
|
||||
for message in sent_messages
|
||||
for message in sent_body["messages"]
|
||||
if "cache_control" in json.dumps(message)
|
||||
] == ["call_a"]
|
||||
assert "cache_control_injection_points" not in sent_body
|
||||
|
||||
def test_bridge_keeps_deployment_credentials_while_dropping_unknown_params(self, respx_mock: respx.MockRouter):
|
||||
upstream: Final = respx_mock.post(
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ from pydantic import TypeAdapter
|
|||
|
||||
import litellm
|
||||
from litellm._logging import verbose_logger
|
||||
from litellm.integrations.anthropic_cache_control_hook import MAX_CACHE_CONTROL_BLOCKS
|
||||
from litellm.llms.custom_httpx.http_handler import AsyncHTTPHandler, HTTPHandler
|
||||
from litellm.types.llms.openai import ResponsesAPIResponse
|
||||
from tests.unit.llms.bedrock.slow_upstream import (
|
||||
|
|
@ -1208,11 +1209,11 @@ async def test_the_ordinal_point_listed_first_takes_the_last_breakpoint_slot(ind
|
|||
tools=[
|
||||
{
|
||||
"type": "function",
|
||||
"name": name,
|
||||
"name": f"t{i}",
|
||||
"parameters": {"type": "object", "properties": {}},
|
||||
"cache_control": {"type": "ephemeral"},
|
||||
}
|
||||
for name in ("t0", "t1", "t2")
|
||||
for i in range(MAX_CACHE_CONTROL_BLOCKS - 1)
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue