mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
fix(responses): strip the responses/ routing prefix on the Responses API path
openai/responses/<model> deployments reached OpenAI as the literal model id responses/<model> on /v1/responses and on /v1/messages (which rides the Responses API for the openai provider) and 400ed with model_not_found, while /v1/chat/completions already stripped the prefix. Strip a leading responses/ right after provider resolution so every Responses API entrypoint (HTTP, websocket, compaction, the /v1/messages adapter) sends the real model id
This commit is contained in:
parent
6d32d4081d
commit
61625723a7
2 changed files with 73 additions and 8 deletions
|
|
@ -640,6 +640,15 @@ def _pop_use_chat_completions_api_kw(kwargs: dict[str, object]) -> bool:
|
|||
return bool(use_cc)
|
||||
|
||||
|
||||
_RESPONSES_ROUTING_PREFIX: Final = "responses/"
|
||||
|
||||
|
||||
def _strip_responses_routing_prefix(model: str) -> str:
|
||||
if not model.startswith(_RESPONSES_ROUTING_PREFIX):
|
||||
return model
|
||||
return model[len(_RESPONSES_ROUTING_PREFIX) :]
|
||||
|
||||
|
||||
def _resolve_model_provider_for_responses(
|
||||
model: str,
|
||||
custom_llm_provider: str | None,
|
||||
|
|
@ -649,20 +658,20 @@ def _resolve_model_provider_for_responses(
|
|||
if custom_llm_provider is not None and not litellm_params.custom_llm_provider:
|
||||
litellm_params.custom_llm_provider = custom_llm_provider
|
||||
(
|
||||
model,
|
||||
custom_llm_provider,
|
||||
provider_model,
|
||||
resolved_provider,
|
||||
dynamic_api_key,
|
||||
dynamic_api_base,
|
||||
) = litellm.get_llm_provider(
|
||||
model=model,
|
||||
litellm_params=litellm_params,
|
||||
)
|
||||
local_vars["custom_llm_provider"] = custom_llm_provider
|
||||
local_vars["custom_llm_provider"] = resolved_provider
|
||||
if dynamic_api_key is not None:
|
||||
litellm_params.api_key = dynamic_api_key
|
||||
if dynamic_api_base is not None:
|
||||
litellm_params.api_base = dynamic_api_base
|
||||
return model, custom_llm_provider
|
||||
return _strip_responses_routing_prefix(provider_model), resolved_provider
|
||||
|
||||
|
||||
def _apply_managed_file_id_mapping(
|
||||
|
|
@ -1997,7 +2006,7 @@ async def _aresponses_websocket(
|
|||
litellm_params_dict: Final = get_litellm_params(**kwargs)
|
||||
|
||||
(
|
||||
model,
|
||||
provider_model,
|
||||
_custom_llm_provider,
|
||||
dynamic_api_key,
|
||||
dynamic_api_base,
|
||||
|
|
@ -2006,6 +2015,7 @@ async def _aresponses_websocket(
|
|||
api_base=api_base,
|
||||
api_key=api_key,
|
||||
)
|
||||
resolved_model: Final = _strip_responses_routing_prefix(provider_model)
|
||||
|
||||
litellm_params_dict["data_residency"] = infer_openai_data_residency(
|
||||
_custom_llm_provider,
|
||||
|
|
@ -2014,7 +2024,7 @@ async def _aresponses_websocket(
|
|||
|
||||
litellm_logging_obj.update_from_kwargs(
|
||||
kwargs=kwargs,
|
||||
model=model,
|
||||
model=resolved_model,
|
||||
user=user,
|
||||
optional_params={},
|
||||
litellm_params=litellm_params_dict,
|
||||
|
|
@ -2024,7 +2034,7 @@ async def _aresponses_websocket(
|
|||
responses_api_provider_config: BaseResponsesAPIConfig | None = None
|
||||
if _custom_llm_provider is not None:
|
||||
responses_api_provider_config = ProviderConfigManager.get_provider_responses_api_config(
|
||||
model=model,
|
||||
model=resolved_model,
|
||||
provider=litellm.LlmProviders(_custom_llm_provider),
|
||||
)
|
||||
|
||||
|
|
@ -2052,7 +2062,7 @@ async def _aresponses_websocket(
|
|||
remaining_kwargs: Final = {k: v for k, v in kwargs.items() if k not in _explicit_keys}
|
||||
|
||||
await base_llm_http_handler.async_responses_websocket(
|
||||
model=model,
|
||||
model=resolved_model,
|
||||
websocket=websocket,
|
||||
logging_obj=litellm_logging_obj,
|
||||
responses_api_provider_config=responses_api_provider_config,
|
||||
|
|
|
|||
|
|
@ -367,3 +367,58 @@ async def test_aresponses_client_header_conflict_is_case_insensitive():
|
|||
|
||||
assert [name for name in request_headers if name.lower() == "x-shared"] == ["x-shared"]
|
||||
assert request_headers["x-shared"] == "from-caller"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
("model", "custom_llm_provider"),
|
||||
[
|
||||
("openai/responses/gpt-5.6", None),
|
||||
("responses/gpt-5.6", "openai"),
|
||||
],
|
||||
)
|
||||
async def test_aresponses_strips_responses_routing_prefix_from_openai_model(model, custom_llm_provider):
|
||||
"""
|
||||
`responses/` is LiteLLM routing sugar, never part of the provider model id.
|
||||
Deployments configured as openai/responses/<model> reach this path directly via
|
||||
/v1/responses and via the /v1/messages adapter (which passes responses/<model>
|
||||
with custom_llm_provider="openai"), so both shapes must hit OpenAI as <model>.
|
||||
"""
|
||||
with patch(
|
||||
"litellm.llms.custom_httpx.http_handler.AsyncHTTPHandler.post",
|
||||
new_callable=AsyncMock,
|
||||
) as mock_post:
|
||||
mock_post.return_value = MockResponse(_minimal_responses_api_payload("resp_prefix_test", "gpt-5.6"), 200)
|
||||
|
||||
await litellm.aresponses(
|
||||
model=model,
|
||||
custom_llm_provider=custom_llm_provider,
|
||||
input="ping",
|
||||
api_key="sk-test",
|
||||
)
|
||||
|
||||
mock_post.assert_called_once()
|
||||
assert mock_post.call_args.kwargs["url"].endswith("/responses")
|
||||
assert mock_post.call_args.kwargs["json"]["model"] == "gpt-5.6"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_aresponses_websocket_strips_responses_routing_prefix_from_openai_model():
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from litellm.responses.main import _aresponses_websocket
|
||||
|
||||
with patch(
|
||||
"litellm.responses.main.base_llm_http_handler.async_responses_websocket",
|
||||
new_callable=AsyncMock,
|
||||
) as mock_ws:
|
||||
await _aresponses_websocket(
|
||||
model="openai/responses/gpt-5.6",
|
||||
websocket=MagicMock(),
|
||||
api_key="sk-test",
|
||||
litellm_logging_obj=MagicMock(),
|
||||
)
|
||||
|
||||
mock_ws.assert_awaited_once()
|
||||
assert mock_ws.call_args.kwargs["model"] == "gpt-5.6"
|
||||
assert mock_ws.call_args.kwargs["custom_llm_provider"] == "openai"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue