fix(anthropic): strip undocumented keys from metadata before sending to API

This commit is contained in:
Sameer Kankute 2026-03-27 08:33:11 +05:30
parent b20cff8673
commit 38e8003297
No known key found for this signature in database
2 changed files with 88 additions and 0 deletions

View File

@ -1421,6 +1421,16 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
):
optional_params["metadata"] = {"user_id": _litellm_metadata["user_id"]}
## Ensure metadata only contains user_id (only documented field in Anthropic Messages API)
if "metadata" in optional_params and isinstance(
optional_params["metadata"], dict
):
_user_id = optional_params["metadata"].get("user_id")
if _user_id is not None:
optional_params["metadata"] = {"user_id": _user_id}
else:
optional_params.pop("metadata")
# Remove internal LiteLLM parameters that should not be sent to Anthropic API
optional_params.pop("is_vertex_request", None)

View File

@ -1800,3 +1800,81 @@ def test_anthropic_structured_output_chat_completion_api():
)
assert response is not None
print(f"response: {response}")
def _make_transform_request(optional_params: dict, litellm_params: dict) -> dict:
from litellm.llms.anthropic.chat.transformation import AnthropicConfig
return AnthropicConfig().transform_request(
model="claude-3-5-sonnet-20241022",
messages=[{"role": "user", "content": "hi"}],
optional_params=optional_params,
litellm_params=litellm_params,
headers={},
)
def test_metadata_only_user_id_passes_through():
"""metadata with only user_id is forwarded as-is."""
data = _make_transform_request(
optional_params={"metadata": {"user_id": "abc123"}},
litellm_params={},
)
assert data.get("metadata") == {"user_id": "abc123"}
def test_metadata_extra_keys_are_stripped():
"""Extra keys in metadata are removed; only user_id is sent."""
data = _make_transform_request(
optional_params={"metadata": {"user_id": "abc123", "extra_key": "val"}},
litellm_params={},
)
assert data.get("metadata") == {"user_id": "abc123"}
def test_metadata_without_user_id_is_dropped():
"""metadata with no user_id is removed entirely."""
data = _make_transform_request(
optional_params={"metadata": {"only_other_key": "val"}},
litellm_params={},
)
assert "metadata" not in data
def test_metadata_user_id_from_litellm_params_strips_extras():
"""user_id from litellm_params metadata is extracted; extra keys are not forwarded."""
data = _make_transform_request(
optional_params={},
litellm_params={"metadata": {"user_id": "abc123", "trace_id": "xyz"}},
)
assert data.get("metadata") == {"user_id": "abc123"}
def test_metadata_filter_applies_to_vertex_anthropic():
"""VertexAIAnthropicConfig inherits the metadata filter."""
from litellm.llms.vertex_ai.vertex_ai_partner_models.anthropic.transformation import (
VertexAIAnthropicConfig,
)
data = VertexAIAnthropicConfig().transform_request(
model="claude-3-5-sonnet-20241022",
messages=[{"role": "user", "content": "hi"}],
optional_params={"metadata": {"user_id": "u1", "extra": "drop_me"}},
litellm_params={},
headers={},
)
assert data.get("metadata") == {"user_id": "u1"}
def test_metadata_filter_applies_to_azure_anthropic():
"""AzureAnthropicConfig inherits the metadata filter."""
from litellm.llms.azure_ai.anthropic.transformation import AzureAnthropicConfig
data = AzureAnthropicConfig().transform_request(
model="claude-3-5-sonnet-20241022",
messages=[{"role": "user", "content": "hi"}],
optional_params={"metadata": {"user_id": "u2", "extra": "drop_me"}},
litellm_params={},
headers={},
)
assert data.get("metadata") == {"user_id": "u2"}