mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
Merge e77de1e81f into cd63c7e5a7
This commit is contained in:
commit
8075edd401
5 changed files with 117 additions and 2 deletions
|
|
@ -455,6 +455,14 @@ class LiteLLMAnthropicMessagesAdapter:
|
|||
)
|
||||
self._add_cache_control_if_applicable(content, tool_result, model)
|
||||
tool_message_list.append(tool_result)
|
||||
elif c.get("type") == "tool_reference":
|
||||
tool_result = ChatCompletionToolMessage(
|
||||
role="tool",
|
||||
tool_call_id=content.get("tool_use_id", ""),
|
||||
content=f"[Loaded tool: {c.get('tool_name', '')}]",
|
||||
)
|
||||
self._add_cache_control_if_applicable(content, tool_result, model)
|
||||
tool_message_list.append(tool_result)
|
||||
elif c.get("type") in ("image", "document"):
|
||||
image_part = self._tool_result_image_part(c.get("source"))
|
||||
tool_result = ChatCompletionToolMessage(
|
||||
|
|
@ -483,6 +491,13 @@ class LiteLLMAnthropicMessagesAdapter:
|
|||
text=c.get("text", ""),
|
||||
)
|
||||
)
|
||||
elif c.get("type") == "tool_reference":
|
||||
combined_content_parts.append(
|
||||
ChatCompletionTextObject(
|
||||
type="text",
|
||||
text=f"[Loaded tool: {c.get('tool_name', '')}]",
|
||||
)
|
||||
)
|
||||
elif c.get("type") in ("image", "document"):
|
||||
image_part = self._tool_result_image_part(c.get("source"))
|
||||
if image_part:
|
||||
|
|
|
|||
|
|
@ -294,7 +294,11 @@ class LiteLLMAnthropicToResponsesAPIAdapter:
|
|||
output_text = inner
|
||||
elif isinstance(inner, list):
|
||||
parts = [
|
||||
c.get("text", "") for c in inner if isinstance(c, dict) and c.get("type") == "text"
|
||||
c.get("text", "")
|
||||
if c.get("type") == "text"
|
||||
else f"[Loaded tool: {c.get('tool_name', '')}]"
|
||||
for c in inner
|
||||
if isinstance(c, dict) and c.get("type") in {"text", "tool_reference"}
|
||||
]
|
||||
output_text = "\n".join(parts)
|
||||
image_candidates = tuple(
|
||||
|
|
|
|||
|
|
@ -324,7 +324,12 @@ class AnthropicMessagesToolResultParam(TypedDict, total=False):
|
|||
is_error: bool
|
||||
content: (
|
||||
str
|
||||
| Iterable[AnthropicMessagesToolResultContent | AnthropicMessagesImageParam | AnthropicMessagesDocumentParam]
|
||||
| Iterable[
|
||||
AnthropicMessagesToolResultContent
|
||||
| AnthropicMessagesImageParam
|
||||
| AnthropicMessagesDocumentParam
|
||||
| ToolReference
|
||||
]
|
||||
)
|
||||
cache_control: dict | ChatCompletionCachedContent | None
|
||||
|
||||
|
|
|
|||
|
|
@ -1610,6 +1610,70 @@ def test_translate_anthropic_messages_to_openai_tool_result_single_item_backward
|
|||
assert tool_message["content"] == "72°F and sunny"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("tool_references", "expected_content"),
|
||||
[
|
||||
(
|
||||
[{"type": "tool_reference", "tool_name": "get_weather"}],
|
||||
"[Loaded tool: get_weather]",
|
||||
),
|
||||
(
|
||||
[
|
||||
{"type": "tool_reference", "tool_name": "get_weather"},
|
||||
{"type": "tool_reference", "tool_name": "search_docs"},
|
||||
],
|
||||
[
|
||||
{"type": "text", "text": "[Loaded tool: get_weather]"},
|
||||
{"type": "text", "text": "[Loaded tool: search_docs]"},
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_translate_anthropic_messages_to_openai_tool_reference_results(
|
||||
tool_references: list[dict[str, str]], expected_content: Any
|
||||
):
|
||||
anthropic_messages = [
|
||||
AnthopicMessagesAssistantMessageParam(
|
||||
role="assistant",
|
||||
content=[
|
||||
{
|
||||
"type": "tool_use",
|
||||
"id": "toolu_tool_search",
|
||||
"name": "ToolSearch",
|
||||
"input": {"query": "weather"},
|
||||
}
|
||||
],
|
||||
),
|
||||
AnthropicMessagesUserMessageParam(
|
||||
role="user",
|
||||
content=[
|
||||
{
|
||||
"type": "tool_result",
|
||||
"tool_use_id": "toolu_tool_search",
|
||||
"content": tool_references,
|
||||
}
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
result = LiteLLMAnthropicMessagesAdapter().translate_anthropic_messages_to_openai(
|
||||
messages=anthropic_messages
|
||||
)
|
||||
|
||||
tool_messages = [
|
||||
message
|
||||
for message in result
|
||||
if isinstance(message, dict) and message.get("role") == "tool"
|
||||
]
|
||||
assert tool_messages == [
|
||||
{
|
||||
"role": "tool",
|
||||
"tool_call_id": "toolu_tool_search",
|
||||
"content": expected_content,
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
def test_streaming_chunk_with_both_text_and_tool_calls_issue_18238():
|
||||
"""
|
||||
When a streaming choice contains both text content and tool_calls,
|
||||
|
|
|
|||
|
|
@ -482,6 +482,33 @@ class TestTranslateMessagesToResponsesInput:
|
|||
result = _translate_messages(messages)
|
||||
assert result[0]["output"] == "Line 1\nLine 2"
|
||||
|
||||
def test_user_tool_result_list_content_preserves_tool_references(self):
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "tool_result",
|
||||
"tool_use_id": "call_search",
|
||||
"content": [
|
||||
{"type": "text", "text": "Available:"},
|
||||
{"type": "tool_reference", "tool_name": "get_weather"},
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
result = _translate_messages(messages)
|
||||
|
||||
assert result == [
|
||||
{
|
||||
"type": "function_call_output",
|
||||
"call_id": "call_search",
|
||||
"output": "Available:\n[Loaded tool: get_weather]",
|
||||
}
|
||||
]
|
||||
|
||||
def test_user_tool_result_null_content(self):
|
||||
"""tool_result with null content becomes empty string output."""
|
||||
messages = [
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue