( lastMessage: AssistantMessage, toolUseContext?: ToolUseContext, timeoutMs: number = TOOL_HOOK_EXECUTION_TIMEOUT_MS, )
| 3678 | } |
| 3679 | |
| 3680 | export async function executeStopFailureHooks( |
| 3681 | lastMessage: AssistantMessage, |
| 3682 | toolUseContext?: ToolUseContext, |
| 3683 | timeoutMs: number = TOOL_HOOK_EXECUTION_TIMEOUT_MS, |
| 3684 | ): Promise<void> { |
| 3685 | const appState = toolUseContext?.getAppState() |
| 3686 | // executeHooksOutsideREPL hardcodes main sessionId (:2738). Agent frontmatter |
| 3687 | // hooks (registerFrontmatterHooks) key by agentId; gating with agentId here |
| 3688 | // would pass the gate but fail execution. Align gate with execution. |
| 3689 | const sessionId = getSessionId() |
| 3690 | if (!hasHookForEvent('StopFailure', appState, sessionId)) return |
| 3691 | |
| 3692 | const rawContent = lastMessage.message?.content |
| 3693 | const lastAssistantText = |
| 3694 | (Array.isArray(rawContent) |
| 3695 | ? extractTextContent(rawContent as readonly { readonly type: string }[], '\n').trim() |
| 3696 | : typeof rawContent === 'string' |
| 3697 | ? rawContent.trim() |
| 3698 | : '') || undefined |
| 3699 | |
| 3700 | // Some createAssistantAPIErrorMessage call sites omit `error` (e.g. |
| 3701 | // image-size at errors.ts:431). Default to 'unknown' so matcher filtering |
| 3702 | // at getMatchingHooks:1525 always applies. |
| 3703 | const error = (lastMessage.error as string | undefined) ?? 'unknown' |
| 3704 | const hookInput: StopFailureHookInput = { |
| 3705 | ...createBaseHookInput(undefined, undefined, toolUseContext), |
| 3706 | hook_event_name: 'StopFailure', |
| 3707 | error, |
| 3708 | error_details: lastMessage.errorDetails, |
| 3709 | last_assistant_message: lastAssistantText, |
| 3710 | } |
| 3711 | |
| 3712 | await executeHooksOutsideREPL({ |
| 3713 | getAppState: toolUseContext?.getAppState, |
| 3714 | hookInput, |
| 3715 | timeoutMs, |
| 3716 | matchQuery: error, |
| 3717 | }) |
| 3718 | } |
| 3719 | |
| 3720 | /** |
| 3721 | * Execute stop hooks if configured |
no test coverage detected