@@ -764,6 +764,126 @@ func TestLeaveAgentTaskSessionRefreshesDurableParentTranscript(t *testing.T) {
764764 assert .Contains (t , app .transcript .History [0 ].Content , "new durable parent message" )
765765}
766766
767+ func TestAgentBackCommandReconcilesOptimisticPromptByEntryID (t * testing.T ) {
768+ t .Parallel ()
769+
770+ fixture , _ , app := newAgentTaskSessionTestApp (t , database .TaskSucceeded )
771+
772+ const prompt = "optimistic parent prompt"
773+
774+ entry , err := fixture .sessions .AppendMessage (t .Context (), fixture .parent .ID , nil , & database.MessageEntity {
775+ Timestamp : time .Now ().UTC ().Add (time .Second ),
776+ Role : database .RoleUser ,
777+ Content : prompt ,
778+ Provider : "" ,
779+ Model : "" , Parts : nil ,
780+ })
781+ require .NoError (t , err )
782+
783+ message := newChatMessage (transcript .RoleUser , prompt )
784+ message .EntryID = cloneStringPtr (& entry .ID )
785+ app .appendMessage (message )
786+
787+ require .NoError (t , app .inspectAgentTask (t .Context (), behaviorTaskID ))
788+ quit , err := app .runSessionCommand (t .Context (), "agents" , "back" , "/agents back" )
789+ require .NoError (t , err )
790+ assert .False (t , quit )
791+ assert .Equal (t , fixture .parent .ID , app .sessionID )
792+ assert .Empty (t , app .agentTaskSessionStack )
793+
794+ matches := 0
795+
796+ for index := range app .transcript .History {
797+ if app .transcript .History [index ].Content == prompt {
798+ matches ++
799+ }
800+ }
801+
802+ assert .Equal (t , 1 , matches )
803+ }
804+
805+ func TestAgentBackAfterParentPromptCompletionDoesNotDuplicateDurableMessages (t * testing.T ) {
806+ t .Parallel ()
807+
808+ fixture , _ , app := newActivePromptInspectionTestApp (t , database .TaskSucceeded , nil )
809+
810+ const (
811+ prompt = "parent prompt completed during inspection"
812+ response = "parent response completed during inspection"
813+ )
814+
815+ userMessage := newChatMessage (transcript .RoleUser , prompt )
816+ app .activePrompt .Prompt = prompt
817+ app .activePrompt .UserMessageTimestamp = userMessage .CreatedAt .UnixNano ()
818+ app .appendMessage (userMessage )
819+ promptID := app .activePrompt .ID
820+
821+ require .NoError (t , app .inspectAgentTask (t .Context (), behaviorTaskID ))
822+
823+ userEntry , err := fixture .sessions .AppendMessage (t .Context (), fixture .parent .ID , nil , & database.MessageEntity {
824+ Timestamp : userMessage .CreatedAt .Add (time .Second ),
825+ Role : database .RoleUser ,
826+ Content : prompt ,
827+ Provider : "" ,
828+ Model : "" , Parts : nil ,
829+ })
830+ require .NoError (t , err )
831+ assistantEntry , err := fixture .sessions .AppendMessage (
832+ t .Context (),
833+ fixture .parent .ID ,
834+ & userEntry .ID ,
835+ & database.MessageEntity {
836+ Timestamp : userMessage .CreatedAt .Add (2 * time .Second ),
837+ Role : database .RoleAssistant ,
838+ Content : response ,
839+ Provider : "" ,
840+ Model : "" , Parts : nil ,
841+ },
842+ )
843+ require .NoError (t , err )
844+
845+ app .handlePromptAsyncEvent (t .Context (), asyncTestEvent (
846+ asyncEventPromptUserEntry ,
847+ fixture .parent .ID ,
848+ userEntry .ID ,
849+ promptID ,
850+ ))
851+
852+ promptResponse := newTestPromptResponse (response )
853+ promptResponse .SessionID = fixture .parent .ID
854+ promptResponse .UserEntryID = userEntry .ID
855+ promptResponse .AssistantEntryID = assistantEntry .ID
856+ app .handlePromptAsyncEvent (t .Context (), & asyncEvent {
857+ Response : promptResponse , ToolCallEvent : nil , ToolEvent : nil , Usage : nil ,
858+ Kind : asyncEventPromptDone , Provider : "" , Text : "" , PromptID : promptID ,
859+ })
860+
861+ assert .Equal (t , fixture .child .ID , app .sessionID )
862+ assert .Nil (t , app .activePrompt )
863+
864+ quit , err := app .runSessionCommand (t .Context (), "agents" , "back" , "/agents back" )
865+ require .NoError (t , err )
866+ assert .False (t , quit )
867+ assert .Equal (t , fixture .parent .ID , app .sessionID )
868+
869+ messageCounts := make (map [string ]int )
870+ entryIDsByContent := make (map [string ][]string )
871+
872+ for index := range app .transcript .History {
873+ message := & app .transcript .History [index ]
874+
875+ messageCounts [message .Content ]++
876+ if message .EntryID != nil {
877+ entryIDsByContent [message .Content ] = append (entryIDsByContent [message .Content ], * message .EntryID )
878+ }
879+ }
880+
881+ assert .Equal (t , 1 , messageCounts [prompt ])
882+ assert .Equal (t , 1 , messageCounts [response ])
883+ assert .Equal (t , []string {userEntry .ID }, entryIDsByContent [prompt ])
884+ assert .Equal (t , []string {assistantEntry .ID }, entryIDsByContent [response ])
885+ }
886+
767887func TestRevisitAgentTaskSessionRefreshesDurableTranscript (t * testing.T ) {
768888 t .Parallel ()
769889
0 commit comments