fix(inference): inject OpenRouter runtime headers via adapter#6584
Conversation
Signed-off-by: San Dang <sdang@nvidia.com>
Code Coverage OverviewLanguages: TypeScript TypeScript / code-coverage/pluginThe overall coverage remains at 96%, unchanged from the branch. TypeScript / code-coverage/cliThe overall coverage in the branch remains at 77%, unchanged from the branch. Show a code coverage summary of the most impacted files.
Updated |
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds an OpenRouter runtime adapter, dedicated port validation, onboarding wiring, and updated docs/tests for the adapter path and its validation rules. ChangesOpenRouter runtime adapter feature
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Onboarding as setupOpenRouterRuntimeInference
participant Lifecycle as ensureOpenRouterRuntimeAdapter
participant Adapter as OpenRouterRuntimeAdapterServer
participant OpenShell
participant OpenRouter as openrouter.ai
Onboarding->>Lifecycle: ensureOpenRouterRuntimeAdapter()
Lifecycle->>Adapter: spawn/reuse detached process
Lifecycle-->>Onboarding: adapter route (baseUrl, logPath)
Onboarding->>OpenShell: upsertProvider(baseUrl) + inference set
Onboarding->>Adapter: verifyOnboardInferenceSmoke request
Adapter->>OpenRouter: forward chat completions with attribution headers
OpenRouter-->>Adapter: response
Adapter-->>Onboarding: smoke verification result
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
🌿 Preview your docs: https://nvidia-preview-pr-6584.docs.buildwithfern.com/nemoclaw |
E2E Advisor RecommendationRequired E2E: Dispatch hint: Full advisor summaryE2E Recommendation AdvisorBase: Required E2E
Optional E2E
New E2E recommendations
Dispatch hint
|
E2E Target RecommendationRequired E2E targets: Dispatch required E2E targets:
Full E2E target advisor summaryE2E Target AdvisorBase: Required E2E targets
Optional E2E targets
Relevant changed files
|
PR Review Advisor (Nemotron Ultra) — Changes requestedMerge posture: Do not merge yet Action checklist
Findings index
🚨 Required before mergeAddress these before merging unless a maintainer explicitly overrides the advisor with rationale.
|
PR Review Advisor — Changes requestedMerge posture: Do not merge yet Action checklist
Findings index
Review findings by urgency: 0 required fixes, 4 items to resolve/justify, 0 in-scope improvements
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (5)
src/lib/inference/openrouter-runtime-adapter.ts (2)
39-39: 🚀 Performance & Scalability | 🔵 TrivialConsider log rotation/size cap for the adapter's JSON-line log.
appendLocalAdapterJsonLine(LOG_PATH, ...)grows unbounded over the adapter's lifetime with no rotation or truncation policy visible in this file.Also applies to: 66-79
🤖 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 `@src/lib/inference/openrouter-runtime-adapter.ts` at line 39, The adapter’s JSON-line log at LOG_PATH is appended to indefinitely, so add a rotation, truncation, or size-cap policy around appendLocalAdapterJsonLine usage in openrouter-runtime-adapter.ts. Update the logging flow in the openRouter runtime adapter methods that write JSON lines (including the paths around the referenced append calls) so the file is periodically rolled over or trimmed, and keep the logging behavior encapsulated via a helper or shared utility to avoid unbounded growth.
284-305: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRedundant port re-validation.
OPENROUTER_RUNTIME_ADAPTER_PORTis already parsed and range-validated (1024–65535) viaparsePortat module load using the same env var. Re-readingprocess.env.NEMOCLAW_OPENROUTER_RUNTIME_ADAPTER_PORThere and re-validating with a weaker check (Number.isInteger(port) || port <= 0, no upper/lower bound) is duplicate logic that could simply reuse the constant.🤖 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 `@src/lib/inference/openrouter-runtime-adapter.ts` around lines 284 - 305, The startOpenRouterRuntimeAdapterFromEnv function is redundantly re-parsing and re-validating the port instead of reusing the already validated OPENROUTER_RUNTIME_ADAPTER_PORT constant. Update this function to rely on the module-level parsed value and remove the extra process.env read plus the weaker Number.isInteger/positive-only check, keeping the existing createOpenRouterRuntimeAdapterServer and server.listen flow unchanged.src/lib/inference/openrouter-runtime-adapter.test.ts (1)
45-101: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winConsider adding coverage for upstream failure mid-stream.
No test exercises an upstream response that errors after headers are sent or hangs past a timeout — the exact gap tied to the missing error handler/timeout flagged in
openrouter-runtime-adapter.ts. Adding such a test would catch regressions here.🤖 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 `@src/lib/inference/openrouter-runtime-adapter.test.ts` around lines 45 - 101, Add a test in OpenRouter Runtime adapter coverage that exercises an upstream failure after the response has started or a request that stalls until timeout, since the current `createOpenRouterRuntimeAdapterServer` happy-path test does not cover the missing error/timeout handling. Use the existing `upstream` server setup and `listen` helpers to simulate a stream that emits partial data then fails, or never finishes, and assert the adapter surfaces the failure instead of hanging silently. Keep the assertions close to the existing `forwards chat completions with OpenRouter attribution headers` test so regressions in `openrouter-runtime-adapter.ts` are caught.src/lib/onboard/inference-providers/remote.ts (1)
187-189: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winHardcoded
"openrouter-api"literal duplicates theOPENROUTER_PROVIDER_NAMEconstant.
openrouter-runtime.tsimports and checks againstOPENROUTER_PROVIDER_NAME(from../inference/openrouter), but this file re-derives the same provider name as a bare string literal. If the constant ever changes,openrouterCredentialValuewould silently stop being hydrated for the real provider name whilesetupOpenRouterRuntimeInference's own guard uses the updated constant, causing a divergence that's easy to miss.♻️ Suggested fix
+import { OPENROUTER_PROVIDER_NAME } from "../../inference/openrouter"; ... - const openrouterCredentialValue = - provider === "openrouter-api" ? hydrateCredentialEnv(openrouterCredentialEnv) : null; + const openrouterCredentialValue = + provider === OPENROUTER_PROVIDER_NAME ? hydrateCredentialEnv(openrouterCredentialEnv) : null;🤖 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 `@src/lib/onboard/inference-providers/remote.ts` around lines 187 - 189, The provider check in `remote.ts` hardcodes the OpenRouter name instead of using the shared `OPENROUTER_PROVIDER_NAME` constant. Update the `openrouterCredentialValue` assignment to compare `provider` against that imported constant, matching the guard used by `setupOpenRouterRuntimeInference` so both paths stay in sync if the provider name changes.src/lib/onboard/openrouter-runtime.ts (1)
135-140: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRedundant sandbox-update call — likely a no-op in production.
options.updateSandboxis typed astypeof registry.updateSandbox(the real module function taking(name, {model, provider})), but production wiring (remote.tsline 203) actually passesregistry.updateSandboxdestructured fromRemoteProviderDeps, which resolves to thecommonDeps.registry.updateSandboxwrapper defined insetup-inference.tsas(name: string) => reserveRoute(name, provider, model)— a single-argument function that ignores the{model, provider}object passed here. Sinceoptions.verifyInferenceRoute(line 123) already triggersreserveRouteand sets its internalrouteReservedguard, this second call becomes a guaranteed no-op, making the block dead code that obscures actual behavior.Consider removing this block, or aligning the
updateSandboxtype/wiring so it reflects what is actually invoked at runtime.♻️ Suggested cleanup
- if (options.sandboxName) { - (options.updateSandbox ?? registry.updateSandbox)(options.sandboxName, { - model: options.model, - provider: options.provider, - }); - } + // Sandbox route is already reserved via options.verifyInferenceRoute above.🤖 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 `@src/lib/onboard/openrouter-runtime.ts` around lines 135 - 140, The sandbox update block in openrouter-runtime is effectively dead code because the runtime-provided `options.updateSandbox` from `remote.ts`/`setup-inference.ts` only accepts the sandbox name and just re-reserves the route, while `options.verifyInferenceRoute` has already done that and set the guard. Remove the `options.sandboxName` update call from `openrouter-runtime` or, if it must remain, change the `RemoteProviderDeps`/`updateSandbox` wiring so `registry.updateSandbox` truly performs the intended model/provider update instead of a no-op wrapper.
🤖 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 `@src/lib/inference/openrouter-runtime-adapter.ts`:
- Around line 164-206: forwardOpenRouterRequest currently streams the upstream
response without handling upstreamRes errors and has no request timeout, leaving
the OpenRouter proxy path vulnerable to crashes or hangs. Update this function
to attach an error handler to upstreamRes alongside the existing upstreamReq
handler, ensure any upstream response failure either sends the JSON error or
destroys the client response safely, and add a timeout on the transport.request
call so stalled connections are aborted and resolved cleanly. Use
forwardOpenRouterRequest, upstreamReq, and upstreamRes to locate the logic.
---
Nitpick comments:
In `@src/lib/inference/openrouter-runtime-adapter.test.ts`:
- Around line 45-101: Add a test in OpenRouter Runtime adapter coverage that
exercises an upstream failure after the response has started or a request that
stalls until timeout, since the current `createOpenRouterRuntimeAdapterServer`
happy-path test does not cover the missing error/timeout handling. Use the
existing `upstream` server setup and `listen` helpers to simulate a stream that
emits partial data then fails, or never finishes, and assert the adapter
surfaces the failure instead of hanging silently. Keep the assertions close to
the existing `forwards chat completions with OpenRouter attribution headers`
test so regressions in `openrouter-runtime-adapter.ts` are caught.
In `@src/lib/inference/openrouter-runtime-adapter.ts`:
- Line 39: The adapter’s JSON-line log at LOG_PATH is appended to indefinitely,
so add a rotation, truncation, or size-cap policy around
appendLocalAdapterJsonLine usage in openrouter-runtime-adapter.ts. Update the
logging flow in the openRouter runtime adapter methods that write JSON lines
(including the paths around the referenced append calls) so the file is
periodically rolled over or trimmed, and keep the logging behavior encapsulated
via a helper or shared utility to avoid unbounded growth.
- Around line 284-305: The startOpenRouterRuntimeAdapterFromEnv function is
redundantly re-parsing and re-validating the port instead of reusing the already
validated OPENROUTER_RUNTIME_ADAPTER_PORT constant. Update this function to rely
on the module-level parsed value and remove the extra process.env read plus the
weaker Number.isInteger/positive-only check, keeping the existing
createOpenRouterRuntimeAdapterServer and server.listen flow unchanged.
In `@src/lib/onboard/inference-providers/remote.ts`:
- Around line 187-189: The provider check in `remote.ts` hardcodes the
OpenRouter name instead of using the shared `OPENROUTER_PROVIDER_NAME` constant.
Update the `openrouterCredentialValue` assignment to compare `provider` against
that imported constant, matching the guard used by
`setupOpenRouterRuntimeInference` so both paths stay in sync if the provider
name changes.
In `@src/lib/onboard/openrouter-runtime.ts`:
- Around line 135-140: The sandbox update block in openrouter-runtime is
effectively dead code because the runtime-provided `options.updateSandbox` from
`remote.ts`/`setup-inference.ts` only accepts the sandbox name and just
re-reserves the route, while `options.verifyInferenceRoute` has already done
that and set the guard. Remove the `options.sandboxName` update call from
`openrouter-runtime` or, if it must remain, change the
`RemoteProviderDeps`/`updateSandbox` wiring so `registry.updateSandbox` truly
performs the intended model/provider update instead of a no-op wrapper.
🪄 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: 1881170d-3967-4f8f-a910-ddc940009600
📒 Files selected for processing (17)
docs/inference/inference-options.mdxdocs/reference/commands.mdxscripts/openrouter-runtime-adapter.jssrc/lib/core/ports.test.tssrc/lib/core/ports.tssrc/lib/inference/openrouter-runtime-adapter.test.tssrc/lib/inference/openrouter-runtime-adapter.tssrc/lib/inference/openrouter.tssrc/lib/onboard.tssrc/lib/onboard/gateway-recovery.tssrc/lib/onboard/inference-providers/remote-openai-surface.test.tssrc/lib/onboard/inference-providers/remote.tssrc/lib/onboard/inference-providers/types.tssrc/lib/onboard/openrouter-runtime.tssrc/lib/onboard/setup-inference.tstest/onboard-openrouter-inference.test.tstest/support/setup-inference-test-harness.ts
Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: San Dang <sdang@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@src/lib/inference/openrouter-runtime-adapter-forward.ts`:
- Around line 82-96: The upstream error handler in
openrouter-runtime-adapter-forward.ts is forwarding err.message directly to the
client via sendJson and compactText, which can expose internal network details.
Update the upstreamReq.on("error") path to log the full error server-side and
return a generic client-facing message instead of the raw message, while keeping
the existing openrouter_runtime_error response shape and resolve(502) behavior.
Focus on the error handling block around upstreamReq.on("error") and
options.res.destroy so the response is sanitized regardless of whether headers
were already sent.
- Around line 61-103: Handle the missing failure paths in
forwardOpenRouterRequest by adding error and timeout handling around the
upstream stream lifecycle. In openrouter-runtime-adapter-forward.ts, update
forwardOpenRouterRequest so the upstreamRes.pipe(options.res) path listens for
upstreamRes errors and aborts/destroys the downstream response safely, and
configure transport.request with a timeout that rejects or destroys the upstream
request and returns the same 502 fallback. Keep the existing behavior for
buildUpstreamUrl, buildForwardRequestHeaders, and sendJson, but ensure both
stalled requests and mid-response resets are handled without crashing or
hanging.
🪄 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: f20f7916-2e5c-4f9f-b50c-1081d31a554c
📒 Files selected for processing (8)
src/lib/inference/openrouter-runtime-adapter-common.tssrc/lib/inference/openrouter-runtime-adapter-entry.tssrc/lib/inference/openrouter-runtime-adapter-forward.tssrc/lib/inference/openrouter-runtime-adapter-lifecycle.tssrc/lib/inference/openrouter-runtime-adapter-server.tssrc/lib/inference/openrouter-runtime-adapter.tssrc/lib/onboard/gateway-recovery.test.tssrc/lib/onboard/setup-inference-route-containment.test.ts
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/lib/inference/openrouter-runtime-adapter-forward.ts (1)
155-171: 🩺 Stability & Availability | 🔴 Critical | 🏗️ Heavy liftUpstream response error handling and request timeout still missing.
upstreamRes.pipe(options.res)has noerrorlistener onupstreamRes, and there's no timeout ontransport.request/upstreamReq. A mid-response reset from OpenRouter crashes the adapter process on the unhandled stream error, and a stalled upstream hangs the request indefinitely. This is the same issue raised in a prior review round on this file and remains unaddressed in the current diff.🐛 Proposed fix
(upstreamRes) => { const status = upstreamRes.statusCode || 502; options.res.writeHead(status, buildForwardResponseHeaders(upstreamRes.headers)); + upstreamRes.on("error", (err) => { + resolve(sendForwardError(options.res, err)); + }); upstreamRes.pipe(options.res); upstreamRes.on("end", () => resolve(status)); }, ); + upstreamReq.setTimeout(30_000, () => { + upstreamReq.destroy(new Error("OpenRouter upstream request timed out")); + }); upstreamReq.on("error", (err) => { resolve(sendForwardError(options.res, err)); }); upstreamReq.end(body);🤖 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 `@src/lib/inference/openrouter-runtime-adapter-forward.ts` around lines 155 - 171, In `openrouter-runtime-adapter-forward`’s upstream request flow, add proper protection for both the response stream and stalled requests. Attach an error handler to `upstreamRes` before piping to `options.res`, and ensure any stream failure routes through `sendForwardError` instead of crashing the process. Also set a timeout on `transport.request`/`upstreamReq` and abort/resolve with the same forward error path when the upstream does not respond in time.
🤖 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 `@src/lib/inference/openrouter-runtime-adapter-forward.ts`:
- Around line 121-137: The generic error path in sendForwardError still forwards
err.message to the client, which can leak upstream/network details; update
sendForwardError to only expose the raw message for ForwardHttpError and use a
safe generic client-facing message for all other errors. Keep the existing
status/code handling in sendForwardError, but ensure compactText(message) is fed
a sanitized fallback string for non-ForwardHttpError cases rather than
err.message.
---
Outside diff comments:
In `@src/lib/inference/openrouter-runtime-adapter-forward.ts`:
- Around line 155-171: In `openrouter-runtime-adapter-forward`’s upstream
request flow, add proper protection for both the response stream and stalled
requests. Attach an error handler to `upstreamRes` before piping to
`options.res`, and ensure any stream failure routes through `sendForwardError`
instead of crashing the process. Also set a timeout on
`transport.request`/`upstreamReq` and abort/resolve with the same forward error
path when the upstream does not respond in time.
🪄 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: 682704e6-b69e-4fb2-ab37-2bc598823cd7
📒 Files selected for processing (6)
src/lib/core/ports.test.tssrc/lib/core/ports.tssrc/lib/inference/openrouter-runtime-adapter-forward.tssrc/lib/inference/openrouter-runtime-adapter-lifecycle.tssrc/lib/inference/openrouter-runtime-adapter.test.tssrc/lib/onboard.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- src/lib/core/ports.test.ts
- src/lib/onboard.ts
- src/lib/inference/openrouter-runtime-adapter-lifecycle.ts
Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: San Dang <sdang@nvidia.com>
cv
left a comment
There was a problem hiding this comment.
Requesting changes on exact head 183c3cbc8a0d09f53a88bae91753443332246b8c.
- In
src/lib/inference/openrouter-runtime-adapter-forward.ts:155-171, add a bounded upstream timeout pluserrorandabortedhandling for the upstream response, with single-settlement cleanup. Add regressions for a pre-response stall and a mid-response reset. - In
src/lib/inference/openrouter-runtime-adapter-forward.ts:121-129, do not return raw network error messages to clients. Return a stable generic response and keep diagnostic details server-side. - Resolve the host-listener boundary. The adapter binds
0.0.0.0,/healthbypasses auth, and runtime requests accept any Bearer-shaped value. The health payload itself is secret-free, and simply binding loopback is incompatible with the current directhost.openshell.internalroute, so implement a topology-compatible source/auth/firewall restriction or record explicit maintainer risk acceptance with focused tests. - After the source fixes, provide exact-head live evidence for
inference-routing,network-policy,onboard-repair,onboard-resume, andcloud-onboard. Also add an OpenRouter-specific sandbox-to-adapter/upstream smoke proving route reachability, attribution headers, and denied unintended egress, or obtain an explicit maintainer waiver.
I am not treating the model-catalog item as part of this PR: that implementation is unchanged, this PR explicitly excludes it, and #5826 remains open. Please address the source blockers before spending live E2E capacity.
|
Hi @cv, I'm requesting maintainer decision on HTTP injection. OpenRouter requested NemoClaw add custom HTTP headers as adverstise There are two options.
|
|
Follow-up pushed through What changed since the
Local verification recorded in the PR body passed, and the latest pushed-head GitHub checks are green. CodeRabbit remains paused/skipped. The PR still shows |
E2E Target Results — ✅ All requested jobs passedRun: 29070537794
|
E2E Target Results — ✅ All requested jobs passedRun: 29070537989
|
E2E Target Results — ✅ All requested jobs passedRun: 29070537970
|
E2E Target Results — ✅ All requested jobs passedRun: 29070537801
|
E2E Target Results — ✅ All requested jobs passedRun: 29070537946
|
## Summary Release-prep documentation for **v0.0.80**. Adds the `## v0.0.80` section to `docs/about/release-notes.mdx` summarizing user-facing changes since v0.0.79, each bullet linking to the relevant deeper page. Produced via `nemoclaw-contributor-update-docs` (pre-tag path): scanned `v0.0.79..HEAD`, applied the docs skip list (no violations), and confirmed the 8 commits that already shipped in-PR docs are complete. No new pages needed. ## Source summary - #6507 -> `docs/about/release-notes.mdx`: Hermes v0.18 + Slack Block Kit (rich rendering, digest-pinned base image). - #6584 / #6616 -> `docs/about/release-notes.mdx`: host-local OpenRouter runtime attribution adapter (port `11437`, `NEMOCLAW_OPENROUTER_RUNTIME_ADAPTER_PORT`) and native Deep Agents `openrouter` provider. - #6210 / #6292 -> `docs/about/release-notes.mdx`: host corporate proxy CA import into sandbox trust (`NEMOCLAW_CORPORATE_CA_BUNDLE`, `NEMOCLAW_CORPORATE_CA_IMPORT`). - #6624 / #6623 / #6656 -> `docs/about/release-notes.mdx`: release-matched base-image selection, surfaced cluster-image build diagnostics, preserved Nemotron profile registration. - #6629 / #6637 -> `docs/about/release-notes.mdx`: bare `connect` default-sandbox behavior and route-probe hardening. - #6634 / #6626 / #6596 / #5569 / #6610 / #6655 -> `docs/about/release-notes.mdx`: onboarding/recovery preservation, stale-gateway-PID fix, installer backup message, vLLM label on managed platforms. - #6578 / #5670 -> `docs/about/release-notes.mdx`: automatic Hermes light terminal skin and non-interactive `npx` MCP server startup. ## Verification `npm run docs`: 0 errors, all internal links resolve (2 pre-existing hidden-page warnings). `_build/` variants for OpenClaw, Hermes, and Deep Agents all regenerate with the v0.0.80 section. Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com> 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Added release notes for v0.0.80. * Documented Hermes upgrades, including Slack Block Kit rendering. * Added details on OpenRouter traffic routing and attribution headers. * Documented improved proxy certificate handling and sandbox reliability. * Highlighted enhanced connection defaults, route-probing safeguards, onboarding recovery, and terminal/MCP startup behavior. * Added references to relevant user-guide documentation. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#6584) <!-- markdownlint-disable MD041 --> ## Summary OpenRouter runtime traffic now goes through a host-local NemoClaw adapter so runtime requests include the OpenRouter attribution headers that OpenShell cannot inject per provider today. The adapter keeps `OPENROUTER_API_KEY` owned by OpenShell, binds runtime requests to the exact OpenShell `Authorization` value via a persisted SHA-256 hash, and adds only `HTTP-Referer` plus `X-OpenRouter-Title`. This runtime adapter is a workaround until OpenShell exposes L7 middleware/default-header injection for provider routes. ## Related Issue Fixes NVIDIA#5826. ## Changes - Added an OpenRouter runtime adapter with split server, forwarding, lifecycle, and compiled TypeScript entrypoint modules that forward `/v1/chat/completions` to OpenRouter with attribution headers. - Wired `openrouter-api` onboarding to register `OPENAI_BASE_URL=http://host.openshell.internal:11437/v1` while retaining `OPENROUTER_API_KEY` as the OpenShell provider credential. - Added `NEMOCLAW_OPENROUTER_RUNTIME_ADAPTER_PORT` with gateway and adapter-port conflict validation. - Hardened adapter lifecycle with a startup lock/post-persist health probe, bounded request-body forwarding, exact bearer-token matching, and hash-only adapter state. - Kept OpenRouter on the same featured cloud model picker/list as NVIDIA Endpoints while preserving OpenRouter-specific credential and manual-model validation. - Moved OpenRouter adapter uninstall cleanup into a focused module instead of growing the uninstall run-plan monolith. - Updated OpenRouter onboarding, adapter, provider recovery, port, and docs coverage. ## Type of Change - [ ] Code change (feature, bug fix, or refactor) - [x] Code change with doc updates - [ ] Doc only (prose changes, no code sample modifications) - [ ] Doc only (includes code sample changes) ## Quality Gates <!-- Check exactly one tests line and one docs line. Check other lines when applicable. Add every requested justification or approval reference. --> - [x] Tests added or updated for changed behavior - [ ] Existing tests cover changed behavior — justification: - [ ] Tests not applicable — justification: - [x] Docs updated for user-facing behavior changes - [ ] Docs not applicable — justification: - [x] Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging) - [x] Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: Local review completed for the credential boundary. OpenShell still owns and injects `OPENROUTER_API_KEY`; the adapter process receives only a SHA-256 authorization hash and does not receive the key in its environment, state file, or token file. Adapter tests cover exact bearer-auth enforcement, path containment, safe health output, oversized-body rejection, generic upstream failure responses, and OpenRouter header forwarding. The adapter intentionally binds `0.0.0.0` because the current OpenShell container route reaches the host through `host.openshell.internal`; exact bearer matching narrows runtime access to the OpenShell-held credential value, and replacing the adapter with OpenShell L7/default-header middleware is tracked as the TODO in `src/lib/onboard/openrouter-runtime.ts`. - [ ] Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue: ## Verification <!-- Check each applicable item only when supported by the requested evidence. Run targeted tests once per relevant change set and rerun after later edits or hook autofixes that can affect the tested behavior. Do not rerun hook-covered checks. --> - [x] PR description includes the DCO sign-off declaration and every commit appears as `Verified` in GitHub - [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or `npm run check:diff` passed when hooks were skipped or unavailable - [x] Targeted behavior tests pass for the current change set, or tests are marked not applicable above — command/result or justification: `npx vitest run --project cli src/lib/core/ports.test.ts src/lib/inference/openrouter-runtime-adapter.test.ts src/lib/onboard/inference-providers/remote-openai-surface.test.ts src/lib/onboard/gateway-recovery.test.ts src/lib/onboard/recovered-provider-reuse.test.ts src/lib/inference/config.test.ts src/lib/inference/onboard-probes.test.ts src/lib/onboard/providers.test.ts src/lib/onboard/setup-nim-flow.test.ts src/lib/onboard/setup-inference-route-containment.test.ts` passed; `npx vitest run --project integration test/onboard-openrouter-inference.test.ts` passed; `npm run typecheck:cli` passed; `npm run build:cli` passed; `npm run source-shape:check` passed; `npm run test-size:check` passed. Follow-up hardening: `npx vitest run --project cli src/lib/onboard/setup-nim-flow.test.ts src/lib/inference/nvidia-featured-models.test.ts src/lib/onboard/nvidia-featured-model-selection.test.ts src/lib/inference/openrouter-runtime-adapter.test.ts src/lib/actions/uninstall/openrouter-runtime-adapter-cleanup.test.ts src/lib/actions/uninstall/run-plan.test.ts` passed; `npx vitest run --project integration test/onboard-openrouter-inference.test.ts` passed; `npm run typecheck:cli` passed; `npm run build:cli` passed; `npm run docs` passed; `npm run test-size:check` passed; `npm run test-conditionals:scan -- --top 25` passed; `npx tsx scripts/check-env-var-docs.ts` passed; `git diff --check` passed. Upstream-abort regression follow-up: `npx vitest run --project cli src/lib/inference/openrouter-runtime-adapter.test.ts src/lib/onboard/inference-providers/remote-openai-surface.test.ts src/lib/onboard/setup-nim-flow.test.ts src/lib/inference/nvidia-featured-models.test.ts src/lib/onboard/nvidia-featured-model-selection.test.ts src/lib/actions/uninstall/openrouter-runtime-adapter-cleanup.test.ts src/lib/actions/uninstall/run-plan.test.ts` passed; `npx vitest run --project integration test/onboard-openrouter-inference.test.ts` passed; `npm run typecheck:cli` passed; `npm run build:cli` passed; `npm run source-shape:check` passed; `npm run test-size:check` passed; `git diff --check` passed. - [ ] Applicable broad gate passed — `npm test` for broad runtime/test-harness changes; `npm run check` for repo-wide validation/coverage changes — command/result: - [x] Quality Gates section completed with required justifications or waivers - [x] No secrets, API keys, or credentials committed - [ ] `npm run docs` builds without warnings (doc changes only) - [ ] Doc pages follow the [style guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md) (doc changes only) - [ ] New doc pages include SPDX header and frontmatter (new pages only) --- <!-- DCO sign-off is required in this PR description, and every commit must appear as Verified in GitHub. Run: git config user.name && git config user.email --> Signed-off-by: San Dang <sdang@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added an OpenRouter runtime adapter with a public `/health` endpoint and forwarding for `POST /v1/chat/completions` only, including OpenRouter attribution headers. * Onboarding can configure an OpenRouter-backed inference route and support the new runtime adapter port/port offset. * **Bug Fixes** * Improved adapter request handling with body size enforcement and explicit auth/endpoint gating. * Strengthened port validation to reserve the OpenRouter adapter port and prevent gateway conflicts (including recovery). * **Documentation** * Documented `NEMOCLAW_OPENROUTER_RUNTIME_ADAPTER_PORT`, validation behavior, and runtime adapter health/log details. * **Tests** * Added adapter forwarding/auth gating/request-size tests and expanded port validation coverage. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: San Dang <sdang@nvidia.com>
## Summary Release-prep documentation for **v0.0.80**. Adds the `## v0.0.80` section to `docs/about/release-notes.mdx` summarizing user-facing changes since v0.0.79, each bullet linking to the relevant deeper page. Produced via `nemoclaw-contributor-update-docs` (pre-tag path): scanned `v0.0.79..HEAD`, applied the docs skip list (no violations), and confirmed the 8 commits that already shipped in-PR docs are complete. No new pages needed. ## Source summary - NVIDIA#6507 -> `docs/about/release-notes.mdx`: Hermes v0.18 + Slack Block Kit (rich rendering, digest-pinned base image). - NVIDIA#6584 / NVIDIA#6616 -> `docs/about/release-notes.mdx`: host-local OpenRouter runtime attribution adapter (port `11437`, `NEMOCLAW_OPENROUTER_RUNTIME_ADAPTER_PORT`) and native Deep Agents `openrouter` provider. - NVIDIA#6210 / NVIDIA#6292 -> `docs/about/release-notes.mdx`: host corporate proxy CA import into sandbox trust (`NEMOCLAW_CORPORATE_CA_BUNDLE`, `NEMOCLAW_CORPORATE_CA_IMPORT`). - NVIDIA#6624 / NVIDIA#6623 / NVIDIA#6656 -> `docs/about/release-notes.mdx`: release-matched base-image selection, surfaced cluster-image build diagnostics, preserved Nemotron profile registration. - NVIDIA#6629 / NVIDIA#6637 -> `docs/about/release-notes.mdx`: bare `connect` default-sandbox behavior and route-probe hardening. - NVIDIA#6634 / NVIDIA#6626 / NVIDIA#6596 / NVIDIA#5569 / NVIDIA#6610 / NVIDIA#6655 -> `docs/about/release-notes.mdx`: onboarding/recovery preservation, stale-gateway-PID fix, installer backup message, vLLM label on managed platforms. - NVIDIA#6578 / NVIDIA#5670 -> `docs/about/release-notes.mdx`: automatic Hermes light terminal skin and non-interactive `npx` MCP server startup. ## Verification `npm run docs`: 0 errors, all internal links resolve (2 pre-existing hidden-page warnings). `_build/` variants for OpenClaw, Hermes, and Deep Agents all regenerate with the v0.0.80 section. Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com> 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Added release notes for v0.0.80. * Documented Hermes upgrades, including Slack Block Kit rendering. * Added details on OpenRouter traffic routing and attribution headers. * Documented improved proxy certificate handling and sandbox reliability. * Highlighted enhanced connection defaults, route-probing safeguards, onboarding recovery, and terminal/MCP startup behavior. * Added references to relevant user-guide documentation. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
OpenRouter runtime traffic now goes through a host-local NemoClaw adapter so runtime requests include the OpenRouter attribution headers that OpenShell cannot inject per provider today. The adapter keeps
OPENROUTER_API_KEYowned by OpenShell, binds runtime requests to the exact OpenShellAuthorizationvalue via a persisted SHA-256 hash, and adds onlyHTTP-RefererplusX-OpenRouter-Title.This runtime adapter is a workaround until OpenShell exposes L7 middleware/default-header injection for provider routes.
Related Issue
Fixes #5826.
Changes
/v1/chat/completionsto OpenRouter with attribution headers.openrouter-apionboarding to registerOPENAI_BASE_URL=http://host.openshell.internal:11437/v1while retainingOPENROUTER_API_KEYas the OpenShell provider credential.NEMOCLAW_OPENROUTER_RUNTIME_ADAPTER_PORTwith gateway and adapter-port conflict validation.Type of Change
Quality Gates
OPENROUTER_API_KEY; the adapter process receives only a SHA-256 authorization hash and does not receive the key in its environment, state file, or token file. Adapter tests cover exact bearer-auth enforcement, path containment, safe health output, oversized-body rejection, generic upstream failure responses, and OpenRouter header forwarding. The adapter intentionally binds0.0.0.0because the current OpenShell container route reaches the host throughhost.openshell.internal; exact bearer matching narrows runtime access to the OpenShell-held credential value, and replacing the adapter with OpenShell L7/default-header middleware is tracked as the TODO insrc/lib/onboard/openrouter-runtime.ts.Verification
Verifiedin GitHubpre-commit,commit-msg, andpre-pushhooks passed, ornpm run check:diffpassed when hooks were skipped or unavailablenpx vitest run --project cli src/lib/core/ports.test.ts src/lib/inference/openrouter-runtime-adapter.test.ts src/lib/onboard/inference-providers/remote-openai-surface.test.ts src/lib/onboard/gateway-recovery.test.ts src/lib/onboard/recovered-provider-reuse.test.ts src/lib/inference/config.test.ts src/lib/inference/onboard-probes.test.ts src/lib/onboard/providers.test.ts src/lib/onboard/setup-nim-flow.test.ts src/lib/onboard/setup-inference-route-containment.test.tspassed;npx vitest run --project integration test/onboard-openrouter-inference.test.tspassed;npm run typecheck:clipassed;npm run build:clipassed;npm run source-shape:checkpassed;npm run test-size:checkpassed. Follow-up hardening:npx vitest run --project cli src/lib/onboard/setup-nim-flow.test.ts src/lib/inference/nvidia-featured-models.test.ts src/lib/onboard/nvidia-featured-model-selection.test.ts src/lib/inference/openrouter-runtime-adapter.test.ts src/lib/actions/uninstall/openrouter-runtime-adapter-cleanup.test.ts src/lib/actions/uninstall/run-plan.test.tspassed;npx vitest run --project integration test/onboard-openrouter-inference.test.tspassed;npm run typecheck:clipassed;npm run build:clipassed;npm run docspassed;npm run test-size:checkpassed;npm run test-conditionals:scan -- --top 25passed;npx tsx scripts/check-env-var-docs.tspassed;git diff --checkpassed. Upstream-abort regression follow-up:npx vitest run --project cli src/lib/inference/openrouter-runtime-adapter.test.ts src/lib/onboard/inference-providers/remote-openai-surface.test.ts src/lib/onboard/setup-nim-flow.test.ts src/lib/inference/nvidia-featured-models.test.ts src/lib/onboard/nvidia-featured-model-selection.test.ts src/lib/actions/uninstall/openrouter-runtime-adapter-cleanup.test.ts src/lib/actions/uninstall/run-plan.test.tspassed;npx vitest run --project integration test/onboard-openrouter-inference.test.tspassed;npm run typecheck:clipassed;npm run build:clipassed;npm run source-shape:checkpassed;npm run test-size:checkpassed;git diff --checkpassed.npm testfor broad runtime/test-harness changes;npm run checkfor repo-wide validation/coverage changes — command/result:npm run docsbuilds without warnings (doc changes only)Signed-off-by: San Dang sdang@nvidia.com
Summary by CodeRabbit
/healthendpoint and forwarding forPOST /v1/chat/completionsonly, including OpenRouter attribution headers.NEMOCLAW_OPENROUTER_RUNTIME_ADAPTER_PORT, validation behavior, and runtime adapter health/log details.