Skip to content

fix(inference): honor compatible-endpoint max_model_len for Hermes context (#6177) - #6293

Merged
cv merged 54 commits into
mainfrom
fix/6177-compatible-endpoint-context
Jul 8, 2026
Merged

fix(inference): honor compatible-endpoint max_model_len for Hermes context (#6177)#6293
cv merged 54 commits into
mainfrom
fix/6177-compatible-endpoint-context

Conversation

@yimoj

@yimoj yimoj commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Compatible-endpoint / custom onboarding never probed the endpoint's runtime context window, and the Hermes image/config carried no context setting. A self-hosted vLLM endpoint serving a NemotronH model (max_model_len=65536) therefore fell back to a ~4K architecture default, and Hermes failed with Error: Context length exceeded (4,181 tokens). Cannot compress further. This teaches onboarding to probe the endpoint's max_model_len (or honor an explicit NEMOCLAW_CONTEXT_WINDOW) and propagate the window into the generated Hermes config.

Related Issue

Fixes #6177

Changes

  • New src/lib/inference/compatible-endpoint-context.ts: probes the configured OpenAI-compatible endpoint's /v1/models for max_model_len and sets NEMOCLAW_CONTEXT_WINDOW when the user has not set one. Wired into the custom-endpoint validation-success path in setup-nim-selection.ts (keeps src/lib/onboard.ts net-zero for the growth guardrail).
  • An explicit NEMOCLAW_CONTEXT_WINDOW always wins and is never downgraded.
  • Strict model matching: a shared multi-model gateway with no exact /v1/models id match never bakes an unrelated model's window (local vLLM keeps its single-served-model fallback).
  • Auto-detected values are cleared before re-selecting a provider (machine/handlers/provider-inference.ts), so retrying away to another provider cannot leave endpoint A's probed window in the environment where dockerfile-patch would treat it as a user override.
  • Defensive filtering of non-object /v1/models entries so an arbitrary endpoint returning {"data":[null]} cannot crash onboarding.
  • Hermes propagation: declares ARG/ENV NEMOCLAW_CONTEXT_WINDOW (empty → auto-detect) in agents/hermes/Dockerfile, reads it in build-env.ts, and writes the resolved window as model.context_length in the generated config.yaml. Hermes reads only context_length (context_window is silently ignored upstream); the model-block key is its highest-priority override, above /v1/models discovery and its built-in NemotronH metadata.
  • Docs: documents the compatible-endpoint context probe and the Hermes context_length behavior in switch-inference-providers.mdx.

Type of Change

  • Code change with doc updates
  • Code change (feature, bug fix, or refactor)
  • 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-review + codex review --uncommitted clean ("No discrete correctness issues"); credential handling reuses the existing curl auth-config (key in a 0600 tmpfile, never argv); endpoint URL is the already-validated/normalized onboarding value.
  • 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: npx vitest run for compatible-endpoint-context, vllm-runtime-context, dockerfile-patch-hermes-context, provider-inference, compatible-endpoint-context-probe, generate-hermes-config, hermes-gateway-wrapper → all pass (139+ tests); npm run typecheck:cli clean.
  • 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)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

E2E evidence — real worktree CLI

Verified end-to-end with the worktree CLI (node ./bin/nemoclaw.js) driving a real onboard against a fake OpenAI-compatible endpoint (bound to 127.0.0.1, serving /v1/models with max_model_len: 65536). Docker was available on the host, so the full Hermes sandbox image was built and the sandbox created.

Command (reporter's flow, fake endpoint substituted for the DGX Spark vLLM server):

NEMOCLAW_PROVIDER=custom \
NEMOCLAW_ENDPOINT_URL=http://127.0.0.1:$PORT/v1 \
NEMOCLAW_MODEL=nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4 \
COMPATIBLE_API_KEY=dummy \
node ./bin/nemoclaw.js onboard --non-interactive --name ctx6177 --agent hermes --no-sandbox-gpu

Onboard transcript (post-fix):

  [3/8] Configuring inference provider
  [non-interactive] Provider: custom
  Chat Completions API available — Hermes will use openai-completions.
  ✓ Using endpoint max_model_len: 65536 tokens
  Using Other OpenAI-compatible endpoint with model: nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4
  ...
  ✓ Sandbox 'ctx6177-3482376' created
### onboard exit: 0

Generated Hermes config.yaml in the built sandbox image (post-fix):

model:
  default: nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4
  provider: custom
  base_url: "https://inference.local/v1"
  api_key: sk-OPENSHELL-PROXY-REWRITE
  context_length: 65536

Pre-fix contrast (same image, NEMOCLAW_CONTEXT_WINDOW unset → the behavior before this PR): the model: block has no context_length, so Hermes falls back to its NemotronH metadata default (~4K) — the reported failure:

model:
  default: nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4
  provider: custom
  base_url: "https://inference.local/v1"
  api_key: sk-OPENSHELL-PROXY-REWRITE
# (no context_length)

The only part of the reporter's setup not reproducible here is the DGX Spark GPU serving the real 120B NemotronH weights and a live hermes chat; the fake endpoint reproduces the exact /v1/models max_model_len signal the fix consumes. Supporting unit/integration tests (real curl vs a live server, real Hermes config generator, real Hermes Dockerfile patch) are listed above.


Signed-off-by: Yimo Jiang yimoj@nvidia.com

Summary by CodeRabbit

  • New Features
    • Hermes now supports NEMOCLAW_CONTEXT_WINDOW, overriding auto-detection and emitting the resolved value as config.yaml’s context_length.
    • OpenAI-compatible endpoint onboarding can auto-derive context length from /v1/models (max_model_len) when NEMOCLAW_CONTEXT_WINDOW is unset.
  • Bug Fixes
    • Prevents previously auto-detected context windows from carrying over across provider re-selection.
    • Adds safer, more accurate /v1/models probing with SSRF protection for private/internal targets.
  • Documentation
    • Updated NEMOCLAW_CONTEXT_WINDOW guidance and override/probe priority rules.
  • Tests
    • Expanded unit, integration, and e2e coverage for overrides, probing, and SSRF behavior.

…ntext (#6177)

Compatible-endpoint / custom onboarding never probed the endpoint's runtime
context window, and the Hermes image/config carried no context setting, so
NemotronH models on a self-hosted vLLM endpoint fell back to a ~4K
architecture default and Hermes errored with "Context length exceeded".

- Probe the configured OpenAI-compatible endpoint's /v1/models for
  max_model_len and set NEMOCLAW_CONTEXT_WINDOW when the user has not set one;
  an explicit override always wins and is never downgraded.
- Use strict model matching so a shared multi-model gateway never bakes an
  unrelated model's window; local vLLM keeps its single-model fallback.
- Clear an auto-detected value when re-selecting away from the endpoint so it
  is never mistaken for a user override by dockerfile-patch.
- Declare ARG/ENV NEMOCLAW_CONTEXT_WINDOW in the Hermes Dockerfile and write
  the resolved window as model.context_length in the generated config so it
  overrides Hermes' built-in metadata (Hermes ignores context_window).

Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
@coderabbitai

coderabbitai Bot commented Jul 6, 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 compatible-endpoint context probing and Hermes context-window plumbing so detected windows are written into generated config, propagated through onboarding, and left unset when auto-detection should remain in effect.

Changes

Context window detection and propagation

Layer / File(s) Summary
vLLM strict model matching resolver
src/lib/inference/vllm-runtime-context.ts, src/lib/inference/vllm-runtime-context.test.ts
Adds strictModelMatch to resolveVllmContextWindowFromModels, filters non-object entries, avoids guessing on ambiguous multi-model responses, and adds tests for invalid payloads and strict matching.
Compatible-endpoint context probe module
src/lib/inference/compatible-endpoint-context.ts, src/lib/inference/compatible-endpoint-context.test.ts, test/compatible-endpoint-context-probe.test.ts
Implements endpoint probing, auto-detected state tracking, stale-value clearing, and applyCompatibleEndpointContextWindow, with unit and integration coverage for probing, overrides, re-probing, and malformed responses.
Onboarding wiring and probe guards
src/lib/onboard/setup-nim-selection.ts, src/lib/onboard/machine/handlers/provider-inference.ts, src/lib/onboard/machine/handlers/provider-inference.test-support.ts, src/lib/onboard/machine/handlers/provider-inference.test.ts, src/lib/onboard/machine/handlers/provider-inference-context-window.test.ts, test/e2e/fixtures/fake-openai-compatible.ts, test/e2e/lib/fake-openai-compatible-api.mts, src/lib/inference/onboard-probes.ts, src/lib/onboard/dockerfile-patch-hermes-context.test.ts, src/lib/private-networks.ts, src/lib/inference/onboard-probes.test.ts
Wires the compatible-endpoint context update into custom remote model validation and clears stale auto-detected values before provider re-selection, while the fake server, probe guard, and patch tests support max_model_len, auth, loopback, and private-address scenarios.
Hermes Dockerfile and config window
agents/hermes/Dockerfile, agents/hermes/config/build-env.ts, agents/hermes/config/hermes-config.ts, docs/inference/switch-inference-providers.mdx, test/generate-hermes-config.test.ts, test/hermes-gateway-wrapper.test.ts
Adds NEMOCLAW_CONTEXT_WINDOW build arg/env plumbing, parses it into Hermes build settings, maps it to model.context_length, and updates docs and config-generation tests.

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

Possibly related PRs

  • NVIDIA/NemoClaw#2108: Updates the same NEMOCLAW_CONTEXT_WINDOW docs in docs/inference/switch-inference-providers.mdx.
  • NVIDIA/NemoClaw#2995: Covers sandbox-internal hostname probe skipping similar to the non-host-probeable endpoint handling here.

Suggested labels: provider: vllm, bug-fix

Suggested reviewers: cv

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: using compatible-endpoint max_model_len for Hermes context.
Linked Issues check ✅ Passed The PR implements compatible-endpoint probing, explicit overrides, strict model matching, and propagation into Hermes config as requested by #6177.
Out of Scope Changes check ✅ Passed No clearly unrelated code changes are apparent; the extra tests, docs, and SSRF guards support the same compatible-endpoint context-window fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/6177-compatible-endpoint-context

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

@github-code-quality

github-code-quality Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in the fix/6177-compatible-... branch is 96%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main fix/6177-compatible-... 424a5e7 +/-
nemoclaw/src/se...cret-scanner.ts 100%
nemoclaw/src/commands/slash.ts 100%
nemoclaw/src/li...bprocess-env.ts 100%
nemoclaw/src/bl...eprint/state.ts 98%
nemoclaw/src/onboard/config.ts 98%
nemoclaw/src/bl...int/snapshot.ts 97%
nemoclaw/src/bl...print/runner.ts 95%
nemoclaw/src/co...ration-state.ts 94%
nemoclaw/src/bl...ate-networks.ts 94%
nemoclaw/src/index.ts 94%

TypeScript / code-coverage/cli

The overall coverage in the fix/6177-compatible-... branch is 76%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main fix/6177-compatible-... 424a5e7 +/-
src/lib/onboard/preflight.ts 82%
src/lib/state/o...oard-session.ts 82%
src/lib/actions...all/run-plan.ts 81%
src/lib/actions...licy-channel.ts 79%
src/lib/actions...box/snapshot.ts 79%
src/lib/state/sandbox.ts 75%
src/lib/onboard...er-gpu-patch.ts 69%
src/lib/policy/index.ts 65%
src/lib/shields/index.ts 60%
src/lib/onboard.ts 28%

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

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: onboard-resume, onboard-repair, cloud-onboard, inference-routing, messaging-compatible-endpoint, bedrock-runtime-compatible-anthropic, hermes-e2e, hermes-shields-config, network-policy
Optional E2E: hermes-inference-switch, openclaw-inference-switch, rebuild-hermes, hermes-gpu-startup, messaging-providers, mcp-bridge

Dispatch hint: onboard-resume,onboard-repair,cloud-onboard,inference-routing,messaging-compatible-endpoint,bedrock-runtime-compatible-anthropic,hermes-e2e,hermes-shields-config,network-policy

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • onboard-resume (medium): Required by the onboarding resume rule because provider-inference state-machine code changed; validates live resume orchestration and state recovery across an interrupted onboard.
  • onboard-repair (medium): Required by the onboarding resume rule because the same provider-inference and setup-inference changes can affect repair policy and resume recovery after failed provider setup.
  • cloud-onboard (medium): Provider inference selection, setup-inference, compatible endpoint context-window handling, and Dockerfile patching can affect full hosted onboarding and image build/runtime configuration.
  • inference-routing (low): Curl probe validation, SSRF preflight, private-network classification, and provider route setup are core inference routing/security boundaries and need live CLI route validation.
  • messaging-compatible-endpoint (medium): Exercises the fake OpenAI-compatible endpoint through a real sandbox, inference.local, messaging config, gateway header stripping, and credential rewrite boundary touched by the compatible endpoint and curl probe changes.
  • bedrock-runtime-compatible-anthropic (medium): Bedrock Runtime endpoint classification changed; this job validates both OpenClaw and Hermes onboarding/runtime behavior for the compatible Anthropic Bedrock adapter boundary.
  • hermes-e2e (medium): Hermes Dockerfile/config generation now propagates context_length and the onboarding flow patches Hermes image build args; a fresh Hermes sandbox should prove runtime startup and hosted inference still work.
  • hermes-shields-config (medium): runtime-config-guard.py and shields/index changes affect Hermes non-root strict hash reconciliation and shields mutable/locked transitions, which are security-critical runtime config boundaries.
  • network-policy (medium): Private network and SSRF classification changes can alter sandbox egress containment; run the live network-policy allow/deny probes to validate the security boundary.

Optional E2E

  • hermes-inference-switch (medium): Useful adjacent coverage for Hermes route/config rewrites after context_length and provider metadata changes, but the PR primarily changes onboarding/probe setup rather than the inference set command.
  • openclaw-inference-switch (medium): Optional confidence for cross-provider route switching after provider metadata and compatible endpoint validation changes.
  • rebuild-hermes (medium): The Dockerfile patch and Hermes config build-arg changes can affect rebuild flows; fresh Hermes E2E is required, while rebuild-specific validation is useful but higher cost.
  • hermes-gpu-startup (high): Optional GPU confidence for local/GPU Hermes startup and runtime context discovery after setup-nim and vLLM context-window changes; explicit-only and higher cost.
  • messaging-providers (medium): WhatsApp QR runtime display changed; full messaging provider coverage is useful if maintainers want end-to-end messaging confidence beyond the required compatible endpoint lane.
  • mcp-bridge (high): MCP live/support files changed and private-network/security behavior is adjacent to tool egress; optional unless reviewers suspect MCP bridge regressions.

New E2E recommendations

  • compatible endpoint context-window and SSRF preflight (high): Existing jobs cover compatible endpoints indirectly, but there is no focused live E2E that proves /v1/models max_model_len auto-detection, curl --resolve pinning, ambient proxy bypass, and DNS-rebinding refusal across both OpenClaw and Hermes onboarding.
    • Suggested test: Add a focused e2e-live job that onboards OpenClaw and Hermes against a hermetic OpenAI-compatible endpoint with public and rebinding DNS fixtures, then asserts baked context metadata/config.yaml context_length and proxy-free curl probe behavior.

Dispatch hint

  • Workflow: .github/workflows/e2e.yaml
  • jobs input: onboard-resume,onboard-repair,cloud-onboard,inference-routing,messaging-compatible-endpoint,bedrock-runtime-compatible-anthropic,hermes-e2e,hermes-shields-config,network-policy

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

E2E Target Recommendation

Required E2E targets: bedrock-runtime-compatible-anthropic, hermes-gpu-startup, mcp-bridge, mcp-bridge-dev, messaging-compatible-endpoint, onboard-resume, e2e-all, onboard-repair
Optional E2E targets: gpu-e2e

Dispatch required E2E targets:

  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=bedrock-runtime-compatible-anthropic
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=hermes-gpu-startup
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=mcp-bridge
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=mcp-bridge-dev
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=messaging-compatible-endpoint
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-resume
  • gh workflow run e2e.yaml --ref <pr-head-ref>
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-repair

Workflow run

Full E2E target advisor summary

E2E Target Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E targets

  • bedrock-runtime-compatible-anthropic: Focused free-standing E2E job wired for changed live test test/e2e/live/bedrock-runtime-compatible-anthropic.test.ts.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=bedrock-runtime-compatible-anthropic
  • hermes-gpu-startup: Focused free-standing E2E job wired for changed live test test/e2e/live/hermes-gpu-startup.test.ts.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=hermes-gpu-startup
  • mcp-bridge: Focused free-standing E2E job wired for changed live test test/e2e/live/mcp-bridge.test.ts.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=mcp-bridge
  • mcp-bridge-dev: Focused free-standing E2E job wired for changed live test test/e2e/live/mcp-bridge.test.ts.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=mcp-bridge-dev
  • messaging-compatible-endpoint: Focused free-standing E2E job wired for changed live test test/e2e/live/messaging-compatible-endpoint.test.ts.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=messaging-compatible-endpoint
  • onboard-resume: Focused free-standing E2E job wired for changed live test test/e2e/live/onboard-resume.test.ts.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-resume
  • e2e-all: Shared E2E fixtures/support and compatible-inference helper changes affect target machinery beyond a single live job, so run the canonical E2E fan-out.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref>
  • onboard-repair: Provider inference state-machine changes can affect repair/backstop execution from persisted sessions, so the onboarding resume rule requires onboard-repair as well.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-repair

Optional E2E targets

  • gpu-e2e: Optional adjacent GPU onboarding coverage for inference/runtime context changes; hermes-gpu-startup is the required Hermes-specific GPU lane.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=gpu-e2e

Relevant changed files

  • agents/hermes/Dockerfile
  • agents/hermes/config/build-env.ts
  • agents/hermes/config/hermes-config.ts
  • agents/hermes/runtime-config-guard.py
  • src/lib/adapters/http/curl-args.ts
  • src/lib/adapters/http/probe.ts
  • src/lib/inference/bedrock-runtime.ts
  • src/lib/inference/compatible-endpoint-context.ts
  • src/lib/inference/endpoint-ssrf-preflight.ts
  • src/lib/inference/onboard-probes.ts
  • src/lib/inference/probe-anthropic.ts
  • src/lib/inference/probe-http-helpers.ts
  • src/lib/inference/vllm-runtime-context.ts
  • src/lib/onboard/dockerfile-patch.ts
  • src/lib/onboard/inference-providers/remote.ts
  • src/lib/onboard/inference-providers/types.ts
  • src/lib/onboard/inference-selection-validation.ts
  • src/lib/onboard/machine/handlers/provider-inference.ts
  • src/lib/onboard/setup-inference.ts
  • src/lib/onboard/setup-nim-flow.ts
  • src/lib/onboard/setup-nim-selection.ts
  • src/lib/private-networks.ts
  • src/lib/shields/index.ts
  • test/e2e/fixtures/fake-openai-compatible.ts
  • test/e2e/lib/fake-openai-compatible-api.mts
  • test/e2e/lib/hermetic-compatible-inference.sh
  • test/e2e/live/bedrock-runtime-compatible-anthropic.test.ts
  • test/e2e/live/hermes-gpu-startup.test.ts
  • test/e2e/live/mcp-bridge-sandbox.ts
  • test/e2e/live/mcp-bridge.test.ts
  • test/e2e/live/messaging-compatible-endpoint.test.ts
  • test/e2e/live/onboard-resume.test.ts
  • test/e2e/support/mcp-bridge-sandbox.test.ts

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor (Nemotron Ultra) — Changes requested

Merge posture: Do not merge yet
Primary next action: Fix PRA-5: Test file exceeds 20-line monolith growth guardrail (+232 lines); then add or justify PRA-T1.
Open items: 7 required · 12 warnings · 3 suggestions · 8 test follow-ups
Since last review: 2 prior items resolved · 12 still apply · 6 new items found

Action checklist

  • PRA-5 Fix: Test file exceeds 20-line monolith growth guardrail (+232 lines) in src/lib/onboard/inference-selection-validation.test.ts:1
  • PRA-6 Fix: @ts-nocheck suppresses TypeScript checking on security-critical SSRF guard logic in src/lib/inference/onboard-probes.ts:1
  • PRA-7 Fix: VITEST bypass in verifyOnboardInferenceSmoke without justification comment in src/lib/inference/onboard-probes.ts:944
  • PRA-8 Fix: Monolith growth +47 lines exceeds 20-line guardrail in src/lib/onboard/setup-inference.ts:1
  • PRA-9 Fix: Test file monolith growth +88 lines exceeds 20-line guardrail in src/lib/adapters/http/probe.test.ts:1
  • PRA-10 Fix: Monolith growth +28 lines exceeds 20-line guardrail in src/lib/inference/onboard-probes.ts:1
  • PRA-11 Fix: Monolith growth +31 lines exceeds 20-line guardrail in src/lib/adapters/http/probe.ts:1
  • PRA-1 Resolve or justify: Source-of-truth review needed: Auto-detected context window state tracking
  • PRA-2 Resolve or justify: Source-of-truth review needed: Dockerfile patch idempotency
  • PRA-3 Resolve or justify: Source-of-truth review needed: Hermes Dockerfile build verification
  • PRA-4 Resolve or justify: Source-of-truth review needed: @ts-nocheck on security-critical module
  • PRA-12 Resolve or justify: Significant growth +82 lines not flagged by test-file guardrail in src/lib/onboard/inference-selection-validation.ts:1
  • PRA-13 Resolve or justify: Double-negative SSRF guard readability — extract isTrustedSandboxBridge helper in src/lib/inference/onboard-probes.ts:634
  • PRA-14 Resolve or justify: Module-level autoDetectedCompatibleContextWindow duplicates Ollama pattern without shared helper in src/lib/inference/compatible-endpoint-context.ts:156
  • PRA-15 Resolve or justify: TODO([DGX Spark][Inference] vLLM compatible-endpoint: context window falls back to ~4K for NemotronH models — agent unusable #6177) references parent issue instead of dedicated follow-up for helper extraction in src/lib/inference/compatible-endpoint-context.ts:152
  • PRA-16 Resolve or justify: Missing idempotency test for NEMOCLAW_CONTEXT_WINDOW dockerfile-patch in src/lib/onboard/dockerfile-patch-hermes-context.test.ts:1
  • PRA-17 Resolve or justify: Hermes Dockerfile build not tested end-to-end with NEMOCLAW_CONTEXT_WINDOW in agents/hermes/Dockerfile:280
  • 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 idempotency test for NEMOCLAW_CONTEXT_WINDOW dockerfile-patch
  • PRA-T7 Add or justify test follow-up: Hermes Dockerfile build not tested end-to-end with NEMOCLAW_CONTEXT_WINDOW
  • PRA-T8 Add or justify test follow-up: Private-address SSRF guard tests should verify extracted isTrustedSandboxBridge helper
  • PRA-20 In-scope improvement: OPENSHELL_MANAGED_HOSTS string-match exemption could use DNS preflight with allowlist in src/lib/inference/endpoint-ssrf-preflight.ts:40
  • PRA-21 In-scope improvement: fetchCompatibleEndpointModels creates new authConfig per call — document intent in src/lib/inference/compatible-endpoint-context.ts:200
  • PRA-22 In-scope improvement: isPrivateResolveAddress uses dynamic require — document why static import not feasible in src/lib/adapters/http/curl-args.ts:180

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 architecture src/lib/onboard/inference-selection-validation.test.ts:1 Extract SSRF preflight integration tests into a separate file (e.g., inference-selection-validation-ssrf-preflight.test.ts) or reduce other coverage to stay within 277 lines.
PRA-6 Required security src/lib/inference/onboard-probes.ts:1 Either (a) migrate the require()-imported dependencies (credentials/store, platform, trace) to typed ESM exports and drop @ts-nocheck, or (b) file a follow-up issue with tracked removal condition and update TODO comment (e.g., TODO(#XXXX): drop @ts-nocheck once credentials/store, platform, trace expose typed ESM exports).
PRA-7 Required architecture src/lib/inference/onboard-probes.ts:944 Add a clear justifying comment at line 944: 'Post-onboarding smoke check runs after sandbox policy exists; VITEST skip acceptable because probe targets sandbox-internal gateway. Security-critical SSRF preflight (assertEndpointResolvesPublic) runs unconditionally.'
PRA-8 Required architecture src/lib/onboard/setup-inference.ts:1 Extract the new SSRF preflight integration logic into a separate module (e.g., inference-preflight.ts) or reduce other code to stay within 20-line growth limit.
PRA-9 Required architecture src/lib/adapters/http/probe.test.ts:1 Extract the new SSRF proxy-bypass test cases into a separate test file (e.g., probe-ssrf-preflight.test.ts) or reduce other coverage to stay within 20-line growth limit.
PRA-10 Required architecture src/lib/inference/onboard-probes.ts:1 Extract the new SSRF preflight/pinnedAddresses logic into a separate module or reduce other code to stay within 20-line growth limit.
PRA-11 Required architecture src/lib/adapters/http/probe.ts:1 Extract the new proxy-bypass logic for --resolve into a separate helper or reduce other code to stay within 20-line growth limit.
PRA-12 Resolve/justify architecture src/lib/onboard/inference-selection-validation.ts:1 Consider extracting SSRF preflight integration into a dedicated module to contain growth.
PRA-13 Resolve/justify security src/lib/inference/onboard-probes.ts:634 Extract `isTrustedSandboxBridge(endpointUrl)` returning true for sandbox-internal hosts (host.openshell.internal) and hijacked docker-internal alias. Guard becomes: `if (isPrivateHostname(hostname) && !isLoopbackHostname(hostname) && !isTrustedSandboxBridge(endpointUrl))`. This also satisfies test coverage request for the helper.
PRA-14 Resolve/justify architecture src/lib/inference/compatible-endpoint-context.ts:156 Either extract a shared `trackAutoDetectedContextWindow` helper used by both Ollama and compatible-endpoint probes, or document why the duplication is acceptable and when it can be removed. File follow-up issue for extraction.
PRA-15 Resolve/justify correctness src/lib/inference/compatible-endpoint-context.ts:152 Create dedicated follow-up issue for extracting trackAutoDetectedContextWindow helper. Update TODO comment with new issue number.
PRA-16 Resolve/justify tests src/lib/onboard/dockerfile-patch-hermes-context.test.ts:1 Add test case: patch with context window, patch again, assert ARG unchanged.
PRA-17 Resolve/justify tests agents/hermes/Dockerfile:280 Add e2e test that builds Hermes image with NEMOCLAW_CONTEXT_WINDOW=65536 and verifies generated config.yaml contains model.context_length: 65536.
PRA-18 Resolve/justify tests src/lib/inference/onboard-probes.test.ts:232 Add unit tests for isTrustedSandboxBridge helper covering sandbox-internal hosts, docker-internal alias, and private LAN addresses. This depends on PRA-9 extraction.
PRA-19 Resolve/justify scope test/hermes-gateway-wrapper.test.ts:1 Verify wrapper test changes are required for current PR scope. If unrelated refactoring, separate. Run secret boundary tests to confirm #4975 protection intact.
PRA-20 Improvement security src/lib/inference/endpoint-ssrf-preflight.ts:40 For managed hosts, run DNS preflight but allowlist the expected resolved addresses (loopback, proxy IP) instead of blanket exemption. This maintains SSRF protection while supporting legitimate managed aliases.

🚨 Required before merge

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

PRA-5 Required — Test file exceeds 20-line monolith growth guardrail (+232 lines)

  • Location: src/lib/onboard/inference-selection-validation.test.ts:1
  • Category: architecture
  • Problem: Test file grew from 257 to ~500 lines (+232), far exceeding the 20-line monolith growth guardrail (max 277 lines). 7 new SSRF preflight integration test cases added without extraction.
  • Impact: Blocks merge per repo policy. Continued growth makes file harder to test, review, and maintain.
  • Required action: Extract SSRF preflight integration tests into a separate file (e.g., inference-selection-validation-ssrf-preflight.test.ts) or reduce other coverage to stay within 277 lines.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: wc -l src/lib/onboard/inference-selection-validation.test.ts — should be ≤277 after extraction
  • Missing regression test: N/A — file-size guardrail enforcement
  • Done when: The required change is committed and verification passes: wc -l src/lib/onboard/inference-selection-validation.test.ts — should be ≤277 after extraction.
  • Evidence: File changed from 257 to 489 lines per diff stat; growth comes from 7 new SSRF preflight integration test cases marked fix(inference): honor compatible-endpoint max_model_len for Hermes context (#6177) #6293

PRA-6 Required — @ts-nocheck suppresses TypeScript checking on security-critical SSRF guard logic

  • Location: src/lib/inference/onboard-probes.ts:1
  • Category: security
  • Problem: @ts-nocheck directive at top of file suppresses TypeScript checking on private-address checks, DNS preflight integration, and pinnedAddresses handling. The directive exists because this module uses require() for credentials/store, platform, trace which lack typed ESM exports.
  • Impact: Type safety gap on security-critical SSRF boundary. Silent type errors could allow invalid private-address checks or incorrect pinnedAddresses handling to reach production.
  • Required action: Either (a) migrate the require()-imported dependencies (credentials/store, platform, trace) to typed ESM exports and drop @ts-nocheck, or (b) file a follow-up issue with tracked removal condition and update TODO comment (e.g., TODO(#XXXX): drop @ts-nocheck once credentials/store, platform, trace expose typed ESM exports).
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: head -5 src/lib/inference/onboard-probes.ts — should show @ts-nocheck with tracked removal condition
  • Missing regression test: N/A — type safety on security-critical boundary
  • Done when: The required change is committed and verification passes: head -5 src/lib/inference/onboard-probes.ts — should show @ts-nocheck with tracked removal condition.
  • Evidence: File begins with // @ts-nocheck and comment explains require() bridge to credentials/store, platform, trace modules

PRA-7 Required — VITEST bypass in verifyOnboardInferenceSmoke without justification comment

  • Location: src/lib/inference/onboard-probes.ts:944
  • Category: architecture
  • Problem: Early return `if (process.env.VITEST === 'true') return;` in verifyOnboardInferenceSmoke disables post-onboarding smoke check in tests without a justifying comment. This is a security-critical path that validates inference connectivity.
  • Impact: Silent test bypass on security-critical validation path; no documentation of why this is acceptable. Could mask regressions in smoke check logic.
  • Required action: Add a clear justifying comment at line 944: 'Post-onboarding smoke check runs after sandbox policy exists; VITEST skip acceptable because probe targets sandbox-internal gateway. Security-critical SSRF preflight (assertEndpointResolvesPublic) runs unconditionally.'
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: grep -n 'VITEST.*true' src/lib/inference/onboard-probes.ts — should show justifying comment on same line or preceding line
  • Missing regression test: N/A — documentation of security-critical bypass justification
  • Done when: The required change is committed and verification passes: grep -n 'VITEST.*true' src/lib/inference/onboard-probes.ts — should show justifying comment on same line or preceding line.
  • Evidence: Line 944: `if (process.env.VITEST === 'true') return;` with no preceding comment

PRA-8 Required — Monolith growth +47 lines exceeds 20-line guardrail

  • Location: src/lib/onboard/setup-inference.ts:1
  • Category: architecture
  • Problem: File grew from 403 to 450 lines (+47), exceeding the 20-line monolith growth guardrail. New SSRF preflight integration logic added without extraction.
  • Impact: Blocks merge per repo policy. Continued growth makes file harder to test, review, and maintain.
  • Required action: Extract the new SSRF preflight integration logic into a separate module (e.g., inference-preflight.ts) or reduce other code to stay within 20-line growth limit.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: wc -l src/lib/onboard/setup-inference.ts — should be ≤423 after extraction
  • Missing regression test: N/A — file-size guardrail enforcement
  • Done when: The required change is committed and verification passes: wc -l src/lib/onboard/setup-inference.ts — should be ≤423 after extraction.
  • Evidence: Diff stat shows +47 lines; new SSRF preflight integration in validateCustomOpenAiLikeSelection/validateCustomAnthropicSelection

PRA-9 Required — Test file monolith growth +88 lines exceeds 20-line guardrail

  • Location: src/lib/adapters/http/probe.test.ts:1
  • Category: architecture
  • Problem: Test file grew from 1146 to ~1234 lines (+88), exceeding the 20-line monolith growth guardrail. New SSRF proxy-bypass test cases added without extraction.
  • Impact: Blocks merge per repo policy. Continued growth makes file harder to test, review, and maintain.
  • Required action: Extract the new SSRF proxy-bypass test cases into a separate test file (e.g., probe-ssrf-preflight.test.ts) or reduce other coverage to stay within 20-line growth limit.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: wc -l src/lib/adapters/http/probe.test.ts — should be ≤1166 after extraction
  • Missing regression test: N/A — file-size guardrail enforcement
  • Done when: The required change is committed and verification passes: wc -l src/lib/adapters/http/probe.test.ts — should be ≤1166 after extraction.
  • Evidence: Diff stat shows +88 lines; new tests: 'bypasses ambient proxies when --resolve pins the validated origin' and 'bypasses ambient proxies for approved no-pin origin'

PRA-10 Required — Monolith growth +28 lines exceeds 20-line guardrail

  • Location: src/lib/inference/onboard-probes.ts:1
  • Category: architecture
  • Problem: File grew from 948 to ~976 lines (+28), exceeding the 20-line monolith growth guardrail. New SSRF preflight/pinnedAddresses logic added without extraction.
  • Impact: Blocks merge per repo policy. Continued growth makes file harder to test, review, and maintain.
  • Required action: Extract the new SSRF preflight/pinnedAddresses logic into a separate module or reduce other code to stay within 20-line growth limit.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: wc -l src/lib/inference/onboard-probes.ts — should be ≤968 after extraction
  • Missing regression test: N/A — file-size guardrail enforcement
  • Done when: The required change is committed and verification passes: wc -l src/lib/inference/onboard-probes.ts — should be ≤968 after extraction.
  • Evidence: Diff stat shows +28 lines; new pinnedAddresses propagation through probeOpenAiLikeEndpoint, probeAnthropicEndpoint

PRA-11 Required — Monolith growth +31 lines exceeds 20-line guardrail

  • Location: src/lib/adapters/http/probe.ts:1
  • Category: architecture
  • Problem: File grew from 819 to ~850 lines (+31), exceeding the 20-line monolith growth guardrail. New proxy-bypass logic for --resolve added without extraction.
  • Impact: Blocks merge per repo policy. Continued growth makes file harder to test, review, and maintain.
  • Required action: Extract the new proxy-bypass logic for --resolve into a separate helper or reduce other code to stay within 20-line growth limit.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: wc -l src/lib/adapters/http/probe.ts — should be ≤839 after extraction
  • Missing regression test: N/A — file-size guardrail enforcement
  • Done when: The required change is committed and verification passes: wc -l src/lib/adapters/http/probe.ts — should be ≤839 after extraction.
  • Evidence: Diff stat shows +31 lines; resolveCurlProbeSpawnEnv now deletes proxy env vars when pinnedAddresses defined
Review findings by urgency: 7 required fixes, 12 items to resolve/justify, 3 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: Auto-detected context window state tracking

  • 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: compatible-endpoint-context.test.ts: clears stale auto value, keeps genuine user override, recomputes over prior auto
  • 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: autoDetectedCompatibleContextWindow module variable mirrors Ollama's autoDetectedOllamaContextWindow. Third duplication would be problematic. No shared helper extracted yet. TODO references parent issue.

PRA-2 Resolve/justify — Source-of-truth review needed: Dockerfile patch idempotency

  • 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: None currently — PRA-12
  • 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: dockerfile-patch-hermes-context.test.ts has 6 cases but none test double-patch idempotency

PRA-3 Resolve/justify — Source-of-truth review needed: Hermes Dockerfile build verification

  • 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: None currently — PRA-13
  • 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: Dockerfile ARG added, promoted to ENV, build-env.ts reads it, hermes-config.ts writes model.context_length. No e2e build test.

PRA-4 Resolve/justify — Source-of-truth review needed: @ts-nocheck on security-critical module

  • 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: None — type safety gap
  • 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: File begins with // @ts-nocheck and comment explains require() bridge. PRA-3 blocker.

PRA-12 Resolve/justify — Significant growth +82 lines not flagged by test-file guardrail

  • Location: src/lib/onboard/inference-selection-validation.ts:1
  • Category: architecture
  • Problem: Source file grew from 292 to 374 lines (+82). SSRF preflight integration logic adds substantial complexity without extraction.
  • Impact: Architecture maintainability debt. File becoming harder to review and test as SSRF logic mixes with validation orchestration.
  • Recommended action: Consider extracting SSRF preflight integration into a dedicated module to contain growth.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: wc -l src/lib/onboard/inference-selection-validation.ts — review whether extraction is feasible
  • Missing regression test: N/A — architecture maintainability
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: wc -l src/lib/onboard/inference-selection-validation.ts — review whether extraction is feasible.
  • Evidence: Diff stat shows +82 lines; new resolveEndpointHost injection, pinnedAddresses return values

PRA-13 Resolve/justify — Double-negative SSRF guard readability — extract isTrustedSandboxBridge helper

  • Location: src/lib/inference/onboard-probes.ts:634
  • Category: security
  • Problem: Double-negative SSRF guard: `isPrivateHostname(probeHostname) && !isLoopbackHostname(probeHostname) && !isHijackedDockerInternalUrl(endpointUrl)`. This mirrors the same pattern in endpoint-ssrf-preflight.ts but isn't extracted to a shared helper.
  • Impact: Reduced readability and maintainability of security-critical guard. Duplication increases risk of divergent fixes. Test coverage request for helper cannot be satisfied until extracted.
  • Recommended action: Extract `isTrustedSandboxBridge(endpointUrl)` returning true for sandbox-internal hosts (host.openshell.internal) and hijacked docker-internal alias. Guard becomes: `if (isPrivateHostname(hostname) && !isLoopbackHostname(hostname) && !isTrustedSandboxBridge(endpointUrl))`. This also satisfies test coverage request for the helper.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: grep -n 'isTrustedSandboxBridge' src/lib/inference/onboard-probes.ts — should exist after extraction
  • Missing regression test: Unit tests for isTrustedSandboxBridge helper covering sandbox-internal hosts, docker-internal alias, and private LAN addresses
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: grep -n 'isTrustedSandboxBridge' src/lib/inference/onboard-probes.ts — should exist after extraction.
  • Evidence: Line 634 in onboard-probes.ts; similar pattern in endpoint-ssrf-preflight.ts:37-41

PRA-14 Resolve/justify — Module-level autoDetectedCompatibleContextWindow duplicates Ollama pattern without shared helper

  • Location: src/lib/inference/compatible-endpoint-context.ts:156
  • Category: architecture
  • Problem: Module-level variable `autoDetectedCompatibleContextWindow` duplicates Ollama pattern (autoDetectedOllamaContextWindow in ollama-runtime-context.ts) without shared helper. Third provider adopting same pattern would triple the duplication.
  • Impact: Code duplication across providers. Increases maintenance burden and risk of inconsistent behavior. TODO references parent issue instead of dedicated follow-up.
  • Recommended action: Either extract a shared `trackAutoDetectedContextWindow` helper used by both Ollama and compatible-endpoint probes, or document why the duplication is acceptable and when it can be removed. File follow-up issue for extraction.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: grep -n 'autoDetected.*ContextWindow' src/lib/inference/ollama-runtime-context.ts src/lib/inference/compatible-endpoint-context.ts — should share a helper or have documented follow-up
  • Missing regression test: N/A — code duplication tracking
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: grep -n 'autoDetected.*ContextWindow' src/lib/inference/ollama-runtime-context.ts src/lib/inference/compatible-endpoint-context.ts — should share a helper or have documented follow-up.
  • Evidence: Line 156 in compatible-endpoint-context.ts; ollama-runtime-context.ts has autoDetectedOllamaContextWindow at similar scope

PRA-15 Resolve/justify — TODO(#6177) references parent issue instead of dedicated follow-up for helper extraction

  • Location: src/lib/inference/compatible-endpoint-context.ts:152
  • Category: correctness
  • Problem: TODO comment at line 152 references parent issue [DGX Spark][Inference] vLLM compatible-endpoint: context window falls back to ~4K for NemotronH models — agent unusable #6177 instead of dedicated follow-up for extracting trackAutoDetectedContextWindow helper. Parent issue is about context window propagation, not helper extraction.
  • Impact: Issue tracking hygiene — helper extraction work not tracked separately, may be forgotten.
  • Recommended action: Create dedicated follow-up issue for extracting trackAutoDetectedContextWindow helper. Update TODO comment with new issue number.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: grep -n 'TODO.*6177' src/lib/inference/compatible-endpoint-context.ts — should reference dedicated follow-up issue
  • Missing regression test: N/A — issue tracking hygiene
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: grep -n 'TODO.*6177' src/lib/inference/compatible-endpoint-context.ts — should reference dedicated follow-up issue.
  • Evidence: Line 152: `// TODO([DGX Spark][Inference] vLLM compatible-endpoint: context window falls back to ~4K for NemotronH models — agent unusable #6177): this auto-state tracking mirrors the Ollama contract...`

PRA-16 Resolve/justify — Missing idempotency test for NEMOCLAW_CONTEXT_WINDOW dockerfile-patch

  • Location: src/lib/onboard/dockerfile-patch-hermes-context.test.ts:1
  • Category: tests
  • Problem: No test verifies that patching the Dockerfile twice with the same context window leaves the ARG unchanged (idempotent). Critical for CI/CD where patch may run multiple times.
  • Impact: Regression risk: dockerfile-patch could accumulate changes or behave differently on second run.
  • Recommended action: Add test case: patch with context window, patch again, assert ARG unchanged.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: grep -n 'patch again' src/lib/onboard/dockerfile-patch-hermes-context.test.ts — should find idempotency test
  • Missing regression test: Test: patch with context window, patch again, assert ARG unchanged
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: grep -n 'patch again' src/lib/onboard/dockerfile-patch-hermes-context.test.ts — should find idempotency test.
  • Evidence: Test file has 6 cases but none test double-patch idempotency

PRA-17 Resolve/justify — Hermes Dockerfile build not tested end-to-end with NEMOCLAW_CONTEXT_WINDOW

  • Location: agents/hermes/Dockerfile:280
  • Category: tests
  • Problem: The ARG NEMOCLAW_CONTEXT_WINDOW is added to Dockerfile and promoted to ENV, read by build-env.ts, and written as model.context_length in config.yaml. No e2e test verifies the full chain.
  • Impact: Integration gap: Dockerfile ARG → build-env → hermes-config → config.yaml chain untested. Could silently fail if any step breaks.
  • Recommended action: Add e2e test that builds Hermes image with NEMOCLAW_CONTEXT_WINDOW=65536 and verifies generated config.yaml contains model.context_length: 65536.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: grep -r 'NEMOCLAW_CONTEXT_WINDOW' test/e2e/ — should find e2e build test
  • Missing regression test: E2E test: build Hermes image with NEMOCLAW_CONTEXT_WINDOW=65536, verify config.yaml has model.context_length: 65536
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: grep -r 'NEMOCLAW_CONTEXT_WINDOW' test/e2e/ — should find e2e build test.
  • Evidence: Dockerfile line 280 adds ARG NEMOCLAW_CONTEXT_WINDOW=; build-env.ts reads it; hermes-config.ts writes model.context_length

PRA-18 Resolve/justify — Private-address SSRF guard tests should verify extracted isTrustedSandboxBridge helper

  • Location: src/lib/inference/onboard-probes.test.ts:232
  • Category: tests
  • Problem: Private-address SSRF guard tests directly test the inline double-negative guard. No isTrustedSandboxBridge helper exists yet (PRA-9), so tests cannot verify the extracted helper.
  • Impact: Test coverage for helper extraction blocked. Once PRA-9 is done, tests must be updated to verify the helper.
  • Recommended action: Add unit tests for isTrustedSandboxBridge helper covering sandbox-internal hosts, docker-internal alias, and private LAN addresses. This depends on PRA-9 extraction.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: grep -n 'isTrustedSandboxBridge' src/lib/inference/onboard-probes.test.ts — should find helper tests after PRA-9 extraction
  • Missing regression test: Unit tests for isTrustedSandboxBridge helper covering sandbox-internal hosts, docker-internal alias, and private LAN addresses
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: grep -n 'isTrustedSandboxBridge' src/lib/inference/onboard-probes.test.ts — should find helper tests after PRA-9 extraction.
  • Evidence: Test file lines 232+ test private-address rejection but test the inline guard, not a helper

PRA-19 Resolve/justify — Wrapper test file reduced 159 lines — verify changes required for current PR scope

💡 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-20 Improvement — OPENSHELL_MANAGED_HOSTS string-match exemption could use DNS preflight with allowlist

  • Location: src/lib/inference/endpoint-ssrf-preflight.ts:40
  • Category: security
  • Problem: OPENSHELL_MANAGED_HOSTS exemption uses string match without validating they resolve to expected addresses. If an attacker controls DNS for inference.local, they could rebind to private addresses.
  • Impact: Potential SSRF bypass if managed host DNS is compromised. Current exemption is blanket — no validation of resolved addresses.
  • Suggested action: For managed hosts, run DNS preflight but allowlist the expected resolved addresses (loopback, proxy IP) instead of blanket exemption. This maintains SSRF protection while supporting legitimate managed aliases.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check assertEndpointResolvesPublic for managed hosts — should resolve and validate against allowlist
  • Missing regression test: Test: managed host resolving to unexpected address is refused
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Lines 27-41: OPENSHELL_MANAGED_HOSTS set and isOpenShellManagedHost exempts before DNS resolution

PRA-21 Improvement — fetchCompatibleEndpointModels creates new authConfig per call — document intent

  • Location: src/lib/inference/compatible-endpoint-context.ts:200
  • Category: architecture
  • Problem: fetchCompatibleEndpointModels creates a new authConfig (with temp file) on every call. Unclear if this is intentional for credential isolation/rotation or could be optimized.
  • Impact: Unnecessary temp file creation overhead if not needed for isolation. Lack of documentation makes future maintenance harder.
  • Suggested action: Document whether per-call authConfig creation is intentional for credential isolation/rotation, or optimize if unnecessary.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: grep -A5 'fetchCompatibleEndpointModels' src/lib/inference/compatible-endpoint-context.ts — should have comment explaining per-call authConfig
  • Missing regression test: N/A — code documentation
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Function creates authConfig = createOpenAiLikeAuthConfig(apiKey || '') and calls authConfig.cleanup() in finally block

PRA-22 Improvement — isPrivateResolveAddress uses dynamic require — document why static import not feasible

  • Location: src/lib/adapters/http/curl-args.ts:180
  • Category: correctness
  • Problem: isPrivateResolveAddress uses dynamic require(`../../private-networks`) to avoid pulling in YAML loader in curl-args tests. No comment explains this rationale.
  • Impact: Dynamic require reduces static analysis and may confuse future maintainers. Without documentation, someone might 'fix' it and break test isolation.
  • Suggested action: Evaluate if static import of isPrivateIp from private-networks is feasible without pulling in YAML loader in curl-args tests. If not, add comment explaining why dynamic require is needed.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check src/lib/adapters/http/curl-args.ts:180 — should have comment explaining dynamic require rationale
  • Missing regression test: N/A — import strategy documentation
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Line 180: `const { isPrivateIp } = require("../../private-networks") as typeof import("../../private-networks");`
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 — Hermes Dockerfile build e2e: NEMOCLAW_CONTEXT_WINDOW=65536 → verify config.yaml has model.context_length: 65536. Runtime/sandbox/infrastructure paths need behavioral runtime validation: agents/hermes/Dockerfile (ARG → config.yaml), agents/hermes/config/build-env.ts, agents/hermes/config/hermes-config.ts, agents/hermes/runtime-config-guard.py (shields transition), src/lib/adapters/http/curl-args.ts (--resolve validation), src/lib/adapters/http/probe.ts (proxy bypass + pinning). Unit tests cover logic but not full integration chain.
  • PRA-T2 Runtime validation — dockerfile-patch idempotency: patch with context window, patch again, assert ARG unchanged. Runtime/sandbox/infrastructure paths need behavioral runtime validation: agents/hermes/Dockerfile (ARG → config.yaml), agents/hermes/config/build-env.ts, agents/hermes/config/hermes-config.ts, agents/hermes/runtime-config-guard.py (shields transition), src/lib/adapters/http/curl-args.ts (--resolve validation), src/lib/adapters/http/probe.ts (proxy bypass + pinning). Unit tests cover logic but not full integration chain.
  • PRA-T3 Runtime validation — Managed-host DNS compromise: inference.local resolving to private IP should be refused (DNS preflight + allowlist). Runtime/sandbox/infrastructure paths need behavioral runtime validation: agents/hermes/Dockerfile (ARG → config.yaml), agents/hermes/config/build-env.ts, agents/hermes/config/hermes-config.ts, agents/hermes/runtime-config-guard.py (shields transition), src/lib/adapters/http/curl-args.ts (--resolve validation), src/lib/adapters/http/probe.ts (proxy bypass + pinning). Unit tests cover logic but not full integration chain.
  • PRA-T4 Runtime validation — isTrustedSandboxBridge helper unit tests (depends on PRA-9 extraction). Runtime/sandbox/infrastructure paths need behavioral runtime validation: agents/hermes/Dockerfile (ARG → config.yaml), agents/hermes/config/build-env.ts, agents/hermes/config/hermes-config.ts, agents/hermes/runtime-config-guard.py (shields transition), src/lib/adapters/http/curl-args.ts (--resolve validation), src/lib/adapters/http/probe.ts (proxy bypass + pinning). Unit tests cover logic but not full integration chain.
  • PRA-T5 Runtime validation — Bedrock Runtime canonical TLS origin rejection test (already added in bedrock-runtime.test.ts). Runtime/sandbox/infrastructure paths need behavioral runtime validation: agents/hermes/Dockerfile (ARG → config.yaml), agents/hermes/config/build-env.ts, agents/hermes/config/hermes-config.ts, agents/hermes/runtime-config-guard.py (shields transition), src/lib/adapters/http/curl-args.ts (--resolve validation), src/lib/adapters/http/probe.ts (proxy bypass + pinning). Unit tests cover logic but not full integration chain.
  • PRA-T6 Missing idempotency test for NEMOCLAW_CONTEXT_WINDOW dockerfile-patch — Add test case: patch with context window, patch again, assert ARG unchanged.
  • PRA-T7 Hermes Dockerfile build not tested end-to-end with NEMOCLAW_CONTEXT_WINDOW — Add e2e test that builds Hermes image with NEMOCLAW_CONTEXT_WINDOW=65536 and verifies generated config.yaml contains model.context_length: 65536.
  • PRA-T8 Private-address SSRF guard tests should verify extracted isTrustedSandboxBridge helper — Add unit tests for isTrustedSandboxBridge helper covering sandbox-internal hosts, docker-internal alias, and private LAN addresses. This depends on PRA-9 extraction.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: Auto-detected context window state tracking

  • 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: compatible-endpoint-context.test.ts: clears stale auto value, keeps genuine user override, recomputes over prior auto
  • 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: autoDetectedCompatibleContextWindow module variable mirrors Ollama's autoDetectedOllamaContextWindow. Third duplication would be problematic. No shared helper extracted yet. TODO references parent issue.

PRA-2 Resolve/justify — Source-of-truth review needed: Dockerfile patch idempotency

  • 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: None currently — PRA-12
  • 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: dockerfile-patch-hermes-context.test.ts has 6 cases but none test double-patch idempotency

PRA-3 Resolve/justify — Source-of-truth review needed: Hermes Dockerfile build verification

  • 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: None currently — PRA-13
  • 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: Dockerfile ARG added, promoted to ENV, build-env.ts reads it, hermes-config.ts writes model.context_length. No e2e build test.

PRA-4 Resolve/justify — Source-of-truth review needed: @ts-nocheck on security-critical module

  • 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: None — type safety gap
  • 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: File begins with // @ts-nocheck and comment explains require() bridge. PRA-3 blocker.

PRA-5 Required — Test file exceeds 20-line monolith growth guardrail (+232 lines)

  • Location: src/lib/onboard/inference-selection-validation.test.ts:1
  • Category: architecture
  • Problem: Test file grew from 257 to ~500 lines (+232), far exceeding the 20-line monolith growth guardrail (max 277 lines). 7 new SSRF preflight integration test cases added without extraction.
  • Impact: Blocks merge per repo policy. Continued growth makes file harder to test, review, and maintain.
  • Required action: Extract SSRF preflight integration tests into a separate file (e.g., inference-selection-validation-ssrf-preflight.test.ts) or reduce other coverage to stay within 277 lines.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: wc -l src/lib/onboard/inference-selection-validation.test.ts — should be ≤277 after extraction
  • Missing regression test: N/A — file-size guardrail enforcement
  • Done when: The required change is committed and verification passes: wc -l src/lib/onboard/inference-selection-validation.test.ts — should be ≤277 after extraction.
  • Evidence: File changed from 257 to 489 lines per diff stat; growth comes from 7 new SSRF preflight integration test cases marked fix(inference): honor compatible-endpoint max_model_len for Hermes context (#6177) #6293

PRA-6 Required — @ts-nocheck suppresses TypeScript checking on security-critical SSRF guard logic

  • Location: src/lib/inference/onboard-probes.ts:1
  • Category: security
  • Problem: @ts-nocheck directive at top of file suppresses TypeScript checking on private-address checks, DNS preflight integration, and pinnedAddresses handling. The directive exists because this module uses require() for credentials/store, platform, trace which lack typed ESM exports.
  • Impact: Type safety gap on security-critical SSRF boundary. Silent type errors could allow invalid private-address checks or incorrect pinnedAddresses handling to reach production.
  • Required action: Either (a) migrate the require()-imported dependencies (credentials/store, platform, trace) to typed ESM exports and drop @ts-nocheck, or (b) file a follow-up issue with tracked removal condition and update TODO comment (e.g., TODO(#XXXX): drop @ts-nocheck once credentials/store, platform, trace expose typed ESM exports).
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: head -5 src/lib/inference/onboard-probes.ts — should show @ts-nocheck with tracked removal condition
  • Missing regression test: N/A — type safety on security-critical boundary
  • Done when: The required change is committed and verification passes: head -5 src/lib/inference/onboard-probes.ts — should show @ts-nocheck with tracked removal condition.
  • Evidence: File begins with // @ts-nocheck and comment explains require() bridge to credentials/store, platform, trace modules

PRA-7 Required — VITEST bypass in verifyOnboardInferenceSmoke without justification comment

  • Location: src/lib/inference/onboard-probes.ts:944
  • Category: architecture
  • Problem: Early return `if (process.env.VITEST === 'true') return;` in verifyOnboardInferenceSmoke disables post-onboarding smoke check in tests without a justifying comment. This is a security-critical path that validates inference connectivity.
  • Impact: Silent test bypass on security-critical validation path; no documentation of why this is acceptable. Could mask regressions in smoke check logic.
  • Required action: Add a clear justifying comment at line 944: 'Post-onboarding smoke check runs after sandbox policy exists; VITEST skip acceptable because probe targets sandbox-internal gateway. Security-critical SSRF preflight (assertEndpointResolvesPublic) runs unconditionally.'
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: grep -n 'VITEST.*true' src/lib/inference/onboard-probes.ts — should show justifying comment on same line or preceding line
  • Missing regression test: N/A — documentation of security-critical bypass justification
  • Done when: The required change is committed and verification passes: grep -n 'VITEST.*true' src/lib/inference/onboard-probes.ts — should show justifying comment on same line or preceding line.
  • Evidence: Line 944: `if (process.env.VITEST === 'true') return;` with no preceding comment

PRA-8 Required — Monolith growth +47 lines exceeds 20-line guardrail

  • Location: src/lib/onboard/setup-inference.ts:1
  • Category: architecture
  • Problem: File grew from 403 to 450 lines (+47), exceeding the 20-line monolith growth guardrail. New SSRF preflight integration logic added without extraction.
  • Impact: Blocks merge per repo policy. Continued growth makes file harder to test, review, and maintain.
  • Required action: Extract the new SSRF preflight integration logic into a separate module (e.g., inference-preflight.ts) or reduce other code to stay within 20-line growth limit.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: wc -l src/lib/onboard/setup-inference.ts — should be ≤423 after extraction
  • Missing regression test: N/A — file-size guardrail enforcement
  • Done when: The required change is committed and verification passes: wc -l src/lib/onboard/setup-inference.ts — should be ≤423 after extraction.
  • Evidence: Diff stat shows +47 lines; new SSRF preflight integration in validateCustomOpenAiLikeSelection/validateCustomAnthropicSelection

PRA-9 Required — Test file monolith growth +88 lines exceeds 20-line guardrail

  • Location: src/lib/adapters/http/probe.test.ts:1
  • Category: architecture
  • Problem: Test file grew from 1146 to ~1234 lines (+88), exceeding the 20-line monolith growth guardrail. New SSRF proxy-bypass test cases added without extraction.
  • Impact: Blocks merge per repo policy. Continued growth makes file harder to test, review, and maintain.
  • Required action: Extract the new SSRF proxy-bypass test cases into a separate test file (e.g., probe-ssrf-preflight.test.ts) or reduce other coverage to stay within 20-line growth limit.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: wc -l src/lib/adapters/http/probe.test.ts — should be ≤1166 after extraction
  • Missing regression test: N/A — file-size guardrail enforcement
  • Done when: The required change is committed and verification passes: wc -l src/lib/adapters/http/probe.test.ts — should be ≤1166 after extraction.
  • Evidence: Diff stat shows +88 lines; new tests: 'bypasses ambient proxies when --resolve pins the validated origin' and 'bypasses ambient proxies for approved no-pin origin'

PRA-10 Required — Monolith growth +28 lines exceeds 20-line guardrail

  • Location: src/lib/inference/onboard-probes.ts:1
  • Category: architecture
  • Problem: File grew from 948 to ~976 lines (+28), exceeding the 20-line monolith growth guardrail. New SSRF preflight/pinnedAddresses logic added without extraction.
  • Impact: Blocks merge per repo policy. Continued growth makes file harder to test, review, and maintain.
  • Required action: Extract the new SSRF preflight/pinnedAddresses logic into a separate module or reduce other code to stay within 20-line growth limit.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: wc -l src/lib/inference/onboard-probes.ts — should be ≤968 after extraction
  • Missing regression test: N/A — file-size guardrail enforcement
  • Done when: The required change is committed and verification passes: wc -l src/lib/inference/onboard-probes.ts — should be ≤968 after extraction.
  • Evidence: Diff stat shows +28 lines; new pinnedAddresses propagation through probeOpenAiLikeEndpoint, probeAnthropicEndpoint

PRA-11 Required — Monolith growth +31 lines exceeds 20-line guardrail

  • Location: src/lib/adapters/http/probe.ts:1
  • Category: architecture
  • Problem: File grew from 819 to ~850 lines (+31), exceeding the 20-line monolith growth guardrail. New proxy-bypass logic for --resolve added without extraction.
  • Impact: Blocks merge per repo policy. Continued growth makes file harder to test, review, and maintain.
  • Required action: Extract the new proxy-bypass logic for --resolve into a separate helper or reduce other code to stay within 20-line growth limit.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: wc -l src/lib/adapters/http/probe.ts — should be ≤839 after extraction
  • Missing regression test: N/A — file-size guardrail enforcement
  • Done when: The required change is committed and verification passes: wc -l src/lib/adapters/http/probe.ts — should be ≤839 after extraction.
  • Evidence: Diff stat shows +31 lines; resolveCurlProbeSpawnEnv now deletes proxy env vars when pinnedAddresses defined

PRA-12 Resolve/justify — Significant growth +82 lines not flagged by test-file guardrail

  • Location: src/lib/onboard/inference-selection-validation.ts:1
  • Category: architecture
  • Problem: Source file grew from 292 to 374 lines (+82). SSRF preflight integration logic adds substantial complexity without extraction.
  • Impact: Architecture maintainability debt. File becoming harder to review and test as SSRF logic mixes with validation orchestration.
  • Recommended action: Consider extracting SSRF preflight integration into a dedicated module to contain growth.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: wc -l src/lib/onboard/inference-selection-validation.ts — review whether extraction is feasible
  • Missing regression test: N/A — architecture maintainability
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: wc -l src/lib/onboard/inference-selection-validation.ts — review whether extraction is feasible.
  • Evidence: Diff stat shows +82 lines; new resolveEndpointHost injection, pinnedAddresses return values

PRA-13 Resolve/justify — Double-negative SSRF guard readability — extract isTrustedSandboxBridge helper

  • Location: src/lib/inference/onboard-probes.ts:634
  • Category: security
  • Problem: Double-negative SSRF guard: `isPrivateHostname(probeHostname) && !isLoopbackHostname(probeHostname) && !isHijackedDockerInternalUrl(endpointUrl)`. This mirrors the same pattern in endpoint-ssrf-preflight.ts but isn't extracted to a shared helper.
  • Impact: Reduced readability and maintainability of security-critical guard. Duplication increases risk of divergent fixes. Test coverage request for helper cannot be satisfied until extracted.
  • Recommended action: Extract `isTrustedSandboxBridge(endpointUrl)` returning true for sandbox-internal hosts (host.openshell.internal) and hijacked docker-internal alias. Guard becomes: `if (isPrivateHostname(hostname) && !isLoopbackHostname(hostname) && !isTrustedSandboxBridge(endpointUrl))`. This also satisfies test coverage request for the helper.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: grep -n 'isTrustedSandboxBridge' src/lib/inference/onboard-probes.ts — should exist after extraction
  • Missing regression test: Unit tests for isTrustedSandboxBridge helper covering sandbox-internal hosts, docker-internal alias, and private LAN addresses
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: grep -n 'isTrustedSandboxBridge' src/lib/inference/onboard-probes.ts — should exist after extraction.
  • Evidence: Line 634 in onboard-probes.ts; similar pattern in endpoint-ssrf-preflight.ts:37-41

PRA-14 Resolve/justify — Module-level autoDetectedCompatibleContextWindow duplicates Ollama pattern without shared helper

  • Location: src/lib/inference/compatible-endpoint-context.ts:156
  • Category: architecture
  • Problem: Module-level variable `autoDetectedCompatibleContextWindow` duplicates Ollama pattern (autoDetectedOllamaContextWindow in ollama-runtime-context.ts) without shared helper. Third provider adopting same pattern would triple the duplication.
  • Impact: Code duplication across providers. Increases maintenance burden and risk of inconsistent behavior. TODO references parent issue instead of dedicated follow-up.
  • Recommended action: Either extract a shared `trackAutoDetectedContextWindow` helper used by both Ollama and compatible-endpoint probes, or document why the duplication is acceptable and when it can be removed. File follow-up issue for extraction.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: grep -n 'autoDetected.*ContextWindow' src/lib/inference/ollama-runtime-context.ts src/lib/inference/compatible-endpoint-context.ts — should share a helper or have documented follow-up
  • Missing regression test: N/A — code duplication tracking
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: grep -n 'autoDetected.*ContextWindow' src/lib/inference/ollama-runtime-context.ts src/lib/inference/compatible-endpoint-context.ts — should share a helper or have documented follow-up.
  • Evidence: Line 156 in compatible-endpoint-context.ts; ollama-runtime-context.ts has autoDetectedOllamaContextWindow at similar scope

PRA-15 Resolve/justify — TODO(#6177) references parent issue instead of dedicated follow-up for helper extraction

  • Location: src/lib/inference/compatible-endpoint-context.ts:152
  • Category: correctness
  • Problem: TODO comment at line 152 references parent issue [DGX Spark][Inference] vLLM compatible-endpoint: context window falls back to ~4K for NemotronH models — agent unusable #6177 instead of dedicated follow-up for extracting trackAutoDetectedContextWindow helper. Parent issue is about context window propagation, not helper extraction.
  • Impact: Issue tracking hygiene — helper extraction work not tracked separately, may be forgotten.
  • Recommended action: Create dedicated follow-up issue for extracting trackAutoDetectedContextWindow helper. Update TODO comment with new issue number.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: grep -n 'TODO.*6177' src/lib/inference/compatible-endpoint-context.ts — should reference dedicated follow-up issue
  • Missing regression test: N/A — issue tracking hygiene
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: grep -n 'TODO.*6177' src/lib/inference/compatible-endpoint-context.ts — should reference dedicated follow-up issue.
  • Evidence: Line 152: `// TODO([DGX Spark][Inference] vLLM compatible-endpoint: context window falls back to ~4K for NemotronH models — agent unusable #6177): this auto-state tracking mirrors the Ollama contract...`

PRA-16 Resolve/justify — Missing idempotency test for NEMOCLAW_CONTEXT_WINDOW dockerfile-patch

  • Location: src/lib/onboard/dockerfile-patch-hermes-context.test.ts:1
  • Category: tests
  • Problem: No test verifies that patching the Dockerfile twice with the same context window leaves the ARG unchanged (idempotent). Critical for CI/CD where patch may run multiple times.
  • Impact: Regression risk: dockerfile-patch could accumulate changes or behave differently on second run.
  • Recommended action: Add test case: patch with context window, patch again, assert ARG unchanged.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: grep -n 'patch again' src/lib/onboard/dockerfile-patch-hermes-context.test.ts — should find idempotency test
  • Missing regression test: Test: patch with context window, patch again, assert ARG unchanged
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: grep -n 'patch again' src/lib/onboard/dockerfile-patch-hermes-context.test.ts — should find idempotency test.
  • Evidence: Test file has 6 cases but none test double-patch idempotency

PRA-17 Resolve/justify — Hermes Dockerfile build not tested end-to-end with NEMOCLAW_CONTEXT_WINDOW

  • Location: agents/hermes/Dockerfile:280
  • Category: tests
  • Problem: The ARG NEMOCLAW_CONTEXT_WINDOW is added to Dockerfile and promoted to ENV, read by build-env.ts, and written as model.context_length in config.yaml. No e2e test verifies the full chain.
  • Impact: Integration gap: Dockerfile ARG → build-env → hermes-config → config.yaml chain untested. Could silently fail if any step breaks.
  • Recommended action: Add e2e test that builds Hermes image with NEMOCLAW_CONTEXT_WINDOW=65536 and verifies generated config.yaml contains model.context_length: 65536.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: grep -r 'NEMOCLAW_CONTEXT_WINDOW' test/e2e/ — should find e2e build test
  • Missing regression test: E2E test: build Hermes image with NEMOCLAW_CONTEXT_WINDOW=65536, verify config.yaml has model.context_length: 65536
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: grep -r 'NEMOCLAW_CONTEXT_WINDOW' test/e2e/ — should find e2e build test.
  • Evidence: Dockerfile line 280 adds ARG NEMOCLAW_CONTEXT_WINDOW=; build-env.ts reads it; hermes-config.ts writes model.context_length

PRA-18 Resolve/justify — Private-address SSRF guard tests should verify extracted isTrustedSandboxBridge helper

  • Location: src/lib/inference/onboard-probes.test.ts:232
  • Category: tests
  • Problem: Private-address SSRF guard tests directly test the inline double-negative guard. No isTrustedSandboxBridge helper exists yet (PRA-9), so tests cannot verify the extracted helper.
  • Impact: Test coverage for helper extraction blocked. Once PRA-9 is done, tests must be updated to verify the helper.
  • Recommended action: Add unit tests for isTrustedSandboxBridge helper covering sandbox-internal hosts, docker-internal alias, and private LAN addresses. This depends on PRA-9 extraction.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: grep -n 'isTrustedSandboxBridge' src/lib/inference/onboard-probes.test.ts — should find helper tests after PRA-9 extraction
  • Missing regression test: Unit tests for isTrustedSandboxBridge helper covering sandbox-internal hosts, docker-internal alias, and private LAN addresses
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: grep -n 'isTrustedSandboxBridge' src/lib/inference/onboard-probes.test.ts — should find helper tests after PRA-9 extraction.
  • Evidence: Test file lines 232+ test private-address rejection but test the inline guard, not a helper

PRA-19 Resolve/justify — Wrapper test file reduced 159 lines — verify changes required for current PR scope

PRA-20 Improvement — OPENSHELL_MANAGED_HOSTS string-match exemption could use DNS preflight with allowlist

  • Location: src/lib/inference/endpoint-ssrf-preflight.ts:40
  • Category: security
  • Problem: OPENSHELL_MANAGED_HOSTS exemption uses string match without validating they resolve to expected addresses. If an attacker controls DNS for inference.local, they could rebind to private addresses.
  • Impact: Potential SSRF bypass if managed host DNS is compromised. Current exemption is blanket — no validation of resolved addresses.
  • Suggested action: For managed hosts, run DNS preflight but allowlist the expected resolved addresses (loopback, proxy IP) instead of blanket exemption. This maintains SSRF protection while supporting legitimate managed aliases.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check assertEndpointResolvesPublic for managed hosts — should resolve and validate against allowlist
  • Missing regression test: Test: managed host resolving to unexpected address is refused
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Lines 27-41: OPENSHELL_MANAGED_HOSTS set and isOpenShellManagedHost exempts before DNS resolution

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 6, 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: Exported remote OpenAI-surface provider setup capability.
Open items: 0 required · 8 warnings · 0 suggestions · 8 test follow-ups
Since last review: 3 prior items resolved · 4 still apply · 0 new items found

Action checklist

  • PRA-1 Resolve or justify: Source-of-truth review needed: Exported remote OpenAI-surface provider setup capability
  • PRA-2 Resolve or justify: Source-of-truth review needed: Literal private endpoint policy in `probeOpenAiLikeEndpoint()`
  • PRA-3 Resolve or justify: Source-of-truth review needed: Hermes `model.context_length` config generation
  • PRA-4 Resolve or justify: Source-of-truth review needed: Remote model validator context-window side effect
  • PRA-5 Resolve or justify: OpenAI-surface setup still accepts an optional preflight capability in src/lib/onboard/inference-providers/remote.ts:124
  • PRA-6 Resolve or justify: Private endpoint policy remains embedded in the untyped probe monolith in src/lib/inference/onboard-probes.ts:603
  • PRA-7 Resolve or justify: Remote model validator still hard-codes the compatible context side effect in src/lib/onboard/setup-nim-selection.ts:231
  • PRA-8 Resolve or justify: Hermes context_length acceptance is still only partially proven in test/generate-hermes-config.test.ts:514
  • 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: Remote model validator still hard-codes the compatible context side effect
  • PRA-T7 Add or justify test follow-up: Acceptance clause
  • PRA-T8 Add or justify test follow-up: Acceptance clause

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 Resolve/justify security src/lib/onboard/inference-providers/remote.ts:124 Make this boundary fail closed: require a structured capability such as `{ kind: "preflighted", pinnedAddresses: string[] } | { kind: "trusted-no-pin" }`, or run `assertEndpointResolvesPublic()` inside the OpenAI-surface branch whenever no capability is supplied. Preserve the Bedrock Runtime exception and OpenShell-managed/loopback trusted-no-pin behavior.
PRA-6 Resolve/justify architecture src/lib/inference/onboard-probes.ts:603 Extract the literal endpoint safety decision into a typed helper near `endpoint-ssrf-preflight.ts` that returns a structured allow/deny result and reason. Keep `onboard-probes.ts` responsible only for translating that result into the existing probe failure shape and running the curl probe flow.
PRA-7 Resolve/justify tests src/lib/onboard/setup-nim-selection.ts:231 Add an optional `applyCompatibleEndpointContextWindow` dependency to `RemoteModelValidatorDeps`, default it to the production function, and call `deps.applyCompatibleEndpointContextWindow(...)` in the custom success path. Keep the production SSRF/context validation unchanged in the default implementation.
PRA-8 Resolve/justify acceptance test/generate-hermes-config.test.ts:514 Extend the generated-config regression for `NEMOCLAW_CONTEXT_WINDOW=65536` to assert `config.auxiliary?.compression?.context_length` is absent and `config.auxiliary.curator` remains exactly the baseline curator config. If a maintained Hermes config-loader/parser harness exists in this repo, add a narrow proof that NemotronH with only `model.context_length=65536` is accepted; otherwise document in the test why that runtime proof is external.
Review findings by urgency: 0 required fixes, 8 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: Exported remote OpenAI-surface provider setup capability

  • 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: No current test covers omitted capability; `remote-openai-surface.test.ts` always passes `pinnedAddresses: ["93.184.216.34"]`.
  • 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: Covered by the security finding for `src/lib/onboard/inference-providers/remote.ts`.

PRA-2 Resolve/justify — Source-of-truth review needed: Literal private endpoint policy in `probeOpenAiLikeEndpoint()`

  • 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: `onboard-probes.test.ts` covers LAN, link-local, and loopback behavior indirectly; focused typed-helper tests are still missing.
  • 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: Covered by the architecture finding for `src/lib/inference/onboard-probes.ts`.

PRA-3 Resolve/justify — Source-of-truth review needed: Hermes `model.context_length` config generation

  • 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: `generate-hermes-config.test.ts` asserts `model.context_length` and no `model.context_window`, but not auxiliary compression absence and curator stability in the context-window case.
  • 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: Covered by the acceptance finding for `test/generate-hermes-config.test.ts`.

PRA-4 Resolve/justify — Source-of-truth review needed: Remote model validator context-window side effect

  • 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: Existing tests cover production helper behavior and higher-level stale-clearing, but not the validator caller contract through an injected applier.
  • 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: Covered by the tests finding for `src/lib/onboard/setup-nim-selection.ts`.

PRA-5 Resolve/justify — OpenAI-surface setup still accepts an optional preflight capability

  • Location: src/lib/onboard/inference-providers/remote.ts:124
  • Category: security
  • Problem: `setupRemoteProviderInference()` accepts `pinnedAddresses?: readonly string[]` and the compatible-Anthropic OpenAI-surface branch passes that optional value into `probeOpenAiSurface()`. The normal `setup-inference.ts` orchestrator now runs `assertEndpointResolvesPublic()` when no pins are supplied, but this exported helper still cannot distinguish a preflighted public endpoint, an explicit trusted no-pin endpoint, and an accidentally omitted capability.
  • Impact: A direct or future caller can run a credentialed compatible-Anthropic `/v1/chat/completions` probe without DNS-backed SSRF preflight, curl `--resolve` pinning, or ambient proxy bypass. That reopens DNS rebinding or proxy-controlled origin selection at an inference credential boundary.
  • Recommended action: Make this boundary fail closed: require a structured capability such as `{ kind: "preflighted", pinnedAddresses: string[] } | { kind: "trusted-no-pin" }`, or run `assertEndpointResolvesPublic()` inside the OpenAI-surface branch whenever no capability is supplied. Preserve the Bedrock Runtime exception and OpenShell-managed/loopback trusted-no-pin behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `src/lib/onboard/setup-inference.ts` around the `assertEndpointResolvesPublic()` backstop and `src/lib/onboard/inference-providers/remote.ts` around the `useOpenAiSurface` branch; confirm there is no path from user-controlled `endpointUrl` to `probeOpenAiSurface()` with an undefined endpoint capability.
  • Missing regression test: Add `remote-openai-surface.test.ts` coverage named `setupRemoteProviderInference fails closed or self-preflights compatible-Anthropic OpenAI-surface setup when no endpoint capability is supplied`, using an injected resolver/probe to prove the credentialed probe is not invoked until the capability is established.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `src/lib/onboard/setup-inference.ts` around the `assertEndpointResolvesPublic()` backstop and `src/lib/onboard/inference-providers/remote.ts` around the `useOpenAiSurface` branch; confirm there is no path from user-controlled `endpointUrl` to `probeOpenAiSurface()` with an undefined endpoint capability.
  • Evidence: `remote.ts` destructures `pinnedAddresses` from args and calls `probeOpenAiSurface(openAiSurfaceBaseUrl, model, credentialValue, { skipResponsesProbe: true, pinnedAddresses })`; current `remote-openai-surface.test.ts` helper always supplies `["93.184.216.34"]`, so the omitted-capability path is not proven.

PRA-6 Resolve/justify — Private endpoint policy remains embedded in the untyped probe monolith

  • Location: src/lib/inference/onboard-probes.ts:603
  • Category: architecture
  • Problem: The literal private/internal endpoint decision remains inside `probeOpenAiLikeEndpoint()` in the large `onboard-probes.ts` module. The asynchronous DNS preflight now protects the normal custom-endpoint caller paths, but this synchronous fallback policy is still a security decision encoded in a monolith rather than a typed, focused helper near `endpoint-ssrf-preflight.ts`.
  • Impact: Future probe call sites or refactors can drift between the DNS preflight, literal private-host rejection, loopback/OpenShell-managed exceptions, and failure-shape translation. Drift in this area can either block legitimate local inference or weaken SSRF defenses.
  • Recommended action: Extract the literal endpoint safety decision into a typed helper near `endpoint-ssrf-preflight.ts` that returns a structured allow/deny result and reason. Keep `onboard-probes.ts` responsible only for translating that result into the existing probe failure shape and running the curl probe flow.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect `src/lib/inference/onboard-probes.ts` around `probeOpenAiLikeEndpoint()` and confirm that private-host policy is no longer hand-coded there; the only remaining code should call a focused helper and map its result to the existing probe response.
  • Missing regression test: Add focused helper tests for `rejects non-loopback private LAN`, `rejects link-local metadata`, `allows loopback`, and `allows OpenShell-managed host aliases`; the existing `onboard-probes.test.ts` cases can then assert only translation into the probe failure shape.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect `src/lib/inference/onboard-probes.ts` around `probeOpenAiLikeEndpoint()` and confirm that private-host policy is no longer hand-coded there; the only remaining code should call a focused helper and map its result to the existing probe response.
  • Evidence: `onboard-probes.ts` still computes `probeHostname`, calls `isPrivateHostname()`/`isLoopbackHostname()`, checks `isHijackedDockerInternalUrl()`, and builds the private-endpoint failure inline.

PRA-7 Resolve/justify — Remote model validator still hard-codes the compatible context side effect

  • Location: src/lib/onboard/setup-nim-selection.ts:231
  • Category: tests
  • Problem: `createRemoteModelValidator()` imports and calls `applyCompatibleEndpointContextWindow()` directly in the custom OpenAI-compatible success path. That makes the validator harder to unit-test as a pure caller/callee boundary and forces tests to exercise production network-preflight/context logic instead of verifying the orchestration contract through an injected dependency.
  • Impact: A regression in the validator's contract could be hidden by broad integration tests or by production side effects. It also makes retry/model-selection tests more brittle because they must carry the real context-probe dependency even when they only need to assert that the validator invokes it on custom success.
  • Recommended action: Add an optional `applyCompatibleEndpointContextWindow` dependency to `RemoteModelValidatorDeps`, default it to the production function, and call `deps.applyCompatibleEndpointContextWindow(...)` in the custom success path. Keep the production SSRF/context validation unchanged in the default implementation.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `src/lib/onboard/setup-nim-selection.ts` around the `selected.key === "custom"` success path and confirm the context-window function is obtained from deps rather than the module import.
  • Missing regression test: Add `setup-nim-selection.test.ts` coverage named `custom compatible endpoint success invokes the injected context-window applier with endpoint, model, and credential env`, and `custom compatible endpoint validation failure does not invoke the context-window applier`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `src/lib/onboard/setup-nim-selection.ts` around the `selected.key === "custom"` success path and confirm the context-window function is obtained from deps rather than the module import.
  • Evidence: The file imports `applyCompatibleEndpointContextWindow` at module scope and calls it directly with `{ credentialEnv: selectedCredentialEnv }`; existing context-window tests cover the production helper, not the validator's injectable caller contract.

PRA-8 Resolve/justify — Hermes context_length acceptance is still only partially proven

  • Location: test/generate-hermes-config.test.ts:514
  • Category: acceptance
  • Problem: The linked issue asks for Hermes to run with a 65K context window rather than the small NemotronH fallback. The PR now asserts `model.context_length` and absence of `model.context_window`, but the prior review's narrower contract is still incomplete: the context-window case does not assert that no auxiliary compression context key is emitted and that the baseline auxiliary curator config remains unchanged.
  • Impact: A later config-generation change could add an ineffective or conflicting auxiliary/compression context setting, or mutate curator config, while the current context tests still pass. That would leave the Hermes runtime acceptance of the intended single `model.context_length` override less certain.
  • Recommended action: Extend the generated-config regression for `NEMOCLAW_CONTEXT_WINDOW=65536` to assert `config.auxiliary?.compression?.context_length` is absent and `config.auxiliary.curator` remains exactly the baseline curator config. If a maintained Hermes config-loader/parser harness exists in this repo, add a narrow proof that NemotronH with only `model.context_length=65536` is accepted; otherwise document in the test why that runtime proof is external.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect `test/generate-hermes-config.test.ts` around the `bakes NEMOCLAW_CONTEXT_WINDOW as model.context_length` test and confirm it covers auxiliary compression absence and curator stability in the same generated config.
  • Missing regression test: Add assertions to the existing `bakes NEMOCLAW_CONTEXT_WINDOW as model.context_length so Hermes cannot downgrade it` test, or add a new `does not write auxiliary compression context when model.context_length is set` test.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect `test/generate-hermes-config.test.ts` around the `bakes NEMOCLAW_CONTEXT_WINDOW as model.context_length` test and confirm it covers auxiliary compression absence and curator stability in the same generated config.
  • Evidence: Current tests at `test/generate-hermes-config.test.ts` assert `config.model.context_length === 65536` and `config.model.context_window` is undefined; baseline curator assertions exist in a separate default-config test but are not tied to the context-window case.

💡 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.
Simplification opportunities: 1 possible cut

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

  • PRA-6 shrink (src/lib/inference/onboard-probes.ts:603): Inline private/internal endpoint policy branch inside `probeOpenAiLikeEndpoint()`.
    • Replacement: A typed `classifyEndpointProbeSafety()`/`validateLiteralEndpointSafety()` helper shared with the SSRF preflight module, plus thin failure-shape translation in `onboard-probes.ts`.
    • Safety boundary: Do not remove or weaken literal private-host rejection, loopback allowance, OpenShell-managed alias handling, DNS preflight, curl pinning, or credential redaction.
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 — setupRemoteProviderInference fails closed or self-preflights compatible-Anthropic OpenAI-surface setup when no endpoint capability is supplied. Unit/integration coverage is broad for the new endpoint probe and SSRF defenses, but this PR changes runtime/sandbox-sensitive Hermes Dockerfile/config generation, Hermes strict-hash reconciliation, curl subprocess trust boundaries, and generated runtime behavior. A small amount of targeted runtime validation remains useful without relying on external E2E job status.
  • PRA-T2 Runtime validation — custom compatible endpoint success invokes the injected context-window applier with endpoint, model, and credential env. Unit/integration coverage is broad for the new endpoint probe and SSRF defenses, but this PR changes runtime/sandbox-sensitive Hermes Dockerfile/config generation, Hermes strict-hash reconciliation, curl subprocess trust boundaries, and generated runtime behavior. A small amount of targeted runtime validation remains useful without relying on external E2E job status.
  • PRA-T3 Runtime validation — custom compatible endpoint validation failure does not invoke the context-window applier. Unit/integration coverage is broad for the new endpoint probe and SSRF defenses, but this PR changes runtime/sandbox-sensitive Hermes Dockerfile/config generation, Hermes strict-hash reconciliation, curl subprocess trust boundaries, and generated runtime behavior. A small amount of targeted runtime validation remains useful without relying on external E2E job status.
  • PRA-T4 Runtime validation — Hermes config generation with NEMOCLAW_CONTEXT_WINDOW=65536 emits model.context_length only and leaves auxiliary compression context absent and auxiliary curator unchanged. Unit/integration coverage is broad for the new endpoint probe and SSRF defenses, but this PR changes runtime/sandbox-sensitive Hermes Dockerfile/config generation, Hermes strict-hash reconciliation, curl subprocess trust boundaries, and generated runtime behavior. A small amount of targeted runtime validation remains useful without relying on external E2E job status.
  • PRA-T5 Runtime validation — A maintained Hermes config parser or wrapper harness accepts a NemotronH config containing only model.context_length=65536, or the test documents why that runtime proof is external. Unit/integration coverage is broad for the new endpoint probe and SSRF defenses, but this PR changes runtime/sandbox-sensitive Hermes Dockerfile/config generation, Hermes strict-hash reconciliation, curl subprocess trust boundaries, and generated runtime behavior. A small amount of targeted runtime validation remains useful without relying on external E2E job status.
  • PRA-T6 Remote model validator still hard-codes the compatible context side effect — Add an optional `applyCompatibleEndpointContextWindow` dependency to `RemoteModelValidatorDeps`, default it to the production function, and call `deps.applyCompatibleEndpointContextWindow(...)` in the custom success path. Keep the production SSRF/context validation unchanged in the default implementation.
  • PRA-T7 Acceptance clause — When onboarding a Hermes sandbox with `NEMOCLAW_PROVIDER=custom` and a local vLLM endpoint serving `nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4` (NemotronH architecture), the agent immediately fails with **"Context length exceeded (4,181 tokens). Cannot compress further."** The runtime context window is detected as ~4K despite the model's `max_position_embeddings=262144` and vLLM's `max_model_len=65536`. — add test evidence or identify existing coverage. `compatible-endpoint-context.ts` probes `/v1/models` and sets `NEMOCLAW_CONTEXT_WINDOW`; `setup-nim-selection.ts` wires it after custom endpoint validation; `compatible-endpoint-context.test.ts`, `test/compatible-endpoint-context-probe.test.ts`, and `generate-hermes-config.test.ts` prove max_model_len reaches generated `model.context_length`. A live Hermes chat/runtime proof for the reported exception is not present in the repo tests.
  • PRA-T8 Acceptance clause — Expected Result: Agent responds normally with 65K context window. — add test evidence or identify existing coverage. Generated config now includes `model.context_length: 65536` and omits ignored `context_window`; however, the repo tests do not exercise a live Hermes chat/runtime with the NemotronH model and 65K prompt budget.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: Exported remote OpenAI-surface provider setup capability

  • 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: No current test covers omitted capability; `remote-openai-surface.test.ts` always passes `pinnedAddresses: ["93.184.216.34"]`.
  • 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: Covered by the security finding for `src/lib/onboard/inference-providers/remote.ts`.

PRA-2 Resolve/justify — Source-of-truth review needed: Literal private endpoint policy in `probeOpenAiLikeEndpoint()`

  • 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: `onboard-probes.test.ts` covers LAN, link-local, and loopback behavior indirectly; focused typed-helper tests are still missing.
  • 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: Covered by the architecture finding for `src/lib/inference/onboard-probes.ts`.

PRA-3 Resolve/justify — Source-of-truth review needed: Hermes `model.context_length` config generation

  • 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: `generate-hermes-config.test.ts` asserts `model.context_length` and no `model.context_window`, but not auxiliary compression absence and curator stability in the context-window case.
  • 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: Covered by the acceptance finding for `test/generate-hermes-config.test.ts`.

PRA-4 Resolve/justify — Source-of-truth review needed: Remote model validator context-window side effect

  • 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: Existing tests cover production helper behavior and higher-level stale-clearing, but not the validator caller contract through an injected applier.
  • 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: Covered by the tests finding for `src/lib/onboard/setup-nim-selection.ts`.

PRA-5 Resolve/justify — OpenAI-surface setup still accepts an optional preflight capability

  • Location: src/lib/onboard/inference-providers/remote.ts:124
  • Category: security
  • Problem: `setupRemoteProviderInference()` accepts `pinnedAddresses?: readonly string[]` and the compatible-Anthropic OpenAI-surface branch passes that optional value into `probeOpenAiSurface()`. The normal `setup-inference.ts` orchestrator now runs `assertEndpointResolvesPublic()` when no pins are supplied, but this exported helper still cannot distinguish a preflighted public endpoint, an explicit trusted no-pin endpoint, and an accidentally omitted capability.
  • Impact: A direct or future caller can run a credentialed compatible-Anthropic `/v1/chat/completions` probe without DNS-backed SSRF preflight, curl `--resolve` pinning, or ambient proxy bypass. That reopens DNS rebinding or proxy-controlled origin selection at an inference credential boundary.
  • Recommended action: Make this boundary fail closed: require a structured capability such as `{ kind: "preflighted", pinnedAddresses: string[] } | { kind: "trusted-no-pin" }`, or run `assertEndpointResolvesPublic()` inside the OpenAI-surface branch whenever no capability is supplied. Preserve the Bedrock Runtime exception and OpenShell-managed/loopback trusted-no-pin behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `src/lib/onboard/setup-inference.ts` around the `assertEndpointResolvesPublic()` backstop and `src/lib/onboard/inference-providers/remote.ts` around the `useOpenAiSurface` branch; confirm there is no path from user-controlled `endpointUrl` to `probeOpenAiSurface()` with an undefined endpoint capability.
  • Missing regression test: Add `remote-openai-surface.test.ts` coverage named `setupRemoteProviderInference fails closed or self-preflights compatible-Anthropic OpenAI-surface setup when no endpoint capability is supplied`, using an injected resolver/probe to prove the credentialed probe is not invoked until the capability is established.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `src/lib/onboard/setup-inference.ts` around the `assertEndpointResolvesPublic()` backstop and `src/lib/onboard/inference-providers/remote.ts` around the `useOpenAiSurface` branch; confirm there is no path from user-controlled `endpointUrl` to `probeOpenAiSurface()` with an undefined endpoint capability.
  • Evidence: `remote.ts` destructures `pinnedAddresses` from args and calls `probeOpenAiSurface(openAiSurfaceBaseUrl, model, credentialValue, { skipResponsesProbe: true, pinnedAddresses })`; current `remote-openai-surface.test.ts` helper always supplies `["93.184.216.34"]`, so the omitted-capability path is not proven.

PRA-6 Resolve/justify — Private endpoint policy remains embedded in the untyped probe monolith

  • Location: src/lib/inference/onboard-probes.ts:603
  • Category: architecture
  • Problem: The literal private/internal endpoint decision remains inside `probeOpenAiLikeEndpoint()` in the large `onboard-probes.ts` module. The asynchronous DNS preflight now protects the normal custom-endpoint caller paths, but this synchronous fallback policy is still a security decision encoded in a monolith rather than a typed, focused helper near `endpoint-ssrf-preflight.ts`.
  • Impact: Future probe call sites or refactors can drift between the DNS preflight, literal private-host rejection, loopback/OpenShell-managed exceptions, and failure-shape translation. Drift in this area can either block legitimate local inference or weaken SSRF defenses.
  • Recommended action: Extract the literal endpoint safety decision into a typed helper near `endpoint-ssrf-preflight.ts` that returns a structured allow/deny result and reason. Keep `onboard-probes.ts` responsible only for translating that result into the existing probe failure shape and running the curl probe flow.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect `src/lib/inference/onboard-probes.ts` around `probeOpenAiLikeEndpoint()` and confirm that private-host policy is no longer hand-coded there; the only remaining code should call a focused helper and map its result to the existing probe response.
  • Missing regression test: Add focused helper tests for `rejects non-loopback private LAN`, `rejects link-local metadata`, `allows loopback`, and `allows OpenShell-managed host aliases`; the existing `onboard-probes.test.ts` cases can then assert only translation into the probe failure shape.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect `src/lib/inference/onboard-probes.ts` around `probeOpenAiLikeEndpoint()` and confirm that private-host policy is no longer hand-coded there; the only remaining code should call a focused helper and map its result to the existing probe response.
  • Evidence: `onboard-probes.ts` still computes `probeHostname`, calls `isPrivateHostname()`/`isLoopbackHostname()`, checks `isHijackedDockerInternalUrl()`, and builds the private-endpoint failure inline.

PRA-7 Resolve/justify — Remote model validator still hard-codes the compatible context side effect

  • Location: src/lib/onboard/setup-nim-selection.ts:231
  • Category: tests
  • Problem: `createRemoteModelValidator()` imports and calls `applyCompatibleEndpointContextWindow()` directly in the custom OpenAI-compatible success path. That makes the validator harder to unit-test as a pure caller/callee boundary and forces tests to exercise production network-preflight/context logic instead of verifying the orchestration contract through an injected dependency.
  • Impact: A regression in the validator's contract could be hidden by broad integration tests or by production side effects. It also makes retry/model-selection tests more brittle because they must carry the real context-probe dependency even when they only need to assert that the validator invokes it on custom success.
  • Recommended action: Add an optional `applyCompatibleEndpointContextWindow` dependency to `RemoteModelValidatorDeps`, default it to the production function, and call `deps.applyCompatibleEndpointContextWindow(...)` in the custom success path. Keep the production SSRF/context validation unchanged in the default implementation.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `src/lib/onboard/setup-nim-selection.ts` around the `selected.key === "custom"` success path and confirm the context-window function is obtained from deps rather than the module import.
  • Missing regression test: Add `setup-nim-selection.test.ts` coverage named `custom compatible endpoint success invokes the injected context-window applier with endpoint, model, and credential env`, and `custom compatible endpoint validation failure does not invoke the context-window applier`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `src/lib/onboard/setup-nim-selection.ts` around the `selected.key === "custom"` success path and confirm the context-window function is obtained from deps rather than the module import.
  • Evidence: The file imports `applyCompatibleEndpointContextWindow` at module scope and calls it directly with `{ credentialEnv: selectedCredentialEnv }`; existing context-window tests cover the production helper, not the validator's injectable caller contract.

PRA-8 Resolve/justify — Hermes context_length acceptance is still only partially proven

  • Location: test/generate-hermes-config.test.ts:514
  • Category: acceptance
  • Problem: The linked issue asks for Hermes to run with a 65K context window rather than the small NemotronH fallback. The PR now asserts `model.context_length` and absence of `model.context_window`, but the prior review's narrower contract is still incomplete: the context-window case does not assert that no auxiliary compression context key is emitted and that the baseline auxiliary curator config remains unchanged.
  • Impact: A later config-generation change could add an ineffective or conflicting auxiliary/compression context setting, or mutate curator config, while the current context tests still pass. That would leave the Hermes runtime acceptance of the intended single `model.context_length` override less certain.
  • Recommended action: Extend the generated-config regression for `NEMOCLAW_CONTEXT_WINDOW=65536` to assert `config.auxiliary?.compression?.context_length` is absent and `config.auxiliary.curator` remains exactly the baseline curator config. If a maintained Hermes config-loader/parser harness exists in this repo, add a narrow proof that NemotronH with only `model.context_length=65536` is accepted; otherwise document in the test why that runtime proof is external.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect `test/generate-hermes-config.test.ts` around the `bakes NEMOCLAW_CONTEXT_WINDOW as model.context_length` test and confirm it covers auxiliary compression absence and curator stability in the same generated config.
  • Missing regression test: Add assertions to the existing `bakes NEMOCLAW_CONTEXT_WINDOW as model.context_length so Hermes cannot downgrade it` test, or add a new `does not write auxiliary compression context when model.context_length is set` test.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect `test/generate-hermes-config.test.ts` around the `bakes NEMOCLAW_CONTEXT_WINDOW as model.context_length` test and confirm it covers auxiliary compression absence and curator stability in the same generated config.
  • Evidence: Current tests at `test/generate-hermes-config.test.ts` assert `config.model.context_length === 65536` and `config.model.context_window` is undefined; baseline curator assertions exist in a separate default-config test but are not tied to the context-window case.

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.

…ests

The codebase-growth-guardrails check forbids changed test files from adding
if statements. Rewrite the Hermes Dockerfile context-window test to drive
NEMOCLAW_CONTEXT_WINDOW by direct assignment with clearing beforeEach/afterEach
hooks (matching the sibling dockerfile-patch suites) instead of a branching
env helper, and reword a comment so it reads without "if".

Signed-off-by: Yimo Jiang <yimoj@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 (1)
test/compatible-endpoint-context-probe.test.ts (1)

34-57: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add local issue-ref suffix to individual test titles.

Both it(...) titles are missing the (#6177) suffix that the guideline requires, even though the describe block has it.

As per path instructions, test/**/*.test.{js,ts} should "use behavior-oriented titles with local issue refs in a final (#1234) suffix."

✏️ Proposed fix
-  it("reads max_model_len from a live /v1/models endpoint into NEMOCLAW_CONTEXT_WINDOW", async () => {
+  it("reads max_model_len from a live /v1/models endpoint into NEMOCLAW_CONTEXT_WINDOW (`#6177`)", async () => {
     ...
-  it("keeps the default context window when the endpoint omits max_model_len", async () => {
+  it("keeps the default context window when the endpoint omits max_model_len (`#6177`)", async () => {
🤖 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/compatible-endpoint-context-probe.test.ts` around lines 34 - 57, Add the
required local issue reference suffix to each individual test title in the
relevant `it(...)` cases within `compatible-endpoint-context-probe.test.ts`;
update both test names so they end with the `(`#6177`)` suffix, matching the
repository convention for behavior-oriented test titles, while leaving the test
logic and surrounding `describe` block unchanged.

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 `@docs/inference/switch-inference-providers.mdx`:
- Line 191: The paragraph in the OpenAI-compatible endpoint section combines
multiple sentences on one line, which breaks the one-sentence-per-line MDX style
used elsewhere. Update the text in this block so each sentence is on its own
line, keeping the content unchanged while preserving the surrounding formatting
and the references to NEMOCLAW_CONTEXT_WINDOW, /v1/models, and
model.context_length.

In `@src/lib/onboard/dockerfile-patch-hermes-context.test.ts`:
- Around line 46-56: The withContextWindowEnv helper in
dockerfile-patch-hermes-context.test.ts is duplicating environment restore logic
that already exists in the shared env-test-helpers utilities. Replace the manual
prior/save/delete branches with restoreEnv or restoreEnvBulk from
test/helpers/env-test-helpers.ts, and update the test setup/teardown around
withContextWindowEnv to use the shared helper so the conditional restore logic
is removed.

---

Nitpick comments:
In `@test/compatible-endpoint-context-probe.test.ts`:
- Around line 34-57: Add the required local issue reference suffix to each
individual test title in the relevant `it(...)` cases within
`compatible-endpoint-context-probe.test.ts`; update both test names so they end
with the `(`#6177`)` suffix, matching the repository convention for
behavior-oriented test titles, while leaving the test logic and surrounding
`describe` block unchanged.
🪄 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: a29414b1-099e-49c9-a591-6cb2d92b1336

📥 Commits

Reviewing files that changed from the base of the PR and between 9ebc888 and a9766b2.

📒 Files selected for processing (16)
  • agents/hermes/Dockerfile
  • agents/hermes/config/build-env.ts
  • agents/hermes/config/hermes-config.ts
  • docs/inference/switch-inference-providers.mdx
  • src/lib/inference/compatible-endpoint-context.test.ts
  • src/lib/inference/compatible-endpoint-context.ts
  • src/lib/inference/vllm-runtime-context.test.ts
  • src/lib/inference/vllm-runtime-context.ts
  • src/lib/onboard/dockerfile-patch-hermes-context.test.ts
  • src/lib/onboard/machine/handlers/provider-inference.ts
  • src/lib/onboard/setup-nim-selection.ts
  • test/compatible-endpoint-context-probe.test.ts
  • test/e2e/fixtures/fake-openai-compatible.ts
  • test/e2e/lib/fake-openai-compatible-api.mts
  • test/generate-hermes-config.test.ts
  • test/hermes-gateway-wrapper.test.ts

Comment thread docs/inference/switch-inference-providers.mdx Outdated
Comment thread src/lib/onboard/dockerfile-patch-hermes-context.test.ts Outdated
Apply PR review advisor feedback for #6177:
- Add a real-server test asserting the compatible-endpoint probe transmits the
  Authorization header through curl's --config temp file (the fake endpoint now
  records header presence without logging the token).
- Qualify the NEMOCLAW_CONTEXT_WINDOW docs default so OpenClaw's baked 131072
  and Hermes' unset/auto-detect behavior are both accurate.
- Document the vLLM auto-detect ceiling (4 MiB tokens, matches Ollama) and the
  host-side onboarding security model for the /v1/models probe.
- Note the Ollama-mirrored auto-state duplication for future extraction.

Signed-off-by: Yimo Jiang <yimoj@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/compatible-endpoint-context-probe.test.ts (1)

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

Missing local issue-ref suffix in test titles.

Per the repo's test-naming convention, only one of the three tests carries the (#6177) suffix. The other two ("reads max_model_len..." and "keeps the default context window...") lack the required issue reference.

As per coding guidelines: "Root-level integration tests under test/ should import source code, use ESM imports, and use behavior-oriented titles with local issue refs in a final (#1234) suffix."

✏️ Proposed fix
-  it("reads max_model_len from a live /v1/models endpoint into NEMOCLAW_CONTEXT_WINDOW", async () => {
+  it("reads max_model_len from a live /v1/models endpoint into NEMOCLAW_CONTEXT_WINDOW (`#6177`)", async () => {
-  it("keeps the default context window when the endpoint omits max_model_len", async () => {
+  it("keeps the default context window when the endpoint omits max_model_len (`#6177`)", async () => {

Also applies to: 70-70

🤖 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/compatible-endpoint-context-probe.test.ts` at line 34, The two
integration test titles in compatible-endpoint-context-probe.test.ts are missing
the required local issue-reference suffix. Update the behavior-oriented titles
in the relevant test cases (the ones for reading max_model_len into
NEMOCLAW_CONTEXT_WINDOW and keeping the default context window) so they match
the repo convention by ending with the same style of final issue ref suffix used
by the existing (`#6177`) test.

Source: Coding guidelines

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

Nitpick comments:
In `@test/compatible-endpoint-context-probe.test.ts`:
- Line 34: The two integration test titles in
compatible-endpoint-context-probe.test.ts are missing the required local
issue-reference suffix. Update the behavior-oriented titles in the relevant test
cases (the ones for reading max_model_len into NEMOCLAW_CONTEXT_WINDOW and
keeping the default context window) so they match the repo convention by ending
with the same style of final issue ref suffix used by the existing (`#6177`) test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 9904371b-ae32-4d43-b303-f4fb362b721a

📥 Commits

Reviewing files that changed from the base of the PR and between 44f0e00 and f9a62f9.

📒 Files selected for processing (6)
  • docs/inference/switch-inference-providers.mdx
  • src/lib/inference/compatible-endpoint-context.ts
  • src/lib/inference/vllm-runtime-context.ts
  • test/compatible-endpoint-context-probe.test.ts
  • test/e2e/fixtures/fake-openai-compatible.ts
  • test/e2e/lib/fake-openai-compatible-api.mts
✅ Files skipped from review due to trivial changes (1)
  • docs/inference/switch-inference-providers.mdx
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/lib/inference/vllm-runtime-context.ts
  • test/e2e/lib/fake-openai-compatible-api.mts
  • src/lib/inference/compatible-endpoint-context.ts

yimoj added 2 commits July 6, 2026 04:54
Second round of PR review advisor feedback for #6177:
- Skip the /v1/models context probe when the endpoint URL is a sandbox-internal
  (host.openshell.internal) or docker-internal host — a host-side GET cannot
  reach it — mirroring probeOpenAiLikeEndpoint, and leave Hermes auto-detect.
- Add a source-boundary note documenting the tolerated invalid states and the
  removal condition for the probe.
- Add a handler-level regression test: a stale auto-detected compatible-endpoint
  context window is cleared before a re-selected provider is patched.
- Add a unit test for the sandbox-internal skip.
- Split the compatible-endpoint docs paragraph into one sentence per line.

Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
…tance (#6177)

Address remaining PR review advisor notes for #6177:
- Add an opt-in NEMOCLAW_FAKE_OPENAI_REQUIRE_AUTH_MODELS flag so the fake
  endpoint enforces auth on GET /v1/models, and cover it end-to-end: the probe
  sets the window only with the correct credential and skips it on 401. The
  readiness probe now accepts 401 (server up) so existing fixtures are unaffected.
- Document why private/loopback endpoints are intentionally not blocked (the
  operator's own self-hosted vLLM on localhost is the primary target; a private
  IP blocklist would break local inference, and probeOpenAiLikeEndpoint does not
  filter them either); only unreachable sandbox-internal hosts are skipped.
- Add the (#6177) local issue-ref suffix to a probe test title.

Signed-off-by: Yimo Jiang <yimoj@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/compatible-endpoint-context-probe.test.ts (1)

70-95: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Consider asserting the request was actually rejected, not just that no window was set.

The wrong-key branch (Lines 78-85) only checks NEMOCLAW_CONTEXT_WINDOW stays undefined. That outcome is also produced by any probe failure (network error, timeout), not specifically an auth rejection. Asserting on server.requests() (e.g. that a /v1/models request without/with wrong auth was recorded) would more precisely confirm the "enforces auth" claim rather than only inferring it from the downstream unset variable.

🤖 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/compatible-endpoint-context-probe.test.ts` around lines 70 - 95, The
test for auth enforcement only checks that NEMOCLAW_CONTEXT_WINDOW remains
unset, which can happen for non-auth probe failures too. Update the "enforces
auth on /v1/models" case in compatible-endpoint-context-probe.test.ts to also
assert the fake server recorded the /v1/models request for the wrong/absent
credential path, using the server.requests() data from
startFakeOpenAiCompatibleServer. Keep the existing
applyCompatibleEndpointContextWindow and fetchCompatibleEndpointModels flow, but
make the assertion verify the request was actually rejected by auth rather than
inferred from the missing window.
🤖 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/compatible-endpoint-context-probe.test.ts`:
- Around line 70-95: The test for auth enforcement only checks that
NEMOCLAW_CONTEXT_WINDOW remains unset, which can happen for non-auth probe
failures too. Update the "enforces auth on /v1/models" case in
compatible-endpoint-context-probe.test.ts to also assert the fake server
recorded the /v1/models request for the wrong/absent credential path, using the
server.requests() data from startFakeOpenAiCompatibleServer. Keep the existing
applyCompatibleEndpointContextWindow and fetchCompatibleEndpointModels flow, but
make the assertion verify the request was actually rejected by auth rather than
inferred from the missing window.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: e78ca19f-6b86-4aa6-a691-439744257e15

📥 Commits

Reviewing files that changed from the base of the PR and between 09d89c8 and 28401a5.

📒 Files selected for processing (4)
  • src/lib/inference/compatible-endpoint-context.ts
  • test/compatible-endpoint-context-probe.test.ts
  • test/e2e/fixtures/fake-openai-compatible.ts
  • test/e2e/lib/fake-openai-compatible-api.mts
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/e2e/lib/fake-openai-compatible-api.mts
  • src/lib/inference/compatible-endpoint-context.ts

yimoj added 3 commits July 6, 2026 05:14
- Use vi.stubEnv/vi.unstubAllEnvs in the Hermes Dockerfile context test instead
  of manual process.env deletion (CodeRabbit / advisor quick win).
- Document that no separate auxiliary/compression context_length is needed:
  Hermes derives its compression threshold from the main model's context_length.

Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
…gth (#6177)

Add a source-level regression that runs the same applyCompatibleEndpointContextWindow
the onboarding boundary calls (injected fetcher, max_model_len 65536), then the
real Hermes config generator, and asserts model.context_length is 65536 and
model.context_window is absent — closing the probe→env→config chain in one test.

Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
Address CodeRabbit review nits:
- The auth-enforcement case now asserts the fake endpoint recorded the
  /v1/models request as auth=missing (rejected) for the wrong-key path and
  auth=ok for the keyed path, instead of only inferring rejection from an unset
  NEMOCLAW_CONTEXT_WINDOW (which a network failure could also produce).
- Add the (#6177) local issue-ref suffix to the remaining probe test title.

Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
@yimoj yimoj added the v0.0.75 label Jul 6, 2026
@yimoj

yimoj commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@prekshivyas prekshivyas self-assigned this Jul 6, 2026
…oundary (#6293)

Custom / compatible-endpoint onboarding probed the operator-supplied
endpoint URL before any private-IP screening. Both the chat-completions
validation probe and the /v1/models context probe would issue host-side
requests to a private/reserved address (SSRF), relying only on the
downstream DNS-pinning config-write boundary as defense.

Add source-boundary validation reusing the shared isPrivateHostname
validator (src/lib/private-networks.ts), before any curl runs:

- probeOpenAiLikeEndpoint (onboard-probes.ts): reject a private/internal
  endpoint after the allowed sandbox-internal / docker-internal hosts are
  handled, so every validation path (including reasoning mode) is covered
  (PRA-2).
- applyCompatibleEndpointContextWindow (compatible-endpoint-context.ts):
  refuse the /v1/models probe for a private endpoint; this path issues its
  own GET independent of validation, so it screens the URL itself
  (PRA-1/PRA-3). Update the misleading JSDoc that claimed private IPs are
  intentionally not blocked (PRA-11).

DNS-pinning at the config-write boundary is kept as defense-in-depth.

Tests:
- Extract the compatible-endpoint context-window handler case into
  provider-inference-context-window.test.ts plus a shared
  provider-inference.test-support.ts, keeping the primary handler spec
  within the growth guardrail (PRA-6).
- Unit-test that applyCompatibleEndpointContextWindow rejects
  10.0.0.1/127.0.0.1/169.254.169.254/172.16.0.1/192.168.1.1 before
  fetchModels, via it.each (PRA-8).
- Add a real-server integration case proving a 127.0.0.1 endpoint is
  refused with no new /v1/models request; migrate the existing happy-path
  probe cases to present a public host to the guard while the injected
  fetcher still hits the loopback fixture (PRA-9).

Signed-off-by: Prekshi Vyas <prekshiv@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: 1

🧹 Nitpick comments (2)
src/lib/inference/onboard-probes.ts (1)

638-664: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Consider extracting the hostname-extraction-plus-guard pattern into a shared helper.

The try/new URL()/catch-to-hostname-then-isPrivateHostname sequence here is the same shape the compatible-endpoint context probe path needs to enforce (per the test suite's SSRF assertions in test/compatible-endpoint-context-probe.test.ts). Consolidating into a single isPrivateEndpointUrl(url) helper in private-networks would prevent the two call sites from silently diverging as the guard evolves.

🤖 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/onboard-probes.ts` around lines 638 - 664, The hostname
parsing plus private-address guard in the onboarding probe is duplicated and
should be centralized. Extract the try/new URL/catch logic and the
isPrivateHostname check into a shared helper such as isPrivateEndpointUrl in
private-networks, then call that helper from onboard-probes and the
compatible-endpoint context probe path. Keep the existing rejection behavior and
message flow, but ensure both call sites use the same helper so SSRF validation
stays consistent as it evolves.
src/lib/onboard/machine/handlers/provider-inference.test-support.ts (1)

51-56: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Unused endpointUrl param should be _-prefixed.

It's never read in the mock body (the returned endpointUrl is a hardcoded literal), unlike the sibling _provider/_credentialEnv params.

As per coding guidelines, "Use _-prefixed names for intentionally unused variables in JavaScript/TypeScript code."

🔧 Proposed fix
     reupsertRoutedProvider: vi.fn(
-      (_provider: string, endpointUrl: string | null, _credentialEnv: string | null) => ({
+      (_provider: string, _endpointUrl: string | null, _credentialEnv: string | null) => ({
         ok: true as const,
         endpointUrl: "http://host.openshell.internal:4000/v1",
       }),
     ),
🤖 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/machine/handlers/provider-inference.test-support.ts` around
lines 51 - 56, The mock in provider-inference.test-support.ts has an unused
endpointUrl parameter in reupsertRoutedProvider, so rename it to an _-prefixed
name to match the sibling _provider and _credentialEnv params. Keep the vi.fn
signature and returned object the same, and only change the parameter name in
reupsertRoutedProvider so the intent to ignore it is explicit.

Source: Coding guidelines

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

Inline comments:
In `@src/lib/inference/onboard-probes.ts`:
- Around line 644-664: The endpoint parsing in onboard-probes should fail closed
instead of falling through when URL parsing fails. Update the probe endpoint
handling around the new URL(String(endpointUrl)) logic so the catch path returns
openAiLikeFailureFromError(error) immediately, rather than setting probeHostname
to an empty string and continuing. Keep the private-host check in place for
valid hostnames, but ensure unparseable inputs in this flow do not proceed to
the curl-based probing logic.

---

Nitpick comments:
In `@src/lib/inference/onboard-probes.ts`:
- Around line 638-664: The hostname parsing plus private-address guard in the
onboarding probe is duplicated and should be centralized. Extract the try/new
URL/catch logic and the isPrivateHostname check into a shared helper such as
isPrivateEndpointUrl in private-networks, then call that helper from
onboard-probes and the compatible-endpoint context probe path. Keep the existing
rejection behavior and message flow, but ensure both call sites use the same
helper so SSRF validation stays consistent as it evolves.

In `@src/lib/onboard/machine/handlers/provider-inference.test-support.ts`:
- Around line 51-56: The mock in provider-inference.test-support.ts has an
unused endpointUrl parameter in reupsertRoutedProvider, so rename it to an
_-prefixed name to match the sibling _provider and _credentialEnv params. Keep
the vi.fn signature and returned object the same, and only change the parameter
name in reupsertRoutedProvider so the intent to ignore it is explicit.
🪄 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: 86a2f198-0199-40a4-96ea-4882cb1260b4

📥 Commits

Reviewing files that changed from the base of the PR and between defffcf and 535d2a6.

📒 Files selected for processing (7)
  • src/lib/inference/compatible-endpoint-context.test.ts
  • src/lib/inference/compatible-endpoint-context.ts
  • src/lib/inference/onboard-probes.ts
  • src/lib/onboard/machine/handlers/provider-inference-context-window.test.ts
  • src/lib/onboard/machine/handlers/provider-inference.test-support.ts
  • src/lib/onboard/machine/handlers/provider-inference.test.ts
  • test/compatible-endpoint-context-probe.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/inference/compatible-endpoint-context.test.ts
  • src/lib/inference/compatible-endpoint-context.ts

Comment thread src/lib/inference/onboard-probes.ts
prekshivyas and others added 3 commits July 6, 2026 09:51
…x test titles

Follow-up to the #6293 SSRF hardening — two CI breakages:
- The isPrivateHostname block in probeOpenAiLikeEndpoint over-blocked
  host.docker.internal, a trusted sandbox->host bridge already gated by the
  allowHostDockerInternal check at the top of the function (Windows-host Ollama
  validation). Exempt the already-permitted hijacked-docker-internal alias.
- Three new test titles put the issue ref mid-parens ("(SSRF, #6293)") which
  fails test-title-style; move to a clean final "(#6293)".

cli project (635 tests) + npm run checks pass locally.

SKIP=test-cli: full hook may trip on pre-existing macOS bash 3.2 noise if this
branch predates #6140; CI runs bash 5.x green.

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
)

The private-address SSRF guard added to probeOpenAiLikeEndpoint rejected
every private/reserved address, but that shared probe is the same one
local inference uses to validate a locally-run Ollama/vLLM/NIM server on
loopback (127.0.0.0/8, ::1, localhost). Loopback only reaches the probing
host itself, so it is not an SSRF pivot to other internal infrastructure;
non-loopback private ranges (LAN, link-local cloud-metadata) stay blocked.

Adds isLoopbackHostname to private-networks plus unit coverage for the
guard's block (LAN/metadata) and allow (loopback) paths.

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.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)
src/lib/private-networks.ts (1)

207-216: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated hostname normalization logic.

The bracket-stripping/trailing-dot/lowercasing block (Lines 208-210) is identical to the one in isPrivateHostname (Lines 184-186). Consider extracting a shared normalizeHostname helper to avoid drift between the two functions.

♻️ Proposed refactor
+function normalizeHostname(hostname: string): string {
+  const stripped =
+    hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
+  return stripped.replace(/\.$/, "").toLowerCase();
+}
+
 export function isPrivateHostname(hostname: string): boolean {
-  const stripped =
-    hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
-  const normalised = stripped.replace(/\.$/, "").toLowerCase();
+  const normalised = normalizeHostname(hostname);
   const { normalisedNames } = load();
   ...
 }

 export function isLoopbackHostname(hostname: string): boolean {
-  const stripped =
-    hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
-  const normalised = stripped.replace(/\.$/, "").toLowerCase();
+  const normalised = normalizeHostname(hostname);
   if (normalised === "localhost") return true;
   ...
 }
🤖 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/private-networks.ts` around lines 207 - 216, The hostname
normalization logic in isLoopbackHostname duplicates the same bracket-stripping,
trailing-dot removal, and lowercasing used in isPrivateHostname, so extract that
shared behavior into a normalizeHostname helper and have both functions call it.
Keep the loopback checks in isLoopbackHostname unchanged, but route the initial
hostname cleanup through the shared helper to prevent the two implementations
from drifting apart.
🤖 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 `@src/lib/private-networks.ts`:
- Around line 207-216: The hostname normalization logic in isLoopbackHostname
duplicates the same bracket-stripping, trailing-dot removal, and lowercasing
used in isPrivateHostname, so extract that shared behavior into a
normalizeHostname helper and have both functions call it. Keep the loopback
checks in isLoopbackHostname unchanged, but route the initial hostname cleanup
through the shared helper to prevent the two implementations from drifting
apart.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c17581e0-c9f8-4826-9939-d21476233504

📥 Commits

Reviewing files that changed from the base of the PR and between ae46f45 and 63ef306.

📒 Files selected for processing (3)
  • src/lib/inference/onboard-probes.test.ts
  • src/lib/inference/onboard-probes.ts
  • src/lib/private-networks.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/inference/onboard-probes.ts

# Conflicts:
#	src/lib/onboard/machine/handlers/provider-inference.test.ts
#	src/lib/onboard/machine/handlers/provider-inference.ts
Comment thread scripts/dogfood-env.sh Fixed
Comment thread scripts/dogfood-env.sh Fixed
Comment thread scripts/dogfood-env.sh Fixed
Comment thread scripts/dogfood-env.sh Fixed
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ⚠️ Run cancelled — no signal

Run: 28906379718
Workflow ref: fix/6177-compatible-endpoint-context
Requested targets: hermes-shields-config,messaging-providers,onboard-resume,hermes-gpu-startup
Requested jobs: (default — all default-enabled free-standing jobs; explicit-only jobs openshell-gateway-auth-contract, mcp-bridge-dev, hermes-gpu-startup, sandbox-rlimits-connect, and jetson-nvmap-gpu are skipped unless selected)
Summary: 0 passed, 0 failed, 4 cancelled, 0 skipped

Job Result
hermes-gpu-startup ⚠️ cancelled
hermes-shields-config ⚠️ cancelled
messaging-providers ⚠️ cancelled
onboard-resume ⚠️ cancelled

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ✅ All selected jobs passed

Run: 28906743092
Workflow ref: fix/6177-compatible-endpoint-context
Requested targets: onboard-resume
Requested jobs: (default — all default-enabled free-standing jobs; explicit-only jobs openshell-gateway-auth-contract, mcp-bridge-dev, hermes-gpu-startup, sandbox-rlimits-connect, and jetson-nvmap-gpu are skipped unless selected)
Summary: 1 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
onboard-resume ✅ success

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ✅ All selected jobs passed

Run: 28906860835
Workflow ref: fix/6177-compatible-endpoint-context
Requested targets: hermes-gpu-startup
Requested jobs: (default — all default-enabled free-standing jobs; explicit-only jobs openshell-gateway-auth-contract, mcp-bridge-dev, hermes-gpu-startup, sandbox-rlimits-connect, and jetson-nvmap-gpu are skipped unless selected)
Summary: 1 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
hermes-gpu-startup ✅ success

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ❌ Some jobs failed

Run: 28906504389
Workflow ref: fix/6177-compatible-endpoint-context
Requested targets: hermes-shields-config,messaging-providers,onboard-resume,hermes-gpu-startup
Requested jobs: (default — all default-enabled free-standing jobs; explicit-only jobs openshell-gateway-auth-contract, mcp-bridge-dev, hermes-gpu-startup, sandbox-rlimits-connect, and jetson-nvmap-gpu are skipped unless selected)
Summary: 2 passed, 2 failed, 0 cancelled, 0 skipped

Job Result
hermes-gpu-startup ❌ failure
hermes-shields-config ✅ success
messaging-providers ✅ success
onboard-resume ❌ failure

Failed jobs: hermes-gpu-startup, onboard-resume. Check run artifacts for logs.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ❌ Some jobs failed

Run: 28907190421
Workflow ref: fix/6177-compatible-endpoint-context
Requested targets: (default — all supported)
Requested jobs: (default — all default-enabled free-standing jobs; explicit-only jobs openshell-gateway-auth-contract, mcp-bridge-dev, hermes-gpu-startup, sandbox-rlimits-connect, and jetson-nvmap-gpu are skipped unless selected)
Summary: 43 passed, 27 failed, 0 cancelled, 5 skipped

Job Result
agent-turn-latency ❌ failure
bedrock-runtime-compatible-anthropic ✅ success
brave-search ✅ success
channels-add-remove ✅ success
channels-stop-start ✅ success
cloud-inference ✅ success
cloud-onboard ❌ failure
common-egress-agent ❌ failure
concurrent-gateway-ports ✅ success
credential-migration ✅ success
credential-sanitization ❌ failure
cron-preflight-inference-local ❌ failure
device-auth-health ✅ success
diagnostics ❌ failure
docs-validation ✅ success
double-onboard ✅ success
full-e2e ❌ failure
gateway-drift-preflight ✅ success
gateway-guard-recovery ✅ success
gateway-health-honest ✅ success
generate-matrix ✅ success
gpu-double-onboard ✅ success
gpu-e2e ✅ success
hermes-dashboard ❌ failure
hermes-discord ❌ failure
hermes-e2e ❌ failure
hermes-gpu-startup ⏭️ skipped
hermes-inference-switch ❌ failure
hermes-shields-config ✅ success
hermes-slack ✅ success
inference-routing ✅ success
issue-2478-crash-loop-recovery ✅ success
issue-4434-tui-unreachable-inference ✅ success
issue-4462-scope-upgrade-approval ❌ failure
jetson-nvmap-gpu ⏭️ skipped
kimi-inference-compat ✅ success
launchable-smoke ✅ success
live ❌ failure
mcp-bridge ✅ success
mcp-bridge-dev ⏭️ skipped
messaging-compatible-endpoint ✅ success
messaging-providers ✅ success
model-router-provider-routed-inference ✅ success
network-policy ❌ failure
ollama-auth-proxy ✅ success
onboard-negative-paths ✅ success
onboard-repair ✅ success
onboard-resume ✅ success
openclaw-discord-pairing ✅ success
openclaw-inference-switch ❌ failure
openclaw-skill-cli ✅ success
openclaw-slack-pairing ✅ success
openclaw-tui-chat-correlation ❌ failure
openshell-gateway-auth-contract ⏭️ skipped
openshell-gateway-upgrade ✅ success
openshell-version-pin ✅ success
overlayfs-autofix ✅ success
rebuild-hermes ❌ failure
rebuild-hermes-stale-base ❌ failure
rebuild-openclaw ✅ success
sandbox-operations ❌ failure
sandbox-rebuild ✅ success
sandbox-rlimits-connect ⏭️ skipped
sandbox-survival ❌ failure
security-posture ❌ failure
sessions-agents-cli ❌ failure
shields-config ❌ failure
skill-agent ✅ success
snapshot-commands ✅ success
spark-install ❌ failure
state-backup-restore ❌ failure
telegram-injection ✅ success
token-rotation ✅ success
tunnel-lifecycle ❌ failure
upgrade-stale-sandbox ❌ failure

Explicit-only jobs skipped: openshell-gateway-auth-contract (default dispatch excludes the resource-heavy OpenShell auth-contract probe unless selected; validate with jobs=openshell-gateway-auth-contract or targets=openshell-gateway-auth-contract), mcp-bridge-dev (default dispatch excludes moving OpenShell dev artifacts unless explicitly selected; validate with jobs=mcp-bridge-dev or targets=mcp-bridge-dev), hermes-gpu-startup (default dispatch excludes this explicit-only job unless selected; validate with jobs=hermes-gpu-startup or targets=hermes-gpu-startup), sandbox-rlimits-connect (default dispatch excludes the destructive rlimit fork/connect probe unless selected; validate with jobs=sandbox-rlimits-connect or targets=sandbox-rlimits-connect), jetson-nvmap-gpu (default dispatch excludes Jetson until a stable Jetson runner is available; validate with jobs=jetson-nvmap-gpu or targets=jetson-nvmap-gpu).

Failed jobs: agent-turn-latency, cloud-onboard, common-egress-agent, credential-sanitization, cron-preflight-inference-local, diagnostics, full-e2e, hermes-dashboard, hermes-discord, hermes-e2e, hermes-inference-switch, issue-4462-scope-upgrade-approval, live, network-policy, openclaw-inference-switch, openclaw-tui-chat-correlation, rebuild-hermes, rebuild-hermes-stale-base, sandbox-operations, sandbox-survival, security-posture, sessions-agents-cli, shields-config, spark-install, state-backup-restore, tunnel-lifecycle, upgrade-stale-sandbox. Check run artifacts for logs.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ✅ All default jobs passed

Run: 28907190421
Workflow ref: fix/6177-compatible-endpoint-context
Requested targets: (default — all supported)
Requested jobs: (default — all default-enabled free-standing jobs; explicit-only jobs openshell-gateway-auth-contract, mcp-bridge-dev, hermes-gpu-startup, sandbox-rlimits-connect, and jetson-nvmap-gpu are skipped unless selected)
Summary: 70 passed, 0 failed, 0 cancelled, 5 skipped

Job Result
agent-turn-latency ✅ success
bedrock-runtime-compatible-anthropic ✅ success
brave-search ✅ success
channels-add-remove ✅ success
channels-stop-start ✅ success
cloud-inference ✅ success
cloud-onboard ✅ success
common-egress-agent ✅ success
concurrent-gateway-ports ✅ success
credential-migration ✅ success
credential-sanitization ✅ success
cron-preflight-inference-local ✅ success
device-auth-health ✅ success
diagnostics ✅ success
docs-validation ✅ success
double-onboard ✅ success
full-e2e ✅ success
gateway-drift-preflight ✅ success
gateway-guard-recovery ✅ success
gateway-health-honest ✅ success
generate-matrix ✅ success
gpu-double-onboard ✅ success
gpu-e2e ✅ success
hermes-dashboard ✅ success
hermes-discord ✅ success
hermes-e2e ✅ success
hermes-gpu-startup ⏭️ skipped
hermes-inference-switch ✅ success
hermes-shields-config ✅ success
hermes-slack ✅ success
inference-routing ✅ success
issue-2478-crash-loop-recovery ✅ success
issue-4434-tui-unreachable-inference ✅ success
issue-4462-scope-upgrade-approval ✅ success
jetson-nvmap-gpu ⏭️ skipped
kimi-inference-compat ✅ success
launchable-smoke ✅ success
live ✅ success
mcp-bridge ✅ success
mcp-bridge-dev ⏭️ skipped
messaging-compatible-endpoint ✅ success
messaging-providers ✅ success
model-router-provider-routed-inference ✅ success
network-policy ✅ success
ollama-auth-proxy ✅ success
onboard-negative-paths ✅ success
onboard-repair ✅ success
onboard-resume ✅ success
openclaw-discord-pairing ✅ success
openclaw-inference-switch ✅ success
openclaw-skill-cli ✅ success
openclaw-slack-pairing ✅ success
openclaw-tui-chat-correlation ✅ success
openshell-gateway-auth-contract ⏭️ skipped
openshell-gateway-upgrade ✅ success
openshell-version-pin ✅ success
overlayfs-autofix ✅ success
rebuild-hermes ✅ success
rebuild-hermes-stale-base ✅ success
rebuild-openclaw ✅ success
sandbox-operations ✅ success
sandbox-rebuild ✅ success
sandbox-rlimits-connect ⏭️ skipped
sandbox-survival ✅ success
security-posture ✅ success
sessions-agents-cli ✅ success
shields-config ✅ success
skill-agent ✅ success
snapshot-commands ✅ success
spark-install ✅ success
state-backup-restore ✅ success
telegram-injection ✅ success
token-rotation ✅ success
tunnel-lifecycle ✅ success
upgrade-stale-sandbox ✅ success

Explicit-only jobs skipped: openshell-gateway-auth-contract (default dispatch excludes the resource-heavy OpenShell auth-contract probe unless selected; validate with jobs=openshell-gateway-auth-contract or targets=openshell-gateway-auth-contract), mcp-bridge-dev (default dispatch excludes moving OpenShell dev artifacts unless explicitly selected; validate with jobs=mcp-bridge-dev or targets=mcp-bridge-dev), hermes-gpu-startup (default dispatch excludes this explicit-only job unless selected; validate with jobs=hermes-gpu-startup or targets=hermes-gpu-startup), sandbox-rlimits-connect (default dispatch excludes the destructive rlimit fork/connect probe unless selected; validate with jobs=sandbox-rlimits-connect or targets=sandbox-rlimits-connect), jetson-nvmap-gpu (default dispatch excludes Jetson until a stable Jetson runner is available; validate with jobs=jetson-nvmap-gpu or targets=jetson-nvmap-gpu).

@prekshivyas

Copy link
Copy Markdown
Collaborator

@cv Exact-head rereview requested for e3a69ce242e0c6f3ba3483f765aa68733963a3d4.

All items from the latest CV review are addressed:

  • Approved no-pin endpoints (explicit loopback, OpenShell-managed aliases, and public IP literals) now carry a structured preflight capability and scrub every ambient proxy spelling before credentialed curl probes. Regressions cover all three origin classes.
  • Resume evidence now requires and records a newly authenticated request, and the live resume path proves real inference routing.
  • Hermes strict restart-seal ordering/hash reconciliation is repaired and covered.
  • The installed Slack + WhatsApp loader collision is repaired; the combined runtime proof passes.
  • Hermes GPU startup now proves the real inference.local POST route and authentication.

Exact-head evidence:

  • Full default E2E fanout: run 28907190421, attempt 270 passed, 0 failed, 5 explicit-only skips. Attempt 1 was throttled by the shared hosted inference endpoint (HTTP 429 across unrelated jobs); rerunning only failed jobs on the unchanged SHA recovered every failure.
  • Explicit hermes-gpu-startup: run 28906860835 — passed on this exact head.
  • Stable mcp-bridge passes in the full exact-head fanout. The explicit moving-dev probe is intentionally not waived: current OpenShell dev is 0.0.78-dev.6+ga7271169 while the reviewed credential-boundary manifest is pinned to 0.0.72, so production correctly fails closed rather than bypassing the version-bound security contract.
  • Required CI, DCO, commit lint, aggregate checks, CodeQL, and both review advisors are green.
  • All 52 PR commits are GitHub Verified (reason: valid) and DCO passes.

The newer green scorecard supersedes the earlier red scorecard from attempt 1 on the same workflow run and SHA. No further code was pushed during the rerun.

@prekshivyas
prekshivyas requested a review from cv July 8, 2026 08:46
@prekshivyas

Copy link
Copy Markdown
Collaborator

@cv Focused exact-head re-review requested for e3a69ce242e0c6f3ba3483f765aa68733963a3d4.

Since your last review at bfe7c9f0, six commits address the remaining proxy credential boundary, authenticated resume proof, Hermes seal ordering, messaging runtime collision, and Hermes GPU inference route.

Current exact-head evidence:

Could you confirm approval or identify any remaining exact-head blocker?

@ericksoa ericksoa added v0.0.78 and removed v0.0.77 labels Jul 8, 2026
Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ❌ Some jobs failed

Run: 28957991760
Workflow ref: fix/6177-compatible-endpoint-context
Requested targets: (selector rejected by workflow validation)
Requested jobs: (selector rejected by workflow validation)
Summary: 0 passed, 1 failed, 0 cancelled, 0 skipped

Job Result
generate-matrix ❌ failure

Failed jobs: generate-matrix. Check run artifacts for logs.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ✅ All selected jobs passed

Run: 28958088095
Workflow ref: fix/6177-compatible-endpoint-context
Requested targets: ubuntu-repo-cloud-openclaw
Requested jobs: (default — all default-enabled free-standing jobs; explicit-only jobs openshell-gateway-auth-contract, mcp-bridge-dev, hermes-gpu-startup, sandbox-rlimits-connect, and jetson-nvmap-gpu are skipped unless selected)
Summary: 1 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
live ✅ success

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ❌ Some jobs failed

Run: 28958085816
Workflow ref: fix/6177-compatible-endpoint-context
Requested targets: (default — all supported)
Requested jobs: bedrock-runtime-compatible-anthropic,hermes-gpu-startup,mcp-bridge,mcp-bridge-dev,messaging-compatible-endpoint,onboard-resume,onboard-repair
Summary: 6 passed, 1 failed, 0 cancelled, 0 skipped

Job Result
bedrock-runtime-compatible-anthropic ✅ success
hermes-gpu-startup ✅ success
mcp-bridge ✅ success
mcp-bridge-dev ❌ failure
messaging-compatible-endpoint ✅ success
onboard-repair ✅ success
onboard-resume ✅ success

Failed jobs: mcp-bridge-dev. Check run artifacts for logs.

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ✅ All selected jobs passed

Run: 28960081025
Workflow ref: fix/6177-compatible-endpoint-context
Requested targets: ubuntu-repo-cloud-openclaw
Requested jobs: (default — all default-enabled free-standing jobs; explicit-only jobs openshell-gateway-auth-contract, mcp-bridge-dev, hermes-gpu-startup, sandbox-rlimits-connect, and jetson-nvmap-gpu are skipped unless selected)
Summary: 1 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
live ✅ success

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ✅ All requested jobs passed

Run: 28960515762
Workflow ref: fix/6177-compatible-endpoint-context
Requested targets: (default — all supported)
Requested jobs: cloud-onboard,inference-routing,hermes-e2e,hermes-shields-config,network-policy
Summary: 5 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
cloud-onboard ✅ success
hermes-e2e ✅ success
hermes-shields-config ✅ success
inference-routing ✅ success
network-policy ✅ success

@prekshivyas

Copy link
Copy Markdown
Collaborator

@cv Exact-head re-review requested for 424a5e754084327e417040b4fa048616caf697de.

The branch now contains current main (4bf5849d), GitHub reports it mergeable with no conflicts, and focused local support tests pass 25/25 with CLI build/typecheck green.

Exact-head evidence:

Could you review this exact head and either approve or identify the remaining blocker(s)? I will not merge while the existing change request or a substantive Advisor concern remains unresolved.

@cv
cv merged commit 7b0b318 into main Jul 8, 2026
272 of 273 checks passed
@cv
cv deleted the fix/6177-compatible-endpoint-context branch July 8, 2026 17:11
cv pushed a commit that referenced this pull request Jul 9, 2026
<!-- markdownlint-disable MD041 -->
## Summary

Prepares the user documentation for NemoClaw v0.0.78 by replacing the
unreleased section with release highlights and synchronizing the
affected inference, lifecycle, messaging, and CLI reference pages with
merged behavior.

## Changes

- Publish the v0.0.78 release-notes section with links to the most
specific user guides for each shipped behavior.
- Document authoritative Deep Agents route health, Nemotron Ultra
profile behavior, and Hermes compatible-endpoint context metadata.
- Document forced rebuild recovery after total backup failure and the
ownership-safe tunnel/full-stop behavior.
- Keep command examples and shared agent variants aligned with the
current OpenClaw, Hermes, and Deep Agents interfaces.

Source mapping:

- [#3787](#3787) ->
`docs/about/release-notes.mdx`: Record reliable workspace template
seeding during sandbox startup.
- [#4960](#4960) ->
`docs/about/release-notes.mdx`: Record safer detection of rewritten
OpenClaw gateway processes.
- [#5676](#5676) ->
`docs/about/release-notes.mdx`: Record warning-tolerant agent-list JSON
handling.
- [#5857](#5857) ->
`docs/about/release-notes.mdx`: Record synchronization of explicit
OpenClaw main-agent model state.
- [#5929](#5929) ->
`docs/about/release-notes.mdx`: Record copyable SSH port-forward
guidance for remote dashboards.
- [#6068](#6068) ->
`docs/about/release-notes.mdx`: Record custom-image plugin provenance
reconciliation.
- [#6116](#6116) ->
`docs/about/release-notes.mdx`: Record live-loopback dashboard-forward
recovery.
- [#6122](#6122) ->
`docs/about/release-notes.mdx`: Announce validated, round-trippable
policy YAML output.
- [#6211](#6211) ->
`docs/manage-sandboxes/lifecycle.mdx`, `docs/reference/commands.mdx`,
`docs/about/release-notes.mdx`: Explain the explicit no-backup `rebuild
--force` recovery boundary.
- [#6283](#6283) ->
`docs/about/release-notes.mdx`: Record Hermes WebUI port alignment.
- [#6293](#6293) ->
`docs/inference/switch-inference-providers.mdx`,
`docs/about/release-notes.mdx`: Document compatible-endpoint
context-length probing for Hermes.
- [#6320](#6320) ->
`docs/about/release-notes.mdx`: Record bounded gateway-recovery waits.
- [#6377](#6377) ->
`docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Explain
rebuild diagnostics and prepared MCP-destroy recovery.
- [#6412](#6412) ->
`docs/get-started/quickstart-langchain-deepagents-code.mdx`,
`docs/about/release-notes.mdx`: Document authoritative agent-visible
inference route health.
- [#6421](#6421) ->
`docs/about/release-notes.mdx`: Record the longer quiet-pull window for
managed vLLM images.
- [#6431](#6431) ->
`docs/inference/model-capability-audit.mdx`,
`docs/about/release-notes.mdx`: Document the version-pinned Nemotron
Ultra profile plugin.
- [#6439](#6439) ->
`docs/about/release-notes.mdx`: Summarize the authenticated, pinned
credential-capture helper boundary.
- [#6450](#6450) ->
`docs/manage-sandboxes/messaging-channels.mdx`,
`docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Document
host-forward cleanup and ownership-safe gateway-port release.
- [#6474](#6474) ->
`docs/manage-sandboxes/messaging-channels.mdx`,
`docs/about/release-notes.mdx`: Record composable OpenClaw messaging
runtime loaders.
- [#6475](#6475) ->
`docs/about/release-notes.mdx`: Record removal of the unavailable Kimi
K2.6 production endpoint option.
- [#6480](#6480) ->
`docs/about/release-notes.mdx`: Record stderr routing for the plugin
registration banner.
- [#6481](#6481) ->
`docs/about/release-notes.mdx`: Record post-pull Ollama model discovery
checks.
- [#6482](#6482) ->
`docs/about/release-notes.mdx`: Record Ollama model warm-up after daemon
restart.
- [#6486](#6486) ->
`docs/about/release-notes.mdx`: Publish the opt-in, thread-scoped Deep
Agents auto-approval boundary.
- [#6490](#6490) ->
`docs/about/release-notes.mdx`: Record diagnostics for custom images
missing the managed runtime.
- [#6494](#6494) ->
`docs/inference/model-capability-audit.mdx`,
`docs/about/release-notes.mdx`: Document nonempty tool-call content
preservation and placeholder rejection.
- [#6497](#6497) ->
`docs/get-started/quickstart-langchain-deepagents-code.mdx`,
`docs/about/release-notes.mdx`: Document isolated Deep Agents
route-probe output.
- [#6506](#6506) ->
`docs/get-started/quickstart-langchain-deepagents-code.mdx`,
`docs/about/release-notes.mdx`: Document observability-preserving
managed route probes.
- [#6508](#6508) ->
`docs/about/release-notes.mdx`: Link the new extension taxonomy and
SDK-readiness reference from the release summary.

Release-source verification: GitHub reports all 29 cited source PRs as
merged with base `main`, and every merge commit is an ancestor of
`origin/main` at `17bf9a6a9688b3b1d69cf4b37d3f23110acb055e`. No
source-mapping mismatches were found.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [x] 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: Documentation-only
release-prep changes; `npm run docs` validates variants, routes, and
Fern content.
- [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
are not applicable to this documentation-only change set.
- [ ] 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) — exited
0 with zero errors; Fern reported the existing unauthenticated
redirect-check and light-mode contrast 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)

---
<!-- 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: Charan Jagwani <cjagwani@nvidia.com>

---------

Signed-off-by: cjagwani <cjagwani@nvidia.com>
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
…ntext (NVIDIA#6177) (NVIDIA#6293)

## Summary

Compatible-endpoint / custom onboarding never probed the endpoint's
runtime context window, and the Hermes image/config carried no context
setting. A self-hosted vLLM endpoint serving a NemotronH model
(`max_model_len=65536`) therefore fell back to a ~4K architecture
default, and Hermes failed with `Error: Context length exceeded (4,181
tokens). Cannot compress further.` This teaches onboarding to probe the
endpoint's `max_model_len` (or honor an explicit
`NEMOCLAW_CONTEXT_WINDOW`) and propagate the window into the generated
Hermes config.

## Related Issue

Fixes NVIDIA#6177

## Changes

- New `src/lib/inference/compatible-endpoint-context.ts`: probes the
configured OpenAI-compatible endpoint's `/v1/models` for `max_model_len`
and sets `NEMOCLAW_CONTEXT_WINDOW` when the user has not set one. Wired
into the custom-endpoint validation-success path in
`setup-nim-selection.ts` (keeps `src/lib/onboard.ts` net-zero for the
growth guardrail).
- An explicit `NEMOCLAW_CONTEXT_WINDOW` always wins and is never
downgraded.
- Strict model matching: a shared multi-model gateway with no exact
`/v1/models` id match never bakes an unrelated model's window (local
vLLM keeps its single-served-model fallback).
- Auto-detected values are cleared before re-selecting a provider
(`machine/handlers/provider-inference.ts`), so retrying away to another
provider cannot leave endpoint A's probed window in the environment
where `dockerfile-patch` would treat it as a user override.
- Defensive filtering of non-object `/v1/models` entries so an arbitrary
endpoint returning `{"data":[null]}` cannot crash onboarding.
- Hermes propagation: declares `ARG/ENV NEMOCLAW_CONTEXT_WINDOW` (empty
→ auto-detect) in `agents/hermes/Dockerfile`, reads it in
`build-env.ts`, and writes the resolved window as `model.context_length`
in the generated `config.yaml`. Hermes reads only `context_length`
(`context_window` is silently ignored upstream); the model-block key is
its highest-priority override, above `/v1/models` discovery and its
built-in NemotronH metadata.
- Docs: documents the compatible-endpoint context probe and the Hermes
`context_length` behavior in `switch-inference-providers.mdx`.

## Type of Change

- [x] Code change with doc updates
- [ ] Code change (feature, bug fix, or refactor)
- [ ] 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-review + `codex
review --uncommitted` clean ("No discrete correctness issues");
credential handling reuses the existing curl auth-config (key in a 0600
tmpfile, never argv); endpoint URL is the already-validated/normalized
onboarding value.
- [ ] 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: `npx vitest run` for
`compatible-endpoint-context`, `vllm-runtime-context`,
`dockerfile-patch-hermes-context`, `provider-inference`,
`compatible-endpoint-context-probe`, `generate-hermes-config`,
`hermes-gateway-wrapper` → all pass (139+ tests); `npm run
typecheck:cli` clean.
- [ ] 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
- [x] `npm run docs` builds without warnings (doc changes only)
- [ ] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

### E2E evidence — real worktree CLI

Verified end-to-end with the worktree CLI (`node ./bin/nemoclaw.js`)
driving a real onboard against a fake OpenAI-compatible endpoint (bound
to `127.0.0.1`, serving `/v1/models` with `max_model_len: 65536`).
Docker was available on the host, so the full Hermes sandbox image was
built and the sandbox created.

Command (reporter's flow, fake endpoint substituted for the DGX Spark
vLLM server):

```
NEMOCLAW_PROVIDER=custom \
NEMOCLAW_ENDPOINT_URL=http://127.0.0.1:$PORT/v1 \
NEMOCLAW_MODEL=nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4 \
COMPATIBLE_API_KEY=dummy \
node ./bin/nemoclaw.js onboard --non-interactive --name ctx6177 --agent hermes --no-sandbox-gpu
```

Onboard transcript (post-fix):

```
  [3/8] Configuring inference provider
  [non-interactive] Provider: custom
  Chat Completions API available — Hermes will use openai-completions.
  ✓ Using endpoint max_model_len: 65536 tokens
  Using Other OpenAI-compatible endpoint with model: nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4
  ...
  ✓ Sandbox 'ctx6177-3482376' created
### onboard exit: 0
```

Generated Hermes `config.yaml` in the built sandbox image (post-fix):

```yaml
model:
  default: nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4
  provider: custom
  base_url: "https://inference.local/v1"
  api_key: sk-OPENSHELL-PROXY-REWRITE
  context_length: 65536
```

Pre-fix contrast (same image, `NEMOCLAW_CONTEXT_WINDOW` unset → the
behavior before this PR): the `model:` block has **no
`context_length`**, so Hermes falls back to its NemotronH metadata
default (~4K) — the reported failure:

```yaml
model:
  default: nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4
  provider: custom
  base_url: "https://inference.local/v1"
  api_key: sk-OPENSHELL-PROXY-REWRITE
# (no context_length)
```

The only part of the reporter's setup not reproducible here is the DGX
Spark GPU serving the real 120B NemotronH weights and a live `hermes
chat`; the fake endpoint reproduces the exact `/v1/models`
`max_model_len` signal the fix consumes. Supporting unit/integration
tests (real curl vs a live server, real Hermes config generator, real
Hermes Dockerfile patch) are listed above.

---
Signed-off-by: Yimo Jiang <yimoj@nvidia.com>


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

* **New Features**
* Hermes now supports `NEMOCLAW_CONTEXT_WINDOW`, overriding
auto-detection and emitting the resolved value as `config.yaml`’s
`context_length`.
* OpenAI-compatible endpoint onboarding can auto-derive context length
from `/v1/models` (`max_model_len`) when `NEMOCLAW_CONTEXT_WINDOW` is
unset.
* **Bug Fixes**
* Prevents previously auto-detected context windows from carrying over
across provider re-selection.
* Adds safer, more accurate `/v1/models` probing with SSRF protection
for private/internal targets.
* **Documentation**
* Updated `NEMOCLAW_CONTEXT_WINDOW` guidance and override/probe priority
rules.
* **Tests**
* Expanded unit, integration, and e2e coverage for overrides, probing,
and SSRF behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Co-authored-by: Prekshi Vyas <prekshiv@nvidia.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Prekshi Vyas <34834085+prekshivyas@users.noreply.github.com>
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
<!-- markdownlint-disable MD041 -->
## Summary

Prepares the user documentation for NemoClaw v0.0.78 by replacing the
unreleased section with release highlights and synchronizing the
affected inference, lifecycle, messaging, and CLI reference pages with
merged behavior.

## Changes

- Publish the v0.0.78 release-notes section with links to the most
specific user guides for each shipped behavior.
- Document authoritative Deep Agents route health, Nemotron Ultra
profile behavior, and Hermes compatible-endpoint context metadata.
- Document forced rebuild recovery after total backup failure and the
ownership-safe tunnel/full-stop behavior.
- Keep command examples and shared agent variants aligned with the
current OpenClaw, Hermes, and Deep Agents interfaces.

Source mapping:

- [NVIDIA#3787](NVIDIA#3787) ->
`docs/about/release-notes.mdx`: Record reliable workspace template
seeding during sandbox startup.
- [NVIDIA#4960](NVIDIA#4960) ->
`docs/about/release-notes.mdx`: Record safer detection of rewritten
OpenClaw gateway processes.
- [NVIDIA#5676](NVIDIA#5676) ->
`docs/about/release-notes.mdx`: Record warning-tolerant agent-list JSON
handling.
- [NVIDIA#5857](NVIDIA#5857) ->
`docs/about/release-notes.mdx`: Record synchronization of explicit
OpenClaw main-agent model state.
- [NVIDIA#5929](NVIDIA#5929) ->
`docs/about/release-notes.mdx`: Record copyable SSH port-forward
guidance for remote dashboards.
- [NVIDIA#6068](NVIDIA#6068) ->
`docs/about/release-notes.mdx`: Record custom-image plugin provenance
reconciliation.
- [NVIDIA#6116](NVIDIA#6116) ->
`docs/about/release-notes.mdx`: Record live-loopback dashboard-forward
recovery.
- [NVIDIA#6122](NVIDIA#6122) ->
`docs/about/release-notes.mdx`: Announce validated, round-trippable
policy YAML output.
- [NVIDIA#6211](NVIDIA#6211) ->
`docs/manage-sandboxes/lifecycle.mdx`, `docs/reference/commands.mdx`,
`docs/about/release-notes.mdx`: Explain the explicit no-backup `rebuild
--force` recovery boundary.
- [NVIDIA#6283](NVIDIA#6283) ->
`docs/about/release-notes.mdx`: Record Hermes WebUI port alignment.
- [NVIDIA#6293](NVIDIA#6293) ->
`docs/inference/switch-inference-providers.mdx`,
`docs/about/release-notes.mdx`: Document compatible-endpoint
context-length probing for Hermes.
- [NVIDIA#6320](NVIDIA#6320) ->
`docs/about/release-notes.mdx`: Record bounded gateway-recovery waits.
- [NVIDIA#6377](NVIDIA#6377) ->
`docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Explain
rebuild diagnostics and prepared MCP-destroy recovery.
- [NVIDIA#6412](NVIDIA#6412) ->
`docs/get-started/quickstart-langchain-deepagents-code.mdx`,
`docs/about/release-notes.mdx`: Document authoritative agent-visible
inference route health.
- [NVIDIA#6421](NVIDIA#6421) ->
`docs/about/release-notes.mdx`: Record the longer quiet-pull window for
managed vLLM images.
- [NVIDIA#6431](NVIDIA#6431) ->
`docs/inference/model-capability-audit.mdx`,
`docs/about/release-notes.mdx`: Document the version-pinned Nemotron
Ultra profile plugin.
- [NVIDIA#6439](NVIDIA#6439) ->
`docs/about/release-notes.mdx`: Summarize the authenticated, pinned
credential-capture helper boundary.
- [NVIDIA#6450](NVIDIA#6450) ->
`docs/manage-sandboxes/messaging-channels.mdx`,
`docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Document
host-forward cleanup and ownership-safe gateway-port release.
- [NVIDIA#6474](NVIDIA#6474) ->
`docs/manage-sandboxes/messaging-channels.mdx`,
`docs/about/release-notes.mdx`: Record composable OpenClaw messaging
runtime loaders.
- [NVIDIA#6475](NVIDIA#6475) ->
`docs/about/release-notes.mdx`: Record removal of the unavailable Kimi
K2.6 production endpoint option.
- [NVIDIA#6480](NVIDIA#6480) ->
`docs/about/release-notes.mdx`: Record stderr routing for the plugin
registration banner.
- [NVIDIA#6481](NVIDIA#6481) ->
`docs/about/release-notes.mdx`: Record post-pull Ollama model discovery
checks.
- [NVIDIA#6482](NVIDIA#6482) ->
`docs/about/release-notes.mdx`: Record Ollama model warm-up after daemon
restart.
- [NVIDIA#6486](NVIDIA#6486) ->
`docs/about/release-notes.mdx`: Publish the opt-in, thread-scoped Deep
Agents auto-approval boundary.
- [NVIDIA#6490](NVIDIA#6490) ->
`docs/about/release-notes.mdx`: Record diagnostics for custom images
missing the managed runtime.
- [NVIDIA#6494](NVIDIA#6494) ->
`docs/inference/model-capability-audit.mdx`,
`docs/about/release-notes.mdx`: Document nonempty tool-call content
preservation and placeholder rejection.
- [NVIDIA#6497](NVIDIA#6497) ->
`docs/get-started/quickstart-langchain-deepagents-code.mdx`,
`docs/about/release-notes.mdx`: Document isolated Deep Agents
route-probe output.
- [NVIDIA#6506](NVIDIA#6506) ->
`docs/get-started/quickstart-langchain-deepagents-code.mdx`,
`docs/about/release-notes.mdx`: Document observability-preserving
managed route probes.
- [NVIDIA#6508](NVIDIA#6508) ->
`docs/about/release-notes.mdx`: Link the new extension taxonomy and
SDK-readiness reference from the release summary.

Release-source verification: GitHub reports all 29 cited source PRs as
merged with base `main`, and every merge commit is an ancestor of
`origin/main` at `17bf9a6a9688b3b1d69cf4b37d3f23110acb055e`. No
source-mapping mismatches were found.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [x] 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: Documentation-only
release-prep changes; `npm run docs` validates variants, routes, and
Fern content.
- [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
are not applicable to this documentation-only change set.
- [ ] 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) — exited
0 with zero errors; Fern reported the existing unauthenticated
redirect-check and light-mode contrast 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)

---
<!-- 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: Charan Jagwani <cjagwani@nvidia.com>

---------

Signed-off-by: cjagwani <cjagwani@nvidia.com>
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 area: routing Request routing, policy routing, model selection, or fallback logic bug-fix PR fixes a bug or regression integration: hermes Hermes integration behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[DGX Spark][Inference] vLLM compatible-endpoint: context window falls back to ~4K for NemotronH models — agent unusable

7 participants