@@ -35,7 +35,7 @@ describe("MessageQueue", () => {
3535 expect ( queue . getDisplayText ( ) ) . toBe ( "/compact -t 3000" ) ;
3636 } ) ;
3737
38- it ( "should return rawCommand even with multiple messages if last has compaction metadata " , ( ) => {
38+ it ( "should show actual messages when compaction is added after normal message " , ( ) => {
3939 queue . add ( "First message" ) ;
4040
4141 const metadata : MuxFrontendMetadata = {
@@ -51,8 +51,9 @@ describe("MessageQueue", () => {
5151
5252 queue . add ( "Summarize this conversation..." , options ) ;
5353
54- // Should use rawCommand from latest options
55- expect ( queue . getDisplayText ( ) ) . toBe ( "/compact" ) ;
54+ // When multiple messages are queued, compaction metadata is lost when sent,
55+ // so display shows actual messages (not rawCommand) to match what will be sent
56+ expect ( queue . getDisplayText ( ) ) . toBe ( "First message\nSummarize this conversation..." ) ;
5657 } ) ;
5758
5859 it ( "should return joined messages when metadata type is not compaction-request" , ( ) => {
@@ -116,6 +117,68 @@ describe("MessageQueue", () => {
116117 } ) ;
117118 } ) ;
118119
120+ describe ( "multi-message batching" , ( ) => {
121+ it ( "should batch multiple follow-up messages" , ( ) => {
122+ queue . add ( "First message" ) ;
123+ queue . add ( "Second message" ) ;
124+ queue . add ( "Third message" ) ;
125+
126+ expect ( queue . getMessages ( ) ) . toEqual ( [ "First message" , "Second message" , "Third message" ] ) ;
127+ expect ( queue . getDisplayText ( ) ) . toBe ( "First message\nSecond message\nThird message" ) ;
128+ } ) ;
129+
130+ it ( "should batch follow-up message after compaction" , ( ) => {
131+ const metadata : MuxFrontendMetadata = {
132+ type : "compaction-request" ,
133+ rawCommand : "/compact" ,
134+ parsed : { } ,
135+ } ;
136+
137+ queue . add ( "Summarize..." , {
138+ model : "claude-3-5-sonnet-20241022" ,
139+ muxMetadata : metadata ,
140+ } ) ;
141+ queue . add ( "And then do this follow-up task" ) ;
142+
143+ // When a follow-up is added, compaction metadata is lost (latestOptions overwritten),
144+ // so display shows actual messages to match what will be sent
145+ expect ( queue . getDisplayText ( ) ) . toBe ( "Summarize...\nAnd then do this follow-up task" ) ;
146+ // Raw messages have the actual prompt
147+ expect ( queue . getMessages ( ) ) . toEqual ( [ "Summarize..." , "And then do this follow-up task" ] ) ;
148+ } ) ;
149+
150+ it ( "should produce combined message for API call" , ( ) => {
151+ queue . add ( "First message" , { model : "gpt-4" } ) ;
152+ queue . add ( "Second message" ) ;
153+
154+ const { message, options } = queue . produceMessage ( ) ;
155+
156+ // Messages are joined with newlines
157+ expect ( message ) . toBe ( "First message\nSecond message" ) ;
158+ // Latest options are used
159+ expect ( options ?. model ) . toBe ( "gpt-4" ) ;
160+ } ) ;
161+
162+ it ( "should batch messages with mixed images" , ( ) => {
163+ const image1 = { url : "data:image/png;base64,abc" , mediaType : "image/png" } ;
164+ const image2 = { url : "data:image/jpeg;base64,def" , mediaType : "image/jpeg" } ;
165+
166+ queue . add ( "Message with image" , { model : "gpt-4" , imageParts : [ image1 ] } ) ;
167+ queue . add ( "Follow-up without image" ) ;
168+ queue . add ( "Another with image" , { model : "gpt-4" , imageParts : [ image2 ] } ) ;
169+
170+ expect ( queue . getMessages ( ) ) . toEqual ( [
171+ "Message with image" ,
172+ "Follow-up without image" ,
173+ "Another with image" ,
174+ ] ) ;
175+ expect ( queue . getImageParts ( ) ) . toEqual ( [ image1 , image2 ] ) ;
176+ expect ( queue . getDisplayText ( ) ) . toBe (
177+ "Message with image\nFollow-up without image\nAnother with image"
178+ ) ;
179+ } ) ;
180+ } ) ;
181+
119182 describe ( "getImageParts" , ( ) => {
120183 it ( "should return accumulated images from multiple messages" , ( ) => {
121184 const image1 = {
0 commit comments