fix(anthropic.py): handle multiple system prompts

This commit is contained in:
Krrish Dholakia 2024-03-22 18:14:15 -07:00
parent de1f348453
commit 691a83b7dc
3 changed files with 45 additions and 14 deletions

View file

@ -131,18 +131,24 @@ def completion(
) )
else: else:
# Separate system prompt from rest of message # Separate system prompt from rest of message
system_prompt_idx: Optional[int] = None system_prompt_indices = []
system_prompt = ""
for idx, message in enumerate(messages): for idx, message in enumerate(messages):
if message["role"] == "system": if message["role"] == "system":
optional_params["system"] = message["content"] system_prompt += message["content"]
system_prompt_idx = idx system_prompt_indices.append(idx)
break if len(system_prompt_indices) > 0:
if system_prompt_idx is not None: for idx in reversed(system_prompt_indices):
messages.pop(system_prompt_idx) messages.pop(idx)
if len(system_prompt) > 0:
optional_params["system"] = system_prompt
# Format rest of message according to anthropic guidelines # Format rest of message according to anthropic guidelines
messages = prompt_factory( try:
model=model, messages=messages, custom_llm_provider="anthropic" messages = prompt_factory(
) model=model, messages=messages, custom_llm_provider="anthropic"
)
except Exception as e:
raise AnthropicError(status_code=400, message=str(e))
## Load Config ## Load Config
config = litellm.AnthropicConfig.get_config() config = litellm.AnthropicConfig.get_config()

View file

@ -5,6 +5,7 @@ from jinja2 import Template, exceptions, Environment, meta
from typing import Optional, Any from typing import Optional, Any
import imghdr, base64 import imghdr, base64
from typing import List from typing import List
import litellm
def default_pt(messages): def default_pt(messages):
@ -642,11 +643,12 @@ def anthropic_messages_pt(messages: list):
""" """
# add role=tool support to allow function call result/error submission # add role=tool support to allow function call result/error submission
user_message_types = {"user", "tool"} user_message_types = {"user", "tool"}
# reformat messages to ensure user/assistant are alternating, if there's either 2 consecutive 'user' messages or 2 consecutive 'assistant' message, add a blank 'user' or 'assistant' message to ensure compatibility # reformat messages to ensure user/assistant are alternating, if there's either 2 consecutive 'user' messages or 2 consecutive 'assistant' message, merge them.
new_messages = [] new_messages = []
msg_i = 0 msg_i = 0
while msg_i < len(messages): while msg_i < len(messages):
user_content = [] user_content = []
## MERGE CONSECUTIVE USER CONTENT ##
while msg_i < len(messages) and messages[msg_i]["role"] in user_message_types: while msg_i < len(messages) and messages[msg_i]["role"] in user_message_types:
if isinstance(messages[msg_i]["content"], list): if isinstance(messages[msg_i]["content"], list):
for m in messages[msg_i]["content"]: for m in messages[msg_i]["content"]:
@ -680,6 +682,7 @@ def anthropic_messages_pt(messages: list):
new_messages.append({"role": "user", "content": user_content}) new_messages.append({"role": "user", "content": user_content})
assistant_content = [] assistant_content = []
## MERGE CONSECUTIVE ASSISTANT CONTENT ##
while msg_i < len(messages) and messages[msg_i]["role"] == "assistant": while msg_i < len(messages) and messages[msg_i]["role"] == "assistant":
assistant_text = ( assistant_text = (
messages[msg_i].get("content") or "" messages[msg_i].get("content") or ""
@ -697,10 +700,22 @@ def anthropic_messages_pt(messages: list):
if assistant_content: if assistant_content:
new_messages.append({"role": "assistant", "content": assistant_content}) new_messages.append({"role": "assistant", "content": assistant_content})
if (
msg_i < len(messages)
and messages[msg_i]["role"] != user_message_types
and messages[msg_i]["role"] != "assistant"
):
raise Exception(f"Invalid role passed in - {messages[msg_i]}")
if new_messages[0]["role"] != "user": if new_messages[0]["role"] != "user":
new_messages.insert( if litellm.modify_params:
0, {"role": "user", "content": [{"type": "text", "text": "."}]} new_messages.insert(
) 0, {"role": "user", "content": [{"type": "text", "text": "."}]}
)
else:
raise Exception(
"Invalid first message. Should always start with 'role'='user' for Anthropic. System prompt is sent separately for Anthropic. set 'litellm.modify_params = True' or 'litellm_settings:modify_params = True' on proxy, to insert a placeholder user message - '.' as the first message, "
)
if new_messages[-1]["role"] == "assistant": if new_messages[-1]["role"] == "assistant":
for content in new_messages[-1]["content"]: for content in new_messages[-1]["content"]:

View file

@ -7223,7 +7223,17 @@ def exception_type(
message=f"AnthropicException - {original_exception.message}", message=f"AnthropicException - {original_exception.message}",
llm_provider="anthropic", llm_provider="anthropic",
model=model, model=model,
response=original_exception.response, response=(
original_exception.response
if hasattr(original_exception, "response")
else httpx.Response(
status_code=500,
request=httpx.Request(
method="POST",
url="https://docs.anthropic.com/claude/reference/messages_post",
),
)
),
) )
else: else:
exception_mapping_worked = True exception_mapping_worked = True