@@ -2431,6 +2431,71 @@ describe("runPreparedReply media-only handling", () => {
24312431 expect ( call ?. followupRun . run . extraSystemPromptStatic ) . toBe ( "group:discord:channel:#ops" ) ;
24322432 } ) ;
24332433
2434+ it ( "keeps the CLI session-reuse static prompt stable across group turns despite first-turn groupIntro" , async ( ) => {
2435+ const { buildGroupIntro } = await import ( "./groups.js" ) ;
2436+ // groupIntro is injected only on the first turn; groupChatContext is persistent.
2437+ vi . mocked ( buildGroupChatContext ) . mockReturnValue ( "GROUP-CHAT-CONTEXT" ) ;
2438+ vi . mocked ( buildGroupIntro ) . mockReturnValue ( "GROUP-INTRO" ) ;
2439+ const groupCtx = {
2440+ Body : "hello team" ,
2441+ RawBody : "hello team" ,
2442+ CommandBody : "hello team" ,
2443+ Provider : "discord" ,
2444+ ChatType : "group" as const ,
2445+ SessionKey : "agent:main:discord:guild-1:channel-1" ,
2446+ } ;
2447+ const groupSessionCtx = {
2448+ Body : "hello team" ,
2449+ BodyStripped : "hello team" ,
2450+ Provider : "discord" ,
2451+ ChatType : "group" as const ,
2452+ } ;
2453+ try {
2454+ // Turn 1: first turn in the session injects the behavioral group intro.
2455+ await runPreparedReply (
2456+ baseParams ( {
2457+ isNewSession : true ,
2458+ systemSent : false ,
2459+ ctx : groupCtx ,
2460+ sessionCtx : groupSessionCtx ,
2461+ } ) ,
2462+ ) ;
2463+ const firstTurn = requireRunReplyAgentCall ( 0 ) ;
2464+ // Turn 2: established session no longer re-injects the intro.
2465+ await runPreparedReply (
2466+ baseParams ( {
2467+ isNewSession : false ,
2468+ systemSent : true ,
2469+ ctx : groupCtx ,
2470+ sessionCtx : groupSessionCtx ,
2471+ sessionEntry : {
2472+ sessionId : "session-1" ,
2473+ updatedAt : 1 ,
2474+ systemSent : true ,
2475+ chatType : "group" ,
2476+ channel : "discord" ,
2477+ } as SessionEntry ,
2478+ } ) ,
2479+ ) ;
2480+ const secondTurn = requireRunReplyAgentCall ( 1 ) ;
2481+
2482+ // The live prompt still gets the intro on the first turn only.
2483+ expect ( firstTurn . followupRun . run . extraSystemPrompt ) . toContain ( "GROUP-INTRO" ) ;
2484+ expect ( secondTurn . followupRun . run . extraSystemPrompt ) . not . toContain ( "GROUP-INTRO" ) ;
2485+
2486+ // The session-reuse hash input excludes the volatile intro and stays identical across
2487+ // turns, so claude-cli reuses the session instead of resetting it every group turn (#69118).
2488+ expect ( firstTurn . followupRun . run . extraSystemPromptStatic ) . not . toContain ( "GROUP-INTRO" ) ;
2489+ expect ( firstTurn . followupRun . run . extraSystemPromptStatic ) . toContain ( "GROUP-CHAT-CONTEXT" ) ;
2490+ expect ( secondTurn . followupRun . run . extraSystemPromptStatic ) . toBe (
2491+ firstTurn . followupRun . run . extraSystemPromptStatic ,
2492+ ) ;
2493+ } finally {
2494+ vi . mocked ( buildGroupChatContext ) . mockReturnValue ( "" ) ;
2495+ vi . mocked ( buildGroupIntro ) . mockReturnValue ( "" ) ;
2496+ }
2497+ } ) ;
2498+
24342499 it . each ( [
24352500 [ "/new" , "new" ] ,
24362501 [ "/reset" , "reset" ] ,
0 commit comments