Implement requestMetadata support for Bedrock Converse API
- Add requestMetadata field to CommonRequestObject type definition - Support request_metadata parameter in get_supported_openai_params - Add comprehensive validation for AWS Bedrock constraints: * Maximum 16 key-value pairs * Key length 1-256 characters * Value length 0-256 characters * Character set validation [a-zA-Z0-9\s:_@0=/+,.-] - Transform request_metadata to top-level requestMetadata field in API request - Maintain backward compatibility with existing functionality - Enable metadata logging and traceability for multi-cloud environments
This commit is contained in:
parent
1d85623b66
commit
a34bb6f6d3
@ -175,6 +175,77 @@ class AmazonConverseConfig(BaseConfig):
|
||||
and v is not None
|
||||
}
|
||||
|
||||
def _validate_request_metadata(self, metadata: dict) -> None:
|
||||
"""
|
||||
Validate requestMetadata according to AWS Bedrock Converse API constraints.
|
||||
|
||||
Constraints:
|
||||
- Maximum of 16 items
|
||||
- Keys: 1-256 characters, pattern [a-zA-Z0-9\\s:_@$#=/+,-.]{1,256}
|
||||
- Values: 0-256 characters, pattern [a-zA-Z0-9\\s:_@$#=/+,-.]{0,256}
|
||||
"""
|
||||
import re
|
||||
|
||||
if not isinstance(metadata, dict):
|
||||
raise litellm.exceptions.BadRequestError(
|
||||
message="request_metadata must be a dictionary",
|
||||
model="bedrock",
|
||||
llm_provider="bedrock",
|
||||
)
|
||||
|
||||
if len(metadata) > 16:
|
||||
raise litellm.exceptions.BadRequestError(
|
||||
message="request_metadata can contain a maximum of 16 items",
|
||||
model="bedrock",
|
||||
llm_provider="bedrock",
|
||||
)
|
||||
|
||||
key_pattern = re.compile(r'^[a-zA-Z0-9\s:_@$#=/+,.-]{1,256}$')
|
||||
value_pattern = re.compile(r'^[a-zA-Z0-9\s:_@$#=/+,.-]{0,256}$')
|
||||
|
||||
for key, value in metadata.items():
|
||||
if not isinstance(key, str):
|
||||
raise litellm.exceptions.BadRequestError(
|
||||
message="request_metadata keys must be strings",
|
||||
model="bedrock",
|
||||
llm_provider="bedrock",
|
||||
)
|
||||
|
||||
if not isinstance(value, str):
|
||||
raise litellm.exceptions.BadRequestError(
|
||||
message="request_metadata values must be strings",
|
||||
model="bedrock",
|
||||
llm_provider="bedrock",
|
||||
)
|
||||
|
||||
if len(key) == 0 or len(key) > 256:
|
||||
raise litellm.exceptions.BadRequestError(
|
||||
message="request_metadata key length must be 1-256 characters",
|
||||
model="bedrock",
|
||||
llm_provider="bedrock",
|
||||
)
|
||||
|
||||
if len(value) > 256:
|
||||
raise litellm.exceptions.BadRequestError(
|
||||
message="request_metadata value length must be 0-256 characters",
|
||||
model="bedrock",
|
||||
llm_provider="bedrock",
|
||||
)
|
||||
|
||||
if not key_pattern.match(key):
|
||||
raise litellm.exceptions.BadRequestError(
|
||||
message=f"request_metadata key '{key}' contains invalid characters. Allowed: [a-zA-Z0-9\\s:_@$#=/+,.-]",
|
||||
model="bedrock",
|
||||
llm_provider="bedrock",
|
||||
)
|
||||
|
||||
if not value_pattern.match(value):
|
||||
raise litellm.exceptions.BadRequestError(
|
||||
message=f"request_metadata value '{value}' contains invalid characters. Allowed: [a-zA-Z0-9\\s:_@$#=/+,.-]",
|
||||
model="bedrock",
|
||||
llm_provider="bedrock",
|
||||
)
|
||||
|
||||
def get_supported_openai_params(self, model: str) -> List[str]:
|
||||
from litellm.utils import supports_function_calling
|
||||
|
||||
@ -188,6 +259,7 @@ class AmazonConverseConfig(BaseConfig):
|
||||
"top_p",
|
||||
"extra_headers",
|
||||
"response_format",
|
||||
"request_metadata",
|
||||
]
|
||||
|
||||
if (
|
||||
@ -497,6 +569,10 @@ class AmazonConverseConfig(BaseConfig):
|
||||
optional_params["thinking"] = AnthropicConfig._map_reasoning_effort(
|
||||
value
|
||||
)
|
||||
if param == "request_metadata":
|
||||
if value is not None:
|
||||
self._validate_request_metadata(value)
|
||||
optional_params["request_metadata"] = value
|
||||
|
||||
# Only update thinking tokens for non-GPT-OSS models
|
||||
if "gpt-oss" not in model:
|
||||
@ -727,6 +803,11 @@ class AmazonConverseConfig(BaseConfig):
|
||||
)
|
||||
inference_params.pop("json_mode", None) # used for handling json_schema
|
||||
|
||||
# Extract request_metadata before processing other parameters
|
||||
request_metadata = inference_params.pop("request_metadata", None)
|
||||
if request_metadata is not None:
|
||||
self._validate_request_metadata(request_metadata)
|
||||
|
||||
# keep supported params in 'inference_params', and set all model-specific params in 'additional_request_params'
|
||||
additional_request_params = {
|
||||
k: v for k, v in inference_params.items() if k not in total_supported_params
|
||||
@ -813,6 +894,10 @@ class AmazonConverseConfig(BaseConfig):
|
||||
if bedrock_tool_config is not None:
|
||||
data["toolConfig"] = bedrock_tool_config
|
||||
|
||||
# Request Metadata (top-level field)
|
||||
if request_metadata is not None:
|
||||
data["requestMetadata"] = request_metadata
|
||||
|
||||
return data
|
||||
|
||||
async def _async_transform_request(
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import json
|
||||
from typing import Any, List, Literal, Optional, Union
|
||||
from typing import Any, Dict, List, Literal, Optional, Union
|
||||
|
||||
from typing_extensions import (
|
||||
TYPE_CHECKING,
|
||||
@ -227,6 +227,7 @@ class CommonRequestObject(
|
||||
toolConfig: ToolConfigBlock
|
||||
guardrailConfig: Optional[GuardrailConfigBlock]
|
||||
performanceConfig: Optional[PerformanceConfigBlock]
|
||||
requestMetadata: Optional[Dict[str, str]]
|
||||
|
||||
|
||||
class RequestObject(CommonRequestObject, total=False):
|
||||
|
||||
Loading…
Reference in New Issue
Block a user