forked from phoenix/litellm-mirror
Merge pull request #3478 from nkvch/Issue-#3474-anthropic-roles-alternation-issue
* feat(factory.py): add support for merging consecutive messages of one role when separated with empty message of another role
This commit is contained in:
commit
a325bf2fb8
3 changed files with 71 additions and 30 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
.venv
|
.venv
|
||||||
|
venv
|
||||||
.env
|
.env
|
||||||
litellm_uuid.txt
|
litellm_uuid.txt
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
|
|
@ -1,27 +1,23 @@
|
||||||
from enum import Enum
|
import json
|
||||||
import requests, traceback
|
import re
|
||||||
import json, re, xml.etree.ElementTree as ET
|
import traceback
|
||||||
from jinja2 import Template, exceptions, meta, BaseLoader
|
|
||||||
from jinja2.sandbox import ImmutableSandboxedEnvironment
|
|
||||||
from typing import (
|
|
||||||
Any,
|
|
||||||
List,
|
|
||||||
Mapping,
|
|
||||||
MutableMapping,
|
|
||||||
Optional,
|
|
||||||
Sequence,
|
|
||||||
)
|
|
||||||
import litellm
|
|
||||||
from litellm.types.completion import (
|
|
||||||
ChatCompletionUserMessageParam,
|
|
||||||
ChatCompletionSystemMessageParam,
|
|
||||||
ChatCompletionMessageParam,
|
|
||||||
ChatCompletionFunctionMessageParam,
|
|
||||||
ChatCompletionMessageToolCallParam,
|
|
||||||
ChatCompletionToolMessageParam,
|
|
||||||
)
|
|
||||||
from litellm.types.llms.anthropic import *
|
|
||||||
import uuid
|
import uuid
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Any, List, Mapping, MutableMapping, Optional, Sequence
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from jinja2 import BaseLoader, Template, exceptions, meta
|
||||||
|
from jinja2.sandbox import ImmutableSandboxedEnvironment
|
||||||
|
|
||||||
|
import litellm
|
||||||
|
from litellm.types.completion import (ChatCompletionFunctionMessageParam,
|
||||||
|
ChatCompletionMessageParam,
|
||||||
|
ChatCompletionMessageToolCallParam,
|
||||||
|
ChatCompletionSystemMessageParam,
|
||||||
|
ChatCompletionToolMessageParam,
|
||||||
|
ChatCompletionUserMessageParam)
|
||||||
|
from litellm.types.llms.anthropic import *
|
||||||
|
|
||||||
|
|
||||||
def default_pt(messages):
|
def default_pt(messages):
|
||||||
|
@ -603,9 +599,10 @@ def construct_tool_use_system_prompt(
|
||||||
|
|
||||||
|
|
||||||
def convert_url_to_base64(url):
|
def convert_url_to_base64(url):
|
||||||
import requests
|
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
for _ in range(3):
|
for _ in range(3):
|
||||||
try:
|
try:
|
||||||
response = requests.get(url)
|
response = requests.get(url)
|
||||||
|
@ -984,6 +981,7 @@ def anthropic_messages_pt(messages: list):
|
||||||
new_messages = []
|
new_messages = []
|
||||||
msg_i = 0
|
msg_i = 0
|
||||||
tool_use_param = False
|
tool_use_param = False
|
||||||
|
merge_with_previous = False
|
||||||
while msg_i < len(messages):
|
while msg_i < len(messages):
|
||||||
user_content = []
|
user_content = []
|
||||||
init_msg_i = msg_i
|
init_msg_i = msg_i
|
||||||
|
@ -1016,7 +1014,13 @@ def anthropic_messages_pt(messages: list):
|
||||||
msg_i += 1
|
msg_i += 1
|
||||||
|
|
||||||
if user_content:
|
if user_content:
|
||||||
|
if merge_with_previous:
|
||||||
|
new_messages[-1]["content"].extend(user_content)
|
||||||
|
merge_with_previous = False
|
||||||
|
else:
|
||||||
new_messages.append({"role": "user", "content": user_content})
|
new_messages.append({"role": "user", "content": user_content})
|
||||||
|
elif msg_i > 0:
|
||||||
|
merge_with_previous = True
|
||||||
|
|
||||||
assistant_content = []
|
assistant_content = []
|
||||||
## MERGE CONSECUTIVE ASSISTANT CONTENT ##
|
## MERGE CONSECUTIVE ASSISTANT CONTENT ##
|
||||||
|
@ -1044,7 +1048,13 @@ def anthropic_messages_pt(messages: list):
|
||||||
msg_i += 1
|
msg_i += 1
|
||||||
|
|
||||||
if assistant_content:
|
if assistant_content:
|
||||||
|
if merge_with_previous:
|
||||||
|
new_messages[-1]["content"].extend(assistant_content)
|
||||||
|
merge_with_previous = False
|
||||||
|
else:
|
||||||
new_messages.append({"role": "assistant", "content": assistant_content})
|
new_messages.append({"role": "assistant", "content": assistant_content})
|
||||||
|
elif msg_i > 0:
|
||||||
|
merge_with_previous = True
|
||||||
|
|
||||||
if msg_i == init_msg_i: # prevent infinite loops
|
if msg_i == init_msg_i: # prevent infinite loops
|
||||||
raise Exception(
|
raise Exception(
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
import sys, os
|
import os
|
||||||
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
import os, io
|
import io
|
||||||
|
import os
|
||||||
|
|
||||||
sys.path.insert(
|
sys.path.insert(
|
||||||
0, os.path.abspath("../..")
|
0, os.path.abspath("../..")
|
||||||
) # Adds the parent directory to the, system path
|
) # Adds the parent directory to the, system path
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import litellm
|
import litellm
|
||||||
from litellm import embedding, completion, completion_cost, Timeout
|
from litellm import (RateLimitError, Timeout, completion, completion_cost,
|
||||||
from litellm import RateLimitError
|
embedding)
|
||||||
from litellm.llms.prompt_templates.factory import anthropic_messages_pt
|
from litellm.llms.prompt_templates.factory import anthropic_messages_pt
|
||||||
|
|
||||||
# litellm.num_retries=3
|
# litellm.num_retries=3
|
||||||
|
@ -163,6 +167,32 @@ def test_completion_claude_3():
|
||||||
pytest.fail(f"Error occurred: {e}")
|
pytest.fail(f"Error occurred: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def test_completion_claude_3_empty_message():
|
||||||
|
litellm.set_verbose = True
|
||||||
|
messages = [{'role': 'user', 'content': 'please create a logo for a modern AI app. create in SVG format'},
|
||||||
|
{'role': 'assistant', 'content': "To create a logo for a modern AI app in SVG format, I'll use the DALL-E 3 Image Generator."},
|
||||||
|
{'role': 'user', 'content': 'output SVG'},
|
||||||
|
{'role': 'assistant', 'content': 'To generate a logo for a modern AI app in SVG format using DALL-E 3, I need to:\n1. Craft a detailed prompt describing the desired logo style and elements\n2. Specify the image size (SVG is vector-based, so size is less relevant)\n3. Call the generate_image function with the prompt and size\n4. Display the generated SVG logo using the provided syntax\nThe prompt should include keywords related to AI, modern design, and SVG format. Some key elements to incorporate could be a brain symbol, circuit lines, or a robot icon, using a minimalist style and a blue color scheme often associated with technology and intelligence.',
|
||||||
|
'tool_calls': [
|
||||||
|
{'id': 'toolu_01KEUtRVySSeMrf3g7rCA12E', 'type': 'function', 'function': {'name': 'python_tool', 'arguments': '{"code": "...python code..."}'}}
|
||||||
|
]},
|
||||||
|
{'role': 'tool', 'content': '...python output...', 'tool_call_id': 'toolu_01KEUtRVySSeMrf3g7rCA12E'},
|
||||||
|
{'role': 'assistant', 'content': ''}, # empty message appended by model after tool call response
|
||||||
|
{'role': 'user', 'content': 'write SVG source youself!'},
|
||||||
|
]
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = completion(
|
||||||
|
model="anthropic/claude-3-opus-20240229",
|
||||||
|
messages=messages,
|
||||||
|
stream=True,
|
||||||
|
tools=[{'type': 'function', 'function': {'name': 'python_tool', 'description': 'Execute code', 'parameters': {'type': 'object', 'properties': {'headline': {'description': 'Must have. Title of this tool call (maximum 15 characters).', 'type': 'string'}, 'code': {'description': 'Python code to execute.', 'type': 'string'}}, 'required': ['code', 'headline']}}}]
|
||||||
|
)
|
||||||
|
print(response)
|
||||||
|
except Exception as e:
|
||||||
|
pytest.fail(f"Error occurred: {e}")
|
||||||
|
|
||||||
|
|
||||||
def test_completion_claude_3_function_call():
|
def test_completion_claude_3_function_call():
|
||||||
litellm.set_verbose = True
|
litellm.set_verbose = True
|
||||||
tools = [
|
tools = [
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue