Uh oh!
There was an error while loading. Please reload this page.
fix(desktop): recover evicted Runtime Host session streams - #2630
Merged
Conversation
M4n5terforce-pushed
the
fix/desktop-session-subscription-recovery
branch
from
August 10, 2026 08:49
cb522dd to
ef90ff3CompareM4n5terforce-pushed
the
fix/desktop-session-subscription-recovery
branch
from
August 10, 2026 09:36
ef90ff3 to
09ca667CompareM4n5ter
marked this pull request as ready for review
August 10, 2026 09:38
Uh oh!
There was an error while loading. Please reload this page.
66 tasks
me2seeks added a commit
to me2seeks/maka-agent
that referenced
this pull request
Aug 18, 2026
…ehind A TUI turn event consumer that fell more than MAX_PENDING_EVENTS_PER_TURN behind had its stream failed permanently while the Host turn kept running; the channel kept draining frames into the dead queue and nothing recovered until the terminal transcript refresh. Shed offset-bearing deltas (healed by the next canonical resync or text completion) and evict the oldest sheddable delta to make room for other events so terminal records always land, and notify the channel once per lag episode. The channel retires the healthy-but-lagged subscription through the existing recovery path — the same resubscribe a Host slow-consumer eviction triggers, and the TUI equivalent of the Desktop subscription owner (apache#2630). Fixesapache#3180 Generated-by: Maka
me2seeks added a commit
to me2seeks/maka-agent
that referenced
this pull request
Aug 18, 2026
…ehind A TUI turn event consumer that fell more than MAX_PENDING_EVENTS_PER_TURN behind had its stream failed permanently while the Host turn kept running; the channel kept draining frames into the dead queue and nothing recovered until the terminal transcript refresh. Shed offset-bearing deltas (healed by the next canonical resync or text completion) and evict the oldest sheddable delta to make room for other events so terminal records always land, and notify the channel once per lag episode. The channel retires the healthy-but-lagged subscription through the existing recovery path — the same resubscribe a Host slow-consumer eviction triggers, and the TUI equivalent of the Desktop subscription owner (apache#2630). Fixesapache#3180 Generated-by: Maka
Astro-Han pushed a commit
that referenced
this pull request
Aug 20, 2026
…n loops (#3181) * fix(cli): resubscribe instead of failing when a turn consumer falls behind A TUI turn event consumer that fell more than MAX_PENDING_EVENTS_PER_TURN behind had its stream failed permanently while the Host turn kept running; the channel kept draining frames into the dead queue and nothing recovered until the terminal transcript refresh. Shed offset-bearing deltas (healed by the next canonical resync or text completion) and evict the oldest sheddable delta to make room for other events so terminal records always land, and notify the channel once per lag episode. The channel retires the healthy-but-lagged subscription through the existing recovery path — the same resubscribe a Host slow-consumer eviction triggers, and the TUI equivalent of the Desktop subscription owner (#2630). Fixes#3180 Generated-by: Maka * test(cli): cover turn consumer lag recovery Flood an unconsumed turn stream past its bound: the channel resubscribes, the stream never rejects, live deltas continue after recovery, and terminal events still land while deltas are shed. Generated-by: Maka * fix(cli): guarantee terminal admission and compact lagged delta backlog on resync Address qodo-code-review findings on #3181: - A full queue with no sheddable delta silently dropped an incoming complete/error/abort, letting the consumer reach end-of-stream without a terminal outcome. Terminal outcomes now evict the oldest event in that corner, so they always land. - After lag recovery, a still-full queue kept shedding the fresh post-resync stream behind stale deltas the canonical replacement had already superseded. Lagging queues now drop their unseen sheddable backlog when the canonical replacement lands. Generated-by: Maka * test(cli): pin terminal admission and resync backlog compaction Both new tests fail against the pre-review channel: the resync marker delta is shed behind the uncompacted backlog, and the terminal outcome is dropped from an all-tool-event backlog. Deterministic ordering: wait for the canonical resync before producing the terminal frame, so the backlog is still full when it is emitted. Generated-by: Maka * fix(cli): re-arm lag detection with hysteresis after the consumer drains CodeRabbit review on #3181: after a lag recovery over a non-delta backlog, the latch stayed on until the queue fully emptied, so fresh output shed while the consumer was still behind could never schedule another canonical recovery. Re-arm once the backlog drains to half the bound: a consumer making progress gets later episodes recovered, while a wedged consumer never drains and cannot loop resubscribes. Generated-by: Maka * test(cli): cover repeated lag recovery after consumer progress Sends fresh output after a non-delta-backlog recovery, then lags the consumer a second time and expects a third subscription. Fails without the hysteresis re-arm: the latch never clears while events remain queued. Generated-by: Maka * test(cli): keep the second subscription's frame stream contiguous CodeRabbit review on #3181: the repeated-recovery test sent sequences 1, then 100..199, then a flood restarting at 1 with the first subscription's id — a stream the real ClientSessionSubscription would reject as a sequence gap, masked by the fake. Thread the subscription id and a starting sequence through floodToolStream so every fake stream stays valid. Generated-by: Maka * fix(cli): shed lagged tool output deltas so tool results land Astro-Han review on #3181 (P2): during a tool-output flood the queue filled with non-sheddable tool_output_delta events, so an incoming tool_result had nothing to evict and was silently dropped, leaving the live tool card stuck at "running" until the durable transcript healed. tool_output_delta is sheddable by design: the protocol documents its chunks as transient UI updates with a monotonic per-tool seq that renderers de-dupe and order by, and the terminal tool_result plus the durable transcript remain the authoritative output. Shedding them under lag matches the text_delta story; a shed range leaves a display gap, never corruption. The remaining boundary is documented at the drop branch: a non-delta, non-terminal event behind a backlog with nothing sheddable (e.g. an all-control backlog) is still dropped, and the durable transcript heals the terminal state. Generated-by: Maka * test(cli): pin the lag hysteresis watermark boundary Astro-Han review on #3181 (P3s): the re-arm boundary was only indirectly covered. The new test drains a full non-delta backlog to one event above the watermark (513 pending) and asserts a fresh overflow does not resubscribe, then drains to the watermark (512 pending) and asserts the next overflow is treated as a new lag episode. Also pin two reviewed behaviors in comments: the retiring-subscription guard swallowing a genuine error racing the deliberate close (the replacement pump re-surfaces real failures via #fail), and the per-queue lag escalating to a session-wide recovery (benign superset: the resync heals every turn, and the latch plus hysteresis prevent resubscribe loops). Generated-by: Maka * fix(runtime-host): coalesce queued assistant deltas instead of evicting Dogfooding this branch surfaced the loop the resubscribe fix could spin: an active turn's thinking/text delta flood outpaces the one-awaited-send flush, the 32-frame subscriber budget overflowed, and the Host evicted the subscription as slow_consumer within seconds of every resubscribe — while the recovering channel had a permanently fatal path (clean iterator end mid-catch-up) and a silently freezing one. The coordinator now folds a queued assistant delta into its queued tail when it continues the same stream contiguously: projectors apply deltas by absolute startOffset, so a merged frame carries byte-identical content, and the absorbed frame never spends a sequence. Eviction stays the backstop for genuinely undrainable backlogs (covered by alternating-stream tests). The channel treats a live stream that ends without subscription.closed as connection_closed, routing it through resync recovery instead of failing the session. Co-Authored-By: Maka <noreply@maka.dev> Generated-by: Maka * fix(runtime-host): bound coalesced session deltas Generated-by: Maka * fix(cli): retain tool results under lag Generated-by: Maka * fix(cli): make session recovery a bounded sequence cut Generated-by: Maka * fix(cli): preserve bounded recovery outcomes * test(cli): exercise post-resync backlog admission * style(cli): format lag admission coverage * fix(cli): close remaining lag recovery boundaries Start recovery stability only after a post-hydration live frame, recover buffered slow-consumer closure during initial hydration, and guarantee assistant completion admission over saturated control backlogs. Generated-by: Maka --------- Co-authored-by: Maka <noreply@maka.dev>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
English
Summary
Recover Desktop session streams when a bounded Runtime Host subscription is evicted while a turn is active.
Dense Agent Graph activity can overflow a client subscription queue within one scheduling window. Runtime Host correctly closes that subscription as a slow consumer, but Desktop previously stopped observing the session while the renderer still expected live updates. The stream then appeared frozen until the user changed sessions and returned.
Desktop now gives each observed Session one replaceable subscription owner. The owner validates and commits a replacement subscription atomically, restores the canonical transcript prefix, and continues offset-bearing deltas without a renderer resubscribe. The observer remains responsible only for Desktop projection and renderer targets.
After in-place recovery or Runtime Host candidate replacement, Desktop reconciles terminal and successor turns, Goal state, exact pending interactions, and Task, Deep Research, Plan, Graph, Shell Run, and PTY projections. A mounted terminal reacquires its controller snapshot and continues receiving live PTY data.
Copied Desktop diagnostic reports now include Session, Turn, event, stable reason/code, recoverability, and redacted internal details. Main-process logs also record subscription recovery attempts and outcomes.
Verification
npm test --workspace @maka/desktop— 1,157 tests passednpm run typecheck --workspace @maka/desktopnpm run build --workspace @maka/desktopgit diff --checkChecklist
Does this PR entail a change in behavior?
中文
概要
当有界 Runtime Host 会话订阅在活跃 turn 期间被淘汰时,自动恢复 Desktop 会话流。
密集的 Agent Graph 活动可能在一个调度窗口内产生超过客户端订阅队列容量的帧。Runtime Host 会按设计以 slow consumer 原因关闭该订阅,但此前 Desktop 会停止观察该会话,而 renderer 仍在等待实时更新。结果是界面流式输出看似冻结,只有切换到其他会话再返回后才恢复。
Desktop 现在为每个被观察的 Session 设置一个可替换的订阅 owner。该 owner 原子地验证并提交替代订阅,恢复权威 transcript 前缀,并在无需 renderer 重新订阅的情况下继续接收带 offset 的 delta。observer 只负责 Desktop 投影与 renderer target。
无论是原订阅就地恢复,还是 Runtime Host candidate 替换,Desktop 都会协调已结束 turn、successor turn、Goal 状态、精确的待处理交互,以及 Task、Deep Research、Plan、Graph、Shell Run 和 PTY 投影。已挂载的终端会重新获取 controller snapshot,并继续接收实时 PTY 数据。
复制出的 Desktop 诊断报告现在还会包含 Session、Turn、事件标识、稳定的 reason/code、是否可恢复以及经过脱敏的内部详情。主进程日志也会记录订阅恢复的开始和结果。
验证
npm test --workspace @maka/desktop— 1,157 项测试通过npm run typecheck --workspace @maka/desktopnpm run build --workspace @maka/desktopgit diff --check检查清单
此 PR 是否包含行为变化?