mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-28 06:23:07 +00:00
Merge ad5389b063 into 8d9b9926d1
This commit is contained in:
commit
e22824ffca
5 changed files with 99 additions and 15 deletions
|
|
@ -28238,6 +28238,9 @@
|
|||
{
|
||||
"$ref": "#/components/schemas/CustomToolCallOutputItem"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/ResponseReasoningItem"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/OutputToolSearchCall"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,13 @@ from openai.types.chat.chat_completion_named_tool_choice_param import (
|
|||
from openai.types.chat.chat_completion_named_tool_choice_param import (
|
||||
Function as NamedToolChoiceFunction,
|
||||
)
|
||||
from openai.types.responses import ResponseFunctionToolCall, ResponseFunctionWebSearch
|
||||
from openai.types.responses import (
|
||||
ResponseFunctionToolCall,
|
||||
ResponseFunctionWebSearch,
|
||||
ResponseReasoningItem,
|
||||
)
|
||||
from openai.types.responses.response_create_params import ResponseInputParam
|
||||
from openai.types.responses.response_reasoning_item import Content as ReasoningContent
|
||||
from openai.types.responses.tool_choice_custom_param import ToolChoiceCustomParam
|
||||
from openai.types.responses.tool_choice_function_param import ToolChoiceFunctionParam
|
||||
from openai.types.responses.tool_param import FunctionToolParam
|
||||
|
|
@ -3037,6 +3042,7 @@ class LiteLLMCompletionResponsesConfig:
|
|||
| ResponseFunctionToolCall
|
||||
| ResponseFunctionWebSearch
|
||||
| CustomToolCallOutputItem
|
||||
| ResponseReasoningItem
|
||||
| OutputToolSearchCall
|
||||
]:
|
||||
responses_output: list[
|
||||
|
|
@ -3047,6 +3053,7 @@ class LiteLLMCompletionResponsesConfig:
|
|||
| ResponseFunctionToolCall
|
||||
| ResponseFunctionWebSearch
|
||||
| CustomToolCallOutputItem
|
||||
| ResponseReasoningItem
|
||||
| OutputToolSearchCall
|
||||
] = []
|
||||
|
||||
|
|
@ -3124,7 +3131,7 @@ class LiteLLMCompletionResponsesConfig:
|
|||
def _extract_reasoning_output_items(
|
||||
chat_completion_response: ModelResponse,
|
||||
choices: list[Choices],
|
||||
) -> list[GenericResponseOutputItem]:
|
||||
) -> list[ResponseReasoningItem]:
|
||||
for choice in choices:
|
||||
if hasattr(choice, "message") and choice.message:
|
||||
message = choice.message
|
||||
|
|
@ -3133,22 +3140,23 @@ class LiteLLMCompletionResponsesConfig:
|
|||
if reasoning_content or encrypted_content:
|
||||
# Only check the first choice for reasoning content
|
||||
return [
|
||||
GenericResponseOutputItem(
|
||||
ResponseReasoningItem(
|
||||
type="reasoning",
|
||||
id=mint_reasoning_item_id(),
|
||||
status=LiteLLMCompletionResponsesConfig._map_chat_completion_finish_reason_to_responses_status(
|
||||
choice.finish_reason
|
||||
),
|
||||
role="assistant",
|
||||
# summary is required by the SDK/spec; the bridge has
|
||||
# no summarized reasoning, so it stays empty
|
||||
summary=[],
|
||||
content=[
|
||||
OutputText(
|
||||
type="output_text",
|
||||
text=text,
|
||||
annotations=[],
|
||||
)
|
||||
ReasoningContent(type="reasoning_text", text=text)
|
||||
for text in (reasoning_content,)
|
||||
if text
|
||||
],
|
||||
status=cast( # cast-ok: the map only returns completed/incomplete, both valid for a reasoning item's narrower status union
|
||||
"Literal['in_progress', 'completed', 'incomplete']",
|
||||
LiteLLMCompletionResponsesConfig._map_chat_completion_finish_reason_to_responses_status(
|
||||
choice.finish_reason
|
||||
),
|
||||
),
|
||||
encrypted_content=encrypted_content,
|
||||
)
|
||||
]
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ from openai.types.responses.response_create_params import (
|
|||
)
|
||||
from openai.types.responses.response_function_tool_call import ResponseFunctionToolCall
|
||||
from openai.types.responses.response_function_web_search import ResponseFunctionWebSearch
|
||||
from openai.types.responses.response_reasoning_item import ResponseReasoningItem
|
||||
from pydantic import (
|
||||
ConfigDict,
|
||||
Discriminator,
|
||||
|
|
@ -1487,6 +1488,7 @@ class ResponsesAPIResponse(BaseLiteLLMOpenAIResponseObject):
|
|||
| ResponseFunctionToolCall
|
||||
| ResponseFunctionWebSearch
|
||||
| CustomToolCallOutputItem
|
||||
| ResponseReasoningItem
|
||||
| OutputToolSearchCall
|
||||
]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -307,9 +307,10 @@ class TestLiteLLMCompletionResponsesConfig:
|
|||
if hasattr(reasoning_item, "id") and reasoning_item.id:
|
||||
assert reasoning_item.id.startswith("rs_"), f"Expected ID to start with 'rs_', got: {reasoning_item.id}"
|
||||
assert reasoning_item.status == "completed"
|
||||
assert reasoning_item.role == "assistant"
|
||||
assert reasoning_item.summary == []
|
||||
assert not hasattr(reasoning_item, "role")
|
||||
assert len(reasoning_item.content) == 1
|
||||
assert reasoning_item.content[0].type == "output_text"
|
||||
assert reasoning_item.content[0].type == "reasoning_text"
|
||||
assert "step by step" in reasoning_item.content[0].text
|
||||
assert "42" in reasoning_item.content[0].text
|
||||
|
||||
|
|
@ -319,6 +320,76 @@ class TestLiteLLMCompletionResponsesConfig:
|
|||
message_item = message_items[0]
|
||||
assert message_item.content[0].text == "The answer is 42."
|
||||
|
||||
def test_reasoning_output_items_validate_against_openai_sdk(self):
|
||||
"""Bridged reasoning items must carry a summary array and reasoning_text
|
||||
content parts so ResponseReasoningItem accepts them (issue #45552)."""
|
||||
from openai.types.responses import ResponseReasoningItem
|
||||
|
||||
chat_completion_response = ModelResponse(
|
||||
id="test-response-id",
|
||||
created=1234567890,
|
||||
model="test-model",
|
||||
object="chat.completion",
|
||||
choices=[
|
||||
Choices(
|
||||
finish_reason="stop",
|
||||
index=0,
|
||||
message=Message(
|
||||
content="The answer is 42.",
|
||||
role="assistant",
|
||||
reasoning_content="Thinking about the question.",
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
responses_api_response = LiteLLMCompletionResponsesConfig.transform_chat_completion_response_to_responses_api_response(
|
||||
request_input="What is the meaning of life?",
|
||||
responses_api_request={},
|
||||
chat_completion_response=chat_completion_response,
|
||||
)
|
||||
|
||||
reasoning_items = [
|
||||
item for item in responses_api_response.output if item.type == "reasoning"
|
||||
]
|
||||
assert len(reasoning_items) == 1
|
||||
|
||||
dumped = reasoning_items[0].model_dump(mode="json")
|
||||
assert dumped["summary"] == []
|
||||
assert dumped["content"][0]["type"] == "reasoning_text"
|
||||
assert "role" not in dumped
|
||||
assert "phase" not in dumped
|
||||
|
||||
validated = ResponseReasoningItem.model_validate(dumped)
|
||||
assert validated.summary == []
|
||||
|
||||
def test_reasoning_output_item_without_text_still_validates(self):
|
||||
"""Encrypted-only reasoning (empty content) must still carry summary: [] and
|
||||
validate against the SDK (issue #45552, display: omitted case)."""
|
||||
from openai.types.responses import ResponseReasoningItem
|
||||
|
||||
message = Message(role="assistant", content="apple")
|
||||
message.thinking_blocks = [
|
||||
{"type": "thinking", "thinking": "", "signature": "sig"}
|
||||
]
|
||||
choice = Choices(index=0, finish_reason="stop", message=message)
|
||||
|
||||
items = LiteLLMCompletionResponsesConfig._extract_reasoning_output_items(
|
||||
chat_completion_response=ModelResponse(
|
||||
id="test-response-id",
|
||||
created=1234567890,
|
||||
model="test-model",
|
||||
object="chat.completion",
|
||||
),
|
||||
choices=[choice],
|
||||
)
|
||||
|
||||
assert len(items) == 1
|
||||
dumped = items[0].model_dump(mode="json")
|
||||
assert dumped["summary"] == []
|
||||
assert dumped["content"] == []
|
||||
ResponseReasoningItem.model_validate(dumped)
|
||||
|
||||
def test_transform_chat_completion_response_without_reasoning_content(self):
|
||||
"""Test that transformation works normally when no reasoning content is present"""
|
||||
# Setup
|
||||
|
|
|
|||
2
ui/litellm-dashboard/src/lib/http/schema.d.ts
generated
vendored
2
ui/litellm-dashboard/src/lib/http/schema.d.ts
generated
vendored
|
|
@ -44279,7 +44279,7 @@ export interface components {
|
|||
/** Output */
|
||||
output: (components["schemas"]["ResponseOutputMessage"] | components["schemas"]["ResponseFileSearchToolCall"] | components["schemas"]["ResponseFunctionToolCall"] | components["schemas"]["ResponseFunctionToolCallOutputItem"] | components["schemas"]["ResponseFunctionWebSearch"] | components["schemas"]["ResponseComputerToolCall"] | components["schemas"]["ResponseComputerToolCallOutputItem"] | components["schemas"]["ResponseReasoningItem"] | components["schemas"]["ResponseToolSearchCall"] | components["schemas"]["ResponseToolSearchOutputItem"] | components["schemas"]["ResponseCompactionItem"] | components["schemas"]["ImageGenerationCall"] | components["schemas"]["ResponseCodeInterpreterToolCall"] | components["schemas"]["LocalShellCall"] | components["schemas"]["LocalShellCallOutput"] | components["schemas"]["ResponseFunctionShellToolCall"] | components["schemas"]["ResponseFunctionShellToolCallOutput"] | components["schemas"]["ResponseApplyPatchToolCall"] | components["schemas"]["ResponseApplyPatchToolCallOutput"] | components["schemas"]["McpCall"] | components["schemas"]["McpListTools"] | components["schemas"]["McpApprovalRequest"] | components["schemas"]["McpApprovalResponse"] | components["schemas"]["ResponseCustomToolCall"] | components["schemas"]["ResponseCustomToolCallOutputItem"] | {
|
||||
[key: string]: unknown;
|
||||
})[] | (components["schemas"]["GenericResponseOutputItem"] | components["schemas"]["OutputCodeInterpreterCall"] | components["schemas"]["OutputFunctionToolCall"] | components["schemas"]["OutputImageGenerationCall"] | components["schemas"]["ResponseFunctionToolCall"] | components["schemas"]["ResponseFunctionWebSearch"] | components["schemas"]["CustomToolCallOutputItem"] | components["schemas"]["OutputToolSearchCall"])[];
|
||||
})[] | (components["schemas"]["GenericResponseOutputItem"] | components["schemas"]["OutputCodeInterpreterCall"] | components["schemas"]["OutputFunctionToolCall"] | components["schemas"]["OutputImageGenerationCall"] | components["schemas"]["ResponseFunctionToolCall"] | components["schemas"]["ResponseFunctionWebSearch"] | components["schemas"]["CustomToolCallOutputItem"] | components["schemas"]["ResponseReasoningItem"] | components["schemas"]["OutputToolSearchCall"])[];
|
||||
/** Parallel Tool Calls */
|
||||
parallel_tool_calls?: boolean | null;
|
||||
/** Previous Response Id */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue