Skip to content

feat(inference): add OpenRouter onboarding support#6461

Merged
cv merged 13 commits into
mainfrom
feat/openrouter-onboarding
Jul 9, 2026
Merged

feat(inference): add OpenRouter onboarding support#6461
cv merged 13 commits into
mainfrom
feat/openrouter-onboarding

Conversation

@sandl99

@sandl99 sandl99 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds first-class OpenRouter onboarding support for OpenClaw, Hermes, and LangChain Deep Agents Code. OpenRouter is exposed as its own provider choice while configuring OpenShell through the OpenAI-compatible runtime path with the OpenRouter base URL and credential environment.

This PR is a partial implementation of #5826. OpenRouter attribution headers are applied to onboarding health checks, catalog probes, and model-validation probes only. Runtime sandbox traffic still uses OpenShell's openai provider profile with OPENAI_BASE_URL=https://openrouter.ai/api/v1; runtime extra outbound headers remain unsupported until OpenShell provides native/static-header support.

Related Issue

Partially addresses #5826.

Changes

  • Adds OpenRouter provider/menu/config handling, including OPENROUTER_API_KEY, openrouter-api, and https://openrouter.ai/api/v1.
  • Loads a temporary OpenRouter catalog through the featured-model catalog mechanism and applies OpenRouter-specific host-side validation headers for catalog/model probes and onboarding health checks.
  • Updates inference validation, credential redaction/scanning allowlists, provider reuse, setup flow, and docs/platform tables for OpenRouter.
  • Adds focused CLI and integration coverage for OpenRouter onboarding and keeps legacy test files within the size budget.

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)

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification:
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: self-reviewed credential handling; OpenRouter secrets are passed via environment, redacted/scanned, and covered by targeted tests. Runtime OpenRouter extra headers are intentionally unsupported in this PR outside onboarding health checks and validation probes.
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Verification

  • PR description includes the DCO sign-off declaration and every commit appears as Verified in GitHub
  • Normal pre-commit, commit-msg, and pre-push hooks passed, or npm run check:diff passed when hooks were skipped or unavailable
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — command/result or justification: npx vitest run --project integration test/onboard-openrouter-inference.test.ts; npx vitest run --project cli src/lib/onboard/providers.test.ts src/lib/onboard/inference-providers/remote-openai-surface.test.ts src/lib/core/ports.test.ts; npm run typecheck:cli; npm run docs; git diff --cached --check.
  • Applicable broad gate passed — npm test for broad runtime/test-harness changes; npm run check for repo-wide validation/coverage changes — command/result:
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed
  • npm run docs builds without warnings (doc changes only) — npm run docs passed; Fern reported 2 existing warnings.
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: San Dang sdang@nvidia.com

Signed-off-by: San Dang <sdang@nvidia.com>
@sandl99 sandl99 self-assigned this Jul 8, 2026
@coderabbitai

coderabbitai Bot commented Jul 8, 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

Adds OpenRouter as a supported inference provider across configuration, onboarding, runtime handling, validation, tests, and docs.

Changes

OpenRouter Provider Integration

Layer / File(s) Summary
OpenRouter constants and extra-header auth plumbing
src/lib/inference/openrouter.ts, src/lib/adapters/http/auth-config.ts, src/lib/inference/provider-models.ts, src/lib/inference/onboard-probes.ts, src/lib/inference/provider-models.test.ts, src/lib/inference/onboard-probes.test.ts
Adds OpenRouter constants and default headers, extends OpenAI-like auth config with extraHeaders, and threads those headers through provider catalog and onboarding probe paths.
Provider identity, aliases, and routing
src/lib/domain/installer/provider.ts, src/lib/actions/inference-set.ts, src/lib/onboard/providers.ts, src/lib/onboard/provider-menu.ts, src/lib/onboard/inference-providers/types.ts, src/lib/onboard/recovered-provider-reuse.ts, src/lib/inference/config.ts, docs/reference/commands.mdx, docs/reference/platform-support.mdx, docs/get-started/quickstart.mdx, docs/inference/inference-options.mdx, docs/inference/switch-inference-providers.mdx, ci/platform-matrix.json, install.sh, scripts/install.sh
Registers openrouter and openrouter-api across installer normalization, onboarding menus/config, remote provider types, recovered-credential reuse, provider selection/sandbox routing, and command/reference docs.
OpenRouter credential validation and secret handling
src/lib/validation.ts, src/lib/onboard/credential-navigation.ts, src/lib/credentials/store.ts, src/lib/security/credential-env.ts, src/lib/security/redact.ts, scripts/checks/direct-credential-env.ts, test/e2e/live/snapshot-credential-scanner.ts, test/e2e/support/snapshot-credential-scanner.test.ts, ci/env-var-doc-allowlist.json
Adds OpenRouter API-key validation, optional credential validators, and OPENROUTER_API_KEY handling in allowlists, redaction, scanner checks, and env-var docs.
OpenRouter catalog and model prompting
src/lib/inference/model-prompts.ts, src/lib/inference/nvidia-featured-models.ts, src/lib/onboard/nvidia-featured-model-selection.ts, src/lib/onboard/setup-nim-flow.ts, src/lib/onboard/setup-nim-selection.ts, src/lib/inference/*tests*, src/lib/onboard/*tests*
Extends cloud prompting with configurable labels and validators, adds catalog URL and label support to featured-model fetching, and creates an OpenRouter featured-model session in setup-nim flows.
OpenRouter onboarding flow
src/lib/onboard.ts, src/lib/onboard/openrouter-selection.ts, src/lib/onboard/openrouter-runtime.ts, src/lib/onboard/inference-providers/remote.ts, src/lib/onboard/setup-inference.ts, test/onboard-openrouter-inference.test.ts, test/onboard-resume-provider-recovery.test.ts, src/lib/onboard/inference-providers/types.ts, src/lib/onboard/inference-providers/remote-openai-surface.test.ts
Wires OpenRouter credential validation, extra headers, runtime adapter setup, and model selection into onboarding execution, and adds direct onboarding and recovery coverage.
OpenRouter runtime adapter
src/lib/core/ports.ts, src/lib/onboard/gateway-recovery.ts, src/lib/inference/openrouter-runtime-adapter.ts, src/lib/core/ports.test.ts, src/lib/inference/openrouter-runtime-adapter.test.ts
Implements the runtime adapter server, lifecycle management, port validation, and adapter tests.
Onboarding selection menu reorder tests
test/onboard-selection.test.ts, test/onboard-selection-anthropic-retry.test.ts, test/package-contract/onboard/compatible-endpoint-reasoning.test.ts, test/onboard.test.ts, ci/test-file-size-budget.json
Updates scripted onboarding selection tests and the file-size budget to match the new provider menu ordering and answer flows.

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

Suggested reviewers: cv, jyaunches

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes match the issue: OpenRouter is added as the second onboarding provider, uses the shared cloud model flow, and includes key and attribution handling.
Out of Scope Changes check ✅ Passed I don't see material out-of-scope changes; the docs, tests, and code updates all support OpenRouter onboarding and header handling.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding OpenRouter onboarding support for inference.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/openrouter-onboarding

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

@github-code-quality

github-code-quality Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage remains at 96%, unchanged from the main branch.

TypeScript / code-coverage/cli

The overall coverage in the feat/openrouter-onbo... branch is 76%. The coverage in the main branch is 77%.

Show a code coverage summary of the most impacted files.
File main 815a587 feat/openrouter-onbo... 0421bdb +/-
src/lib/sandbox...rsion-scheme.ts 100% 73% -27%
src/lib/actions...ge-preflight.ts 89% 74% -15%
src/lib/actions...e-validation.ts 90% 81% -9%
src/lib/actions...x/mcp-bridge.ts 44% 35% -9%
src/lib/sandbox/config.ts 61% 54% -7%
src/lib/actions...lution-probe.ts 94% 88% -6%
src/lib/onboard.ts 28% 28% 0%
src/lib/adapters/http/probe.ts 89% 91% +2%
src/lib/actions...-add-restart.ts 14% 19% +5%
src/lib/inferen...e/openrouter.ts 0% 100% +100%

Updated July 09, 2026 07:59 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

@sandl99 sandl99 added area: inference Inference routing, serving, model selection, or outputs area: providers Inference provider integrations and provider behavior enhancement New capability or improvement request labels Jul 8, 2026
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: cloud-onboard, credential-sanitization, security-posture, inference-routing, network-policy, onboard-repair, onboard-resume
Optional E2E: cloud-inference, openclaw-inference-switch, hermes-inference-switch

Dispatch hint: cloud-onboard,credential-sanitization,security-posture,inference-routing,network-policy,onboard-repair,onboard-resume

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • cloud-onboard (high): Required floor from the platform-install risk plan: install.sh, scripts/install.sh, platform matrix, and hosted onboarding/provider changes must validate clean install plus full hosted onboarding on a live host.
  • credential-sanitization (high): Required floor from credentials-security: credential store, env handling, redaction, credential navigation, and snapshot scanner changes must prove secrets are sanitized from live logs/artifacts/snapshots and not copied across sandbox boundaries.
  • security-posture (high): Required floor from credentials-security: security-boundary changes need live OpenClaw/Hermes posture coverage to ensure credential isolation and fail-closed behavior remain intact.
  • inference-routing (medium): Required floor from inference-policy: provider selection, OpenRouter/OpenAI-compatible config, validation probes, and inference-set changes must validate the real host-to-sandbox inference.local route and provider failure classification.
  • network-policy (high): Required floor from inference-policy: inference provider routing and validation changes must prove the live network policy allows intended inference egress and denies unintended routes.
  • onboard-repair (high): Required floor from lifecycle-state and the onboarding resume rule: onboard/provider state changes and recovered provider reuse can affect repair after interrupted onboarding, so live repair convergence must be validated.
  • onboard-resume (medium): Required floor from lifecycle-state and the onboarding resume rule: changes to onboarding provider selection/state handling require live resume coverage and must not rely only on unit/runtime-boundary tests.

Optional E2E

  • cloud-inference (medium): Useful adjacent confidence for provider/model catalog and routed inference changes because it validates install.sh onboarding through a live hosted provider and sandbox inference.local completion path.
  • openclaw-inference-switch (medium): Useful adjacent confidence for src/lib/actions/inference-set.ts and provider alias changes, especially runtime route/config synchronization after switching providers for OpenClaw.
  • hermes-inference-switch (medium): Useful adjacent confidence for inference-set/provider alias changes across the Hermes route/config synchronization path.

New E2E recommendations

  • openrouter-provider (high): This PR appears to promote OpenRouter to a first-class onboarding route, but existing live E2E coverage found in the workflow inventory does not include an OpenRouter-specific onboarding and inference.local smoke using OPENROUTER_API_KEY. inference-routing has generic provider slices but no dedicated OpenRouter route.
    • Suggested test: Add a workflow-dispatched live OpenRouter provider E2E that onboards with NEMOCLAW_PROVIDER=openrouter, validates OpenRouter credential/model selection, verifies OpenShell registers openrouter-api with the expected base URL/headers, and confirms sandbox inference.local chat completion without leaking OPENROUTER_API_KEY.
  • openrouter-provider-switch (medium): The PR changes inference-set aliases and documents switching to openrouter-api, but the existing openclaw/hermes inference switch matrices cover NVIDIA-hosted and Anthropic-compatible modes, not OpenRouter.
    • Suggested test: Extend inference switch live coverage with an OpenRouter mode for OpenClaw and Hermes, gated on OPENROUTER_API_KEY, to validate inference set --provider openrouter-api updates the gateway route, registry metadata, and in-sandbox config.

Dispatch hint

  • Workflow: .github/workflows/e2e.yaml
  • jobs input: cloud-onboard,credential-sanitization,security-posture,inference-routing,network-policy,onboard-repair,onboard-resume

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

E2E Target Recommendation

Required E2E targets: cloud-onboard, credential-sanitization, security-posture, inference-routing, network-policy, onboard-repair, onboard-resume
Optional E2E targets: None

Dispatch required E2E targets:

  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=cloud-onboard
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=credential-sanitization
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=security-posture
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=inference-routing
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=network-policy
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-repair
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-resume

Workflow run

Full E2E target advisor summary

E2E Target Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E targets

  • cloud-onboard: Installer and platform changes must work on a clean supported host with the pinned runtime dependencies.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=cloud-onboard
  • credential-sanitization: Credential and security-boundary changes must preserve secrecy, sanitization, and fail-closed policy behavior.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=credential-sanitization
  • security-posture: Credential and security-boundary changes must preserve secrecy, sanitization, and fail-closed policy behavior.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=security-posture
  • inference-routing: Inference selection, reachability, and network policy must agree at the real host-to-sandbox boundary.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=inference-routing
  • network-policy: Inference selection, reachability, and network policy must agree at the real host-to-sandbox boundary.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=network-policy
  • onboard-repair: Onboarding and sandbox state must converge across persisted metadata, reported status, and the live runtime.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-repair
  • onboard-resume: Onboarding and sandbox state must converge across persisted metadata, reported status, and the live runtime.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-resume

Optional E2E targets

  • None.

Relevant changed files

  • ci/platform-matrix.json
  • install.sh
  • scripts/checks/direct-credential-env.ts
  • scripts/install.sh
  • src/lib/actions/inference-set.ts
  • src/lib/adapters/http/auth-config.ts
  • src/lib/credentials/store.ts
  • src/lib/domain/installer/provider.ts
  • src/lib/inference/config.ts
  • src/lib/inference/model-prompts.ts
  • src/lib/inference/nvidia-featured-models.ts
  • src/lib/inference/onboard-probes.ts
  • src/lib/inference/openrouter.ts
  • src/lib/inference/provider-models.ts
  • src/lib/onboard.ts
  • src/lib/onboard/credential-navigation.ts
  • src/lib/onboard/inference-providers/types.ts
  • src/lib/onboard/inference-selection-validation.ts
  • src/lib/onboard/nvidia-featured-model-selection.ts
  • src/lib/onboard/openrouter-selection.ts
  • src/lib/onboard/provider-menu.ts
  • src/lib/onboard/providers.ts
  • src/lib/onboard/recovered-provider-reuse.ts
  • src/lib/onboard/setup-nim-flow.ts
  • src/lib/onboard/setup-nim-selection.ts
  • src/lib/security/credential-env.ts
  • src/lib/security/redact.ts
  • test/e2e/live/snapshot-credential-scanner.ts
  • test/e2e/support/snapshot-credential-scanner.test.ts

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Changes requested

Merge posture: Do not merge yet
Primary next action: Resolve or justify PRA-1: Source-of-truth review needed: OpenRouter provider implemented through OpenShell's generic OpenAI provider profile.
Open items: 0 required · 4 warnings · 0 suggestions · 7 test follow-ups
Since last review: 0 prior items resolved · 2 still apply · 1 new item found

Action checklist

  • PRA-1 Resolve or justify: Source-of-truth review needed: OpenRouter provider implemented through OpenShell's generic OpenAI provider profile
  • PRA-2 Resolve or justify: OpenRouter route is only proven through mocked setup, not the sandbox/OpenShell boundary in test/onboard-openrouter-inference.test.ts:21
  • PRA-3 Resolve or justify: Invalid OpenRouter key rejection lacks an onboarding side-effect regression in src/lib/onboard/openrouter-selection.ts:54
  • PRA-4 Resolve or justify: OpenRouter tested claim should caveat runtime header limitations or cite runtime evidence in ci/platform-matrix.json:91
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation
  • PRA-T4 Add or justify test follow-up: OpenRouter route is only proven through mocked setup, not the sandbox/OpenShell boundary
  • PRA-T5 Add or justify test follow-up: Invalid OpenRouter key rejection lacks an onboarding side-effect regression
  • PRA-T6 Add or justify test follow-up: Acceptance clause
  • PRA-T7 Add or justify test follow-up: OpenRouter provider implemented through OpenShell's generic OpenAI provider profile

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-2 Resolve/justify tests test/onboard-openrouter-inference.test.ts:21 Add or identify a runtime-style OpenRouter route test using a local fake OpenAI-compatible upstream behind the OpenShell provider path. Verify sandbox/runtime traffic reaches `/v1/chat/completions` through `inference.local`, the OpenRouter credential is absent from argv/logs/artifacts, and egress outside the intended route is denied by policy.
PRA-3 Resolve/justify tests src/lib/onboard/openrouter-selection.ts:54 Add a setup/onboarding harness regression that sets `NEMOCLAW_PROVIDER=openrouter` and `OPENROUTER_API_KEY=sk-test`, then asserts onboarding exits with the `sk-or-` guidance before any provider create/update or inference route mutation.
PRA-4 Resolve/justify docs ci/platform-matrix.json:91 Either add the runtime-boundary evidence requested above and cite it in the provider status rationale, or caveat the matrix/docs to state that runtime traffic uses OpenShell's generic OpenAI-compatible profile without OpenRouter attribution headers until native/static-header support exists.
Review findings by urgency: 0 required fixes, 4 items to resolve/justify, 0 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — Source-of-truth review needed: OpenRouter provider implemented through OpenShell's generic OpenAI provider profile

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Covered by finding 3: either add runtime evidence that the generic profile route works for the documented tested claim, or add a docs-generation assertion that the provider note includes the runtime-header limitation.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `src/lib/inference/openrouter.ts` defines `OPENROUTER_PROVIDER_TYPE = "openai"`; `src/lib/inference/onboard-probes.ts` adds headers only via `getProbeExtraHeaders()`; docs/platform rows promote OpenRouter as tested.

PRA-2 Resolve/justify — OpenRouter route is only proven through mocked setup, not the sandbox/OpenShell boundary

  • Location: test/onboard-openrouter-inference.test.ts:21
  • Category: tests
  • Problem: The changed tests assert the setup command shape, provider update, `inference set`, `verifyInferenceRoute`, and `verifyOnboardInferenceSmoke` calls, but they do not prove that a sandboxed agent actually reaches an OpenRouter-compatible upstream through `https://inference.local/v1\` or that unintended egress remains denied. This is a deterministic regression risk for the `inference-policy` family because OpenRouter is a new hosted route implemented through OpenShell's generic `openai` profile.
  • Impact: A provider can look correctly registered in unit and harness tests while runtime traffic fails, bypasses the intended OpenShell route, or silently depends on host/network behavior not covered by the static tests.
  • Recommended action: Add or identify a runtime-style OpenRouter route test using a local fake OpenAI-compatible upstream behind the OpenShell provider path. Verify sandbox/runtime traffic reaches `/v1/chat/completions` through `inference.local`, the OpenRouter credential is absent from argv/logs/artifacts, and egress outside the intended route is denied by policy.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `test/onboard-openrouter-inference.test.ts:21` and `src/lib/inference/config.test.ts:390` to confirm current evidence stops at mocked command/config boundaries; then check for an E2E or runtime-style test that drives a real `inference.local` request to a fake upstream.
  • Missing regression test: A runtime-style test that onboards or configures `openrouter-api` with a fake local OpenAI-compatible upstream, sends a sandbox request through `https://inference.local/v1/chat/completions\`, asserts the fake upstream received the request, asserts `OPENROUTER_API_KEY` does not appear in process argv/log captures, and asserts a non-provider egress attempt is blocked.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `test/onboard-openrouter-inference.test.ts:21` and `src/lib/inference/config.test.ts:390` to confirm current evidence stops at mocked command/config boundaries; then check for an E2E or runtime-style test that drives a real `inference.local` request to a fake upstream.
  • Evidence: `test/onboard-openrouter-inference.test.ts:36-55` asserts command strings and mocked verifier calls; `src/lib/inference/config.test.ts:390-394` asserts managed-provider config; the risk plan requires `inference-routing` and `network-policy` validation for changed inference-policy files.

PRA-3 Resolve/justify — Invalid OpenRouter key rejection lacks an onboarding side-effect regression

  • Location: src/lib/onboard/openrouter-selection.ts:54
  • Category: tests
  • Problem: `validateOpenRouterApiKeyValue()` has unit coverage for rejecting missing and non-`sk-or-` keys, and `validateNonInteractiveCredential()` is intended to fail before provider work. The current evidence does not show a non-interactive onboarding path with `NEMOCLAW_PROVIDER=openrouter` and an invalid key aborting before OpenShell provider create/update or `inference set` side effects.
  • Impact: A future refactor could move or skip the prefix check and still pass unit validation tests, allowing invalid OpenRouter credentials to mutate gateway/provider state before the failure is surfaced.
  • Recommended action: Add a setup/onboarding harness regression that sets `NEMOCLAW_PROVIDER=openrouter` and `OPENROUTER_API_KEY=sk-test`, then asserts onboarding exits with the `sk-or-` guidance before any provider create/update or inference route mutation.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Compare `src/lib/validation.test.ts:447-457` for pure validator coverage with `test/onboard-openrouter-inference.test.ts:36-39`, which currently covers only the valid-key command path.
  • Missing regression test: A non-interactive onboarding test with `NEMOCLAW_PROVIDER=openrouter`, `OPENROUTER_API_KEY=sk-test`, and a command recorder for OpenShell that asserts no `provider create`, `provider update`, or `inference set` command is issued and stderr includes `Invalid OpenRouter API key. Must start with sk-or-`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Compare `src/lib/validation.test.ts:447-457` for pure validator coverage with `test/onboard-openrouter-inference.test.ts:36-39`, which currently covers only the valid-key command path.
  • Evidence: `src/lib/onboard/openrouter-selection.ts:54-80` performs the non-interactive validation; `src/lib/validation.test.ts:452-456` covers the validator in isolation; no changed test was found that exercises the full invalid-key onboarding side-effect boundary.

PRA-4 Resolve/justify — OpenRouter tested claim should caveat runtime header limitations or cite runtime evidence

  • Location: ci/platform-matrix.json:91
  • Category: docs
  • Problem: The platform matrix and generated docs mark OpenRouter as a first-class tested provider for OpenClaw, Hermes, and LangChain Deep Agents Code. The implementation registers `openrouter-api` through OpenShell's `openai` profile and adds OpenRouter attribution headers only for host-side catalog/model/probe requests; runtime sandbox traffic does not get those extra headers in this PR.
  • Impact: Launch-facing docs can imply full runtime parity even though a meaningful provider-specific runtime behavior is currently a compatibility shim. If OpenRouter changes enforcement or rate-limiting around attribution headers, users may see runtime failures despite the tested claim.
  • Recommended action: Either add the runtime-boundary evidence requested above and cite it in the provider status rationale, or caveat the matrix/docs to state that runtime traffic uses OpenShell's generic OpenAI-compatible profile without OpenRouter attribution headers until native/static-header support exists.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `src/lib/inference/openrouter.ts:10-13` and `src/lib/inference/onboard-probes.ts:241-244` to confirm the shim/header scope, then compare the OpenRouter provider notes in `ci/platform-matrix.json:91-96` and generated docs.
  • Missing regression test: If the tested claim remains uncaveated, add a runtime OpenRouter acceptance test proving the OpenShell `openai` profile route succeeds without runtime attribution headers for the documented agents; otherwise add a docs-generation assertion that the OpenRouter provider note includes the runtime-header limitation.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `src/lib/inference/openrouter.ts:10-13` and `src/lib/inference/onboard-probes.ts:241-244` to confirm the shim/header scope, then compare the OpenRouter provider notes in `ci/platform-matrix.json:91-96` and generated docs.
  • Evidence: `src/lib/inference/openrouter.ts:10-13` documents the lack of a native OpenRouter profile; `getProbeExtraHeaders()` only returns OpenRouter headers for probes; `ci/platform-matrix.json` adds OpenRouter with status `tested` and notes first-class onboarding for all three agents.

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

  • None.
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — Add or identify a runtime-style OpenRouter route test with a local fake OpenAI-compatible upstream behind OpenShell, verifying sandbox traffic reaches `/v1/chat/completions` through `https://inference.local/v1\` and unintended egress is denied.. Changed code crosses provider credentials, OpenShell provider registration, sandbox inference routing, and network policy boundaries. Unit and mocked tests are strong, but deterministic risk invariants for inference-policy and credentials-security need runtime-boundary evidence. Required risk-plan jobs remain a validation floor and are not claimed to have run.
  • PRA-T2 Runtime validation — Add or identify a non-interactive invalid-key OpenRouter onboarding test with `NEMOCLAW_PROVIDER=openrouter` and `OPENROUTER_API_KEY=sk-test`, asserting onboarding exits before provider create/update or `inference set` and prints the `sk-or-` guidance.. Changed code crosses provider credentials, OpenShell provider registration, sandbox inference routing, and network policy boundaries. Unit and mocked tests are strong, but deterministic risk invariants for inference-policy and credentials-security need runtime-boundary evidence. Required risk-plan jobs remain a validation floor and are not claimed to have run.
  • PRA-T3 Runtime validation — Run or otherwise account for the risk-plan validation floor for this change set: `cloud-onboard`, `credential-sanitization`, `security-posture`, `inference-routing`, `network-policy`, `onboard-repair`, and `onboard-resume`; do not downgrade these jobs based on unit coverage.. Changed code crosses provider credentials, OpenShell provider registration, sandbox inference routing, and network policy boundaries. Unit and mocked tests are strong, but deterministic risk invariants for inference-policy and credentials-security need runtime-boundary evidence. Required risk-plan jobs remain a validation floor and are not claimed to have run.
  • PRA-T4 OpenRouter route is only proven through mocked setup, not the sandbox/OpenShell boundary — Add or identify a runtime-style OpenRouter route test using a local fake OpenAI-compatible upstream behind the OpenShell provider path. Verify sandbox/runtime traffic reaches `/v1/chat/completions` through `inference.local`, the OpenRouter credential is absent from argv/logs/artifacts, and egress outside the intended route is denied by policy.
  • PRA-T5 Invalid OpenRouter key rejection lacks an onboarding side-effect regression — Add a setup/onboarding harness regression that sets `NEMOCLAW_PROVIDER=openrouter` and `OPENROUTER_API_KEY=sk-test`, then asserts onboarding exits with the `sk-or-` guidance before any provider create/update or inference route mutation.
  • PRA-T6 Acceptance clause — No linked issue acceptance clauses or linked issue comments were provided in the deterministic review context. — add test evidence or identify existing coverage. `pr_review_correctness_state_context` and reconciliation context both reported `linkedIssues: []`; review therefore mapped observable PR-scope behavior instead of literal issue clauses.
  • PRA-T7 OpenRouter provider implemented through OpenShell's generic OpenAI provider profile — Covered by finding 3: either add runtime evidence that the generic profile route works for the documented tested claim, or add a docs-generation assertion that the provider note includes the runtime-header limitation.. `src/lib/inference/openrouter.ts` defines `OPENROUTER_PROVIDER_TYPE = "openai"`; `src/lib/inference/onboard-probes.ts` adds headers only via `getProbeExtraHeaders()`; docs/platform rows promote OpenRouter as tested.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: OpenRouter provider implemented through OpenShell's generic OpenAI provider profile

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Covered by finding 3: either add runtime evidence that the generic profile route works for the documented tested claim, or add a docs-generation assertion that the provider note includes the runtime-header limitation.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `src/lib/inference/openrouter.ts` defines `OPENROUTER_PROVIDER_TYPE = "openai"`; `src/lib/inference/onboard-probes.ts` adds headers only via `getProbeExtraHeaders()`; docs/platform rows promote OpenRouter as tested.

PRA-2 Resolve/justify — OpenRouter route is only proven through mocked setup, not the sandbox/OpenShell boundary

  • Location: test/onboard-openrouter-inference.test.ts:21
  • Category: tests
  • Problem: The changed tests assert the setup command shape, provider update, `inference set`, `verifyInferenceRoute`, and `verifyOnboardInferenceSmoke` calls, but they do not prove that a sandboxed agent actually reaches an OpenRouter-compatible upstream through `https://inference.local/v1\` or that unintended egress remains denied. This is a deterministic regression risk for the `inference-policy` family because OpenRouter is a new hosted route implemented through OpenShell's generic `openai` profile.
  • Impact: A provider can look correctly registered in unit and harness tests while runtime traffic fails, bypasses the intended OpenShell route, or silently depends on host/network behavior not covered by the static tests.
  • Recommended action: Add or identify a runtime-style OpenRouter route test using a local fake OpenAI-compatible upstream behind the OpenShell provider path. Verify sandbox/runtime traffic reaches `/v1/chat/completions` through `inference.local`, the OpenRouter credential is absent from argv/logs/artifacts, and egress outside the intended route is denied by policy.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `test/onboard-openrouter-inference.test.ts:21` and `src/lib/inference/config.test.ts:390` to confirm current evidence stops at mocked command/config boundaries; then check for an E2E or runtime-style test that drives a real `inference.local` request to a fake upstream.
  • Missing regression test: A runtime-style test that onboards or configures `openrouter-api` with a fake local OpenAI-compatible upstream, sends a sandbox request through `https://inference.local/v1/chat/completions\`, asserts the fake upstream received the request, asserts `OPENROUTER_API_KEY` does not appear in process argv/log captures, and asserts a non-provider egress attempt is blocked.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `test/onboard-openrouter-inference.test.ts:21` and `src/lib/inference/config.test.ts:390` to confirm current evidence stops at mocked command/config boundaries; then check for an E2E or runtime-style test that drives a real `inference.local` request to a fake upstream.
  • Evidence: `test/onboard-openrouter-inference.test.ts:36-55` asserts command strings and mocked verifier calls; `src/lib/inference/config.test.ts:390-394` asserts managed-provider config; the risk plan requires `inference-routing` and `network-policy` validation for changed inference-policy files.

PRA-3 Resolve/justify — Invalid OpenRouter key rejection lacks an onboarding side-effect regression

  • Location: src/lib/onboard/openrouter-selection.ts:54
  • Category: tests
  • Problem: `validateOpenRouterApiKeyValue()` has unit coverage for rejecting missing and non-`sk-or-` keys, and `validateNonInteractiveCredential()` is intended to fail before provider work. The current evidence does not show a non-interactive onboarding path with `NEMOCLAW_PROVIDER=openrouter` and an invalid key aborting before OpenShell provider create/update or `inference set` side effects.
  • Impact: A future refactor could move or skip the prefix check and still pass unit validation tests, allowing invalid OpenRouter credentials to mutate gateway/provider state before the failure is surfaced.
  • Recommended action: Add a setup/onboarding harness regression that sets `NEMOCLAW_PROVIDER=openrouter` and `OPENROUTER_API_KEY=sk-test`, then asserts onboarding exits with the `sk-or-` guidance before any provider create/update or inference route mutation.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Compare `src/lib/validation.test.ts:447-457` for pure validator coverage with `test/onboard-openrouter-inference.test.ts:36-39`, which currently covers only the valid-key command path.
  • Missing regression test: A non-interactive onboarding test with `NEMOCLAW_PROVIDER=openrouter`, `OPENROUTER_API_KEY=sk-test`, and a command recorder for OpenShell that asserts no `provider create`, `provider update`, or `inference set` command is issued and stderr includes `Invalid OpenRouter API key. Must start with sk-or-`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Compare `src/lib/validation.test.ts:447-457` for pure validator coverage with `test/onboard-openrouter-inference.test.ts:36-39`, which currently covers only the valid-key command path.
  • Evidence: `src/lib/onboard/openrouter-selection.ts:54-80` performs the non-interactive validation; `src/lib/validation.test.ts:452-456` covers the validator in isolation; no changed test was found that exercises the full invalid-key onboarding side-effect boundary.

PRA-4 Resolve/justify — OpenRouter tested claim should caveat runtime header limitations or cite runtime evidence

  • Location: ci/platform-matrix.json:91
  • Category: docs
  • Problem: The platform matrix and generated docs mark OpenRouter as a first-class tested provider for OpenClaw, Hermes, and LangChain Deep Agents Code. The implementation registers `openrouter-api` through OpenShell's `openai` profile and adds OpenRouter attribution headers only for host-side catalog/model/probe requests; runtime sandbox traffic does not get those extra headers in this PR.
  • Impact: Launch-facing docs can imply full runtime parity even though a meaningful provider-specific runtime behavior is currently a compatibility shim. If OpenRouter changes enforcement or rate-limiting around attribution headers, users may see runtime failures despite the tested claim.
  • Recommended action: Either add the runtime-boundary evidence requested above and cite it in the provider status rationale, or caveat the matrix/docs to state that runtime traffic uses OpenShell's generic OpenAI-compatible profile without OpenRouter attribution headers until native/static-header support exists.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `src/lib/inference/openrouter.ts:10-13` and `src/lib/inference/onboard-probes.ts:241-244` to confirm the shim/header scope, then compare the OpenRouter provider notes in `ci/platform-matrix.json:91-96` and generated docs.
  • Missing regression test: If the tested claim remains uncaveated, add a runtime OpenRouter acceptance test proving the OpenShell `openai` profile route succeeds without runtime attribution headers for the documented agents; otherwise add a docs-generation assertion that the OpenRouter provider note includes the runtime-header limitation.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `src/lib/inference/openrouter.ts:10-13` and `src/lib/inference/onboard-probes.ts:241-244` to confirm the shim/header scope, then compare the OpenRouter provider notes in `ci/platform-matrix.json:91-96` and generated docs.
  • Evidence: `src/lib/inference/openrouter.ts:10-13` documents the lack of a native OpenRouter profile; `getProbeExtraHeaders()` only returns OpenRouter headers for probes; `ci/platform-matrix.json` adds OpenRouter with status `tested` and notes first-class onboarding for all three agents.

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor (Nemotron Ultra) — Blocked

Merge posture: Do not merge until addressed
Primary next action: Fix PRA-5: OPENROUTER_FEATURED_MODELS_URL hardcoded to NVIDIA catalog; then add or justify PRA-T1.
Open items: 6 required · 9 warnings · 1 suggestion · 8 test follow-ups
Since last review: 1 prior item resolved · 15 still apply · 3 new items found

Action checklist

  • PRA-5 Fix: OPENROUTER_FEATURED_MODELS_URL hardcoded to NVIDIA catalog in src/lib/inference/openrouter.ts:5
  • PRA-6 Fix: extraHeaders parameter lacks validation — header injection vector in src/lib/adapters/http/auth-config.ts:147
  • PRA-7 Fix: @ts-nocheck disables type safety on credential/provider registry boundary in src/lib/onboard/providers.ts:1
  • PRA-8 Fix: @ts-nocheck disables type safety on network probe boundary in src/lib/inference/onboard-probes.ts:1
  • PRA-9 Fix: Monolith test file grew by 42 lines without extraction in src/lib/onboard/recovered-provider-reuse.test.ts:1
  • PRA-10 Fix: DEFAULT_CLOUD_MODEL (Nemotron 3 Super) used for OpenRouter but unverified on OpenRouter in src/lib/inference/config.ts:119
  • PRA-1 Resolve or justify: Source-of-truth review needed: OpenRouter featured model catalog integration
  • PRA-2 Resolve or justify: Source-of-truth review needed: DEFAULT_CLOUD_MODEL for OpenRouter
  • PRA-3 Resolve or justify: Source-of-truth review needed: extraHeaders parameter without validation
  • PRA-4 Resolve or justify: Source-of-truth review needed: @ts-nocheck on providers.ts and onboard-probes.ts
  • PRA-11 Resolve or justify: Source-of-truth workaround undocumented: OpenRouter uses NVIDIA catalog parser in src/lib/onboard/setup-nim-flow.ts:346
  • PRA-12 Resolve or justify: Missing test coverage for critical OpenRouter paths in test/onboard-openrouter-inference.test.ts:1
  • PRA-14 Resolve or justify: onboard.ts ~4893 lines; OpenRouter logic added inline not extracted in src/lib/onboard.ts:3593
  • PRA-15 Resolve or justify: Non-interactive credential validation skipped when reuseGatewayCredentialWithoutLocalKey=true in src/lib/onboard/openrouter-selection.ts:61
  • PRA-16 Resolve or justify: Documentation claims OpenRouter has own catalog but implementation uses NVIDIA's in docs/inference/inference-options.mdx:69
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation
  • PRA-T4 Add or justify test follow-up: Runtime validation
  • PRA-T5 Add or justify test follow-up: Runtime validation
  • PRA-T6 Add or justify test follow-up: Missing test coverage for critical OpenRouter paths
  • PRA-T7 Add or justify test follow-up: Acceptance clause
  • PRA-T8 Add or justify test follow-up: Acceptance clause
  • PRA-13 In-scope improvement: Duplicate catalog pattern: openrouter-selection.ts duplicates nvidia-featured-model-selection.ts in src/lib/onboard/openrouter-selection.ts:1

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-2 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-3 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-4 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-5 Required correctness src/lib/inference/openrouter.ts:5 Replace with OpenRouter's actual models endpoint (https://openrouter.ai/api/v1/models, requires authentication) or remove the featured catalog integration for OpenRouter and fall back to manual entry only. Add a comment explaining why OpenRouter doesn't use a featured catalog.
PRA-6 Required security src/lib/adapters/http/auth-config.ts:147 Add validation for extraHeaders: reject newlines, ensure 'Header-Name: value' format, strip hop-by-hop headers, or replace with OpenRouter-specific createOpenRouterAuthConfig() that hardcodes the two attribution headers and removes the generic parameter.
PRA-7 Required security src/lib/onboard/providers.ts:1 Remove @ts-nocheck and fix underlying type errors. If legitimate dynamic patterns exist, refactor to proper types or use targeted @ts-expect-error with comments explaining why.
PRA-8 Required security src/lib/inference/onboard-probes.ts:1 Remove @ts-nocheck and fix underlying type errors, or add a concrete tracking issue with timeline. If migration is tracked separately, link the issue in the comment.
PRA-9 Required architecture src/lib/onboard/recovered-provider-reuse.test.ts:1 Extract OpenRouter-specific tests into dedicated test files: onboard-openrouter-recovery.test.ts, model-prompts-openrouter.test.ts, config-openrouter.test.ts, providers-openrouter.test.ts. Offset growth before merge.
PRA-10 Required correctness src/lib/inference/config.ts:119 Verify Nemotron 3 Super availability on OpenRouter. If not available, change default to a confirmed OpenRouter model (e.g., moonshotai/kimi-k2.6 used in tests) or add logic to validate default availability at onboarding time.
PRA-11 Resolve/justify architecture src/lib/onboard/setup-nim-flow.ts:346 Add comment block in openrouter.ts and setup-nim-flow.ts addressing all five source-of-truth questions. Change catalogLabel to reflect reality (e.g., 'NVIDIA featured models (temporary fallback for OpenRouter)').
PRA-12 Resolve/justify tests test/onboard-openrouter-inference.test.ts:1 Add behavior-specific tests: (1) catalog fetch URL test, (2) probe header test in onboard-probes.test.ts, (3) OpenRouter recovery test in onboard-openrouter-recovery.test.ts, (4) non-interactive validation skip test, (5) policy preset test, (6) inference set switch test.
PRA-13 Improvement architecture src/lib/onboard/openrouter-selection.ts:1 If OpenRouter publishes a real catalog, extract shared FeaturedModelCatalogSession module parameterized by URL, retiredModelIds, label. Otherwise, remove catalog integration entirely for OpenRouter (fall back to manual entry) per PRA-22.
PRA-14 Resolve/justify architecture src/lib/onboard.ts:3593 Continue extracting provider-specific onboarding logic into dedicated modules under src/lib/onboard/inference-providers/. At minimum, ensure no further growth in this PR.
PRA-15 Resolve/justify correctness src/lib/onboard/openrouter-selection.ts:61 Validate credential even in recovery path, or document why gateway credential reuse bypasses validation (e.g., gateway already validated it).
PRA-16 Resolve/justify docs docs/inference/inference-options.mdx:69 Update docs to reflect reality: 'OpenRouter temporarily uses NVIDIA's featured model catalog as a fallback; models shown are NVIDIA-curated and may not be available on OpenRouter. Manual entry is recommended.' Or fix implementation first (finding #1) then update docs.

🚨 Required before merge

Address these before merging unless a maintainer explicitly overrides the advisor with rationale.

PRA-5 Required — OPENROUTER_FEATURED_MODELS_URL hardcoded to NVIDIA catalog

  • Location: src/lib/inference/openrouter.ts:5
  • Category: correctness
  • Problem: OPENROUTER_FEATURED_MODELS_URL exports 'https://assets.ngc.nvidia.com/products/api-catalog/featured-models-openrouter.json' (NVIDIA's catalog). setup-nim-flow.ts:346-354 feeds this to createNvidiaFeaturedModelSession() which applies NVIDIA-specific retired-model filtering, ID normalization (minimax-m2.7→m3, bare nemotron-3-*→nvidia/nemotron-3-*), and label normalization. OpenRouter has no featured catalog at this URL; onboarding users who pick OpenRouter see NVIDIA-curated models (Nemotron, Kimi, Minimax) instead of OpenRouter-available models. Violates acceptance clause from feat: adding OpenRouter as an inference provider #5826 claiming 'OpenRouter uses its own featured model catalog'.
  • Impact: OpenRouter onboarding model picker shows incorrect NVIDIA models leading to validation failures or wrong model selection. Manual entry still works but catalog-backed picker is fundamentally broken.
  • Required action: Replace with OpenRouter's actual models endpoint (https://openrouter.ai/api/v1/models, requires authentication) or remove the featured catalog integration for OpenRouter and fall back to manual entry only. Add a comment explaining why OpenRouter doesn't use a featured catalog.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check src/lib/inference/openrouter.ts:5 — the URL is hardcoded to NVIDIA's assets domain. In production onboarding, selecting OpenRouter loads NVIDIA models.
  • Missing regression test: Add integration test that selects OpenRouter provider and verifies the catalog URL fetched is OpenRouter's, not NVIDIA's, and that displayed models are OpenRouter-available models.
  • Done when: The required change is committed and verification passes: Check src/lib/inference/openrouter.ts:5 — the URL is hardcoded to NVIDIA's assets domain. In production onboarding, selecting OpenRouter loads NVIDIA models.
  • Evidence: src/lib/inference/openrouter.ts:5 exports OPENROUTER_FEATURED_MODELS_URL = 'https://assets.ngc.nvidia.com/products/api-catalog/featured-models-openrouter.json'; setup-nim-flow.ts:347 uses this URL for OpenRouter catalog session

PRA-6 Required — extraHeaders parameter lacks validation — header injection vector

  • Location: src/lib/adapters/http/auth-config.ts:147
  • Category: security
  • Problem: createOpenAiLikeAuthConfig() accepts extraHeaders?: readonly string[] and blindly appends each entry as a curl header (lines 147-148): for (const header of options.extraHeaders ?? []) { entries.push({ kind: 'header', value: header }); }. No validation: newlines not rejected, no 'Header-Name: value' format enforcement, hop-by-hop headers (Connection, Transfer-Encoding, Keep-Alive, etc.) not stripped. Currently only OpenRouter uses it (two static headers from getOpenRouterCurlHeaders()) but API is an open header-injection surface for any future caller.
  • Impact: Malicious or buggy caller could inject arbitrary headers, newlines, or hop-by-hop headers into curl probes, potentially bypassing security controls or causing probe misbehavior.
  • Required action: Add validation for extraHeaders: reject newlines, ensure 'Header-Name: value' format, strip hop-by-hop headers, or replace with OpenRouter-specific createOpenRouterAuthConfig() that hardcodes the two attribution headers and removes the generic parameter.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read auth-config.ts:147-148; attempt extraHeaders: ['X-Injected: value\r\nX-Another: bad'] in a test — observe both headers are passed to curl without sanitization.
  • Missing regression test: Add unit test for createOpenAiLikeAuthConfig with malicious extraHeaders (newlines, malformed format, hop-by-hop headers) asserting they are rejected or sanitized.
  • Done when: The required change is committed and verification passes: Read auth-config.ts:147-148; attempt extraHeaders: ['X-Injected: value\r\nX-Another: bad'] in a test — observe both headers are passed to curl without sanitization.
  • Evidence: src/lib/adapters/http/auth-config.ts:130-151 adds extraHeaders parameter and blindly appends at lines 147-148; openrouter-selection.ts:50 calls getProbeExtraHeaders('openrouter-api') returning static headers

PRA-7 Required — @ts-nocheck disables type safety on credential/provider registry boundary

  • Location: src/lib/onboard/providers.ts:1
  • Category: security
  • Problem: @ts-nocheck at top of src/lib/onboard/providers.ts:1 disables TypeScript checking for the entire file. This file handles credential resolution (resolveProviderCredential, getCredential), provider registry (getProviderSelectionConfig, registerProvider), and gateway provider CRUD — all trust boundaries where type safety is a primary defense.
  • Impact: Type errors in credential handling, provider identity, or gateway registration go undetected at compile time, increasing risk of credential leakage, provider spoofing, or gateway misconfiguration.
  • Required action: Remove @ts-nocheck and fix underlying type errors. If legitimate dynamic patterns exist, refactor to proper types or use targeted @ts-expect-error with comments explaining why.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check src/lib/onboard/providers.ts:1 — @ts-nocheck directive present. Run npx tsc --noEmit src/lib/onboard/providers.ts to see suppressed errors.
  • Missing regression test: Add CI check that fails on @ts-nocheck in security-critical files (credentials/store.ts, onboard/providers.ts, inference/onboard-probes.ts, security/credential-env.ts, security/redact.ts).
  • Done when: The required change is committed and verification passes: Check src/lib/onboard/providers.ts:1 — @ts-nocheck directive present. Run npx tsc --noEmit src/lib/onboard/providers.ts to see suppressed errors.
  • Evidence: src/lib/onboard/providers.ts:1 has @ts-nocheck; file exports resolveProviderCredential, getCredential, registerProvider, getProviderSelectionConfig

PRA-8 Required — @ts-nocheck disables type safety on network probe boundary

  • Location: src/lib/inference/onboard-probes.ts:1
  • Category: security
  • Problem: @ts-nocheck at top of src/lib/inference/onboard-probes.ts:1 disables TypeScript checking for the entire file. This file constructs curl argv with credentials, performs SSRF validation, sends network probes with API keys, and handles probe responses — all trust boundaries where type safety is a primary defense.
  • Impact: Type errors in curl argument construction, credential handling, SSRF validation, or response parsing go undetected at compile time, increasing risk of SSRF bypass, credential leakage, or probe logic errors.
  • Required action: Remove @ts-nocheck and fix underlying type errors, or add a concrete tracking issue with timeline. If migration is tracked separately, link the issue in the comment.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check src/lib/inference/onboard-probes.ts:1 — @ts-nocheck directive present. Run npx tsc --noEmit src/lib/inference/onboard-probes.ts to see suppressed errors.
  • Missing regression test: Add CI check that fails on @ts-nocheck in security-critical files.
  • Done when: The required change is committed and verification passes: Check src/lib/inference/onboard-probes.ts:1 — @ts-nocheck directive present. Run npx tsc --noEmit src/lib/inference/onboard-probes.ts to see suppressed errors.
  • Evidence: src/lib/inference/onboard-probes.ts:1 has @ts-nocheck; file exports validateOpenAiLikeSelection, validateAnthropicSelection, getProbeExtraHeaders, runCurlProbe

PRA-9 Required — Monolith test file grew by 42 lines without extraction

  • Location: src/lib/onboard/recovered-provider-reuse.test.ts:1
  • Category: architecture
  • Problem: recovered-provider-reuse.test.ts grew from 483 to 525 lines (+42) by adding OpenRouter recovery test cases inline. Risk plan requires offsetting growth before merge for files exceeding +20 lines. Three other test files also exceed threshold: model-prompts.test.ts +30, config.test.ts +24, providers.test.ts +22.
  • Impact: Test monoliths become harder to maintain, slower to run, and couple unrelated provider logic. Growth without extraction violates the project's architecture guardrails.
  • Required action: Extract OpenRouter-specific tests into dedicated test files: onboard-openrouter-recovery.test.ts, model-prompts-openrouter.test.ts, config-openrouter.test.ts, providers-openrouter.test.ts. Offset growth before merge.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check ci/test-file-size-budget.json — blocker files not budgeted; grep for 'openrouter' in each test file — test blocks added inline.
  • Missing regression test: N/A — this is a structural finding; the regression test is the extraction itself.
  • Done when: The required change is committed and verification passes: Check ci/test-file-size-budget.json — blocker files not budgeted; grep for 'openrouter' in each test file — test blocks added inline.
  • Evidence: riskPlan monolithDeltas shows recovered-provider-reuse.test.ts +42 (blocker), model-prompts.test.ts +30 (blocker), config.test.ts +24 (blocker), providers.test.ts +22 (blocker)

PRA-10 Required — DEFAULT_CLOUD_MODEL (Nemotron 3 Super) used for OpenRouter but unverified on OpenRouter

  • Location: src/lib/inference/config.ts:119
  • Category: correctness
  • Problem: config.ts:15 exports DEFAULT_CLOUD_MODEL = 'nvidia/nemotron-3-super-120b-a12b'. config.ts:119-125 uses this for openrouter-api in getProviderSelectionConfig(). Integration test test/onboard-openrouter-inference.test.ts:17 uses moonshotai/kimi-k2.6. No evidence Nemotron 3 Super is available on OpenRouter. User selecting OpenRouter gets NVIDIA default that will fail validation.
  • Impact: OpenRouter onboarding defaults to a model that may not exist on OpenRouter, causing immediate validation failure and confusing UX.
  • Required action: Verify Nemotron 3 Super availability on OpenRouter. If not available, change default to a confirmed OpenRouter model (e.g., moonshotai/kimi-k2.6 used in tests) or add logic to validate default availability at onboarding time.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check config.ts:119-125 — openrouter-api case returns model: model || DEFAULT_CLOUD_MODEL. Attempt OpenRouter onboarding with default — observe validation failure.
  • Missing regression test: Add test that onboarding with OpenRouter provider and no explicit model either succeeds with a valid OpenRouter default or fails with a clear 'model not available on OpenRouter' message (not a generic validation error).
  • Done when: The required change is committed and verification passes: Check config.ts:119-125 — openrouter-api case returns model: model || DEFAULT_CLOUD_MODEL. Attempt OpenRouter onboarding with default — observe validation failure.
  • Evidence: config.ts:15 DEFAULT_CLOUD_MODEL = 'nvidia/nemotron-3-super-120b-a12b'; config.ts:119-125 uses it for openrouter-api; test/onboard-openrouter-inference.test.ts:17 uses moonshotai/kimi-k2.6
Review findings by urgency: 6 required fixes, 9 items to resolve/justify, 1 in-scope improvement

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — Source-of-truth review needed: OpenRouter featured model catalog integration

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as missing.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: No test proves OpenRouter still lacks a catalog. Needed: test that fetches OPENROUTER_FEATURED_MODELS_URL and asserts it returns NVIDIA catalog structure.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: openrouter.ts:5 exports NVIDIA URL; setup-nim-flow.ts:346-354 uses NVIDIA parser with empty retiredModelIds and misleading label

PRA-2 Resolve/justify — Source-of-truth review needed: DEFAULT_CLOUD_MODEL for OpenRouter

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as missing.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Test that OpenRouter onboarding with default model either succeeds (model exists on OpenRouter) or fails with clear 'not available on OpenRouter' message.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: config.ts:15 DEFAULT_CLOUD_MODEL = NVIDIA model; config.ts:119-125 uses it for openrouter-api; test uses moonshotai/kimi-k2.6

PRA-3 Resolve/justify — Source-of-truth review needed: extraHeaders parameter without validation

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Test that extraHeaders with newlines, malformed format, or hop-by-hop headers are rejected/sanitized.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: auth-config.ts:147-148 blindly appends extraHeaders; openrouter-selection.ts:50 only current caller

PRA-4 Resolve/justify — Source-of-truth review needed: @ts-nocheck on providers.ts and onboard-probes.ts

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: CI check that fails on @ts-nocheck in security-critical file list.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: providers.ts:1 and onboard-probes.ts:1 both have @ts-nocheck; unchanged from prior review

PRA-11 Resolve/justify — Source-of-truth workaround undocumented: OpenRouter uses NVIDIA catalog parser

  • Location: src/lib/onboard/setup-nim-flow.ts:346
  • Category: architecture
  • Problem: setup-nim-flow.ts:346-354 creates openRouterFeaturedModels session using NVIDIA's catalog parser with: catalogUrl: OPENROUTER_FEATURED_MODELS_URL (NVIDIA URL), retiredModelIds: [] (disables NVIDIA filter), catalogLabel: 'OpenRouter's featured model catalog' (misleading). No comment answers: (a) what invalid state is handled (OpenRouter has no catalog), (b) where created (this PR), (c) why source cannot be fixed (OpenRouter doesn't publish one), (d) regression test proving source cannot regress, (e) when workaround can be removed.
  • Impact: Maintainers and operators cannot understand why OpenRouter uses NVIDIA's catalog parser, what the fallback behavior is, or when it can be removed. Debugging 'why do I see Nemotron models on OpenRouter?' has no code-level explanation.
  • Recommended action: Add comment block in openrouter.ts and setup-nim-flow.ts addressing all five source-of-truth questions. Change catalogLabel to reflect reality (e.g., 'NVIDIA featured models (temporary fallback for OpenRouter)').
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read openrouter.ts and setup-nim-flow.ts:346-354 — no comment explains the workaround, catalogLabel claims 'OpenRouter's featured model catalog'.
  • Missing regression test: Add test that fetches OPENROUTER_FEATURED_MODELS_URL and asserts it returns NVIDIA's catalog structure (not OpenRouter's), proving the workaround is still in place.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read openrouter.ts and setup-nim-flow.ts:346-354 — no comment explains the workaround, catalogLabel claims 'OpenRouter's featured model catalog'.
  • Evidence: setup-nim-flow.ts:346-354 creates openRouterFeaturedModels with NVIDIA URL, empty retiredModelIds, misleading label; openrouter.ts:5 exports the NVIDIA URL

PRA-12 Resolve/justify — Missing test coverage for critical OpenRouter paths

  • Location: test/onboard-openrouter-inference.test.ts:1
  • Category: tests
  • Problem: No test verifies: (a) catalog fetch uses correct URL (not NVIDIA's), (b) validation probe includes extraHeaders attribution headers, (c) OpenRouter recovery round-trip (credential reuse, gateway provider identity), (d) non-interactive credential validation skip branch (reuseGatewayCredentialWithoutLocalKey=true), (e) network policy presets applied for OpenRouter, (f) model-switch via 'inference set --provider openrouter-api'. Risk plan invariants inference-routing, network-policy, onboard-resume lack evidence.
  • Impact: Critical OpenRouter behaviors untested; regressions in catalog fetching, probe headers, recovery, policy, or switching would not be caught.
  • Recommended action: Add behavior-specific tests: (1) catalog fetch URL test, (2) probe header test in onboard-probes.test.ts, (3) OpenRouter recovery test in onboard-openrouter-recovery.test.ts, (4) non-interactive validation skip test, (5) policy preset test, (6) inference set switch test.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Grep test files for OpenRouter + catalog/headers/recovery/policy/switch — all absent.
  • Missing regression test: Each missing coverage area needs a concrete test as described in recommendation.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Grep test files for OpenRouter + catalog/headers/recovery/policy/switch — all absent.
  • Evidence: test/onboard-openrouter-inference.test.ts only covers basic non-interactive setup; no tests for catalog, headers, recovery, policy, or switch

PRA-14 Resolve/justify — onboard.ts ~4893 lines; OpenRouter logic added inline not extracted

  • Location: src/lib/onboard.ts:3593
  • Category: architecture
  • Problem: OpenRouter credential validation (line 3593), model validation options (line 3612), model selection (line 3631) wired directly in onboard.ts instead of src/lib/onboard/inference-providers/. File remains near 5000 lines; prior review PRA-13 flagged this. This PR adds OpenRouter calls without extraction.
  • Impact: onboard.ts monolith continues growing; provider-specific logic scattered instead of modularized. Harder to test, review, and maintain.
  • Recommended action: Continue extracting provider-specific onboarding logic into dedicated modules under src/lib/onboard/inference-providers/. At minimum, ensure no further growth in this PR.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check onboard.ts lines 3593-3631 — inline OpenRouter calls to openrouterSelection.credentialValidatorForProvider, openAiLikeModelValidationOptions, selectModel.
  • Missing regression test: N/A — architecture finding.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check onboard.ts lines 3593-3631 — inline OpenRouter calls to openrouterSelection.credentialValidatorForProvider, openAiLikeModelValidationOptions, selectModel.
  • Evidence: onboard.ts:3593-3631 imports openrouterSelection and calls its functions directly in main onboarding flow

PRA-15 Resolve/justify — Non-interactive credential validation skipped when reuseGatewayCredentialWithoutLocalKey=true

  • Location: src/lib/onboard/openrouter-selection.ts:61
  • Category: correctness
  • Problem: openrouter-selection.ts:61-83 validateNonInteractiveCredential() only runs when isNonInteractive && isOpenRouterProvider && !reuseGatewayCredentialWithoutLocalKey. Recovery path sets reuseGatewayCredentialWithoutLocalKey=true, skipping validation entirely. No test covers this branch.
  • Impact: Recovered OpenRouter sandbox may proceed with invalid/stale gateway credential without validation, leading to silent inference failures later.
  • Recommended action: Validate credential even in recovery path, or document why gateway credential reuse bypasses validation (e.g., gateway already validated it).
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read openrouter-selection.ts:61-83; trace recovery call path in recovered-provider-reuse.ts — observe reuseGatewayCredentialWithoutLocalKey=true bypasses validation.
  • Missing regression test: Add test: recover OpenRouter sandbox with invalid gateway credential — assert validation runs and fails, or assert documented bypass rationale.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read openrouter-selection.ts:61-83; trace recovery call path in recovered-provider-reuse.ts — observe reuseGatewayCredentialWithoutLocalKey=true bypasses validation.
  • Evidence: openrouter-selection.ts:61-83 early-returns when reuseGatewayCredentialWithoutLocalKey=true; recovered-provider-reuse.ts sets this flag for recovery

PRA-16 Resolve/justify — Documentation claims OpenRouter has own catalog but implementation uses NVIDIA's

  • Location: docs/inference/inference-options.mdx:69
  • Category: docs
  • Problem: docs/inference/inference-options.mdx:69 states 'OpenRouter uses the same catalog-backed picker flow with its own OpenRouter featured model catalog' but implementation uses NVIDIA's catalog parser with NVIDIA URL and NVIDIA-specific normalization. Docs and code are out of sync.
  • Impact: Users and maintainers reading docs believe OpenRouter has a dedicated catalog; actual behavior shows NVIDIA models. Misleading documentation.
  • Recommended action: Update docs to reflect reality: 'OpenRouter temporarily uses NVIDIA's featured model catalog as a fallback; models shown are NVIDIA-curated and may not be available on OpenRouter. Manual entry is recommended.' Or fix implementation first (finding ci: auto-update release notes on push to main #1) then update docs.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read inference-options.mdx:69 vs openrouter.ts:5 and setup-nim-flow.ts:346-354 — docs claim own catalog, code uses NVIDIA's.
  • Missing regression test: Add doc validation test that checks inference-options.mdx catalog description matches implementation behavior.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read inference-options.mdx:69 vs openrouter.ts:5 and setup-nim-flow.ts:346-354 — docs claim own catalog, code uses NVIDIA's.
  • Evidence: inference-options.mdx:69 claims OpenRouter has own catalog; openrouter.ts:5 exports NVIDIA URL; setup-nim-flow.ts:346-354 uses NVIDIA parser

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

PRA-13 Improvement — Duplicate catalog pattern: openrouter-selection.ts duplicates nvidia-featured-model-selection.ts

  • Location: src/lib/onboard/openrouter-selection.ts:1
  • Category: architecture
  • Problem: openrouter-selection.ts (110 lines) duplicates nvidia-featured-model-selection.ts pattern: both create FeaturedModelSession via createNvidiaFeaturedModelSession(), both call promptCloudModel(). Could share FeaturedModelCatalogSession abstraction parameterized by catalog URL, retired models, label — but current implementation is a workaround; extracting would solidify it.
  • Impact: Duplicated code increases maintenance burden and solidifies the workaround. If OpenRouter publishes a real catalog, both files need changes.
  • Suggested action: If OpenRouter publishes a real catalog, extract shared FeaturedModelCatalogSession module parameterized by URL, retiredModelIds, label. Otherwise, remove catalog integration entirely for OpenRouter (fall back to manual entry) per PRA-22.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Compare openrouter-selection.ts and nvidia-featured-model-selection.ts — ~80% structural duplication in select() method and session creation.
  • Missing regression test: N/A — simplification finding.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: openrouter-selection.ts:85-110 selectModel() mirrors nvidia-featured-model-selection.ts createNvidiaFeaturedModelSession() pattern
Simplification opportunities: 1 possible cut, net -80 lines possible

These are safe simplification checks only. Do not remove validation, security controls, data-loss prevention, or required tests.

  • PRA-13 yagni (src/lib/onboard/openrouter-selection.ts:1): src/lib/onboard/openrouter-selection.ts selectModel() and createNvidiaFeaturedModelSession() usage
    • Replacement: Shared FeaturedModelCatalogSession module (if OpenRouter publishes catalog) or manual entry only (if not)
    • Net: -80 lines
    • Safety boundary: Must not remove credential validation, probe header injection, or recovery logic — only the catalog picker duplication
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — Run the cloud-onboard E2E job for installer and platform changes. Matched files: ci/platform-matrix.json, install.sh, scripts/install.sh.. Deterministic regression risks require live validation: lifecycle-state (onboard-resume, onboard-repair), inference-policy (inference-routing, network-policy), platform-install (cloud-onboard), credentials-security (credential-sanitization, security-posture). Unit and mocked tests cover basic flows but critical paths (catalog fetch, probe headers, recovery, policy, model switch) lack coverage and need runtime validation against real OpenRouter endpoint.
  • PRA-T2 Runtime validation — Run the credential-sanitization E2E job for credential boundary changes. Matched files: scripts/checks/direct-credential-env.ts, src/lib/credentials/store.ts, src/lib/onboard/credential-navigation.ts, src/lib/security/credential-env.ts, src/lib/security/redact.ts.. Deterministic regression risks require live validation: lifecycle-state (onboard-resume, onboard-repair), inference-policy (inference-routing, network-policy), platform-install (cloud-onboard), credentials-security (credential-sanitization, security-posture). Unit and mocked tests cover basic flows but critical paths (catalog fetch, probe headers, recovery, policy, model switch) lack coverage and need runtime validation against real OpenRouter endpoint.
  • PRA-T3 Runtime validation — Run the security-posture E2E job for security boundary changes. Matched files: same as credential-sanitization.. Deterministic regression risks require live validation: lifecycle-state (onboard-resume, onboard-repair), inference-policy (inference-routing, network-policy), platform-install (cloud-onboard), credentials-security (credential-sanitization, security-posture). Unit and mocked tests cover basic flows but critical paths (catalog fetch, probe headers, recovery, policy, model switch) lack coverage and need runtime validation against real OpenRouter endpoint.
  • PRA-T4 Runtime validation — Run the inference-routing E2E job for OpenRouter routing validation. Matched files: src/lib/actions/inference-set.ts, src/lib/inference/config.ts, src/lib/inference/model-prompts.ts, src/lib/inference/nvidia-featured-models.ts, src/lib/inference/onboard-probes.ts.. Deterministic regression risks require live validation: lifecycle-state (onboard-resume, onboard-repair), inference-policy (inference-routing, network-policy), platform-install (cloud-onboard), credentials-security (credential-sanitization, security-posture). Unit and mocked tests cover basic flows but critical paths (catalog fetch, probe headers, recovery, policy, model switch) lack coverage and need runtime validation against real OpenRouter endpoint.
  • PRA-T5 Runtime validation — Run the network-policy E2E job for OpenRouter policy presets. Matched files: same as inference-routing.. Deterministic regression risks require live validation: lifecycle-state (onboard-resume, onboard-repair), inference-policy (inference-routing, network-policy), platform-install (cloud-onboard), credentials-security (credential-sanitization, security-posture). Unit and mocked tests cover basic flows but critical paths (catalog fetch, probe headers, recovery, policy, model switch) lack coverage and need runtime validation against real OpenRouter endpoint.
  • PRA-T6 Missing test coverage for critical OpenRouter paths — Add behavior-specific tests: (1) catalog fetch URL test, (2) probe header test in onboard-probes.test.ts, (3) OpenRouter recovery test in onboard-openrouter-recovery.test.ts, (4) non-interactive validation skip test, (5) policy preset test, (6) inference set switch test.
  • PRA-T7 Acceptance clause — Adds first-class OpenRouter onboarding support for OpenClaw, Hermes, and LangChain Deep Agents Code (feat: adding OpenRouter as an inference provider #5826) — add test evidence or identify existing coverage. Provider choice added, credential env OPENROUTER_API_KEY integrated, OpenShell provider openrouter-api registered, attribution headers on probes. But catalog-backed picker shows NVIDIA models (finding ci: auto-update release notes on push to main #1), default model unverified (finding Bootstrap sandbox OpenClaw config after launch and migrate #5), docs claim own catalog (finding Remove unsupported local-model choices from onboarding until local inference is actually supported #11).
  • PRA-T8 Acceptance clause — OpenRouter uses the same catalog-backed picker flow with its own OpenRouter featured model catalog — add test evidence or identify existing coverage. Implementation uses NVIDIA's catalog URL (openrouter.ts:5) and NVIDIA parser (setup-nim-flow.ts:346-354). No OpenRouter catalog exists at that URL.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: OpenRouter featured model catalog integration

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as missing.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: No test proves OpenRouter still lacks a catalog. Needed: test that fetches OPENROUTER_FEATURED_MODELS_URL and asserts it returns NVIDIA catalog structure.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: openrouter.ts:5 exports NVIDIA URL; setup-nim-flow.ts:346-354 uses NVIDIA parser with empty retiredModelIds and misleading label

PRA-2 Resolve/justify — Source-of-truth review needed: DEFAULT_CLOUD_MODEL for OpenRouter

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as missing.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Test that OpenRouter onboarding with default model either succeeds (model exists on OpenRouter) or fails with clear 'not available on OpenRouter' message.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: config.ts:15 DEFAULT_CLOUD_MODEL = NVIDIA model; config.ts:119-125 uses it for openrouter-api; test uses moonshotai/kimi-k2.6

PRA-3 Resolve/justify — Source-of-truth review needed: extraHeaders parameter without validation

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Test that extraHeaders with newlines, malformed format, or hop-by-hop headers are rejected/sanitized.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: auth-config.ts:147-148 blindly appends extraHeaders; openrouter-selection.ts:50 only current caller

PRA-4 Resolve/justify — Source-of-truth review needed: @ts-nocheck on providers.ts and onboard-probes.ts

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: CI check that fails on @ts-nocheck in security-critical file list.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: providers.ts:1 and onboard-probes.ts:1 both have @ts-nocheck; unchanged from prior review

PRA-5 Required — OPENROUTER_FEATURED_MODELS_URL hardcoded to NVIDIA catalog

  • Location: src/lib/inference/openrouter.ts:5
  • Category: correctness
  • Problem: OPENROUTER_FEATURED_MODELS_URL exports 'https://assets.ngc.nvidia.com/products/api-catalog/featured-models-openrouter.json' (NVIDIA's catalog). setup-nim-flow.ts:346-354 feeds this to createNvidiaFeaturedModelSession() which applies NVIDIA-specific retired-model filtering, ID normalization (minimax-m2.7→m3, bare nemotron-3-*→nvidia/nemotron-3-*), and label normalization. OpenRouter has no featured catalog at this URL; onboarding users who pick OpenRouter see NVIDIA-curated models (Nemotron, Kimi, Minimax) instead of OpenRouter-available models. Violates acceptance clause from feat: adding OpenRouter as an inference provider #5826 claiming 'OpenRouter uses its own featured model catalog'.
  • Impact: OpenRouter onboarding model picker shows incorrect NVIDIA models leading to validation failures or wrong model selection. Manual entry still works but catalog-backed picker is fundamentally broken.
  • Required action: Replace with OpenRouter's actual models endpoint (https://openrouter.ai/api/v1/models, requires authentication) or remove the featured catalog integration for OpenRouter and fall back to manual entry only. Add a comment explaining why OpenRouter doesn't use a featured catalog.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check src/lib/inference/openrouter.ts:5 — the URL is hardcoded to NVIDIA's assets domain. In production onboarding, selecting OpenRouter loads NVIDIA models.
  • Missing regression test: Add integration test that selects OpenRouter provider and verifies the catalog URL fetched is OpenRouter's, not NVIDIA's, and that displayed models are OpenRouter-available models.
  • Done when: The required change is committed and verification passes: Check src/lib/inference/openrouter.ts:5 — the URL is hardcoded to NVIDIA's assets domain. In production onboarding, selecting OpenRouter loads NVIDIA models.
  • Evidence: src/lib/inference/openrouter.ts:5 exports OPENROUTER_FEATURED_MODELS_URL = 'https://assets.ngc.nvidia.com/products/api-catalog/featured-models-openrouter.json'; setup-nim-flow.ts:347 uses this URL for OpenRouter catalog session

PRA-6 Required — extraHeaders parameter lacks validation — header injection vector

  • Location: src/lib/adapters/http/auth-config.ts:147
  • Category: security
  • Problem: createOpenAiLikeAuthConfig() accepts extraHeaders?: readonly string[] and blindly appends each entry as a curl header (lines 147-148): for (const header of options.extraHeaders ?? []) { entries.push({ kind: 'header', value: header }); }. No validation: newlines not rejected, no 'Header-Name: value' format enforcement, hop-by-hop headers (Connection, Transfer-Encoding, Keep-Alive, etc.) not stripped. Currently only OpenRouter uses it (two static headers from getOpenRouterCurlHeaders()) but API is an open header-injection surface for any future caller.
  • Impact: Malicious or buggy caller could inject arbitrary headers, newlines, or hop-by-hop headers into curl probes, potentially bypassing security controls or causing probe misbehavior.
  • Required action: Add validation for extraHeaders: reject newlines, ensure 'Header-Name: value' format, strip hop-by-hop headers, or replace with OpenRouter-specific createOpenRouterAuthConfig() that hardcodes the two attribution headers and removes the generic parameter.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read auth-config.ts:147-148; attempt extraHeaders: ['X-Injected: value\r\nX-Another: bad'] in a test — observe both headers are passed to curl without sanitization.
  • Missing regression test: Add unit test for createOpenAiLikeAuthConfig with malicious extraHeaders (newlines, malformed format, hop-by-hop headers) asserting they are rejected or sanitized.
  • Done when: The required change is committed and verification passes: Read auth-config.ts:147-148; attempt extraHeaders: ['X-Injected: value\r\nX-Another: bad'] in a test — observe both headers are passed to curl without sanitization.
  • Evidence: src/lib/adapters/http/auth-config.ts:130-151 adds extraHeaders parameter and blindly appends at lines 147-148; openrouter-selection.ts:50 calls getProbeExtraHeaders('openrouter-api') returning static headers

PRA-7 Required — @ts-nocheck disables type safety on credential/provider registry boundary

  • Location: src/lib/onboard/providers.ts:1
  • Category: security
  • Problem: @ts-nocheck at top of src/lib/onboard/providers.ts:1 disables TypeScript checking for the entire file. This file handles credential resolution (resolveProviderCredential, getCredential), provider registry (getProviderSelectionConfig, registerProvider), and gateway provider CRUD — all trust boundaries where type safety is a primary defense.
  • Impact: Type errors in credential handling, provider identity, or gateway registration go undetected at compile time, increasing risk of credential leakage, provider spoofing, or gateway misconfiguration.
  • Required action: Remove @ts-nocheck and fix underlying type errors. If legitimate dynamic patterns exist, refactor to proper types or use targeted @ts-expect-error with comments explaining why.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check src/lib/onboard/providers.ts:1 — @ts-nocheck directive present. Run npx tsc --noEmit src/lib/onboard/providers.ts to see suppressed errors.
  • Missing regression test: Add CI check that fails on @ts-nocheck in security-critical files (credentials/store.ts, onboard/providers.ts, inference/onboard-probes.ts, security/credential-env.ts, security/redact.ts).
  • Done when: The required change is committed and verification passes: Check src/lib/onboard/providers.ts:1 — @ts-nocheck directive present. Run npx tsc --noEmit src/lib/onboard/providers.ts to see suppressed errors.
  • Evidence: src/lib/onboard/providers.ts:1 has @ts-nocheck; file exports resolveProviderCredential, getCredential, registerProvider, getProviderSelectionConfig

PRA-8 Required — @ts-nocheck disables type safety on network probe boundary

  • Location: src/lib/inference/onboard-probes.ts:1
  • Category: security
  • Problem: @ts-nocheck at top of src/lib/inference/onboard-probes.ts:1 disables TypeScript checking for the entire file. This file constructs curl argv with credentials, performs SSRF validation, sends network probes with API keys, and handles probe responses — all trust boundaries where type safety is a primary defense.
  • Impact: Type errors in curl argument construction, credential handling, SSRF validation, or response parsing go undetected at compile time, increasing risk of SSRF bypass, credential leakage, or probe logic errors.
  • Required action: Remove @ts-nocheck and fix underlying type errors, or add a concrete tracking issue with timeline. If migration is tracked separately, link the issue in the comment.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check src/lib/inference/onboard-probes.ts:1 — @ts-nocheck directive present. Run npx tsc --noEmit src/lib/inference/onboard-probes.ts to see suppressed errors.
  • Missing regression test: Add CI check that fails on @ts-nocheck in security-critical files.
  • Done when: The required change is committed and verification passes: Check src/lib/inference/onboard-probes.ts:1 — @ts-nocheck directive present. Run npx tsc --noEmit src/lib/inference/onboard-probes.ts to see suppressed errors.
  • Evidence: src/lib/inference/onboard-probes.ts:1 has @ts-nocheck; file exports validateOpenAiLikeSelection, validateAnthropicSelection, getProbeExtraHeaders, runCurlProbe

PRA-9 Required — Monolith test file grew by 42 lines without extraction

  • Location: src/lib/onboard/recovered-provider-reuse.test.ts:1
  • Category: architecture
  • Problem: recovered-provider-reuse.test.ts grew from 483 to 525 lines (+42) by adding OpenRouter recovery test cases inline. Risk plan requires offsetting growth before merge for files exceeding +20 lines. Three other test files also exceed threshold: model-prompts.test.ts +30, config.test.ts +24, providers.test.ts +22.
  • Impact: Test monoliths become harder to maintain, slower to run, and couple unrelated provider logic. Growth without extraction violates the project's architecture guardrails.
  • Required action: Extract OpenRouter-specific tests into dedicated test files: onboard-openrouter-recovery.test.ts, model-prompts-openrouter.test.ts, config-openrouter.test.ts, providers-openrouter.test.ts. Offset growth before merge.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check ci/test-file-size-budget.json — blocker files not budgeted; grep for 'openrouter' in each test file — test blocks added inline.
  • Missing regression test: N/A — this is a structural finding; the regression test is the extraction itself.
  • Done when: The required change is committed and verification passes: Check ci/test-file-size-budget.json — blocker files not budgeted; grep for 'openrouter' in each test file — test blocks added inline.
  • Evidence: riskPlan monolithDeltas shows recovered-provider-reuse.test.ts +42 (blocker), model-prompts.test.ts +30 (blocker), config.test.ts +24 (blocker), providers.test.ts +22 (blocker)

PRA-10 Required — DEFAULT_CLOUD_MODEL (Nemotron 3 Super) used for OpenRouter but unverified on OpenRouter

  • Location: src/lib/inference/config.ts:119
  • Category: correctness
  • Problem: config.ts:15 exports DEFAULT_CLOUD_MODEL = 'nvidia/nemotron-3-super-120b-a12b'. config.ts:119-125 uses this for openrouter-api in getProviderSelectionConfig(). Integration test test/onboard-openrouter-inference.test.ts:17 uses moonshotai/kimi-k2.6. No evidence Nemotron 3 Super is available on OpenRouter. User selecting OpenRouter gets NVIDIA default that will fail validation.
  • Impact: OpenRouter onboarding defaults to a model that may not exist on OpenRouter, causing immediate validation failure and confusing UX.
  • Required action: Verify Nemotron 3 Super availability on OpenRouter. If not available, change default to a confirmed OpenRouter model (e.g., moonshotai/kimi-k2.6 used in tests) or add logic to validate default availability at onboarding time.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check config.ts:119-125 — openrouter-api case returns model: model || DEFAULT_CLOUD_MODEL. Attempt OpenRouter onboarding with default — observe validation failure.
  • Missing regression test: Add test that onboarding with OpenRouter provider and no explicit model either succeeds with a valid OpenRouter default or fails with a clear 'model not available on OpenRouter' message (not a generic validation error).
  • Done when: The required change is committed and verification passes: Check config.ts:119-125 — openrouter-api case returns model: model || DEFAULT_CLOUD_MODEL. Attempt OpenRouter onboarding with default — observe validation failure.
  • Evidence: config.ts:15 DEFAULT_CLOUD_MODEL = 'nvidia/nemotron-3-super-120b-a12b'; config.ts:119-125 uses it for openrouter-api; test/onboard-openrouter-inference.test.ts:17 uses moonshotai/kimi-k2.6

PRA-11 Resolve/justify — Source-of-truth workaround undocumented: OpenRouter uses NVIDIA catalog parser

  • Location: src/lib/onboard/setup-nim-flow.ts:346
  • Category: architecture
  • Problem: setup-nim-flow.ts:346-354 creates openRouterFeaturedModels session using NVIDIA's catalog parser with: catalogUrl: OPENROUTER_FEATURED_MODELS_URL (NVIDIA URL), retiredModelIds: [] (disables NVIDIA filter), catalogLabel: 'OpenRouter's featured model catalog' (misleading). No comment answers: (a) what invalid state is handled (OpenRouter has no catalog), (b) where created (this PR), (c) why source cannot be fixed (OpenRouter doesn't publish one), (d) regression test proving source cannot regress, (e) when workaround can be removed.
  • Impact: Maintainers and operators cannot understand why OpenRouter uses NVIDIA's catalog parser, what the fallback behavior is, or when it can be removed. Debugging 'why do I see Nemotron models on OpenRouter?' has no code-level explanation.
  • Recommended action: Add comment block in openrouter.ts and setup-nim-flow.ts addressing all five source-of-truth questions. Change catalogLabel to reflect reality (e.g., 'NVIDIA featured models (temporary fallback for OpenRouter)').
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read openrouter.ts and setup-nim-flow.ts:346-354 — no comment explains the workaround, catalogLabel claims 'OpenRouter's featured model catalog'.
  • Missing regression test: Add test that fetches OPENROUTER_FEATURED_MODELS_URL and asserts it returns NVIDIA's catalog structure (not OpenRouter's), proving the workaround is still in place.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read openrouter.ts and setup-nim-flow.ts:346-354 — no comment explains the workaround, catalogLabel claims 'OpenRouter's featured model catalog'.
  • Evidence: setup-nim-flow.ts:346-354 creates openRouterFeaturedModels with NVIDIA URL, empty retiredModelIds, misleading label; openrouter.ts:5 exports the NVIDIA URL

PRA-12 Resolve/justify — Missing test coverage for critical OpenRouter paths

  • Location: test/onboard-openrouter-inference.test.ts:1
  • Category: tests
  • Problem: No test verifies: (a) catalog fetch uses correct URL (not NVIDIA's), (b) validation probe includes extraHeaders attribution headers, (c) OpenRouter recovery round-trip (credential reuse, gateway provider identity), (d) non-interactive credential validation skip branch (reuseGatewayCredentialWithoutLocalKey=true), (e) network policy presets applied for OpenRouter, (f) model-switch via 'inference set --provider openrouter-api'. Risk plan invariants inference-routing, network-policy, onboard-resume lack evidence.
  • Impact: Critical OpenRouter behaviors untested; regressions in catalog fetching, probe headers, recovery, policy, or switching would not be caught.
  • Recommended action: Add behavior-specific tests: (1) catalog fetch URL test, (2) probe header test in onboard-probes.test.ts, (3) OpenRouter recovery test in onboard-openrouter-recovery.test.ts, (4) non-interactive validation skip test, (5) policy preset test, (6) inference set switch test.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Grep test files for OpenRouter + catalog/headers/recovery/policy/switch — all absent.
  • Missing regression test: Each missing coverage area needs a concrete test as described in recommendation.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Grep test files for OpenRouter + catalog/headers/recovery/policy/switch — all absent.
  • Evidence: test/onboard-openrouter-inference.test.ts only covers basic non-interactive setup; no tests for catalog, headers, recovery, policy, or switch

PRA-13 Improvement — Duplicate catalog pattern: openrouter-selection.ts duplicates nvidia-featured-model-selection.ts

  • Location: src/lib/onboard/openrouter-selection.ts:1
  • Category: architecture
  • Problem: openrouter-selection.ts (110 lines) duplicates nvidia-featured-model-selection.ts pattern: both create FeaturedModelSession via createNvidiaFeaturedModelSession(), both call promptCloudModel(). Could share FeaturedModelCatalogSession abstraction parameterized by catalog URL, retired models, label — but current implementation is a workaround; extracting would solidify it.
  • Impact: Duplicated code increases maintenance burden and solidifies the workaround. If OpenRouter publishes a real catalog, both files need changes.
  • Suggested action: If OpenRouter publishes a real catalog, extract shared FeaturedModelCatalogSession module parameterized by URL, retiredModelIds, label. Otherwise, remove catalog integration entirely for OpenRouter (fall back to manual entry) per PRA-22.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Compare openrouter-selection.ts and nvidia-featured-model-selection.ts — ~80% structural duplication in select() method and session creation.
  • Missing regression test: N/A — simplification finding.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: openrouter-selection.ts:85-110 selectModel() mirrors nvidia-featured-model-selection.ts createNvidiaFeaturedModelSession() pattern

PRA-14 Resolve/justify — onboard.ts ~4893 lines; OpenRouter logic added inline not extracted

  • Location: src/lib/onboard.ts:3593
  • Category: architecture
  • Problem: OpenRouter credential validation (line 3593), model validation options (line 3612), model selection (line 3631) wired directly in onboard.ts instead of src/lib/onboard/inference-providers/. File remains near 5000 lines; prior review PRA-13 flagged this. This PR adds OpenRouter calls without extraction.
  • Impact: onboard.ts monolith continues growing; provider-specific logic scattered instead of modularized. Harder to test, review, and maintain.
  • Recommended action: Continue extracting provider-specific onboarding logic into dedicated modules under src/lib/onboard/inference-providers/. At minimum, ensure no further growth in this PR.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check onboard.ts lines 3593-3631 — inline OpenRouter calls to openrouterSelection.credentialValidatorForProvider, openAiLikeModelValidationOptions, selectModel.
  • Missing regression test: N/A — architecture finding.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check onboard.ts lines 3593-3631 — inline OpenRouter calls to openrouterSelection.credentialValidatorForProvider, openAiLikeModelValidationOptions, selectModel.
  • Evidence: onboard.ts:3593-3631 imports openrouterSelection and calls its functions directly in main onboarding flow

PRA-15 Resolve/justify — Non-interactive credential validation skipped when reuseGatewayCredentialWithoutLocalKey=true

  • Location: src/lib/onboard/openrouter-selection.ts:61
  • Category: correctness
  • Problem: openrouter-selection.ts:61-83 validateNonInteractiveCredential() only runs when isNonInteractive && isOpenRouterProvider && !reuseGatewayCredentialWithoutLocalKey. Recovery path sets reuseGatewayCredentialWithoutLocalKey=true, skipping validation entirely. No test covers this branch.
  • Impact: Recovered OpenRouter sandbox may proceed with invalid/stale gateway credential without validation, leading to silent inference failures later.
  • Recommended action: Validate credential even in recovery path, or document why gateway credential reuse bypasses validation (e.g., gateway already validated it).
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read openrouter-selection.ts:61-83; trace recovery call path in recovered-provider-reuse.ts — observe reuseGatewayCredentialWithoutLocalKey=true bypasses validation.
  • Missing regression test: Add test: recover OpenRouter sandbox with invalid gateway credential — assert validation runs and fails, or assert documented bypass rationale.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read openrouter-selection.ts:61-83; trace recovery call path in recovered-provider-reuse.ts — observe reuseGatewayCredentialWithoutLocalKey=true bypasses validation.
  • Evidence: openrouter-selection.ts:61-83 early-returns when reuseGatewayCredentialWithoutLocalKey=true; recovered-provider-reuse.ts sets this flag for recovery

PRA-16 Resolve/justify — Documentation claims OpenRouter has own catalog but implementation uses NVIDIA's

  • Location: docs/inference/inference-options.mdx:69
  • Category: docs
  • Problem: docs/inference/inference-options.mdx:69 states 'OpenRouter uses the same catalog-backed picker flow with its own OpenRouter featured model catalog' but implementation uses NVIDIA's catalog parser with NVIDIA URL and NVIDIA-specific normalization. Docs and code are out of sync.
  • Impact: Users and maintainers reading docs believe OpenRouter has a dedicated catalog; actual behavior shows NVIDIA models. Misleading documentation.
  • Recommended action: Update docs to reflect reality: 'OpenRouter temporarily uses NVIDIA's featured model catalog as a fallback; models shown are NVIDIA-curated and may not be available on OpenRouter. Manual entry is recommended.' Or fix implementation first (finding ci: auto-update release notes on push to main #1) then update docs.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read inference-options.mdx:69 vs openrouter.ts:5 and setup-nim-flow.ts:346-354 — docs claim own catalog, code uses NVIDIA's.
  • Missing regression test: Add doc validation test that checks inference-options.mdx catalog description matches implementation behavior.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read inference-options.mdx:69 vs openrouter.ts:5 and setup-nim-flow.ts:346-354 — docs claim own catalog, code uses NVIDIA's.
  • Evidence: inference-options.mdx:69 claims OpenRouter has own catalog; openrouter.ts:5 exports NVIDIA URL; setup-nim-flow.ts:346-354 uses NVIDIA parser

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@sandl99 sandl99 changed the title feat(cli): add OpenRouter onboarding support feat(inference): add OpenRouter onboarding support Jul 8, 2026

@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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/get-started/quickstart.mdx (1)

129-141: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Numbered wizard-menu example is now stale.

The table below (lines 163-171) places OpenRouter as the second provider option, per the PR objective that OpenRouter is "positioned as the second inference option." But the sample terminal output block at lines 132-140 still shows the pre-OpenRouter menu (8 items, no OpenRouter entry). A user following this example would see a mismatched menu when actually running nemoclaw onboard.

📝 Proposed fix
 ```text
   1) NVIDIA Endpoints
-  2) OpenAI
-  3) Other OpenAI-compatible endpoint
-  4) Anthropic
-  5) Other Anthropic-compatible endpoint
-  6) Google Gemini
-  7) Local Ollama (localhost:11434)
-  8) Model Router (experimental)
+  2) OpenRouter
+  3) OpenAI
+  4) Other OpenAI-compatible endpoint
+  5) Anthropic
+  6) Other Anthropic-compatible endpoint
+  7) Google Gemini
+  8) Local Ollama (localhost:11434)
+  9) Model Router (experimental)
   Choose [1]:
</details>






Also applies to: 163-166

<details>
<summary>🤖 Prompt for AI Agents</summary>

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

In @docs/get-started/quickstart.mdx around lines 129 - 141, The quickstart’s
terminal example is stale: the wizard menu shown in the inference provider
prompt no longer matches the provider ordering used by the onboarding flow.
Update the sample output in the quickstart doc so it reflects the current
nemoclaw onboard menu with OpenRouter as the second inference option and the
remaining entries renumbered accordingly, keeping the example consistent with
the provider table and the prompt displayed by the onboarding wizard.


</details>

<!-- cr-comment:v1:1c784d0e2769bcfb2cfd1ec9 -->

</blockquote></details>

</blockquote></details>
🧹 Nitpick comments (3)
test/onboard-selection.test.ts (1)

565-601: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Menu-index shifts look internally consistent.

Verified against sibling ordering comments elsewhere in the file (e.g. "vLLM is option 8 (build, openrouter, openai, custom, anthropic, anthropicCompatible, gemini, vllm)") — OpenAI=3, Other-OpenAI-compat=4, Anthropic=5, Other-Anthropic-compat=6, Gemini=7 all match a single insertion of OpenRouter at position 2.

Separately: this file relies on hardcoded numeric menu indices in many places, which required updating ~15 locations for this one insertion. The file already has a pattern-based alternative (selectRecentMenuOption/menuSelections) used elsewhere in the same batch runner; consider migrating more scenarios to it to avoid this fragility on future menu reorders.

🤖 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 `@test/onboard-selection.test.ts` around lines 565 - 601, The hardcoded menu
indices in the onboarding selection tests are too brittle and required
widespread updates after inserting a new option. Update the affected scenarios
in onboard-selection.test.ts to prefer the existing pattern-based helpers like
selectRecentMenuOption and menuSelections where possible, and keep the remaining
numeric answers aligned with the current menu order using the referenced option
labels such as OpenAI API key, Anthropic API key, Google Gemini API key, and the
OpenAI/Anthropic-compatible endpoint entries.
scripts/checks/direct-credential-env.ts (1)

17-27: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated credential-key inventory can silently drift from SUPPORTED_CREDENTIAL_ENV_NAMES.

CREDENTIAL_ENV_KEYS is a hand-maintained subset that already diverges from src/lib/security/credential-env.ts's SUPPORTED_CREDENTIAL_ENV_NAMES (e.g. missing GOOGLE_API_KEY, NOUS_API_KEY, AWS_*, HF_TOKEN, etc.). Adding OPENROUTER_API_KEY here manually, rather than deriving from the canonical inventory, means future credential env additions risk silently bypassing this direct-process.env guardrail check.

Consider importing SUPPORTED_CREDENTIAL_ENV_NAMES as the canonical source for this set instead of maintaining a parallel list.

As per path instructions for scripts/checks/**: "Derive inventories and limits from a canonical source where possible; flag duplicated lists that can silently drift."

🤖 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/checks/direct-credential-env.ts` around lines 17 - 27, The direct
credential env check is maintaining its own list in CREDENTIAL_ENV_KEYS, which
can drift from the canonical inventory. Update the logic in
direct-credential-env.ts to derive the set from SUPPORTED_CREDENTIAL_ENV_NAMES
in src/lib/security/credential-env.ts instead of hardcoding names like
OPENROUTER_API_KEY, so the guardrail automatically stays in sync with future
credential additions.

Source: Path instructions

src/lib/inference/config.ts (1)

271-278: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low value

OpenRouter is intentionally excluded from the Responses API path, but this creates an unreachable entry in recovered-provider-reuse.ts.

The exclusion is confirmed: shouldSkipResponsesProbe explicitly includes "openrouter-api" (line 317 in validation.ts), forcing inferenceApi = "openai-completions". The test comment documents this as intentional: "OpenRouter uses Chat Completions here" (line 435 in validation.test.ts).

However, recovered-provider-reuse.ts line 14 declares openrouter: new Set(["openai-completions", "openai-responses"]), which means the openai-responses path is unreachable in practice—shouldSkipResponsesProbe overrides it to openai-completions before that configuration is consulted. Either the test comment should clarify why OpenRouter is limited to Chat Completions (e.g., due to beta concerns), or the openai-responses entry for OpenRouter in recovered-provider-reuse.ts should be removed to avoid the inconsistency.

🤖 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/config.ts` around lines 271 - 278, OpenRouter is
intentionally routed away from the Responses API, so the `openrouter` entry in
`recovered-provider-reuse.ts` is inconsistent with the actual flow. Update the
configuration by removing the unreachable `openai-responses` option for
OpenRouter, or adjust the related `validation.test.ts` expectation/comment to
clearly explain why `shouldSkipResponsesProbe` in `validation.ts` forces
`openai-completions` before reuse is consulted. Keep the behavior aligned across
`OPENROUTER_PROVIDER_NAME`, `shouldSkipResponsesProbe`, and the
recovered-provider reuse mapping.
🤖 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/onboard.ts`:
- Around line 3609-3629: The non-interactive OpenRouter credential check is
still implemented inline in handleRemoteProviderSelection inside onboard.ts, but
it should be moved into the existing validation flow. Route the OpenRouter API
key check through the focused credential-navigation /
inference-selection-validation validator path instead of duplicating
validateOpenRouterApiKeyValue plus process.exit(1) here, and keep onboard.ts
limited to wiring and selection flow.
- Around line 3639-3642: The OpenRouter featured-model catalog path duplicates
header resolution by calling openrouter.getOpenRouterCurlHeaders() instead of
using getProbeExtraHeaders(state.provider), which can drift from the shared
contract. Update the onboarding flow in onboard.ts, especially the
featured-model catalog logic and any nearby header setup, to route all provider
header resolution through getProbeExtraHeaders(state.provider) consistently.
Keep the existing behavior for OpenRouter, but remove the direct
OpenRouter-specific header call so the same helper is used everywhere.

---

Outside diff comments:
In `@docs/get-started/quickstart.mdx`:
- Around line 129-141: The quickstart’s terminal example is stale: the wizard
menu shown in the inference provider prompt no longer matches the provider
ordering used by the onboarding flow. Update the sample output in the quickstart
doc so it reflects the current `nemoclaw onboard` menu with `OpenRouter` as the
second inference option and the remaining entries renumbered accordingly,
keeping the example consistent with the provider table and the prompt displayed
by the onboarding wizard.

---

Nitpick comments:
In `@scripts/checks/direct-credential-env.ts`:
- Around line 17-27: The direct credential env check is maintaining its own list
in CREDENTIAL_ENV_KEYS, which can drift from the canonical inventory. Update the
logic in direct-credential-env.ts to derive the set from
SUPPORTED_CREDENTIAL_ENV_NAMES in src/lib/security/credential-env.ts instead of
hardcoding names like OPENROUTER_API_KEY, so the guardrail automatically stays
in sync with future credential additions.

In `@src/lib/inference/config.ts`:
- Around line 271-278: OpenRouter is intentionally routed away from the
Responses API, so the `openrouter` entry in `recovered-provider-reuse.ts` is
inconsistent with the actual flow. Update the configuration by removing the
unreachable `openai-responses` option for OpenRouter, or adjust the related
`validation.test.ts` expectation/comment to clearly explain why
`shouldSkipResponsesProbe` in `validation.ts` forces `openai-completions` before
reuse is consulted. Keep the behavior aligned across `OPENROUTER_PROVIDER_NAME`,
`shouldSkipResponsesProbe`, and the recovered-provider reuse mapping.

In `@test/onboard-selection.test.ts`:
- Around line 565-601: The hardcoded menu indices in the onboarding selection
tests are too brittle and required widespread updates after inserting a new
option. Update the affected scenarios in onboard-selection.test.ts to prefer the
existing pattern-based helpers like selectRecentMenuOption and menuSelections
where possible, and keep the remaining numeric answers aligned with the current
menu order using the referenced option labels such as OpenAI API key, Anthropic
API key, Google Gemini API key, and the OpenAI/Anthropic-compatible endpoint
entries.
🪄 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: e6f293b1-cbca-46ad-99ee-0f48486b5ddd

📥 Commits

Reviewing files that changed from the base of the PR and between be3e7cc and 343254e.

📒 Files selected for processing (50)
  • ci/platform-matrix.json
  • docs/get-started/quickstart.mdx
  • docs/inference/inference-options.mdx
  • docs/inference/switch-inference-providers.mdx
  • docs/reference/commands.mdx
  • docs/reference/platform-support.mdx
  • scripts/checks/direct-credential-env.ts
  • src/lib/actions/inference-set-provider-alias.test.ts
  • src/lib/actions/inference-set.ts
  • src/lib/adapters/http/auth-config.ts
  • src/lib/credentials/store.ts
  • src/lib/domain/installer/provider.test.ts
  • src/lib/domain/installer/provider.ts
  • src/lib/inference/config.test.ts
  • src/lib/inference/config.ts
  • src/lib/inference/model-prompts.test.ts
  • src/lib/inference/model-prompts.ts
  • src/lib/inference/nvidia-featured-models.test.ts
  • src/lib/inference/nvidia-featured-models.ts
  • src/lib/inference/onboard-probes.test.ts
  • src/lib/inference/onboard-probes.ts
  • src/lib/inference/openrouter.ts
  • src/lib/inference/provider-models.test.ts
  • src/lib/inference/provider-models.ts
  • src/lib/onboard.ts
  • src/lib/onboard/credential-navigation.ts
  • src/lib/onboard/inference-providers/types.ts
  • src/lib/onboard/inference-selection-validation.ts
  • src/lib/onboard/nvidia-featured-model-selection.test.ts
  • src/lib/onboard/nvidia-featured-model-selection.ts
  • src/lib/onboard/provider-menu.test.ts
  • src/lib/onboard/provider-menu.ts
  • src/lib/onboard/providers.test.ts
  • src/lib/onboard/providers.ts
  • src/lib/onboard/recovered-provider-reuse.test.ts
  • src/lib/onboard/recovered-provider-reuse.ts
  • src/lib/onboard/setup-nim-flow.test.ts
  • src/lib/onboard/setup-nim-flow.ts
  • src/lib/onboard/setup-nim-selection.ts
  • src/lib/security/credential-env.ts
  • src/lib/security/redact.ts
  • src/lib/validation.test.ts
  • src/lib/validation.ts
  • test/e2e/live/snapshot-credential-scanner.ts
  • test/e2e/support/snapshot-credential-scanner.test.ts
  • test/onboard-openrouter-inference.test.ts
  • test/onboard-resume-provider-recovery.test.ts
  • test/onboard-selection.test.ts
  • test/onboard.test.ts
  • test/support/onboard-selection-test-helpers.ts

Comment thread src/lib/onboard.ts Outdated
Comment thread src/lib/onboard.ts Outdated
Signed-off-by: San Dang <sdang@nvidia.com>

@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)
test/onboard-selection.test.ts (1)

1258-1258: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Menu index shifts are consistent with OpenRouter insertion, but magic-number selections remain fragile.

The numeric answer shifts ("7""8", "3""4") correctly account for OpenRouter's new position 2 in the provider menu, per the documented order at line 3863. However, these embedded scripts still hardcode positional menu indices rather than using the label-based selectRecentMenuOption pattern already adopted in PROCESS_CREDENTIAL_BACK_SCENARIOS (lines 693-705, 710-711). Any future menu reorder will again require touching a dozen call sites across this file.

Also applies to: 1440-1440, 2222-2222, 2301-2301, 2402-2402, 2505-2505, 2608-2608, 3121-3121, 3749-3749, 3863-3868, 3967-3967, 3982-3983

🤖 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 `@test/onboard-selection.test.ts` at line 1258, The test scenarios in
onboard-selection.test.ts still hardcode numeric menu picks, which makes them
brittle when provider order changes. Update the affected scenario setups to use
the same label-based selectRecentMenuOption approach already used in
PROCESS_CREDENTIAL_BACK_SCENARIOS, and replace the positional answers in the
referenced scenario arrays with menu-label selections for the corresponding
prompts. Use the existing scenario builders and menu-selection helpers in this
test file to keep the OpenRouter-related order changes isolated from future
reordering.
🤖 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 `@test/onboard-selection.test.ts`:
- Line 1258: The test scenarios in onboard-selection.test.ts still hardcode
numeric menu picks, which makes them brittle when provider order changes. Update
the affected scenario setups to use the same label-based selectRecentMenuOption
approach already used in PROCESS_CREDENTIAL_BACK_SCENARIOS, and replace the
positional answers in the referenced scenario arrays with menu-label selections
for the corresponding prompts. Use the existing scenario builders and
menu-selection helpers in this test file to keep the OpenRouter-related order
changes isolated from future reordering.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: ee529774-2452-4456-b308-e6157714d8d1

📥 Commits

Reviewing files that changed from the base of the PR and between 343254e and b6581d8.

📒 Files selected for processing (15)
  • ci/test-file-size-budget.json
  • docs/get-started/quickstart.mdx
  • install.sh
  • scripts/checks/direct-credential-env.ts
  • scripts/install.sh
  • src/lib/inference/onboard-probes.ts
  • src/lib/onboard.ts
  • src/lib/onboard/openrouter-selection.ts
  • src/lib/onboard/recovered-provider-reuse.test.ts
  • src/lib/onboard/recovered-provider-reuse.ts
  • src/lib/onboard/setup-nim-selection.ts
  • src/lib/security/credential-env.ts
  • test/onboard-selection-anthropic-retry.test.ts
  • test/onboard-selection.test.ts
  • test/package-contract/onboard/compatible-endpoint-reasoning.test.ts
✅ Files skipped from review due to trivial changes (6)
  • ci/test-file-size-budget.json
  • test/package-contract/onboard/compatible-endpoint-reasoning.test.ts
  • src/lib/security/credential-env.ts
  • docs/get-started/quickstart.mdx
  • scripts/install.sh
  • install.sh
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/inference/onboard-probes.ts
  • src/lib/onboard/setup-nim-selection.ts

sandl99 added 6 commits July 8, 2026 16:09
Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: San Dang <sdang@nvidia.com>

@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: 2

🧹 Nitpick comments (3)
src/lib/onboard/inference-providers/remote.ts (1)

202-208: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Update the stale comment to reflect the new OpenRouter short-circuit.

The comment says "the adapter branch above" (singular) but there are now two adapter short-circuits above (Bedrock and OpenRouter) that both bypass this OpenAI-surface logic.

✏️ Suggested tweak
-  // Bedrock endpoints never reach here — the adapter branch above returns first.
+  // Bedrock and OpenRouter endpoints never reach here — the adapter branches above return first.
🤖 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 202 - 208, Update
the stale explanatory comment in the onboarding logic near the OpenAI-surface
check so it matches the current control flow. The note in remote.ts still says
only the adapter branch above returns first, but the logic now has two
short-circuits before this path: the Bedrock branch and the OpenRouter branch.
Adjust the comment text to mention both bypasses and keep it aligned with the
surrounding onboarding conditions in the relevant remote provider flow.
test/onboard-openrouter-inference.test.ts (1)

15-16: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use ESM import instead of require() for this src module.

openrouter-runtime.ts uses plain named exports, so the require()/opaque-typing workaround documented for dist/lib/onboard doesn't apply here. As per coding guidelines, test/**/*.test.{js,ts}: "Use ESM (import/export) in root-level tests under test/."

♻️ Proposed fix
-const openrouterRuntimeOnboard =
-  require("../src/lib/onboard/openrouter-runtime") as typeof import("../src/lib/onboard/openrouter-runtime.js");
+import * as openrouterRuntimeOnboard from "../src/lib/onboard/openrouter-runtime.js";
🤖 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 `@test/onboard-openrouter-inference.test.ts` around lines 15 - 16, The test is
using a CommonJS require() workaround for a source module that already has named
ESM exports, so switch the openrouterRuntimeOnboard import in the test to a
normal ESM import from openrouter-runtime instead of requiring it. Keep the
symbol name openrouterRuntimeOnboard the same so the rest of the test stays
unchanged, and remove the opaque typeof import pattern that was only needed for
dist/lib/onboard.

Source: Coding guidelines

src/lib/onboard/openrouter-runtime.ts (1)

43-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Link the tracked retirement issue in the TODO.

Other temporary-bridge comments in this codebase reference a tracking issue number (e.g. #6294 in remote.ts). As per path instructions, temporary/bounded compatibility paths should "link the retirement issue or PR in GitHub, and state observable exit criteria."

🤖 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 43 - 46, The
temporary-bridge TODO in openrouter-runtime should reference the tracked
retirement issue so it can be tied to a concrete exit plan. Update the comment
near the OpenShell/OpenRouter onboarding path to include the GitHub issue or PR
number, and keep the existing note about removing the local runtime adapter once
provider-route middleware supports extra outbound headers; use the TODO in
openrouter-runtime as the anchor for this update.

Source: Path instructions

🤖 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-221: Add an explicit timeout to the outbound OpenRouter proxy
request in forwardToOpenRouter so a stalled upstream cannot hang forever. Mirror
the timeout pattern used in probeAdapterHealth by setting a reasonable timeout
on the transport.request call and handling the timeout event by logging
request_failed, destroying the upstream request, and returning a 504-style error
through sendError or res.destroy as appropriate. Keep the fix scoped to
forwardToOpenRouter and the upstreamReq lifecycle.
- Around line 271-291: The adapter is currently started with a bind host that
exposes it on all interfaces, so tighten the network exposure in
startOpenRouterRuntimeAdapterFromEnv and the
OPENROUTER_RUNTIME_ADAPTER_BIND_HOST setting. Update the server bind target to
loopback or add equivalent network isolation so
createOpenRouterRuntimeAdapterServer() is only reachable locally, and keep the
existing adapter_ready logging consistent with the new bind host.

---

Nitpick comments:
In `@src/lib/onboard/inference-providers/remote.ts`:
- Around line 202-208: Update the stale explanatory comment in the onboarding
logic near the OpenAI-surface check so it matches the current control flow. The
note in remote.ts still says only the adapter branch above returns first, but
the logic now has two short-circuits before this path: the Bedrock branch and
the OpenRouter branch. Adjust the comment text to mention both bypasses and keep
it aligned with the surrounding onboarding conditions in the relevant remote
provider flow.

In `@src/lib/onboard/openrouter-runtime.ts`:
- Around line 43-46: The temporary-bridge TODO in openrouter-runtime should
reference the tracked retirement issue so it can be tied to a concrete exit
plan. Update the comment near the OpenShell/OpenRouter onboarding path to
include the GitHub issue or PR number, and keep the existing note about removing
the local runtime adapter once provider-route middleware supports extra outbound
headers; use the TODO in openrouter-runtime as the anchor for this update.

In `@test/onboard-openrouter-inference.test.ts`:
- Around line 15-16: The test is using a CommonJS require() workaround for a
source module that already has named ESM exports, so switch the
openrouterRuntimeOnboard import in the test to a normal ESM import from
openrouter-runtime instead of requiring it. Keep the symbol name
openrouterRuntimeOnboard the same so the rest of the test stays unchanged, and
remove the opaque typeof import pattern that was only needed for
dist/lib/onboard.
🪄 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: 15e02baf-3dab-4c92-be58-514dc9eb1298

📥 Commits

Reviewing files that changed from the base of the PR and between 14d5b5b and ea83be8.

📒 Files selected for processing (18)
  • ci/env-var-doc-allowlist.json
  • ci/platform-matrix.json
  • docs/inference/inference-options.mdx
  • docs/reference/platform-support.mdx
  • src/lib/core/ports.test.ts
  • src/lib/core/ports.ts
  • src/lib/inference/openrouter-runtime-adapter.test.ts
  • src/lib/inference/openrouter-runtime-adapter.ts
  • src/lib/inference/openrouter.ts
  • src/lib/onboard.ts
  • src/lib/onboard/gateway-recovery.ts
  • src/lib/onboard/inference-providers/remote-openai-surface.test.ts
  • src/lib/onboard/inference-providers/remote.ts
  • src/lib/onboard/inference-providers/types.ts
  • src/lib/onboard/openrouter-runtime.ts
  • src/lib/onboard/providers.test.ts
  • src/lib/onboard/setup-inference.ts
  • test/onboard-openrouter-inference.test.ts
✅ Files skipped from review due to trivial changes (2)
  • docs/reference/platform-support.mdx
  • ci/platform-matrix.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/lib/onboard/providers.test.ts
  • docs/inference/inference-options.mdx
  • src/lib/onboard.ts

Comment thread src/lib/inference/openrouter-runtime-adapter.ts Outdated
Comment thread src/lib/inference/openrouter-runtime-adapter.ts Outdated
Signed-off-by: San Dang <sdang@nvidia.com>

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

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.test.ts (1)

1-192: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Link the retirement issue/PR for this temporary adapter The exit criteria are already in the TODO, but the migration tracker link is still missing from src/lib/inference/openrouter-runtime-adapter.ts.

🤖 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 1 - 192,
The temporary adapter TODO is missing the migration tracker reference, so update
the TODO comment in openrouter-runtime-adapter.ts to include the retirement
issue/PR link alongside the existing exit criteria. Locate the adapter setup
around createOpenRouterRuntimeAdapterServer and the related health/runtime
comments, then add the tracker URL without changing behavior or test
expectations.

Source: Path instructions

🧹 Nitpick comments (1)
src/lib/inference/openrouter-runtime-adapter.test.ts (1)

155-176: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Missing x-openrouter-title assertion for models passthrough.

The chat-completions test verifies both http-referer and x-openrouter-title attribution headers are forwarded, but this models-endpoint test only checks authorization and http-referer (Lines 173-174). Since the PR objective requires both attribution headers on all API requests, consider asserting x-openrouter-title here too for consistent coverage.

🧪 Suggested addition
     expect(upstream.captured[0].headers.authorization).toBe(OPENROUTER_TEST_AUTHORIZATION);
     expect(upstream.captured[0].headers["http-referer"]).toBe("https://www.nvidia.com/nemoclaw/");
+    expect(upstream.captured[0].headers["x-openrouter-title"]).toBe("NVIDIA NemoClaw");
   });
🤖 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 155 - 176,
The models passthrough test in openrouter-runtime-adapter is missing coverage
for the attribution header forwarding expected on all requests. Update the test
around createOpenRouterRuntimeAdapterServer, fetch, and upstream.captured
assertions to also verify that x-openrouter-title is preserved alongside
authorization and http-referer, matching the chat-completions test’s header
checks.
🤖 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.

Outside diff comments:
In `@src/lib/inference/openrouter-runtime-adapter.test.ts`:
- Around line 1-192: The temporary adapter TODO is missing the migration tracker
reference, so update the TODO comment in openrouter-runtime-adapter.ts to
include the retirement issue/PR link alongside the existing exit criteria.
Locate the adapter setup around createOpenRouterRuntimeAdapterServer and the
related health/runtime comments, then add the tracker URL without changing
behavior or test expectations.

---

Nitpick comments:
In `@src/lib/inference/openrouter-runtime-adapter.test.ts`:
- Around line 155-176: The models passthrough test in openrouter-runtime-adapter
is missing coverage for the attribution header forwarding expected on all
requests. Update the test around createOpenRouterRuntimeAdapterServer, fetch,
and upstream.captured assertions to also verify that x-openrouter-title is
preserved alongside authorization and http-referer, matching the
chat-completions test’s header checks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 5fb40271-9e66-43af-8553-58de6842ebcd

📥 Commits

Reviewing files that changed from the base of the PR and between ea83be8 and fe9c8e7.

📒 Files selected for processing (5)
  • ci/env-var-doc-allowlist.json
  • src/lib/inference/openrouter-runtime-adapter.test.ts
  • src/lib/inference/openrouter-runtime-adapter.ts
  • src/lib/onboard/openrouter-runtime.ts
  • test/onboard-openrouter-inference.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • test/onboard-openrouter-inference.test.ts
  • ci/env-var-doc-allowlist.json
  • src/lib/inference/openrouter-runtime-adapter.ts
  • src/lib/onboard/openrouter-runtime.ts

Comment thread src/lib/inference/openrouter-runtime-adapter.ts Fixed
ericksoa added a commit that referenced this pull request Jul 8, 2026
<!-- markdownlint-disable MD041 -->
## Summary
Removes `moonshotai/kimi-k2.6` from NVIDIA Endpoints onboarding because
its Chat Completions route now returns HTTP 404 even though NVIDIA's
public featured feed and authenticated `/v1/models` catalog still
advertise it. This PR does not add K2.7 or another replacement; a new
Kimi model can be added after its production model ID and runtime route
are live.

## Changes
- Remove Kimi K2.6 from the bundled NVIDIA Endpoints fallback and filter
the stale live-catalog entry.
- Preserve the independent Hermes Provider K2.6 choice and
existing/custom-route OpenClaw compatibility.
- Keep Kimi compatibility coverage hermetic while the public NVIDIA K2.6
route is unavailable.
- Update onboarding and capability documentation to distinguish catalog
metadata from runtime availability.
- Update picker, catalog, provider-boundary, documentation, and workflow
coverage for the retired choice.

## Runtime Evidence
- Public featured feed: still advertises `moonshotai/kimi-k2.6`.
- Authenticated `https://integrate.api.nvidia.com/v1/models`: still
advertises `moonshotai/kimi-k2.6` and no other Kimi model.
- Actual `moonshotai/kimi-k2.6` Chat Completions request: HTTP 404.
- Exact-main Kimi job: [run 28953873907 / job
85907646487](https://github.com/NVIDIA/NemoClaw/actions/runs/28953873907/job/85907646487)
failed onboarding with `Chat Completions API: HTTP 404`.
- `moonshotai/kimi-k2.7-code` is absent from `/v1/models` and its
candidate route also returns HTTP 404, so replacement support remains
out of scope.

## 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 sample changes)

## Quality Gates
- [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)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification:
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Advisor Follow-up Rationale
- **Connect reconciliation (`PRA-1` / `PRA-7`):** This PR changes future
NVIDIA Endpoints choices only; it deliberately preserves existing
sandbox and custom-route compatibility and does not alter reconciliation
semantics. Generic model divergence is covered in
`src/lib/inference/config.test.ts`, and caller-level warning plus
realignment is covered in
`src/lib/actions/sandbox/connect-route-lifecycle.test.ts`.
- **Manual `Other...` entry (`PRA-2`):** NVIDIA `/v1/models` still
advertises K2.6, so the generic catalog validator cannot truthfully
reject that ID. The retired-model policy removes K2.6 from advertised
and fallback choices while retaining the generic manual path. Actual
Kimi availability is checked by the model-aware Chat Completions probe;
the linked exact-main run demonstrates the resulting HTTP 404 before
successful onboarding.
- **Open PR overlap (`PRA-3`):** #6461 is still open and this head is
currently mergeable against live `main`. If #6461 lands first, normal
merge-order conflict resolution and exact-head revalidation apply.
- **Deny-list authority (`PRA-5`):**
`src/lib/inference/nvidia-featured-models.ts` already documents why
repository retirement policy overrides stale catalog metadata while
preserving the independent Hermes Provider catalog.
- **Hermes Provider warning:** Hermes Provider is an independent,
pre-existing route and model catalog that this NVIDIA Endpoints
retirement intentionally leaves unchanged. The advisor identified no
evidence that its K2.6 route is unavailable; adding a new provider-level
runtime validation contract belongs in separate provider work.
- **Numeric picker tests:** The production prompt accepts numeric menu
input, so the tests intentionally exercise that user contract. Each
affected test immediately asserts the exact selected model and probe
target, preventing an index change from silently validating the wrong
model.
- **Runtime test follow-ups:** The exact-head Kimi E2E proves
secret-free mock routing plus the split tool trajectory; existing health
tests prove model-aware Chat Completions failures are unhealthy. The
linked exact-main public run supplies the stale-catalog-success /
Chat-Completions-404 negative-path evidence without adding live-secret
dependency to this PR.
- **Runtime follow-up:** Exact-head E2E run
[28957983313](https://github.com/NVIDIA/NemoClaw/actions/runs/28957983313)
passes `inference-routing`, `cloud-onboard`, and the repaired hermetic
`kimi-inference-compat` lane. The public negative-path evidence remains
the linked exact-main HTTP 404 run.

## Verification
- [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
- [x] Targeted behavior tests pass for the current change set: 164
focused config, model-prompt, featured-catalog, docs-contract, and
onboarding tests
- [x] E2E workflow boundary tests pass: 17 tests
- [x] Exact-head advisor-required E2E run
[28957983313](https://github.com/NVIDIA/NemoClaw/actions/runs/28957983313)
passes `inference-routing`, `cloud-onboard`, and `kimi-inference-compat`
- [x] `npm run typecheck:cli`, `npm run source-shape:check`, `npm run
test-size:check`, and `npm run validate:configs` pass
- [x] Applicable broad gate passed — all exact-head required contexts
and the standard matrix are green
- [ ] Quality Gates section completed with required justifications or
waivers — sensitive-path review remains on the normal approval path
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings — 0 errors and 2
pre-existing warnings
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
- [ ] New doc pages include SPDX header and frontmatter — no new pages

---
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Updated model availability filtering so retired/unavailable
compatibility options (including Kimi K2.6) no longer appear in
onboarding prompts, improving default selection reliability.
* Adjusted the live compatibility testing setup and mode-dependent
classification to run consistently in mock mode.
* Improved mock streaming behavior so tool calls are emitted as separate
`exec` calls with distinct arguments.

* **Documentation**
* Refreshed inference onboarding/model task-fit guidance to clarify that
runtime route validation determines current availability.
* Updated curated model lists and platform reference links to match the
latest availability rules.

* **Tests / CI**
* Updated and expanded coverage to reflect the revised availability and
selection behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
@sandl99

sandl99 commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator Author

Follow-up on the latest Nemotron Ultra advisor comment for a4097a8:

  • PRA-4 / PRA-5: current code no longer uses the generic NVIDIA featured catalog for OpenRouter. OPENROUTER_FEATURED_MODELS_URL points to https://assets.ngc.nvidia.com/products/api-catalog/featured-models-openrouter.json, and setup-nim-flow.ts passes retiredModelIds: [] so OpenRouter does not inherit the NVIDIA Endpoints retirement filter. Covered by src/lib/inference/nvidia-featured-models.test.ts.
  • Runtime adapter CodeRabbit comments are stale for the current head: src/lib/inference/openrouter-runtime-adapter.ts is absent in this branch.
  • The remaining runtime E2E items are useful future coverage, but the GPT-5.5 advisor classifies them as non-blocking test follow-ups, and there is no live OpenRouter-specific E2E target/key path in this PR.
  • Local verification run before push: npx vitest run --project cli src/lib/inference/nvidia-featured-models.test.ts src/lib/inference/onboard-probes.test.ts src/lib/onboard/setup-nim-flow.test.ts; npx vitest run --project integration test/onboard-openrouter-inference.test.ts; npx vitest run --project cli src/lib/onboard/nvidia-featured-model-selection.test.ts src/lib/onboard/providers.test.ts src/lib/onboard/inference-providers/remote-openai-surface.test.ts; npm run typecheck:cli; npm run test-size:check; npm run docs.

All required PR checks are green after the push.

@sandl99 sandl99 added the v0.0.79 Release target label Jul 9, 2026
@sandl99
sandl99 requested a review from cv July 9, 2026 03:43
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ✅ All requested jobs passed

Run: 28992839983
Workflow ref: feat/openrouter-onboarding
Requested targets: (default — all supported)
Requested jobs: cloud-onboard,onboard-resume,onboard-repair,inference-routing,cloud-inference,openclaw-inference-switch,credential-sanitization,credential-migration,snapshot-commands
Summary: 9 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
cloud-inference ✅ success
cloud-onboard ✅ success
credential-migration ✅ success
credential-sanitization ✅ success
inference-routing ✅ success
onboard-repair ✅ success
onboard-resume ✅ success
openclaw-inference-switch ✅ success
snapshot-commands ✅ success

@cv
cv merged commit b1e35df into main Jul 9, 2026
55 of 59 checks passed
@cv
cv deleted the feat/openrouter-onboarding branch July 9, 2026 08:48
@jyaunches jyaunches mentioned this pull request Jul 9, 2026
21 tasks
cv pushed a commit that referenced this pull request Jul 9, 2026
<!-- markdownlint-disable MD041 -->
## Summary
Adds the pre-tag v0.0.79 release notes entry to
`docs/about/release-notes.mdx` so the release plan can be generated
after docs merge.
The entry summarizes the merged v0.0.79 release train across inference,
diagnostics, runtime hardening, policies, onboarding recovery, and
release validation.

## Changes
- Added the v0.0.79 release notes section with linked follow-up
documentation for OpenRouter onboarding, managed vLLM changes,
completion and logging, Deep Agents runtime limits, policy updates,
onboarding recovery, and release validation.
- Source summary:
- #6461 -> `docs/about/release-notes.mdx`: Documents OpenRouter
onboarding support and links to inference/provider references.
- #6271 and #6272 -> `docs/about/release-notes.mdx`: Documents shell
completion and structured logging highlights.
- #6465, #6539, #6570, and #6528 -> `docs/about/release-notes.mdx`:
Documents status route-drift, orphaned sandbox, gateway cleanup, and DGX
Spark express-install diagnostics.
- #6523, #6551, #6484, #6488, #6324, and #6542 ->
`docs/about/release-notes.mdx`: Documents managed vLLM, Qwen3.6 tool
parser, compaction, and timeout/readiness improvements.
- #6559, #6538, #6560, #6568, #6552, #6567, and #6587 ->
`docs/about/release-notes.mdx`: Documents runtime, credential, proxy,
PID namespace, TOML, and provider-state hardening.
- #6541, #5415, #6246, #6496, and #6573 ->
`docs/about/release-notes.mdx`: Documents GitHub policy, Gmail policy,
MCP allowlist, WhatsApp, and messaging-variant updates.
- #6253, #6572, #6444, #6536, and #5860 ->
`docs/about/release-notes.mdx`: Documents onboarding resume and
create-step recovery improvements.
- #6508, #6527, #5506, #6588, #6446, #6447, #6582, #6296, #6367, #6397,
and #6505 -> `docs/about/release-notes.mdx`: Documents docs,
release-risk, and E2E validation updates.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [x] 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. -->
- [ ] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [x] Tests not applicable — justification: Release-note prose only.
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification:
- [ ] 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: Tests
not applicable, release-note prose only.
- [ ] 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)
- [x] 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)

Docs validation note: `npm run docs:check-agent-variants && npm run
docs:check-routes && git diff --check` passed. Full `npm run docs` is
currently blocked before Fern validation because the pinned
`fern-api@5.65.2` package is unavailable from npm (`ETARGET No matching
version found`).

---
<!-- 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: Julie Yaunches <jyaunches@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Added release notes for v0.0.79 with a new summary of recent
improvements, including onboarding and inference options, operator/CLI
diagnostics, sandbox recovery hardening, runtime limits, network policy
behavior, and release validation updates.
  * Added updated references and links for the latest release.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
<!-- markdownlint-disable MD041 -->
## Summary
Removes `moonshotai/kimi-k2.6` from NVIDIA Endpoints onboarding because
its Chat Completions route now returns HTTP 404 even though NVIDIA's
public featured feed and authenticated `/v1/models` catalog still
advertise it. This PR does not add K2.7 or another replacement; a new
Kimi model can be added after its production model ID and runtime route
are live.

## Changes
- Remove Kimi K2.6 from the bundled NVIDIA Endpoints fallback and filter
the stale live-catalog entry.
- Preserve the independent Hermes Provider K2.6 choice and
existing/custom-route OpenClaw compatibility.
- Keep Kimi compatibility coverage hermetic while the public NVIDIA K2.6
route is unavailable.
- Update onboarding and capability documentation to distinguish catalog
metadata from runtime availability.
- Update picker, catalog, provider-boundary, documentation, and workflow
coverage for the retired choice.

## Runtime Evidence
- Public featured feed: still advertises `moonshotai/kimi-k2.6`.
- Authenticated `https://integrate.api.nvidia.com/v1/models`: still
advertises `moonshotai/kimi-k2.6` and no other Kimi model.
- Actual `moonshotai/kimi-k2.6` Chat Completions request: HTTP 404.
- Exact-main Kimi job: [run 28953873907 / job
85907646487](https://github.com/NVIDIA/NemoClaw/actions/runs/28953873907/job/85907646487)
failed onboarding with `Chat Completions API: HTTP 404`.
- `moonshotai/kimi-k2.7-code` is absent from `/v1/models` and its
candidate route also returns HTTP 404, so replacement support remains
out of scope.

## 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 sample changes)

## Quality Gates
- [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)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification:
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Advisor Follow-up Rationale
- **Connect reconciliation (`PRA-1` / `PRA-7`):** This PR changes future
NVIDIA Endpoints choices only; it deliberately preserves existing
sandbox and custom-route compatibility and does not alter reconciliation
semantics. Generic model divergence is covered in
`src/lib/inference/config.test.ts`, and caller-level warning plus
realignment is covered in
`src/lib/actions/sandbox/connect-route-lifecycle.test.ts`.
- **Manual `Other...` entry (`PRA-2`):** NVIDIA `/v1/models` still
advertises K2.6, so the generic catalog validator cannot truthfully
reject that ID. The retired-model policy removes K2.6 from advertised
and fallback choices while retaining the generic manual path. Actual
Kimi availability is checked by the model-aware Chat Completions probe;
the linked exact-main run demonstrates the resulting HTTP 404 before
successful onboarding.
- **Open PR overlap (`PRA-3`):** NVIDIA#6461 is still open and this head is
currently mergeable against live `main`. If NVIDIA#6461 lands first, normal
merge-order conflict resolution and exact-head revalidation apply.
- **Deny-list authority (`PRA-5`):**
`src/lib/inference/nvidia-featured-models.ts` already documents why
repository retirement policy overrides stale catalog metadata while
preserving the independent Hermes Provider catalog.
- **Hermes Provider warning:** Hermes Provider is an independent,
pre-existing route and model catalog that this NVIDIA Endpoints
retirement intentionally leaves unchanged. The advisor identified no
evidence that its K2.6 route is unavailable; adding a new provider-level
runtime validation contract belongs in separate provider work.
- **Numeric picker tests:** The production prompt accepts numeric menu
input, so the tests intentionally exercise that user contract. Each
affected test immediately asserts the exact selected model and probe
target, preventing an index change from silently validating the wrong
model.
- **Runtime test follow-ups:** The exact-head Kimi E2E proves
secret-free mock routing plus the split tool trajectory; existing health
tests prove model-aware Chat Completions failures are unhealthy. The
linked exact-main public run supplies the stale-catalog-success /
Chat-Completions-404 negative-path evidence without adding live-secret
dependency to this PR.
- **Runtime follow-up:** Exact-head E2E run
[28957983313](https://github.com/NVIDIA/NemoClaw/actions/runs/28957983313)
passes `inference-routing`, `cloud-onboard`, and the repaired hermetic
`kimi-inference-compat` lane. The public negative-path evidence remains
the linked exact-main HTTP 404 run.

## Verification
- [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
- [x] Targeted behavior tests pass for the current change set: 164
focused config, model-prompt, featured-catalog, docs-contract, and
onboarding tests
- [x] E2E workflow boundary tests pass: 17 tests
- [x] Exact-head advisor-required E2E run
[28957983313](https://github.com/NVIDIA/NemoClaw/actions/runs/28957983313)
passes `inference-routing`, `cloud-onboard`, and `kimi-inference-compat`
- [x] `npm run typecheck:cli`, `npm run source-shape:check`, `npm run
test-size:check`, and `npm run validate:configs` pass
- [x] Applicable broad gate passed — all exact-head required contexts
and the standard matrix are green
- [ ] Quality Gates section completed with required justifications or
waivers — sensitive-path review remains on the normal approval path
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings — 0 errors and 2
pre-existing warnings
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
- [ ] New doc pages include SPDX header and frontmatter — no new pages

---
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Updated model availability filtering so retired/unavailable
compatibility options (including Kimi K2.6) no longer appear in
onboarding prompts, improving default selection reliability.
* Adjusted the live compatibility testing setup and mode-dependent
classification to run consistently in mock mode.
* Improved mock streaming behavior so tool calls are emitted as separate
`exec` calls with distinct arguments.

* **Documentation**
* Refreshed inference onboarding/model task-fit guidance to clarify that
runtime route validation determines current availability.
* Updated curated model lists and platform reference links to match the
latest availability rules.

* **Tests / CI**
* Updated and expanded coverage to reflect the revised availability and
selection behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
<!-- markdownlint-disable MD041 -->
## Summary

Adds first-class OpenRouter onboarding support for OpenClaw, Hermes, and
LangChain Deep Agents Code. OpenRouter is exposed as its own provider
choice while configuring OpenShell through the OpenAI-compatible runtime
path with the OpenRouter base URL and credential environment.

This PR is a partial implementation of NVIDIA#5826. OpenRouter attribution
headers are applied to onboarding health checks, catalog probes, and
model-validation probes only. Runtime sandbox traffic still uses
OpenShell's `openai` provider profile with
`OPENAI_BASE_URL=https://openrouter.ai/api/v1`; runtime extra outbound
headers remain unsupported until OpenShell provides native/static-header
support.

## Related Issue

Partially addresses NVIDIA#5826.

## Changes

- Adds OpenRouter provider/menu/config handling, including
`OPENROUTER_API_KEY`, `openrouter-api`, and
`https://openrouter.ai/api/v1`.
- Loads a temporary OpenRouter catalog through the featured-model
catalog mechanism and applies OpenRouter-specific host-side validation
headers for catalog/model probes and onboarding health checks.
- Updates inference validation, credential redaction/scanning
allowlists, provider reuse, setup flow, and docs/platform tables for
OpenRouter.
- Adds focused CLI and integration coverage for OpenRouter onboarding
and keeps legacy test files within the size budget.

## 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

- [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: self-reviewed
credential handling; OpenRouter secrets are passed via environment,
redacted/scanned, and covered by targeted tests. Runtime OpenRouter
extra headers are intentionally unsupported in this PR outside
onboarding health checks and validation probes.
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification

- [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 integration
test/onboard-openrouter-inference.test.ts`; `npx vitest run --project
cli src/lib/onboard/providers.test.ts
src/lib/onboard/inference-providers/remote-openai-surface.test.ts
src/lib/core/ports.test.ts`; `npm run typecheck:cli`; `npm run docs`;
`git diff --cached --check`.
- [ ] 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) — `npm
run docs` passed; Fern reported 2 existing warnings.
- [x] 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)

---
Signed-off-by: San Dang <sdang@nvidia.com>

---------

Signed-off-by: San Dang <sdang@nvidia.com>
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
<!-- markdownlint-disable MD041 -->
## Summary
Adds the pre-tag v0.0.79 release notes entry to
`docs/about/release-notes.mdx` so the release plan can be generated
after docs merge.
The entry summarizes the merged v0.0.79 release train across inference,
diagnostics, runtime hardening, policies, onboarding recovery, and
release validation.

## Changes
- Added the v0.0.79 release notes section with linked follow-up
documentation for OpenRouter onboarding, managed vLLM changes,
completion and logging, Deep Agents runtime limits, policy updates,
onboarding recovery, and release validation.
- Source summary:
- NVIDIA#6461 -> `docs/about/release-notes.mdx`: Documents OpenRouter
onboarding support and links to inference/provider references.
- NVIDIA#6271 and NVIDIA#6272 -> `docs/about/release-notes.mdx`: Documents shell
completion and structured logging highlights.
- NVIDIA#6465, NVIDIA#6539, NVIDIA#6570, and NVIDIA#6528 -> `docs/about/release-notes.mdx`:
Documents status route-drift, orphaned sandbox, gateway cleanup, and DGX
Spark express-install diagnostics.
- NVIDIA#6523, NVIDIA#6551, NVIDIA#6484, NVIDIA#6488, NVIDIA#6324, and NVIDIA#6542 ->
`docs/about/release-notes.mdx`: Documents managed vLLM, Qwen3.6 tool
parser, compaction, and timeout/readiness improvements.
- NVIDIA#6559, NVIDIA#6538, NVIDIA#6560, NVIDIA#6568, NVIDIA#6552, NVIDIA#6567, and NVIDIA#6587 ->
`docs/about/release-notes.mdx`: Documents runtime, credential, proxy,
PID namespace, TOML, and provider-state hardening.
- NVIDIA#6541, NVIDIA#5415, NVIDIA#6246, NVIDIA#6496, and NVIDIA#6573 ->
`docs/about/release-notes.mdx`: Documents GitHub policy, Gmail policy,
MCP allowlist, WhatsApp, and messaging-variant updates.
- NVIDIA#6253, NVIDIA#6572, NVIDIA#6444, NVIDIA#6536, and NVIDIA#5860 ->
`docs/about/release-notes.mdx`: Documents onboarding resume and
create-step recovery improvements.
- NVIDIA#6508, NVIDIA#6527, NVIDIA#5506, NVIDIA#6588, NVIDIA#6446, NVIDIA#6447, NVIDIA#6582, NVIDIA#6296, NVIDIA#6367, NVIDIA#6397,
and NVIDIA#6505 -> `docs/about/release-notes.mdx`: Documents docs,
release-risk, and E2E validation updates.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [x] 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. -->
- [ ] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [x] Tests not applicable — justification: Release-note prose only.
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification:
- [ ] 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: Tests
not applicable, release-note prose only.
- [ ] 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)
- [x] 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)

Docs validation note: `npm run docs:check-agent-variants && npm run
docs:check-routes && git diff --check` passed. Full `npm run docs` is
currently blocked before Fern validation because the pinned
`fern-api@5.65.2` package is unavailable from npm (`ETARGET No matching
version found`).

---
<!-- 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: Julie Yaunches <jyaunches@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Added release notes for v0.0.79 with a new summary of recent
improvements, including onboarding and inference options, operator/CLI
diagnostics, sandbox recovery hardening, runtime limits, network policy
behavior, and release validation updates.
  * Added updated references and links for the latest release.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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 area: providers Inference provider integrations and provider behavior enhancement New capability or improvement request v0.0.79 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants