From d52ba903dd33b9e1bca175e6c37027dc9c5d3dc9 Mon Sep 17 00:00:00 2001 From: kerry Date: Tue, 27 Oct 2026 18:04:51 +0000 Subject: [PATCH] refactor(bedrock): record the native guardrail trace where the Bedrock response is parsed Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/litellm_core_utils/litellm_logging.py | 1 - litellm/llms/bedrock/chat/converse_transformation.py | 2 ++ .../anthropic_claude_transformation.py | 1 + litellm/llms/custom_httpx/llm_http_handler.py | 1 + litellm/proxy/common_request_processing.py | 1 - .../responses/litellm_completion_transformation/handler.py | 5 ----- 6 files changed, 4 insertions(+), 7 deletions(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index e89470152d9..55f0f5d49f6 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -2969,7 +2969,6 @@ class Logging(LiteLLMLoggingBaseClass): result = self._handle_a2a_response_logging(result=result) logging_result: Final = self.normalize_logging_result(result=result) - self.record_native_bedrock_guardrail(logging_result) if cache_hit is None and _served_from_cache_at_no_charge(logging_result): self.model_call_details["cache_hit"] = True diff --git a/litellm/llms/bedrock/chat/converse_transformation.py b/litellm/llms/bedrock/chat/converse_transformation.py index 4d7ec663d09..de1ca373e6f 100644 --- a/litellm/llms/bedrock/chat/converse_transformation.py +++ b/litellm/llms/bedrock/chat/converse_transformation.py @@ -2859,6 +2859,8 @@ class AmazonConverseConfig(BaseConfig): # Add "trace" from Bedrock guardrails - if user has opted in to returning it if "trace" in completion_response: setattr(model_response, "trace", completion_response["trace"]) + if logging_obj is not None: + logging_obj.record_native_bedrock_guardrail(model_response) # Add service_tier if present in Bedrock response # Map Bedrock serviceTier (object) to OpenAI service_tier (string) diff --git a/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude_transformation.py b/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude_transformation.py index 2218c0d3ed4..eb6ed5c75e3 100644 --- a/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude_transformation.py +++ b/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude_transformation.py @@ -426,4 +426,5 @@ class AmazonAnthropicClaudeConfig(AmazonInvokeConfig, AnthropicConfig): trace: Final = object_mapping(body.get(BEDROCK_INVOKE_TRACE_FIELD)) if trace is not None: setattr(response, BEDROCK_INVOKE_TRACE_FIELD, trace) + logging_obj.record_native_bedrock_guardrail(response) return response diff --git a/litellm/llms/custom_httpx/llm_http_handler.py b/litellm/llms/custom_httpx/llm_http_handler.py index 7b808cf2be2..54a41dd1e67 100644 --- a/litellm/llms/custom_httpx/llm_http_handler.py +++ b/litellm/llms/custom_httpx/llm_http_handler.py @@ -2705,6 +2705,7 @@ class BaseLLMHTTPHandler: raw_response=response, logging_obj=logging_obj, ) + logging_obj.record_native_bedrock_guardrail(initial_response) return await self._finalize_anthropic_messages_response( initial_response=initial_response, diff --git a/litellm/proxy/common_request_processing.py b/litellm/proxy/common_request_processing.py index 930ba9aa283..a7de72a574e 100644 --- a/litellm/proxy/common_request_processing.py +++ b/litellm/proxy/common_request_processing.py @@ -3260,7 +3260,6 @@ class ProxyBaseLLMRequestProcessing: if is_unbilled_non_inference_call_from_params(logging_obj.call_type, logging_obj.litellm_params, response) else computed_cost_for_headers ) - logging_obj.record_native_bedrock_guardrail(response) request_metadata_bucket: Final[object] = get_or_create_metadata_bucket(self.data)[1] # pyright: ignore[reportUnknownVariableType, reportUnknownMemberType] # self.data is an untyped dict guardrail_cost_for_headers: Final = guardrail_information_cost( _guardrail_entries_for_headers(request_metadata_bucket, logging_obj) # pyright: ignore[reportUnknownArgumentType] # bucket comes from the untyped request dict diff --git a/litellm/responses/litellm_completion_transformation/handler.py b/litellm/responses/litellm_completion_transformation/handler.py index 2559d746d41..ea3bda1b8b5 100644 --- a/litellm/responses/litellm_completion_transformation/handler.py +++ b/litellm/responses/litellm_completion_transformation/handler.py @@ -8,7 +8,6 @@ from typing import Final from pydantic import TypeAdapter import litellm -from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj from litellm.responses.additional_tools import hoist_additional_tools from litellm.responses.litellm_completion_transformation.compaction_items import holds_compaction_summary from litellm.responses.litellm_completion_transformation.streaming_iterator import ( @@ -134,10 +133,6 @@ class LiteLLMCompletionTransformationHandler: litellm_completion_response: Final[ModelResponse | litellm.CustomStreamWrapper] = await litellm.acompletion( **acompletion_args, ) - logging_obj: Final[object] = kwargs.get("litellm_logging_obj") # pyright: ignore[reportUnknownVariableType, reportUnknownMemberType] # kwargs is untyped - if isinstance(litellm_completion_response, ModelResponse) and isinstance(logging_obj, LiteLLMLoggingObj): - logging_obj.record_native_bedrock_guardrail(litellm_completion_response) - if isinstance(litellm_completion_response, ModelResponse): responses_api_response: Final[ResponsesAPIResponse] = ( LiteLLMCompletionResponsesConfig.transform_chat_completion_response_to_responses_api_response(