@@ -280,6 +280,9 @@ async function promptGPT(systemPrompt, input) {
280
280
281
281
let buffer = "" ;
282
282
let contentBuffer = [ ] ;
283
+ let thinkingContent = "" ;
284
+ let isThinking = false ;
285
+ let lastThinkingMessageIndex = - 1 ;
283
286
284
287
try {
285
288
while ( true ) {
@@ -303,7 +306,44 @@ async function promptGPT(systemPrompt, input) {
303
306
const token = jsonData . choices [ 0 ] . delta . content ;
304
307
305
308
if ( token ) {
306
- contentBuffer . push ( token ) ;
309
+ // Check for thinking tags
310
+ if ( token . includes ( "<thinking>" ) || token . includes ( "<think>" ) ) {
311
+ isThinking = true ;
312
+ thinkingContent = "" ;
313
+ lastThinkingMessageIndex = - 1 ;
314
+ return ;
315
+ }
316
+ if ( token . includes ( "</thinking>" ) || token . includes ( "</think>" ) ) {
317
+ isThinking = false ;
318
+ if ( thinkingContent . trim ( ) ) {
319
+ // Only add the final thinking message if we don't already have one
320
+ if ( lastThinkingMessageIndex === - 1 ) {
321
+ Alpine . store ( "chat" ) . add ( "thinking" , thinkingContent ) ;
322
+ }
323
+ }
324
+ return ;
325
+ }
326
+
327
+ // Handle content based on thinking state
328
+ if ( isThinking ) {
329
+ thinkingContent += token ;
330
+ // Update the last thinking message or create a new one
331
+ if ( lastThinkingMessageIndex === - 1 ) {
332
+ // Create new thinking message
333
+ Alpine . store ( "chat" ) . add ( "thinking" , thinkingContent ) ;
334
+ lastThinkingMessageIndex = Alpine . store ( "chat" ) . history . length - 1 ;
335
+ } else {
336
+ // Update existing thinking message
337
+ const chatStore = Alpine . store ( "chat" ) ;
338
+ const lastMessage = chatStore . history [ lastThinkingMessageIndex ] ;
339
+ if ( lastMessage && lastMessage . role === "thinking" ) {
340
+ lastMessage . content = thinkingContent ;
341
+ lastMessage . html = DOMPurify . sanitize ( marked . parse ( thinkingContent ) ) ;
342
+ }
343
+ }
344
+ } else {
345
+ contentBuffer . push ( token ) ;
346
+ }
307
347
}
308
348
} catch ( error ) {
309
349
console . error ( "Failed to parse line:" , line , error ) ;
@@ -322,6 +362,9 @@ async function promptGPT(systemPrompt, input) {
322
362
if ( contentBuffer . length > 0 ) {
323
363
addToChat ( contentBuffer . join ( "" ) ) ;
324
364
}
365
+ if ( thinkingContent . trim ( ) && lastThinkingMessageIndex === - 1 ) {
366
+ Alpine . store ( "chat" ) . add ( "thinking" , thinkingContent ) ;
367
+ }
325
368
326
369
// Highlight all code blocks once at the end
327
370
hljs . highlightAll ( ) ;
@@ -375,7 +418,17 @@ document.addEventListener("alpine:init", () => {
375
418
} ,
376
419
add ( role , content , image , audio ) {
377
420
const N = this . history . length - 1 ;
378
- if ( this . history . length && this . history [ N ] . role === role ) {
421
+ // For thinking messages, always create a new message
422
+ if ( role === "thinking" ) {
423
+ let c = "" ;
424
+ const lines = content . split ( "\n" ) ;
425
+ lines . forEach ( ( line ) => {
426
+ c += DOMPurify . sanitize ( marked . parse ( line ) ) ;
427
+ } ) ;
428
+ this . history . push ( { role, content, html : c , image, audio } ) ;
429
+ }
430
+ // For other messages, merge if same role
431
+ else if ( this . history . length && this . history [ N ] . role === role ) {
379
432
this . history [ N ] . content += content ;
380
433
this . history [ N ] . html = DOMPurify . sanitize (
381
434
marked . parse ( this . history [ N ] . content )
0 commit comments