This commit is contained in:
Zhu Lei 2026-10-19 00:59:11 +00:00 • committed by GitHub
commit d76f1ccc11
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 56 additions and 2 deletions

View file

@ -201,7 +201,7 @@ from litellm.types.llms.openai import (
ChatCompletionUserMessage,
ToolMessageContentPart,
)
from litellm.types.utils import Choices, ModelResponse, StreamingChoices, Usage
from litellm.types.utils import Choices, FunctionCall, ModelResponse, StreamingChoices, Usage
from litellm.utils import supports_mid_conversation_system
from .streaming_iterator import AnthropicSSEStream, AnthropicStreamWrapper
@ -1436,15 +1436,40 @@ class LiteLLMAnthropicMessagesAdapter:
if provider_specific_fields:
tool_use_block.provider_specific_fields = provider_specific_fields
new_content.append(tool_use_block.model_dump(exclude_none=True))
if choice.message.function_call is not None:
new_content.append(
self._legacy_function_call_block(choice.message.function_call, tool_name_mapping).model_dump(
exclude_none=True
)
)
return new_content
@staticmethod
def _legacy_function_call_block(
function_call: FunctionCall, tool_name_mapping: Mapping[str, str] | None
) -> AnthropicResponseContentBlockToolUse:
from litellm._uuid import uuid
raw_name: Final = function_call.name or ""
name: Final = tool_name_mapping.get(raw_name, raw_name) if tool_name_mapping else raw_name
return AnthropicResponseContentBlockToolUse(
type="tool_use",
id=normalize_anthropic_tool_use_id(str(uuid.uuid4())),
name=name,
input=parse_tool_call_arguments(
function_call.arguments,
tool_name=name,
context="Anthropic pass-through adapter",
),
)
def _translate_openai_finish_reason_to_anthropic(self, openai_finish_reason: str) -> AnthropicFinishReason:
if openai_finish_reason == "stop":
return "end_turn"
elif openai_finish_reason == "length":
return "max_tokens"
elif openai_finish_reason == "tool_calls":
elif openai_finish_reason in ("tool_calls", "function_call"):
return "tool_use"
elif openai_finish_reason in ["content_filter", "refusal"]:
return "refusal"

View file

@ -5235,3 +5235,32 @@ def test_eager_input_streaming_tool_reaches_bedrock_converse_as_beta():
assert data["additionalModelRequestFields"]["anthropic_beta"] == ["fine-grained-tool-streaming-2025-05-14"]
assert data["toolConfig"]["tools"][0]["toolSpec"]["inputSchema"]["json"] == EAGER_INPUT_SCHEMA
def test_translate_openai_function_call_response_to_anthropic_tool_use():
"""A legacy OpenAI function_call finish maps to an Anthropic tool_use turn."""
response: Final = ModelResponse(
id="chatcmpl-function-call",
model="legacy-function-model",
choices=[
Choices(
index=0,
finish_reason="function_call",
message=Message(
role="assistant",
content=None,
function_call={"name": "get_weather", "arguments": '{"location": "Boston"}'},
),
)
],
usage=Usage(prompt_tokens=10, completion_tokens=5, total_tokens=15),
)
result: Final = LiteLLMAnthropicMessagesAdapter().translate_openai_response_to_anthropic(response)
assert result["stop_reason"] == "tool_use"
[block] = result["content"] or []
assert block["type"] == "tool_use"
assert block["name"] == "get_weather"
assert block["input"] == {"location": "Boston"}
assert block["id"] and all(c.isalnum() or c in "-_" for c in block["id"])