Antigravity 就绪性:转录内容说明了什么¶
src/main/runtime/terminal-wait-detection.ts 中的 findAntigravityReadyPromptIndex 决定
Antigravity 面板是否已准备好接受提示。它被重写了五次,每个版本都针对一个五行的屏幕来调优,
该屏幕是从记忆中录入到 .spec.ts 夹具中的。前四个中有三个被发现比它们所替代的 bug 还要糟糕,
第五个被回退了。
现在有了真实的转录记录。它们是在 macOS 上通过实时运行的 agy,使用
agent-pty-transcript-capture.md 记录下来的,并已提交到
src/main/runtime/__fixtures__/ 下。src/main/runtime/antigravity-readiness-transcripts.test.ts
会在运行时环境中重放它们。
要点:捕获到的就绪屏幕需要一条裸光标规则,而且活动中的模型选择器必须否决那个过期的光标。
早期的检测器拒绝了真实的就绪屏幕,却接受了活动中的模型选择器。已发布的第六版规则接受裸输入区光标,
而活动选择器保护机制会阻止保留的光标满足 tui-idle,直到 /model 退出。
版本¶
| 项目 | 值 |
|---|---|
agy --version |
1.1.25 |
| TUI 打印的横幅 | Antigravity CLI 1.2.0 |
| 捕获信息 | 2026-09-10, macOS, 120x40 PTY |
二进制文件与其自身的横幅不一致。任何以版本字符串为关键依据的规则都必须读取横幅,
而不是 --version,并且必须容忍二者不一致。
捕获内容是什么¶
| 夹具 | 说明 |
|---|---|
antigravity-ready-api-key-gemini-model.txt |
就绪屏幕,API 密钥身份,Gemini 3.7 Flash(低) |
antigravity-ready-account-info-hidden.txt |
相同的就绪屏幕,但带有 AGY_CLI_HIDE_ACCOUNT_INFO=1 |
antigravity-dialog-trust-workspace.txt |
工作区信任对话框,活动且未应答 |
antigravity-dialog-model-picker.txt |
/model 选择器,活动且未应答 |
antigravity-dialog-command-palette.txt |
斜杠命令面板,活动且未应答 |
antigravity-dialog-dismissed.txt |
/model 选择器已用 esc 关闭,然后进入稳定状态 |
antigravity-busy-mid-turn.txt |
一次真实轮次,录制在 spinner 仍活动时停止 |
antigravity-busy-turn-ended.txt |
同一轮次结束并返回输入区之后的情况 |
哪些内容无法捕获,以及原因¶
下面没有任何内容是伪造的。每一条都是记录器在无法改变操作者账户状态或配置时无法触达的情况, 而这属于越界行为。
| 缺失项 | 原因 |
|---|---|
antigravity-ready-business-non-gemini.txt |
这台机器没有 OAuth 会话——CLI 会打印 "You are currently not signed in",并使用 GEMINI_API_KEY 进行身份验证。要到达 Business 就绪屏幕,需要登录某个人的账户。 |
| 任何就绪屏幕上的非 Gemini 模型 | agy models 提供 11 个模型,全部是 Gemini,并且 settings.json 将 modelProvider: gemini 固定。从该账户无法触达非 Gemini 行。 |
antigravity-dialog-sign-in.txt |
取消设置 GEMINI_API_KEY 并不会进入登录对话框;CLI 会因为 modelProvider 被固定而拒绝启动。要到达该界面,意味着需要编辑操作者的 settings.json。 |
antigravity-dialog-theme-picker.txt |
在 1.2.0 中没有 /theme 命令(Unknown command: /theme)。该选择器只在首次运行的引导中出现,这意味着需要删除操作者的配置。 |
antigravity-dialog-privacy-notice.txt |
首次运行的引导,同上。 |
antigravity-dialog-update-banner.txt |
无法强制触发;会话期间没有待处理的更新。 |
每一条都仍然作为测试套件中一个命名的、被跳过的用例保留,以便它能被看到,而不是被遗忘。
转录内容说明了什么¶
1. 就绪屏幕的模型行不在行首¶
就绪屏幕在左侧打印一个块状字形 logo,而且身份、模型和路径行被绘制在与 logo 相同的物理行上。 Orca 推导出的内容是:
早期的检测器要求在某行修剪后执行 normalized.startsWith('gemini', trimmedStart)。修剪后的行
以 ▀ 开头,因此该规则从未匹配。已发布的检测器改用裸输入区光标。在真实屏幕上用三种方式测量:
| 输入 | isKnownReadyPromptPreview |
|---|---|
| 真实的就绪屏幕 | true |
| 去除 logo 字形后的同一屏幕 | true |
真实的就绪屏幕后跟活动中的 /model 选择器 |
false |
因此,logo——一种装饰,并可通过 AGY_CLI_HIDE_LOGO 隐藏——不再决定就绪状态,
而且活动中的对话框不能再将过期的输入区光标复用为就绪信号。
2. 用于满足模型规则的对话框¶
/model 每行打印一个选项:
这些行_确实_以 Gemini 开头,并且一条单独的 > composer 行位于同一尾部中更早的位置,来自选择器打开之前。旧规则的两部分都在对话框占据屏幕时得到了满足,于是窗格被判定为就绪。随附的检测器现在能识别活动的 Switch Model 界面,并在看到 Exited /model command 之前拒绝该过时的光标。
3. > 是对话框选中标记,而不仅仅是 composer 光标¶
每个对话框都用 > 标记当前高亮的行:> Yes, I trust this folder、> Gemini 3.7 Flash (current)、> /add-dir。空闲 composer 是一行其完整 trim 后内容为 > 的行。这个区别是唯一能区分二者的东西;这意味着 PRs #15840 和 #15852 提出的放宽方案——接受任何以 > _开头_的行——会让信任对话框和模型选择器被读作就绪。在 1.2.0 上,空闲 composer 就是一个单独的 >;这些 PR 中关于 1.1.17 mode-banner 的说法无法在此复现,可能特定于某种 mode。
4. 没有邮箱账户行,而且该行可以完全关闭¶
对于 API-key 用户,身份行显示的字面内容为 Gemini API key。没有 @,没有域名,没有任何可供 account-row 规则依据的东西。另外,AGY_CLI_HIDE_ACCOUNT_INFO=1——二进制中受支持的环境变量——会从完全就绪的屏幕中移除该行,antigravity-ready-account-info-hidden.txt 捕获的正是这种情况。
5. 对话框有两种绘制方式,而且 banner 永远不会被重新打印¶
信任对话框和登录启动画面使用备用屏幕(ESC[?1049h … ESC[?1049l)。模型选择器和命令面板则使用 erase-to-EOL 在主屏幕上原地绘制。关闭后,CLI 会打印 ⎿ Exited /model command 并重绘 composer——它不会重新打印 banner。头部区域保持在启动时的位置。
6. 行通过光标寻址定位,而不是换行符¶
状态行是通过绝对和相对移动(ESC[13;99H、ESC[83X ESC[83C)写入的,因此 ? for shortcuts 和 Gemini 3.7 Flash · low 最终落在同一条派生行上。任何假设一个屏幕行等于一个以 \n 分隔的行的规则,所读取的文档都与用户看到的不是同一个。
8. 忙碌帧与空闲帧完全一样地停放光标——区别在于 spinner¶
结束进行中 turn 的帧与结束空闲屏幕的帧,会用相同的字节停放光标。只有提示行不同,而 park 会擦除它:
idle: ? for shortcuts ESC[83X ESC[83C Gemini 3.7 Flash · low CR ESC[2A ESC[2C ESC[?25h
busy: esc to cancel ESC[85X ESC[85C Gemini 3.7 Flash · low CR ESC[2A ESC[2C ESC[?25h
因此,一条以“光标是尾部中最后的东西”为关键的规则,仅凭帧本身无法区分忙碌与空闲。能挽回这一点的是接下来发生的内容。每个 spinner tick 都是自己的一次重绘,并带有自己的 park,位置比帧的 park 高两行:
第二个 CR ESC[2A 会把 composer 行裁剪掉,因此实时 turn 期间的保留尾部结束于 spinner 行,而不是光标。在 antigravity-busy-mid-turn.txt 上测得:
| 捕获 | 最后保留的行 | 是否存在单独的 > 行 |
|---|---|---|
antigravity-ready-api-key-gemini-model.txt |
> |
是 |
antigravity-busy-mid-turn.txt |
⣟ Generating... |
否 |
对基于光标的规则而言的后果: 对于真实的 turn 中途捕获,它已经会回答“未就绪”,因为尾部并没有一个单独的光标可供匹配。一个保留 park 字节、只修改状态文本的人造输入,并不能真实反映实时 turn——实时 turn 中有一个 spinner 行在 composer _下方_不断重绘。
残余窗口及其蕴含的判定条款。 在帧的 park 与下一个 spinner tick 之间,尾部确实会结束于单独的光标,并且与空闲状态无法区分。这个间隙正好是一个 tick 间隔。任何以持续静默为门槛的就绪判定路径都是安全的,因为 tick 会持续到来,窗格从不安静;而只检查保留文本的路径则不安全。对于这些路径,证据支持且仅支持一个判定条款:
保留尾部的最后可见行上出现一个盲文字形(U+2800–U+28FF)表示正在工作。
该谓词已存在于本文件中,用于 cursor-agent(CURSOR_BUSY_SPINNER_RE),应复用而不是重新发明。它必须限定为最后可见行,而不是整个尾部:首次运行的记录会在启动期间打印 ⠾ Signing in...,否则它会把就绪屏幕永久钉在忙碌状态。
捕获中没有任何其他内容能区分这两种状态。提示行(esc to cancel 与 ? for shortcuts)在两种情况下都会被 park 擦除,park 的偏移完全相同,而且每次重绘(无论空闲还是忙碌)周围都会出现 ESC[?25l/ESC[?25h 包裹。
已确认 / 已否定,按尝试分组¶
证据列指明 fixture;所有引用文本均来自已提交的 transcript 文件。
尝试 1——HEAD 上的规则¶
| # | 论断 | 判定 | 证据 |
|---|---|---|---|
| 1.1 | 就绪屏幕会打印横幅 Antigravity CLI |
已确认 | 两个就绪 fixture 中均出现 Antigravity CLI 1.2.0 |
| 1.1b | ……并且其最后一次出现在尾部的那一次才是有效的 | 证伪 | 信任对话框自身的正文写着_“Antigravity CLI 需要读取、编辑和执行此处的文件的权限”_, 因此 lastIndexOf 落在对话框内部 |
| 1.2 | 模型行以厂商单词 Gemini 开头 |
证伪 | ▀▀▀▀▀▀▀▀ Gemini 3.7 Flash (Low) — 徽标位于其之前;从未出现在行首 |
| 1.3 | 光标行去除首尾空白后的全部内容是 > |
已确认(1.2.0 空闲状态) | 两个就绪测试样例中各有一个单独的 > |
| 1.3b | ……并且只有 composer(输入区)会打印 > |
证伪 | > Yes, I trust this folder, > Gemini 3.7 Flash (current), > /add-dir |
| 1.4 | 就绪屏幕会将工作区路径单独打印在一行上 | 证伪 | 该路径与徽标字形共享同一行(▄▀▀ ▀▀▄ ~) |
尝试 2(循环 1)——屏蔽模型行¶
| # | 主张 | 判定 | 证据 |
|---|---|---|---|
| 2.1 | 对话框模型行的措辞是可枚举的 | 证伪 | 命令面板列出了 50 多个带自由格式描述的命令;选择器会打印账户提供的任意模型 |
| 2.2 | 对话框永远不会复现真实的模型行 | 证伪 | /model 选择器会打印四行真实的模型行,每行一个,且位于行首 |
尝试 3(循环 2)——基于 headerIndex 的结构排序¶
| # | 主张 | 判定 | 证据 |
|---|---|---|---|
| 3.1 | 活动对话框会打印在就绪界面下方 | 已确认(针对就地对话框) | 选择器和命令面板会追加在 composer(输入区)下方 |
| 3.2 | 对话框关闭时会重新打印横幅 | 证伪 | antigravity-dialog-dismissed.txt 显示 ⎿ Exited /model command 和一个重绘后的 composer(输入区),没有横幅 |
| 3.3 | Antigravity 不使用备用屏幕 | 证伪 | ESC[?1049h 会打开信任对话框和登录闪屏 |
| 3.4 | 每次按键不会进行全量重绘 | 部分证伪 | 输入 /mod 时,每次按键都会用 ESC[K 重绘命令面板区域 |
由于 3.2,headerIndex 无法作为锚点:它永远不会前进。排序只能相对于模型/光标位置来表达,而这正是 1.2 和 1.3b 刚刚推翻的。
尝试 4(循环 3)——要求存在一个正向的账户行¶
| # | 主张 | 判定 | 证据 |
|---|---|---|---|
| 4.1 | 每个就绪屏幕都会打印一个账户行 | 证伪(两次) | API 密钥身份会打印 Gemini API key(没有 @);AGY_CLI_HIDE_ACCOUNT_INFO=1 会完全移除该行 |
| 4.2 | 启动对话框永远不会包含同时带有 @ 和 . 的 token |
此处无法验证 | 捕获到的对话框中没有一个包含这样的 token,但命令面板会显示自由格式的技能描述,这些是用户编写的文本 |
| 4.3 | 账户行可与普通文本区分开来 | 证伪 | 该行并不是独立的行;它与徽标共享同一行 |
尝试 5(PR #19749,已回滚)——排序 + 账户行¶
| # | 主张 | 判定 | 证据 |
|---|---|---|---|
| 5.1 | 排序加上账户行可以将就绪屏幕与对话框区分开 | 证伪 | 账户行是可选的(4.1),并且排序锚点永远不会移动(3.2) |
| # | 声明 | 判定 | 证据 |
|---|---|---|---|
| 5.2 | 执行两个构建就足以验证 | 已反驳 | 所执行的输入是手写测试夹具,因此该检查复现了测试夹具的假设。真实屏幕在该夹具的模型行、路径行和账户行上与其不一致 |
| 5.3 | 该卡点是模型名称问题 | 已反驳 | 它是行首问题。即使是 Gemini 3.7 Flash (Low) —— 一个 Gemini 模型 —— 也会失败,因为它前面有一个标志字形 |
横切¶
| # | 问题 | 答案 |
|---|---|---|
| X1 | agy 是否设置区分忙碌和空闲的 OSC 标题? |
否。 任何捕获中都没有出现任何 OSC 标题序列。基于标题的就绪状态对该代理不可用 |
| X2 | 它是否使用裸 \r 重绘? |
是,持续地,并且还有 ESC[K 和绝对光标移动 |
| X3 | 光标是否保留在尾部? | 是 —— 每个就绪捕获中都有一个裸 > 行 |
| X4 | 横幅到光标的距离 | 在 120x40 PTY 上约 8 行派生行;横幅落在 6 行预览窗口之外,因此只有完整保留的尾部才能看到它 |
| X5 | 信任屏幕与就绪屏幕上的窗格标题 | 相同:无 |
第六次尝试已发布¶
是的 —— 但它不是前五种中任何一种的变体。它们中的每一种都细化了一个针对以
\n 分隔的行的谓词,而证据表明信息并不在那一层。
捕获所支持的内容以及已发布检测器现在所做的:
- 唯一稳定的、无对话框的就绪标记是一行,其整个修剪后的内容为
>。 它 存在于每个就绪捕获中,并且不存在于任何对话框捕获中,因为对话框中的>总是 携带其选中行的标签。这比任何一次尝试使用的规则都更窄,也是 唯一在与转录文本接触后幸存下来的规则。 - 去掉模型行要求。 模型行匹配的是对话框,而不是就绪屏幕,因此 保留该要求会使检测器判断反转。
- 不要要求账户行。 它由环境变量可选,并且对 API 密钥用户不携带电子邮件。
- 否决一个活动的模型选择器。
Switch Model后跟一个带标签的选择行,意味着 裸光标属于选择器后面的编辑器;就绪状态在Exited /model command之后恢复。 - 不要锚定在
headerIndex上。 横幅只打印一次,并且从不重新打印。 - 被阻止的信号路径已经有效 用于信任对话框:
antigravity-dialog-trust-workspace.txt今天被正确拒绝,依据的是措辞,而不是结构。
仍然未知且应当捕获的是:登录、主题、隐私和更新对话框,以及 任何编辑器未处于空闲状态的就绪屏幕(accept-edits 和 plan mode,PRs #15840 和
15852 从截图中描述了它们)。裸 > 规则的好坏仅取决于这样的声明:这些模式¶
仍然以裸 > 结束;该声明尚未测试。
诚实的总结是,这是一个屏幕形状的问题,却正在用行形状的工具解决。 针对派生尾部的规则可以做得比今天发布的版本好得多,但持久的修复方法是 询问终端模拟器屏幕底部一行实际是什么,而不是从用光标寻址写入的字节流中推断它。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 orca48/orca