(
permissionMode?: string,
signal?: AbortSignal,
timeoutMs: number = TOOL_HOOK_EXECUTION_TIMEOUT_MS,
stopHookActive: boolean = false,
subagentId?: AgentId,
toolUseContext?: ToolUseContext,
messages?: Message[],
agentType?: string,
requestPrompt?: (
sourceName: string,
toolInputSummary?: string | null,
) => (request: PromptRequest) => Promise<PromptResponse>,
)
| 3789 | * @returns Async generator that yields progress messages and blocking errors |
| 3790 | */ |
| 3791 | export async function* executeStopHooks( |
| 3792 | permissionMode?: string, |
| 3793 | signal?: AbortSignal, |
| 3794 | timeoutMs: number = TOOL_HOOK_EXECUTION_TIMEOUT_MS, |
| 3795 | stopHookActive: boolean = false, |
| 3796 | subagentId?: AgentId, |
| 3797 | toolUseContext?: ToolUseContext, |
| 3798 | messages?: Message[], |
| 3799 | agentType?: string, |
| 3800 | requestPrompt?: ( |
| 3801 | sourceName: string, |
| 3802 | toolInputSummary?: string | null, |
| 3803 | ) => (request: PromptRequest) => Promise<PromptResponse>, |
| 3804 | ): AsyncGenerator<AggregatedHookResult> { |
| 3805 | const hookEvent = subagentId ? 'SubagentStop' : 'Stop' |
| 3806 | const appState = toolUseContext?.getAppState() |
| 3807 | const sessionId = toolUseContext?.agentId ?? getSessionId() |
| 3808 | if (!hasHookForEvent(hookEvent, appState, sessionId)) { |
| 3809 | return |
| 3810 | } |
| 3811 | |
| 3812 | // Extract text content from the last assistant message so hooks can |
| 3813 | // inspect the final response without reading the transcript file. |
| 3814 | const lastAssistantMessage = messages |
| 3815 | ? getLastAssistantMessage(messages) |
| 3816 | : undefined |
| 3817 | const lastAssistantContent = lastAssistantMessage?.message?.content |
| 3818 | const lastAssistantText = lastAssistantMessage |
| 3819 | ? (Array.isArray(lastAssistantContent) |
| 3820 | ? extractTextContent( |
| 3821 | lastAssistantContent as readonly { readonly type: string }[], |
| 3822 | '\n', |
| 3823 | ).trim() |
| 3824 | : typeof lastAssistantContent === 'string' |
| 3825 | ? lastAssistantContent.trim() |
| 3826 | : '') || undefined |
| 3827 | : undefined |
| 3828 | |
| 3829 | const hookInput: StopHookInput | SubagentStopHookInput = subagentId |
| 3830 | ? { |
| 3831 | ...createBaseHookInput(permissionMode), |
| 3832 | hook_event_name: 'SubagentStop', |
| 3833 | stop_hook_active: stopHookActive, |
| 3834 | agent_id: subagentId, |
| 3835 | agent_transcript_path: getAgentTranscriptPath(subagentId), |
| 3836 | agent_type: agentType ?? '', |
| 3837 | last_assistant_message: lastAssistantText, |
| 3838 | } |
| 3839 | : { |
| 3840 | ...createBaseHookInput(permissionMode), |
| 3841 | hook_event_name: 'Stop', |
| 3842 | stop_hook_active: stopHookActive, |
| 3843 | last_assistant_message: lastAssistantText, |
| 3844 | } |
| 3845 | |
| 3846 | // Trust check is now centralized in executeHooks() |
| 3847 | yield* executeHooks({ |
| 3848 | hookInput, |
no test coverage detected