Skip to content

Comments

Feat(guardrail): Adding support for custom Ovalix guardrail#21887

Open
shalom-ovalix wants to merge 4 commits intoBerriAI:mainfrom
shalom-ovalix:ovelix-custom-guardrail-support
Open

Feat(guardrail): Adding support for custom Ovalix guardrail#21887
shalom-ovalix wants to merge 4 commits intoBerriAI:mainfrom
shalom-ovalix:ovelix-custom-guardrail-support

Conversation

@shalom-ovalix
Copy link

Relevant issues

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have Added testing in the tests/litellm/ directory, Adding at least 1 test is a hard requirement - see details
  • My PR passes all unit tests on make test-unit
  • My PR's scope is as isolated as possible, it only solves 1 specific problem
  • [] I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

CI (LiteLLM team)

CI status guideline:

  • 50-55 passing tests: main is stable with minor issues.
  • 45-49 passing tests: acceptable but needs attention
  • <= 40 passing tests: unstable; be careful with your merges and assess the risk.
  • Branch creation CI run
    Link:

  • CI run for the last commit
    Link:

  • Merge / cherry-pick CI run
    Links:

Type

🆕 New Feature
🐛 Bug Fix
🧹 Refactoring
📖 Documentation
🚄 Infrastructure
✅ Test

Changes

@vercel
Copy link

vercel bot commented Feb 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
litellm Ready Ready Preview, Comment Feb 22, 2026 4:26pm

Request Review

@CLAassistant
Copy link

CLAassistant commented Feb 22, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ shalom-ovalix
❌ Shalom Jamil


Shalom Jamil seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@shalom-ovalix
Copy link
Author

@greptileai

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 22, 2026

Greptile Summary

This PR adds a new Ovalix guardrail integration that supports pre-call (user input) and post-call (LLM output) checkpoints via the Ovalix Tracker service, with optional correction, anonymization, and blocking of content.

  • Implements OvalixGuardrail class extending CustomGuardrail with apply_guardrail() for both request and response paths
  • Adds Ovalix to the SupportedGuardrailIntegrations enum and LitellmParams config model for proxy YAML configuration
  • Auto-discovers pre/post checkpoint IDs from config or environment variables, and auto-registers the appropriate event hooks
  • Includes session management using SHA-256-hashed actor identifiers for session continuity across requests
  • The pre-call path rebuilds the texts list from structured_messages rather than operating on the input texts, which could cause length mismatches with the upstream guardrail translation handler's text_task_mappings when multimodal (list) content is present
  • Comprehensive test suite with 20+ mock-based unit tests covering allow, anonymize, block, error handling, and edge cases

Confidence Score: 3/5

  • This PR is generally safe but has a logic concern in the pre-call path that could cause incorrect guardrail application for multimodal content.
  • The integration follows established guardrail patterns and has good test coverage. However, the pre-call apply_guardrail path derives its returned texts list from structured_messages instead of operating on the input texts, creating a potential length mismatch with the upstream handler's task mappings when multimodal list content is involved. Previous review issues (IndexError, dead code, hash non-determinism, silent content dropping) have been addressed.
  • Pay close attention to litellm/proxy/guardrails/guardrail_hooks/ovalix/ovalix.py — specifically the apply_guardrail request path and _generate_post_guardrail_text method's interaction with the upstream guardrail translation handler.

Important Files Changed

Filename Overview
litellm/proxy/guardrails/guardrail_hooks/ovalix/ovalix.py Core guardrail implementation with pre/post-call checkpoint support. The pre-call path rebuilds the texts list from structured_messages rather than operating on the input texts, which may cause length mismatches with the upstream handler's task_mappings for multimodal content. Otherwise well-structured with proper error handling, session management, and blocking logic.
litellm/proxy/guardrails/guardrail_hooks/ovalix/init.py Standard guardrail registration following existing patterns. Correctly registers initializer and class in both registries, reads config from litellm_params, and adds callback to logging_callback_manager.
litellm/types/guardrails.py Adds OVALIX enum value to SupportedGuardrailIntegrations, imports OvalixGuardrailConfigModel, and adds it to LitellmParams multiple inheritance. Follows the same pattern used by all other guardrail integrations.
litellm/types/proxy/guardrails/guardrail_hooks/ovalix.py Clean Pydantic config model defining Ovalix-specific configuration fields (tracker_api_base, tracker_api_key, application_id, checkpoint IDs). Follows the GuardrailConfigModel base class pattern correctly.
tests/test_litellm/proxy/guardrails/guardrail_hooks/test_ovalix.py Comprehensive test suite with 20+ tests covering initialization, config validation, checkpoint calls, pre/post-call guardrail behavior, blocking, anonymization, error handling, and edge cases. All tests use mocked HTTP calls (no real network requests). Good coverage of core scenarios.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Proxy as LiteLLM Proxy
    participant Handler as Guardrail Translation Handler
    participant Ovalix as OvalixGuardrail
    participant Tracker as Ovalix Tracker API

    Note over Client,Tracker: Pre-call (request) flow
    Client->>Proxy: POST /chat/completions
    Proxy->>Handler: process_input_messages(data)
    Handler->>Handler: Extract texts & task_mappings
    Handler->>Ovalix: apply_guardrail(inputs, input_type="request")
    Ovalix->>Ovalix: _generate_post_guardrail_text(messages)
    loop For each user message (reversed)
        Ovalix->>Tracker: POST /checkpoint (pre_checkpoint_id)
        Tracker-->>Ovalix: {action_type, modified_data}
        alt action_type == "block" (last message)
            Ovalix-->>Handler: raise OvalixGuardrailBlockedException
        else action_type == "block" (older message)
            Ovalix->>Ovalix: Replace text with block message
        else allow / anonymize
            Ovalix->>Ovalix: Use modified_data or original
        end
    end
    Ovalix-->>Handler: Updated inputs with texts
    Handler->>Handler: Map texts back to messages
    Handler-->>Proxy: Modified request data
    Proxy->>Proxy: Call LLM

    Note over Client,Tracker: Post-call (response) flow
    Proxy->>Handler: process_output_response(response)
    Handler->>Handler: Extract response texts
    Handler->>Ovalix: apply_guardrail(inputs, input_type="response")
    Ovalix->>Ovalix: _generate_post_guardrail_llm_responses(texts)
    loop For each response text (reversed)
        Ovalix->>Tracker: POST /checkpoint (post_checkpoint_id)
        Tracker-->>Ovalix: {action_type, modified_data}
    end
    Ovalix-->>Handler: Updated texts
    Handler->>Handler: Map texts back to response choices
    Handler-->>Proxy: Modified response
    Proxy-->>Client: Final response
Loading

Last reviewed commit: fff1bb3

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@shalom-ovalix
Copy link
Author

@greptileai

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@shalom-ovalix shalom-ovalix force-pushed the ovelix-custom-guardrail-support branch from 68df6f6 to 37cb2d2 Compare February 22, 2026 14:32
@shalom-ovalix
Copy link
Author

@greptileai

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

@shalom-ovalix shalom-ovalix force-pushed the ovelix-custom-guardrail-support branch 2 times, most recently from 8491f13 to def509d Compare February 22, 2026 15:30
@shalom-ovalix
Copy link
Author

@greptileai

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@shalom-ovalix shalom-ovalix force-pushed the ovelix-custom-guardrail-support branch from 4284e63 to 83f293a Compare February 22, 2026 16:20
@shalom-ovalix
Copy link
Author

@greptileai

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +252 to +260
messages = inputs.get("structured_messages") or []
if not messages:
return inputs

if self._pre_checkpoint_id:
post_guardrail_texts = await self._generate_post_guardrail_text(
messages, actor, session_id
)
return {**inputs, "texts": post_guardrail_texts}
Copy link
Contributor

Choose a reason for hiding this comment

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

Pre-call texts list may not match upstream task mappings

The upstream _apply_guardrail_responses_to_input_texts in handler.py expects the returned texts list to have a 1:1 correspondence with text_task_mappings, which tracks (message_index, content_index) for each extracted text item. This code ignores the input texts and instead builds a new list from structured_messages — one entry per message.

This works correctly for the common case (all messages have simple string content), but breaks when a message has list content (multimodal). For example, a message with content = [{"type": "text", "text": "a"}, {"type": "text", "text": "b"}] produces 2 entries in the upstream's text_task_mappings, but _generate_post_guardrail_text inserts the raw list as a single entry. The resulting length mismatch means the upstream handler silently skips applying guardrail corrections to some messages.

Consider operating on inputs.get("texts", []) directly (like the response path does) instead of deriving texts from structured_messages, so the returned list always matches the upstream mapping. Alternatively, if working with structured_messages is intentional (e.g., to inspect roles), ensure the returned texts list maintains the same length and order as the input texts.

Comment on lines +324 to +335
"""
Generate post-guardrail text for the given messages.

Args:
messages: List of messages
actor: Actor
session_id: Session ID
request_data: Request data

Returns:
List of post-guardrail texts
"""
Copy link
Contributor

Choose a reason for hiding this comment

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

Stale docstring parameter

The docstring references request_data: Request data as a parameter, but it was removed from the method signature.

Suggested change
"""
Generate post-guardrail text for the given messages.
Args:
messages: List of messages
actor: Actor
session_id: Session ID
request_data: Request data
Returns:
List of post-guardrail texts
"""
) -> List[Any]:
"""
Generate post-guardrail text for the given messages.
Args:
messages: List of messages
actor: Actor
session_id: Session ID
Returns:
List of post-guardrail texts
"""

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.

2 participants