/** * Agent Attention Verdict * * Decides, from what an agent's terminal shows, whether the agent is blocked * on a human (an approval prompt, a trust dialog, a plan-mode menu, any * selection dialog) rather than working or idle. See * `specs/2026-09-26-agent-waiting-on-human.md`. * * Pure functions only: the caller supplies the rendered screen text and the * latest OSC terminal title. The rules are pinned by fixture files of real * captured screens in `__fixtures__/agent-screens/`. * * Signals and what each one is worth (verified 2026-09-26 on Claude Code * 2.1.283 and Codex 0.157.1): * - Screen text: the primary signal. A blocking dialog renders a selector * (`❯` / `›`) plus dialog-specific text or a confirm footer. * - OSC title: Codex writes `[ ! ] Action Required | …` while it waits and a * braille spinner while it works, so its title votes. Claude Code writes * `✳ ` in every state, so a Claude title is a label only. * * @module services/monitoring/agent-attention */ /** Overall verdict for one agent at one moment. */ export type AttentionVerdict = 'waiting_on_human' | 'busy' | 'idle'; /** * What the agent is waiting on. * - `permission`: a tool or command approval * - `trust`: a folder / workspace trust dialog * - `plan`: Claude Code's plan-approval menu * - `menu`: some other selection dialog (onboarding, opt-in, …) * - `unspecified`: only the terminal title said so */ export type WaitingKind = 'permission' | 'trust' | 'plan' | 'menu' | 'unspecified'; /** What the OSC terminal title says on its own. */ export type TitleSignal = 'waiting' | 'busy' | 'none'; /** Input to {@link computeAgentAttention}. */ export interface AttentionInput { /** Rendered screen text (ANSI allowed; it is stripped). */ screen: string; /** Latest OSC 0/2 terminal title, if known. */ title?: string | null; } /** Result of {@link computeAgentAttention}. */ export interface AttentionResult { /** The fused verdict. */ verdict: AttentionVerdict; /** Set only when `verdict` is `waiting_on_human`. */ kind?: WaitingKind; /** Names of the rules that fired, for logs and escalation text. */ evidence: string[]; /** Non-empty screen lines the rules examined (0 means nothing was examined). */ linesExamined: number; /** Human-readable task label taken from the title, without status glyphs. */ titleLabel?: string; } /** * Keep the bottom of the screen: the last N non-empty lines. * * Dialogs render at the bottom. Restricting to the bottom region keeps a * dialog that was answered minutes ago (still in scrollback) from counting. * * @param screen - Rendered screen text, ANSI allowed * @returns The bottom non-empty lines, joined with newlines, and their count */ export declare function bottomRegion(screen: string): { text: string; lines: number; }; /** * Read the OSC terminal title. * * @param title - Latest OSC title, or null/undefined when unknown * @returns The title's own signal and its label without status glyphs * * @example * ```typescript * classifyTitle('[ ! ] Action Required | ⠸ | repo'); // { signal: 'waiting', label: 'repo' } * classifyTitle('✳ Fix login bug'); // { signal: 'none', label: 'Fix login bug' } * ``` */ export declare function classifyTitle(title: string | null | undefined): { signal: TitleSignal; label: string; }; /** * Find a blocking dialog at the bottom of the screen. * * @param screen - Rendered screen text, ANSI allowed * @returns The dialog kind (undefined when none), rule evidence, whether a * busy marker is visible, and how many lines were examined */ export declare function detectPromptOnScreen(screen: string): { kind?: WaitingKind; evidence: string[]; busy: boolean; linesExamined: number; }; /** * Fuse screen and title into one attention verdict. * * Precedence: a dialog on screen wins (it is explicit), then a waiting title, * then any busy signal, else idle. * * @param input - Rendered screen and latest title * @returns The verdict with its evidence and the number of lines examined * * @example * ```typescript * const r = computeAgentAttention({ screen: backend.captureOutput(s, 40), title }); * if (r.verdict === 'waiting_on_human') routeToOwner(r.kind); * ``` */ export declare function computeAgentAttention(input: AttentionInput): AttentionResult; //# sourceMappingURL=agent-attention.d.ts.map