Skip to content

子代理 UI 打磨:列表贴合内容、详情页去掉横线带、命令执行成块 - #36

Merged
tt-a1i merged 7 commits into
mainfrom
subagent-ui-polish
Aug 20, 2026
Merged

子代理 UI 打磨:列表贴合内容、详情页去掉横线带、命令执行成块#36
tt-a1i merged 7 commits into
mainfrom
subagent-ui-polish

Conversation

@tt-a1i

@tt-a1i tt-a1i commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

子代理的三个界面都做了视觉整理:多子代理列表、单个子代理详情、以及详情里的命令执行渲染。

① 命令执行渲染成块(transcript.ts

一次 bash 调用原来是三段互不相干的行,output: 读起来像调试日志;运行中的工具还是另一种排版,结束时会整行重排。

Before

→ bash git status --porcelain

  output: M extensions/foo.ts

bash git status --porcelain · running · M extensions/foo.ts

After

$ git status --porcelain
  ✓  M extensions/subagents/src/ui/takeover.ts

→ read extensions/subagents/src/ui/transcript.ts
  ✓ import { getMarkdownTheme } from ...

$ bun run test
  ✗ 1 test failed

⠋ $ bun run check
  · Checked 223 files
  • bash 用 shell 提示符 $ cmd,其他工具保留 → name args
  • 调用与结果按 toolId 配对,中间不再插空行,一次执行读起来是一块
  • 状态由 glyph 承担( / / 运行中 spinner),删掉 · running · done 后缀;运行中的部分输出用中性 ·,不冒领成功
  • 运行中与结束后排版完全一致,只有首字符 glyph 变化,settle 时不再重排

② 列表贴合内容 + 显示实时活动(takeover.ts

  • 原来固定渲染 rows - 5 行,1 个子代理也撑出一整屏空框 → 现在高度按行数走,上限不变
  • 双 header(Subagents / 3 agents + 边框标题 agents · 0/3)合成一个边框标题 ╭─ Subagents · 2 running · 1 done ─╮
  • 状态不再说两遍( + running):运行中是 spinner,结束是 /
  • 运行中的行显示当前在做什么(最新 liveTool 的名字与参数摘要),比静态 model 名有用
  • … N more 独占一行,不再覆盖真实条目
  • 窄终端按优先级丢弃右侧字段(先丢 backend、model),不再把一长串 · 硬截断

③ 详情页 chrome 从 5 条通栏横线降到 3 条

  • 顶栏承载信息:左边 glyph + 标题,右边右对齐 model · ctx% · elapsed(窄屏按优先级丢弃)
  • 滚动状态从正文里挪到横线上右对齐(↓ 42),正文视口高度恒定,滚动时 overlay 不跳动
  • 占位文案 (no output yet) → dim 的 waiting for output…
  • 键位提示在窄屏下省略 page 键

其他

  • spinner 帧与节奏统一到 transcript.ts 一处导出,dashboard / 详情页 header / transcript 三处同帧(原来是三份各自的拷贝)
  • 只在有子代理运行时把重绘节奏提到 ~120ms,空闲回落到 1s,idle 状态不会 8 次/秒重绘
  • 无 domain / backend 改动:outputPreview 仍是上游收敛过的单行,本次纯渲染层

验证

  • bun run test:736 + 29 全绿(基线 723 + 29)
  • bun run check 退出 0(仅剩 file-search/src/binaries.ts 既存 warning)
  • 新增测试覆盖:列表高度贴合、more 行不覆盖、glyph/活动渲染、窄宽度每行 visibleWidth <= width、详情页恰好 3 条横线且高度恒定、滚动指示只在滚动时出现、调用+结果无空行、运行/结束排版一致、spinner 帧边界确定性

tt-a1i added 7 commits August 20, 2026 23:29
Use status glyphs for tool results and live execution state.\nKeep tool calls and results contiguous, with running and settled tools sharing one body shape.
The dashboard, takeover header, and transcript each grew their own spinner
copy. Export the frames and cadence from transcript.ts, pass the render's
`now` into buildTranscriptLines so both spinners show the same frame, and
mark a running tool's partial output with a neutral dot instead of a success
glyph it has not earned yet.
Review found the running/settled parity contract was vacuous in production:
message_end lands the assistant toolCall in the transcript before
tool_execution_start creates the live entry, and ToolEnd deletes that entry
rather than marking it done. So a running command was rendered twice and the
block reflowed two columns left when it settled.

Give an execution exactly one glyph, on its command line: the live block owns
the call while the tool runs, the transcript's call line takes over with the
settled glyph in the same column, and output lines are plain indented text.
The item cache now keys on width plus tool phase, so a pending glyph cannot
outlive its phase. Also sanitize tool names in the dashboard activity string
(they come from the child's own events) and share one timestamp per frame.
@tt-a1i

tt-a1i commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator Author

追加:glm-5.3 子代理审查后的修复

两个 reviewer 子代理(transcript.ts / takeover.ts 各一个)审出一个实质问题,已修(a73357a):

运行中的命令被渲染了两遍,settle 时整块左移重排。 原因是生产事件顺序与我们的假设不符:message_end(含 assistant 的 toolCall)先落 transcript,tool_execution_start 才创建 live 条目;而 ToolEnd删除 live 条目而非置 done: truemanager.ts:429-431)。所以运行期间 transcript 的 call 行和 live 行同时存在,显示同一条命令;settle 后 live 消失,块从 4 列缩到 2 列——正是本 PR 声称要消除的重排。原先的「运行/结束同形」测试构造的是 done: true 这个生产中不存在的状态,等于没有约束。

改法:一次执行只有一个 glyph,落在命令行上。

  • 运行中:live 块接管该 call(transcript 里同 toolId 的 call 行跳过渲染)
  • 结束后:transcript 的 call 行接手,glyph 变为 /列完全不变
  • 输出行不再重复 glyph,改为缩进纯文本
running:  ⠋ $ bun run test        settled:  ✓ $ bun run test
              719 pass                          719 pass

同时修的:

  • item 缓存 key 从 width 变为 width|tool phase,避免 pending 的 · 被永久缓存
  • 孤立 result(上方没有对应 call)仍自带 glyph,用 ✓ → bash 形式,不再输出空的 $
  • dashboard 活动串里的 tool name 未做 sanitize(P1,终端注入口)——tool name 来自子会话自己的事件,同样不可信;truncateToWidth 只在测量时忽略转义序列
  • dashboard 每行各自取 Date.now() 改为整帧共享一个时间戳,避免同屏 spinner 不同帧

新增测试:生产顺序下的 running→settled 无重复无重排、spinner 跨帧不被缓存冻结、缓存按宽度与 phase 双维度区分、孤立 result 渲染。

738 + 29 全绿bun run check 退出 0。

审查里其余为测试加固建议(并行 tool call 的配对语义、dashboard 精确 padding 断言、… N more 在向下滚动时应叫 hidden)与 nits,未在本 PR 处理。

@tt-a1i
tt-a1i merged commit be39576 into main Aug 20, 2026
4 checks passed
@tt-a1i
tt-a1i deleted the subagent-ui-polish branch August 20, 2026 16:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant