@@ -289,6 +289,23 @@ export const sseHandlers: Record<string, SSEHandler> = {
289289 markToolResultSeen ( toolCall . id )
290290 return
291291 }
292+
293+ // Decision was null — timed out or aborted.
294+ // Do NOT fall through to auto-execute. Mark the tool as timed out
295+ // and notify Go so it can unblock waitForExternalTool.
296+ toolCall . status = 'rejected'
297+ toolCall . endTime = Date . now ( )
298+ markToolComplete ( toolCall . id , toolCall . name , 408 , 'Tool approval timed out' , {
299+ skipped : true ,
300+ reason : 'timeout' ,
301+ } ) . catch ( ( err ) => {
302+ logger . error ( 'markToolComplete fire-and-forget failed (timeout)' , {
303+ toolCallId : toolCall . id ,
304+ error : err instanceof Error ? err . message : String ( err ) ,
305+ } )
306+ } )
307+ markToolResultSeen ( toolCall . id )
308+ return
292309 }
293310
294311 if ( options . autoExecuteTools !== false ) {
@@ -431,9 +448,10 @@ export const subAgentHandlers: Record<string, SSEHandler> = {
431448 return
432449 }
433450
434- // Integration tools (user-installed) require approval in interactive mode,
435- // same as top-level interrupt tools.
436- if ( options . interactive === true && isIntegrationTool ( toolName ) ) {
451+ // Interrupt tools and integration tools (user-installed) require approval
452+ // in interactive mode, same as top-level handler.
453+ const needsSubagentApproval = isInterruptToolName ( toolName ) || isIntegrationTool ( toolName )
454+ if ( options . interactive === true && needsSubagentApproval ) {
437455 const decision = await waitForToolDecision (
438456 toolCallId ,
439457 options . timeout || STREAM_TIMEOUT_MS ,
@@ -481,6 +499,22 @@ export const subAgentHandlers: Record<string, SSEHandler> = {
481499 markToolResultSeen ( toolCall . id )
482500 return
483501 }
502+
503+ // Decision was null — timed out or aborted.
504+ // Do NOT fall through to auto-execute.
505+ toolCall . status = 'rejected'
506+ toolCall . endTime = Date . now ( )
507+ markToolComplete ( toolCall . id , toolCall . name , 408 , 'Tool approval timed out' , {
508+ skipped : true ,
509+ reason : 'timeout' ,
510+ } ) . catch ( ( err ) => {
511+ logger . error ( 'markToolComplete fire-and-forget failed (subagent timeout)' , {
512+ toolCallId : toolCall . id ,
513+ error : err instanceof Error ? err . message : String ( err ) ,
514+ } )
515+ } )
516+ markToolResultSeen ( toolCall . id )
517+ return
484518 }
485519
486520 // Client-executable run tools in interactive mode: defer to client.
0 commit comments