mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-10 08:28:25 +00:00
Merge cd08abb92d into d5ca88900c
This commit is contained in:
commit
9d63ffb3c5
7 changed files with 85 additions and 3 deletions
|
|
@ -1750,11 +1750,9 @@ def convert_to_gemini_tool_call_result(
|
|||
# Not valid JSON, wrap in content field
|
||||
response_data = {"content": content_str}
|
||||
|
||||
# We can't determine from openai message format whether it's a successful or
|
||||
# error call result so default to the successful result template
|
||||
_function_response: Final = VertexFunctionResponse(
|
||||
name=name,
|
||||
response=response_data,
|
||||
response={"error": content_str} if message.get("is_error") is True else response_data,
|
||||
)
|
||||
if gemini_call_id:
|
||||
_function_response["id"] = gemini_call_id
|
||||
|
|
|
|||
|
|
@ -562,6 +562,11 @@ class LiteLLMAnthropicMessagesAdapter:
|
|||
content=self._tool_result_content(content.get("content")),
|
||||
)
|
||||
self._add_cache_control_if_applicable(content, tool_result, model)
|
||||
tool_result_block = cast(Mapping[str, object], content) # cast-ok: untrusted client payload
|
||||
if tool_result_block.get("is_error") is True and self.target_consumes_tool_error(
|
||||
model, custom_llm_provider
|
||||
):
|
||||
tool_result["is_error"] = True
|
||||
tool_message_list.append(tool_result)
|
||||
|
||||
if len(tool_message_list) > 0:
|
||||
|
|
@ -737,6 +742,13 @@ class LiteLLMAnthropicMessagesAdapter:
|
|||
def target_consumes_cache_control(cls, model: str) -> bool:
|
||||
return cls.is_anthropic_claude_model(model) or cls.is_bedrock_arn_model(model) or "gemini" in model.lower()
|
||||
|
||||
@staticmethod
|
||||
def target_consumes_tool_error(model: str | None, custom_llm_provider: str | None) -> bool:
|
||||
# Decide on the provider alone: aliased model names ("prod-model" routed to
|
||||
# gemini) carry no "gemini" substring.
|
||||
provider: Final = custom_llm_provider or (model.split("/", 1)[0] if model and "/" in model else None)
|
||||
return provider in ("gemini", "vertex_ai", "vertex_ai_beta")
|
||||
|
||||
@staticmethod
|
||||
def translate_thinking_for_model(
|
||||
thinking: AnthropicThinkingParam,
|
||||
|
|
|
|||
|
|
@ -49412,6 +49412,10 @@
|
|||
],
|
||||
"title": "Content"
|
||||
},
|
||||
"is_error": {
|
||||
"title": "Is Error",
|
||||
"type": "boolean"
|
||||
},
|
||||
"role": {
|
||||
"const": "tool",
|
||||
"title": "Role",
|
||||
|
|
|
|||
|
|
@ -957,6 +957,7 @@ class ChatCompletionToolMessage(TypedDict):
|
|||
role: Literal["tool"]
|
||||
content: str | Iterable[ToolMessageContentPart] # writable-ok: Pydantic warns on ReadOnly TypedDict fields
|
||||
tool_call_id: str
|
||||
is_error: NotRequired[bool] # writable-ok: Pydantic warns on ReadOnly TypedDict fields
|
||||
|
||||
|
||||
class ChatCompletionFunctionMessage(TypedDict):
|
||||
|
|
|
|||
|
|
@ -2279,6 +2279,36 @@ def test_convert_gemini_tool_call_result_with_data_url_extra_params():
|
|||
)
|
||||
|
||||
|
||||
def test_convert_gemini_tool_call_result_error_goes_to_response_error():
|
||||
"""https://github.com/BerriAI/litellm/issues/44979"""
|
||||
last_message_with_tool_calls = {
|
||||
"role": "assistant",
|
||||
"content": "",
|
||||
"tool_calls": [
|
||||
{
|
||||
"id": "call_1",
|
||||
"type": "function",
|
||||
"index": 0,
|
||||
"function": {"name": "deploy", "arguments": "{}"},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
failed = convert_to_gemini_tool_call_result(
|
||||
message=ChatCompletionToolMessage(
|
||||
role="tool", tool_call_id="call_1", content="exit code 1: migration failed", is_error=True
|
||||
),
|
||||
last_message_with_tool_calls=last_message_with_tool_calls,
|
||||
)
|
||||
succeeded = convert_to_gemini_tool_call_result(
|
||||
message=ChatCompletionToolMessage(role="tool", tool_call_id="call_1", content="deployed"),
|
||||
last_message_with_tool_calls=last_message_with_tool_calls,
|
||||
)
|
||||
|
||||
assert failed["function_response"]["response"] == {"error": "exit code 1: migration failed"}
|
||||
assert succeeded["function_response"]["response"] == {"content": "deployed"}
|
||||
|
||||
|
||||
def _gemini_tool_result_fixture(
|
||||
content: str,
|
||||
) -> tuple[ChatCompletionToolMessage, dict]:
|
||||
|
|
|
|||
|
|
@ -2736,6 +2736,41 @@ def test_cache_control_not_preserved_in_tool_result_for_non_claude():
|
|||
assert "cache_control" not in tool_message
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model,custom_llm_provider,keeps_is_error",
|
||||
[
|
||||
("gemini/gemini-3.5-flash-lite", None, True),
|
||||
("gemini-3.5-flash-lite", "vertex_ai", True),
|
||||
("gpt-4", "openai", False),
|
||||
("openrouter/google/gemini-3.5-flash-lite", None, False),
|
||||
("prod-model", "gemini", True),
|
||||
],
|
||||
)
|
||||
def test_tool_result_is_error_kept_only_for_gemini_targets(model, custom_llm_provider, keeps_is_error):
|
||||
"""https://github.com/BerriAI/litellm/issues/44979"""
|
||||
anthropic_messages = [
|
||||
AnthropicMessagesUserMessageParam(
|
||||
role="user",
|
||||
content=[
|
||||
{
|
||||
"type": "tool_result",
|
||||
"tool_use_id": "toolu_1",
|
||||
"content": "exit code 1: migration failed",
|
||||
"is_error": True,
|
||||
}
|
||||
],
|
||||
)
|
||||
]
|
||||
|
||||
result = LiteLLMAnthropicMessagesAdapter().translate_anthropic_messages_to_openai(
|
||||
messages=anthropic_messages, model=model, custom_llm_provider=custom_llm_provider
|
||||
)
|
||||
|
||||
tool_message = next(msg for msg in result if msg.get("role") == "tool")
|
||||
assert tool_message["content"] == "exit code 1: migration failed"
|
||||
assert tool_message.get("is_error") is (True if keeps_is_error else None)
|
||||
|
||||
|
||||
def test_cache_control_preserved_in_assistant_text_for_claude():
|
||||
"""Cache control should be preserved in assistant text blocks for Claude models."""
|
||||
anthropic_messages = [
|
||||
|
|
|
|||
2
ui/litellm-dashboard/src/lib/http/schema.d.ts
generated
vendored
2
ui/litellm-dashboard/src/lib/http/schema.d.ts
generated
vendored
|
|
@ -29462,6 +29462,8 @@ export interface components {
|
|||
ChatCompletionToolMessage: {
|
||||
/** Content */
|
||||
content: string | (components["schemas"]["ChatCompletionTextObject"] | components["schemas"]["ChatCompletionImageObject"] | components["schemas"]["ChatCompletionAudioObject"] | components["schemas"]["ChatCompletionFileObject"] | components["schemas"]["ChatCompletionToolReferenceObject"])[];
|
||||
/** Is Error */
|
||||
is_error?: boolean;
|
||||
/**
|
||||
* Role
|
||||
* @constant
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue