fix(runtime): hold an agy composer whose draft reads like an edit mode (#39296)

A draft such as `dark mode: fix the toggle`, or agy's plan placeholder typed
verbatim, matches the composer caret row's edit-mode alternative. agy hides
`? for shortcuts` while the composer holds text, so composer_ready refused,
but composer_ready_custom_status_line (#38930) took agy's own
`[mode · ]model · effort` footer for a custom status row and answered idle.
Orca would then paste into the operator's unsent text.

Status rows may no longer be agy's built-in footer. The captured agy 1.2.7
screen of the plan placeholder typed as a draft comes from #23402.

Split from #23402.

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
This commit is contained in:
Neil
2026-11-06 21:21:39 -08:00
committed by GitHub
co-authored by seonghobae
parent e956b1902e
commit 0fd39beedf
4 changed files with 53 additions and 4 deletions
@@ -0,0 +1,9 @@
{
"capturedAt": "2026-09-19T07:34:50.080Z",
"platform": "darwin",
"command": ["agy", "--mode", "plan"],
"cols": 120,
"rows": 40,
"note": "Plan mode; exact placeholder wording typed as an unsent draft at 12 seconds",
"exitCode": 0
}
@@ -0,0 +1,13 @@
_Ga=q,f=32,s=1,v=1,i=31;AAAAAA==\[?2026$p[?2027$p[?5W[?2004h[>4;2m[>1u[?u[0 q␍
▄▀▀▄ Antigravity CLI 1.2.7
▀▀▀▀▀▀ Gemini API key
▀▀▀▀▀▀▀▀ Gemini 3.7 Flash (Low)
▄▀▀ ▀▀▄ ~/orca/workspaces/orca/agy-gemini-issues
▄▀▀ ▀▀▄
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
> Plan mode: research & plan only (shift+tab to cycle)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
? for shortcutsplan · Gemini 3.7 Flash · low␍[?25h[?25lPlan
 p[?25h[?25lmode: re[?25h[?25lsearch[?25h[?25l& plan[?25h[?25l only (s[?25h[?25lhift+ta[?25h[?25lb to cy[?25h[?25lcle)[?25h
@@ -0,0 +1,24 @@
import { describe, expect, it } from 'vitest'
import { finalReplayFrame } from '../agent-transcript-replay-test-harness'
import { evaluateAgentStateRules } from './agent-state-rules-engine'
const verdict = (lines: readonly string[]) =>
evaluateAgentStateRules('antigravity', { readScreenLines: () => lines })?.state
describe('an Antigravity composer holding a mode-shaped draft', () => {
it('holds when agy 1.2.7 shows the plan placeholder typed as unsent text', async () => {
const { ruledScreenLines } = await finalReplayFrame(
'antigravity-plan-hint-as-draft-127',
120,
40
)
expect(verdict(ruledScreenLines)).toBe('hold')
})
it('holds for a draft that only reads like an edit mode', () => {
const rule = '─'.repeat(40)
expect(verdict([rule, '> dark mode: fix the toggle', rule, 'Gemini 3.7 Flash · low'])).toBe(
'hold'
)
})
})
@@ -28,7 +28,7 @@
},
{
"id": "composer_ready_custom_status_line",
"why": "A custom statusLine paints its own rows where the hint row was, so `esc to cancel` never shows. agy 1.5.2 then marks a turn only with a braille spinner row right above the composer. Status rows may hold no rule run, hint or busy hint, so hint-row layouts and garbled grids cannot match, and pickers drawn between the composer and the status rows break the run of rows.",
"why": "A custom statusLine replaces the hint row, so `esc to cancel` never shows; agy 1.5.2 then marks a turn only with a braille spinner row above the composer. Status rows may not hold a rule run, a hint, or agy's own `[mode · ]model · effort` footer, which drops its hint while the composer holds a draft. Pickers between the composer and status rows break the run. A custom row shaped like that footer holds; a mode-shaped draft above a custom statusLine still reads idle.",
"priority": 400,
"when": {
"region": "screen",
@@ -41,7 +41,8 @@
"optional": {
"none": [
{ "regex": "──" },
{ "regex": "esc to cancel|for shortcuts", "ignoreCase": true }
{ "regex": "esc to cancel|for shortcuts", "ignoreCase": true },
{ "regex": "^(?:[a-z][a-z-]* · )?[^·]+ · (?:low|medium|high)$" }
]
}
},
@@ -49,14 +50,16 @@
"optional": {
"none": [
{ "regex": "──" },
{ "regex": "esc to cancel|for shortcuts", "ignoreCase": true }
{ "regex": "esc to cancel|for shortcuts", "ignoreCase": true },
{ "regex": "^(?:[a-z][a-z-]* · )?[^·]+ · (?:low|medium|high)$" }
]
}
},
{
"none": [
{ "regex": "──" },
{ "regex": "esc to cancel|for shortcuts", "ignoreCase": true }
{ "regex": "esc to cancel|for shortcuts", "ignoreCase": true },
{ "regex": "^(?:[a-z][a-z-]* · )?[^·]+ · (?:low|medium|high)$" }
]
}
]