@@ -1022,6 +1022,8 @@ describe("eventBridge", () => {
10221022 expect ( useUIStore . getState ( ) . toasts . at ( - 1 ) ?. message ) . toBe (
10231023 "已达到本次运行最大轮数,可继续发送消息或调高 runtime.max_turns" ,
10241024 ) ;
1025+ useSessionStore . setState ( { currentSessionId : "" } as any ) ;
1026+ useGatewayStore . setState ( { currentRunId : "" } as any ) ;
10251027 } ) ;
10261028
10271029 it ( "RunError with max-turn stop reason uses explicit max-turn UX instead of generic run failed" , ( ) => {
@@ -1069,6 +1071,7 @@ describe("eventBridge", () => {
10691071 it ( "RunError with max-turn stop reason is handled during session mismatch" , ( ) => {
10701072 const api = createMockGatewayAPI ( ) ;
10711073 useSessionStore . setState ( { currentSessionId : "sess-current" } as any ) ;
1074+ useGatewayStore . setState ( { currentRunId : "run-max-turn-mismatch" } as any ) ;
10721075 useChatStore . getState ( ) . addMessage ( {
10731076 id : "tool-running-run-error-mismatch" ,
10741077 role : "tool" ,
@@ -1106,6 +1109,92 @@ describe("eventBridge", () => {
11061109 ) ;
11071110 } ) ;
11081111
1112+ it ( "RunError during session mismatch is ignored when run id is stale" , ( ) => {
1113+ const api = createMockGatewayAPI ( ) ;
1114+ useSessionStore . setState ( { currentSessionId : "sess-current" } as any ) ;
1115+ useGatewayStore . setState ( { currentRunId : "run-current" } as any ) ;
1116+ useChatStore . getState ( ) . addMessage ( {
1117+ id : "tool-running-stale-run-error" ,
1118+ role : "tool" ,
1119+ type : "tool_call" ,
1120+ content : "" ,
1121+ toolName : "bash" ,
1122+ toolCallId : "tc-stale-run-error" ,
1123+ toolStatus : "running" ,
1124+ timestamp : Date . now ( ) ,
1125+ } ) ;
1126+ useChatStore . getState ( ) . setGenerating ( true ) ;
1127+
1128+ handleGatewayEvent (
1129+ {
1130+ type : EventType . RunError ,
1131+ payload : {
1132+ event_type : EventType . RunError ,
1133+ payload : {
1134+ code : "max_turn_exceeded" ,
1135+ message : "runtime: max turn limit reached (40)" ,
1136+ stop_reason : "max_turn_exceeded" ,
1137+ } ,
1138+ } ,
1139+ session_id : "sess-stale" ,
1140+ run_id : "run-stale" ,
1141+ } ,
1142+ api ,
1143+ ) ;
1144+
1145+ expect ( useChatStore . getState ( ) . isGenerating ) . toBe ( true ) ;
1146+ expect ( useChatStore . getState ( ) . stopReason ) . toBe ( "" ) ;
1147+ expect ( useChatStore . getState ( ) . messages [ 0 ] . toolStatus ) . toBe ( "running" ) ;
1148+ expect ( useUIStore . getState ( ) . toasts ) . toHaveLength ( 0 ) ;
1149+ useSessionStore . setState ( { currentSessionId : "" } as any ) ;
1150+ useGatewayStore . setState ( { currentRunId : "" } as any ) ;
1151+ } ) ;
1152+
1153+ it ( "RunError for current run is handled while transitioning" , ( ) => {
1154+ const api = createMockGatewayAPI ( ) ;
1155+ useSessionStore . setState ( { currentSessionId : "sess-current" } as any ) ;
1156+ useGatewayStore . setState ( { currentRunId : "run-transition" } as any ) ;
1157+ useChatStore . setState ( { isTransitioning : true } as any ) ;
1158+ useChatStore . getState ( ) . addMessage ( {
1159+ id : "tool-running-transition-run-error" ,
1160+ role : "tool" ,
1161+ type : "tool_call" ,
1162+ content : "" ,
1163+ toolName : "bash" ,
1164+ toolCallId : "tc-transition-run-error" ,
1165+ toolStatus : "running" ,
1166+ timestamp : Date . now ( ) ,
1167+ } ) ;
1168+ useChatStore . getState ( ) . setGenerating ( true ) ;
1169+
1170+ handleGatewayEvent (
1171+ {
1172+ type : EventType . RunError ,
1173+ payload : {
1174+ event_type : EventType . RunError ,
1175+ payload : {
1176+ code : "max_turn_exceeded" ,
1177+ message : "runtime: max turn limit reached (40)" ,
1178+ stop_reason : "max_turn_exceeded" ,
1179+ } ,
1180+ } ,
1181+ session_id : "sess-stale" ,
1182+ run_id : "run-transition" ,
1183+ } ,
1184+ api ,
1185+ ) ;
1186+
1187+ expect ( useChatStore . getState ( ) . isGenerating ) . toBe ( false ) ;
1188+ expect ( useChatStore . getState ( ) . stopReason ) . toBe ( "max_turn_exceeded" ) ;
1189+ expect ( useChatStore . getState ( ) . messages [ 0 ] . toolStatus ) . toBe ( "error" ) ;
1190+ expect ( useUIStore . getState ( ) . toasts . at ( - 1 ) ?. message ) . toBe (
1191+ "已达到本次运行最大轮数,可继续发送消息或调高 runtime.max_turns" ,
1192+ ) ;
1193+ useSessionStore . setState ( { currentSessionId : "" } as any ) ;
1194+ useGatewayStore . setState ( { currentRunId : "" } as any ) ;
1195+ useChatStore . setState ( { isTransitioning : false } as any ) ;
1196+ } ) ;
1197+
11091198 it ( "RunCanceled does not convert running tool calls to done" , ( ) => {
11101199 const api = createMockGatewayAPI ( ) ;
11111200 useChatStore . getState ( ) . addMessage ( {
0 commit comments