You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug] 摘要失败后仍只留 1 条用户消息,当前长回合无真摘要 / Failed compaction still keeps one user line and drops the active turn #827
Follow-up to #543 / PR #563 (ADR 0282 / D445). Do not reopen #543 — the UI and retry/preflight slice shipped; the remaining hole is the fallback contract.
On PI-Desktop 0.15.2, a long Agent session still lost almost all working memory after automatic compaction #3. The transcript row now correctly says:
上下文已压缩 · 第 3 次 摘要生成失败 · 已保留近期上下文
That label is the #563 UI fix. It is not a successful summary. After that row, the model no longer knew decisions, paths, or unfinished work from the active turn. The user had to re-steer from scratch.
Open PI-Desktop 0.15.2 (Linux AppImage / WSL2), Agent mode, a long coding session with many tool results.
Let automatic compaction succeed at least once (a real 4–9k-character summary).
Continue the same turn until the context hits the hard limit again (tokensBefore here ≈ 140k, mid-turn, retainedTailMode: active_turn).
Watch 上下文已压缩 · 第 N 次 摘要生成失败 · 已保留近期上下文.
Ask about files, decisions, or unfinished work from after the last successful summary but before the failure row — or simply continue the same task without restating it.
Input still too large after the one reduced pass: do not skip the model. Chunk / map-reduce / keep truncating tool output until a new structured summary covers the range this checkpoint claims.
Last resort only: persist a bounded recent original tail on the order of keepRecentTokens (thousands of tokens of recent user + assistant + tool text), not a single user sentence.
If a previous real summary exists, keep it and cover the delta since that summary. Do not tell the model that one leftover user line is the source of truth for the whole continuation.
The UI label “摘要生成失败 · 已保留近期上下文” is fine only if “近期上下文” is actually large enough to continue the task.
No usage object → this attempt did not complete a summary call (budget-reduced input still too large, or retries exhausted). Contrast gen 1–2, which both have provider usage.
retainedTail is a single user line (the task that was in flight). Codex-shaped prep still folds all history into messagesToSummarize and keeps at most that one user message (active_turn) or none (completed_turn). keepRecentTokens still does not decide survival.
createFallbackCheckpoint appends the previous summary (good vs 0.14.8’s 112-token stub) and instructs: “Use the one retained latest user request as the source of truth for that continuation.” After the row, the model treated that one sentence as the whole job and forgot the rest of the turn (~168 messages between gen 2 and gen 3: 3 user / 34 assistant / 131 tool).
Full JSONL remains on disk (~6.5MB). Only the next model request is stripped. The UI looks intact; the agent is amnesiac.
Fallback notice appended to the carried gen-2 summary (sidecar COMPACTION_FALLBACK_MARKER):
[automatic context recovery: older context was omitted after summary generation failed]
The automatic summary request did not complete. Older messages before this checkpoint are omitted from the next model request.
The complete transcript remains available in the session. The provider is continuing the active turn. Use the one retained latest user request as the source of truth for that continuation.
No full transcript attached (privacy). Happy to add redacted sidecar traces if useful.
Screenshots / 截图
No screenshot. The UI row is the #563 failure label, which is correct; the bug is what the next model request contains.
After the one reduced pass still overflows: chunk the range and still call the model; merge partial summaries until the checkpoint covers throughMessageId. Do not fall back solely because compactionSummaryWouldExceedBudget is true.
Last resort: persist a bounded recent original tail (keep-recent / 8k–20k tokens of recent user+assistant+tool text), not one user message. selectRetainedUserMessages already exists; Codex shaping currently throws that budget away.
Stop telling the model that the leftover user line is the source of truth when the new summary was not generated. Carry the previous summary without overriding the active-turn goal.
Optional: persist build.message (why the summary failed: budget vs provider error vs abort) on details, so the next report is not usage: null with no reason.
What happened? / 问题描述
Follow-up to #543 / PR #563 (ADR 0282 / D445). Do not reopen #543 — the UI and retry/preflight slice shipped; the remaining hole is the fallback contract.
On PI-Desktop 0.15.2, a long Agent session still lost almost all working memory after automatic compaction #3. The transcript row now correctly says:
上下文已压缩 · 第 3 次 摘要生成失败 · 已保留近期上下文That label is the #563 UI fix. It is not a successful summary. After that row, the model no longer knew decisions, paths, or unfinished work from the active turn. The user had to re-steer from scratch.
#563 explicitly deferred:
keepRecentsurvival ([Feature] 设置页增加上下文压缩阈值(keepRecent / reserve) / Expose compaction keepRecentTokens and reserveTokens in Settings #203)So a failed attempt still omits the current long turn from the next model request, even when a previous real summary exists.
这是 #543 / PR #563(ADR 0282 / D445)的后续,不要重开 #543。UI 和重试/预检那一层已经落地;剩下的是回退契约。
PI-Desktop 0.15.2 上,一条长 Agent 会话在自动压缩第 3 次后几乎丢掉全部工作记忆。转录行现在会正确显示:
上下文已压缩 · 第 3 次 摘要生成失败 · 已保留近期上下文这正是 #563 的 UI 修复,不是一次成功摘要。该行之后,模型不再知道当前回合里的决策、路径、未完成工作,用户只能重新引导。
#563 明确没做:分段 map-reduce、Codex 形
keepRecent存活(#203)、回退尾部大小不变(仍最多最后一条用户消息)。所以失败时,即使上一份真摘要还在,当前长回合仍会从下一次模型请求里拿掉。Steps to reproduce / 复现步骤
Open PI-Desktop 0.15.2 (Linux AppImage / WSL2), Agent mode, a long coding session with many tool results.
Let automatic compaction succeed at least once (a real 4–9k-character summary).
Continue the same turn until the context hits the hard limit again (
tokensBeforehere ≈ 140k, mid-turn,retainedTailMode: active_turn).Watch
上下文已压缩 · 第 N 次 摘要生成失败 · 已保留近期上下文.Ask about files, decisions, or unfinished work from after the last successful summary but before the failure row — or simply continue the same task without restating it.
打开 PI-Desktop 0.15.2(Linux AppImage / WSL2),Agent 模式,跑带大量工具输出的长会话。
先让自动压缩成功至少一次(4–9k 字的真摘要)。
同一回合继续做到再次撞硬上限(本机
tokensBefore≈ 14 万,回合中,retainedTailMode: active_turn)。看到
上下文已压缩 · 第 N 次 摘要生成失败 · 已保留近期上下文。再问「上一份成功摘要之后、失败行之前」的文件、决策、未完成工作,或不重述任务直接让它接着干。
Expected behavior / 预期行为
Compaction is a summarization pass. A failure must not wipe the active turn.
keepRecentTokens(thousands of tokens of recent user + assistant + tool text), not a single user sentence.压缩的本质是调模型总结。失败不得清掉当前回合。
Actual behavior / 实际行为
Inspected the session JSONL and installed
pi-host/0.15.2/agent-runtime/sidecar.js(this machine).Session had 3 compaction entries:
usageGeneration 3
details:{ "failureCode": "CONTEXT_COMPACTION_FAILED", "fallback": "retained_tail", "generation": 3, "retainedTailMode": "active_turn" }tokensBefore: 139667usageobject → this attempt did not complete a summary call (budget-reduced input still too large, or retries exhausted). Contrast gen 1–2, which both have provider usage.retainedTailis a single user line (the task that was in flight). Codex-shaped prep still folds all history intomessagesToSummarizeand keeps at most that one user message (active_turn) or none (completed_turn).keepRecentTokensstill does not decide survival.createFallbackCheckpointappends the previous summary (good vs 0.14.8’s 112-token stub) and instructs: “Use the one retained latest user request as the source of truth for that continuation.” After the row, the model treated that one sentence as the whole job and forgot the rest of the turn (~168 messages between gen 2 and gen 3: 3 user / 34 assistant / 131 tool).retainedTailForContexton 0.15.2 is still:v0.15.3 changelog does not mention this path.
对照本机会话 JSONL 和已安装的
pi-host/0.15.2/agent-runtime/sidecar.js。该会话共 3 次压缩:第 1、2 次是真摘要(5802 / 8620 字,有
usage);第 3 次是回退(failureCode: CONTEXT_COMPACTION_FAILED,fallback: retained_tail,tokensBefore: 139667,没有usage)。第 3 次摘要 = 第 2 次原文照搬 + 失败声明(9027 字),retainedTail只剩当前回合那一句用户消息。相对 0.14.8,「空壳 112 tokens 伪装成成功摘要」已经没了;上一份真摘要也会带上。但 Codex 形仍把全部历史折进
messagesToSummarize,最多留 1 条 user。createFallbackCheckpoint还写着「用这一条用户请求作为续写的唯一真相」。失败行之后模型就围着那一句转,丢掉 gen2→gen3 之间约 168 条(3 用户 / 34 助手 / 131 工具)。磁盘 JSONL 还在,被拿掉的是下一次模型请求。0.15.3 changelog 未再动这条路径。App version / 应用版本
0.15.2
Operating system / 操作系统
Linux
Extra environment / 其他环境信息
6.18.33.2-microsoft-standard-WSL2) x86_64~/.local/opt/pi-desktop/VERSION)pi-host0.15.2grok-4.6YahooYuan666)keepRecent/reservesettings; Codex shaping still ignores keepRecent for survival)Logs / 日志
Sanitized compaction checkpoints (no transcript body). Generation 3 is the failure:
{ "generation": 1, "strategy": "summary", "retainedTailMode": "active_turn", "tokensBefore": 146922, "summaryChars": 5802, "usage": { "input": 82503, "output": 1715, "totalTokens": 84346 } }{ "generation": 2, "strategy": "summary", "retainedTailMode": "active_turn", "tokensBefore": 147171, "summaryChars": 8620, "usage": { "input": 41917, "output": 2617, "totalTokens": 44662 } }{ "failureCode": "CONTEXT_COMPACTION_FAILED", "fallback": "retained_tail", "generation": 3, "retainedTailMode": "active_turn", "tokensBefore": 139667, "summaryChars": 9027, "usage": null, "retainedTailCount": 1 }Fallback notice appended to the carried gen-2 summary (sidecar
COMPACTION_FALLBACK_MARKER):No full transcript attached (privacy). Happy to add redacted sidecar traces if useful.
Screenshots / 截图
No screenshot. The UI row is the #563 failure label, which is correct; the bug is what the next model request contains.
无截图。界面行已经是 #563 的失败文案,文案没问题;问题是下一次模型请求里实际还剩什么。
Suggested fix (for maintainers)
In
packages/agent-runtimecompaction fallback (0.15.2sidecar.js:fitSummaryInputToBudget/recoverCompactionFailure/codexShapedPreparation/retainedTailForContext):throughMessageId. Do not fall back solely becausecompactionSummaryWouldExceedBudgetis true.selectRetainedUserMessagesalready exists; Codex shaping currently throws that budget away.build.message(why the summary failed: budget vs provider error vs abort) ondetails, so the next report is notusage: nullwith no reason.fitSummaryInputToBudget/recoverCompactionFailure/codexShapedPreparation/retainedTailForContext:throughMessageId。不要只因为compactionSummaryWouldExceedBudget就回退。selectRetainedUserMessages已在,Codex 形把这个预算丢掉了。build.message(预算 / 供应商 / 中止)写进details,避免再出现只有usage: null、没有原因的检查点。