This commit is contained in:
Steffan W 2026-10-01 18:16:04 +00:00 • committed by GitHub
commit 3b5bb5adc5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 55 additions and 29 deletions

View file

@ -108,7 +108,11 @@ class ChatGPTResponsesAPIConfig(OpenAIResponsesAPIConfig):
"truncation",
}
return {k: v for k, v in request.items() if k in allowed_keys}
return {
k: "priority" if k == "service_tier" and v == "fast" else v
for k, v in request.items()
if k in allowed_keys or (k == "service_tier" and v in ("default", "priority", "fast"))
}
def transform_response_api_response(
self,

View file

@ -6,6 +6,7 @@ Source: litellm/llms/chatgpt/responses/transformation.py
import json
from collections.abc import Generator
from typing import Final
from unittest.mock import MagicMock, patch
import httpx
@ -30,6 +31,46 @@ def local_model_cost_map(monkeypatch: pytest.MonkeyPatch) -> Generator[None, Non
class TestChatGPTResponsesAPITransformation:
@pytest.mark.parametrize(
("requested_tier", "expected_tier"),
[("default", "default"), ("priority", "priority"), ("fast", "priority")],
)
@pytest.mark.parametrize("effort", ["low", "high"])
def test_chatgpt_preserves_service_tier(self, requested_tier: str, expected_tier: str, effort: str) -> None:
config: Final = ChatGPTResponsesAPIConfig()
request: Final = config.transform_responses_api_request(
model="chatgpt/gpt-6.1-sol",
input=[{"role": "user", "content": "Reply with OK"}],
response_api_optional_request_params={
"service_tier": requested_tier,
"reasoning": {"effort": effort},
"max_output_tokens": 16,
"prompt_cache_options": {"ttl": "30m"},
},
litellm_params=GenericLiteLLMParams(),
headers={},
)
assert request["service_tier"] == expected_tier
assert request["reasoning"] == {"effort": effort}
assert request["stream"] is True
assert request["store"] is False
assert "max_output_tokens" not in request
assert "prompt_cache_options" not in request
@pytest.mark.parametrize("requested_tier", [None, "auto", "flex", "unknown"])
def test_chatgpt_does_not_introduce_unsupported_service_tier(self, requested_tier: str | None) -> None:
config: Final = ChatGPTResponsesAPIConfig()
request: Final = config.transform_responses_api_request(
model="chatgpt/gpt-6.1-sol",
input=[{"role": "user", "content": "Reply with OK"}],
response_api_optional_request_params={} if requested_tier is None else {"service_tier": requested_tier},
litellm_params=GenericLiteLLMParams(),
headers={},
)
assert "service_tier" not in request
@pytest.mark.parametrize(
"model_name",
[
@ -55,7 +96,6 @@ class TestChatGPTResponsesAPITransformation:
assert isinstance(config, ChatGPTResponsesAPIConfig)
assert config.custom_llm_provider == LlmProviders.CHATGPT
@pytest.mark.parametrize(
"model_name",
[
@ -92,14 +132,10 @@ class TestChatGPTResponsesAPITransformation:
url = config.get_complete_url(api_base=None, litellm_params={})
assert url == "https://chatgpt.example.com/responses"
custom_url = config.get_complete_url(
api_base="https://custom.chatgpt.com", litellm_params={}
)
custom_url = config.get_complete_url(api_base="https://custom.chatgpt.com", litellm_params={})
assert custom_url == "https://custom.chatgpt.com/responses"
url_with_slash = config.get_complete_url(
api_base="https://chatgpt.example.com/", litellm_params={}
)
url_with_slash = config.get_complete_url(api_base="https://chatgpt.example.com/", litellm_params={})
assert url_with_slash == "https://chatgpt.example.com/responses"
@patch("litellm.llms.chatgpt.responses.transformation.Authenticator")
@ -162,9 +198,7 @@ class TestChatGPTResponsesAPITransformation:
"user": "user_123",
"temperature": 0.2,
"top_p": 0.9,
"context_management": [
{"type": "compaction", "compact_threshold": 200000}
],
"context_management": [{"type": "compaction", "compact_threshold": 200000}],
"metadata": {"foo": "bar"},
"max_output_tokens": 123,
"stream_options": {"include_usage": True},
@ -203,9 +237,7 @@ class TestChatGPTResponsesAPITransformation:
("chatgpt/gpt-5.3-codex", "gpt-5.3-codex"),
],
)
def test_chatgpt_non_stream_sse_response_parsing(
self, model_name: str, response_model: str
):
def test_chatgpt_non_stream_sse_response_parsing(self, model_name: str, response_model: str):
config = ChatGPTResponsesAPIConfig()
response_payload = {
"id": "resp_test",
@ -228,9 +260,7 @@ class TestChatGPTResponsesAPITransformation:
"",
]
)
raw_response = httpx.Response(
200, headers={"content-type": "text/event-stream"}, text=sse_body
)
raw_response = httpx.Response(200, headers={"content-type": "text/event-stream"}, text=sse_body)
logging_obj = MagicMock()
parsed = config.transform_response_api_response(
@ -248,9 +278,7 @@ class TestChatGPTResponsesAPITransformation:
("chatgpt/gpt-5.3-codex", "gpt-5.3-codex"),
],
)
def test_chatgpt_non_stream_sse_response_recovers_output_items(
self, model_name: str, response_model: str
):
def test_chatgpt_non_stream_sse_response_recovers_output_items(self, model_name: str, response_model: str):
config = ChatGPTResponsesAPIConfig()
response_payload = {
"id": "resp_test",
@ -273,9 +301,7 @@ class TestChatGPTResponsesAPITransformation:
"",
]
)
raw_response = httpx.Response(
200, headers={"content-type": "text/event-stream"}, text=sse_body
)
raw_response = httpx.Response(200, headers={"content-type": "text/event-stream"}, text=sse_body)
logging_obj = MagicMock()
parsed = config.transform_response_api_response(
@ -315,9 +341,7 @@ class TestChatGPTResponsesAPITransformation:
"",
]
)
raw_response = httpx.Response(
200, headers={"content-type": "text/event-stream"}, text=sse_body
)
raw_response = httpx.Response(200, headers={"content-type": "text/event-stream"}, text=sse_body)
logging_obj = MagicMock()
parsed = config.transform_response_api_response(
@ -350,9 +374,7 @@ class TestChatGPTResponsesAPITransformation:
"",
]
)
raw_response = httpx.Response(
502, headers={"content-type": "text/event-stream"}, text=sse_body
)
raw_response = httpx.Response(502, headers={"content-type": "text/event-stream"}, text=sse_body)
logging_obj = MagicMock()
with pytest.raises(OpenAIError) as exc_info: