mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
Merge f2dae20e49 into e9b1c11098
This commit is contained in:
commit
8efe952649
2 changed files with 94 additions and 0 deletions
|
|
@ -1,3 +1,4 @@
|
|||
import hashlib
|
||||
from collections.abc import Mapping
|
||||
from typing import TYPE_CHECKING, Any, Final, cast
|
||||
|
||||
|
|
@ -130,6 +131,7 @@ class ChatGPTResponsesAPIConfig(OpenAIResponsesAPIConfig):
|
|||
if "reasoning.encrypted_content" not in include:
|
||||
include.append("reasoning.encrypted_content")
|
||||
request["include"] = include
|
||||
request["input"] = self._normalize_responses_input_for_chatgpt(request.get("input"))
|
||||
|
||||
allowed_keys: Final = {
|
||||
"model",
|
||||
|
|
@ -153,6 +155,36 @@ class ChatGPTResponsesAPIConfig(OpenAIResponsesAPIConfig):
|
|||
filtered["service_tier"] = service_tier
|
||||
return filtered
|
||||
|
||||
@classmethod
|
||||
def _normalize_responses_input_for_chatgpt(cls, input_value: Any) -> Any:
|
||||
if not isinstance(input_value, list):
|
||||
return input_value
|
||||
|
||||
normalized_input: list[Any] = []
|
||||
changed = False
|
||||
for item in input_value:
|
||||
if isinstance(item, dict):
|
||||
item_type = item.get("type")
|
||||
if item_type in {"reasoning", "web_search_call"}:
|
||||
changed = True
|
||||
continue
|
||||
if item_type == "function_call":
|
||||
current_id = item.get("id")
|
||||
normalized_id = cls._normalize_function_call_item_id(current_id)
|
||||
if normalized_id != current_id:
|
||||
item = dict(item)
|
||||
item["id"] = normalized_id
|
||||
changed = True
|
||||
normalized_input.append(item)
|
||||
return normalized_input if changed else input_value
|
||||
|
||||
@staticmethod
|
||||
def _normalize_function_call_item_id(item_id: Any) -> Any:
|
||||
if not isinstance(item_id, str) or not item_id or item_id.startswith("fc"):
|
||||
return item_id
|
||||
digest: Final = hashlib.sha256(item_id.encode("utf-8")).hexdigest()[:32]
|
||||
return f"fc_{digest}"
|
||||
|
||||
def transform_response_api_response(
|
||||
self,
|
||||
model: str,
|
||||
|
|
|
|||
|
|
@ -218,6 +218,68 @@ class TestChatGPTResponsesAPITransformation:
|
|||
assert "reasoning.encrypted_content" in request["include"]
|
||||
assert request["instructions"].startswith("You are Codex, based on GPT-5.")
|
||||
|
||||
def test_chatgpt_normalizes_foreign_function_call_item_id(self):
|
||||
config = ChatGPTResponsesAPIConfig()
|
||||
input_items = [
|
||||
{
|
||||
"type": "function_call",
|
||||
"id": "toolu_fixture_123",
|
||||
"call_id": "call_fixture_123",
|
||||
"name": "read_file",
|
||||
"arguments": '{"path":"README.md"}',
|
||||
}
|
||||
]
|
||||
|
||||
request = config.transform_responses_api_request(
|
||||
model="chatgpt/gpt-5.6-sol",
|
||||
input=input_items,
|
||||
response_api_optional_request_params={},
|
||||
litellm_params=GenericLiteLLMParams(),
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert request["input"] == [
|
||||
{
|
||||
"type": "function_call",
|
||||
"id": "fc_064009edc4c975f0fa4b447f8ea388e0",
|
||||
"call_id": "call_fixture_123",
|
||||
"name": "read_file",
|
||||
"arguments": '{"path":"README.md"}',
|
||||
}
|
||||
]
|
||||
|
||||
def test_chatgpt_omits_replayed_private_output_items(self):
|
||||
config = ChatGPTResponsesAPIConfig()
|
||||
input_items = [
|
||||
{"type": "reasoning", "id": "rs_fixture", "encrypted_content": "opaque"},
|
||||
{
|
||||
"type": "message",
|
||||
"role": "user",
|
||||
"content": [{"type": "input_text", "text": "continue"}],
|
||||
},
|
||||
{"type": "web_search_call", "id": "ws_fixture", "status": "completed"},
|
||||
{
|
||||
"type": "function_call",
|
||||
"id": "fc_fixture",
|
||||
"call_id": "call_fixture",
|
||||
"name": "read_file",
|
||||
"arguments": '{"path":"README.md"}',
|
||||
},
|
||||
]
|
||||
|
||||
request = config.transform_responses_api_request(
|
||||
model="chatgpt/gpt-5.6-sol",
|
||||
input=input_items,
|
||||
response_api_optional_request_params={},
|
||||
litellm_params=GenericLiteLLMParams(),
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert [item["type"] for item in request["input"]] == [
|
||||
"message",
|
||||
"function_call",
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model_name",
|
||||
[
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue