Show Codex model capacity failures as red agent status (#28231)

* Show Codex model capacity failures in agent status

* Reduce Codex capacity detection work on terminal output

* Preserve Codex capacity notices across partial terminal frames
This commit is contained in:
Neil
2026-10-13 01:58:00 -07:00
committed by GitHub
parent 4559c250b3
commit 9e52645e6c
15 changed files with 805 additions and 10 deletions
@@ -1,4 +1,4 @@
import type { ParsedAgentStatusPayload } from './agent-status-types'
import { mainAgentStatusEqual, type ParsedAgentStatusPayload } from './agent-status-types'
/** Whether a terminal status is the same hook status with only hook-owned metadata omitted.
*
@@ -13,6 +13,8 @@ export function terminalStatusPayloadMatchesHook(
// OSC never carries model/children; compare only fields its protocol owns.
return (
cachedHookPayload.state === terminalPayload.state &&
(terminalPayload.mainAgent === undefined ||
mainAgentStatusEqual(cachedHookPayload.mainAgent, terminalPayload.mainAgent)) &&
// OSC never carries workingMode either; only a stated mismatch breaks equivalence.
(terminalPayload.workingMode === undefined ||
cachedHookPayload.workingMode === terminalPayload.workingMode) &&
+51
View File
@@ -0,0 +1,51 @@
import { describe, expect, it, vi } from 'vitest'
import { CODEX_CAPACITY_MESSAGE, CodexCapacityNoticeTracker } from './codex-capacity-notice'
describe('Codex capacity candidate bounds', () => {
it('reads neither the screen nor its mode during ordinary output', () => {
const tracker = new CodexCapacityNoticeTracker()
const readScreen = vi.fn(() => [])
const readSynchronized = vi.fn(() => false)
tracker.observe('ordinary output'.repeat(1000), readScreen, readSynchronized)
expect(readScreen).not.toHaveBeenCalled()
expect(readSynchronized).not.toHaveBeenCalled()
})
it('does not inspect a partial synchronized frame with combined ANSI modes', () => {
const tracker = new CodexCapacityNoticeTracker()
const readScreen = vi.fn(() => [`■ ${CODEX_CAPACITY_MESSAGE}`, '›'])
expect(tracker.observe(`\x1b[?25;2026h■ ${CODEX_CAPACITY_MESSAGE}`, readScreen)).toBe(false)
expect(readScreen).not.toHaveBeenCalled()
expect(tracker.observe('\x1b[?2026;25l', readScreen)).toBe(true)
expect(readScreen).toHaveBeenCalledTimes(1)
})
it('ignores repeated unrelated markers and still accepts a later native notice', () => {
const tracker = new CodexCapacityNoticeTracker()
const readScreen = vi.fn(() => [`■ ${CODEX_CAPACITY_MESSAGE}`, '›'])
expect(tracker.observe('■'.repeat(100_000), readScreen)).toBe(false)
expect(readScreen).not.toHaveBeenCalled()
expect(tracker.observe(`■ ${CODEX_CAPACITY_MESSAGE}`, readScreen)).toBe(true)
expect(readScreen).toHaveBeenCalledTimes(1)
})
it('finds the notice inside a large text chunk after unrelated warning markers', () => {
const tracker = new CodexCapacityNoticeTracker()
const readScreen = vi.fn(() => [`■ ${CODEX_CAPACITY_MESSAGE}`, '›'])
expect(
tracker.observe(
`⚠ unrelated\n${'x'.repeat(1024 * 1024)}\n■ ${CODEX_CAPACITY_MESSAGE}`,
readScreen
)
).toBe(true)
expect(readScreen).toHaveBeenCalledTimes(1)
})
it('recognizes a split notice immediately after abandoning an unrelated warning', () => {
const tracker = new CodexCapacityNoticeTracker()
const readScreen = vi.fn(() => [`⚠ ${CODEX_CAPACITY_MESSAGE}`, '›'])
expect(tracker.observe('⚠ 1 warning · f2 to view', readScreen)).toBe(false)
expect(readScreen).not.toHaveBeenCalled()
expect(tracker.observe('⚠ Selected model is ', readScreen)).toBe(false)
expect(tracker.observe('at capacity. Please try a different model.', readScreen)).toBe(true)
expect(tracker.observe('ordinary output'.repeat(100_000), readScreen)).toBe(false)
expect(readScreen).toHaveBeenCalledTimes(1)
})
})
+87
View File
@@ -0,0 +1,87 @@
import { createTerminalEscapeScanner } from './terminal-escape-scanner'
export const CODEX_CAPACITY_MESSAGE = 'Selected model is at capacity. Please try a different model.'
const NOTICE = /^[■⚠]\s+Selected model is at capacity\. Please try a different model\.$/
const MAX_NOTICE_LENGTH = 160
/** Only a newly painted native notice at the end of the conversation can close a turn. */
export class CodexCapacityNoticeTracker {
private tail = ''
private pending = false
private synchronized = false
private readonly scanner = createTerminalEscapeScanner({
onCsi: (marker, params, final) => {
if (
marker === '?' &&
params.split(';').includes('2026') &&
(final === 'h' || final === 'l')
) {
this.synchronized = final === 'h'
} else if ((final === 'H' || final === 'f') && this.tail && !this.tail.endsWith(' ')) {
this.tail += ' '
}
},
onText: (text) => this.observeText(text)
})
private observeText(text: string): void {
if (this.tail) {
this.updateCandidate(this.tail + text.slice(0, MAX_NOTICE_LENGTH))
}
let error = text.indexOf('■')
let warning = text.indexOf('⚠')
while (error !== -1 || warning !== -1) {
const start = error === -1 ? warning : warning === -1 ? error : Math.min(error, warning)
this.updateCandidate(text.slice(start, start + MAX_NOTICE_LENGTH))
if (start === error) {
error = text.indexOf('■', start + 1)
} else {
warning = text.indexOf('⚠', start + 1)
}
}
}
private updateCandidate(text: string): void {
const content = text.slice(1).trimStart()
if (content && content[0] !== CODEX_CAPACITY_MESSAGE[0]) {
this.tail = ''
return
}
const candidate = text.replace(/\s+/g, ' ')
const message = candidate.slice(1).trimStart()
if (message.startsWith(CODEX_CAPACITY_MESSAGE)) {
this.pending = true
this.tail = ''
} else {
this.tail = CODEX_CAPACITY_MESSAGE.startsWith(message) ? candidate : ''
}
}
observe(
data: string,
readScreen: () => readonly string[],
readSynchronized?: () => boolean
): boolean {
this.scanner.observe(data)
if (!this.pending || (readSynchronized?.() ?? this.synchronized)) {
return false
}
this.pending = false
this.tail = ''
const lines = readScreen()
const composer = lines.findLastIndex((line) => /^\s*›/.test(line))
if (composer === -1) {
return false
}
const above = lines.slice(0, composer).filter((line) => line.trim() !== '')
let notice = ''
for (let index = above.length - 1; index >= 0 && notice.length < MAX_NOTICE_LENGTH; index--) {
notice = `${above[index].trim()} ${notice}`.trim()
if (NOTICE.test(notice)) {
return true
}
}
return false
}
}