Commit 0d5c876
## Summary
A `rebuild` that has to recover the recorded provider from the
registered gateway credential replaced the sandbox with no reasoning
configuration: the replacement recorded
`compatibleEndpointReasoningEffort = null` even though the authoritative
resume configuration carried `high`, so the effort had to be restored by
hand with `inference set --reasoning-effort high`. Three NemoClaw-owned
gaps combined, and all three are fixed here. The documented contract in
`docs/inference/configure-model-capabilities.mdx` — "a resumed onboard
and `nemoclaw <sandbox-name> rebuild` both replay those recorded values"
— now holds on the recovered path too. No new flag, environment
variable, or configuration surface: the reporter's command is `rebuild
--yes`, and it works unchanged.
## Related Issue
Fixes #7940
## Changes
- `src/lib/onboard/session-updates.ts`: `OnboardSessionUpdateInput` and
`toSessionUpdates()` never carried `compatibleEndpointReasoningEffort`,
so the value the callers in `machine/handlers/provider-inference.ts`
supply was dropped before the session was written — and therefore before
the registry entry that `onboard/sandbox-registration.ts` writes from
that session. `SessionUpdates` already supported the field. The
normalizer now maps it, keeping the `undefined` leave-unchanged versus
explicit `null` clear semantics, and normalizing through
`normalizeReasoningEffort` so an unrecognized value clears the recorded
effort instead of persisting an effort the endpoint never received. This
gap alone also made a *fresh* compatible-endpoint onboard with
`NEMOCLAW_REASONING_EFFORT=high` record `null`.
- `src/lib/actions/sandbox/rebuild-recreate-phase.ts`: the recreate
isolates the ambient onboard-selection environment so an unrelated
onboard cannot steer it (#5735), but it re-seeded only
`NEMOCLAW_POLICY_TIER`. Both the recovered provider selection and
`src/lib/onboard/dockerfile-patch.ts` — which bakes `ARG
NEMOCLAW_REASONING_EFFORT` into the sandbox image — read the value from
`process.env`, so the inner `onboard --resume` ran with no reasoning
inputs. The recreate now re-seeds `NEMOCLAW_REASONING` and
`NEMOCLAW_REASONING_EFFORT` from the authoritative `resumeConfig` inside
the isolated window, only for the `compatible-endpoint` provider that
can use them. The existing isolation restore returns the caller's
ambient values on success and on failure, so the seed stays scoped to
the recreate.
- `src/lib/onboard/machine/handlers/provider-inference.ts`: the
recovered branch reaches `resolveRecoveredProviderCredentialReuse()` (no
host credential copy, validated gateway credential) and sets
`reuseGatewayCredentialWithoutLocalKey`, which short-circuits
`validateSelectedRemoteModel()` — the only caller of
`configureCompatibleEndpointReasoning[Effort]()` for a custom endpoint.
The selection therefore reported no reasoning at all and cleared the
recorded values. The handler now replays the recorded mode and effort
for that same route when the selection reused the gateway credential.
This is the boundary that owns the recorded route, so the fix also
covers a plain recovered `onboard --resume`, not only a rebuild
recreate.
- `src/lib/actions/sandbox/rebuild-recreate-reasoning.test.ts` (new):
the recreate observes the recorded values, ambient values are restored
on success and on a failed recreate, a resume configuration that no
longer carries an effort clears it for the recreate, and a provider that
cannot use reasoning still sees the isolated environment (#5735
unchanged).
-
`src/lib/onboard/machine/handlers/provider-inference-authoritative-recovery.test.ts`,
`src/lib/onboard/session-updates.test.ts`,
`test/helpers/rebuild-flow-lifecycle-cases.ts`: regression coverage for
the recovered gateway-credential replay, the normalizer's nullable
contract, and the rebuild lifecycle case that now asserts the effort
survives.
- Follow-up commit `1b1bf3e39` (CodeRabbit finding): the replay applied
the recorded values without naming them, so an exported
`NEMOCLAW_REASONING`/`NEMOCLAW_REASONING_EFFORT` that disagreed with the
recorded value was discarded silently — the exact no-op #7462 removed
from the sibling resumed-selection path. The replay now emits the same
`describeIgnoredReasoningEnv()` / `describeIgnoredReasoningEffortEnv()`
report before configuring, extracted into
`replayRecoveredCompatibleEndpointReasoning()` to keep
`handleProviderInferenceState` under the Biome cognitive-complexity
budget. A rebuild recreate seeds the environment from the same recorded
configuration, so it stays silent. Covered by a new case that fails
without the source change, strengthened in `2b0610047` to assert that
the report names the recorded values, not only the ignored ambient ones.
Each new assertion was confirmed to fail without its corresponding
source change.
## Type of Change
- [x] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)
## Quality Gates
- [x] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [ ] Tests not applicable — justification:
- [ ] Docs updated for user-facing behavior changes
- [x] Docs not applicable — justification: no user-visible surface
changes. `docs/inference/configure-model-capabilities.mdx` already
documents the behavior this restores ("Onboarding records the reasoning
flag and the reasoning effort in the sandbox's session and registry
entry. A resumed onboard and `nemoclaw <sandbox-name> rebuild` both
replay those recorded values"), and the `inference set
--reasoning-effort` contract, the route rules, and the reasoning-effort
inputs are all unchanged.
- [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: the credential path is
untouched. The recovered branch still reuses the validated gateway
credential and still skips `validateSelectedRemoteModel()`; this change
only replays the already-recorded reasoning mode and effort for that
selection, and no credential value is read, written, logged, or moved.
The reseeded environment values are the two reasoning variables, taken
from the authoritative resume configuration rather than the ambient
environment, and they are restored by the existing `#5735` isolation
restore on success and failure — so ambient-environment isolation is
preserved, not weakened. `codex review --base origin/main` reports no
findings at head `1b1bf3e39`.
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:
## Documentation Writer Review
- [x] Documentation writer subagent reviewed the completed changes
- Result: `docs-accurate-no-change`
- Evidence: reviewed the changed sources against the reasoning-effort
documentation. `docs/inference/configure-model-capabilities.mdx` already
states that a resumed onboard and `nemoclaw <sandbox-name> rebuild`
replay the recorded reasoning flag and reasoning effort, and that an
exported `NEMOCLAW_REASONING`/`NEMOCLAW_REASONING_EFFORT` does not
change them; that is exactly the contract this change restores on the
recovered path, so the page is accurate before and after.
`docs/reference/commands.mdx` documents `inference set
--reasoning-effort`, which is unchanged. No new flag, environment
variable, default, error message, or command output is introduced, so no
page needs an edit and no changelog surface changes. Review performed by
the primary agent in this session; no separate subagent surface was
used. Re-reviewed at head `1b1bf3e39` after the CodeRabbit follow-up:
that commit adds an operator-facing report that reuses the existing
`Ignoring NEMOCLAW_REASONING...` message already documented on the same
page, so no page needs an edit. Re-checked at head `2b0610047`: that
commit strengthens a test assertion only, so no documentation change is
needed. The governing `AGENTS.md` blob remains `c052d60aa`.
- Agent: Claude Code
<!-- docs-review-head-sha: 2b06100 -->
<!-- docs-review-agents-blob-sha: c052d60 -->
## Verification
- [x] PR description includes a `Signed-off-by:` line and every commit
appears as `Verified` in GitHub
- [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run validate:pr` passed after refreshing `origin/main` when hooks
were skipped or unavailable — `npm run validate:pr` after `git fetch
origin main` and a rebase onto `origin/main` `387cb0864`: all prek
pre-commit hooks, commitlint, and pre-push hooks Passed (exit 0).
commitlint reports 0 problems and 1 `footer-leading-blank` warning for
the `Signed-off-by:` trailer that follows the `Fixes` line.
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — command/result or justification: `npx
vitest run --project cli src/lib/onboard/session-updates.test.ts
src/lib/actions/sandbox/rebuild-recreate-reasoning.test.ts
src/lib/onboard/machine/handlers/provider-inference-authoritative-recovery.test.ts
src/lib/actions/sandbox/rebuild-env-isolation.test.ts
src/lib/actions/sandbox/rebuild-flow.test.ts
src/lib/onboard/setup-nim-flow.test.ts` → 6 files / 136 tests passed;
`npm run typecheck:cli` and `npm run checks:repository` clean
- [x] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result: `npm test` at head
`1b1bf3e39` → 23188 passed, 14 failed across 8 files, every one
pre-existing or load-induced and unrelated to this change:
- `test/install-station-dgx-os.test.ts` (5),
`test/install-station-host-preparation.test.ts` (3),
`test/install-station-package-transaction.test.ts` (1): this host has a
pending reboot (`/var/run/reboot-required`, dated 2026-07-28), so
`station-prepare` refuses with `A reboot is pending on the Station
factory image` / `An unrelated reboot is already pending`. All 9
reproduce identically in a clean `origin/main` worktree.
- `test/issue-5667-hosted-inference-model-namespace.test.ts` (1):
reproduces identically in a clean `origin/main` worktree, in isolation.
- `test/package-contract/managed-image-registry-transport.test.ts` (1):
the packed-CLI `--omit=dev` install fails registry resolution with `npm
error notarget No matching version found for @aws-sdk/core@^3.977.3`, an
upstream dependency-resolution failure with no relation to this change.
- `test/gateway-state-reconcile-2276.test.ts`,
`test/rebuild-credential-preflight.test.ts`,
`test/langchain-deepagents-code-image-credentials.test.ts` (1 each):
15-60 s timeouts under full-suite parallel load. Re-running exactly
those three files on this branch passes 143/143 in 80 s. The first two
exercise the rebuild lifecycle this change touches, so they were re-run
specifically to confirm the change is not the cause.
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings (doc changes only)
- [ ] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)
### Reporter-workflow E2E (Linux x86_64, real worktree CLI)
Every command below ran the worktree CLI (`./bin/nemoclaw.js`), never a
global `nemoclaw`. Gateway port 8194 with an isolated state root
(`~/.nemoclaw/gateways/8194`), sandbox `e2e-7940-effort`, a local
OpenAI-compatible mock endpoint on `http://127.0.0.1:8000/v1`, a
configured Telegram channel, and presets `telegram,local-inference`. The
reporter's step 3 is reproduced by leaving `COMPATIBLE_API_KEY` out of
the rebuild environment while the validated gateway credential stays
registered, which is what forces the recovered-provider branch.
**Before the fix** (`dist` built from `origin/main`):
```text
$ NEMOCLAW_REASONING=true NEMOCLAW_REASONING_EFFORT=high ./bin/nemoclaw.js onboard --fresh --non-interactive ...
session.compatibleEndpointReasoningEffort = null # the normalizer dropped it
registry.compatibleEndpointReasoningEffort = null
generated openclaw.json "reasoning_effort" = "high" # baked from the ambient env
$ ./bin/nemoclaw.js e2e-7940-effort inference set --provider compatible-endpoint --model ... --reasoning-effort high
session.compatibleEndpointReasoning = true, effort = high # documented pre-rebuild state restored
registry effort = high
$ ./bin/nemoclaw.js e2e-7940-effort rebuild --yes # no COMPATIBLE_API_KEY in the environment
Revalidating recovered compatible-endpoint identity…
Reusing existing gateway credential…
exit 0
session.compatibleEndpointReasoning = null # the recorded reasoning mode was lost
```
The recorded effort survived that run only because the same normalizer
defect also dropped the recovered `null`; the reasoning mode, which the
normalizer did carry, was cleared to `null` — the reporter's defect.
**After the fix** (`dist` built from this branch, same commands):
```text
$ NEMOCLAW_REASONING=true NEMOCLAW_REASONING_EFFORT=high ./bin/nemoclaw.js onboard --fresh --non-interactive ...
session reasoning = true, effort = high
registry reasoning = true, effort = high
$ ./bin/nemoclaw.js e2e-7940-effort rebuild --yes # no COMPATIBLE_API_KEY, same recovered branch
exit 0
session reasoning = true, effort = high
registry reasoning = true, effort = high
in-sandbox /sandbox/.openclaw/openclaw.json "reasoning_effort" = "high"
image built by the recreate (nemoclaw-sandbox-local:e2e-7940-effort-1785467801916) has the same value baked in
```
All three recording surfaces the issue names — onboard session,
replacement registry row, and generated OpenClaw configuration — keep
`high` across the recovered rebuild.
---
Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Preserved compatible-endpoint reasoning mode and effort settings
during onboarding recovery and sandbox recreation.
* Added support for storing, restoring, and clearing reasoning effort
settings in onboarding sessions.
* Ensured recovered settings override conflicting ambient configuration
when applicable.
* **Bug Fixes**
* Prevented reasoning configuration from being lost during sandbox
rebuilds or credential-based recovery.
* **Tests**
* Added coverage for successful recovery, failure cleanup, stale-value
removal, and provider-specific behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
Co-authored-by: J. Yaunches <jyaunches@nvidia.com>
1 parent 7eb0369 commit 0d5c876
7 files changed
Lines changed: 452 additions & 2 deletions
File tree
- src/lib
- actions/sandbox
- onboard
- machine/handlers
- test/helpers
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
193 | 194 | | |
194 | 195 | | |
195 | 196 | | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
196 | 208 | | |
197 | 209 | | |
198 | 210 | | |
| |||
Lines changed: 208 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
Lines changed: 116 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
85 | 85 | | |
86 | 86 | | |
87 | 87 | | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
88 | 204 | | |
0 commit comments