No supported path to set NEMOCLAW_REASONING on an existing sandbox; local reasoning models stall the agent idle timeout
- Dominant language
- TypeScript
- Stars
- 22.5k
- Forks
- 3.1k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 715
Description
### Investigation Summary
- The model is a reasoning model: vLLM is launched with `--reasoning-parser nemotron_v3`, and a direct API call returns ~130 of 149 completion tokens in the `reasoning` field before any `content` (with `max_tokens: 20`, `content` is `null` and `finish_reason: "length"`).
- OpenClaw is configured as if it is not: `openclaw.json` shows `"reasoning": false` on the model entry, and the container env shows `NEMOCLAW_REASONING=false`.
- The config generator supports the flag — `scripts/generate-openclaw-config.mts` contains `const reasoning = (env.NEMOCLAW_REASONING || "false") === "true";` and `Dockerfile` has `ARG NEMOCLAW_REASONING=false` — but passing `NEMOCLAW_REASONING=true` to the installer, to `rebuild --yes`, and to the installer with `NEMOCLAW_RECREATE_SANDBOX=1` leaves the baked value unchanged in all three cases.
- Resulting failure: agent runs abort with `LLM idle timeout (120s): no response from model` while logs show `lastProgress=model_call:stream_progress lastProgressAge=117s` — the stream is open and emitting reasoning tokens, but they are not credited as progress.
- Unknown: whether the intended path to set this on an existing sandbox is a different command/flag, and whether the idle timer is designed to ignore reasoning-token progress or this is unintended.
### Description
On a local reasoning model (Nemotron 3 Super via vLLM with `--reasoning-parser nemotron_v3`), agent runs consistently fail with `LLM idle timeout (120s): no response from model`, even for simple single-tool requests such as "check my email".
The model is working correctly. A direct call to the vLLM endpoint returns a valid response quickly, but the majority of generated tokens are emitted in the `reasoning` field before any `content` appears. During an agent run the stream is open and progressing (`lastProgress=model_call:stream_progress`), yet the idle detector fires at 120s because no `content` has arrived.
The generated `openclaw.json` declares `"reasoning": false` for this model. `scripts/generate-openclaw-config.mts` reads `NEMOCLAW_REASONING` to set that value, and the Dockerfile exposes `ARG NEMOCLAW_REASONING=false`, but there appears to be no user-facing way to set it to `true` on an existing sandbox — the env var is not picked up by the installer's recovery path, by `rebuild`, or by recreate.
Expected: either a supported way to declare a local model as a reasoning model on an existing sandbox, or reasoning-token stream progress should reset the idle timer so runs are not aborted while the model is actively generating.
### Reproduction Steps
1. Onboard a sandbox on DGX Spark using a local vLLM endpoint serving a reasoning model (Nemotron 3 Super, launched with `--reasoning-parser nemotron_v3`).
2. Confirm the model emits reasoning before content:
curl -s http://localhost:8000/v1/chat/completions -H "Content-Type: application/json" \
-d '{"model":"nemotron-3-super","messages":[{"role":"user","content":"Say hello"}],"max_tokens":20}'
→ `"content": null`, `finish_reason: "length"`, all tokens in `reasoning`.
3. Observe the generated config declares the model as non-reasoning:
ssh openshell- "cat /sandbox/.openclaw/openclaw.json | python3 -m json.tool | grep -A2 -B2 reasoning"
→ `"reasoning": false`
4. Attempt to set the flag, in three ways:
a. Installer: NEMOCLAW_REASONING=true NEMOCLAW_INSTALL_REF=v0.0.92 ... ./nemoclaw.sh
b. Rebuild: NEMOCLAW_REASONING=true nemoclaw rebuild --yes
c. Recreate: NEMOCLAW_REASONING=true NEMOCLAW_RECREATE_SANDBOX=1 ... ./nemoclaw.sh
5. After each attempt, verify it did not take:
docker inspect $(docker ps -q --filter name=openshell-) --format '{{json .Config.Env}}' | python3 -m json.tool | grep -i reasoning
→ `NEMOCLAW_REASONING=false`
6. Send the agent any request requiring a tool call. The run aborts at 120s with `LLM idle timeout`.
### Environment
- Platform: NVIDIA DGX Spark (GB10, aarch64), 128GB unified memory
- Host OS: Ubuntu 24.04 / DGX OS 7.5.0, kernel 6.17.0-1021-nvidia
- GPU driver: 580.159.03, CUDA 13.0
- NemoClaw: v0.0.92
- OpenShell: 0.0.85 (docker driver)
- OpenClaw: 2026.7.1
- Node.js: v22.22.2
- Inference: vLLM v0.18.1-cu130 (Docker), serving `nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4`
launched with `--reasoning-parser nemotron_v3 --enable-auto-tool-choice --tool-call-parser qwen3_coder`
- Relevant config: `agents.defaults.timeoutSeconds: 600`, `thinkingDefault: "off"`,
container env `NEMOCLAW_MAX_TOKENS=4096`, `NEMOCLAW_TOOL_DISCLOSURE=progressive`
- Observed generation rate: ~12 tokens/sec
### Debug Output
Full nemoclaw debug --quick output available; the relevant excerpts are in the Logs section above. Happy to attach the complete tarball if useful.
### Logs
```shell
### 1. Gateway declares the model as non-reasoning
2026-07-24T05:37:46.869+00:00 [gateway] agent model: inference/nemotron-3-super (thinking=off, fast=off)
### 2. But vLLM is serving it WITH a reasoning parser
~/vllm/start-super.sh:
--reasoning-parser nemotron_v3
--enable-auto-tool-choice
--tool-call-parser qwen3_coder
### 3. And the model demonstrably emits reasoning before content
$ curl -s http://localhost:8000/v1/chat/completions -H "Content-Type: application/json" \
-d '{"model":"nemotron-3-super","messages":[{"role":"user","content":"Say hello"}],"max_tokens":20}'
"content": null,
"finish_reason": "length",
"reasoning": "We are to say hello.\n The instruction is simple: \"Say hello\"\n We'll output the string"
Same request with max_tokens=500 completes normally in 12.4s:
149 completion tokens total, ~130 emitted as `reasoning`,
content = "Hello! 👋 How can I assist you today?"
### 4. Config and container env both show reasoning disabled
$ ssh openshell- "cat /sandbox/.openclaw/openclaw.json | python3 -m json.tool | grep -A2 -B2 reasoning"
"id": "nemotron-3-super",
"name": "inference/nemotron-3-super",
"reasoning": false,
$ docker inspect $(docker ps -q --filter name=openshell-) --format '{{json .Config.Env}}' | grep -i reasoning
"NEMOCLAW_REASONING=false"
(unchanged after passing NEMOCLAW_REASONING=true to the installer,
to `rebuild --yes`, and to the installer with NEMOCLAW_RECREATE_SANDBOX=1)
### 5. Result: agent runs abort while the model is still streaming
2026-07-23T23:50:43.177 [provider-transport-fetch] [model-fetch] start provider=inference
api=openai-completions model=nemotron-3-super method=POST
url=https://inference.local/v1/chat/completions timeoutMs=undefined
2026-07-23T23:50:43.224 [provider-transport-fetch] [model-fetch] response
status=200 elapsedMs=46 contentType=text/event-stream; charset=utf-8
2026-07-23T23:53:25.630 [diagnostic] long-running session: state=processing age=145s
activeWorkKind=model_call lastProgress=model_call:stream_progress
lastProgressAge=117s recovery=none
2026-07-23T23:53:30.536 [agent/embedded] embedded run failover decision: stage=assistant
decision=surface_error reason=timeout from=inference/nemotron-3-super
rawError=LLM idle timeout (120s): no response from model
The stream opens in 46ms and is actively producing reasoning tokens,
but the idle detector fires at 120s because no `content` has arrived.
### Related (possibly separate issue): Telegram webhook management fails at startup
2026-07-24T05:37:49.635 [telegram] deleteWebhook failed: Network request for 'deleteWebhook' failed!
2026-07-24T05:37:49.639 [telegram] deleteMyCommands failed: Network request for 'deleteMyCommands' failed!
2026-07-24T05:37:49.653 [telegram] setMyCommands failed: Network request for 'setMyCommands' failed!
[telegram] [default] bridge did not start within 15s; check channels.telegram.enabled, plugin entries, and gateway log
```
### Checklist
- [x] I confirmed this bug is reproducible
- [x] I searched existing issues and this is not a duplicate
Contributor guide
Research direction
Start with scripts/generate-openclaw-config.mts and the NEMOCLAW_REASONING declaration in Dockerfile, then trace how the installer, rebuild --yes, and NEMOCLAW_RECREATE_SANDBOX=1 pass environment values into an existing sandbox. Reproduce the generated reasoning:false configuration and the 120-second idle timeout with the supplied vLLM reasoning stream. Done means either an existing sandbox can reliably receive reasoning:true or reasoning-token progress prevents the idle timeout.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, typescript
- Domain
- ai, backend, devops
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100