@@ -812,6 +812,92 @@ describe('doStream', () => {
812812 expect ( reasoningDeltas ) . not . toContain ( 'Also ignored' ) ;
813813 } ) ;
814814
815+ it ( 'should maintain correct reasoning order when content comes after reasoning (issue #7824)' , async ( ) => {
816+ // This test reproduces the issue where reasoning appears first but then gets "pushed down"
817+ // by content that comes later in the stream
818+ server . urls [ 'https://openrouter.ai/api/v1/chat/completions' ] ! . response = {
819+ type : 'stream-chunks' ,
820+ chunks : [
821+ // First chunk: Start with reasoning
822+ `data: {"id":"chatcmpl-order-test","object":"chat.completion.chunk","created":1711357598,"model":"gpt-3.5-turbo-0125",` +
823+ `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"role":"assistant",` +
824+ `"reasoning":"I need to think about this step by step..."},` +
825+ `"logprobs":null,"finish_reason":null}]}\n\n` ,
826+ // Second chunk: More reasoning
827+ `data: {"id":"chatcmpl-order-test","object":"chat.completion.chunk","created":1711357598,"model":"gpt-3.5-turbo-0125",` +
828+ `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{` +
829+ `"reasoning":" First, I should analyze the request."},` +
830+ `"logprobs":null,"finish_reason":null}]}\n\n` ,
831+ // Third chunk: Even more reasoning
832+ `data: {"id":"chatcmpl-order-test","object":"chat.completion.chunk","created":1711357598,"model":"gpt-3.5-turbo-0125",` +
833+ `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{` +
834+ `"reasoning":" Then I should provide a helpful response."},` +
835+ `"logprobs":null,"finish_reason":null}]}\n\n` ,
836+ // Fourth chunk: Content starts
837+ `data: {"id":"chatcmpl-order-test","object":"chat.completion.chunk","created":1711357598,"model":"gpt-3.5-turbo-0125",` +
838+ `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"content":"Hello! "},` +
839+ `"logprobs":null,"finish_reason":null}]}\n\n` ,
840+ // Fifth chunk: More content
841+ `data: {"id":"chatcmpl-order-test","object":"chat.completion.chunk","created":1711357598,"model":"gpt-3.5-turbo-0125",` +
842+ `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"content":"How can I help you today?"},` +
843+ `"logprobs":null,"finish_reason":null}]}\n\n` ,
844+ // Finish chunk
845+ `data: {"id":"chatcmpl-order-test","object":"chat.completion.chunk","created":1711357598,"model":"gpt-3.5-turbo-0125",` +
846+ `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{},` +
847+ `"logprobs":null,"finish_reason":"stop"}]}\n\n` ,
848+ `data: {"id":"chatcmpl-order-test","object":"chat.completion.chunk","created":1711357598,"model":"gpt-3.5-turbo-0125",` +
849+ `"system_fingerprint":"fp_3bc1b5746c","choices":[],"usage":{"prompt_tokens":17,"completion_tokens":30,"total_tokens":47}}\n\n` ,
850+ 'data: [DONE]\n\n' ,
851+ ] ,
852+ } ;
853+
854+ const { stream } = await model . doStream ( {
855+ prompt : TEST_PROMPT ,
856+ } ) ;
857+
858+ const elements = await convertReadableStreamToArray ( stream ) ;
859+
860+ // The expected order should be:
861+ // 1. reasoning-start
862+ // 2. reasoning-delta (3 times)
863+ // 3. reasoning-end (when text starts)
864+ // 4. text-start
865+ // 5. text-delta (2 times)
866+ // 6. text-end (when stream finishes)
867+
868+ const streamOrder = elements . map ( el => el . type ) ;
869+
870+ // Find the positions of key events
871+ const reasoningStartIndex = streamOrder . indexOf ( 'reasoning-start' ) ;
872+ const reasoningEndIndex = streamOrder . indexOf ( 'reasoning-end' ) ;
873+ const textStartIndex = streamOrder . indexOf ( 'text-start' ) ;
874+
875+ // Reasoning should come before text and end before text starts
876+ expect ( reasoningStartIndex ) . toBeLessThan ( textStartIndex ) ;
877+ expect ( reasoningEndIndex ) . toBeLessThan ( textStartIndex ) ;
878+
879+ // Verify reasoning content
880+ const reasoningDeltas = elements
881+ . filter ( ( el ) => el . type === 'reasoning-delta' )
882+ . map ( ( el ) => ( el as { type : 'reasoning-delta' ; delta : string } ) . delta ) ;
883+
884+ expect ( reasoningDeltas ) . toEqual ( [
885+ 'I need to think about this step by step...' ,
886+ ' First, I should analyze the request.' ,
887+ ' Then I should provide a helpful response.' ,
888+ ] ) ;
889+
890+ // Verify text content
891+ const textDeltas = elements
892+ . filter ( ( el ) => el . type === 'text-delta' )
893+ . map ( ( el ) => ( el as { type : 'text-delta' ; delta : string } ) . delta ) ;
894+
895+ expect ( textDeltas ) . toEqual ( [
896+ 'Hello! ' ,
897+ 'How can I help you today?' ,
898+ ] ) ;
899+ } ) ;
900+
815901 it ( 'should stream tool deltas' , async ( ) => {
816902 server . urls [ 'https://openrouter.ai/api/v1/chat/completions' ] ! . response = {
817903 type : 'stream-chunks' ,
0 commit comments