Repository navigation
fix(compaction): keep the post-compaction autocontinue on the session working model - #8397
mradwankhalil wants to merge 15 commits into
Conversation
|
Root cause (the synthetic continue inheriting the summarize model) is now tracked upstream at anomalyco/opencode#49386 — note the repo moved from sst/opencode to anomalyco/opencode. This PR is the plugin-side mitigation until core can resolve the continue model from the session instead. |
b53ea27 to
0d10267
Compare
|
Follow-up commit pushed:
Observed live: continuations on The follow-up adds Verified: package |
OpenCode's synthetic post-compaction continue inherits the summarize request's model (session/compaction.ts stamps model: userMessage.model). When an agent's compaction.model differs from the model the session is actually running, the compaction model ended up continuing the task. The experimental.compaction.autocontinue handler now compares the compaction trigger message's model with the nearest non-compaction message's model. On a mismatch it disables OpenCode's synthetic continue and re-issues the continue prompt via session.promptAsync with the session's working model, agent, and the compaction_continue metadata marker. Lookup failures and equal models keep the previous behavior. Adds plugin/compaction-autocontinue-reroute.ts and three regression tests.
…l assistant turn Follow-up to the autocontinue reroute: the resolver previously used the newest message carrying agent+model fields, which includes compaction summaries and the internal compaction_continue prompts themselves. Once a continue was issued on a non-session model it kept re-resolving to that model, silently switching live sessions to the compaction model (observed: zai-coding-plan/glm-5.3-flash continuations after the session had returned to its own model; same pattern across Sep 14/15/18 sessions). Now the working model/agent are resolved only from non-compaction, non-internal messages, preferring the newest assistant turn. Added isCompactionArtifact / isInternalContinuationMessage / pickActiveSessionMessage helpers. Verified: package typecheck (tsgo) clean, full build clean, live-session message forensics.
a98b94d to
fc569ee
Compare
|
Thanks for this, @mradwankhalil, the working-model fix is a good catch. One real CI failure to sort out: the prompt-route audit ( The other two reds need nothing from you: the Windows "memory pressure dream wiring" failure is a known flake (#10154), and the changelog check is failing on several PRs since the v5.1.35 cut moved |
|
Thanks — both points noted, and that's the shape we'll push on the branch:
Also, thanks for the flake pointer on the Windows "memory pressure dream wiring" failure (#10154) — good to know it and the changelog gate are not this PR's to fix beyond the move. |
…ompt gate The prompt-route audit flags plugin/compaction-autocontinue-reroute.ts for calling client.session.promptAsync directly; only the shared prompt gate may call the raw OpenCode prompt APIs. The reroute now goes through dispatchInternalPrompt with an explicit queueBehavior, and the result is checked with isInternalPromptDispatchAccepted (sent or queued counts as reissued); anything else is logged and reported as not reissued.
|
Both points are pushed on the branch, new head
Checks on the branch: |
…nue-working-model
…ontinue-working-model # Conflicts: # CHANGELOG.md
…ontinue-working-model # Conflicts: # CHANGELOG.md
a0cbc6b to
23dad8c
Compare
…changelog refresh)
|
Thanks for the updates, @mradwankhalil! A heads-up on the red CI here: most of it isn't from your change. A dev-wide lint/typecheck break landed in dev and is fixed there now. Could you merge the current dev into this branch? That should clear the inherited typecheck, ubuntu test and senpi-compatibility failures. A couple of Windows-only failures may still show up after that; those are known and being fixed on our side, so you can ignore them. Anything else still red is worth a look. |
|
Merged I have also noted your later clarification on #9787/#10828 that the remaining Senpi Ubuntu freshness failure is an upstream generated-artifact issue. I am leaving those generated bundles untouched rather than adding unrelated regeneration to this PR. This confirms the requested merge, not an all-green CI result; the known Windows failures remain separate as you advised. Thank you for the guidance. |
|
Changelog entries moved to per-PR fragments (#10477). Pull requests no longer edit git fetch origin dev
bun script/changelog-fragments-cli.ts from-diff --base origin/dev --pr <this PR's number>
git add -A && git commit -m "chore(changelog): move the entry into changes/unreleased"That moves your Unreleased paragraphs and log entries into |
|
Thanks for clarifying the fragment format. Noted: this PR's entry belongs in |
Summary
compaction.modeldiffers from it.session/compaction.ts:model: userMessage.model), so with a per-agentcompaction.modelconfigured the compaction model silently ran the continuation turns. The existing guard only matchesagent === "compaction"and can never catch a model-only mismatch.session.promptAsyncwith the working model, the working agent, and thecompaction_continuemetadata marker.plugin/compaction-autocontinue-reroute.ts+ three regression tests.Problem
With
agents.<agent>.compaction.modelconfigured (preemptive compaction enabled), a live session was observed continuing on the compaction model after auto-compaction. Message rows from that session'sopencode.db:zai-coding-plan/glm-5.3-flashcompactionpart,auto: true)zai-coding-plan/glm-5.3-flashagent: "compaction") — expectedzai-coding-plan/glm-5.3-flashzai-coding-plan/glm-5.3-flashopencode-go/deepseek-v4.1-flashRoot cause chain
client.session.summarize({ providerID, modelID: <compaction.model>, auto: true })(hooks/preemptive-compaction-trigger.ts).SessionCompaction.create).model: userMessage.model— i.e. the summarize model — and gates it only on theexperimental.compaction.autocontinueplugin hook (packages/opencode/src/session/compaction.ts, around lines 497–548 in v1.18.31).createCompactionAutocontinueHandlerdisables the continue only whenisCompactionAgent(input.agent). When the trigger's agent is the working agent (normal case) and only the model differs, the guard cannot match, so the continue runs on the compaction model.Fix
plugin/compaction-autocontinue-reroute.tscompactionpart) and the working model (nearest non-compaction message, via the existingfindNearestMessageWithFieldsFromMessages, which already skips compaction messages).createCompactionAutocontinueHandlernow, after the existing checkpoint restores:output.enabled = falseto drop OpenCode's poisoned synthetic continue, thensession.promptAsync({ body: { agent, model: <working>, parts: [{ type: "text", text: <same continue text>, metadata: { compaction_continue: true } }] } }).Behavior matrix:
Wiring:
testing/create-plugin-module.tspassesclientanddirectoryinto the handler options. Both are optional — without a client the handler keeps the previous behavior, so existing unit tests and non-client call sites are unaffected.Notes / limitations
session.promptAsyncbody has novariantfield, so the re-issued continue runs at the model's default effort; model selection itself is exact.compaction.model.compaction.model, not just one.Verification
bun test src/index.compacting.test.ts src/index.compaction-model-agnostic.static.test.ts→ 16 pass / 0 fail, 52 expect() calls (3 new cases: reroute on mismatch; unchanged on equal models; unchanged on lookup failure)bunx tsgo --noEmit -p packages/omo-opencode/tsconfig.json→ passedbun run build→ passedOnly the intended files are included (4 files, +308/−1); unrelated local worktree edits were not staged.
Summary by cubic
Fixes post-compaction autocontinue running on the configured
compaction.modelinstead of the session's working model.OpenCode's synthetic continue inherits the summarize request's model, so with a per-agent
compaction.modelconfigured, the compaction model silently ran continuation turns after auto-compaction. The handler now compares the compaction trigger's model with the working model, resolved from the newest real assistant turn while skipping compaction summaries and internal continue prompts so the reroute doesn't cascade onto itself. On mismatch it disables the synthetic continue and reissues the same prompt on the working model and agent through the shared prompt gate (dispatchInternalPrompt, queued when busy); a sent or queued dispatch counts as reissued, while equal models, lookup failures, and rejected dispatches keep the previous flow.plugin/compaction-autocontinue-reroute.tsmodule plusclient/directorywiring intesting/create-plugin-module.ts.Written for commit 7de402d. Summary will update on new commits.
Rebased onto
v5.0.0-beta.72(2026-09-18)The fix has been ported forward from
beta.62to the current release so it can merge cleanly:v5.0.0-beta.72; the only conflict waschanges.md(changelog) and the base version was kept there.bun install+bun run build) — replaying it collides with extension files this release removed.packages/omo-opencode/src/index.compacting.test.ts: 14 pass / 0 fail; typecheck clean onomo-opencode,omo-senpi,omo-codex.v5.0.0-beta.72(compaction-autocontinue-rerouteabsent from the tree), so it is still required.Reproduction this addresses: after auto-compaction, the synthetic continuation ran on the compaction model instead of the session working model (
session/compaction.tsstamps the trigger message with the per-agentcompaction.model, and the continuation inheritsuserMessage.model). The addedcompaction-autocontinue-reroutemodule disables core's synthetic continue and re-issues the prompt viasession.promptAsyncwith the working model.