mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-23 05:34:41 +00:00
Merge ec7ffe3b36 into 415b84232f
This commit is contained in:
commit
090e90b184
2 changed files with 121 additions and 1 deletions
|
|
@ -529,10 +529,16 @@ class LiteLLMAnthropicMessagesAdapter:
|
|||
self._add_cache_control_if_applicable(content, doc_obj, model)
|
||||
new_user_content_list.append(doc_obj)
|
||||
elif content.get("type") == "tool_result":
|
||||
raw_tool_result_content: Final = self._tool_result_content(content.get("content"))
|
||||
tool_result_content: Final = (
|
||||
self._mark_tool_result_as_error(raw_tool_result_content)
|
||||
if content.get("is_error")
|
||||
else raw_tool_result_content
|
||||
)
|
||||
tool_result = ChatCompletionToolMessage(
|
||||
role="tool",
|
||||
tool_call_id=content.get("tool_use_id", ""),
|
||||
content=self._tool_result_content(content.get("content")),
|
||||
content=tool_result_content,
|
||||
)
|
||||
self._add_cache_control_if_applicable(content, tool_result, model)
|
||||
tool_message_list.append(tool_result)
|
||||
|
|
@ -1321,6 +1327,20 @@ class LiteLLMAnthropicMessagesAdapter:
|
|||
case _:
|
||||
return list(parts)
|
||||
|
||||
@staticmethod
|
||||
def _mark_tool_result_as_error(content: ToolResultContent) -> ToolResultContent:
|
||||
"""Keep Anthropic's `is_error` signal visible.
|
||||
|
||||
Chat Completions tool messages have no error field, so encode the
|
||||
flag into the content itself; models and downstream provider
|
||||
mappings can then still tell the tool call failed.
|
||||
"""
|
||||
if isinstance(content, str):
|
||||
return "[tool error] " + content if content else "[tool error]"
|
||||
if isinstance(content, list):
|
||||
return [ChatCompletionTextObject(type="text", text="[tool error] "), *content]
|
||||
return content
|
||||
|
||||
def _tool_result_part(self, item: object) -> ToolMessageContentPart | None:
|
||||
if isinstance(item, str):
|
||||
return ChatCompletionTextObject(type="text", text=item)
|
||||
|
|
|
|||
|
|
@ -4712,6 +4712,106 @@ def test_tool_result_without_translatable_content_still_answers_its_tool_use(too
|
|||
assert result[0]["role"] == "assistant"
|
||||
|
||||
|
||||
def test_tool_result_is_error_is_encoded_in_string_content():
|
||||
adapter = LiteLLMAnthropicMessagesAdapter()
|
||||
|
||||
result = adapter.translate_anthropic_messages_to_openai(
|
||||
messages=[
|
||||
_anthropic_tool_use_turn("toolu_01"),
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "tool_result",
|
||||
"tool_use_id": "toolu_01",
|
||||
"content": "deploy failed",
|
||||
"is_error": True,
|
||||
}
|
||||
],
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
assert result[1] == {
|
||||
"role": "tool",
|
||||
"tool_call_id": "toolu_01",
|
||||
"content": "[tool error] deploy failed",
|
||||
}
|
||||
|
||||
|
||||
def test_tool_result_is_error_puts_the_marker_first_in_part_lists():
|
||||
adapter = LiteLLMAnthropicMessagesAdapter()
|
||||
|
||||
result = adapter.translate_anthropic_messages_to_openai(
|
||||
messages=[
|
||||
_anthropic_tool_use_turn("toolu_01"),
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "tool_result",
|
||||
"tool_use_id": "toolu_01",
|
||||
"content": [{"type": "text", "text": "boom"}, _tool_reference_block()],
|
||||
"is_error": True,
|
||||
}
|
||||
],
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
assert result[1]["content"] == [
|
||||
{"type": "text", "text": "[tool error] "},
|
||||
{"type": "text", "text": "boom"},
|
||||
{"type": "tool_reference", "tool_name": "WebFetch"},
|
||||
]
|
||||
|
||||
|
||||
def test_tool_result_is_error_with_empty_content_keeps_the_marker():
|
||||
adapter = LiteLLMAnthropicMessagesAdapter()
|
||||
|
||||
result = adapter.translate_anthropic_messages_to_openai(
|
||||
messages=[
|
||||
_anthropic_tool_use_turn("toolu_01"),
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "tool_result",
|
||||
"tool_use_id": "toolu_01",
|
||||
"content": "",
|
||||
"is_error": True,
|
||||
}
|
||||
],
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
assert result[1]["content"] == "[tool error]"
|
||||
|
||||
|
||||
def test_tool_result_without_is_error_keeps_content_unchanged():
|
||||
adapter = LiteLLMAnthropicMessagesAdapter()
|
||||
|
||||
result = adapter.translate_anthropic_messages_to_openai(
|
||||
messages=[
|
||||
_anthropic_tool_use_turn("toolu_01"),
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "tool_result",
|
||||
"tool_use_id": "toolu_01",
|
||||
"content": "deploy succeeded",
|
||||
"is_error": False,
|
||||
}
|
||||
],
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
assert result[1]["content"] == "deploy succeeded"
|
||||
|
||||
|
||||
def _openai_response_with_usage(usage: Usage) -> ModelResponse:
|
||||
return ModelResponse(
|
||||
id="resp_web_search",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue