终端 UI 与运行状态
Agent CLI 不是简单聊天框。它需要让用户知道:
- 当前模型在想什么。
- 哪个工具正在运行。
- 哪个工具等待权限。
- 后台任务是否还活着。
- MCP 或插件是否连接失败。
- 会话是否被 compact。
Claude Code 使用 React/Ink 风格的终端 UI,并维护一个很大的 AppState。
AppState 的源码锚点在 state/AppStateStore.ts。它不仅保存消息展示状态,还保存权限上下文、MCP clients/tools/resources、plugin 状态、任务、通知、todos、bridge 和 prompt suggestion 等运行状态。
AppState 的职责
AppStateStore.ts 里集中保存:
- settings。
- permission context。
- MCP clients/tools/resources。
- plugin 状态。
- tasks。
- notifications。
- todos。
- thinking 状态。
- prompt suggestion。
- remote/bridge 状态。
这说明真实 Agent 产品的 UI 状态远不止 messages。
不要让 UI 污染核心循环
核心原则:
text
AgentLoop 产出事件
UI 订阅事件并渲染1
2
2
不要让 Tool 直接操作 UI。Tool 应该产出结构化 progress 和 result,UI adapter 再决定怎么显示。
简化版 UI 状态
建议先拆成:
ts
type RuntimeState = {
session: SessionState
tools: ToolState
permissions: PermissionState
ui: UIState
extensions: ExtensionState
}1
2
3
4
5
6
7
2
3
4
5
6
7
不要一开始做一个无所不包的全局对象。
小结
终端 UI 的价值是可观察性。用户愿意授权 Agent 做事,前提是看得见它在做什么、为什么卡住、接下来需要谁确认。