refactor: add agent-scoped model setup registry#3121
Conversation
|
Caution Review failedFailed to post review comments 📝 WalkthroughWalkthroughAdds a model-specific setup registry and discovery pipeline: new schema and manifests under nemoclaw-blueprint/model-specific-setup are staged into builds, discovered/validated by OpenClaw and Hermes config generators, merged into generated configs (compat blobs, plugins, Hermes env), with docs, tests, Docker and E2E updates. ChangesModel-Specific Setup Registry
Sequence Diagram(s)sequenceDiagram
autonumber
participant Gen as Config Generator
participant FS as Filesystem Registry
participant Val as Validator
participant Agg as Aggregator
participant Stage as Sandbox Stager
Gen->>FS: locate nemoclaw-blueprint/model-specific-setup
FS-->>Gen: list JSON manifests
Gen->>Val: read & validate manifests
Val-->>Gen: validated, matching manifests
Gen->>Agg: merge effects (openclawCompat / hermesCompat, plugins)
Agg-->>Gen: final config + plugin_load_paths
Gen->>Stage: stage registry and plugins into build context / image
Stage-->>Gen: staged artifacts available
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Selective E2E Results — ✅ All requested jobs passedRun: 25438334013
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 `@agents/hermes/generate-config.ts`:
- Around line 199-205: The registry discovery in findRegistryRoot currently only
checks process.cwd() and misses the bundled manifests when the caller's working
directory differs; update findRegistryRoot to also check a path relative to this
file (use __dirname) — e.g., include join(__dirname, "..", "..",
"nemoclaw-blueprint", "model-specific-setup") or an appropriate __dirname-based
relative path in the roots array so the bundled manifests are discovered
regardless of caller cwd; keep the existing environment and image-root checks
and the filter logic intact.
In `@nemoclaw-blueprint/model-specific-setup/schema.json`:
- Line 1: schema.json is missing the required SPDX header for JSON sources; add
the repository's JSON-compatible SPDX metadata as the first property in the file
(e.g., a top-level "spdx" or "SPDX-License-Identifier" string field following
the project's SPDX pattern) so the file complies with the license-header rule,
or explicitly add this path to the license-header rule's exemptions if
intentional; update schema.json accordingly and ensure the header key/name
matches the project's existing JSON SPDX convention used elsewhere.
In `@scripts/generate-openclaw-config.py`:
- Around line 305-311: The loop over model_specific_setups silently merges
effects["openclawCompat"] into inference_compat and appends
effects["openclawPlugins"] into openclaw_plugins; change it to fail fast on
conflicting non-additive changes by checking collisions before mutating: when
merging openclawCompat, for each key in effects.get("openclawCompat", {}), if
the key already exists in inference_compat and the value differs, raise an error
(include manifest id and key); when handling effects.get("openclawPlugins", []),
ensure plugin uniqueness by checking plugin id (or filename) against existing
entries in openclaw_plugins and raise on duplicates instead of silently
appending; only allow merges that are purely additive (new keys/plugins) and
abort on conflicts.
🪄 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: 8b2b3f34-9b32-4843-a77a-16cfbcc05b42
📒 Files selected for processing (13)
AGENTS.mdDockerfileagents/hermes/generate-config.tsnemoclaw-blueprint/model-specific-setup/README.mdnemoclaw-blueprint/model-specific-setup/hermes/README.mdnemoclaw-blueprint/model-specific-setup/openclaw/kimi-k2.6-managed-inference.jsonnemoclaw-blueprint/model-specific-setup/schema.jsonscripts/generate-openclaw-config.pysrc/lib/sandbox-build-context.tstest/generate-hermes-config.test.tstest/generate-openclaw-config.test.tstest/sandbox-build-context.test.tstest/sandbox-provisioning.test.ts
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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 `@nemoclaw-blueprint/model-specific-setup/schema.json`:
- Around line 14-16: The schema currently allows any "effects" regardless of
"agent", so update the JSON Schema to make "effects" conditional on the "agent"
value using an if/then (or dependentSchemas) guard: add an "if": {"properties":
{"agent": {"const":"openclaw"}}} with a corresponding "then" that
defines/permits only the "effects" shape valid for openclaw (and similarly an
"if" for "hermes" with its own "effects" structure/required properties such as
"hermesCompat"), or alternatively use "oneOf" with two full schemas each locking
"agent" to a single const and the matching "effects"; target the existing
"agent" and "effects" keys in the manifest schema so editor/CI validation
rejects cross-agent combinations.
In `@scripts/generate-openclaw-config.py`:
- Around line 176-202: The validator currently ensures
effects.openclawPlugins[*].path exists but does not verify
effects.openclawPlugins[*].loadPath, so typos will pass validation; update the
loop that iterates plugins (the block using plugins, plugin, index, source_path
and registry_root) to perform the same checks on plugin["loadPath"] as you do
for plugin["path"]: ensure loadPath is a non-empty string, not absolute, does
not contain ".." in its Path.parts, and that (registry_root.parent /
loadPath).exists() (or otherwise maps to the staged plugin location you expect);
raise a ValueError with the same style and
manifest_path/effects.openclawPlugins[{index}].loadPath context when any check
fails.
In `@src/lib/onboard-providers.ts`:
- Around line 312-316: The getSandboxInferenceConfig function still injects Kimi
compatibility keys; remove that Kimi special-case logic so this route no longer
mutates or injects compat keys itself and instead relies solely on the manifest
registry as the single source of truth (i.e., delete the branch/assignments that
add Kimi-specific keys based on provider/model/preferredInferenceApi and ensure
the function returns only values derived from the manifest/registry lookup or
passed parameters). Update any local references in getSandboxInferenceConfig
that expect those injected keys so they read from the manifest registry or the
existing SandboxInferenceConfig fields instead (keep function signature the
same: getSandboxInferenceConfig(model, provider, preferredInferenceApi) and
remove Kimi-specific mutations).
In `@test/generate-hermes-config.test.ts`:
- Around line 228-274: The test mutates the checked-in registry by writing a
broken manifest into registryDir; instead, create an isolated copy of the
script-relative registry before writing the invalid manifest and point the test
at that copy: copy the directory referenced by registryDir into a temp
subdirectory (e.g., under tmpDir), compute manifestPath inside the copied tree,
write the manifest there, then call runConfigScriptRaw with cwd/tmp path that
references the copied registry; ensure cleanup removes the copied registry and
manifest in the finally block. Use the existing registryDir, manifestPath and
runConfigScriptRaw identifiers to locate where to change behavior.
🪄 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: dcf04db8-0ea0-4f4f-932f-ffe90c19c1fc
📒 Files selected for processing (8)
.coderabbit.yamlagents/hermes/generate-config.tsnemoclaw-blueprint/model-specific-setup/schema.jsonscripts/generate-openclaw-config.pysrc/lib/onboard-providers.tstest/e2e/test-kimi-inference-compat.shtest/generate-hermes-config.test.tstest/generate-openclaw-config.test.ts
Selective E2E Results — ✅ All requested jobs passedRun: 25439498086
|
Selective E2E Results — ✅ All requested jobs passedRun: 25440365645
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@nemoclaw-blueprint/model-specific-setup/schema.json`:
- Around line 26-52: The current "match" object schema allows an empty object
(so { "match": {} } is valid); update the "match" schema to forbid empties by
adding a constraint such as "minProperties": 1 (or an equivalent anyOf/oneOf
that requires at least one of the properties). Locate the "match" object in
schema.json (the object with properties "modelIds", "providerKey",
"inferenceApi", "baseUrl") and add the "minProperties": 1 constraint so a
manifest must specify at least one matching key.
In `@scripts/generate-openclaw-config.py`:
- Around line 83-111: The code currently ignores an invalid
NEMOCLAW_MODEL_SPECIFIC_SETUP_DIR and falls back to defaults; update
_registry_roots/_find_registry_root so that when env contains
NEMOCLAW_MODEL_SPECIFIC_SETUP_DIR you validate Path(explicit).is_dir()
immediately and do not silently continue: if the explicit path exists and is a
directory, use it; if it exists but is not a directory or does not exist, raise
a ValueError (or RuntimeError) with a clear message mentioning
NEMOCLAW_MODEL_SPECIFIC_SETUP_DIR and the bad path so operators are alerted;
keep the rest of the roots logic unchanged for the non-explicit case.
🪄 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: e5c199d2-0749-4807-9e32-edd79671f4dd
📒 Files selected for processing (7)
nemoclaw-blueprint/model-specific-setup/schema.jsonscripts/generate-openclaw-config.pysrc/lib/onboard-providers.tstest/generate-hermes-config.test.tstest/generate-openclaw-config.test.tstest/onboard.test.tstest/validate-config-schemas.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- test/generate-hermes-config.test.ts
- src/lib/onboard-providers.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
scripts/generate-openclaw-config.py (1)
203-219: ⚡ Quick winKeep
openclawPlugins[*].pathinsideopenclaw-plugins/.This validator currently accepts any existing blueprint-relative file, so a manifest can point OpenClaw at arbitrary staged artifacts outside
nemoclaw-blueprint/openclaw-plugins/. That weakens the new agent-owned executable boundary and turns some manifest mistakes into startup-time plugin load failures instead of validation errors. Please restrictpathto theopenclaw-plugins/subtree and derive/validateloadPathfrom that normalized path.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/generate-openclaw-config.py` around lines 203 - 219, Restrict validation so effects.openclawPlugins[*].path must be inside the azul subtree "openclaw-plugins/": after making source_path = Path(plugin["path"]) and rejecting absolute paths or any .. parts, normalize it (e.g. source_path = source_path.relative_to(source_path.anchor) or source_path.resolve() against registry_root.parent) and ensure its first path component equals "openclaw-plugins" (reject otherwise), and then check existence under registry_root.parent / source_path; finally derive expected_load_path from that normalized path (e.g. "/usr/local/share/nemoclaw/openclaw-plugins/..." built from source_path.without leading slashes) and validate plugin["loadPath"].rstrip("/") against that value (use manifest_path, index, plugin variables for error messages).
🤖 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 `@nemoclaw-blueprint/model-specific-setup/schema.json`:
- Around line 22-24: The schema's string fields like "description" currently
only use "minLength": 1 which allows whitespace-only values; update those
properties (e.g., the "description" property and the other string fields noted
in ranges 31-50 and 74-80) to include a non-whitespace pattern such as requiring
at least one non-space character (pattern: ".*\\S.*" or equivalent) so the JSON
Schema rejects whitespace-only strings and stays consistent with the generators
and runtime validation.
---
Nitpick comments:
In `@scripts/generate-openclaw-config.py`:
- Around line 203-219: Restrict validation so effects.openclawPlugins[*].path
must be inside the azul subtree "openclaw-plugins/": after making source_path =
Path(plugin["path"]) and rejecting absolute paths or any .. parts, normalize it
(e.g. source_path = source_path.relative_to(source_path.anchor) or
source_path.resolve() against registry_root.parent) and ensure its first path
component equals "openclaw-plugins" (reject otherwise), and then check existence
under registry_root.parent / source_path; finally derive expected_load_path from
that normalized path (e.g. "/usr/local/share/nemoclaw/openclaw-plugins/..."
built from source_path.without leading slashes) and validate
plugin["loadPath"].rstrip("/") against that value (use manifest_path, index,
plugin variables for error messages).
🪄 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: 9e605eb3-5a99-4d9d-b109-eb8b1b9b9e81
📒 Files selected for processing (6)
agents/hermes/generate-config.tsnemoclaw-blueprint/model-specific-setup/schema.jsonscripts/generate-openclaw-config.pytest/generate-hermes-config.test.tstest/generate-openclaw-config.test.tstest/validate-config-schemas.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- test/generate-openclaw-config.test.ts
- test/generate-hermes-config.test.ts
Selective E2E Results — ✅ All requested jobs passedRun: 25441432044
|
Selective E2E Results — ✅ All requested jobs passedRun: 25442080061
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
test/validate-config-schemas.test.ts (1)
294-301: ⚡ Quick winValidate the whole registry, not just the Kimi fixture.
This suite hard-codes one OpenClaw manifest and only exercises Hermes as a rejection case. Future files under
nemoclaw-blueprint/model-specific-setup/*/*.jsoncan drift without this test catching it, and the repo rule that the parent directory must matchagentis still unenforced. Please enumerate all checked-in manifests here, assertdirname(file) === agent, and keep a minimal positive Hermes fixture if there still isn’t a committed Hermes manifest.As per coding guidelines
nemoclaw-blueprint/model-specific-setup/**/*.json: Model-specific sandbox compatibility manifests must use one exact agent per manifest (use exact agent name likeopenclaworhermes) innemoclaw-blueprint/model-specific-setup/<agent>/directory; do not create shared multi-agent manifests.Also applies to: 335-347
🤖 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/validate-config-schemas.test.ts` around lines 294 - 301, Replace the single hard-coded Kimi fixture-based test in the "model-specific-setup/schema.json" suite with a loop that enumerates all committed JSON files under the glob "nemoclaw-blueprint/model-specific-setup/**/*.json"; for each file, load it with loadJSON, compile the schema with compileSchema("nemoclaw-blueprint/model-specific-setup/schema.json") (or reuse validate), and run the existing assertions (expectValid/expectInvalid) per-file; additionally assert that path.dirname(file) === agent (i.e., the parent directory name equals the agent string parsed from the file path) to enforce the one-agent-per-manifest rule, and if no Hermes manifest is present include/keep a minimal positive Hermes fixture so the Hermes rejection test still has a baseline.
🤖 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 `@nemoclaw-blueprint/model-specific-setup/schema.json`:
- Around line 69-88: The openclawPlugins schema currently allows arbitrary
non-whitespace strings for the "path" and "loadPath" properties; tighten these
to only permit safe relative paths under the OpenClaw staging tree by
disallowing leading slashes (absolute paths) and any ".." path segments and
restricting segment characters to a safe subset (alphanumerics, dot, underscore,
hyphen and forward slash). Update the "path" and "loadPath" property schemas in
the openclawPlugins item to use a pattern that rejects leading "/" and any ".."
segment (and optionally enforces a non-empty segment pattern), and add unit
tests that assert invalidation for examples like "/etc/passwd", "../secrets",
"subdir/../escape", and valid acceptance for "pluginA/main.js" and
"dir/sub_dir/plugin.so".
---
Nitpick comments:
In `@test/validate-config-schemas.test.ts`:
- Around line 294-301: Replace the single hard-coded Kimi fixture-based test in
the "model-specific-setup/schema.json" suite with a loop that enumerates all
committed JSON files under the glob
"nemoclaw-blueprint/model-specific-setup/**/*.json"; for each file, load it with
loadJSON, compile the schema with
compileSchema("nemoclaw-blueprint/model-specific-setup/schema.json") (or reuse
validate), and run the existing assertions (expectValid/expectInvalid) per-file;
additionally assert that path.dirname(file) === agent (i.e., the parent
directory name equals the agent string parsed from the file path) to enforce the
one-agent-per-manifest rule, and if no Hermes manifest is present include/keep a
minimal positive Hermes fixture so the Hermes rejection test still has a
baseline.
🪄 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: f7f6cee3-5475-49f7-8c41-0000fcf4d64d
📒 Files selected for processing (2)
nemoclaw-blueprint/model-specific-setup/schema.jsontest/validate-config-schemas.test.ts
Selective E2E Results — ✅ All requested jobs passedRun: 25442906865
|
There was a problem hiding this comment.
♻️ Duplicate comments (1)
nemoclaw-blueprint/model-specific-setup/schema.json (1)
80-88:⚠️ Potential issue | 🟠 Major | ⚡ Quick winTraversal is still allowed when
..is the first plugin segment.Line 83 and Line 88 run the negative lookahead after the fixed prefix, so
(?:^|/)no longer catches the..immediately following that prefix. Today bothopenclaw-plugins/../escapeand/usr/local/share/nemoclaw/openclaw-plugins/../escapestill match, which weakens the staging-tree boundary this PR is trying to enforce. Please move the traversal check to the start of the whole pattern and add those two samples to the negative test matrix.Suggested regex fix
"path": { "type": "string", "minLength": 1, - "pattern": "^openclaw-plugins/(?!.*(?:^|/)\\.\\.(?:/|$))[A-Za-z0-9._-]+(?:/[A-Za-z0-9._-]+)*$" + "pattern": "^(?!.*(?:^|/)\\.\\.(?:/|$))openclaw-plugins/[A-Za-z0-9._-]+(?:/[A-Za-z0-9._-]+)*$" }, "loadPath": { "type": "string", "minLength": 1, - "pattern": "^/usr/local/share/nemoclaw/openclaw-plugins/(?!.*(?:^|/)\\.\\.(?:/|$))[A-Za-z0-9._-]+(?:/[A-Za-z0-9._-]+)*$" + "pattern": "^(?!.*(?:^|/)\\.\\.(?:/|$))/usr/local/share/nemoclaw/openclaw-plugins/[A-Za-z0-9._-]+(?:/[A-Za-z0-9._-]+)*$" }Run this read-only check to confirm the current regex still accepts the first-segment traversal cases; the two
.../../escapelines should printtruebefore the fix andfalseafter it:#!/bin/bash set -euo pipefail node <<'NODE' const fs = require('node:fs'); const schema = JSON.parse( fs.readFileSync('nemoclaw-blueprint/model-specific-setup/schema.json', 'utf8'), ); const props = schema.properties.effects.properties.openclawPlugins.items.properties; const cases = [ ['path', props.path.pattern, 'openclaw-plugins/../escape'], ['path', props.path.pattern, 'openclaw-plugins/subdir/../escape'], [ 'loadPath', props.loadPath.pattern, '/usr/local/share/nemoclaw/openclaw-plugins/../escape', ], [ 'loadPath', props.loadPath.pattern, '/usr/local/share/nemoclaw/openclaw-plugins/subdir/../escape', ], ]; for (const [label, pattern, sample] of cases) { const re = new RegExp(pattern); console.log(`${label}\t${sample}\t${re.test(sample)}`); } NODE🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@nemoclaw-blueprint/model-specific-setup/schema.json` around lines 80 - 88, The regex for the "path" and "loadPath" patterns currently applies the traversal negative lookahead after the fixed prefix, allowing "../" as the first segment; update both patterns in schema.json so the (?!.*(?:^|/)\\.\\.(?:/|$)) negative lookahead appears at the very start of the whole pattern (before the fixed "openclaw-plugins" or "/usr/local/share/nemoclaw/openclaw-plugins/" prefix) to reject any leading ".." segment, and add the two samples "openclaw-plugins/../escape" and "/usr/local/share/nemoclaw/openclaw-plugins/../escape" to the negative test matrix mentioned in the review so they return false.
🤖 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.
Duplicate comments:
In `@nemoclaw-blueprint/model-specific-setup/schema.json`:
- Around line 80-88: The regex for the "path" and "loadPath" patterns currently
applies the traversal negative lookahead after the fixed prefix, allowing "../"
as the first segment; update both patterns in schema.json so the
(?!.*(?:^|/)\\.\\.(?:/|$)) negative lookahead appears at the very start of the
whole pattern (before the fixed "openclaw-plugins" or
"/usr/local/share/nemoclaw/openclaw-plugins/" prefix) to reject any leading ".."
segment, and add the two samples "openclaw-plugins/../escape" and
"/usr/local/share/nemoclaw/openclaw-plugins/../escape" to the negative test
matrix mentioned in the review so they return false.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: e6d79b7c-3b09-4479-8d2c-93e5d6c6a80e
📒 Files selected for processing (2)
nemoclaw-blueprint/model-specific-setup/schema.jsontest/validate-config-schemas.test.ts
Selective E2E Results — ✅ All requested jobs passedRun: 25450743668
|
Audit result: Hermes / Kimi K2.6Verdict: Hermes does not need a Kimi-specific affordance right now. Validated against PR head Observed configuration and runtime behavior:
Conclusion: Hermes is using OpenAI chat-completions with string message content and standard function tools, and it completed the terminal-loop acceptance path. That differs from the old OpenClaw failure class fixed by #3046. No Hermes Kimi manifest, runtime shim, or OpenClaw plugin reuse is justified from this evidence. Validation reported:
Remaining risk: this is one local Hermes/Kimi runtime proof, not a GitHub e2e matrix run. Reopen the decision if Hermes starts failing with Kimi tool-bearing requests, NemoClaw changes Hermes away from custom chat-completions on |
## Summary - Bump docs metadata to 0.0.36 and refresh generated NemoClaw user skills. - Document Model Router onboarding, validation retries, Ollama tool checks, Hermes policy behavior, and deployment verification updates. - Remove suppressed experimental command references from public docs per `docs/.docs-skip`. ## Source summary - #2202 -> `docs/get-started/quickstart.md`, `docs/inference/inference-options.md`, `docs/reference/architecture.md`: Document Model Router setup and routed inference architecture. - #3128 -> `docs/get-started/quickstart.md`, `docs/reference/commands.md`: Document deployment verification and HTTP 401 health handling. - #3104 -> `docs/inference/inference-options.md`: Document retry behavior for transient provider validation failures. - #3121 -> `docs/reference/architecture.md`: Document agent-scoped model/provider compatibility manifests. - #3046 -> `docs/reference/architecture.md`: Tie model-specific compatibility setup to known model/provider behavior. - #3097 -> `docs/inference/use-local-inference.md`: Document Ollama tool-calling capability validation. - #3082 -> `docs/reference/commands.md`: Document `NEMOCLAW_SANDBOX_NAME` as the interactive sandbox-name default. - f586cc5, 3442adf -> `docs/get-started/quickstart-hermes.md`, `docs/reference/network-policies.md`: Document Hermes agent-specific baseline policy endpoints. ## Test plan - `python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user` - `make docs` - `npm run build:cli` - `rg` skip-term scan for `docs/` and generated user skills Made with [Cursor](https://cursor.com) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Model Router provider for complexity-based routed inference. * Ollama/local inference onboarding now validates tool-calling capability. * Added `local-inference` network policy preset. * **Documentation** * New integration policy examples (Outlook, Telegram, Slack, Discord, GitHub, Jira, etc.). * Clarified config immutability workflow and sandbox writable paths. * Hermes baseline network policy documented. * **Improvements** * Health checks treat device-auth responses as live; transient validation retries. * Installer performs pre-install reachability checks; CLI onboarding gained a --fresh option. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Context
Follow-up to issue #2620: #2620
PR #3046 fixed the immediate OpenClaw/Kimi K2.6 managed
inference.localcompatibility path: #3046That fix left the compatibility behavior embedded directly in
scripts/generate-openclaw-config.py. This PR moves that behavior into an agent-aware registry so future model/provider compatibility work has an explicit home and cannot accidentally apply across OpenClaw and Hermes.Where the architecture landed
The model-specific setup architecture now has three explicit layers:
nemoclaw-blueprint/model-specific-setup/<agent>/*.jsonis the source of truth for deciding when model/provider compatibility setup applies. Every manifest declares exactly oneagent, a route match (modelIds,providerKey,inferenceApi,baseUrl), and declarative effects.openclawCompatandopenclawPlugins; Hermes validateshermesCompatshape and ignores OpenClaw manifests. The Hermes build-time generator is now a thin entrypoint overagents/hermes/config/, so future Hermes env parsing, config construction, registry handling, and serialization have explicit module homes instead of landing in one monolithic script.nemoclaw-blueprint/openclaw-plugins/; Hermes runtime code belongs underagents/hermes/. The registry decides activation, while agent-specific code performs runtime behavior.For this PR, the first registry entry is OpenClaw-only:
model-specific-setup/openclaw/kimi-k2.6-managed-inference.json. It preserves the Kimi K2.6 managedinference.localbehavior from PR #3046 by applying the same OpenClaw compat flags and loading the same Kimi OpenClaw plugin path. Hermes now has the architectural lane and validation path, but no Hermes Kimi behavior is added without a Hermes-specific repro and acceptance test.What this PR does
nemoclaw-blueprint/model-specific-setup/as the declarative registry for model/provider compatibility setup.agentfirst-class in every manifest. v1 manifests target exactly one agent, for exampleopenclaworhermes.model-specific-setup/openclaw/kimi-k2.6-managed-inference.json. This preserves the Kimi K2.6 managedinference.localbehavior from PR fix: support reasoning models in the OpenClaw harness #3046.agent: "openclaw"instead of hardcoding Kimi constants and predicates in the generator.agents/hermes/config/, keepingagents/hermes/generate-config.tsas orchestration only.nemoclaw-blueprint/openclaw-plugins/generically and normalizes plugin directory/file permissions withfind, so future OpenClaw model-specific plugins do not require one-off Dockerfile edits.AGENTS.mdand the registry README: OpenClaw executable wrappers go underopenclaw-plugins/; Hermes executable wrappers go underagents/hermes/; manifests stay declarative.What this PR intentionally does not do
Tests
npm run build:clinpm run typecheck:clinpm run lintnpx vitest run test/generate-hermes-config.test.ts test/validate-config-schemas.test.ts test/generate-openclaw-config.test.tspython3 -m py_compile scripts/generate-openclaw-config.pybash -n test/e2e/test-kimi-inference-compat.sh && bash -n agents/hermes/start.sh && bash -n scripts/lib/sandbox-init.shgit diff --checkE2E Gate
be8c398b:nightly-e2e/kimi-inference-compat-e2e: https://github.com/NVIDIA/NemoClaw/actions/runs/25450743668tls handshake eofwhile creating/listing sandboxes. The runner gate is the merge gate for this PR.Summary by CodeRabbit
New Features
Improvements
Documentation
Tests