Agent 状态
文档编写中
部分内容可能尚不完整。
跑着长任务的 Thread 会带一个实时状态,让你一眼看出哪些会话需要你,而不必逐个访问。当一个你没在看的 Thread 结束、或者开始等待一个决定时,会播放一声短提示音。
状态分为 working(工作中)、blocked(等待用户决定)和 idle(空闲)。ThinkTerm 无法归类的会话则不做标记。
该检测默认关闭,在设置里开启。
状态是怎么判定的
会参考三类证据,契约性由强到弱。
1. THINKTERM_AGENT 变量。 程序自行上报身份、会话和状态。这是下文描述的公开协议,也是唯一一个能在程序界面被重新设计之后依然存活的来源。
2. 屏幕规则。 用 TOML 清单匹配 pane 的可见输出及其终端标题。内置规则来自 herdr 项目。
3. 原生转义序列。 OSC 9;4 进度报告,以及标题开头的 spinner 标记。功能关闭时,也只会用到这一类。
有两条仲裁规则很关键,而且它们是有意指向相反方向的:
- 活着的进程在"身份"上胜出。 匹配到清单的前台进程,是"现在正在运行什么"的事实依据。上报的变量是一条来自过去的消息,永远不能覆盖它 —— 因此一个已退出程序留下的变量,无法给之后在该 pane 里运行的东西贴错标签。
- 屏幕在"状态"上胜出。 程序普遍会漏掉"用户按了 Esc"和"提示被取消"这两种转换,而它们最终都表现为屏幕上明显空闲。因此匹配到的屏幕规则的优先级高于上报的状态。
由屏幕推断出的转换 —— 离开 blocked,以及从 working 转为 idle —— 会有约 450 毫秒的去抖,因为一帧画到一半不该触发一次通知重放。通过协议上报的状态则跳过去抖:明确的上报不是猜测。
从你自己的程序上报状态
每当状态变化时,向你的终端写入一条转义序列:
ESC ] 1337 ; SetUserVar=THINKTERM_AGENT=<base64(value)> BEL在 shell 里:
v="v1;agent=my-agent;state=working;session=$SESSION_ID;ts=$(date +%s)"
printf '\033]1337;SetUserVar=THINKTERM_AGENT=%s\007' \
"$(printf %s "$v" | base64 | tr -d '\n')"这条序列不渲染任何内容、不移动光标,因此可以安全地穿插在全屏输出之间。它在 SSH 和 ThinkTerm 多路复用域上都有效 —— 由持有该 pty 的终端负责解析,其值会自动跨 mux 连接镜像。
值的语法,版本 1
v1;agent=<id>;state=<working|idle|blocked>[;session=<id>][;pid=<n>][;ts=<unix-seconds>][;ended=1]| 字段 | 含义 |
|---|---|
v1 | 语法版本。未知主版本会被完全忽略 |
agent | 必填。一个简短稳定的标识符 |
state | 必填。working、idle 或 blocked。其他值视为未知,不驱动任何指示 |
session | 你自己的会话 id,为会话恢复保留。可以为空 |
pid | 为向前兼容而接受;目前忽略 |
ts | 发出时间,unix 秒。见下文 |
ended=1 | 会话已结束 |
未知的键会被忽略,因此这套语法可以在不破坏旧读取方的前提下扩展。
关于 ts。 超过六小时的非 idle 上报不再具有权威性 —— 服务端上的 pane 可能比写入它的会话活得更久 —— 而超前于当前时间五分钟以上的时间戳同样处理,这样一个走快的时钟就无法让一条上报永远保鲜。在那些永远无法观测到进程的 pane 上(SSH、tmux 和串口 pane),这同一个六小时窗口还会让上报的身份过期,因为那是唯一剩下的、能提示该程序可能未道别就崩溃的信号。如果你的会话确实可能长时间保持非 idle —— 比如一个挂了一夜的审批提示 —— 请定期重发当前状态;任何一次重发都会重置该窗口。idle 上报以及不带 ts 的上报会被无限期信任。
关于 ended=1。 只要你的进程仍是该 pane 的前台组长,这个标志就会被忽略:活着的进程优先于它自己的告别。进程退出之后,该 pane 就不再被归类。
什么时候发什么。 一轮开始时发 working;准备好接受输入时发 idle;在你显示出需要作答的提示的那一刻发 blocked;该提示结束时再发相应的状态 —— 包括用户取消或中断的情况。如果你的运行时能自己观测到上述所有转换,那么 ThinkTerm 对你完全不需要屏幕规则。
覆盖某条屏幕规则
把你自己的清单放进下面这个目录,即可替换内置清单:
~/.config/thinkterm/agent-detection/决定替换哪个内置清单的是文件内部的 id,文件名会被忽略。放好之后在 Agents 面板里重新加载规则。
写规则时要知道一件事:标题和进度这两个区域只能看到程序实际发出过的内容。在标题或进度报告到达之前两者都是空的,并且在 pane 的程序发生变化时会被清空。展示层的兜底值 —— 由进程名推导出的标签标题、假定的"无进度" —— 永远不会进入规则。因此像 regex = ['\S'] 这样一条针对标题的规则,无法匹配上一个其程序从未发声的 pane。
相关
- 命令行 ——
cli agent,以及从一个 pane 驱动另一个
