@@ -404,26 +404,68 @@ function queueOutcomeToDeliveryResult(
404404async function sendSubagentAnnounceDirectly ( params : {
405405 targetRequesterSessionKey : string ;
406406 triggerMessage : string ;
407+ completionMessage ?: string ;
408+ expectsCompletionMessage : boolean ;
407409 directIdempotencyKey : string ;
410+ completionDirectOrigin ?: DeliveryContext ;
408411 directOrigin ?: DeliveryContext ;
409412 requesterIsSubagent : boolean ;
410413} ) : Promise < SubagentAnnounceDeliveryResult > {
411414 try {
415+ const completionDirectOrigin = normalizeDeliveryContext ( params . completionDirectOrigin ) ;
416+ const completionChannel =
417+ typeof completionDirectOrigin ?. channel === "string"
418+ ? completionDirectOrigin . channel . trim ( )
419+ : "" ;
420+ const completionTo =
421+ typeof completionDirectOrigin ?. to === "string" ? completionDirectOrigin . to . trim ( ) : "" ;
422+ const completionHasThreadHint =
423+ completionDirectOrigin ?. threadId != null &&
424+ String ( completionDirectOrigin . threadId ) . trim ( ) !== "" ;
425+ const hasCompletionDirectTarget =
426+ ! params . requesterIsSubagent && Boolean ( completionChannel ) && Boolean ( completionTo ) ;
427+
428+ if (
429+ params . expectsCompletionMessage &&
430+ hasCompletionDirectTarget &&
431+ ! completionHasThreadHint &&
432+ params . completionMessage ?. trim ( )
433+ ) {
434+ await callGateway ( {
435+ method : "send" ,
436+ params : {
437+ channel : completionChannel ,
438+ to : completionTo ,
439+ accountId : completionDirectOrigin ?. accountId ,
440+ sessionKey : params . targetRequesterSessionKey ,
441+ message : params . completionMessage ,
442+ idempotencyKey : params . directIdempotencyKey ,
443+ } ,
444+ timeoutMs : 15_000 ,
445+ } ) ;
446+
447+ return {
448+ delivered : true ,
449+ path : "direct" ,
450+ } ;
451+ }
452+
453+ const directOrigin = normalizeDeliveryContext ( params . directOrigin ) ;
454+ const threadId =
455+ directOrigin ?. threadId != null && directOrigin . threadId !== ""
456+ ? String ( directOrigin . threadId )
457+ : undefined ;
458+
412459 await callGateway ( {
413460 method : "agent" ,
414461 params : {
415462 sessionKey : params . targetRequesterSessionKey ,
416463 message : params . triggerMessage ,
417464 deliver : ! params . requesterIsSubagent ,
418- channel : params . requesterIsSubagent ? undefined : params . directOrigin ?. channel ,
419- accountId : params . requesterIsSubagent ? undefined : params . directOrigin ?. accountId ,
420- to : params . requesterIsSubagent ? undefined : params . directOrigin ?. to ,
421- threadId :
422- ! params . requesterIsSubagent &&
423- params . directOrigin ?. threadId != null &&
424- params . directOrigin . threadId !== ""
425- ? String ( params . directOrigin . threadId )
426- : undefined ,
465+ channel : params . requesterIsSubagent ? undefined : directOrigin ?. channel ,
466+ accountId : params . requesterIsSubagent ? undefined : directOrigin ?. accountId ,
467+ to : params . requesterIsSubagent ? undefined : directOrigin ?. to ,
468+ threadId : params . requesterIsSubagent ? undefined : threadId ,
427469 idempotencyKey : params . directIdempotencyKey ,
428470 } ,
429471 expectFinal : true ,
@@ -443,12 +485,14 @@ async function sendSubagentAnnounceDirectly(params: {
443485 }
444486}
445487
446- async function deliverSubagentCompletionAnnouncement ( params : {
488+ async function deliverSubagentAnnouncement ( params : {
447489 requesterSessionKey : string ;
448490 announceId ?: string ;
449491 triggerMessage : string ;
492+ completionMessage ?: string ;
450493 summaryLine ?: string ;
451494 requesterOrigin ?: DeliveryContext ;
495+ completionDirectOrigin ?: DeliveryContext ;
452496 directOrigin ?: DeliveryContext ;
453497 targetRequesterSessionKey : string ;
454498 requesterIsSubagent : boolean ;
@@ -476,7 +520,10 @@ async function deliverSubagentCompletionAnnouncement(params: {
476520 const direct = await sendSubagentAnnounceDirectly ( {
477521 targetRequesterSessionKey : params . targetRequesterSessionKey ,
478522 triggerMessage : params . triggerMessage ,
523+ completionMessage : params . completionMessage ,
524+ expectsCompletionMessage : params . expectsCompletionMessage ,
479525 directIdempotencyKey : params . directIdempotencyKey ,
526+ completionDirectOrigin : params . completionDirectOrigin ,
480527 directOrigin : params . directOrigin ,
481528 requesterIsSubagent : params . requesterIsSubagent ,
482529 } ) ;
@@ -761,6 +808,7 @@ export async function runSubagentAnnounceFlow(params: {
761808 const taskLabel = params . label || params . task || "task" ;
762809 const announceSessionId = childSessionId || "unknown" ;
763810 const findings = reply || "(no output)" ;
811+ let completionMessage = "" ;
764812 let triggerMessage = "" ;
765813
766814 let requesterDepth = getSubagentDepthFromSessionStore ( targetRequesterSessionKey ) ;
@@ -824,39 +872,20 @@ export async function runSubagentAnnounceFlow(params: {
824872 startedAt : params . startedAt ,
825873 endedAt : params . endedAt ,
826874 } ) ;
827- triggerMessage = [
875+ completionMessage = [
828876 `[System Message] [sessionId: ${ announceSessionId } ] A ${ announceType } "${ taskLabel } " just ${ statusLabel } .` ,
829877 "" ,
830878 "Result:" ,
831879 findings ,
832880 "" ,
833881 statsLine ,
834- "" ,
835- replyInstruction ,
836882 ] . join ( "\n" ) ;
883+ triggerMessage = [ completionMessage , "" , replyInstruction ] . join ( "\n" ) ;
837884
838885 const announceId = buildAnnounceIdFromChildRun ( {
839886 childSessionKey : params . childSessionKey ,
840887 childRunId : params . childRunId ,
841888 } ) ;
842- if ( ! expectsCompletionMessage ) {
843- const queued = await maybeQueueSubagentAnnounce ( {
844- requesterSessionKey : targetRequesterSessionKey ,
845- announceId,
846- triggerMessage,
847- summaryLine : taskLabel ,
848- requesterOrigin : targetRequesterOrigin ,
849- } ) ;
850- if ( queued === "steered" ) {
851- didAnnounce = true ;
852- return true ;
853- }
854- if ( queued === "queued" ) {
855- didAnnounce = true ;
856- return true ;
857- }
858- }
859-
860889 // Send to the requester session. For nested subagents this is an internal
861890 // follow-up injection (deliver=false) so the orchestrator receives it.
862891 let directOrigin = targetRequesterOrigin ;
@@ -868,12 +897,14 @@ export async function runSubagentAnnounceFlow(params: {
868897 // catches duplicates if this announce is also queued by the gateway-
869898 // level message queue while the main session is busy (#17122).
870899 const directIdempotencyKey = buildAnnounceIdempotencyKey ( announceId ) ;
871- const delivery = await deliverSubagentCompletionAnnouncement ( {
900+ const delivery = await deliverSubagentAnnouncement ( {
872901 requesterSessionKey : targetRequesterSessionKey ,
873902 announceId,
874903 triggerMessage,
904+ completionMessage,
875905 summaryLine : taskLabel ,
876906 requesterOrigin : targetRequesterOrigin ,
907+ completionDirectOrigin : targetRequesterOrigin ,
877908 directOrigin,
878909 targetRequesterSessionKey,
879910 requesterIsSubagent,
0 commit comments