Skip to content

fix(proxy): invoke post-call guardrails on pass-through endpoint responses (#20270) - #26262

Merged
krrish-berri-2 merged 2 commits into
BerriAI:litellm_oss_branchfrom
predibase:fix/passthrough-post-call-guardrails
Apr 24, 2026
Merged

fix(proxy): invoke post-call guardrails on pass-through endpoint responses (#20270)#26262
krrish-berri-2 merged 2 commits into
BerriAI:litellm_oss_branchfrom
predibase:fix/passthrough-post-call-guardrails

Conversation

@tuhinspatra

@tuhinspatra tuhinspatra commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #20270 — post-call guardrails are never invoked on pass-through endpoint responses.

Pass-through endpoints (/vertex_ai/*, /openai/*, /bedrock/*) currently fire pre-call hooks but skip
post-call guardrails entirely for non-streaming responses. The handler infrastructure already exists
(PassThroughEndpointHandler.process_output_response()) but is never reached because:

  1. pass_through_request() never calls post_call_success_hook after reading the response
  2. UnifiedLLMGuardrails.async_post_call_success_hook() can't resolve call_type for pass-through routes
    (not in API_ROUTE_TO_CALL_TYPES, response is a raw dict not a typed LLMResponseTypes)

Changes

pass_through_endpoints.py

  • Call proxy_logging_obj.post_call_success_hook() after reading non-streaming response body
  • Only fire when guardrails are explicitly configured for the pass-through endpoint (opt-in, no behavior
    change for existing users without guardrails)
  • Handle ModifyResponseException with post_call_failure_hook + 200 response (matches proxy_server.py
    and anthropic_endpoints patterns)
  • Add debug logging for non-JSON responses and non-dict hook return types

unified_guardrail.py

  • Add fallback to resolve call_type from logging_obj.call_type when route-based and response-type-based
    resolution both return None

Backwards Compatibility

Post-call hooks are gated on guardrails_to_run being non-empty — they only fire when guardrails are
explicitly configured for the pass-through endpoint. Existing pass-through users without guardrail
configuration see zero behavior change. This prevents default_on guardrails and CustomLogger callbacks
from unexpectedly activating on pass-through routes.

Test Plan

Manual end-to-end verification

Tested this PR against real Vertex AI (not mocks) using a local LiteLLM proxy built from this branch. Both the allow and block paths in the new code work as designed.

Setup

  • Branch: fix/passthrough-post-call-guardrails @ 9e09b19d6c, installed editable: uv pip install -e ".[proxy]"
  • Proxy config: one pass_through_endpoints entry targeting gemini-2.0-flash:generateContent on us-central1, attached to a custom CustomGuardrail registered with mode: post_call and default_on: true.
  • Custom guardrail's async_post_call_success_hook logs when fired and raises ModifyResponseException if the response contains a functionCall whose name matches a configured value.
  • Auth: bearer token from gcloud auth print-access-token (ADC), X-Goog-User-Project header for billing.
  general_settings:
    master_key: sk-test
    pass_through_endpoints:
      - path: "/vertex-test/generateContent"
        target: "https://us-central1-aiplatform.googleapis.com/v1/projects/<proj>/locations/us-central1/publishers/google/models/gemini-2.0-flash:generateContent"
        headers:
          Authorization: "Bearer os.environ/GOOGLE_ACCESS_TOKEN"
          X-Goog-User-Project: "os.environ/GOOGLE_QUOTA_PROJECT"
          Content-Type: "application/json"
        guardrails:
          pr-test-guardrail: null

  guardrails:
    - guardrail_name: "pr-test-guardrail"
      litellm_params:
        guardrail: test_guardrail.pr_test_guardrail
        mode: "post_call"
        default_on: true

Results

  1. Allow path — Vertex returns a benign functionCall: get_weather; guardrail returns the response unchanged.
  Request:  {"contents":[{"role":"user","parts":[{"text":"Call get_weather with location=San Francisco..."}]}], "tools":[...]}
  Hook log: [PR_TEST_GUARDRAIL] POST_CALL fired guardrail=pr-test-guardrail response_type=dict
  HTTP:     200
  Body:     {"candidates":[{"content":{"role":"model","parts":[{"functionCall":{"name":"get_weather","args":{"location":"San Francisco"}}}]}, ...}]}

post_call_success_hook fires exactly once per request (verified via inserted diagnostic); the original upstream body is forwarded byte-equivalent (content-length left intact since _content_modified stays False).

  1. Block path — Vertex returns functionCall: delete_everything; guardrail raises ModifyResponseException.
  Hook log: [PR_TEST_GUARDRAIL] POST_CALL fired ... blocking functionCall=delete_everything
  HTTP:     200
  Body:     {
              "error": {
                "message": "functionCall 'delete_everything' blocked by PRTestGuardrail",
                "type": "content_filter",
                "guardrail_name": "pr-test-guardrail",
                "model": "unknown"
              }
            }

Matches the new error envelope exactly (type, guardrail_name, model, message). post_call_failure_hook is invoked once (verified). 200 status returned per the PR's design choice for guardrail violations.

  1. No-guardrail regression — same endpoint with the guardrails: block on the pass-through entry removed: collect_guardrails returns None, post_call_success_hook is not invoked, response forwarded unchanged. Confirms the opt-in gate.

UTs

  • test_post_call_success_hook_called_when_guardrails_configured — verifies hook fires with guardrails
  • test_post_call_success_hook_skipped_when_no_guardrails — verifies no-op without guardrails
  • test_modify_response_exception_returns_200 — verifies guardrail violation returns 200 with message,
    calls post_call_failure_hook, includes usage
  • test_pass_through_call_type_resolved_from_logging_obj — verifies unified guardrail resolves
    call_type for pass-through endpoints

Limitations (follow-up)

  • Streaming pass-through responses are not covered (non-streaming only in this PR)
  • PassThroughEndpointHandler.process_output_response() extracts texts but not tool_calls from the
    response — guardrails that inspect tool calls from native provider formats need a separate enhancement

@CLAassistant

CLAassistant commented Apr 22, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@codspeed-hq

codspeed-hq Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Congrats! CodSpeed is installed 🎉

🆕 16 new benchmarks were detected.

You will start to see performance impacts in the reports once the benchmarks are run from your default branch.

Detected benchmarks


Open in CodSpeed

@greptile-apps

greptile-apps Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR wires post-call guardrails into non-streaming pass-through endpoint responses (/vertex_ai/*, /openai/*, /bedrock/*). It moves ModifyResponseException from custom_guardrail.py into litellm/exceptions.py, adds a post_call_success_hook invocation gated on guardrails_to_run, handles the ModifyResponseException path with a 200 response, strips stale content-length on body rewrites, and adds a call_type fallback in unified_guardrail.py for pass-through routes. The previously flagged 400-vs-200 status code and stale content-length issues from prior review rounds are both fixed in the current commit.

Confidence Score: 4/5

Safe to merge with one small logging-accuracy fix worth addressing before or after merge.

The three previously flagged P0/P1 issues (400 vs 200 status, stale content-length, ModifyResponseException placement) are all resolved in the current commit. The remaining open item is the logging payload recording None when a post-call hook returns a non-dict — a correctness issue for observability but not for the client-facing response.

litellm/proxy/pass_through_endpoints/pass_through_endpoints.py — the response_body variable should be restored to its pre-hook value when the hook returns a non-dict, so passthrough_logging_payload records the actual response body.

Important Files Changed

Filename Overview
litellm/exceptions.py Adds ModifyResponseException as a first-class exception; clean move from custom_guardrail.py, no issues.
litellm/integrations/custom_guardrail.py Replaces inline ModifyResponseException definition with a re-export from litellm.exceptions; backward-compatible and correct.
litellm/proxy/guardrails/guardrail_hooks/unified_guardrail/unified_guardrail.py Adds call_type fallback from litellm_logging_obj for pass-through routes; correctly keyed on CallTypes.pass_through.value == "pass_through_endpoint" and the handler exists in load_guardrail_translation_mappings().
litellm/proxy/pass_through_endpoints/pass_through_endpoints.py Core change: adds opt-in post_call_success_hook invocation, ModifyResponseException handler returning HTTP 200, and content-length strip on body rewrite. _content_modified is set to True whenever hook returns any dict (including unchanged), causing unconditional re-encoding for all guardrail-enabled requests.
tests/test_litellm/proxy/pass_through_endpoints/test_passthrough_post_call_guardrails.py New mock-only test file; covers hook firing, no-op path, ModifyResponseException→200, and unified guardrail call_type resolution. Compliant with repo mock-only test policy.

Sequence Diagram

sequenceDiagram
    participant Client
    participant PassThrough as pass_through_request()
    participant PreHook as proxy_logging_obj.pre_call_hook
    participant Upstream as Upstream Provider
    participant PostHook as proxy_logging_obj.post_call_success_hook
    participant UnifiedGuardrail as UnifiedLLMGuardrails
    participant PTHandler as PassThroughEndpointHandler

    Client->>PassThrough: POST /vertex_ai/* (with guardrails_config)
    PassThrough->>PassThrough: collect_guardrails() → guardrails_to_run
    PassThrough->>PassThrough: init logging_obj (call_type=pass_through_endpoint)
    PassThrough->>PreHook: pre_call_hook(data=_parsed_body)
    PreHook-->>PassThrough: possibly stripped data
    PassThrough->>Upstream: HTTP POST
    Upstream-->>PassThrough: JSON response
    alt guardrails_to_run non-empty AND response is JSON
        PassThrough->>PostHook: post_call_success_hook(hook_data, response_body)
        PostHook->>UnifiedGuardrail: async_post_call_success_hook()
        UnifiedGuardrail->>UnifiedGuardrail: resolve call_type
        UnifiedGuardrail->>PTHandler: process_output_response()
        PTHandler-->>UnifiedGuardrail: possibly modified response dict
        UnifiedGuardrail-->>PostHook: response dict
        PostHook-->>PassThrough: response dict
        alt guardrail raised ModifyResponseException
            PassThrough->>PassThrough: catch ModifyResponseException
            PassThrough->>Client: 200 + error envelope
        else normal path
            PassThrough->>PassThrough: re-encode if dict, strip content-length if modified
            PassThrough->>Client: 200 + response
        end
    else no guardrails or non-JSON
        PassThrough->>Client: 200 + original response bytes
    end
Loading

Reviews (9): Last reviewed commit: "test: add unit tests for pass-through po..." | Re-trigger Greptile

Comment thread litellm/proxy/pass_through_endpoints/pass_through_endpoints.py
Comment on lines +921 to +926
if response_body is not None and guardrails_to_run:
response_body = await proxy_logging_obj.post_call_success_hook(
data=_parsed_body,
user_api_key_dict=user_api_key_dict,
response=response_body, # type: ignore[arg-type]
)

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 post_call_success_hook also fires non-guardrail CustomLogger callbacks

proxy_logging_obj.post_call_success_hook() iterates litellm.callbacks and calls async_post_call_success_hook on every non-guardrail CustomLogger instance unconditionally (see utils.py lines 2086-2091). The PR description and backwards-compatibility note state that "CustomLogger callbacks" won't activate on pass-through routes, but any CustomLogger in the global callback list will actually fire whenever guardrails_to_run is non-empty — this is a broader behavior change than the documentation implies. Users who have both custom logging callbacks and a guardrail configured on a pass-through route may observe unexpected side effects from those logging callbacks. Consider documenting this, or filtering to only the guardrail code path if that was the intent.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Acknowledged — this is consistent with how post_call_success_hook works on all other endpoints (/chat/completions, /v1/messages, etc.) where both guardrail and non-guardrail CustomLogger callbacks fire in the same hook. Since pass-through guardrails are opt-in only (user must explicitly configure guardrails_config), enabling the hook is an intentional decision. Filtering to guardrail-only callbacks would diverge from the standard endpoint behavior and could surprise users who expect their logging callbacks to fire when guardrails are active. Happy to add a note in the PR description clarifying this.

Comment thread litellm/proxy/pass_through_endpoints/pass_through_endpoints.py Fixed
@tuhinspatra
tuhinspatra force-pushed the fix/passthrough-post-call-guardrails branch from d85481e to 0b89fd4 Compare April 22, 2026 19:37
@@ -34,6 +34,7 @@
from litellm._logging import verbose_proxy_logger
from litellm._uuid import uuid
from litellm.constants import MAXIMUM_TRACEBACK_LINES_TO_LOG
from litellm.integrations.custom_guardrail import ModifyResponseException
@@ -635,6 +635,7 @@ async def pass_through_request( # noqa: PLR0915
custom_llm_provider: Optional field - custom LLM provider for the endpoint
guardrails_config: Optional field - guardrails configuration for passthrough endpoint
"""
from litellm.integrations.custom_guardrail import ModifyResponseException
@@ -635,6 +635,7 @@
custom_llm_provider: Optional field - custom LLM provider for the endpoint
guardrails_config: Optional field - guardrails configuration for passthrough endpoint
"""
from litellm.integrations.custom_guardrail import ModifyResponseException
@tuhinspatra
tuhinspatra changed the base branch from main to litellm_oss_branch April 22, 2026 20:39
@gitguardian

gitguardian Bot commented Apr 22, 2026

Copy link
Copy Markdown

️✅ There are no secrets present in this pull request anymore.

If these secrets were true positive and are still valid, we highly recommend you to revoke them.
While these secrets were previously flagged, we no longer have a reference to the
specific commits where they were detected. Once a secret has been leaked into a git
repository, you should consider it compromised, even if it was deleted immediately.
Find here more information about risks.


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@tuhinspatra
tuhinspatra force-pushed the fix/passthrough-post-call-guardrails branch from 9e09b19 to 4d1da0a Compare April 22, 2026 21:00
Comment on lines +998 to 1011
error_body = {
"error": {
"message": e.message or "Response blocked by guardrail",
"type": "content_filter",
"guardrail_name": e.guardrail_name,
"model": e.model,
}
}
return Response(
content=json.dumps(error_body),
status_code=400,
media_type="application/json",
)
except Exception as e:

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.

P1 ModifyResponseException returns 400, but the contract requires 200

ModifyResponseException's own docstring says "It should be caught by the proxy and returned with a 200 status code", and both proxy_server.py (line 7168, comment: "return 200 with violation message") and anthropic_endpoints/endpoints.py (line 72, same comment) honour that. Returning 400 breaks clients that rely on the semantic guarantee that guardrail substitutions are surfaced as valid (200) responses, not as HTTP errors.

The PR description even names the test test_modify_response_exception_returns_200, but the committed test asserts result.status_code == 400 — confirming the intent was 200 and this is an unintended divergence.

        return Response(
            content=json.dumps(error_body),
            status_code=200,          # ← should be 200, not 400
            media_type="application/json",
        )

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in a5c7abe — changed back to status_code=200 to match the ModifyResponseException contract (consistent with proxy_server.py and anthropic_endpoints.py). The response body uses a provider-agnostic error envelope instead of ModelResponse since pass-through clients may be any provider (Gemini, Bedrock, etc.).

litellm_logging_obj is not None
and getattr(litellm_logging_obj, "call_type", None)
== CallTypes.pass_through.value
):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is a pre-existing log line in unified_guardrail.py (line 237: verbose_proxy_logger.debug("async_post_call_success_hook response: %s", response)) — not introduced by this PR. Our changes start at line 248 (the call_type fallback block). The CodeQL finding is on existing code that happens to be in the diff context.

self.guardrail_name = guardrail_name
self.detection_info = detection_info or {}
super().__init__(message)
from litellm.exceptions import ModifyResponseException as ModifyResponseException

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is a pre-existing cyclic import through litellm/__init__.py — not introduced by this PR. Our change actually improved the situation: we moved the import target from custom_guardrail (which chains into custom_logger → proxy code) to exceptions (a leaf module with only typing, httpx, openai, litellm.types.utils imports). The cycle CodeQL detects is the top-level litellm package re-export chain that affects virtually every module in the codebase.

@@ -635,6 +635,7 @@ async def pass_through_request( # noqa: PLR0915
custom_llm_provider: Optional field - custom LLM provider for the endpoint
guardrails_config: Optional field - guardrails configuration for passthrough endpoint
"""
from litellm.exceptions import ModifyResponseException

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Same as above — this is the same pre-existing litellm/__init__.py cycle, not introduced by this PR. The function-level import ensures no module-load-time issue; CodeQL is flagging the broader package-level cycle that exists for virtually every litellm.* module.

Comment on lines +751 to +757
# Re-apply guardrails metadata after pre_call_hook (which may return a stripped dict)
if guardrails_to_run:
if _parsed_body is None:
_parsed_body = {}
if "metadata" not in _parsed_body:
_parsed_body["metadata"] = {}
_parsed_body["metadata"]["guardrails"] = guardrails_to_run

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.

P1 litellm_logging_obj not re-applied after pre_call_hook, making the unified_guardrail fallback dead code

logging_obj is stored in _parsed_body["litellm_logging_obj"] at line 743, but when pre_call_hook returns a stripped dict (the comment at line 751 explicitly acknowledges this risk for metadata.guardrails), litellm_logging_obj is not re-applied. The re-apply block at lines 751–757 only restores metadata.guardrails.

As a result, when post_call_success_hook(data=_parsed_body, ...) is called at line 930, _parsed_body won't contain litellm_logging_obj, so data.get("litellm_logging_obj") in unified_guardrail.py line 232 always returns None — and the entire call_type resolution fallback added in this PR silently does nothing, causing the unified guardrail to fall through to return response unmodified.

        # Re-apply guardrails metadata after pre_call_hook (which may return a stripped dict)
        if guardrails_to_run:
            if _parsed_body is None:
                _parsed_body = {}
            if "metadata" not in _parsed_body:
                _parsed_body["metadata"] = {}
            _parsed_body["metadata"]["guardrails"] = guardrails_to_run
+           _parsed_body["litellm_logging_obj"] = logging_obj

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 059815fhook_data now explicitly includes litellm_logging_obj = logging_obj, ensuring the unified guardrail fallback can resolve call_type from data.get("litellm_logging_obj") regardless of what pre_call_hook does to _parsed_body.

…onses (BerriAI#20270)

Wire post_call_success_hook into non-streaming pass-through response path,
gated on explicit guardrail config (opt-in only, no backwards-compat break).

- Call post_call_success_hook after reading non-streaming response body
- Build enriched hook_data with guardrails metadata and litellm_logging_obj
  at call site (avoids mutation of _parsed_body which is shared by logging)
- Handle ModifyResponseException with provider-agnostic error envelope,
  post_call_failure_hook, and defensive try/except
- Strip stale content-length when guardrail modifies response body
- Move ModifyResponseException to litellm.exceptions to break cyclic import;
  re-export from custom_guardrail for backwards compat
- Add call_type fallback in UnifiedLLMGuardrails for pass-through endpoints
  using CallTypes.pass_through.value enum
5 tests covering the post-call guardrail invocation on pass-through endpoints:
- post_call_success_hook fires when guardrails configured
- post_call_success_hook skipped when no guardrails (backwards compat)
- ModifyResponseException returns 200 with provider-agnostic error
- UnifiedLLMGuardrails resolves call_type from logging_obj for pass-through
- ModifyResponseException re-export from custom_guardrail stays in sync
@tuhinspatra
tuhinspatra force-pushed the fix/passthrough-post-call-guardrails branch from a2d1d95 to 32cdace Compare April 23, 2026 20:07
@veria-ai

veria-ai Bot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Low: No security issues found

This PR enables post-call guardrail invocation on pass-through endpoint responses, which is a security improvement — guardrails that previously didn't run on pass-through responses now get invoked. The ModifyResponseException class was moved to a shared location (pure refactor). Error responses from guardrail interventions use guardrail-provided fields (not user input). No injection, auth bypass, or data exposure patterns found.


Status: 0 open
Risk: 2/10

Posted by Veria AI · 2026-04-23T20:09:46.114Z

@tuhinspatra

Copy link
Copy Markdown
Contributor Author

Hi @ishaan-jaff @krrish-berri-2 - this PR is ready for review:

  • All 4 CI checks passing (unit-test, GitGuardian, Greptile, Veria)
  • 3 rounds of internal review completed, all comments addressed
  • Manually tested end-to-end with Vertex AI / Gemini pass-through + guardrails
  • Small, focused change: 5 files, 2 clean commits (production fix + tests)
  • Fixes a real gap reported in [Bug]: Passthrough Guardrails not working for post_call #20270 - post-call guardrails never fire on pass-through endpoints

Happy to address any feedback. Thanks!

@krrish-berri-2
krrish-berri-2 merged commit 17fef6e into BerriAI:litellm_oss_branch Apr 24, 2026
4 checks passed
Sameerlite pushed a commit that referenced this pull request Apr 27, 2026
…onses (#20270) (#26262)

* fix(proxy): invoke post-call guardrails on pass-through endpoint responses (#20270)

Wire post_call_success_hook into non-streaming pass-through response path,
gated on explicit guardrail config (opt-in only, no backwards-compat break).

- Call post_call_success_hook after reading non-streaming response body
- Build enriched hook_data with guardrails metadata and litellm_logging_obj
  at call site (avoids mutation of _parsed_body which is shared by logging)
- Handle ModifyResponseException with provider-agnostic error envelope,
  post_call_failure_hook, and defensive try/except
- Strip stale content-length when guardrail modifies response body
- Move ModifyResponseException to litellm.exceptions to break cyclic import;
  re-export from custom_guardrail for backwards compat
- Add call_type fallback in UnifiedLLMGuardrails for pass-through endpoints
  using CallTypes.pass_through.value enum

* test: add unit tests for pass-through post-call guardrails

5 tests covering the post-call guardrail invocation on pass-through endpoints:
- post_call_success_hook fires when guardrails configured
- post_call_success_hook skipped when no guardrails (backwards compat)
- ModifyResponseException returns 200 with provider-agnostic error
- UnifiedLLMGuardrails resolves call_type from logging_obj for pass-through
- ModifyResponseException re-export from custom_guardrail stays in sync
fzowl pushed a commit to fzowl/litellm that referenced this pull request Jun 24, 2026
…onses (BerriAI#20270) (BerriAI#26262)

* fix(proxy): invoke post-call guardrails on pass-through endpoint responses (BerriAI#20270)

Wire post_call_success_hook into non-streaming pass-through response path,
gated on explicit guardrail config (opt-in only, no backwards-compat break).

- Call post_call_success_hook after reading non-streaming response body
- Build enriched hook_data with guardrails metadata and litellm_logging_obj
  at call site (avoids mutation of _parsed_body which is shared by logging)
- Handle ModifyResponseException with provider-agnostic error envelope,
  post_call_failure_hook, and defensive try/except
- Strip stale content-length when guardrail modifies response body
- Move ModifyResponseException to litellm.exceptions to break cyclic import;
  re-export from custom_guardrail for backwards compat
- Add call_type fallback in UnifiedLLMGuardrails for pass-through endpoints
  using CallTypes.pass_through.value enum

* test: add unit tests for pass-through post-call guardrails

5 tests covering the post-call guardrail invocation on pass-through endpoints:
- post_call_success_hook fires when guardrails configured
- post_call_success_hook skipped when no guardrails (backwards compat)
- ModifyResponseException returns 200 with provider-agnostic error
- UnifiedLLMGuardrails resolves call_type from logging_obj for pass-through
- ModifyResponseException re-export from custom_guardrail stays in sync
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.

4 participants