Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
24a97b8
fix(hermes): honor Ollama context floor
HwangJohn Jul 13, 2026
dd2cd37
docs(hermes): document Ollama context floor helpers
HwangJohn Jul 14, 2026
9d340ab
Merge branch 'main' into codex/6760-hermes-ollama-context
cv Jul 14, 2026
6a7e29a
fix(hermes): verify Ollama runtime context floor
cjagwani Jul 14, 2026
c1b25f5
merge(main): sync current main into PR 6767
cjagwani Jul 14, 2026
17752d6
refactor(onboard): extract Ollama context outcome
cjagwani Jul 14, 2026
94ac846
fix(onboard): record Ollama resume repair failures
cjagwani Jul 14, 2026
f6e92b6
fix(onboard): require strict Ollama runtime proof
cjagwani Jul 14, 2026
cbbc2e1
test(onboard): keep strict fallback cases linear
cjagwani Jul 14, 2026
7aa3e61
merge: sync Hermes Ollama context with main
HwangJohn Jul 15, 2026
910f064
chore(onboard): keep Hermes context merge net neutral
HwangJohn Jul 15, 2026
f91962a
fix(onboard): exit pinned Ollama context failures
cjagwani Jul 15, 2026
3944cdf
test(hermes): harden Ollama context coverage
cjagwani Jul 15, 2026
a203b46
merge: sync main into Hermes Ollama context fix
cjagwani Jul 15, 2026
74e3fee
merge: sync main into Hermes Ollama context fix
cjagwani Jul 15, 2026
b221699
merge: sync main into Hermes Ollama context fix
cjagwani Jul 15, 2026
de3f940
merge: sync main into Hermes Ollama context fix
cjagwani Jul 15, 2026
7f4ef71
merge: sync main into Hermes Ollama context fix
cjagwani Jul 15, 2026
14efdac
merge: sync main into Hermes context floor
cjagwani Jul 15, 2026
a8dde36
merge: sync main into Hermes context floor
cjagwani Jul 15, 2026
206aabf
merge: sync main into Hermes context floor
cjagwani Jul 15, 2026
8d807f9
merge: sync Hermes context floor with main
cv Jul 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions agents/hermes/config/build-env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import { isObjectRecord } from "./object-record.ts";

export type HermesWebSearchProvider = "tavily";

/** Minimum context window Hermes accepts for generated configuration. */
export const MIN_HERMES_CONTEXT_WINDOW = 64_000;

export type HermesBuildSettings = {
model: string;
baseUrl: string;
Expand All @@ -29,6 +32,7 @@ export type HermesBuildSettings = {
};
};

/** Read and validate the environment consumed by the Hermes config generator. */
export function readHermesBuildSettings(env: NodeJS.ProcessEnv): HermesBuildSettings {
const model = readRequiredEnv(env, "NEMOCLAW_MODEL");
const baseUrl = readRequiredEnv(env, "NEMOCLAW_INFERENCE_BASE_URL");
Expand All @@ -50,14 +54,24 @@ export function readHermesBuildSettings(env: NodeJS.ProcessEnv): HermesBuildSett
};
}

// Parse NEMOCLAW_CONTEXT_WINDOW as a positive integer of tokens. Empty, absent,
// or malformed values return null so the generated config omits context_length
// and Hermes keeps auto-detecting from the endpoint's /v1/models. See #6177.
/**
* Parse `NEMOCLAW_CONTEXT_WINDOW` for Hermes config generation.
*
* Empty, absent, or malformed values return null so Hermes keeps auto-detecting
* from the endpoint's `/v1/models`; explicit values below the Hermes floor fail
* before writing an unusable config. See #6177.
*/
function readContextWindow(env: NodeJS.ProcessEnv): number | null {
const raw = (env.NEMOCLAW_CONTEXT_WINDOW || "").trim();
if (!/^[1-9][0-9]*$/.test(raw)) return null;
const parsed = Number(raw);
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null;
if (!Number.isSafeInteger(parsed) || parsed <= 0) return null;
if (parsed < MIN_HERMES_CONTEXT_WINDOW) {
throw new Error(
`Hermes NEMOCLAW_CONTEXT_WINDOW must be at least ${MIN_HERMES_CONTEXT_WINDOW} tokens, got ${parsed}`,
);
}
return parsed;
}

function readWebSearchProvider(env: NodeJS.ProcessEnv): HermesWebSearchProvider | null {
Expand Down
10 changes: 8 additions & 2 deletions docs/inference/configure-model-limits.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,21 @@ Hermes accepts `NEMOCLAW_CONTEXT_WINDOW` as its model-limit override.

| Variable | Values | Default |
|---|---|---|
| `NEMOCLAW_CONTEXT_WINDOW` | Positive integer in tokens | Unset so Hermes auto-detects |
| `NEMOCLAW_CONTEXT_WINDOW` | Positive integer, at least `64000` tokens | Unset so Hermes auto-detects |

```bash
export NEMOCLAW_CONTEXT_WINDOW=65536
$$nemoclaw onboard
```

When onboarding resolves a valid value, NemoClaw writes it as `model.context_length` in `/sandbox/.hermes/config.yaml`.
If no explicit or probed value is available, the field remains unset so Hermes can auto-detect it from the endpoint.
For non-Ollama endpoints, the field remains unset when no explicit or probed value is available so Hermes can auto-detect it from the endpoint.
When NemoClaw starts Local Ollama on macOS or Linux, it requests at least `64000` tokens.
Fresh onboarding then verifies the loaded model's actual `context_length` through `/api/ps`.
Resumed onboarding and sandbox rebuilds warm the exact recorded Ollama model and repeat this verification before reusing its route.
When `NEMOCLAW_CONTEXT_WINDOW` is larger than `64000`, the Ollama runtime must provide at least that larger value.
Onboarding stops before building the sandbox when Ollama reports a smaller, missing, or malformed value and shows the required `OLLAMA_CONTEXT_LENGTH` value for restarting Ollama.
Setting `NEMOCLAW_CONTEXT_WINDOW` does not raise the Ollama daemon's runtime context or bypass this check.

</AgentOnly>

Expand Down
15 changes: 15 additions & 0 deletions docs/inference/set-up-ollama.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ If the validation probe times out, NemoClaw retries with a larger timeout before
Each Ollama-backed OpenClaw passthrough checks whether the selected model is still loaded and sends a bounded warm-up request when necessary.
</AgentOnly>

<AgentOnly variant="hermes">
Hermes requires at least `64000` tokens, so NemoClaw requests that host-side context length when it starts Ollama on macOS or Linux.
Fresh onboarding verifies after model warm-up that `/api/ps` reports at least `64000` for the loaded model.
Resumed onboarding and sandbox rebuilds warm the exact recorded Ollama model and repeat this verification before reusing its route.
When `NEMOCLAW_CONTEXT_WINDOW` is unset, NemoClaw writes the verified runtime value as `model.context_length` in `/sandbox/.hermes/config.yaml`.
An explicit `NEMOCLAW_CONTEXT_WINDOW` must be at least `64000`; NemoClaw writes that value only when the loaded model reports at least the same context length.
If an existing or unmanaged daemon reports less, omits the value, or returns a malformed value, onboarding stops before building the sandbox and shows the required `OLLAMA_CONTEXT_LENGTH` value for restarting Ollama.
</AgentOnly>

## Use Windows-Host Ollama from WSL

When NemoClaw runs in WSL, the provider menu can offer these Windows-host actions:
Expand Down Expand Up @@ -201,6 +210,12 @@ It does not make the larger models usable on N1X, reject an explicitly selected
When Ollama reports a context length below `16384` and `NEMOCLAW_CONTEXT_WINDOW` is unset, NemoClaw writes a `contextWindow` of `16384` so the agent prompt and tool definitions fit better than the stock daemon default.
</AgentOnly>

<AgentOnly variant="hermes">
When `NEMOCLAW_CONTEXT_WINDOW` is unset, NemoClaw writes a valid loaded-model context length of at least `64000` as `model.context_length`.
When you set a larger value explicitly, the loaded model must report at least that value before NemoClaw writes the explicit value.
When the runtime value is lower or cannot be verified, onboarding stops and tells you which `OLLAMA_CONTEXT_LENGTH` value to use when restarting the host daemon before retrying.
</AgentOnly>

If the initial validation times out during a cold load, NemoClaw retries once with a 300-second probe budget.
This retry also applies to tight-VRAM hosts where model warm-up can spill from GPU to CPU.

Expand Down
3 changes: 2 additions & 1 deletion docs/reference/commands.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3320,6 +3320,7 @@ Hermes-specific onboarding configuration:
| `NEMOCLAW_NOUS_AUTH_METHOD` | same as `NEMOCLAW_HERMES_AUTH_METHOD` | Nous-specific alias for Hermes Provider authentication selection. |
| `NEMOCLAW_HERMES_TOOL_GATEWAYS` | comma-separated list | Selects managed Hermes tool gateways in non-interactive onboarding. Valid values are `nous-web`, `nous-image`, `nous-audio`, `nous-browser`, and `nous-code`; the `nous-` prefix is optional. Unknown values fail before sandbox creation. |
| `NEMOCLAW_HERMES_TOOL_GATEWAY_PRESETS` | comma-separated list | Back-compatible alias for `NEMOCLAW_HERMES_TOOL_GATEWAYS`. |
| `NEMOCLAW_CONTEXT_WINDOW` | positive integer, at least `64000` tokens | Overrides `model.context_length` in the built Hermes config. Fresh and resumed Local Ollama onboarding, including sandbox rebuilds, must verify a loaded runtime context at least as large as this value. |
| `NEMOCLAW_EXTRA_PLACEHOLDER_KEYS` | whitespace- or comma-separated list of upper-snake env keys | Adds operator-supplied OpenShell provider rows so per-profile credentials such as `TELEGRAM_BOT_TOKEN_AGENT_A` flow through the same out-of-process placeholder injection that the canonical channel tokens use, instead of being baked into each Hermes profile `.env` as raw text. Refer to [Extra placeholder keys](#extra-placeholder-keys) for the entry shape and validation rules. |

</AgentOnly>
Expand Down Expand Up @@ -3432,7 +3433,7 @@ Set them before running `$$nemoclaw onboard`.
| Variable | Format | Effect |
|----------|--------|--------|
| `NEMOCLAW_YES` | `1` to enable | Auto-accepts confirmation prompts (`--yes` equivalent) including in helpers like the Ollama proxy auth setup, but does not accept managed-vLLM storage warnings. |
| `NEMOCLAW_OLLAMA_NO_AUTOSTART` | `1` to enable | Skips the wizard's eager Ollama auto-start during inference-provider selection (equivalent to passing `--no-ollama-autostart`). When set and Ollama is not running on `localhost:11434`, the `$$nemoclaw onboard` Local Ollama path prints a warning and selects the default fallback model instead of spawning `ollama serve`. The flag covers only the provider-selection step; later setup steps (auth proxy, validation, model warm) still expect a reachable Ollama. On Linux hosts with a systemd Ollama unit, the loopback-override path may still restart the daemon before this gate runs. |
| `NEMOCLAW_OLLAMA_NO_AUTOSTART` | `1` to enable | Skips the wizard's eager Ollama auto-start during inference-provider selection (equivalent to passing `--no-ollama-autostart`). When set and Ollama is not running on `localhost:11434`, an agent that uses the legacy `16384`-token context floor, currently OpenClaw, prints a warning and selects the default fallback model instead of spawning `ollama serve`. An agent that requires a larger verified runtime context, currently Hermes at `64000` tokens, returns to interactive provider selection or exits when the Ollama provider is pinned or onboarding is non-interactive. The flag covers only the provider-selection step; later setup steps (auth proxy, validation, model warm) still expect a reachable Ollama. On Linux hosts with a systemd Ollama unit, the loopback-override path may still restart the daemon before this gate runs. |
| `NEMOCLAW_NON_INTERACTIVE_SUDO_MODE` | `prompt` or empty/unset | When set to `prompt`, allows non-interactive onboarding to use prompt-capable `sudo` for host setup steps that require elevation, which can ask for a password. Empty/unset is the default and uses `sudo -n`, which fails instead of asking for a password. Any other value is rejected. |
| `NEMOCLAW_NO_EXPRESS` | `1` to enable | Installer-only. Skips the DGX Spark, DGX Station, and Windows WSL express install prompt and continues with the normal interactive onboarding flow. |
| `NEMOCLAW_EXPERIMENTAL` | `1` to enable | Surfaces experimental providers and flows in onboarding. |
Expand Down
36 changes: 36 additions & 0 deletions docs/reference/troubleshooting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2444,6 +2444,9 @@ If the process exists but the endpoint is unreachable, use the restart action wh
### Ollama inference fails or hangs in WSL

Ollama configures context length based on your hardware.

<AgentOnly variant="openclaw">

On some GPUs (for example RTX 3500), the default context length is not sufficient for OpenClaw.
During onboarding, NemoClaw raises loaded-model context lengths below `16384` to `16384` when `NEMOCLAW_CONTEXT_WINDOW` is unset.
Set the variable manually when you need a different value or when you run Ollama outside the managed onboarding path.
Expand All @@ -2454,6 +2457,26 @@ pkill -f 'ollama serve'
OLLAMA_CONTEXT_LENGTH=16384 ollama serve
```

</AgentOnly>

<AgentOnly variant="hermes">

Hermes requires at least `64000` tokens.
During onboarding, NemoClaw verifies the loaded model's actual `context_length` through Ollama's `/api/ps` endpoint.
Resumed onboarding and sandbox rebuilds warm the exact recorded Ollama model and repeat this check before reusing its route.
Resume stops when that recorded model is missing, Ollama is unreachable, model warm-up fails, or the runtime context cannot be verified.
If you set `NEMOCLAW_CONTEXT_WINDOW` above `64000`, the loaded model must provide at least that larger value.
If the runtime value is too small, missing, or malformed, onboarding stops before sandbox creation and asks you to restart the host daemon with the required context length.
`NEMOCLAW_CONTEXT_WINDOW` controls Hermes prompt budgeting; it does not change the Ollama daemon or bypass this runtime check.
Force a larger context length:

```bash
pkill -f 'ollama serve'
OLLAMA_CONTEXT_LENGTH=64000 ollama serve
```

</AgentOnly>

Verify that Ollama inference works:

```bash
Expand All @@ -2470,11 +2493,24 @@ sudo systemctl status ollama

If it is active, stop it first, then start with the custom context length:

<AgentOnly variant="openclaw">

```bash
sudo systemctl stop ollama
OLLAMA_CONTEXT_LENGTH=16384 ollama serve
```

</AgentOnly>

<AgentOnly variant="hermes">

```bash
sudo systemctl stop ollama
OLLAMA_CONTEXT_LENGTH=64000 ollama serve
```

</AgentOnly>

For additional troubleshooting, refer to the [Windows Setup](../get-started/prerequisites/windows-preparation) page.
<AgentOnly variant="openclaw">
For first-time OpenClaw setup, refer to the [Quickstart](../get-started/quickstart).
Expand Down
23 changes: 19 additions & 4 deletions src/lib/inference/local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,16 @@ import {
OLLAMA_MODEL_REGISTRY,
SMALLEST_OLLAMA_MODEL_TAG,
} from "./ollama-model-registry";
import type { OllamaRuntimeModelStatus } from "./ollama-runtime-context";
import type {
ApplyOllamaRuntimeContextWindowOptions,
ApplyOllamaRuntimeContextWindowResult,
OllamaRuntimeModelStatus,
} from "./ollama-runtime-context";
import {
applyOllamaRuntimeContextWindow as applyOllamaRuntimeContextWindowWithHost,
getOllamaContextWindowFloorForAgent,
MAX_AUTODETECTED_OLLAMA_CONTEXT_WINDOW,
MIN_HERMES_OLLAMA_CONTEXT_WINDOW,
parsePositiveInteger,
probeOllamaRuntimeModelStatus as probeOllamaRuntimeModelStatusWithHost,
resetOllamaRuntimeContextWindowAutoState,
Expand Down Expand Up @@ -876,7 +882,12 @@ export function parseOllamaTags(output: string | null | undefined): string[] {
}
}

export { MAX_AUTODETECTED_OLLAMA_CONTEXT_WINDOW, parsePositiveInteger };
export {
getOllamaContextWindowFloorForAgent,
MAX_AUTODETECTED_OLLAMA_CONTEXT_WINDOW,
MIN_HERMES_OLLAMA_CONTEXT_WINDOW,
parsePositiveInteger,
};

export function probeOllamaRuntimeModelStatus(
model: string,
Expand All @@ -900,8 +911,12 @@ export function resolveOllamaRuntimeContextWindow(

export { resetOllamaRuntimeContextWindowAutoState };

export function applyOllamaRuntimeContextWindow(selectedModel: string): void {
applyOllamaRuntimeContextWindowWithHost(selectedModel, getResolvedOllamaHost);
/** Apply Ollama runtime context-window adoption using the resolved local host. */
export function applyOllamaRuntimeContextWindow(
selectedModel: string,
options: Pick<ApplyOllamaRuntimeContextWindowOptions, "contextWindowFloor"> = {},
): ApplyOllamaRuntimeContextWindowResult {
return applyOllamaRuntimeContextWindowWithHost(selectedModel, getResolvedOllamaHost, options);
}

export function applyVllmRuntimeContextWindow(
Expand Down
Loading
Loading