Repository navigation
v0.49.36
·
258 commits
to master
since this release
v0.49.36
This patch fixes a set of OpenCode 2 compaction problems (empty and missed folds, a manual /compact that reclaimed nothing, per-pass work that grew with the session), unblocks long OpenCode sessions that refused every turn on compaction markers, lets emergency recovery work after provider overflows it didn't recognize, keeps the prompt cache intact after a restart and around replies with signed thinking, and fixes several Pi, Oh My Pi and dreamer issues.
Upgrading
- Restart OpenCode or Pi after updating. No database migration is needed.
Fixed
OpenCode 2
- Every request failed on OpenCode 2.2 after a fold kept a failed tool call: when Magic Context rebuilt the messages kept after a fold, it wrote a failed tool call's result in a shape OpenCode 2.2's request check rejects, so each later request failed with "Schema validation failed". Failed calls are now restored in the same shape OpenCode itself sends.
- A manual
/compactreclaimed nothing (#866, thanks @cxkun): the served prompt stayed the same size after/compact. It now folds the summarized history and keeps the conversation that isn't summarized yet, plus the current instructions. On a test session shaped like the report, the request went from 166k to 42k tokens. - Empty folds for sessions without history (#838, thanks @iceteaSA): OpenCode 2 asked Magic Context for a checkpoint in sessions that had no summary yet, such as subagents, and Magic Context answered with an empty summary that OpenCode 2.2.0 refuses. Such sessions now get a short non-empty note that their history is kept as raw messages.
- The idle fold never ran after a restart (#848, thanks @null-axiom): the idle window lived only in memory, so a restart or plugin reload lost it. An idle window that expired while OpenCode was down now folds after the restart, once.
- Per-pass work grew with the session (#845, #846, #863, thanks @iceteaSA): each pass looked up what it had last sent once for every message, read plugin storage for every synthetic message, and kept restored rows without a limit. Each lookup now happens once per pass, synthetic-message checks are remembered, and the restored-row cache has a size limit.
- A session could refuse every turn after one refusal (#828, thanks @dhaern): a refused turn sends nothing, so the last usage reading never refreshed, and the next turn was refused on the same stale number. Once a summary or fold lands after the refusal, Magic Context now drops that reading and measures the next request itself.
- Summaries stalled behind a large early message (#867, thanks @gaojunran): the per-run limit counted tool outputs and images, which the summarizer doesn't read, so one large attachment could block every run. The limit now counts only text and tool inputs.
OpenCode
- Long sessions refused every turn on compaction markers (#856, thanks @mcheiyue): the check counted OpenCode's own compaction markers and older Magic Context markers as unknown, and refused the turn with error MC-S06. It now ignores OpenCode's markers and recovers Magic Context's own markers when they can be verified. It still refuses when OpenCode would stop loading history past the point the summaries cover.
- The prompt cache was rewritten after a restart: after a host restart, replies sent without their
§N§tag numbers could gain them on a pass that otherwise reused the cache, which rewrote the cached prompt from that point. Tags are now added only on a pass that already rewrites that part of the prompt. - Replies with signed thinking reached the provider with an extra space: Anthropic signs a reply's thinking blocks, and the reply must come back unchanged. OpenCode turns Magic Context's empty placeholder beside signed thinking into a single space, so the reply no longer matched what the model wrote. New replies no longer carry the placeholder. Replies already sent keep their shape until the cached prompt is rebuilt anyway.
- Background jobs started a new worker for every job (#776, thanks @moynzzz): on Bun before 1.4, each worker leaked its event loop and about 0.8 MB. Jobs now reuse one worker per kind. This also fixes the first index write stalling on OpenCode 1.18's embedded Bun.
- Sidebar polls rewrote unchanged usage (#825, thanks @iceteaSA): an idle poll now writes nothing when nothing changed, and the sidebar's usage totals survive a plugin reload.
Pi and Oh My Pi
- Pi turned null tool arguments into text (#843, thanks @G0-0000 for the fix): Pi 1.5 converts tool arguments before checking them, so a null note or memory body was saved as the word "null", and null ids became
[0].ctx_noteandctx_memorynow reject those arguments before Pi converts them. The tool definitions are unchanged. - A rewind kept drops made on the abandoned branch (#837, thanks @TheOrdinaryWow): after rewinding or forking, content the agent had dropped with
ctx_reduceafter the rewind point stayed hidden. Queued drops from the abandoned branch are now cancelled. Drops that already landed are restored on the next pass that rebuilds the cached prompt anyway. - Wrong message positions across system checkpoints (#835, thanks @chpock): for numbering, Pi counts tool results together with the next user message. A system entry in between dropped them from the count, so later positions were off. They now carry past system entries.
- An Electron host was taken for Pi (#851, thanks @trim21): an editor embedding Pi with an Electron executable could spawn the editor itself as Pi. Magic Context now checks the executable before treating it as Pi.
- Emergency recovery skipped large image results (#865, thanks @hakil): after a provider overflow with no usage reported, Pi now estimates the request it will actually send and runs recovery once more, which drops the large image results.
- Tiny summary runs on Pi (#853, thanks @galact-byte): the per-run limit counted tool outputs, which the summarizer doesn't read, so runs stopped after a few messages. It now counts only text and tool inputs, as on OpenCode.
- Oh My Pi Codex refused turns (#861, #862, thanks @RiAnBee): a reply with only hidden reasoning, and the date and folder control message, made the dispatch check refuse the turn. Both are now accepted.
Overflow detection and search
- LiteLLM and DeepSeek overflow errors weren't recognized (#859, thanks @XA21X): emergency recovery never started for them. Their messages and input counts are now parsed.
- Search skipped reranking for non-Latin text (#849, thanks @Neko-Yukari): the check that decides whether a query is prose only recognized Latin script. It now recognizes prose in any script.
Summaries and dreamer
- Free models looped until timeout (#841, thanks @Mirrowel): when a summarizer model returned an error, the run retried it instead of moving to the next model. A recorded provider error now moves to the next model in the chain.
- The dreamer's token budget never filled (#829, thanks @null-axiom): each step was charged before its token count was known. Steps are now charged once they finish, with their final count.
- The retrospective counted the wrong sessions (#830, thanks @null-axiom): its gate counted subagent sessions and other hosts' sessions. It now counts only this host's top-level sessions.
- Verify asked about the same memories every run (#847, thanks @null-axiom): verify now records its verdicts, so a memory it skipped isn't asked about again.