This commit is contained in:
Deepanshu Pal 2026-10-04 18:30:03 -04:00 • committed by GitHub
commit acf653b8f8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 65 additions and 0 deletions

View file

@ -636,6 +636,25 @@ class LiteLLMAnthropicMessagesAdapter:
assistant_message["reasoning_content"] = reasoning_content
new_messages.append(assistant_message)
has_conversational_input = any(m.get("role") != "system" for m in replayable_messages)
has_translated_conversation = any(m.get("role") != "system" for m in new_messages)
if has_conversational_input and not has_translated_conversation:
unrecognized_block_types = sorted(
{
str(content.get("type"))
for message in replayable_messages
if message.get("role") != "system" and isinstance(message.get("content"), list)
for content in message["content"]
if isinstance(content, dict) and content.get("type") is not None
}
)
type_list = ", ".join(json.dumps(block_type) for block_type in unrecognized_block_types) or "unknown"
raise litellm.BadRequestError(
message=f"Anthropic pass-through: every message's content blocks were of unrecognized types ({type_list}), so translation produced an empty conversation. Refusing to dispatch a request with no messages.",
model=model or "",
llm_provider="anthropic",
)
return new_messages
@staticmethod

View file

@ -5167,3 +5167,49 @@ def test_eager_input_streaming_tool_reaches_bedrock_converse_as_beta():
assert data["additionalModelRequestFields"]["anthropic_beta"] == ["fine-grained-tool-streaming-2025-05-14"]
assert data["toolConfig"]["tools"][0]["toolSpec"]["inputSchema"]["json"] == EAGER_INPUT_SCHEMA
def test_translate_anthropic_to_openai_rejects_all_unrecognized_content_blocks():
request = {
"model": "openai/gpt-4o",
"max_tokens": 1024,
"messages": [{"role": "user", "content": [{"type": "not_a_real_block", "text": "hello"}]}],
}
with pytest.raises(litellm.BadRequestError, match="not_a_real_block"):
LiteLLMAnthropicMessagesAdapter().translate_anthropic_to_openai(request)
control_chars = {
**request,
"messages": [{"role": "user", "content": [{"type": "forged\nERROR: injected"}]}],
}
with pytest.raises(litellm.BadRequestError) as exc_info:
LiteLLMAnthropicMessagesAdapter().translate_anthropic_to_openai(control_chars)
assert "forged\\nERROR: injected" in str(exc_info.value)
assert "forged\nERROR: injected" not in str(exc_info.value)
with_system = {
**request,
"messages": [
{"role": "system", "content": "keep this"},
*request["messages"],
],
}
with pytest.raises(litellm.BadRequestError):
LiteLLMAnthropicMessagesAdapter().translate_anthropic_to_openai(with_system)
mixed = {
"model": "openai/gpt-4o",
"max_tokens": 1024,
"messages": [
{
"role": "user",
"content": [
{"type": "not_a_real_block", "text": "ignored"},
{"type": "text", "text": "hello"},
],
}
],
}
openai_request, _ = LiteLLMAnthropicMessagesAdapter().translate_anthropic_to_openai(mixed)
assert openai_request["messages"] == [{"role": "user", "content": [{"type": "text", "text": "hello"}]}]