Skip to content

fix: persist modelContextLimit, skip min-threshold when unknown, percentage defaults, keep blocks active across restarts - #607

Open
Neko-Yukari wants to merge 4 commits into
Opencode-DCP:masterfrom
Neko-Yukari:fix-restart-thresholds
Open

fix: persist modelContextLimit, skip min-threshold when unknown, percentage defaults, keep blocks active across restarts#607
Neko-Yukari wants to merge 4 commits into
Opencode-DCP:masterfrom
Neko-Yukari:fix-restart-thresholds

Conversation

@Neko-Yukari

Copy link
Copy Markdown

Summary

Four related fixes for premature compression reminders on modern large-context models (256K-1M tokens), observed as "restart then immediately asked to compress" on a ~300K / 1M context.

1. Persist modelContextLimit (state/persistence.ts, state/state.ts)

opencode runs the chat.message transform before the system.prompt hook, so on the first message after a restart state.modelContextLimit is not yet cached and is not persisted. resolveContextTokenLimit then fails for percentage limits. Persisting the value restores it before the first transform.

2. Skip min-threshold check when limit is unknown (messages/inject/utils.ts)

Previously overMinLimit = minContextLimit === undefined ? true — with the limit unresolvable, a normal ~300K context on a 1M model triggered compression nudges on every turn. Now it skips the check (false); the real model limit is still enforced by the API layer. (max side already behaved this way.)

3. Default limits as percentages (config.ts)

Absolute 100000/50000 defaults fire far too early on 256K-1M models. Defaults are now 85%/60% of the model context, falling back gracefully when the limit is unknown.

4. Keep compress blocks active across restarts (messages/sync.ts)

compressMessageId (the assistant message executing compress) is marked ignored/synthetic and never persisted, so after a restart syncCompressionBlocks deactivated the block and the full original context was re-injected. When the origin message is missing but the anchor message still exists, the block is kept active so the summary keeps being injected.

Tests

109/109 pass. Added:

  • min-threshold skip when modelContextLimit unknown
  • 300K-context / 1M-model no-false-alarm regression
  • modelContextLimit persistence round-trip
  • sync-block keep-active + summary-injection regressions

…is missing

compressMessageId (the assistant message executing compress) is marked
ignored/synthetic and never persisted, so after an opencode restart the
block was deactivated and the full original context was re-injected,
causing premature compression reminders. Fall back to anchorMessageId
(which persists): if the anchor exists, keep the block active so the
compressed summary keeps being injected into the LLM context.
Absolute 100K/50K defaults trigger compression reminders far too early
on modern large-context models (256K-1M). Use 85%/60% of the model
context by default; falls back gracefully when the limit is unknown.
opencode runs the chat.message transform before the system.prompt hook,
so on the first message after a restart state.modelContextLimit is not
yet cached. resolveContextTokenLimit then fails for percentage limits
and overMinLimit fell back to unconditional true, injecting compression
nudges on every turn for a normal ~300K context on 1M models.

Fix: overMinLimit now returns false when the limit cannot be resolved
(skip nudge instead of unconditionally triggering). The model limit is a
session constant: from the second turn onward the system.prompt hook has
cached it and threshold checks work normally. The real model limit is
still enforced by the API layer.

Tests: 108/108 pass (added min-threshold skip and 300K no-false-alarm
regressions).
@Neko-Yukari
Neko-Yukari force-pushed the fix-restart-thresholds branch from 4e0a9cd to 275a36c Compare August 18, 2026 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant