Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
284 changes: 139 additions & 145 deletions litellm/litellm_core_utils/litellm_logging.py

Large diffs are not rendered by default.

36 changes: 27 additions & 9 deletions litellm/llms/a2a/chat/guardrail_translation/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ async def process_output_response(
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: Optional["LiteLLMLoggingObj"] = None,
user_api_key_dict: Optional["UserAPIKeyAuth"] = None,
request_data: Optional[dict] = None,
) -> Any:
"""
Process A2A output response by applying guardrails to text content.
Expand Down Expand Up @@ -166,13 +167,21 @@ async def process_output_response(
return response

# Step 2: Apply guardrail to all texts in batch
# Create a request_data dict with response info and user API key metadata
request_data: dict = {"response": response_dict}
# Use the real request_data if provided (proxy path), otherwise
# create a standalone dict (SDK / direct-call path).
if request_data is None:
request_data = {"response": response_dict}
else:
if "response" not in request_data:
request_data["response"] = response_dict

# Add user API key metadata with prefixed keys
user_metadata = self.transform_user_api_key_dict_to_metadata(user_api_key_dict)
if user_metadata:
request_data["litellm_metadata"] = user_metadata
if "litellm_metadata" not in request_data:
user_metadata = self.transform_user_api_key_dict_to_metadata(
user_api_key_dict
)
if user_metadata:
request_data["litellm_metadata"] = user_metadata

inputs = GenericGuardrailAPIInputs(texts=texts_to_check)

Expand Down Expand Up @@ -213,6 +222,7 @@ async def process_output_streaming_response(
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: Optional["LiteLLMLoggingObj"] = None,
user_api_key_dict: Optional["UserAPIKeyAuth"] = None,
request_data: Optional[dict] = None,
) -> List[Any]:
"""
Process A2A streaming output by applying guardrails to accumulated text.
Expand Down Expand Up @@ -258,10 +268,18 @@ async def process_output_streaming_response(
if not combined_text:
return responses_so_far

request_data: dict = {"responses_so_far": responses_so_far}
user_metadata = self.transform_user_api_key_dict_to_metadata(user_api_key_dict)
if user_metadata:
request_data["litellm_metadata"] = user_metadata
if request_data is None:
request_data = {"responses_so_far": responses_so_far}
else:
if "responses_so_far" not in request_data:
request_data["responses_so_far"] = responses_so_far

if "litellm_metadata" not in request_data:
user_metadata = self.transform_user_api_key_dict_to_metadata(
user_api_key_dict
)
if user_metadata:
request_data["litellm_metadata"] = user_metadata

inputs = GenericGuardrailAPIInputs(texts=[combined_text])
guardrailed_inputs = await guardrail_to_apply.apply_guardrail(
Expand Down
26 changes: 17 additions & 9 deletions litellm/llms/anthropic/chat/guardrail_translation/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ async def process_output_response(
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: Optional[Any] = None,
user_api_key_dict: Optional[Any] = None,
request_data: Optional[dict] = None,
) -> Any:
"""
Process output response by applying guardrails to text content and tool calls.
Expand Down Expand Up @@ -323,15 +324,21 @@ async def process_output_response(

# Step 2: Apply guardrail to all texts in batch
if texts_to_check or tool_calls_to_check:
# Create a request_data dict with response info and user API key metadata
request_data: dict = {"response": response}
# Use the real request_data if provided (proxy path), otherwise
# create a standalone dict (SDK / direct-call path).
if request_data is None:
request_data = {"response": response}
else:
if "response" not in request_data:
request_data["response"] = response

# Add user API key metadata with prefixed keys
user_metadata = self.transform_user_api_key_dict_to_metadata(
user_api_key_dict
)
if user_metadata:
request_data["litellm_metadata"] = user_metadata
if "litellm_metadata" not in request_data:
user_metadata = self.transform_user_api_key_dict_to_metadata(
user_api_key_dict
)
if user_metadata:
request_data["litellm_metadata"] = user_metadata

inputs = GenericGuardrailAPIInputs(texts=texts_to_check)
if images_to_check:
Expand Down Expand Up @@ -375,6 +382,7 @@ async def process_output_streaming_response(
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: Optional[Any] = None,
user_api_key_dict: Optional[Any] = None,
request_data: Optional[dict] = None,
) -> List[Any]:
"""
Process output streaming response by applying guardrails to text content.
Expand Down Expand Up @@ -413,7 +421,7 @@ async def process_output_streaming_response(

_guardrailed_inputs = await guardrail_to_apply.apply_guardrail( # allow rejecting the response, if invalid
inputs=guardrail_inputs,
request_data={},
request_data=request_data if request_data is not None else {},
input_type="response",
logging_obj=litellm_logging_obj,
)
Expand All @@ -426,7 +434,7 @@ async def process_output_streaming_response(
string_so_far = self.get_streaming_string_so_far(responses_so_far)
_guardrailed_inputs = await guardrail_to_apply.apply_guardrail( # allow rejecting the response, if invalid
inputs={"texts": [string_so_far]},
request_data={},
request_data=request_data if request_data is not None else {},
input_type="response",
logging_obj=litellm_logging_obj,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ async def process_output_response(
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: Optional["LiteLLMLoggingObj"] = None,
user_api_key_dict: Optional["UserAPIKeyAuth"] = None,
request_data: Optional[dict] = None,
) -> Any:
"""
Process output response with guardrails.
Expand All @@ -91,6 +92,7 @@ async def process_output_streaming_response(
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: Optional["LiteLLMLoggingObj"] = None,
user_api_key_dict: Optional["UserAPIKeyAuth"] = None,
request_data: Optional[dict] = None,
) -> Any:
"""
Process output streaming response with guardrails.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ async def process_output_response(
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: Optional[Any] = None,
user_api_key_dict: Optional[Any] = None,
request_data: Optional[dict] = None,
) -> Any:
"""
Process output response - not applicable for rerank.
Expand Down
20 changes: 17 additions & 3 deletions litellm/llms/mistral/ocr/guardrail_translation/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ async def process_output_response(
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: Optional[Any] = None,
user_api_key_dict: Optional[Any] = None,
request_data: Optional[dict] = None,
) -> Any:
"""
Process OCR output by applying guardrails to extracted page text.
Expand Down Expand Up @@ -127,14 +128,27 @@ async def process_output_response(
if model:
inputs["model"] = model

# Use the real request_data if provided (proxy path), otherwise
# create a standalone dict (SDK / direct-call path).
if request_data is None:
request_data = {}

# Add user metadata if available
if user_api_key_dict is not None:
metadata = self.transform_user_api_key_dict_to_metadata(user_api_key_dict)
inputs.update(metadata) # type: ignore
user_metadata = self.transform_user_api_key_dict_to_metadata(
user_api_key_dict
)
if user_metadata:
# Preserve original behavior: inject metadata into inputs for
# third-party guardrail providers that read it from there
inputs.update(user_metadata) # type: ignore
# Also store in request_data for the logging pipeline
if "litellm_metadata" not in request_data:
request_data["litellm_metadata"] = user_metadata

guardrailed_inputs = await guardrail_to_apply.apply_guardrail(
inputs=inputs,
request_data={},
request_data=request_data,
input_type="response",
logging_obj=litellm_logging_obj,
)
Expand Down
49 changes: 32 additions & 17 deletions litellm/llms/openai/chat/guardrail_translation/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ async def process_input_messages(
if tool_calls_to_check:
inputs["tool_calls"] = tool_calls_to_check # type: ignore
if messages:
inputs[
"structured_messages"
] = messages # pass the openai /chat/completions messages to the guardrail, as-is
inputs["structured_messages"] = (
messages # pass the openai /chat/completions messages to the guardrail, as-is
)
# Pass tools (function definitions) to the guardrail
tools = data.get("tools")
if tools:
Expand Down Expand Up @@ -260,6 +260,7 @@ async def process_output_response(
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: Optional[Any] = None,
user_api_key_dict: Optional[Any] = None,
request_data: Optional[dict] = None,
) -> Any:
"""
Process output response by applying guardrails to text content.
Expand Down Expand Up @@ -308,15 +309,21 @@ async def process_output_response(

# Step 2: Apply guardrail to all texts and tool calls in batch
if texts_to_check or tool_calls_to_check:
# Create a request_data dict with response info and user API key metadata
request_data: dict = {"response": response}
# Use the real request_data if provided (proxy path), otherwise
# create a standalone dict (SDK / direct-call path).
if request_data is None:
request_data = {"response": response}
else:
if "response" not in request_data:
request_data["response"] = response

# Add user API key metadata with prefixed keys
user_metadata = self.transform_user_api_key_dict_to_metadata(
user_api_key_dict
)
if user_metadata:
request_data["litellm_metadata"] = user_metadata
if "litellm_metadata" not in request_data:
user_metadata = self.transform_user_api_key_dict_to_metadata(
user_api_key_dict
)
if user_metadata:
request_data["litellm_metadata"] = user_metadata

inputs = GenericGuardrailAPIInputs(texts=texts_to_check)
if images_to_check:
Expand Down Expand Up @@ -364,6 +371,7 @@ async def process_output_streaming_response(
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: Optional[Any] = None,
user_api_key_dict: Optional[Any] = None,
request_data: Optional[dict] = None,
) -> List["ModelResponseStream"]:
"""
Process output streaming responses by applying guardrails to text content.
Expand Down Expand Up @@ -402,6 +410,7 @@ async def process_output_streaming_response(
guardrail_to_apply=guardrail_to_apply,
litellm_logging_obj=litellm_logging_obj,
user_api_key_dict=user_api_key_dict,
request_data=request_data,
)

return responses_so_far
Expand Down Expand Up @@ -436,15 +445,21 @@ async def process_output_streaming_response(

# Step 3: Apply guardrail to all combined texts in batch
if texts_to_check:
# Create a request_data dict with response info and user API key metadata
request_data: dict = {"responses": responses_so_far}
# Use the real request_data if provided (proxy path), otherwise
# create a standalone dict (SDK / direct-call path).
if request_data is None:
request_data = {"responses": responses_so_far}
else:
if "responses" not in request_data:
request_data["responses"] = responses_so_far

# Add user API key metadata with prefixed keys
user_metadata = self.transform_user_api_key_dict_to_metadata(
user_api_key_dict
)
if user_metadata:
request_data["litellm_metadata"] = user_metadata
if "litellm_metadata" not in request_data:
user_metadata = self.transform_user_api_key_dict_to_metadata(
user_api_key_dict
)
if user_metadata:
request_data["litellm_metadata"] = user_metadata

inputs = GenericGuardrailAPIInputs(texts=texts_to_check)
if images_to_check:
Expand Down
21 changes: 14 additions & 7 deletions litellm/llms/openai/completion/guardrail_translation/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ async def process_output_response(
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: Optional[Any] = None,
user_api_key_dict: Optional[Any] = None,
request_data: Optional[dict] = None,
) -> Any:
"""
Process output response by applying guardrails to completion text.
Expand Down Expand Up @@ -155,15 +156,21 @@ async def process_output_response(

# Apply guardrails in batch
if texts_to_check:
# Create a request_data dict with response info and user API key metadata
request_data: dict = {"response": response}
# Use the real request_data if provided (proxy path), otherwise
# create a standalone dict (SDK / direct-call path).
if request_data is None:
request_data = {"response": response}
else:
if "response" not in request_data:
request_data["response"] = response

# Add user API key metadata with prefixed keys
user_metadata = self.transform_user_api_key_dict_to_metadata(
user_api_key_dict
)
if user_metadata:
request_data["litellm_metadata"] = user_metadata
if "litellm_metadata" not in request_data:
user_metadata = self.transform_user_api_key_dict_to_metadata(
user_api_key_dict
)
if user_metadata:
request_data["litellm_metadata"] = user_metadata

inputs = GenericGuardrailAPIInputs(texts=texts_to_check)
# Include model information from the response if available
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ async def process_output_response(
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: Optional[Any] = None,
user_api_key_dict: Optional[Any] = None,
request_data: Optional[dict] = None,
) -> Any:
"""
Process output response - embeddings responses contain vectors, not text.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ async def process_output_response(
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: Optional[Any] = None,
user_api_key_dict: Optional[Any] = None,
request_data: Optional[dict] = None,
) -> Any:
"""
Process output response - typically not needed for image generation.
Expand Down
Loading
Loading