feat(tui): show live compaction progress
This commit is contained in:
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-07-29-human-transcript-append-origin.md
|
||||
2026-07-29-human-transcript-append-origin.md: dcc4a786c6f1926f06dce03124ec1d8ca805d7ae
|
||||
2026-07-29-human-transcript-append-origin.zh.md: 0fefc52afa52e99cdec2bcea1a86b9c28711dd67
|
||||
2026-07-29-human-transcript-append-origin.md: a47dd49dd831cdd32d520137417bf47d2c056a09
|
||||
2026-07-29-human-transcript-append-origin.zh.md: 31639bd9aac5d6dace80392004f37c747bff2c36
|
||||
|
||||
@@ -26,7 +26,7 @@ No persisted event, RPC envelope, compaction transaction, or model-visible surfa
|
||||
|
||||
The browser client is fixed separately, in [the web transcript projection note](2026-07-30-web-transcript-log-ordered-projection.md): it projects the same append-origin transcript in log order and renders a marker component, and it closes the pagination hole this change opened — because `session.history` no longer spends quota on the checkpoint, it never cuts on the checkpoint's provenance group, so a page can carry a checkpoint citing a `surfaceOp.start` outside the window, which the browser's surface fold rejected. That hole predates this change (counting could already run past a checkpoint into the range it shadows), but the old rule accidentally covered the case where the checkpoint was the oldest counted message and pulled the whole shadowed range onto its page.
|
||||
|
||||
Rendering compaction *progress* — a terminal indicator while a compaction runs — needs the bracket-first ordering that the queued manual `/compact` work introduces, and is out of scope here. The marker also carries no scale: the checkpoint's `sourceEventSeqs` already hold the shadowed count, so a count or range would tell a reader how much each row folded. That belongs with progress, where the reader meets the other half of the same information. Whoever takes it should fold the terminal's two replacement branches — replay and the live listener, textually identical and 600 lines apart — into one `renderReplacement(event)` first, so the marker's content has a single home.
|
||||
The terminal's [live compaction progress decision](../feature/2026-07-30-compaction-progress-visibility.md) uses standalone bracket events to drive the existing one-cell indicator. It does not change the completion marker owned here or add scale: the checkpoint's `sourceEventSeqs` remain available for a separately justified count or range. Progress therefore needs neither marker-content changes nor a prerequisite `renderReplacement(event)` extraction.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ Status: implemented
|
||||
|
||||
浏览器客户端在[Web 记录投影笔记](2026-07-30-web-transcript-log-ordered-projection.md)中单独修复:它按日志顺序投影同一份 append 来源记录并渲染一个标记组件,同时闭合本次变更打开的分页缺口——因为 `session.history` 不再为检查点消耗额度,它永远不会按检查点的溯源分组切分,于是一页可以携带一个引用了窗口之外 `surfaceOp.start` 的检查点,而浏览器的 surface fold 会拒绝该范围。这个缺口早于本次变更(此前计数就可能越过检查点进入它所遮蔽的范围),但旧规则恰好覆盖了这样一种情形:检查点是最旧的被计数消息,其溯源分组把整段被遮蔽的范围一起拉到该页。
|
||||
|
||||
渲染压缩*进度*——压缩运行期间的终端指示——需要排队式手动 `/compact` 工作引入的“先开括号”顺序,不在本次范围内。标记同样不携带规模信息:检查点的 `sourceEventSeqs` 已经包含被遮蔽的数量,因此一个计数或区间可以告诉读者每一行折叠了多少内容。这件事属于进度那一侧,读者正是在那里遇到同一份信息的另一半。接手者应当先把终端里两处替换分支——回放与实时监听器,文本完全相同却相隔 600 行——合并为一个 `renderReplacement(event)`,让标记的内容只有一个归处。
|
||||
终端的[实时压缩进度决策](../feature/2026-07-30-compaction-progress-visibility.md)使用独立标记对中的事件驱动现有的单格指示器。它既不改变本文所负责的完成标记,也不添加规模信息:检查点的 `sourceEventSeqs` 仍可供经另行论证的计数或区间使用。因此,进度显示既不需要修改标记内容,也不以提取 `renderReplacement(event)` 为前置条件。
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-07-30-web-transcript-log-ordered-projection.md
|
||||
2026-07-30-web-transcript-log-ordered-projection.md: 0c58373d58e08fbfe260f16f2104b3f7d1ccc3fd
|
||||
2026-07-30-web-transcript-log-ordered-projection.zh.md: 49de0a9ecbbf2da92113f8ad63afe6478caedadd
|
||||
2026-07-30-web-transcript-log-ordered-projection.md: 878feaca0ff0f20bac03237fa9c4ecdeb3465571
|
||||
2026-07-30-web-transcript-log-ordered-projection.zh.md: 2b7e66d0b403b19d38ae40367081832834b628b4
|
||||
|
||||
@@ -69,4 +69,4 @@ The web e2e scenario now seeds a real compaction transaction over its recorded t
|
||||
|
||||
## Deferred
|
||||
|
||||
Compaction **progress** — an indicator while a compaction runs — needs the bracket-first ordering the queued manual-compaction work introduces, and stays out of scope here as it did in the terminal. The marker also carries no **scale**: the checkpoint's `sourceEventSeqs` already hold the shadowed count, so a count or range would tell a reader how much each row folded. Both belong together, where the reader meets the two halves of the same information.
|
||||
The terminal's [compaction progress decision](../feature/2026-07-30-compaction-progress-visibility.md) uses the live standalone bracket to drive a one-cell indicator and does not change this browser projection. The marker still carries no **scale**: the checkpoint's `sourceEventSeqs` hold the shadowed count, so a separately justified count or range can be added without coupling it to progress.
|
||||
|
||||
@@ -69,4 +69,4 @@ Web e2e 场景现在在它录制的那一轮之上播种一次真实的压缩事
|
||||
|
||||
## Deferred
|
||||
|
||||
压缩**进度**——压缩运行期间的指示——需要排队式手动压缩工作引入的“先开括号”顺序,与终端一样不在本次范围内。标记同样不携带**规模**信息:检查点的 `sourceEventSeqs` 已经包含被遮蔽的数量,因此一个计数或区间可以告诉读者每一行折叠了多少内容。两者应当放在一起,读者正是在那里遇到同一份信息的两半。
|
||||
终端的[压缩进度决策](../feature/2026-07-30-compaction-progress-visibility.md)使用实时独立标记对驱动单格指示器,并不改变此浏览器投影。标记仍不携带**规模**信息:检查点的 `sourceEventSeqs` 保存被遮蔽的数量,因此可以另行论证后添加计数或区间,而无须将其与进度耦合。
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-30-compaction-progress-visibility.md
|
||||
2026-07-30-compaction-progress-visibility.md: fdd927f41b967ebd118b2934b300bca60ad99a87
|
||||
2026-07-30-compaction-progress-visibility.zh.md: 95059a8e12dc2378728a5c89a2f571536ac51ded
|
||||
@@ -0,0 +1,47 @@
|
||||
# Agent Note: Live standalone compaction progress in the terminal
|
||||
|
||||
Status: implemented
|
||||
|
||||
English | [中文](2026-07-30-compaction-progress-visibility.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
A standalone manual compaction runs between turns while the agent remains idle. The TUI's turn-phase indicator therefore kept its plain `>` caret throughout the slow summary operation, and a failed attempt produced no transcript row because no replacement checkpoint landed.
|
||||
|
||||
The durable log can retain an unmatched `compact/start` after a process dies. That orphan is useful recovery evidence, but it is not proof that work is running in the current process; replaying it as progress would leave resumed sessions with a permanent phantom indicator.
|
||||
|
||||
## Decision
|
||||
|
||||
The TUI treats the live standalone `compact/start { turn: null }` to matching `compact/end` bracket as the source of in-flight compaction presentation. A module-local `compacting` cell records the render-clock start and owns one animation timer. The existing one-cell indicator renders `⊙` through the same fade and throb path as turn-phase glyphs, and the terminal progress bit remains active until the bracket closes.
|
||||
|
||||
Turn-phase glyphs take precedence over `⊙`. Numbered compaction brackets are ignored because they are enclosed by a running turn whose phase already lights the indicator. The compaction cell does not change the idle editor border, hint, or steering badge, so prompts remain visibly accepted while standalone compaction reserves turn admission.
|
||||
|
||||
The cell is live-only. Mount and transcript replay never scan history for an unmatched start; only a `session/event` notification observed by the mounted TUI can open it. Turn-status transitions preserve the cell, while terminal teardown clears its timer and progress bit.
|
||||
|
||||
On `compact/end`, the TUI clears the live cell before starting the ordinary glyph fade-out. An end carrying `error` adds `Compaction failed: <error>` as a warning. Successful completion remains represented by the landed replacement's transcript marker, and duration remains derivable from the matching durable start and end timestamps without another visible row.
|
||||
|
||||
This decision partially supersedes only the progress-related deferred clauses in the [terminal transcript decision](../bug-fix/2026-07-29-human-transcript-append-origin.md) and [browser transcript decision](../bug-fix/2026-07-30-web-transcript-log-ordered-projection.md): progress does not require marker scale or a replacement-rendering refactor. Both notes remain active and continue to own append-origin transcript projection and landed checkpoint markers. The [queued manual compaction decision](2026-07-30-queued-manual-compaction.md) remains the owner of bracket ordering, locking, and stale-orphan classification.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Add `progressLabel` to `CommandDefinition` and a second TUI status controller, as explored in PR #669.** Rejected because command metadata is not the compaction lifecycle authority, automatic compaction does not originate from a human command, and two status controllers can disagree about the same indicator.
|
||||
|
||||
**Add `compacting` to `TurnPhase`, as explored in PR #669.** Rejected because standalone compaction deliberately has no turn, while numbered compaction already has a visible running-turn phase.
|
||||
|
||||
**Add a fifth `TimingBucket`.** Rejected because timing buckets partition an open model step and feed its transcript footer. Standalone compaction has no step transition, and a new bucket would add a meaningless compaction column to every step total.
|
||||
|
||||
**Share one timer among running, fading, and compaction states.** Rejected because fade-out owns a self-terminating timer, while live compaction has an independent open/close lifetime. Sharing would restructure the reviewed animation state machine without removing an actual concurrent timer.
|
||||
|
||||
**Scan the log for an unmatched `compact/start`.** Rejected because a stale orphan from an earlier process lifecycle is expected durable history. Only the live notification proves current work.
|
||||
|
||||
**Use a generic command-running indicator.** Rejected for this behavior because the compaction bracket is the more precise source and also covers non-command paths. A future generic command indicator belongs to the `command/run` / `command/done` lifecycle.
|
||||
|
||||
**Print a success notice with duration.** Rejected because the landed replacement already supplies the completion marker. The bracket timestamps preserve duration for a future presentation that justifies another transcript row.
|
||||
|
||||
## Consequences
|
||||
|
||||
Manual compaction now has visible liveness while the agent is idle, failure has a direct warning, and a resumed orphan never looks active. The indicator remains one terminal cell wide and reuses the existing animation, color, and terminal-progress behavior.
|
||||
|
||||
The live cell and its timer are additional process-local state, cleared on both bracket close and TUI teardown. This is intentionally not reconstructible presentation state: durable history supplies the successful marker and timing facts, while current-process observation alone supplies liveness.
|
||||
|
||||
The package-level TUI tests pin standalone start, numbered-start exclusion, fade-out, failure warning, idle-status preservation, running-turn precedence, orphaned resume, and timer disposal. The assembled `queued-manual-compact` terminal scenario also observes `dsh ⊙` while the real summary boundary is held.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Agent Note: 终端中的实时独立压缩进度
|
||||
|
||||
Status: implemented
|
||||
|
||||
[English](2026-07-30-compaction-progress-visibility.md) | 中文
|
||||
|
||||
## 问题
|
||||
|
||||
独立手动压缩(compaction)在轮次之间运行,此时 agent(智能体)保持空闲。因此,在缓慢的摘要操作期间,TUI 的轮次阶段指示器始终显示普通的 `>` 光标;尝试失败时,由于没有替换检查点落地,也不会产生 transcript(文本记录)行。
|
||||
|
||||
进程终止后,持久日志中可能保留未匹配的 `compact/start`。该未匹配标记是有用的恢复证据,但无法证明当前进程中有工作正在运行;若将其回放为进度,恢复后的会话便会永久显示虚假的进度指示。
|
||||
|
||||
## 决策
|
||||
|
||||
TUI 将实时独立的 `compact/start { turn: null }` 与匹配的 `compact/end` 组成的标记对,作为显示进行中压缩状态的真源。模块局部的 `compacting` 状态记录渲染时钟的起始时间,并独占一个动画定时器。现有的单格指示器通过与轮次阶段字形相同的明暗渐变和呼吸律动路径渲染 `⊙`,终端进度标志位会保持活跃,直至标记对闭合。
|
||||
|
||||
轮次阶段字形的优先级高于 `⊙`。带编号的压缩标记对会被忽略,因为它们处于运行中的轮次内,该轮次的阶段已经激活指示器。压缩状态不会改变空闲编辑器边框、提示或 steering(中途引导)徽标,因此,在独立压缩预留轮次准入期间,界面仍会明确显示提示词已获接纳。
|
||||
|
||||
该状态只反映实时事件。挂载和 transcript 回放绝不会扫描历史以查找未匹配的 start;只有已挂载的 TUI 观察到 `session/event` 通知,才能开启该状态。轮次状态转换会保留该状态,而终端清理会清除其定时器和进度标志位。
|
||||
|
||||
收到 `compact/end` 时,TUI 会先清除实时状态,再启动普通字形的淡出。携带 `error` 的结束事件会以警告形式添加 `Compaction failed: <error>`。成功完成仍由已落地替换项的 transcript 标记呈现;无需再添加可见行,也可从匹配且已持久记录的开始与结束时间戳推导持续时间。
|
||||
|
||||
本决策仅部分取代[终端 transcript 决策](../bug-fix/2026-07-29-human-transcript-append-origin.md)和[浏览器 transcript 决策](../bug-fix/2026-07-30-web-transcript-log-ordered-projection.md)中与进度相关的延期条款:进度显示不要求标记携带规模信息,也不要求重构替换项渲染。两份记录均保持活动状态,并继续负责基于追加来源的 transcript 投影和已落地检查点标记。[排队式手动压缩决策](2026-07-30-queued-manual-compaction.md)继续负责标记对顺序、锁定机制和陈旧未匹配标记分类。
|
||||
|
||||
## 曾考虑的替代方案
|
||||
|
||||
**按照 PR(Pull Request)#669 中探索的方案,为 `CommandDefinition` 添加 `progressLabel` 和第二个 TUI 状态控制器。** 不予采用:命令元数据并非压缩生命周期的权威依据,自动压缩并非由人工命令发起,两个状态控制器也可能对同一个指示器给出不一致状态。
|
||||
|
||||
**按照 PR #669 中探索的方案,将 `compacting` 添加到 `TurnPhase`。** 不予采用:独立压缩按设计没有轮次,而带编号的压缩已经具有可见的运行轮次阶段。
|
||||
|
||||
**添加第五个 `TimingBucket`。** 不予采用:计时分桶用于划分一个开放模型步骤内的时间,并为其 transcript 页脚提供数据。独立压缩没有步骤转换,新分桶会在每个步骤总计中加入一个没有意义的压缩列。
|
||||
|
||||
**让运行、淡出和压缩状态共享一个定时器。** 不予采用:淡出过程独占一个会自行终止的定时器,而实时压缩有独立的开启与闭合生命周期。共享定时器会重构已经评审的动画状态机,却不能消除实际存在的并发定时器。
|
||||
|
||||
**扫描日志,查找未匹配的 `compact/start`。** 不予采用:来自先前进程生命周期的陈旧未匹配标记是预期的持久历史。只有实时通知才能证明当前进程正在执行工作。
|
||||
|
||||
**使用通用的命令运行指示器。** 本行为不采用该方案,因为压缩标记对是更精确的真源,并且还覆盖非命令路径。未来若实现通用命令指示器,应归属于 `command/run` 和 `command/done` 生命周期。
|
||||
|
||||
**打印包含持续时间的成功通知。** 不予采用:已落地的替换项已经提供完成标记。标记对的时间戳保留了持续时间,可供未来能够证明新增 transcript 行合理的展示方式使用。
|
||||
|
||||
## 后果
|
||||
|
||||
手动压缩在 agent 空闲时会显示正在运行,失败会直接产生警告,恢复会话时的陈旧未匹配标记绝不会显示为活动状态。指示器保持一个终端字符单元宽,并复用现有的动画、颜色和终端进度行为。
|
||||
|
||||
实时状态及其定时器是额外的进程局部状态,在标记对闭合和 TUI 清理这两种情况下都会清除。按设计,这种显示状态不可重建:持久历史提供成功标记与计时事实,只有当前进程的观察才能提供运行中状态。
|
||||
|
||||
包(package)级 TUI 测试固定了以下行为:独立开始事件、排除带编号的开始事件、淡出、失败警告、保留空闲状态、运行轮次优先级、存在未匹配标记时的恢复,以及定时器释放。组装后的 `queued-manual-compact` 终端场景还会在真实摘要边界保持开放期间观察到 `dsh ⊙`。
|
||||
Reference in New Issue
Block a user