mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-09 22:31:41 +00:00
Merge 93a704253b into 1af7a403c6
This commit is contained in:
commit
767020f635
3 changed files with 89 additions and 0 deletions
|
|
@ -10,6 +10,16 @@ from litellm.secret_managers.main import get_secret_str
|
|||
CLAUDE_PLATFORM_SERVICE_NAME: Final = "aws-external-anthropic"
|
||||
CLAUDE_PLATFORM_BEDROCK_ROUTE: Final = "claude_platform/"
|
||||
|
||||
# Aliases litellm accepts for the workspace identifier; all of them are
|
||||
# consumed only as the `anthropic-workspace-id` HTTP header and must be
|
||||
# stripped from request-body params before transformation (#29272).
|
||||
_WORKSPACE_ID_PARAM_KEYS: Tuple[str, ...] = (
|
||||
"workspace_id",
|
||||
"aws_workspace_id",
|
||||
"anthropic-workspace-id",
|
||||
"anthropic_workspace_id",
|
||||
)
|
||||
|
||||
|
||||
def strip_claude_platform_route(model: str) -> str:
|
||||
if model.startswith(CLAUDE_PLATFORM_BEDROCK_ROUTE):
|
||||
|
|
@ -42,6 +52,20 @@ class BedrockClaudePlatformMixin(BaseAWSLLM):
|
|||
return str(workspace_id)
|
||||
return get_secret_str("ANTHROPIC_AWS_WORKSPACE_ID") or get_secret_str("ANTHROPIC_WORKSPACE_ID")
|
||||
|
||||
@staticmethod
|
||||
def _pop_workspace_id_params(optional_params: dict, litellm_params: dict) -> None:
|
||||
"""Strip every workspace_id alias from both param dicts.
|
||||
|
||||
``workspace_id`` (and its aliases) is consumed only as the
|
||||
``anthropic-workspace-id`` HTTP header. If we leave the keys in
|
||||
``optional_params``, the inherited ``AnthropicConfig.transform_request``
|
||||
serializes them into the JSON body, and Anthropic's ``/v1/messages``
|
||||
rejects unknown top-level fields (#29272).
|
||||
"""
|
||||
for key in _WORKSPACE_ID_PARAM_KEYS:
|
||||
optional_params.pop(key, None)
|
||||
litellm_params.pop(key, None)
|
||||
|
||||
def _get_required_aws_region_name(self, optional_params: dict) -> str:
|
||||
aws_region_name: Final = (
|
||||
optional_params.get("aws_region_name")
|
||||
|
|
|
|||
|
|
@ -41,6 +41,13 @@ class BedrockClaudePlatformConfig(BedrockClaudePlatformMixin, AnthropicConfig):
|
|||
model=model,
|
||||
)
|
||||
|
||||
# Drop workspace_id alias keys from optional_params/litellm_params now
|
||||
# that we've turned the value into the `anthropic-workspace-id` header.
|
||||
# Without this they survive into `AnthropicConfig.transform_request` and
|
||||
# ship as a top-level field in the JSON body, which Anthropic's
|
||||
# /v1/messages rejects (#29272).
|
||||
self._pop_workspace_id_params(optional_params, litellm_params)
|
||||
|
||||
api_key = api_key or get_secret_str("ANTHROPIC_AWS_API_KEY")
|
||||
anthropic_headers: Final = self.get_anthropic_headers(
|
||||
api_key=api_key,
|
||||
|
|
|
|||
|
|
@ -362,3 +362,61 @@ def test_sigv4_no_duplicate_content_type_when_caller_sets_lowercase():
|
|||
"Duplicate keys produce 'application/json, application/json' in the "
|
||||
"SigV4 canonical string and cause a 401."
|
||||
)
|
||||
|
||||
|
||||
def test_claude_platform_strips_workspace_id_aliases_from_request_body():
|
||||
"""Regression for #29272.
|
||||
|
||||
`workspace_id` (and its aliases `aws_workspace_id`, `anthropic-workspace-id`,
|
||||
`anthropic_workspace_id`) is consumed only as the
|
||||
`anthropic-workspace-id` header. They were left in `optional_params`, so
|
||||
the inherited `AnthropicConfig.transform_request` serialized them as
|
||||
top-level fields of the JSON body and Anthropic's `/v1/messages`
|
||||
rejected the request with `unknown field`.
|
||||
|
||||
Verify every alias is popped from both `optional_params` and
|
||||
`litellm_params` once `validate_environment` runs.
|
||||
"""
|
||||
from litellm.llms.bedrock.claude_platform.transformation import (
|
||||
BedrockClaudePlatformConfig,
|
||||
)
|
||||
|
||||
config = BedrockClaudePlatformConfig()
|
||||
|
||||
optional_params = {
|
||||
"workspace_id": "wrkspc_a",
|
||||
"aws_workspace_id": "wrkspc_b",
|
||||
"anthropic-workspace-id": "wrkspc_c",
|
||||
"anthropic_workspace_id": "wrkspc_d",
|
||||
"max_tokens": 1024, # must survive
|
||||
}
|
||||
litellm_params = {
|
||||
"workspace_id": "wrkspc_e",
|
||||
"anthropic_workspace_id": "wrkspc_f",
|
||||
"metadata": {"trace_id": "abc"}, # must survive
|
||||
}
|
||||
|
||||
headers = config.validate_environment(
|
||||
api_key="fake-platform-key",
|
||||
headers={},
|
||||
model="claude-sonnet-4-6",
|
||||
messages=[{"role": "user", "content": "hello"}],
|
||||
optional_params=optional_params,
|
||||
litellm_params=litellm_params,
|
||||
)
|
||||
|
||||
assert headers["anthropic-workspace-id"] == "wrkspc_a"
|
||||
|
||||
# No alias survives into params that downstream transformers serialize.
|
||||
for key in (
|
||||
"workspace_id",
|
||||
"aws_workspace_id",
|
||||
"anthropic-workspace-id",
|
||||
"anthropic_workspace_id",
|
||||
):
|
||||
assert key not in optional_params, f"{key} leaked into optional_params"
|
||||
assert key not in litellm_params, f"{key} leaked into litellm_params"
|
||||
|
||||
# Unrelated params untouched.
|
||||
assert optional_params["max_tokens"] == 1024
|
||||
assert litellm_params["metadata"] == {"trace_id": "abc"}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue