Skip to content

fix(inference): shim globalThis.fetch to proxy inference.local for cr…#4916

Open
Abhi190702 wants to merge 5 commits into
NVIDIA:mainfrom
Abhi190702:fix/4730-fetch-proxy-inference-local
Open

fix(inference): shim globalThis.fetch to proxy inference.local for cr…#4916
Abhi190702 wants to merge 5 commits into
NVIDIA:mainfrom
Abhi190702:fix/4730-fetch-proxy-inference-local

Conversation

@Abhi190702

@Abhi190702 Abhi190702 commented Jun 7, 2026

Copy link
Copy Markdown

Summary

This PR fixes a bug where cron agentTurn jobs using a local inference provider (Ollama or vLLM, configured to map via the virtual host https://inference.local/v1) are skipped.
At execution time, the OpenClaw cron scheduler runs a "provider preflight" check using Node’s native fetch() (backed by undici in Node 18+). Since fetch() bypasses the legacy http.request network stack, it bypasses the sandbox's existing proxy-rewrite logic, attempts raw DNS resolution for the virtual hostname inference.local, and fails with getaddrinfo EAI_AGAIN. By shimming fetch() for inference.local requests, the preflight check is correctly routed through the OpenShell sandbox proxy.

Related Issue

Fixes #4730

Changes

  • Extended http-proxy-fix.js to Shim globalThis.fetch:
    • Overrides global fetch (only on Node runtimes >= 18).
    • Limits interception strictly to requests targeting the virtual hostname inference.local (all other hosts bypass the wrapper).
    • Converts matching fetch calls into the same HTTP FORWARD-mode structure that is intercepted and handled by the existing, robust http.request proxy rewrite.
    • Translates streaming response bodies back to native WHATWG streams using stream.Readable.toWeb(res) to preserve full streaming compatibility for downstream LLM consumers.
    • Guarded by __nemoclawFetchPatched to remain completely idempotent when loaded multiple times.
  • Fixed Case-Insensitive Environment collisions in Test Suites:
    • Removed duplicate stubs setting both HTTPS_PROXY and https_proxy in test/http-proxy-fix-e2e.test.ts and test/http-proxy-fix-rewrite.test.ts to prevent test failures on Windows hosts where the environment block is case-insensitive.
  • Improved Platform Portability for Sync Tests:
    • Added conditional skip blocks in test/http-proxy-fix-sync.test.ts if a usable bash shell is not available locally, preventing false failures on Windows machines while ensuring the tests still fail and block regressions in Linux-based CI environments.
  • Added Comprehensive Regression Tests:
    • Introduced test/http-proxy-fix-fetch.test.ts with coverage for fetch rewrite, passthrough, idempotency, and Node < 18 fallback logic.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Verification

  • npx prek run --all-files passes (verified locally, excluding missing system-level hadolint tool on Windows environment)
  • npm test passes (verified all http-proxy-fix suites pass cleanly on Windows)
  • Tests added or updated for new or changed behavior
  • No secrets, API keys, or credentials committed
  • Docs updated for user-facing behavior changes
  • npm run docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: ABHIJEET RANJAN abhijeet.r1907@gmail.com

Summary by CodeRabbit

  • Bug Fixes

    • Ensure HTTPS requests via env proxy use CONNECT-style routing and strip hop-by-hop headers; fetch to the local inference endpoint is routed through the same proxy and patching is idempotent.
  • Tests

    • Added regression tests for fetch/proxy routing and idempotent patching; updated proxy test setups and added a bash-availability guard for one sync test.
  • Documentation

    • Expanded in-script comments explaining proxy/fetch routing behavior.

@copy-pr-bot

copy-pr-bot Bot commented Jun 7, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR extends the http-proxy-fix preload to intercept fetch() calls to https://inference.local/* and route them through the existing FORWARD-mode http.request rewrite, adds proxy parsing and an idempotent fetch patch, updates start-script docs, aligns test environment vars, adds fetch regression tests, and makes the sync test conditional on Bash availability.

Changes

Proxy Fetch Shim and Alignment

Layer / File(s) Summary
Proxy fix fetch shim implementation
nemoclaw-blueprint/scripts/http-proxy-fix.js, scripts/nemoclaw-start.sh
Updates header comments and proxy parsing; adds fetch detection/rewriting helpers that buffer bodies, copy headers, set content-length when needed, forward rewritten FORWARD-mode requests via http.request() -> https.request() targeting the real host, wrap responses into Response objects, and install an idempotent globalThis.fetch patch during init. Shell script docs expanded to describe the rewrite and fetch routing.
Test environment proxy variable alignment
test/http-proxy-fix-e2e.test.ts, test/http-proxy-fix-rewrite.test.ts
Adjusts beforeEach setup to set NODE_USE_ENV_PROXY=1 and HTTPS_PROXY to the configured proxy; removes prior clearing of lowercase/alternate proxy env vars.
Fetch routing regression test suite
test/http-proxy-fix-fetch.test.ts
New Vitest module that stubs/validates fetch routing: ensures fetch('https://inference.local/...') is rewritten through the proxy with correct host/port/path/method/headers/body; verifies non-inference.local requests bypass interception; checks idempotency and behavior when native fetch is absent.

Test Infrastructure Robustness

Layer / File(s) Summary
Bash availability check for sync test
test/http-proxy-fix-sync.test.ts
Adds tryUsableBash() probe using bash -lc, derives bashAvailable, throws in CI if missing, otherwise warns and skips locally; wraps existing preload sync test with it.skipIf(!bashAvailable) and updates Vitest import style.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant FetchShim as Fetch Shim
  participant HttpWrapper as http.request wrapper
  participant Proxy
  participant Destination as Real Host
  Client->>FetchShim: fetch('https://inference.local/...')
  FetchShim->>FetchShim: normalize URL, copy headers/body
  FetchShim->>HttpWrapper: http.request(proxyHost:proxyPort, path=fullTargetURL)
  HttpWrapper->>HttpWrapper: rewrite FORWARD-mode -> https.request(destHost, path)
  HttpWrapper->>Proxy: CONNECT / tunneled request
  Proxy->>Destination: tunnel to destination
  Destination-->>Proxy: response stream
  Proxy-->>HttpWrapper: proxied stream
  HttpWrapper-->>FetchShim: IncomingMessage stream
  FetchShim-->>Client: Response (stream/body)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#2344: Both PRs implement/extend the same proxy fix by wrapping http.request() and rewriting FORWARD-mode HTTPS proxy requests into https.request() calls.

Suggested labels

area: local-models

Suggested reviewers

  • prekshivyas

"🐰 I hopped through code, rewrote the trail,
Fetch calls to inference now ride the proxy rail.
Headers and bodies I bundle with care,
No DNS skip — the tunnel's laid bare.
A tiny patch, stitched once, light as hare."

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is truncated and incomplete, ending with 'cr…' instead of specifying the complete scope or objective. Complete the title to clearly describe what the fetch shim does (e.g., 'fix(inference): shim globalThis.fetch to proxy inference.local for cron jobs') for clarity.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR implements a fetch shim that routes inference.local requests through the proxy path, directly addressing the issue #4730 requirement to prevent DNS resolution failures for inference.local.
Out of Scope Changes check ✅ Passed All changes are in-scope: fetch shim and proxy routing for inference.local, test setup corrections for Windows compatibility, bash availability checks, and regression tests for the new fetch behavior.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@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.

🧹 Nitpick comments (2)
scripts/nemoclaw-start.sh (1)

2058-2072: Queue sandbox entrypoint E2Es for this change.

Because this script affects sandbox boot/runtime boundaries that unit tests miss, run:
gh workflow run nightly-e2e.yaml --ref <branch> -f jobs=sandbox-survival-e2e,sandbox-operations-e2e,cloud-e2e,openclaw-slack-pairing-e2e

As per coding guidelines, scripts/nemoclaw-start.sh changes should be validated with the listed sandbox E2E suites.

🤖 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 `@scripts/nemoclaw-start.sh` around lines 2058 - 2072, The change to
scripts/nemoclaw-start.sh must be validated by queuing the specified sandbox E2E
suites before merging: run the GitHub Actions workflow nightly-e2e.yaml against
your branch and pass the jobs input set to
sandbox-survival-e2e,sandbox-operations-e2e,cloud-e2e,openclaw-slack-pairing-e2e
(e.g. using the gh CLI: gh workflow run nightly-e2e.yaml --ref <branch> -f
jobs=sandbox-survival-e2e,sandbox-operations-e2e,cloud-e2e,openclaw-slack-pairing-e2e);
ensure the workflow completes successfully for scripts/nemoclaw-start.sh changes
and block merge until those E2E suites pass.

Source: Coding guidelines

nemoclaw-blueprint/scripts/http-proxy-fix.js (1)

23-27: Run the proxy-chain E2Es for this L7 rewrite before merge.

This path is explicitly marked for manual FORWARD-mode validation; run:
gh workflow run nightly-e2e.yaml --ref <branch> -f jobs=cloud-e2e,inference-routing-e2e

As per coding guidelines, nemoclaw-blueprint/scripts/http-proxy-fix.js changes require manual validation using cloud-e2e and inference-routing-e2e.

Also applies to: 246-260, 329-329

🤖 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 `@nemoclaw-blueprint/scripts/http-proxy-fix.js` around lines 23 - 27, This
change in nemoclaw-blueprint/scripts/http-proxy-fix.js touches a manual
FORWARD-mode L7 rewrite that must be validated by running the cloud and
inference routing end-to-end suites before merging: run the GitHub workflow
nightly-e2e.yaml with ref set to your branch and pass -f
jobs=cloud-e2e,inference-routing-e2e (gh workflow run nightly-e2e.yaml --ref
<branch> -f jobs=cloud-e2e,inference-routing-e2e), exercise the
https://inference.local/* fetch wrapper and confirm FORWARD-mode behavior, and
repeat validation for the other affected regions noted (around the other changes
at the same file ranges) before approving the PR.

Source: Coding guidelines

🤖 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.

Nitpick comments:
In `@nemoclaw-blueprint/scripts/http-proxy-fix.js`:
- Around line 23-27: This change in nemoclaw-blueprint/scripts/http-proxy-fix.js
touches a manual FORWARD-mode L7 rewrite that must be validated by running the
cloud and inference routing end-to-end suites before merging: run the GitHub
workflow nightly-e2e.yaml with ref set to your branch and pass -f
jobs=cloud-e2e,inference-routing-e2e (gh workflow run nightly-e2e.yaml --ref
<branch> -f jobs=cloud-e2e,inference-routing-e2e), exercise the
https://inference.local/* fetch wrapper and confirm FORWARD-mode behavior, and
repeat validation for the other affected regions noted (around the other changes
at the same file ranges) before approving the PR.

In `@scripts/nemoclaw-start.sh`:
- Around line 2058-2072: The change to scripts/nemoclaw-start.sh must be
validated by queuing the specified sandbox E2E suites before merging: run the
GitHub Actions workflow nightly-e2e.yaml against your branch and pass the jobs
input set to
sandbox-survival-e2e,sandbox-operations-e2e,cloud-e2e,openclaw-slack-pairing-e2e
(e.g. using the gh CLI: gh workflow run nightly-e2e.yaml --ref <branch> -f
jobs=sandbox-survival-e2e,sandbox-operations-e2e,cloud-e2e,openclaw-slack-pairing-e2e);
ensure the workflow completes successfully for scripts/nemoclaw-start.sh changes
and block merge until those E2E suites pass.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 8bb8c76b-ef65-451b-8a27-18f945b49a7a

📥 Commits

Reviewing files that changed from the base of the PR and between e2edaad and c9a1fa3.

📒 Files selected for processing (6)
  • nemoclaw-blueprint/scripts/http-proxy-fix.js
  • scripts/nemoclaw-start.sh
  • test/http-proxy-fix-e2e.test.ts
  • test/http-proxy-fix-fetch.test.ts
  • test/http-proxy-fix-rewrite.test.ts
  • test/http-proxy-fix-sync.test.ts
💤 Files with no reviewable changes (2)
  • test/http-proxy-fix-rewrite.test.ts
  • test/http-proxy-fix-e2e.test.ts

@cv cv added the v0.0.61 Release target label Jun 7, 2026
@wscurran wscurran added area: inference Inference routing, serving, model selection, or outputs bug-fix PR fixes a bug or regression provider: ollama Ollama local model provider behavior provider: vllm vLLM local or hosted provider behavior labels Jun 8, 2026
@wscurran

wscurran commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

✨ Thanks for submitting this detailed PR about shimming globalThis.fetch to proxy inference.local for cron agentTurn jobs using a local inference provider. This proposes a way to fix the regression in the inference area.


Related open issues:

@Abhi190702

Copy link
Copy Markdown
Author

Thanks for the review.

On the two nitpicks from CodeRabbit — I don't have access to
trigger the nightly-e2e.yaml workflow directly from a fork PR,
so I can't run sandbox-survival-e2e, sandbox-operations-e2e,
cloud-e2e or inference-routing-e2e myself. If a maintainer is
able to queue those E2E suites against this branch, I'm happy
to wait for them to pass before merge.

Let me know if there's
anything else I can address from my side.

@cv cv self-assigned this Jun 8, 2026
@cv cv added v0.0.62 Release target v0.0.63 Release target and removed v0.0.61 Release target v0.0.62 Release target labels Jun 8, 2026
@jyaunches jyaunches added v0.0.64 Release target and removed v0.0.63 Release target labels Jun 11, 2026
@Abhi190702 Abhi190702 force-pushed the fix/4730-fetch-proxy-inference-local branch 2 times, most recently from cc75ff1 to 6938c37 Compare June 11, 2026 12:26
…on preflight

Cron agentTurn jobs using a local Ollama provider were being skipped
because the cron scheduler's provider preflight uses fetch() (undici)
rather than http.request(), bypassing the OpenShell sandbox proxy that
routes the virtual hostname inference.local to the local Ollama instance.

The existing http-proxy-fix.js already patches http.request and
https.request to honour proxy env variables. The preflight never goes
through that path — it calls fetch() directly, which resolves
inference.local via raw DNS, gets EAI_AGAIN, and marks the provider
unreachable, causing the cron job to be skipped entirely.

Extended http-proxy-fix.js to wrap globalThis.fetch for requests whose
hostname is inference.local, routing them through the existing
proxy-aware path. Every other hostname passes through the original
fetch unchanged.

The shim is:
- Idempotent via __nemoclawFetchPatched guard
- A no-op when typeof globalThis.fetch !== 'function' (Node < 18)
- Scoped strictly to inference.local via URL hostname parsing
- Non-destructive to the existing http.request/https.request patch
- Free of hardcoded replacement addresses
- Does not modify NO_PROXY or the managed inference.local routing design

Also fixed in this commit:
- Pre-existing Windows env case collision (HTTPS_PROXY vs https_proxy)
  in the existing proxy test suite causing false failures on Windows
- Bash-dependent sync tests now skip locally when Bash/WSL is
  unavailable, but fail in CI to catch real regressions

Verification:
- npm test (proxy-focused suites) passed
- npm run typecheck passed
- node --check http-proxy-fix.js passed
- git diff --check passed

Fixes NVIDIA#4730

# Conflicts:
#	test/http-proxy-fix-sync.test.ts
@Abhi190702 Abhi190702 force-pushed the fix/4730-fetch-proxy-inference-local branch from 6938c37 to 564b9a3 Compare June 11, 2026 12:29

@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.

🧹 Nitpick comments (1)
nemoclaw-blueprint/scripts/http-proxy-fix.js (1)

169-178: 💤 Low value

Fallback at line 177 could be more explicit.

The fallback return res; would fail when passed to the Response constructor (which expects a Web stream), but this edge case is unlikely in Node 18+ where Readable.toWeb is available. Consider throwing an error or adding a comment explaining this is unreachable in the target environment.

💡 Optional: Make the fallback more explicit
   var stream = require('stream');
   if (stream.Readable && typeof stream.Readable.toWeb === 'function') {
     return stream.Readable.toWeb(res);
   }
-  return res;
+  // Unreachable in Node 18+ (target environment); Response constructor requires Web stream
+  throw new Error('stream.Readable.toWeb unavailable; Node 18+ required');
🤖 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 `@nemoclaw-blueprint/scripts/http-proxy-fix.js` around lines 169 - 178, In
responseBody, the fallback "return res" can produce an invalid value for the
Response constructor; update the function (responseBody) to make this case
explicit by either throwing a clear Error (e.g., "Readable.toWeb not available:
cannot convert response stream") or by adding a comment asserting the branch is
unreachable in our Node >=18 target and adding a defensive throw to fail fast;
change the final fallback in responseBody to one of those options so callers
never receive an unsupported value.
🤖 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.

Nitpick comments:
In `@nemoclaw-blueprint/scripts/http-proxy-fix.js`:
- Around line 169-178: In responseBody, the fallback "return res" can produce an
invalid value for the Response constructor; update the function (responseBody)
to make this case explicit by either throwing a clear Error (e.g.,
"Readable.toWeb not available: cannot convert response stream") or by adding a
comment asserting the branch is unreachable in our Node >=18 target and adding a
defensive throw to fail fast; change the final fallback in responseBody to one
of those options so callers never receive an unsupported value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 27fc137d-6f15-4e9b-a8b9-9d495f322f41

📥 Commits

Reviewing files that changed from the base of the PR and between 6938c37 and 564b9a3.

📒 Files selected for processing (6)
  • nemoclaw-blueprint/scripts/http-proxy-fix.js
  • scripts/nemoclaw-start.sh
  • test/http-proxy-fix-e2e.test.ts
  • test/http-proxy-fix-fetch.test.ts
  • test/http-proxy-fix-rewrite.test.ts
  • test/http-proxy-fix-sync.test.ts
💤 Files with no reviewable changes (2)
  • test/http-proxy-fix-rewrite.test.ts
  • test/http-proxy-fix-e2e.test.ts
✅ Files skipped from review due to trivial changes (1)
  • scripts/nemoclaw-start.sh
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/http-proxy-fix-sync.test.ts
  • test/http-proxy-fix-fetch.test.ts

@cv cv added v0.0.65 Release target and removed v0.0.64 Release target labels Jun 12, 2026
@cv cv added v0.0.66 Release target and removed v0.0.65 Release target labels Jun 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: inference Inference routing, serving, model selection, or outputs bug-fix PR fixes a bug or regression provider: ollama Ollama local model provider behavior provider: vllm vLLM local or hosted provider behavior v0.0.66 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

(v0.0.57 cron job failure) Agent cron job uses inference/gemma4:26b but the local provider endpoint is not reachable at https://inference.local/v1.

4 participants