@@ -2640,6 +2640,59 @@ describe("AgentServer HTTP Mode", () => {
26402640 expect ( resetTurnMessages ) . not . toHaveBeenCalled ( ) ;
26412641 } , 20000 ) ;
26422642
2643+ it ( "does not queue steering behind an active non-steering turn" , async ( ) => {
2644+ const s = createServer ( ) ;
2645+ await s . start ( ) ;
2646+ let finishTurn ! : ( result : { stopReason : "end_turn" } ) => void ;
2647+ const prompt = vi . fn ( ( params : { _meta ?: { steer ?: boolean } } ) =>
2648+ params . _meta ?. steer === true
2649+ ? Promise . resolve ( {
2650+ stopReason : "end_turn" as const ,
2651+ _meta : { steer : true } ,
2652+ } )
2653+ : new Promise < { stopReason : "end_turn" } > ( ( resolve ) => {
2654+ finishTurn = resolve ;
2655+ } ) ,
2656+ ) ;
2657+ const serverInternals = s as unknown as {
2658+ session : { clientConnection : { prompt : typeof prompt } } ;
2659+ } ;
2660+ serverInternals . session . clientConnection . prompt = prompt ;
2661+
2662+ const token = createToken ( ) ;
2663+ const send = ( id : string , steer = false ) =>
2664+ fetch ( `http://localhost:${ port } /command` , {
2665+ method : "POST" ,
2666+ headers : {
2667+ Authorization : `Bearer ${ token } ` ,
2668+ "Content-Type" : "application/json" ,
2669+ } ,
2670+ body : JSON . stringify ( {
2671+ jsonrpc : "2.0" ,
2672+ id,
2673+ method : "user_message" ,
2674+ params : { content : id , messageId : id , ...( steer && { steer } ) } ,
2675+ } ) ,
2676+ } ) ;
2677+
2678+ const activeTurn = send ( "normal-turn" ) ;
2679+ await vi . waitFor ( ( ) => expect ( prompt ) . toHaveBeenCalledTimes ( 1 ) ) ;
2680+
2681+ const steerResponse = await send ( "steer-turn" , true ) ;
2682+ await expect ( steerResponse . json ( ) ) . resolves . toMatchObject ( {
2683+ result : { stopReason : "steered" , steered : true } ,
2684+ } ) ;
2685+ expect ( prompt ) . toHaveBeenCalledTimes ( 2 ) ;
2686+ expect ( prompt . mock . calls [ 1 ] ?. [ 0 ] ) . toEqual (
2687+ expect . objectContaining ( {
2688+ _meta : expect . objectContaining ( { steer : true } ) ,
2689+ } ) ,
2690+ ) ;
2691+
2692+ finishTurn ( { stopReason : "end_turn" } ) ;
2693+ await activeTurn ;
2694+ } , 20000 ) ;
2695+
26432696 it ( "declines steering without blocking on a fallback normal turn" , async ( ) => {
26442697 const s = createServer ( ) ;
26452698 await s . start ( ) ;
@@ -2951,18 +3004,21 @@ describe("AgentServer HTTP Mode", () => {
29513004 ) ;
29523005 const { relaySpy, send } = await setupRelayEchoServer ( prompt ) ;
29533006
2954- // The second message lands while the first turn is still in flight;
2955- // each relay carries its own sender's id, not the first turn's.
3007+ // The second non-steering message lands while the first turn is still in
3008+ // flight. It waits for exclusive turn ownership, and each relay carries
3009+ // its own sender's id.
29563010 const first = send ( "m-first" ) ;
29573011 await vi . waitFor ( ( ) => expect ( prompt ) . toHaveBeenCalledTimes ( 1 ) ) ;
29583012 const second = send ( "m-second" ) ;
2959- await vi . waitFor ( ( ) => expect ( prompt ) . toHaveBeenCalledTimes ( 2 ) ) ;
3013+ await new Promise ( ( resolve ) => setTimeout ( resolve , 25 ) ) ;
3014+ expect ( prompt ) . toHaveBeenCalledTimes ( 1 ) ;
29603015
29613016 pendingTurns [ 0 ] ( { stopReason : "end_turn" } ) ;
29623017 await first ;
29633018 await vi . waitFor ( ( ) => expect ( relaySpy ) . toHaveBeenCalledTimes ( 1 ) ) ;
29643019 expect ( relaySpy . mock . calls [ 0 ] [ 4 ] ) . toBe ( "m-first" ) ;
29653020
3021+ await vi . waitFor ( ( ) => expect ( prompt ) . toHaveBeenCalledTimes ( 2 ) ) ;
29663022 pendingTurns [ 1 ] ( { stopReason : "end_turn" } ) ;
29673023 await second ;
29683024 await vi . waitFor ( ( ) => expect ( relaySpy ) . toHaveBeenCalledTimes ( 2 ) ) ;
0 commit comments