mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-03 02:22:24 +00:00
test(bedrock): relocate anthropic Claude 3 config tests to official suite for Codecov
This commit is contained in:
parent
6ec8bf4fe9
commit
ce24346526
2 changed files with 220 additions and 220 deletions
|
|
@ -136,223 +136,3 @@ async def test_should_not_fail_with_forwarded_headers_bedrock_invoke_messages():
|
|||
print("INVOKE API RESPONSE: ", response)
|
||||
|
||||
INSTANCE_BASE_ANTHROPIC_MESSAGES_TEST._validate_response(response)
|
||||
|
||||
|
||||
def test_bedrock_anthropic_messages_system_role_transformation():
|
||||
"""
|
||||
Test that system messages in the messages array are correctly extracted and moved
|
||||
to the top-level system parameter for Bedrock.
|
||||
"""
|
||||
config = litellm.AmazonAnthropicClaudeMessagesConfig()
|
||||
|
||||
# 1. Test case: System message in messages array, no existing system param
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{"role": "system", "content": "You are a helpful assistant"},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={"max_tokens": 100},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert req["system"] == [{"type": "text", "text": "You are a helpful assistant"}]
|
||||
|
||||
# 2. Test case: System message in messages array, and existing system param
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{"role": "system", "content": "System message in messages array"},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={
|
||||
"max_tokens": 100,
|
||||
"system": "Existing top-level system message",
|
||||
},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert req["system"] == [
|
||||
{"type": "text", "text": "Existing top-level system message"},
|
||||
{"type": "text", "text": "System message in messages array"},
|
||||
]
|
||||
|
||||
# 3. Test case: Empty system message content (should remove system message from messages, system param unaffected)
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{"role": "system", "content": ""},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={"max_tokens": 100},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert "system" not in req
|
||||
|
||||
# 4. Test case: Non-text items in list content (should only extract text items, ignore non-text)
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": [
|
||||
{"type": "text", "text": "This is text"},
|
||||
{
|
||||
"type": "image",
|
||||
"source": {
|
||||
"type": "base64",
|
||||
"media_type": "image/jpeg",
|
||||
"data": "abc",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={"max_tokens": 100},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert req["system"] == [{"type": "text", "text": "This is text"}]
|
||||
|
||||
# 5. Test case: cache_control in system message (should preserve cache_control)
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "Cached system message",
|
||||
"cache_control": {"type": "ephemeral"},
|
||||
},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={"max_tokens": 100},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert req["system"] == [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "Cached system message",
|
||||
"cache_control": {"type": "ephemeral"},
|
||||
}
|
||||
]
|
||||
|
||||
# 6. Test case: content as list, type text with empty text, cache_control, and list containing non-dict items
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "This is text",
|
||||
"cache_control": {"type": "ephemeral"},
|
||||
},
|
||||
{"type": "text", "text": ""}, # empty text, should be ignored
|
||||
"invalid_non_dict_item", # non-dict item in list, should be ignored
|
||||
],
|
||||
},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={"max_tokens": 100},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert req["system"] == [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "This is text",
|
||||
"cache_control": {"type": "ephemeral"},
|
||||
}
|
||||
]
|
||||
|
||||
# 7. Test case: system_messages_found is True but system_messages_to_add is empty (e.g., content list only has non-text item)
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": [
|
||||
{
|
||||
"type": "image",
|
||||
"source": {
|
||||
"type": "base64",
|
||||
"media_type": "image/jpeg",
|
||||
"data": "abc",
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={"max_tokens": 100},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert "system" not in req
|
||||
|
||||
# 8. Test case: existing_system is empty string
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{"role": "system", "content": "System message"},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={
|
||||
"max_tokens": 100,
|
||||
"system": "",
|
||||
},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert req["system"] == [{"type": "text", "text": "System message"}]
|
||||
|
||||
# 9. Test case: existing_system is list
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{"role": "system", "content": "System message"},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={
|
||||
"max_tokens": 100,
|
||||
"system": [{"type": "text", "text": "Existing list item"}],
|
||||
},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert req["system"] == [
|
||||
{"type": "text", "text": "Existing list item"},
|
||||
{"type": "text", "text": "System message"},
|
||||
]
|
||||
|
||||
# 10. Test case: messages contains elements that are not dicts or do not have role="system"
|
||||
req_data = {
|
||||
"messages": [
|
||||
"not_a_dict_message",
|
||||
{"content": "no_role_key"},
|
||||
{"role": "user", "content": "Hello"},
|
||||
]
|
||||
}
|
||||
config._extract_system_messages_from_messages(req_data)
|
||||
assert req_data["messages"] == [
|
||||
"not_a_dict_message",
|
||||
{"content": "no_role_key"},
|
||||
{"role": "user", "content": "Hello"},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1648,3 +1648,223 @@ async def test_unified_bedrock_messages_sse_usage_and_cost_claude_sonnet_46():
|
|||
custom_llm_provider="bedrock",
|
||||
)
|
||||
assert cost == pytest.approx(0.052150725, rel=0, abs=1e-9)
|
||||
|
||||
|
||||
def test_bedrock_anthropic_messages_system_role_transformation():
|
||||
"""
|
||||
Test that system messages in the messages array are correctly extracted and moved
|
||||
to the top-level system parameter for Bedrock.
|
||||
"""
|
||||
config = AmazonAnthropicClaudeMessagesConfig()
|
||||
|
||||
# 1. Test case: System message in messages array, no existing system param
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{"role": "system", "content": "You are a helpful assistant"},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={"max_tokens": 100},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert req["system"] == [{"type": "text", "text": "You are a helpful assistant"}]
|
||||
|
||||
# 2. Test case: System message in messages array, and existing system param
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{"role": "system", "content": "System message in messages array"},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={
|
||||
"max_tokens": 100,
|
||||
"system": "Existing top-level system message",
|
||||
},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert req["system"] == [
|
||||
{"type": "text", "text": "Existing top-level system message"},
|
||||
{"type": "text", "text": "System message in messages array"},
|
||||
]
|
||||
|
||||
# 3. Test case: Empty system message content (should remove system message from messages, system param unaffected)
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{"role": "system", "content": ""},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={"max_tokens": 100},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert "system" not in req
|
||||
|
||||
# 4. Test case: Non-text items in list content (should only extract text items, ignore non-text)
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": [
|
||||
{"type": "text", "text": "This is text"},
|
||||
{
|
||||
"type": "image",
|
||||
"source": {
|
||||
"type": "base64",
|
||||
"media_type": "image/jpeg",
|
||||
"data": "abc",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={"max_tokens": 100},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert req["system"] == [{"type": "text", "text": "This is text"}]
|
||||
|
||||
# 5. Test case: cache_control in system message (should preserve cache_control)
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "Cached system message",
|
||||
"cache_control": {"type": "ephemeral"},
|
||||
},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={"max_tokens": 100},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert req["system"] == [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "Cached system message",
|
||||
"cache_control": {"type": "ephemeral"},
|
||||
}
|
||||
]
|
||||
|
||||
# 6. Test case: content as list, type text with empty text, cache_control, and list containing non-dict items
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "This is text",
|
||||
"cache_control": {"type": "ephemeral"},
|
||||
},
|
||||
{"type": "text", "text": ""}, # empty text, should be ignored
|
||||
"invalid_non_dict_item", # non-dict item in list, should be ignored
|
||||
],
|
||||
},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={"max_tokens": 100},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert req["system"] == [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "This is text",
|
||||
"cache_control": {"type": "ephemeral"},
|
||||
}
|
||||
]
|
||||
|
||||
# 7. Test case: system_messages_found is True but system_messages_to_add is empty (e.g., content list only has non-text item)
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": [
|
||||
{
|
||||
"type": "image",
|
||||
"source": {
|
||||
"type": "base64",
|
||||
"media_type": "image/jpeg",
|
||||
"data": "abc",
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={"max_tokens": 100},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert "system" not in req
|
||||
|
||||
# 8. Test case: existing_system is empty string
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{"role": "system", "content": "System message"},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={
|
||||
"max_tokens": 100,
|
||||
"system": "",
|
||||
},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert req["system"] == [{"type": "text", "text": "System message"}]
|
||||
|
||||
# 9. Test case: existing_system is list
|
||||
req = config.transform_anthropic_messages_request(
|
||||
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
messages=[
|
||||
{"role": "system", "content": "System message"},
|
||||
{"role": "user", "content": "Hello"},
|
||||
],
|
||||
anthropic_messages_optional_request_params={
|
||||
"max_tokens": 100,
|
||||
"system": [{"type": "text", "text": "Existing list item"}],
|
||||
},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
assert req["messages"] == [{"role": "user", "content": "Hello"}]
|
||||
assert req["system"] == [
|
||||
{"type": "text", "text": "Existing list item"},
|
||||
{"type": "text", "text": "System message"},
|
||||
]
|
||||
|
||||
# 10. Test case: messages contains elements that are not dicts or do not have role="system"
|
||||
req_data = {
|
||||
"messages": [
|
||||
"not_a_dict_message",
|
||||
{"content": "no_role_key"},
|
||||
{"role": "user", "content": "Hello"},
|
||||
]
|
||||
}
|
||||
config._extract_system_messages_from_messages(req_data)
|
||||
assert req_data["messages"] == [
|
||||
"not_a_dict_message",
|
||||
{"content": "no_role_key"},
|
||||
{"role": "user", "content": "Hello"},
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue