mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-17 23:51:30 +00:00
Merge pull request #41144 from BerriAI/litellm_responses_bridge_filters_unknown_params
fix(responses): filter bridged kwargs like the native Responses path
This commit is contained in:
commit
41b5d47c71
2 changed files with 134 additions and 3 deletions
|
|
@ -1,9 +1,10 @@
|
|||
import asyncio
|
||||
import contextvars
|
||||
from collections.abc import Coroutine, Generator, Iterable, Mapping
|
||||
from collections.abc import Coroutine, Generator, Iterable, Mapping, Sequence
|
||||
from contextlib import contextmanager
|
||||
from dataclasses import dataclass
|
||||
from functools import partial
|
||||
from types import MappingProxyType
|
||||
from typing import TYPE_CHECKING, Any, Final, Literal, NoReturn, Optional, TypeAlias, cast
|
||||
|
||||
import httpx
|
||||
|
|
@ -15,7 +16,7 @@ from litellm._logging import verbose_logger
|
|||
from litellm.completion_extras.litellm_responses_transformation.transformation import (
|
||||
LiteLLMResponsesTransformationHandler,
|
||||
)
|
||||
from litellm.constants import request_timeout
|
||||
from litellm.constants import DEFAULT_CHAT_COMPLETION_PARAM_VALUES, request_timeout
|
||||
from litellm.integrations.anthropic_cache_control_hook import CARRY_UNMATCHED_MESSAGE_POINTS
|
||||
from litellm.litellm_core_utils.asyncify import run_async_function
|
||||
from litellm.litellm_core_utils.core_helpers import normalize_drop_params
|
||||
|
|
@ -52,6 +53,7 @@ from litellm.llms.openai.data_residency import infer_openai_data_residency
|
|||
from litellm.secret_managers.main import get_secret_str
|
||||
from litellm.types.responses.main import *
|
||||
from litellm.types.router import GenericLiteLLMParams
|
||||
from litellm.types.utils import all_litellm_params
|
||||
from litellm.utils import (
|
||||
ProviderConfigManager,
|
||||
client,
|
||||
|
|
@ -408,6 +410,25 @@ def _bridges_to_chat_completions(
|
|||
return responses_api_provider_config is None or use_chat_completions_api is True
|
||||
|
||||
|
||||
def _bridge_kwargs(
|
||||
kwargs: Mapping[str, object],
|
||||
responses_api_provider_config: BaseResponsesAPIConfig | None,
|
||||
allowed_openai_params: Sequence[str] | None,
|
||||
) -> Mapping[str, object]:
|
||||
if responses_api_provider_config is None:
|
||||
return kwargs
|
||||
forwarded_keys: Final = frozenset(
|
||||
(
|
||||
*litellm.OPENAI_CHAT_COMPLETION_PARAMS,
|
||||
*DEFAULT_CHAT_COMPLETION_PARAM_VALUES,
|
||||
*all_litellm_params,
|
||||
*GenericLiteLLMParams.model_fields,
|
||||
*(allowed_openai_params or ()),
|
||||
)
|
||||
)
|
||||
return MappingProxyType({key: value for key, value in kwargs.items() if key in forwarded_keys})
|
||||
|
||||
|
||||
_ResponsesCompatibilityFailure: TypeAlias = Literal["encrypted_task_unsupported"]
|
||||
|
||||
|
||||
|
|
@ -1281,6 +1302,7 @@ def responses(
|
|||
return _file_search_dispatch
|
||||
|
||||
if _bridges_to_chat_completions(responses_api_provider_config, use_chat_completions_api):
|
||||
bridge_kwargs: Final = _bridge_kwargs(kwargs, responses_api_provider_config, allowed_openai_params)
|
||||
return litellm_completion_transformation_handler.response_api_handler(
|
||||
model=model,
|
||||
input=input,
|
||||
|
|
@ -1292,7 +1314,7 @@ def responses(
|
|||
extra_body=extra_body,
|
||||
timeout=timeout if timeout is not None else request_timeout,
|
||||
allowed_openai_params=allowed_openai_params,
|
||||
**kwargs,
|
||||
**bridge_kwargs,
|
||||
)
|
||||
|
||||
# Get optional parameters for the responses API
|
||||
|
|
|
|||
|
|
@ -6,12 +6,14 @@ Includes file_search emulation: the flag must be forwarded on inner aresponses
|
|||
calls so routed requests do not hit a custom api_base /v1/responses endpoint.
|
||||
"""
|
||||
|
||||
import json
|
||||
from importlib import import_module
|
||||
from typing import Final
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
import respx
|
||||
|
||||
import litellm
|
||||
from litellm.llms.custom_httpx.http_handler import HTTPHandler
|
||||
|
|
@ -189,6 +191,113 @@ class TestUseResponsesApiBridgeFlag:
|
|||
"reasoning_effort"
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("model", "upstream_url", "use_chat_completions_api", "allowed_openai_params", "expected_chat_template_kwargs"),
|
||||
[
|
||||
pytest.param(
|
||||
"openai/my-custom-model",
|
||||
"https://api.openai.com/v1/chat/completions",
|
||||
True,
|
||||
None,
|
||||
None,
|
||||
id="native-config-drops-unknown-param",
|
||||
),
|
||||
pytest.param(
|
||||
"openai/my-custom-model",
|
||||
"https://api.openai.com/v1/chat/completions",
|
||||
True,
|
||||
["chat_template_kwargs"],
|
||||
{"thinking": True},
|
||||
id="native-config-keeps-allowed-param",
|
||||
),
|
||||
pytest.param(
|
||||
"together_ai/my-custom-model",
|
||||
"https://api.together.ai/v1/chat/completions",
|
||||
False,
|
||||
None,
|
||||
{"thinking": True},
|
||||
id="no-native-config-keeps-passthrough",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_bridge_forwards_same_params_as_native_dispatch(
|
||||
self,
|
||||
model: str,
|
||||
upstream_url: str,
|
||||
use_chat_completions_api: bool,
|
||||
allowed_openai_params: list[str] | None,
|
||||
expected_chat_template_kwargs: dict[str, bool] | None,
|
||||
respx_mock: respx.MockRouter,
|
||||
):
|
||||
upstream: Final = respx_mock.post(upstream_url).mock(
|
||||
return_value=httpx.Response(
|
||||
status_code=200,
|
||||
json={
|
||||
"id": "chatcmpl-123",
|
||||
"object": "chat.completion",
|
||||
"created": 1677652288,
|
||||
"model": "my-custom-model",
|
||||
"choices": [
|
||||
{"index": 0, "message": {"role": "assistant", "content": "Answer"}, "finish_reason": "stop"}
|
||||
],
|
||||
"usage": {"prompt_tokens": 9, "completion_tokens": 1, "total_tokens": 10},
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
response: Final = litellm.responses(
|
||||
model=model,
|
||||
input="Hello",
|
||||
use_chat_completions_api=use_chat_completions_api,
|
||||
allowed_openai_params=allowed_openai_params,
|
||||
chat_template_kwargs={"thinking": True},
|
||||
drop_params=True,
|
||||
api_key="fake-provider-api-key",
|
||||
num_retries=0,
|
||||
)
|
||||
|
||||
assert upstream.call_count == 1
|
||||
request_body: Final = json.loads(upstream.calls[0].request.read())
|
||||
assert request_body.get("chat_template_kwargs") == expected_chat_template_kwargs
|
||||
assert request_body["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert response.output[0].content[0].text == "Answer"
|
||||
|
||||
def test_bridge_keeps_deployment_credentials_while_dropping_unknown_params(self, respx_mock: respx.MockRouter):
|
||||
upstream: Final = respx_mock.post(
|
||||
"https://example-resource.openai.azure.com/openai/deployments/my-deployment/chat/completions",
|
||||
params={"api-version": "2024-10-21"},
|
||||
).mock(
|
||||
return_value=httpx.Response(
|
||||
status_code=200,
|
||||
json={
|
||||
"id": "chatcmpl-123",
|
||||
"object": "chat.completion",
|
||||
"created": 1677652288,
|
||||
"model": "my-deployment",
|
||||
"choices": [
|
||||
{"index": 0, "message": {"role": "assistant", "content": "Answer"}, "finish_reason": "stop"}
|
||||
],
|
||||
"usage": {"prompt_tokens": 9, "completion_tokens": 1, "total_tokens": 10},
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
litellm.responses(
|
||||
model="azure/my-deployment",
|
||||
input="Hello",
|
||||
use_chat_completions_api=True,
|
||||
api_base="https://example-resource.openai.azure.com",
|
||||
api_version="2024-10-21",
|
||||
azure_ad_token="fake-azure-ad-token",
|
||||
chat_template_kwargs={"thinking": True},
|
||||
num_retries=0,
|
||||
)
|
||||
|
||||
assert upstream.call_count == 1
|
||||
request: Final = upstream.calls[0].request
|
||||
assert request.headers["authorization"] == "Bearer fake-azure-ad-token"
|
||||
assert "chat_template_kwargs" not in json.loads(request.read())
|
||||
|
||||
@patch.object(import_module("litellm.responses.file_search.emulated_handler"), "_call_aresponses")
|
||||
@patch.object(
|
||||
import_module("litellm.responses.main").ProviderConfigManager, "get_provider_responses_api_config"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue