From 3cd84bef0a9ad516dfa0cfd25f8c6089ca4c8526 Mon Sep 17 00:00:00 2001 From: Merge Sim Date: Wed, 2 Sep 2026 20:03:06 -0700 Subject: [PATCH] fix(agents): restore title classifier memoization --- src/shared/terminal-title-agent-type.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/shared/terminal-title-agent-type.ts b/src/shared/terminal-title-agent-type.ts index f27c1af2a51..25a955b3954 100644 --- a/src/shared/terminal-title-agent-type.ts +++ b/src/shared/terminal-title-agent-type.ts @@ -11,6 +11,7 @@ import { isLegacyPiCompatibleTitle } from './pi-compatible-synthetic-title' import { resolveCanonicalPaneAgentIdentity } from './pane-agent-identity-adapter' +import { memoizeTitleClassification } from './terminal-title-classification-memo' import type { TuiAgent } from './tui-agent' export const CLAUDE_IDLE = '\u2733' // ✳ (eight-spoked asterisk — Claude Code idle prefix) @@ -85,7 +86,7 @@ export function isPiAgentTitle(title: string): boolean { * Used to scope prompt-cache-timer behavior to Claude sessions only — other * agents have different (or no) caching semantics. */ -export function isClaudeAgent(title: string): boolean { +function computeIsClaudeAgent(title: string): boolean { if (!title || isClaudeManagementTitle(title) || isOpenCodeNativeTitle(title)) { return false } @@ -122,11 +123,15 @@ export function isClaudeAgent(title: string): boolean { return false } +/** Pure in `title` — memoized so repeated selector reads skip the regex ladder. */ +export const isClaudeAgent: (title: string) => boolean = + memoizeTitleClassification(computeIsClaudeAgent) + export function isClaudeManagementTitle(title: string): boolean { return CLAUDE_MANAGEMENT_TITLE_RE.test(title) } -export function getAgentLabel(title: string): string | null { +function computeAgentLabel(title: string): string | null { if (isClaudeManagementTitle(title)) { return null } @@ -213,6 +218,10 @@ export function getAgentLabel(title: string): string | null { return null } +/** Pure in `title` — memoized so repeated selector reads skip the regex ladder. */ +export const getAgentLabel: (title: string) => string | null = + memoizeTitleClassification(computeAgentLabel) + const TITLE_LABEL_TO_AGENT: Partial> = { 'Claude Code': 'claude', OpenClaude: 'openclaude', @@ -267,10 +276,14 @@ export function resolveTerminalTitleAgentType(title: string): TuiAgent | null { * that something is running, not proof the agent is Claude — so a task or * worktree title cannot become Claude without an explicit "Claude Code" name. */ -export function resolveExplicitTerminalTitleAgentType(title: string): TuiAgent | null { +function computeExplicitTerminalTitleAgentType(title: string): TuiAgent | null { const titleAgent = resolveTerminalTitleAgentType(title) if (isGenericClaudeStatusClaim(title, titleAgent)) { return null } return titleAgent } + +/** Pure in `title` — memoized so repeated selector reads skip the canonical/title parse. */ +export const resolveExplicitTerminalTitleAgentType: (title: string) => TuiAgent | null = + memoizeTitleClassification(computeExplicitTerminalTitleAgentType)