Skip to content

feat(iorails): Inference-time http headers - #2227

Draft
tgasser-nv wants to merge 6 commits into
developfrom
feat/iorails-custom-headers-inference
Draft

feat(iorails): Inference-time http headers#2227
tgasser-nv wants to merge 6 commits into
developfrom
feat/iorails-custom-headers-inference

Conversation

@tgasser-nv

@tgasser-nv tgasser-nv commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Description

Adds inference-time headers to IORails with connection through Guardrails facade. This allows clients to set per-inference headers (for tracking or governance)

Related Issue(s)

Verification

AI Assistance

  • No AI tools were used.
  • AI tools were used; a human reviewed and can explain every change (tool: ___).

Checklist

  • I've read the CONTRIBUTING guidelines.
  • This PR links to a triaged issue assigned to me.
  • My PR title follows the project commit convention.
  • I've updated the documentation if applicable.
  • I've added tests if applicable.
  • I've noted any verification beyond CI and any checks I couldn't run.
  • I did not update generated changelog files manually.
  • I addressed all CodeRabbit, Greptile, and other review comments, or replied with why no change is needed.
  • @mentions of the person or team responsible for reviewing proposed changes.

Summary by CodeRabbit

  • New Features

    • Added support for configuring default HTTP headers for model requests.
    • Added per-request HTTP headers for synchronous, asynchronous, and streaming inference.
    • Per-request headers override configured headers case-insensitively and apply across provider calls.
    • Headers are kept separate from request bodies and values are converted to strings.
  • Documentation

    • Added configuration guidance, precedence rules, and security recommendations.
    • Documented that per-request headers are supported only with IORails.

@github-actions github-actions Bot added status: needs triage New issues that have not yet been reviewed or categorized. size: L labels Jul 27, 2026
@tgasser-nv tgasser-nv self-assigned this Jul 27, 2026
@tgasser-nv tgasser-nv added status: triaged Triaged by a maintainer; eligible for automated review (CodeRabbit/Greptile). and removed status: needs triage New issues that have not yet been reviewed or categorized. labels Jul 27, 2026
@tgasser-nv
tgasser-nv marked this pull request as ready for review July 27, 2026 22:00
@greptile-apps

greptile-apps Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds request-scoped HTTP headers to the IORails inference pipeline.

  • Extends the Guardrails and IORails generation and streaming APIs with http_headers.
  • Propagates headers through request-scoped context to model and jailbreak-detection API calls.
  • Adds case-insensitive layering for base, configured default, and per-request headers.
  • Documents header precedence, engine support, and configuration behavior.
  • Adds unit and integration coverage for propagation, isolation, streaming, and header merging.

Confidence Score: 5/5

The pull request appears safe to merge, with no actionable defects identified in the changed header propagation paths.

Request headers are scoped around each IORails operation, read at centralized outbound call sites, kept out of provider request bodies, layered case-insensitively, and cleaned up across normal, exceptional, and streaming lifecycles.

Important Files Changed

Filename Overview
nemoguardrails/guardrails/guardrails.py Extends the public generation and streaming facade with explicit IORails header forwarding and LLMRails rejection.
nemoguardrails/guardrails/iorails.py Binds inference headers to non-streaming and streaming request lifecycles before rail and model execution.
nemoguardrails/guardrails/guardrails_types.py Introduces the request-scoped header ContextVar, coercion, nesting, and cross-context teardown handling.
nemoguardrails/guardrails/engine_registry.py Reads request headers at the outbound-call choke points and keeps them separate from provider request bodies.
nemoguardrails/guardrails/model_engine.py Implements configured and inference-time header precedence while reserving transport-only parameter names.
nemoguardrails/guardrails/api_engine.py Applies inference-time headers to arbitrary API rail requests without adding them to JSON bodies.
nemoguardrails/guardrails/_http.py Adds a non-mutating, case-insensitive header merge helper.
docs/configure-rails/yaml-schema/model-configuration.mdx Documents configured and per-request headers, precedence, coercion, and IORails-only runtime support.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Facade as Guardrails
    participant IO as IORails
    participant Context as Request Header Context
    participant Registry as EngineRegistry
    participant Engine as ModelEngine/APIEngine
    participant Provider

    Client->>Facade: generate/stream(http_headers)
    Facade->>IO: Forward request headers
    IO->>Context: Bind headers for request scope
    IO->>Registry: Run main and rail calls
    Registry->>Context: Read current headers
    Registry->>Engine: Call with http_headers
    Engine->>Engine: Merge base, default, request headers
    Engine->>Provider: HTTP request
    Provider-->>Engine: Response
    Engine-->>Client: Guarded response or stream
    IO->>Context: Restore prior header context
Loading

Reviews (1): Last reviewed commit: "Initial checkin of inference-time http h..." | Re-trigger Greptile

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds parameters.default_headers and request-scoped http_headers support. Headers are merged case-insensitively, remain outside request bodies, propagate through synchronous, asynchronous, streaming, model, and API paths, and are supported for IORails only at inference time.

Changes

HTTP header composition

Layer / File(s) Summary
Header composition and transport requests
docs/configure-rails/..., nemoguardrails/guardrails/_http.py, nemoguardrails/guardrails/model_engine.py, nemoguardrails/guardrails/api_engine.py, tests/guardrails/test__http.py, tests/guardrails/test_model_engine.py, tests/guardrails/test_api_engine.py
Adds case-insensitive merging, immutable configured defaults, precedence for base/configured/request headers, and transport-only handling for model and API requests.

Request propagation

Layer / File(s) Summary
Request-scoped propagation and engine routing
nemoguardrails/guardrails/guardrails_types.py, nemoguardrails/guardrails/iorails.py, nemoguardrails/guardrails/engine_registry.py, nemoguardrails/guardrails/guardrails.py, tests/guardrails/test_guardrails_types.py, tests/guardrails/test_engine_registry.py, tests/guardrails/test_guardrails.py, tests/guardrails/test_iorails_streaming.py
Binds headers with a ContextVar, forwards them through IORails and EngineRegistry paths, supports streaming, and raises NotImplementedError for LLMRails inference headers.

End-to-end validation

Layer / File(s) Summary
End-to-end propagation validation
tests/guardrails/test_iorails.py
Verifies model-specific configured headers, inference-time overrides, cleanup after success and failure, wire-level propagation, and exclusion from request bodies.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant IORails
  participant EngineRegistry
  participant ModelEngine
  participant Provider
  Caller->>IORails: generate or stream with http_headers
  IORails->>IORails: Bind request-scoped headers
  IORails->>EngineRegistry: Execute provider calls
  EngineRegistry->>ModelEngine: Pass request headers
  ModelEngine->>Provider: Send merged HTTP headers
  IORails->>IORails: Reset request-scoped headers
Loading

Possibly related PRs

  • NVIDIA-NeMo/Guardrails#2220: Adds the shared case-insensitive header merging and configured default-header propagation extended by this PR.

Suggested reviewers: cparisien, pouyanpi

🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Test Results For Major Changes ⚠️ Warning Major new header-plumbing feature spans engine, facade, docs, and tests, but the PR description's Verification section is blank and gives no test results/testing info. Add the tests run and outcomes (unit/e2e or CI results) to the PR description; if nothing was run, state that explicitly.
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 91.27% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: adding inference-time HTTP headers for IORails.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/iorails-custom-headers-inference

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@nemoguardrails/guardrails/model_engine.py`:
- Around line 91-100: Update the parameter-merging flow in the model engine to
remove or reject the runtime GenerationOptions.llm_params entry named
http_headers before forwarding arguments to engine.chat_completion(). Ensure it
cannot collide with the explicit http_headers keyword, while preserving the
existing filtering of config-time parameters.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 5e0ed380-df0b-4352-a4e9-51e0a3000e26

📥 Commits

Reviewing files that changed from the base of the PR and between e267714 and fd22f2e.

📒 Files selected for processing (16)
  • docs/configure-rails/yaml-schema/model-configuration.mdx
  • nemoguardrails/guardrails/_http.py
  • nemoguardrails/guardrails/api_engine.py
  • nemoguardrails/guardrails/engine_registry.py
  • nemoguardrails/guardrails/guardrails.py
  • nemoguardrails/guardrails/guardrails_types.py
  • nemoguardrails/guardrails/iorails.py
  • nemoguardrails/guardrails/model_engine.py
  • tests/guardrails/test__http.py
  • tests/guardrails/test_api_engine.py
  • tests/guardrails/test_engine_registry.py
  • tests/guardrails/test_guardrails.py
  • tests/guardrails/test_guardrails_types.py
  • tests/guardrails/test_iorails.py
  • tests/guardrails/test_iorails_streaming.py
  • tests/guardrails/test_model_engine.py

Comment on lines +91 to +100
# client-only options — these configure transport, not the
# chat-completion request body, so they are never forwarded as body
# fields.
"default_headers",
"default_query",
# inference-time header argument name — reserved so a model configured
# with `parameters.http_headers` (the per-request argument mistaken for
# the config key `default_headers`) can't collide with the explicit
# http_headers keyword the engine registry passes into chat_completion().
"http_headers",

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether llm_params / GenerationOptions filters reserved keys like "http_headers" before merging.
rg -nP -C5 'llm_params' nemoguardrails/guardrails/engine_registry.py nemoguardrails/rails/llm/options.py 2>/dev/null

Repository: NVIDIA-NeMo/Guardrails

Length of output: 5098


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '190,230p' nemoguardrails/guardrails/engine_registry.py
printf '\n---\n'
sed -n '1,220p' nemoguardrails/guardrails/model_engine.py

Repository: NVIDIA-NeMo/Guardrails

Length of output: 11304


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "_RESERVED_LLM_PARAMETERS|http_headers|get_http_headers\(|merged_params = \{\*\*engine.body_param_defaults, \*\*kwargs\}" nemoguardrails/guardrails nemoguardrails/rails/llm

Repository: NVIDIA-NeMo/Guardrails

Length of output: 7151


Prevent llm_params.http_headers from colliding with the explicit header kwarg. The reserved set only filters config-time parameters; a runtime GenerationOptions.llm_params value named http_headers can still reach engine.chat_completion(...) and trigger a duplicate-key TypeError. Reject or strip that key before merging.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nemoguardrails/guardrails/model_engine.py` around lines 91 - 100, Update the
parameter-merging flow in the model engine to remove or reject the runtime
GenerationOptions.llm_params entry named http_headers before forwarding
arguments to engine.chat_completion(). Ensure it cannot collide with the
explicit http_headers keyword, while preserving the existing filtering of
config-time parameters.

@tgasser-nv
tgasser-nv marked this pull request as draft July 28, 2026 13:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: L status: triaged Triaged by a maintainer; eligible for automated review (CodeRabbit/Greptile).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant