mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-01 02:02:20 +00:00
fix(responses): filter out non-litellm kwargs in Responses API completion bridge
When the Responses API bridge forwards requests to litellm.completion(), it merges all **kwargs into the completion args. Client-specific params like `client_metadata` (sent by the OpenAI SDK) are not valid litellm.completion() arguments and cause 'unexpected keyword argument' errors at the provider SDK level. Filter kwargs to only pass litellm-internal params (prefixed with `litellm_`) to the completion/acompletion calls. Fixes #28539
This commit is contained in:
parent
b0b25ae4b9
commit
e3261e8601
2 changed files with 77 additions and 2 deletions
|
|
@ -20,6 +20,18 @@ from litellm.types.llms.openai import (
|
|||
from litellm.types.utils import ModelResponse
|
||||
|
||||
|
||||
def _filter_kwargs_for_completion(kwargs: dict) -> dict:
|
||||
"""
|
||||
Filter kwargs to only include litellm-internal params that are safe to pass
|
||||
to litellm.completion() / litellm.acompletion().
|
||||
|
||||
Responses API requests may contain client-specific params (e.g. client_metadata)
|
||||
that are NOT valid litellm.completion() arguments. Passing them through causes
|
||||
'unexpected keyword argument' errors at the provider SDK level.
|
||||
"""
|
||||
return {k: v for k, v in kwargs.items() if k.startswith("litellm_")}
|
||||
|
||||
|
||||
class LiteLLMCompletionTransformationHandler:
|
||||
def response_api_handler(
|
||||
self,
|
||||
|
|
@ -59,7 +71,7 @@ class LiteLLMCompletionTransformationHandler:
|
|||
)
|
||||
|
||||
completion_args = {}
|
||||
completion_args.update(kwargs)
|
||||
completion_args.update(_filter_kwargs_for_completion(kwargs))
|
||||
completion_args.update(litellm_completion_request)
|
||||
|
||||
litellm_completion_response: Union[
|
||||
|
|
@ -109,7 +121,7 @@ class LiteLLMCompletionTransformationHandler:
|
|||
)
|
||||
|
||||
acompletion_args = {}
|
||||
acompletion_args.update(kwargs)
|
||||
acompletion_args.update(_filter_kwargs_for_completion(kwargs))
|
||||
acompletion_args.update(litellm_completion_request)
|
||||
|
||||
litellm_completion_response: Union[
|
||||
|
|
|
|||
63
tests/test_litellm/test_responses_api_client_metadata.py
Normal file
63
tests/test_litellm/test_responses_api_client_metadata.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
"""
|
||||
Unit tests for fix #28539: client_metadata should NOT be forwarded from
|
||||
Responses API bridge to litellm.completion()/acompletion().
|
||||
|
||||
The Responses API handler merges **kwargs into the completion args dict.
|
||||
When a client sends client_metadata (an OpenAI Responses API param), it flows
|
||||
through kwargs and causes 'unexpected keyword argument' errors at the provider
|
||||
SDK level. The fix filters kwargs to only pass litellm-internal params
|
||||
(prefixed with 'litellm_').
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from litellm.responses.litellm_completion_transformation.handler import (
|
||||
_filter_kwargs_for_completion,
|
||||
)
|
||||
|
||||
|
||||
class TestFilterKwargsForCompletion:
|
||||
"""Verify _filter_kwargs_for_completion strips non-litellm kwargs."""
|
||||
|
||||
def test_strips_client_metadata(self):
|
||||
"""client_metadata from the Responses API must not pass through."""
|
||||
kwargs = {
|
||||
"litellm_logging_obj": "mock_obj",
|
||||
"litellm_metadata": {"key": "value"},
|
||||
"client_metadata": {"session": "abc123"},
|
||||
}
|
||||
filtered = _filter_kwargs_for_completion(kwargs)
|
||||
assert "client_metadata" not in filtered
|
||||
assert filtered["litellm_logging_obj"] == "mock_obj"
|
||||
assert filtered["litellm_metadata"] == {"key": "value"}
|
||||
|
||||
def test_preserves_all_litellm_prefixed_kwargs(self):
|
||||
"""All litellm_* kwargs should be preserved."""
|
||||
kwargs = {
|
||||
"litellm_call_id": "call-123",
|
||||
"litellm_metadata": {},
|
||||
"litellm_logging_obj": None,
|
||||
"litellm_parent_otel_span": "span",
|
||||
}
|
||||
filtered = _filter_kwargs_for_completion(kwargs)
|
||||
assert filtered == kwargs
|
||||
|
||||
def test_strips_all_non_litellm_kwargs(self):
|
||||
"""Any non-litellm_* kwarg should be stripped."""
|
||||
kwargs = {
|
||||
"litellm_metadata": {},
|
||||
"client_metadata": {"x": 1},
|
||||
"some_other_param": True,
|
||||
"prompt_id": "p-1",
|
||||
}
|
||||
filtered = _filter_kwargs_for_completion(kwargs)
|
||||
assert filtered == {"litellm_metadata": {}}
|
||||
|
||||
def test_empty_kwargs(self):
|
||||
"""Empty kwargs should return empty dict."""
|
||||
assert _filter_kwargs_for_completion({}) == {}
|
||||
|
||||
def test_no_litellm_kwargs(self):
|
||||
"""If only non-litellm kwargs, return empty dict."""
|
||||
kwargs = {"client_metadata": {}, "extra_param": "value"}
|
||||
assert _filter_kwargs_for_completion(kwargs) == {}
|
||||
Loading…
Add table
Reference in a new issue