diff --git a/litellm/llms/prompt_templates/factory.py b/litellm/llms/prompt_templates/factory.py index dc4c417cd37..908aebef9a9 100644 --- a/litellm/llms/prompt_templates/factory.py +++ b/litellm/llms/prompt_templates/factory.py @@ -18,6 +18,7 @@ from litellm.types.completion import ( ChatCompletionMessageParam, ChatCompletionFunctionMessageParam, ChatCompletionMessageToolCallParam, + ChatCompletionToolMessageParam, ) from litellm.types.llms.anthropic import * import uuid @@ -1034,6 +1035,40 @@ def anthropic_messages_pt(messages: list): msg_i += 1 + ## MERGE CONSECUTIVE TOOL CONTENT ## + while msg_i < len(messages) and messages[msg_i]["role"] == "tool": + """ + Anthropic function message: "role", "name", "input", "id" + OpenAI function message: "content", "name", "role" + + - Check if received message is a tool call input or model text response + """ + tool_use_param = True + _message = ChatCompletionToolMessageParam(**messages[msg_i]) # type: ignore + anthropic_tool_message: Optional[ + AnthropicMessagesAssistantMessageValues + ] = None + + try: + anthropic_tool_message = AnthopicMessagesAssistantMessageToolCallParam( + type="tool_use" + ) + anthropic_tool_message["input"] = json.loads(_message["content"]) + anthropic_tool_message["id"] = _message["tool_call_id"] + anthropic_tool_message["name"] = _message["name"] + except Exception as e: + litellm.print_verbose( + "Invalid dictionary content. Treating as text instead." + ) + anthropic_tool_message = ( + AnthopicMessagesAssistantMessageTextContentParam(type="text") + ) + anthropic_tool_message["text"] = _message["content"] + + assistant_content.append(anthropic_tool_message) # type: ignore + + msg_i += 1 + if assistant_content: new_messages.append({"role": "assistant", "content": assistant_content}) diff --git a/litellm/tests/test_completion.py b/litellm/tests/test_completion.py index 1108db860d4..c0b4e3136d5 100644 --- a/litellm/tests/test_completion.py +++ b/litellm/tests/test_completion.py @@ -2367,7 +2367,17 @@ def test_completion_with_fallbacks(): ], ], ) -def test_completion_anthropic_hanging(function_call): +@pytest.mark.parametrize( + "tool_call", + [ + [{"role": "tool", "tool_call_id": "1234", "content": "Kokoko"}], + [ + {"role": "tool", "tool_call_id": "12344", "content": "Kokoko"}, + {"role": "tool", "tool_call_id": "1214", "content": "Kokoko"}, + ], + ], +) +def test_completion_anthropic_hanging(function_call, tool_call): litellm.modify_params = True messages = [ { @@ -2382,7 +2392,7 @@ def test_completion_anthropic_hanging(function_call): }, }, ] - messages = messages + function_call + messages = messages + function_call + tool_call litellm.completion( model="claude-3-haiku-20240307", messages=messages,