Skip to content

feat(guardrails): optional skip tool message in unified guardrail inputs - #27441

Merged
shivamrawat1 merged 2 commits into
litellm_internal_stagingfrom
litellm_remove_tool_call_from_guardrails
May 9, 2026
Merged

feat(guardrails): optional skip tool message in unified guardrail inputs #27441
shivamrawat1 merged 2 commits into
litellm_internal_stagingfrom
litellm_remove_tool_call_from_guardrails

Conversation

@shivamrawat1

@shivamrawat1 shivamrawat1 commented May 8, 2026

Copy link
Copy Markdown
Collaborator

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:

  • Global: litellm_settings.skip_tool_message_in_guardrail: true
  • Per-guardrail override: litellm_params.skip_tool_message_in_guardrail (true / false /
    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

  • litellm.skip_tool_message_in_guardrail global +
    BaseLitellmParams.skip_tool_message_in_guardrail per-guardrail param.
  • New helpers in litellm/llms/base_llm/guardrail_translation/utils.py:
    effective_skip_tool_message_for_guardrail, openai_messages_without_tool.
  • guardrail_registry propagates the per-guardrail value onto the callback at
    registration time.
  • OpenAI + Anthropic handlers filter tool-role messages from texts_to_check,
    structured_messages, and the extraction loop when the flag resolves to true.
  • Tests cover the helper, per-guardrail-vs-global precedence, and end-to-end filtering
    on the OpenAI handler.
  • Dashboard: tri-state skip_tool_message_choice control on add/edit forms with matching
    SkipToolMessageChoice helpers and unit tests.

When tool message is skipped:
Screenshot 2026-05-07 at 7 11 19 PM

When tool messge is included:
Screenshot 2026-05-07 at 7 10 42 PM

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

codecov Bot commented May 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.59259% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...ms/anthropic/chat/guardrail_translation/handler.py 71.42% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@greptile-apps

greptile-apps Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds an opt-in skip_tool_message_in_guardrail flag that drops role: "tool" messages from unified guardrail inputs, mirroring the existing skip_system_message_in_guardrail behavior exactly — the model still receives the full conversation.

  • Backend: global litellm.skip_tool_message_in_guardrail flag and per-guardrail BaseLitellmParams.skip_tool_message_in_guardrail override; new effective_skip_tool_message_for_guardrail / openai_messages_without_tool helpers; OpenAI and Anthropic handlers filter texts_to_check, structured_messages, and the per-message extraction loop; guardrail_registry propagates the per-guardrail value at registration time.
  • Dashboard: tri-state skip_tool_message_choice dropdown (Inherit / Yes / No) added to all three guardrail forms (add, edit, info) with matching SkipToolMessageChoice helpers and unit tests.
  • Tests: four new mock-only tests cover the helper, per-guardrail-vs-global precedence, and end-to-end filtering on the OpenAI handler (Anthropic path coverage noted as missing in a prior review thread).

Confidence Score: 5/5

Safe 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.

Important Files Changed

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

Comment on lines +214 to 218
role = str(message.get("role") or "").lower()
if skip_system_message and role == "system":
return
if skip_tool_message and role == "tool":
return

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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(
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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>
@shivamrawat1 shivamrawat1 changed the title feat(guardrails): optional skip tool message in unified guardrail inputs feat(guardrails): optional skip tool message in unified guardrail inputs May 8, 2026
@shivamrawat1

Copy link
Copy Markdown
Collaborator Author

@greptileai review again with the new comit

@shivamrawat1
shivamrawat1 merged commit 3d1127a into litellm_internal_staging May 9, 2026
115 checks passed
@shivamrawat1
shivamrawat1 deleted the litellm_remove_tool_call_from_guardrails branch May 9, 2026 20:05
fzowl pushed a commit to fzowl/litellm that referenced this pull request Jun 24, 2026
…l_from_guardrails

  feat(guardrails): optional skip tool message in unified guardrail inputs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants