fix: Support text.format parameter in Responses API for providers without native ResponsesAPIConfig (#16023)

Fixes #15995

When using the Responses API with providers that don't have a native
ResponsesAPIConfig implementation (like Gemini, Anthropic, Cohere, etc.),
the text.format parameter was being ignored. This happened because these
providers fall back to using the LiteLLMCompletionTransformationHandler,
which converts Responses API requests to Chat Completion API requests.

Changes:
- Added 'text' to the list of supported parameters in
  LiteLLMCompletionResponsesConfig.get_supported_openai_params()
- Added transformation logic to convert text.format (Responses API format)
  to response_format (Chat Completion API format) in
  transform_responses_api_request_to_chat_completion_request()
- Created _transform_text_format_to_response_format() method to handle
  the conversion between the two format structures

The transformation supports:
- json_schema: Converts to Chat Completion's json_schema format with
  proper nested structure
- json_object: Converts to Chat Completion's json_object mode
- text: Returns None (default text format)

This fix benefits all providers that use the fallback transformation
handler, ensuring consistent behavior with OpenAI's native Responses API
implementation.
This commit is contained in:
Rodolfo Nobrega de Resende 2025-10-28 22:06:48 -03:00 committed by GitHub
parent b0a2e08a60
commit 29f0ed223a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -87,6 +87,7 @@ class LiteLLMCompletionResponsesConfig:
"previous_response_id", "previous_response_id",
"stream", "stream",
"temperature", "temperature",
"text",
"tool_choice", "tool_choice",
"tools", "tools",
"top_p", "top_p",
@ -109,6 +110,14 @@ class LiteLLMCompletionResponsesConfig:
tools, web_search_options = LiteLLMCompletionResponsesConfig.transform_responses_api_tools_to_chat_completion_tools( tools, web_search_options = LiteLLMCompletionResponsesConfig.transform_responses_api_tools_to_chat_completion_tools(
responses_api_request.get("tools") or [] # type: ignore responses_api_request.get("tools") or [] # type: ignore
) )
response_format = None
text_param = responses_api_request.get("text")
if text_param:
response_format = LiteLLMCompletionResponsesConfig._transform_text_format_to_response_format(
text_param
)
litellm_completion_request: dict = { litellm_completion_request: dict = {
"messages": LiteLLMCompletionResponsesConfig.transform_responses_api_input_to_messages( "messages": LiteLLMCompletionResponsesConfig.transform_responses_api_input_to_messages(
input=input, input=input,
@ -126,6 +135,7 @@ class LiteLLMCompletionResponsesConfig:
"metadata": kwargs.get("metadata"), "metadata": kwargs.get("metadata"),
"service_tier": kwargs.get("service_tier"), "service_tier": kwargs.get("service_tier"),
"web_search_options": web_search_options, "web_search_options": web_search_options,
"response_format": response_format,
# litellm specific params # litellm specific params
"custom_llm_provider": custom_llm_provider, "custom_llm_provider": custom_llm_provider,
"extra_headers": extra_headers, "extra_headers": extra_headers,
@ -907,3 +917,56 @@ class LiteLLMCompletionResponsesConfig:
setattr(response_usage, "cost", usage.cost) setattr(response_usage, "cost", usage.cost)
return response_usage return response_usage
@staticmethod
def _transform_text_format_to_response_format(
text_param: Union[Dict[str, Any], Any],
) -> Optional[Dict[str, Any]]:
"""
Transform Responses API text.format parameter to Chat Completion response_format parameter.
Responses API text parameter structure:
{
"format": {
"type": "json_schema",
"name": "schema_name",
"schema": {...},
"strict": True
}
}
Chat Completion response_format structure:
{
"type": "json_schema",
"json_schema": {
"name": "schema_name",
"schema": {...},
"strict": True
}
}
"""
if not text_param:
return None
if isinstance(text_param, dict):
format_param = text_param.get("format")
if format_param and isinstance(format_param, dict):
format_type = format_param.get("type")
if format_type == "json_schema":
return {
"type": "json_schema",
"json_schema": {
"name": format_param.get("name", "response_schema"),
"schema": format_param.get("schema", {}),
"strict": format_param.get("strict", False),
}
}
elif format_type == "json_object":
return {
"type": "json_object"
}
elif format_type == "text":
return None
return None