# Agent Note：TUI 提示区状态指示器

Status: implemented

[English](2026-07-24-tui-prompt-status-indicator.md) | 中文

## 问题

轮次运行期间，输入提示区只显示其静态的 `dsh>` 前缀。assistant 头部承载已用计时，但编辑器所在的这一行——也就是用户注意力所在之处——对 agent 此刻正在做什么没有任何实时信号：是在等待第一个 token、思考、响应，还是在运行工具。

## 决策

agent 运行期间，一个按阶段区分的字形会替换内置 `${indicator}` 提示区值中的 `>` 光标符。`inputPrompt` 主题模板默认为 `${symbol} ${indicator}`，其中内置 `${symbol}` 值承载 `dsh` 标签，`${indicator}` 承载光标符槽位及其在光标前的尾随间隙；模板中的字面空格将两者隔开，在每种状态下渲染为 `dsh <字形> `。阶段取自当前打开步骤的活跃计时桶，其派生所依据的会话事件与规则和[消息头部计时](2026-07-24-tui-message-header-timing.md)相同——没有引入新的阶段模型。每个桶对应一个字形：`◍` 等待模型（第一个 token 之前）、`✻` 思考、`●` 响应、`⚙` 工具。运行中但没有打开步骤的轮次回退到等待模型的字形；agent 空闲时则恢复为纯 `>`。

字形占据光标符所在的同一列，且每一帧的显示宽度都相同，因此无论阶段切换还是字形动画，光标都不会移动。活动状态由亮度脉动传达，而不是靠出现和消失：一个四帧三角波（暗 → 正常 → 亮 → 正常）用真正的 SGR 强度码（2 与 1）包裹带 accent 色的字形——绝不使用调色板语义上的 `dim` 角色，因为在浅色 scheme 下它是一种颜色，会被字形自身的 accent 色覆盖——因此脉动在任何终端 scheme 下都能保留。渲染时钟节拍为每帧 250 ms，是与配套的 100 ms 状态刷新并列的固定呈现节奏，而非部署选项。运行状态计时器每 100 ms 无条件刷新一次，而不再只在存在流式组件时刷新，因此即使在第一个 token 之前的等待期间，脉动也能持续。

光标符及其动画自成一个 `${indicator}` 值，与 `${symbol}` 标签分离，因此 `inputPrompt` 模板将二者组合：`${symbol} ${indicator}` 读作 `dsh <光标符>`。可配置性位于该模板——部署可重排或丢弃任一值，省略 `${indicator}` 即退出运行指示器。字形集、脉动以及 `dsh` 标签都固定在代码中——不是逐部署字段——与它们映射的固定计时桶标签一致。

内置 `${symbol}`/`${indicator}` 的更新搭乘 TUI 本就在每次可能改变某个值的状态变化（`agent/status`、会话事件、100 ms 运行状态计时器、异步模型上下文解析）时驱动的渲染。而一个自行变化的值——插件拥有的 `${custom}` 片段——则通过注册表的合并变更通知重绘，而渲染器直接订阅它，而非通过 Cordis 事件（参见[注册表](2026-07-24-configurable-tui-prompt-theme.md)）。

## 考虑过的替代方案

**把字形作为自己的 `${status}` token 前置在 `dsh>` 之前。** 已否决：前置 token 每次出现都会把整个提示区——连同光标——向右移动两列，清除时又缩回。在尾随的 `${indicator}` 槽位替换光标符能让光标列保持固定。

**出现又消失的闪烁字形。** 已否决：一旦字形占据光标符所在列，开/关式的空白帧在水平方向上不再移动任何东西，但空帧读起来像闪烁。亮度脉动让字符保持不动的同时持续做动画。

**按阶段的 spinner 动画**（旋转帧）。已否决：四个阶段已经通过各自的字形形状区分；逐帧切换字符会把「哪个阶段」与「仍在工作」混为一谈。脉动只改变强度做动画，而形状始终是稳定的阶段信号，且复用了既有的 100 ms 状态计时器。

**在 TUI 中新建阶段状态机。** 已否决：头部计时机制已从会话事件回放出当前打开步骤的活跃桶。从该桶派生字形，能让「这个步骤处于哪个阶段」保持单一事实来源。

## 后果

用户在自己本就注视的光标符处获得可一眼掌握的实时阶段信号，且光标与提示区都没有水平移动。脉动的代价是整个运行轮次内每 100 ms 一次的终端渲染，而不再只在流式组件挂载期间。字形映射与脉动都固定在代码中、不可配置，与其所对应的固定计时桶标签一致。
