Skip to content

fix(runtime): malformed compaction summaries can permanently strand a session #3743

Description

@somewan820
English

What happened

A tool-heavy Desktop Session can become permanently stranded after automatic history compaction returns a provider-completed but structurally invalid summary.

Observed on main@3a9824a7e with a custom openai-responses-compatible connection and gpt-5.6-sol:

  • the selected model had no declared contextWindow, so Runtime used the bounded fallback capacity (32,000 history budget + 16,384 reserve);
  • the active Turn accumulated large GitHub issue and pull-request tool results;
  • active tool-result pruning ran and reported 74 pruned results / 352,159 estimated tokens saved;
  • history compaction then ran eight times in the same Turn;
  • all eight model calls completed, but every compaction decision failed open with malformed_summary_missing_section;
  • the final Turn outcome was context_budget_exhausted;
  • a short follow-up message immediately ran another history_compact call, which completed with finishReason: stop after 113,942 ms (37,498 input tokens, 1,895 output tokens), but the Turn still ended as context_budget_exhausted with detail summarizer_failed.

The summary validator is behaving correctly: an incomplete summary must not replace durable history. The liveness defect is that the same Session has no bounded repair or escape path. Repeating or regenerating can issue the same doomed compaction again, while Desktop presents only the generic "Task run failed" toast.

The Session history remained intact and Runtime Host stayed ready; there was no process exit. GitHub access itself was not the failure.

How to reproduce

  1. Configure a custom Responses-compatible relay model without declaring its context window, so the default bounded fallback applies.
  2. Start a Desktop Session that accumulates enough text-heavy tool results to exceed that capacity. Fetching several full GitHub issue / PR bodies in one Turn reproduces the observed shape.
  3. Make the history summarizer return non-empty text with finishReason: stop that omits one or more required checkpoint sections.
  4. Observe that the summary is correctly rejected as malformed_summary_missing_section and no checkpoint is written.
  5. Continue until the outgoing request remains over capacity.
  6. Observe context_budget_exhausted.
  7. Send a short follow-up message or regenerate.
  8. Observe another completed history_compact request followed by the same terminal failure, with no actionable recovery guidance.

This should also be covered deterministically with an injected summarizer; it does not require a live provider test.

Expected behavior

  • Keep the strict checkpoint-summary validator introduced for fix(runtime): history compaction accepts truncated/unstructured LLM summaries without validation #3029. A malformed summary must never replace folded history.
  • Bound repair attempts for a given compaction input/failure fingerprint. Do not repeatedly spend model calls on an identical malformed-summary outcome.
  • After the bounded attempt is exhausted, preserve a stable diagnostic reason such as malformed_summary_missing_section through the terminal projection.
  • Present actionable recovery: configure the model's real context window, switch model/connection, or start a fresh task/branch.
  • A changed model, connection, context-window declaration, or source-history fingerprint may retry; an unchanged failure should not loop blindly.
  • Add regression coverage for an over-capacity, tool-heavy history whose summarizer completes normally but omits required sections.

The exact repair mechanism (one stricter retry, structured-output summary, alternate summarizer, or another bounded strategy) can be decided in implementation. Weakening or bypassing summary validation is not an acceptable fix.

Environment

  • Maka commit: 3a9824a7e
  • Maka version: 0.2.0 development build
  • Surface: Desktop + Runtime Host
  • OS: macOS 26.6 / Darwin 25.6.0 arm64
  • Electron: 43.4.1
  • Node.js: 24.18.1
  • Provider type: custom openai-responses-compatible
  • Model: gpt-5.6-sol
  • Runtime Host: remained ready; no local process exit captured

Logs, screenshots, or additional context

First failed Turn diagnostics:

contextWindow: null
failureClass: context_budget_exhausted
compaction decisions:
  failedOpen / context_limit / malformed_summary_missing_section: 8
  unchanged / context_budget_exhausted: 1
latest main input tokens: 43,145
active pruned tool results: 74
active estimated tokens saved: 352,159

Immediate follow-up Turn:

callKind: history_compact
status: completed
finishReason: stop
latency: 113,942 ms
input tokens: 37,498
output tokens: 1,895
terminal detail: summarizer_failed
failureClass: context_budget_exhausted

Related:

Out of scope:

  • changing the actual context limit exposed by a custom relay;
  • weakening checkpoint validation;
  • an unrelated Electron MaxListenersExceededWarning observed earlier in the same app process.

AI assistance disclosure: Codex inspected the local durable Runtime records and source, drafted this report from the reporter-provided diagnostic, and posted it at the reporter's request.

简体中文

发生了什么

当自动历史压缩返回一个 provider 已正常完成、但结构不合法的摘要时,一个工具结果很多的 Desktop Session 会被永久卡住。

main@3a9824a7e 上观察到该问题,使用的是自定义 openai-responses-compatible 连接和 gpt-5.6-sol

  • 所选模型没有声明 contextWindow,因此 Runtime 使用了有界回退容量(32,000 history budget + 16,384 reserve);
  • 当前 Turn 累积了大量 GitHub issue 和 pull request 工具结果;
  • active tool-result pruning 已运行,并报告裁剪 74 个结果、预计节省 352,159 tokens;
  • 随后在同一个 Turn 中运行了八次历史压缩;
  • 八次模型调用都正常完成,但每次压缩决策都以 malformed_summary_missing_section 失败开放;
  • 最终 Turn 结果为 context_budget_exhausted
  • 紧接着发送一条很短的后续消息后,又立即运行了一次 history_compact。该调用在 113,942 ms 后以 finishReason: stop 正常完成(37,498 input tokens、1,895 output tokens),但该 Turn 仍以 context_budget_exhausted 结束,详情为 summarizer_failed

摘要校验器的行为是正确的:不完整摘要不能替换持久历史。活性缺陷在于,同一个 Session 没有有界的修复或退出路径。重复发送或重新生成可能再次发起同一个注定失败的压缩,而 Desktop 只显示泛化的“任务运行失败”toast。

Session 历史仍然完整,Runtime Host 也始终保持 ready,没有进程退出。GitHub 访问本身不是失败原因。

如何复现

  1. 配置一个没有声明上下文窗口的自定义 Responses-compatible relay 模型,使其采用默认有界回退。
  2. 启动一个 Desktop Session,并积累足够多的文本类工具结果,使其超过该容量。一次 Turn 中读取多个完整 GitHub issue / PR 正文可以复现本次观察到的形态。
  3. 让历史摘要器返回非空文本和 finishReason: stop,但缺少一个或多个 checkpoint 必需章节。
  4. 观察摘要被正确拒绝为 malformed_summary_missing_section,且没有写入 checkpoint。
  5. 继续运行,直到实际待发送请求仍然超过容量。
  6. 观察 context_budget_exhausted
  7. 发送一条很短的后续消息或执行重新生成。
  8. 观察另一次正常完成的 history_compact 请求,以及随后相同的终止失败;界面没有提供可操作的恢复建议。

该问题也应通过注入摘要器进行确定性测试,不需要依赖真实 provider 测试。

预期行为

  • 保留 fix(runtime): history compaction accepts truncated/unstructured LLM summaries without validation #3029 引入的严格 checkpoint 摘要校验器。格式错误的摘要绝不能替换被折叠的历史。
  • 对同一个压缩输入/失败指纹限制修复尝试次数,不要在完全相同的坏摘要结果上反复消耗模型调用。
  • 有界尝试耗尽后,通过终态投影保留稳定的诊断原因,例如 malformed_summary_missing_section
  • 提供可操作的恢复路径:配置模型的真实上下文窗口、切换模型/连接,或者启动新的任务/分支。
  • 当模型、连接、上下文窗口声明或源历史指纹发生变化时可以重试;条件没有变化时不应盲目循环。
  • 增加回归覆盖:一个超过容量、工具结果很多的历史,其摘要器正常完成但遗漏必需章节。

具体修复机制(一次更严格的重试、结构化输出摘要、备用摘要模型或其他有界策略)可以在实现阶段决定。削弱或绕过摘要校验不是可接受的修复。

环境

  • Maka commit:3a9824a7e
  • Maka 版本:0.2.0 development build
  • 使用面:Desktop + Runtime Host
  • OS:macOS 26.6 / Darwin 25.6.0 arm64
  • Electron:43.4.1
  • Node.js:24.18.1
  • Provider 类型:自定义 openai-responses-compatible
  • 模型:gpt-5.6-sol
  • Runtime Host:始终保持 ready;没有捕获到本地进程退出

日志、截图或其他上下文

第一次失败 Turn 的诊断:

contextWindow: null
failureClass: context_budget_exhausted
compaction decisions:
  failedOpen / context_limit / malformed_summary_missing_section: 8
  unchanged / context_budget_exhausted: 1
latest main input tokens: 43,145
active pruned tool results: 74
active estimated tokens saved: 352,159

紧接着的后续 Turn:

callKind: history_compact
status: completed
finishReason: stop
latency: 113,942 ms
input tokens: 37,498
output tokens: 1,895
terminal detail: summarizer_failed
failureClass: context_budget_exhausted

相关 issue:

非目标:

  • 修改自定义 relay 实际暴露的上下文限制;
  • 削弱 checkpoint 校验;
  • 处理同一应用进程中更早出现、但与本问题无关的 Electron MaxListenersExceededWarning

AI 协助披露:Codex 检查了本地持久化的 Runtime 记录和源码,基于报告者提供的诊断起草本报告,并按报告者要求发布。

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions