test(agent-status): harden Antigravity title collision

This commit is contained in:
Brennan Benson
2026-08-19 16:28:38 -07:00
parent 233b2a1100
commit 778a382d3e
3 changed files with 34 additions and 37 deletions
@@ -1,12 +1,13 @@
import { describe, expect, it } from 'vitest'
import { getAgentLabel } from './agent-title-identity'
import { resolveExplicitTerminalTitleAgentType } from './terminal-title-agent-type'
import { GEMINI_IDLE, GEMINI_WORKING } from './agent-title-core'
import {
GEMINI_IDLE,
GEMINI_PERMISSION,
GEMINI_SILENT_WORKING,
GEMINI_WORKING
} from './agent-title-core'
// Why: Antigravity's models are named "Gemini <n.n> <Name>" (see the real `agy models`
// output parsed in commit-message-agent-spec.test.ts), so an agy pane's own title carries a
// whole `gemini` token. Gemini CLI is checked before Antigravity in getAgentLabel, so the
// model name used to win and an agy pane read as Gemini CLI.
describe('agy titles carrying a Gemini model name', () => {
const AGY_TITLES = [
'⠋ agy · Gemini 3.7 Flash · high',
@@ -14,34 +15,38 @@ describe('agy titles carrying a Gemini model name', () => {
'agy · Gemini 3.5 Flash (High)'
]
it.each(AGY_TITLES)('labels %s as Antigravity', (title) => {
it.each(AGY_TITLES)('labels %s as Antigravity on both title paths', (title) => {
expect(getAgentLabel(title)).toBe('Antigravity')
})
// Why: the two chain copies are reached by different surfaces — the sidebar goes through
// getAgentLabel, the tab through resolveExplicitTerminalTitleAgentType. A fix in one only
// moves the disagreement rather than removing it.
it.each(AGY_TITLES)('resolves %s as antigravity on the tab path too', (title) => {
expect(resolveExplicitTerminalTitleAgentType(title)).toBe('antigravity')
})
})
describe('titles that must keep their existing label', () => {
// Why: a real recorded pane title from terminal history. A Grok pane whose TASK TEXT
// contains the token "Antigravity" — it resolves correctly only because grok is checked
// before antigravity, which is why this fix narrows a token instead of reordering.
it('keeps a grok pane whose task text names Antigravity', () => {
expect(getAgentLabel('STA-4011 Linux Antigravity Commit Messages - grok')).toBe('Grok')
it('keeps the recorded Grok pane whose task text names Antigravity', () => {
const title = 'STA-4011 Linux Antigravity Commit Messages - grok'
expect(getAgentLabel(title)).toBe('Grok')
expect(resolveExplicitTerminalTitleAgentType(title)).toBe('grok')
})
// Why: the four Gemini OSC glyphs are decisive and stay so; agy emits none of them.
it('still labels a glyph-bearing Gemini CLI title', () => {
expect(getAgentLabel(`${GEMINI_WORKING} Gemini CLI`)).toBe('Gemini CLI')
expect(getAgentLabel(`${GEMINI_IDLE} Gemini CLI`)).toBe('Gemini CLI')
})
it.each([GEMINI_PERMISSION, GEMINI_WORKING, GEMINI_SILENT_WORKING, GEMINI_IDLE])(
'keeps Gemini glyph %s decisive over an agy token',
(glyph) => {
const title = `${glyph} agy · Gemini 3.7 Flash`
expect(getAgentLabel(title)).toBe('Gemini CLI')
expect(resolveExplicitTerminalTitleAgentType(title)).toBe('gemini')
}
)
// Why: a Gemini CLI title with no agy token must be unaffected by the narrowing.
it('still labels a bare gemini token title', () => {
expect(getAgentLabel('gemini ready')).toBe('Gemini CLI')
expect(resolveExplicitTerminalTitleAgentType('gemini ready')).toBe('gemini')
})
it.each(['agy-workspace · Gemini ready', '/tmp/agy/models · Gemini ready'])(
'does not treat an agy path fragment as Antigravity in %s',
(title) => {
expect(getAgentLabel(title)).toBe('Gemini CLI')
expect(resolveExplicitTerminalTitleAgentType(title)).toBe('gemini')
}
)
})
+3 -7
View File
@@ -67,15 +67,11 @@ export function isGeminiTerminalTitle(title: string): boolean {
if (isPiAgentTitle(title)) {
return false
}
// Why: Antigravity's models are named "Gemini <n.n> <Name>", so an agy pane's own
// title carries a whole `gemini` token. Gemini CLI is checked before Antigravity in
// getAgentLabel, so without this the model name wins and an agy pane reads as Gemini
// CLI. Only the token path defers — the four Gemini OSC glyphs stay decisive, and agy
// emits none of them.
if (titleHasAgentName(title, 'antigravity') || AGY_AGENT_NAME_RE.test(title)) {
if (!titleHasAgentName(title, 'gemini')) {
return false
}
return titleHasAgentName(title, 'gemini')
// Why: agy titles include Gemini model names; the glyph path above stays authoritative.
return !(titleHasAgentName(title, 'antigravity') || AGY_AGENT_NAME_RE.test(title))
}
export function isPiTerminalTitle(title: string): boolean {
+3 -7
View File
@@ -48,15 +48,11 @@ export function isGeminiTerminalTitle(title: string): boolean {
if (isPiAgentTitle(title)) {
return false
}
// Why: Antigravity's models are named "Gemini <n.n> <Name>", so an agy pane's own
// title carries a whole `gemini` token. Gemini CLI is checked before Antigravity in
// getAgentLabel, so without this the model name wins and an agy pane reads as Gemini
// CLI. Only the token path defers — the four Gemini OSC glyphs stay decisive, and agy
// emits none of them.
if (titleHasAgentName(title, 'antigravity') || AGY_AGENT_NAME_RE.test(title)) {
if (!titleHasAgentName(title, 'gemini')) {
return false
}
return titleHasAgentName(title, 'gemini')
// Why: agy titles include Gemini model names; the glyph path above stays authoritative.
return !(titleHasAgentName(title, 'antigravity') || AGY_AGENT_NAME_RE.test(title))
}
// Why: Grok Build's working OSC titles use a fixed frame shape —