Add e2e tests for checking if all beta headers in the mapping works

This commit is contained in:
Sameer Kankute 2026-02-13 15:46:21 +05:30
parent 5075b8e2ee
commit f2c7156512
4 changed files with 191 additions and 11 deletions

View file

@ -3600,6 +3600,7 @@ jobs:
-e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
-e AWS_REGION_NAME="us-east-1" \
-e LITELLM_LOCAL_ANTHROPIC_BETA_HEADERS="True" \
--add-host host.docker.internal:host-gateway \
--name my-app \
-v $(pwd)/tests/proxy_e2e_anthropic_messages_tests/test_config.yaml:/app/config.yaml \

View file

@ -2,8 +2,8 @@
"description": "Mapping of Anthropic beta headers for each provider. Keys are input header names, values are provider-specific header names (or null if unsupported). Only headers present in mapping keys with non-null values can be forwarded.",
"anthropic": {
"advanced-tool-use-2025-11-20": "advanced-tool-use-2025-11-20",
"bash_20241022": "bash_20241022",
"bash_20250124": "bash_20250124",
"bash_20241022": null,
"bash_20250124": null,
"code-execution-2025-08-25": "code-execution-2025-08-25",
"compact-2026-01-12": "compact-2026-01-12",
"computer-use-2025-01-24": "computer-use-2025-01-24",
@ -13,26 +13,26 @@
"effort-2025-11-24": "effort-2025-11-24",
"fast-mode-2026-02-01": "fast-mode-2026-02-01",
"files-api-2025-04-14": "files-api-2025-04-14",
"structured-output-2024-03-01": "structured-output-2024-03-01",
"structured-output-2024-03-01": null,
"fine-grained-tool-streaming-2025-05-14": "fine-grained-tool-streaming-2025-05-14",
"interleaved-thinking-2025-05-14": "interleaved-thinking-2025-05-14",
"mcp-client-2025-11-20": "mcp-client-2025-11-20",
"mcp-client-2025-04-04": "mcp-client-2025-04-04",
"mcp-servers-2025-12-04": "mcp-servers-2025-12-04",
"mcp-servers-2025-12-04": null,
"output-128k-2025-02-19": "output-128k-2025-02-19",
"prompt-caching-scope-2026-01-05": "prompt-caching-scope-2026-01-05",
"skills-2025-10-02": "skills-2025-10-02",
"structured-outputs-2025-11-13": "structured-outputs-2025-11-13",
"text_editor_20241022": "text_editor_20241022",
"text_editor_20250124": "text_editor_20250124",
"text_editor_20241022": null,
"text_editor_20250124": null,
"token-efficient-tools-2025-02-19": "token-efficient-tools-2025-02-19",
"web-fetch-2025-09-10": "web-fetch-2025-09-10",
"web-search-2025-03-05": "web-search-2025-03-05"
},
"azure_ai": {
"advanced-tool-use-2025-11-20": "advanced-tool-use-2025-11-20",
"bash_20241022": "bash_20241022",
"bash_20250124": "bash_20250124",
"bash_20241022": null,
"bash_20250124": null,
"code-execution-2025-08-25": "code-execution-2025-08-25",
"compact-2026-01-12": null,
"computer-use-2025-01-24": "computer-use-2025-01-24",
@ -46,7 +46,7 @@
"interleaved-thinking-2025-05-14": "interleaved-thinking-2025-05-14",
"mcp-client-2025-11-20": "mcp-client-2025-11-20",
"mcp-client-2025-04-04": "mcp-client-2025-04-04",
"mcp-servers-2025-12-04": "mcp-servers-2025-12-04",
"mcp-servers-2025-12-04": null,
"output-128k-2025-02-19": null,
"structured-output-2024-03-01": null,
"prompt-caching-scope-2026-01-05": "prompt-caching-scope-2026-01-05",
@ -59,7 +59,7 @@
"web-search-2025-03-05": "web-search-2025-03-05"
},
"bedrock_converse": {
"advanced-tool-use-2025-11-20": "tool-search-tool-2025-10-19",
"advanced-tool-use-2025-11-20": null,
"bash_20241022": null,
"bash_20250124": null,
"code-execution-2025-08-25": null,
@ -84,7 +84,7 @@
"text_editor_20241022": null,
"text_editor_20250124": null,
"token-efficient-tools-2025-02-19": null,
"tool-search-tool-2025-10-19": "tool-search-tool-2025-10-19",
"tool-search-tool-2025-10-19": null,
"web-fetch-2025-09-10": null,
"web-search-2025-03-05": null
},

View file

@ -0,0 +1,169 @@
"""
This test ensures that the proxy can passthrough anthropic requests
"""
from pathlib import Path
import pytest
import aiohttp
import json
def get_all_supported_anthropic_beta_headers(provider: str):
config_path = (
Path(__file__).resolve().parents[2]
/ "litellm"
/ "anthropic_beta_headers_config.json"
)
with open(config_path, "r") as f:
config = json.load(f)
anthropic_mapping = config.get(provider, {})
# Only include headers that have a non-null mapping value
return [
header_name
for header_name, provider_value in anthropic_mapping.items()
if provider_value is not None
]
@pytest.mark.asyncio
@pytest.mark.flaky(retries=3, delay=2)
@pytest.mark.parametrize(
"model_name,provider_name",
[
("claude-sonnet-4-5-20250929", "anthropic"),
("azure-ai-claude-opus-4.5", "azure_ai"),
("vertex-ai-claude-opus-4-6", "vertex_ai"),
],
)
async def test_anthropic_messages_with_all_beta_headers(model_name, provider_name):
"""
Test that v1/messages endpoint works with all non-null Anthropic beta headers
and doesn't throw errors
"""
print("Testing v1/messages with all non-null Anthropic beta headers")
headers = {
"Authorization": "Bearer sk-1234",
"Content-Type": "application/json",
"anthropic-version": "2023-06-01",
"anthropic-beta": ",".join(get_all_supported_anthropic_beta_headers(provider_name)),
}
payload = {
"model": model_name,
"max_tokens": 10,
"messages": [{"role": "user", "content": "Say 'hello' and nothing else"}],
"tools": [{
"type": "code_execution_20250825",
"name": "code_execution"
}]
}
async with aiohttp.ClientSession() as session:
async with session.post(
"http://0.0.0.0:4000/v1/messages",
json=payload,
headers=headers
) as response:
response_text = await response.text()
print(f"Response status: {response.status}")
print(f"Response text: {response_text}")
# The request should succeed without errors
assert response.status == 200, f"Request should succeed, got status {response.status}: {response_text}"
response_json = await response.json()
print(f"Response JSON: {json.dumps(response_json, indent=4, default=str)}")
# Basic response validation
assert "id" in response_json, "Response should have an id"
assert "content" in response_json, "Response should have content"
assert "model" in response_json, "Response should have model"
assert "usage" in response_json, "Response should have usage"
# Verify usage information
usage = response_json["usage"]
assert "input_tokens" in usage, "Usage should have input_tokens"
assert "output_tokens" in usage, "Usage should have output_tokens"
assert usage["input_tokens"] > 0, "Should have some input tokens"
assert usage["output_tokens"] > 0, "Should have some output tokens"
print(f"✅ Test passed: Request with all beta headers succeeded")
print(f" Model: {response_json['model']}")
print(f" Input tokens: {usage['input_tokens']}")
print(f" Output tokens: {usage['output_tokens']}")
@pytest.mark.asyncio
@pytest.mark.flaky(retries=3, delay=2)
@pytest.mark.parametrize(
"model_name,provider_name",
[
("bedrock-claude-opus-4.5", "bedrock"),
("bedrock-converse-claude-sonnet-4.5", "bedrock_converse")
],
)
async def test_bedrock_invoke_messages_with_all_beta_headers(
model_name, provider_name
):
"""
Test that v1/messages endpoint works with all non-null Anthropic beta headers
for both bedrock and bedrock_converse providers.
"""
print(f"Testing v1/messages for model={model_name}, provider={provider_name}")
beta_headers = get_all_supported_anthropic_beta_headers(provider_name)
headers = {
"Authorization": "Bearer sk-1234",
"Content-Type": "application/json",
"anthropic-version": "2023-06-01",
"anthropic-beta": ",".join(beta_headers),
}
payload = {
"model": model_name,
"max_tokens": 10,
"messages": [
{"role": "user", "content": "Say 'hello' and nothing else"}
],
}
async with aiohttp.ClientSession() as session:
async with session.post(
"http://0.0.0.0:4000/v1/messages",
json=payload,
headers=headers,
) as response:
response_text = await response.text()
print(f"Response status: {response.status}")
print(f"Response text: {response_text}")
assert (
response.status == 200
), f"{provider_name} request failed: {response.status}: {response_text}"
response_json = await response.json()
# Basic response validation
assert "id" in response_json
assert "content" in response_json
assert "model" in response_json
assert "usage" in response_json
usage = response_json["usage"]
assert "input_tokens" in usage
assert "output_tokens" in usage
assert usage["input_tokens"] > 0
assert usage["output_tokens"] > 0
print("✅ Test passed")
print(f" Provider: {provider_name}")
print(f" Model: {response_json['model']}")
print(f" Input tokens: {usage['input_tokens']}")
print(f" Output tokens: {usage['output_tokens']}")

View file

@ -29,3 +29,13 @@ model_list:
litellm_params:
model: "bedrock/converse/us.anthropic.claude-sonnet-4-5-20250929-v1:0"
aws_region_name: "us-east-1"
# Vertex AI models
- model_name: vertex-ai-claude-opus-4-6
litellm_params:
model: "vertex_ai/claude-opus-4-6"
vertex_ai_project: "pathrise-convert-1606954137718"
vertex_ai_location: "asia-southeast1"
general_settings:
forward_client_headers_to_llm_api: true