Skip to content

feat(http): add canonical request lifecycle - #2210

Merged
Pouyanpi merged 6 commits into
developfrom
pouyanpi/rail-library-stack-11-http-observability
Jul 29, 2026
Merged

feat(http): add canonical request lifecycle#2210
Pouyanpi merged 6 commits into
developfrom
pouyanpi/rail-library-stack-11-http-observability

Conversation

@Pouyanpi

@Pouyanpi Pouyanpi commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Description

Adds the canonical http_call request helper and managed HTTP client
composition on top of the Stack 9 contract.

Design principle: lifecycle ownership is explicit. Injected clients remain
caller-owned; only fallback clients created by http_call are closed by the
helper. Request execution therefore stays transport-neutral and can be reused by
IORails or library integrations without duplicating cleanup logic.

Instrumentation is intentionally separate in sibling Stack 10. It decorates the
same client contract without becoming a dependency of the request lifecycle or
later migrations.

Layer Base PR
HTTP contract develop #2209
HTTP instrumentation Stack 9 #2219
Request lifecycle Stack 9 #2210
Request migrations Stack 11 #2211
Action migrations Stack 12 #2212

Related Issue(s)

  • Internal tracking: NGUARD-857, NGUARD-860

Verification

  • make test TEST="tests/http" — 65 passed.
  • Pre-commit passed on the changed files.
  • Tests made no live provider calls.

AI Assistance

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

Codex assisted with implementation, validation, and stack restructuring. Check
the disclosure box after human review.

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 a transport-neutral asynchronous HTTP client interface.
    • Added HTTP request and response handling with status checks, JSON parsing, and clear error reporting.
    • Added configurable retries for eligible failures, including backoff and Retry-After support.
    • Added URL sanitization to protect credentials and sensitive query information in errors.
    • Added HTTPX integration with configurable timeouts, redirects, and connection limits.
    • Added request helpers and deterministic testing utilities.

@github-actions github-actions Bot added status: needs triage New issues that have not yet been reviewed or categorized. size: L labels Jul 23, 2026
@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-11-http-observability branch from 07e412a to 1743c83 Compare July 23, 2026 14:42
@Pouyanpi Pouyanpi changed the title feat(http): add privacy-safe client lifecycle and observability feat(http): add canonical request helper and client instrumentation Jul 23, 2026
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-11-http-observability branch from 1743c83 to 6fad585 Compare July 23, 2026 16:21
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-11-http-observability branch from 6fad585 to 95c2003 Compare July 23, 2026 16:28
@Pouyanpi
Pouyanpi marked this pull request as ready for review July 23, 2026 16:37
@Pouyanpi Pouyanpi 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 23, 2026
@Pouyanpi Pouyanpi self-assigned this Jul 23, 2026
@Pouyanpi Pouyanpi added this to the v0.24.0 milestone Jul 23, 2026
@greptile-apps

greptile-apps Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds the canonical http_call request helper and create_http_client factory, completing the Stack 9 HTTP lifecycle layer. Ownership semantics are explicit and consistent: injected clients are yielded and left unclosed; clients created by the helper are always released in the finally block regardless of request outcome.

  • request.py introduces _resolve_http_client (an async context manager) and http_call, which captures the response inside the context manager and performs status-error raising after cleanup — safe because HTTPResponse holds materialized bytes independent of the transport.
  • runtime.py composes HttpxHTTPClient and RetryingHTTPClient into a single closable client, delegating the injected-vs-owned validation to the transport layer.
  • errors.py extends HTTPStatusError to extract retry_count from response.extensions, aligning status-error metadata with what RetryingHTTPClient already records for transport errors.

Confidence Score: 5/5

Safe to merge — ownership semantics, cleanup paths, and error context are all correct.

The request lifecycle, client ownership rules, and retry-count propagation are correctly implemented and well-tested. The one comment flagged (duplicated timeout constant) is a future maintenance concern, not a current defect.

Files Needing Attention: nemoguardrails/http/runtime.py — the 30.0 literal should be kept in sync with _DEFAULT_TIMEOUT_SECONDS in transport.py.

Important Files Changed

Filename Overview
nemoguardrails/http/request.py New file implementing managed request lifecycle: _resolve_http_client context manager handles client ownership (injected vs owned), and http_call wraps request execution with deterministic cleanup and optional status-error raising. Logic is sound.
nemoguardrails/http/runtime.py New file providing create_http_client factory that composes HttpxHTTPClient and RetryingHTTPClient. Delegation of validation to the transport layer is intentional; duplicated timeout constant is flagged.
nemoguardrails/http/errors.py HTTPStatusError now extracts retry_count from response.extensions, overriding the base-class default of 0. Type guard on the extracted value is correct.
tests/http/test_request.py Good coverage of ownership semantics, status-error raising, credential sanitization, and error propagation. All assertions are specific and deterministic.
tests/http/test_runtime.py Covers factory composition (with and without retry), option forwarding, and close delegation. Test assertions are correct against the implementation.
nemoguardrails/http/init.py Exports create_http_client and http_call; public surface is minimal and consistent with the rest of the module.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["http_call(client, method, url, ...)"] --> B{client provided?}
    B -- Yes --> C["_resolve_http_client yields injected client\n(no ownership taken)"]
    B -- No --> D["factory() → owned ClosableHTTPClient"]
    D --> E{isinstance ClosableHTTPClient?}
    E -- No --> F["raise TypeError"]
    E -- Yes --> G["_resolve_http_client yields owned client\n(finally: await owned.close())"]
    C --> H["resolved.request(method, url, ...)"]
    G --> H
    H -- raises --> I["Exception propagates\n(owned client still closed via finally)"]
    H -- success --> J["response captured outside context manager"]
    J --> K{raise_for_status\nand status >= 400?}
    K -- No --> L["return response"]
    K -- Yes --> M["response.raise_for_status(HTTPRequest(...))\n-> HTTPStatusError with sanitized URL\n   and retry_count from extensions"]
Loading

Reviews (6): Last reviewed commit: "perf(http): skip success request context" | Re-trigger Greptile

Comment thread nemoguardrails/http/request.py
Comment thread nemoguardrails/http/request.py Outdated
Comment thread nemoguardrails/http/instrumentation.py Outdated
Comment thread nemoguardrails/http/instrumentation.py Outdated
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-11-http-observability branch from eb9066c to 9138450 Compare July 24, 2026 10:14
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-11-http-observability branch from 9138450 to 623ba26 Compare July 24, 2026 15:53
@github-actions github-actions Bot added size: M and removed size: L labels Jul 24, 2026
@Pouyanpi Pouyanpi changed the title feat(http): add canonical request helper and client instrumentation feat(http): add canonical request lifecycle Jul 24, 2026

@tgasser-nv tgasser-nv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks good!

nit: Could you add add docstrings to the new files to match the existing files like client.py, types.py, etc in this directory?

Comment thread tests/http/test_runtime.py
Comment thread nemoguardrails/http/runtime.py
Comment thread nemoguardrails/http/runtime.py Outdated
Comment thread nemoguardrails/http/request.py
Base automatically changed from pouyanpi/rail-library-stack-9-http-contract to develop July 29, 2026 07:40
Pouyanpi added 2 commits July 29, 2026 09:43
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-11-http-observability branch from 623ba26 to 4d67108 Compare July 29, 2026 07:45
Pouyanpi added 3 commits July 29, 2026 09:51
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d91f7d5a-2b18-4ec5-a240-2677bac25759

📥 Commits

Reviewing files that changed from the base of the PR and between 83d2211 and 623ba26.

📒 Files selected for processing (16)
  • nemoguardrails/http/__init__.py
  • nemoguardrails/http/_url.py
  • nemoguardrails/http/client.py
  • nemoguardrails/http/errors.py
  • nemoguardrails/http/request.py
  • nemoguardrails/http/retry.py
  • nemoguardrails/http/runtime.py
  • nemoguardrails/http/testing.py
  • nemoguardrails/http/transport.py
  • nemoguardrails/http/types.py
  • tests/http/test_contract.py
  • tests/http/test_request.py
  • tests/http/test_retry.py
  • tests/http/test_runtime.py
  • tests/http/test_transport.py
  • tests/http/test_url.py

📝 Walkthrough

Walkthrough

Introduces a transport-neutral asynchronous HTTP package with request/response types, client protocols, HTTPX transport, retry handling, lifecycle management, URL sanitization, runtime composition, test doubles, and comprehensive tests.

Changes

HTTP foundation

Layer / File(s) Summary
Contracts, values, errors, and URL handling
nemoguardrails/http/__init__.py, nemoguardrails/http/client.py, nemoguardrails/http/errors.py, nemoguardrails/http/types.py, nemoguardrails/http/_url.py, tests/http/test_contract.py, tests/http/test_url.py
Defines transport-neutral request/response objects, client protocols, error types, response decoding/status helpers, URL sanitization, and public exports.
HTTPX transport adapter
nemoguardrails/http/transport.py, tests/http/test_transport.py
Forwards requests through HTTPX, materializes neutral responses, enforces timeouts, translates transport failures, and manages owned clients.
Retry policy and retrying client
nemoguardrails/http/retry.py, tests/http/test_retry.py
Adds configurable status and transport retries, Retry-After parsing, exponential backoff, retry metadata, method filtering, and cleanup behavior.
Request orchestration and runtime composition
nemoguardrails/http/request.py, nemoguardrails/http/runtime.py, nemoguardrails/http/testing.py, tests/http/test_request.py, tests/http/test_runtime.py, tests/http/test_contract.py
Adds managed-client resolution, http_call, runtime client construction, and a recording test client with lifecycle and forwarding tests.

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

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant http_call
  participant create_http_client
  participant RetryingHTTPClient
  participant HttpxHTTPClient
  Caller->>http_call: submit HTTP request
  http_call->>create_http_client: create client
  create_http_client->>RetryingHTTPClient: optionally configure retries
  RetryingHTTPClient->>HttpxHTTPClient: send request
  HttpxHTTPClient-->>RetryingHTTPClient: response or transport error
  RetryingHTTPClient-->>http_call: final response
  http_call-->>Caller: return response or raise error
Loading

Possibly related PRs

  • NVIDIA-NeMo/Guardrails#2209: Overlaps with the transport-neutral HTTP contracts, retrying client, HTTPX adapter, and related exports.
🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: adding a canonical HTTP request helper and managed client lifecycle.
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.
Test Results For Major Changes ✅ Passed The PR is a major HTTP subsystem addition, and its description includes verification details: 65 passing HTTP tests, pre-commit checks, and no live provider calls.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch pouyanpi/rail-library-stack-11-http-observability
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pouyanpi/rail-library-stack-11-http-observability

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

Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
@github-actions github-actions Bot added size: L and removed size: M labels Jul 29, 2026
@Pouyanpi
Pouyanpi merged commit ccc8255 into develop Jul 29, 2026
15 checks passed
@Pouyanpi
Pouyanpi deleted the pouyanpi/rail-library-stack-11-http-observability branch July 29, 2026 08:01
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.

2 participants