Merge pull request #23240 from BerriAI/litellm_bedrock-nova-output-config-spend-tracking

fix(bedrock): strip output_config from Converse requests; fix spend tracking redaction test
This commit is contained in:
Sameer Kankute
2026-03-10 12:15:06 +05:30
committed by GitHub
3 changed files with 31 additions and 2 deletions
@@ -1206,6 +1206,7 @@ class AmazonConverseConfig(BaseConfig):
self._validate_request_metadata(request_metadata)
output_config: Optional[OutputConfigBlock] = inference_params.pop("outputConfig", None)
inference_params.pop("output_config", None) # Bedrock Converse doesn't support it
# keep supported params in 'inference_params', and set all model-specific params in 'additional_request_params'
additional_request_params = {
@@ -3170,6 +3170,33 @@ def test_transform_request_with_output_config():
assert result["outputConfig"]["textFormat"]["structure"]["jsonSchema"]["name"] == "TestSchema"
def test_output_config_snake_case_stripped_from_bedrock_converse_request():
"""Test that output_config (snake_case) is stripped from Bedrock Converse requests.
Bedrock Converse API doesn't support the output_config parameter (Anthropic-only).
Nova and other Converse models reject requests with extraneous output_config.
"""
config = AmazonConverseConfig()
messages = [{"role": "user", "content": "test"}]
optional_params = {
"output_config": {"effort": "high"},
}
result = config._transform_request(
model="us.amazon.nova-pro-v1:0",
messages=messages,
optional_params=optional_params,
litellm_params={},
headers={},
)
# output_config must not appear in additionalModelRequestFields
additional = result.get("additionalModelRequestFields", {})
assert "output_config" not in additional, (
f"output_config should be stripped for Bedrock Converse, got: {list(additional.keys())}"
)
def test_transform_response_native_structured_output():
"""Test response handling when model returns JSON as text content (native structured output)."""
response_json = {
@@ -1071,9 +1071,10 @@ def test_spend_logs_redacts_request_and_response_when_turn_off_message_logging_e
response_result = _get_response_for_spend_logs_payload(payload=payload, kwargs=kwargs)
# When redaction is enabled and response is a dict (not ModelResponse),
# perform_redaction returns {"text": "redacted-by-litellm"}
# perform_redaction redacts content in-place within the choices structure
parsed_response = json.loads(response_result)
assert parsed_response == {"text": "redacted-by-litellm"}
assert parsed_response["choices"][0]["message"]["content"] == "redacted-by-litellm"
assert parsed_response["choices"][0]["message"]["role"] == "assistant"
@patch("litellm.secret_managers.main.get_secret_bool")