Context and compaction
Manage context, compaction and retained turns.
Manual for v0.9.5. Stable release: v0.9.5.
Documentation · Sessions · Configuration
/compactFor a handoff instead of more investigation:
/answer Summarize the goal, completed changes, unresolved questions, and tests run.Keep the goal and constraints in the conversation or a prompt
template, or set a durable objective with
/goal <objective> and inspect it with /goal status. See sessions.
Request budgeting#
Before every model turn, octet estimates the whole next request: instructions,
history and the exact enabled tool schemas. With the default
threshold_fraction = 1.0, the limit is the context window minus a fixed 16K
reserve for the turn (or the model's larger advertised reasoning floor). There's
no extra percentage buffer. max_active_tokens sets a smaller working set if
you want one. The model's advertised maximum output is still the request
ceiling, and it only shrinks when the input leaves less room in the window. When
it does shrink, octet keeps a small headroom (1% of the window, clamped to 256
to 4096 tokens), because the provider counts tokens its own way.
If a provider rejects a request for size, octet recovers where it can. Local compaction runs at the next reducible boundary and the request is retried, bounded like other provider retries. Named policy, authorization, quota and rate-limit rejections still fail without compacting, and a session with no reducible history reports the limit instead of retrying.
Why the headroom, and what counts as a size rejection
The input count is an estimate. The provider counts with its own tokenizer and chat template, so without a reserve a request sits exactly on the boundary, where a one-token difference is a hard rejection. A real vLLM server answered a 131072-token window with "you requested 30896 output tokens and your prompt contains at least 100177 input tokens, for a total of at least 131073 tokens".
Size recovery includes strict servers that answer HTTP 400, 413 or 422 with a
provider-shaped body carrying a numeric code, which used to take the
permanent-failure branch. Recovery stays bounded: if the provider's own count
exceeds the estimate by more than the reserve, the request fails with the
provider's message.
Codex budgeting
The authenticated Codex working-window policy caps most models, including Astra,
at 272K request tokens, and keeps larger provider-advertised maximums as
discovery metadata. GPT-5.6 Luna is the model-specific exception and may use up
to a 372K working window. Smaller discovered provider windows still win. This
limits repeated prompt encoding and moves long sessions to compaction before
oversized requests dominate latency and cost. A zero or unset
compaction.max_active_tokens removes only the extra working-set ceiling, not
the model-specific Codex route cap. A smaller explicit ceiling stays a separate
setting.
Settings#
In ~/.octet/config.toml:
[compaction]
mode = "local" # disabled, local, or native-responses
threshold_fraction = 1.0
# max_active_tokens = 200000 # Optional smaller working set; zero/unset uses model limit.
keep_recent_tokens = 20000
compact_model = "openrouter/anthropic/claude-haiku-4.5"| Setting | What it does |
|---|---|
mode |
local by default, not native Responses. disabled turns off automatic compaction. |
threshold_fraction |
Default 1.0. Applies alongside any smaller absolute ceiling. |
max_active_tokens |
Optional smaller active-context limit. Zero is the same as unset. |
keep_recent_tokens |
20000 in the example. The recent tail is kept to roughly that many tokens. |
compact_model |
Optional model for local summaries. The example is a choice, not a guaranteed available provider. |
Environment variables: OCTET_COMPACTION_MODE,
OCTET_COMPACTION_THRESHOLD_FRACTION and OCTET_COMPACTION_MAX_ACTIVE_TOKENS.
The old enabled = true and OCTET_AUTO_COMPACT=true still select local. The
deprecated keep_recent_turns key still loads from old config. New config uses
keep_recent_tokens.
The footer percentage uses the full model window, not a smaller configured
working set. For example, max_active_tokens = 120000 is a 9.15% ceiling on a
1,310,720-token model, and the coding-turn reserve makes the input trigger lower
still. With no cap and the default fraction, that model's threshold is about
98.75%. A process-local /auto-compact override or provider context-overflow
recovery can also trigger compaction earlier, so check the active setting and
the compaction reason before blaming the model for a low percentage.
What is retained#
Local compaction writes a bounded summary only at a safe, completed-turn
boundary. It keeps a recent tail and the active skill state, and doesn't rewrite
history. An empty, whitespace-only or over-128KiB handoff (including the
host-derived file footer) fails closed before a checkpoint is written, and octet
never truncates a summary or file evidence. Resume rebuilds context from the
selected parent chain and its compaction boundary. The compact footer shows the
latest provider turn's usage, not cumulative traffic. Session
records cover skill snapshots and the cumulative
details.readFiles and details.modifiedFiles.
native-responses uses the provider's opaque compaction instead, without
showing the payload in the transcript. It needs the active OpenAI Responses
endpoint and model, and never falls back to a Chat or Anthropic summary. Native
route-affine replay is different from a process-local WebSocket response ID. See
transport caveats and the compaction
design.
Responses replay, the tool-schema budget and snap-compact
- When a normal Responses turn has no complete same-route output sidecar (older
sessions, or a completed response without terminal
output), octet replays the canonical conversation instead and sends the current effective reasoning effort as the request baseline. It doesn't replay opaque reasoning updates without their complete history. Ordinary Responses model switches keep the canonical conversation but can't replay opaque output or reasoning updates from the previous route.native-responsesmode still needs complete same-route replay, and refuses such a switch until a valid local replay boundary exists. - Rust embedders may call
Agent::set_tool_schema_budget_bytes. The default is 128KiB of exact serialized provider-visible tool-definition JSON. A non-empty schema set over the limit is refused before provider I/O, rather than having tools omitted or rewritten. A zero budget permits only an empty tool set. - The local octet-snap-compact
extension can replace the
parent-model summary call with deterministic PNG frames, when you enable it
and the active model accepts images. Its checkpoint keeps the source text for
later re-compaction, but a vision model's context gets the frames instead of
that text. Text-only routes use the normal summarizer until a bitmap
checkpoint exists, and continuing from such a checkpoint requires switching
back to a vision route. Rendering is capped at 120 seconds across all source
chunks and frame validation. A timeout, a cancel or an image context limit
fails closed without discarding history. Successive source sections keep
explicit boundaries. It doesn't change
native-responsesmode.