feat(guardrails): optional skip tool message in unified guardrail inputs - #27441
Conversation
Mirrors the system-message skip in PR #25481 for tool-role messages. Adds a global litellm.skip_tool_message_in_guardrail flag and a per-guardrail litellm_params.skip_tool_message_in_guardrail override, applied in the OpenAI and Anthropic chat translation handlers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Greptile SummaryThis PR adds an opt-in
Confidence Score: 5/5Safe to merge — the change is purely additive with a False-by-default flag, and the OpenAI guardrail path (the common case) is fully correct and well-tested. All changed paths are additive opt-in behaviour; no existing logic is altered. The OpenAI handler implementation is correct end-to-end. The Anthropic handler's role == tool guard in _extract_input_text_and_images is dead code for Anthropic-native tool results (flagged in a prior review thread), but the effective behaviour is still correct today because Anthropic tool-result blocks don't carry a text field at the content-item level, so they would never be extracted regardless. No files require special attention; the Anthropic handler dead-code issue was already noted in a prior review thread.
|
| Filename | Overview |
|---|---|
| litellm/llms/base_llm/guardrail_translation/utils.py | Adds effective_skip_tool_message_for_guardrail and openai_messages_without_tool — clean mirrors of the existing system-message helpers. |
| litellm/llms/openai/chat/guardrail_translation/handler.py | Correctly propagates skip_tool through _extract_inputs and the structured_messages filter; mirrors the skip_system pattern precisely. |
| litellm/llms/anthropic/chat/guardrail_translation/handler.py | Adds skip_tool to _extract_input_text_and_images and structured_messages filter; the role == "tool" guard in _extract_input_text_and_images is dead code for Anthropic native format (noted in prior review thread). |
| litellm/proxy/guardrails/guardrail_registry.py | Propagates skip_tool_message_in_guardrail from litellm_params onto the callback at registration — exactly mirrors the skip_system pattern. |
| litellm/types/guardrails.py | Adds skip_tool_message_in_guardrail: Optional[bool] field to BaseLitellmParams with correct default and description. |
| tests/test_litellm/proxy/guardrails/guardrail_hooks/unified_guardrails/test_unified_guardrail.py | Adds four new tests covering helper functions, per-guardrail precedence, and end-to-end OpenAI handler filtering; all mock-only, no real network calls. |
Reviews (2): Last reviewed commit: "feat(dashboard): skip_tool_message_in_gu..." | Re-trigger Greptile
| role = str(message.get("role") or "").lower() | ||
| if skip_system_message and role == "system": | ||
| return | ||
| if skip_tool_message and role == "tool": | ||
| return |
There was a problem hiding this comment.
skip_tool_message guard is dead code for Anthropic native tool results
In the Anthropic Messages passthrough flow, data["messages"] is in Anthropic native format. Tool results are represented as user-role messages containing type: "tool_result" content blocks — they never carry role: "tool". The guard if skip_tool_message and role == "tool": return therefore never fires for these messages, making the skip ineffective at the extraction level.
The effective behavior happens to be correct today because _extract_input_text_and_images only pulls content_item.get("text"), which returns None for tool_result blocks (they use content, not text). The structured_messages filter also works correctly because it operates on the already-translated OpenAI-format messages. However, if text extraction is ever enhanced to handle nested tool_result content blocks, this guard will silently fail to suppress them.
| @@ -180,6 +182,136 @@ async def apply_guardrail( | |||
| } | |||
There was a problem hiding this comment.
No tests for Anthropic handler's
skip_tool_message behavior
The PR mirrors skip_system_message support for tool messages across both OpenAIChatCompletionsHandler and AnthropicMessagesHandler, but the test suite only covers the OpenAI path. An equivalent test using AnthropicMessagesHandler (with Anthropic-native tool-result messages in user role) would have surfaced the dead-code issue in _extract_input_text_and_images and confirmed the feature works end-to-end for Anthropic passthrough requests.
Adds a tri-state control (inherit / yes / no) when creating or editing guardrails so admins can set litellm_params.skip_tool_message_in_guardrail without YAML, mirroring the existing skip_system_message control. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@greptileai review again with the new comit |
…l_from_guardrails feat(guardrails): optional skip tool message in unified guardrail inputs
Solves LIT-2834
Description
Adds an opt-in flag to drop role: "tool" messages (function/tool results) from the
inputs sent to unified guardrails, mirroring the existing
skip_system_message_in_guardrail behavior from #25481. The model still receives the
full conversation — only what is forwarded to the guardrail evaluator changes.
Two layers of control, identical to the system-message flag:
unset). Unset = inherit global.
Applied in both the OpenAI chat-completions and Anthropic messages guardrail
translation handlers (filters texts, structured_messages, and the per-message
extraction). Also exposed in the dashboard as a tri-state dropdown (Inherit / Yes / No)
on the create and edit guardrail forms.
Cause
Tool-result messages are often large (retrieved documents, KB snippets) and contain
content the model fetched on the user's behalf rather than user input. Sending them to
a guardrail balloons cost/latency and produces false positives on benign retrieved text
— but there was no way to exclude them without dropping them from the LLM call too.
Fix
BaseLitellmParams.skip_tool_message_in_guardrail per-guardrail param.
effective_skip_tool_message_for_guardrail, openai_messages_without_tool.
registration time.
structured_messages, and the extraction loop when the flag resolves to true.
on the OpenAI handler.
SkipToolMessageChoice helpers and unit tests.
When tool message is skipped:

When tool messge is included:
