You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: uniform assemble tokenBudget and messages-only currentTokenCount
tokenBudget passed to ContextEngine.assemble now means the same thing on
every harness path: the budget available for assembled messages, computed
by the shared computeContextEngineMessageBudget helper (context window
minus compaction reserve minus rendered system/user prompt pressure).
currentTokenCount is now a messages-only estimate
(estimateTranscriptTokenPressure), so engines size systemPromptAddition
as tokenBudget - currentTokenCount with no double-counting.
- PI main assemble: budget block now uses the shared helper; count is
messages-only
- PI tool loop: new assembleTokenBudget hook param carries the loop
budget; afterTurn keeps the raw window per its contract; the hook
resolves getRuntimeContext once per iteration instead of twice
- Codex harness: derives the budget with reserve 0 (native compaction
owns the reserve concept there)
- plugin SDK re-exports both helpers instead of the removed
estimatePrePromptTokens alias; docs and interface comments updated
Copy file name to clipboardExpand all lines: docs/concepts/context-engine.md
+5-6Lines changed: 5 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -74,7 +74,7 @@ Every time OpenClaw runs a model prompt, the context engine participates at four
74
74
Called when a new message is added to the session. The engine can store or index the message in its own data store.
75
75
</Accordion>
76
76
<Accordiontitle="2. Assemble">
77
-
Called before each model run. The engine returns an ordered set of messages (and an optional `systemPromptAddition`) that fit within the token budget. OpenClaw also passes an optional `currentTokenCount` — a best-effort estimate of tokens already consumed by `messages + system prompt + incoming prompt` — so engines can bound any `systemPromptAddition` against the remaining headroom.
77
+
Called before each model run. The engine returns an ordered set of messages (and an optional `systemPromptAddition`) that fit within the token budget. OpenClaw also passes an optional `currentTokenCount` — a best-effort estimate of the tokens the pre-assembly `messages` already consume — so engines can bound any `systemPromptAddition` against the remaining headroom.
78
78
</Accordion>
79
79
<Accordiontitle="3. Compact">
80
80
Called when the context window is full, or when the user runs `/compact`. The engine summarizes older history to free space.
@@ -108,19 +108,18 @@ The `assemble` method can return a `systemPromptAddition` string. OpenClaw prepe
108
108
`assemble` receives two values that together let engines bound their injection:
109
109
110
110
<ParamFieldpath="tokenBudget"type="number">
111
-
The model's full input context window for this run (e.g. `200_000`, `1_048_576`). Not the headroom remaining — engines must subtract what is already consumed.
111
+
The budget available for the assembled messages. The runtime computes this as the model's context window minus its compaction reserve (when the harness holds one) and the rendered system/user prompt pressure — engines do not subtract those themselves.
112
112
</ParamField>
113
113
<ParamFieldpath="currentTokenCount"type="number">
114
-
Best-effort pre-assembly estimate of tokens already consumed by `messages + system prompt + incoming prompt`. Computed by the runtime via the same estimator the preemptive overflow precheck uses, so engines see the same number the runtime would. Optional — may be`undefined` on older OpenClaw runtimes; treat absence as "no headroom info, inject conservatively or skip the guard."
114
+
Best-effort estimate of the tokens the pre-assembly `messages` already consume, computed with the same transcript estimator the runtime uses (`estimateTranscriptTokenPressure` on `openclaw/plugin-sdk/agent-harness-runtime`), so engines see the same number the runtime would. Optional — `undefined` on older OpenClaw runtimes; treat absence as "no headroom info, inject conservatively or skip the guard."
115
115
</ParamField>
116
116
117
-
A typical guard looks like:
117
+
Both values live on the same scale, so the remaining headroom for a `systemPromptAddition` is their difference:
118
118
119
119
```ts
120
-
const responseReserve =8_192; // assistant response budget; not in currentTokenCount
Copy file name to clipboardExpand all lines: src/agents/embedded-agent-runner/tool-result-context-guard.ts
+11-9Lines changed: 11 additions & 9 deletions
Original file line number
Diff line number
Diff line change
@@ -330,6 +330,8 @@ export function installContextEngineLoopHook(params: {
330
330
sessionKey?: string;
331
331
sessionFile: string;
332
332
tokenBudget?: number;
333
+
/** Budget for assemble calls: context window minus compaction reserve and rendered system-prompt pressure. Falls back to `tokenBudget` when absent. */
/** Budget available for the assembled messages. The runtime has already subtracted its compaction reserve (when it holds one) and the rendered system/user prompt pressure from the context window. */
384
385
tokenBudget?: number;
385
-
/** Best-effort pre-assembly prompt token estimate so engines can bound any `systemPromptAddition` against `tokenBudget`. */
386
+
/** Best-effort token estimate of `messages` alone, from the runtime's transcript estimator. Remaining headroom for any `systemPromptAddition` is `tokenBudget - currentTokenCount`. Omitted on runtimes that predate the field. */
386
387
currentTokenCount?: number;
387
388
/** Tool names available for this run so engines can align prompt guidance with runtime tool access. */
0 commit comments