@@ -3696,6 +3696,69 @@ describe("gateway agent handler chat.abort integration", () => {
36963696 } ) ;
36973697 } ) ;
36983698
3699+ it ( "preserves stop-command reason when /stop lands during the accepted ack yield" , async ( ) => {
3700+ prime ( ) ;
3701+ mocks . agentCommand . mockReturnValueOnce ( new Promise ( ( ) => { } ) ) ;
3702+
3703+ const context = makeContext ( ) ;
3704+ const respond = vi . fn ( ) ;
3705+ const runId = "idem-stop-before-dispatch" ;
3706+ await invokeAgent (
3707+ {
3708+ message : "hi" ,
3709+ agentId : "main" ,
3710+ sessionKey : "agent:main:main" ,
3711+ idempotencyKey : runId ,
3712+ } ,
3713+ { context, respond, reqId : runId , flushDispatch : false } ,
3714+ ) ;
3715+
3716+ expectRecordFields ( mockCallArg ( respond , 0 , 1 ) , {
3717+ runId,
3718+ sessionKey : "agent:main:main" ,
3719+ status : "accepted" ,
3720+ } ) ;
3721+ expect ( context . chatAbortControllers . has ( runId ) ) . toBe ( true ) ;
3722+
3723+ const stopRespond = vi . fn ( ) ;
3724+ await chatHandlers [ "chat.send" ] ( {
3725+ params : {
3726+ sessionKey : "agent:main:main" ,
3727+ message : "/stop" ,
3728+ idempotencyKey : "idem-stop-command-before-dispatch" ,
3729+ } ,
3730+ respond : stopRespond as never ,
3731+ context,
3732+ req : { type : "req" , id : "stop-req" , method : "chat.send" } ,
3733+ client : null ,
3734+ isWebchatConnect : ( ) => false ,
3735+ } ) ;
3736+
3737+ expectRecordFields ( mockCallArg ( stopRespond , 0 , 1 ) , {
3738+ aborted : true ,
3739+ runIds : [ runId ] ,
3740+ } ) ;
3741+ expect ( context . chatAbortControllers . has ( runId ) ) . toBe ( false ) ;
3742+
3743+ await flushScheduledDispatchStep ( ) ;
3744+
3745+ expect ( mocks . agentCommand ) . not . toHaveBeenCalled ( ) ;
3746+ expectRecordFields ( context . dedupe . get ( `agent:${ runId } ` ) ?. payload , {
3747+ runId,
3748+ status : "timeout" ,
3749+ summary : "aborted" ,
3750+ stopReason : "stop" ,
3751+ } ) ;
3752+ const finalResponse = respond . mock . calls . find (
3753+ ( call : unknown [ ] ) => ( call [ 1 ] as { status ?: unknown } | undefined ) ?. status === "timeout" ,
3754+ ) ;
3755+ expectRecordFields ( requireValue ( finalResponse , "terminal response missing" ) [ 1 ] , {
3756+ runId,
3757+ status : "timeout" ,
3758+ stopReason : "stop" ,
3759+ } ) ;
3760+ } ) ;
3761+
36993762 it ( "does not dispatch when chat.abort lands during pre-accept setup" , async ( ) => {
37003763 prime ( ) ;
37013764 const requestedSessionKey = "agent:main:legacy-main" ;
0 commit comments