Skip to content

fix(responses): preserve custom tools through guardrails - #34361

Draft
mayank-affirm wants to merge 1 commit into
BerriAI:litellm_internal_stagingfrom
mayank-affirm:litellm_preserve_custom_tools_through_guardrails
Draft

fix(responses): preserve custom tools through guardrails#34361
mayank-affirm wants to merge 1 commit into
BerriAI:litellm_internal_stagingfrom
mayank-affirm:litellm_preserve_custom_tools_through_guardrails

Conversation

@mayank-affirm

Copy link
Copy Markdown

TLDR

Problem this solves:

  • Custom tools lose their Responses shape after guardrails
  • Custom outputs can skip guardrail inspection

How it solves it:

  • Restore only unchanged custom tools after guardrails
  • Inspect custom calls across all response paths

Relevant issues

Follow-up to #32258

Linear ticket

Pre-Submission checklist

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

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

The proxy used a live provider-backed model with a pass-through request and response guardrail

Request used for both runs:

{
  "model": "glm-local",
  "input": "Call exec with exactly text(\"OK\"). Do not answer in prose.",
  "tools": [
    {
      "type": "custom",
      "name": "exec",
      "description": "Execute JavaScript and return its output",
      "format": {
        "type": "grammar",
        "syntax": "lark",
        "definition": "start: /[\\s\\S]+/"
      }
    }
  ],
  "tool_choice": {
    "type": "custom",
    "name": "exec"
  },
  "max_output_tokens": 100
}

Before (baf85d7):

HTTP 500
Invalid tool choice, tool_choice={'type': 'custom', 'name': 'exec'}

After (4fbe675):

HTTP 200
x-litellm-applied-guardrails: live-pass-through
LIVE_GUARDRAIL {"input_type":"request","tool_count":1,"tool_names":["exec"]}
LIVE_GUARDRAIL {"input_type":"response","tool_count":1,"tool_names":["exec"]}
{
  "status": "completed",
  "output": [
    {
      "type": "custom_tool_call",
      "name": "exec",
      "input": "text(\"OK\")",
      "arguments": null
    }
  ]
}

Type

🐛 Bug Fix

Changes

The Responses bridge added in #32258 projects custom tools into functions for Chat Completions providers. Responses guardrail processing kept that projected function after inspection, so downstream clients received a function_call instead of the original custom_tool_call. Response guardrails also omitted custom calls from completed responses and response.output_item.done streaming events

This change restores an original custom tool only when the guardrail output exactly matches its function projection. Guardrail removals, reordering, modifications, and injected tools remain intact. Forced custom tool choices are translated for the provider, raw custom inputs are wrapped for guardrail inspection, and tool-call output indexes are preserved

Regression tests cover unchanged and modified custom tools, removed and reordered tools, injected tools, forced custom choices, Pydantic and dictionary outputs, completed and streaming responses, guardrail blocking, and output index preservation

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

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

Files with missing lines Patch % Lines
.../openai/responses/guardrail_translation/handler.py 93.75% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing mayank-affirm:litellm_preserve_custom_tools_through_guardrails (4fbe675) with litellm_internal_staging (baf85d7)

Open in CodSpeed

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