@tanstack/ai 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/esm/activities/chat/index.js +206 -172
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/stream/index.d.ts +1 -1
- package/dist/esm/activities/chat/stream/processor.d.ts +22 -43
- package/dist/esm/activities/chat/stream/processor.js +89 -156
- package/dist/esm/activities/chat/stream/processor.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-calls.d.ts +22 -21
- package/dist/esm/activities/chat/tools/tool-calls.js +40 -27
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
- package/dist/esm/activities/generateImage/index.js +41 -1
- package/dist/esm/activities/generateImage/index.js.map +1 -1
- package/dist/esm/activities/generateSpeech/index.js +33 -1
- package/dist/esm/activities/generateSpeech/index.js.map +1 -1
- package/dist/esm/activities/generateTranscription/index.js +29 -1
- package/dist/esm/activities/generateTranscription/index.js.map +1 -1
- package/dist/esm/activities/generateVideo/index.js +50 -0
- package/dist/esm/activities/generateVideo/index.js.map +1 -1
- package/dist/esm/activities/summarize/index.js +9 -8
- package/dist/esm/activities/summarize/index.js.map +1 -1
- package/dist/esm/event-client.d.ts +378 -254
- package/dist/esm/event-client.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/stream-to-response.d.ts +1 -1
- package/dist/esm/stream-to-response.js +5 -3
- package/dist/esm/stream-to-response.js.map +1 -1
- package/dist/esm/types.d.ts +162 -46
- package/package.json +1 -1
- package/src/activities/chat/index.ts +267 -191
- package/src/activities/chat/stream/index.ts +1 -5
- package/src/activities/chat/stream/processor.ts +128 -269
- package/src/activities/chat/tools/tool-calls.ts +55 -49
- package/src/activities/generateImage/index.ts +47 -2
- package/src/activities/generateSpeech/index.ts +37 -1
- package/src/activities/generateTranscription/index.ts +33 -1
- package/src/activities/generateVideo/index.ts +54 -0
- package/src/activities/summarize/index.ts +10 -9
- package/src/event-client.ts +460 -256
- package/src/index.ts +2 -3
- package/src/stream-to-response.ts +8 -6
- package/src/types.ts +209 -65
|
@@ -6,11 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
// Core processor
|
|
8
8
|
export { StreamProcessor, createReplayStream } from './processor'
|
|
9
|
-
export type {
|
|
10
|
-
StreamProcessorEvents,
|
|
11
|
-
StreamProcessorHandlers,
|
|
12
|
-
StreamProcessorOptions,
|
|
13
|
-
} from './processor'
|
|
9
|
+
export type { StreamProcessorEvents, StreamProcessorOptions } from './processor'
|
|
14
10
|
|
|
15
11
|
// Strategies
|
|
16
12
|
export {
|
|
@@ -78,67 +78,13 @@ export interface StreamProcessorEvents {
|
|
|
78
78
|
onThinkingUpdate?: (messageId: string, content: string) => void
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
/**
|
|
82
|
-
* Legacy handlers for backward compatibility
|
|
83
|
-
* These are the old callback-style handlers
|
|
84
|
-
*/
|
|
85
|
-
export interface StreamProcessorHandlers {
|
|
86
|
-
onTextUpdate?: (content: string) => void
|
|
87
|
-
onThinkingUpdate?: (content: string) => void
|
|
88
|
-
|
|
89
|
-
// Tool call lifecycle handlers
|
|
90
|
-
onToolCallStart?: (index: number, id: string, name: string) => void
|
|
91
|
-
onToolCallDelta?: (index: number, args: string) => void
|
|
92
|
-
onToolCallComplete?: (
|
|
93
|
-
index: number,
|
|
94
|
-
id: string,
|
|
95
|
-
name: string,
|
|
96
|
-
args: string,
|
|
97
|
-
) => void
|
|
98
|
-
onToolCallStateChange?: (
|
|
99
|
-
index: number,
|
|
100
|
-
id: string,
|
|
101
|
-
name: string,
|
|
102
|
-
state: ToolCallState,
|
|
103
|
-
args: string,
|
|
104
|
-
parsedArgs?: any,
|
|
105
|
-
) => void
|
|
106
|
-
|
|
107
|
-
// Tool result handlers
|
|
108
|
-
onToolResultStateChange?: (
|
|
109
|
-
toolCallId: string,
|
|
110
|
-
content: string,
|
|
111
|
-
state: ToolResultState,
|
|
112
|
-
error?: string,
|
|
113
|
-
) => void
|
|
114
|
-
|
|
115
|
-
// Approval/client tool handlers
|
|
116
|
-
onApprovalRequested?: (
|
|
117
|
-
toolCallId: string,
|
|
118
|
-
toolName: string,
|
|
119
|
-
input: any,
|
|
120
|
-
approvalId: string,
|
|
121
|
-
) => void
|
|
122
|
-
onToolInputAvailable?: (
|
|
123
|
-
toolCallId: string,
|
|
124
|
-
toolName: string,
|
|
125
|
-
input: any,
|
|
126
|
-
) => void
|
|
127
|
-
|
|
128
|
-
// Stream lifecycle
|
|
129
|
-
onStreamEnd?: (content: string, toolCalls?: Array<ToolCall>) => void
|
|
130
|
-
onError?: (error: { message: string; code?: string }) => void
|
|
131
|
-
}
|
|
132
|
-
|
|
133
81
|
/**
|
|
134
82
|
* Options for StreamProcessor
|
|
135
83
|
*/
|
|
136
84
|
export interface StreamProcessorOptions {
|
|
137
85
|
chunkStrategy?: ChunkStrategy
|
|
138
|
-
/**
|
|
86
|
+
/** Event-driven handlers */
|
|
139
87
|
events?: StreamProcessorEvents
|
|
140
|
-
/** Legacy callback handlers (for backward compatibility) */
|
|
141
|
-
handlers?: StreamProcessorHandlers
|
|
142
88
|
jsonParser?: {
|
|
143
89
|
parse: (jsonString: string) => any
|
|
144
90
|
}
|
|
@@ -168,7 +114,6 @@ export interface StreamProcessorOptions {
|
|
|
168
114
|
export class StreamProcessor {
|
|
169
115
|
private chunkStrategy: ChunkStrategy
|
|
170
116
|
private events: StreamProcessorEvents
|
|
171
|
-
private handlers: StreamProcessorHandlers
|
|
172
117
|
private jsonParser: { parse: (jsonString: string) => any }
|
|
173
118
|
private recordingEnabled: boolean
|
|
174
119
|
|
|
@@ -197,7 +142,6 @@ export class StreamProcessor {
|
|
|
197
142
|
constructor(options: StreamProcessorOptions = {}) {
|
|
198
143
|
this.chunkStrategy = options.chunkStrategy || new ImmediateStrategy()
|
|
199
144
|
this.events = options.events || {}
|
|
200
|
-
this.handlers = options.handlers || {}
|
|
201
145
|
this.jsonParser = options.jsonParser || defaultJSONParser
|
|
202
146
|
this.recordingEnabled = options.recording ?? false
|
|
203
147
|
|
|
@@ -423,49 +367,51 @@ export class StreamProcessor {
|
|
|
423
367
|
}
|
|
424
368
|
|
|
425
369
|
switch (chunk.type) {
|
|
426
|
-
|
|
427
|
-
|
|
370
|
+
// AG-UI Events
|
|
371
|
+
case 'TEXT_MESSAGE_CONTENT':
|
|
372
|
+
this.handleTextMessageContentEvent(chunk)
|
|
428
373
|
break
|
|
429
374
|
|
|
430
|
-
case '
|
|
431
|
-
this.
|
|
375
|
+
case 'TOOL_CALL_START':
|
|
376
|
+
this.handleToolCallStartEvent(chunk)
|
|
432
377
|
break
|
|
433
378
|
|
|
434
|
-
case '
|
|
435
|
-
this.
|
|
379
|
+
case 'TOOL_CALL_ARGS':
|
|
380
|
+
this.handleToolCallArgsEvent(chunk)
|
|
436
381
|
break
|
|
437
382
|
|
|
438
|
-
case '
|
|
439
|
-
this.
|
|
383
|
+
case 'TOOL_CALL_END':
|
|
384
|
+
this.handleToolCallEndEvent(chunk)
|
|
440
385
|
break
|
|
441
386
|
|
|
442
|
-
case '
|
|
443
|
-
this.
|
|
387
|
+
case 'RUN_FINISHED':
|
|
388
|
+
this.handleRunFinishedEvent(chunk)
|
|
444
389
|
break
|
|
445
390
|
|
|
446
|
-
case '
|
|
447
|
-
this.
|
|
391
|
+
case 'RUN_ERROR':
|
|
392
|
+
this.handleRunErrorEvent(chunk)
|
|
448
393
|
break
|
|
449
394
|
|
|
450
|
-
case '
|
|
451
|
-
this.
|
|
395
|
+
case 'STEP_FINISHED':
|
|
396
|
+
this.handleStepFinishedEvent(chunk)
|
|
452
397
|
break
|
|
453
398
|
|
|
454
|
-
case '
|
|
455
|
-
this.
|
|
399
|
+
case 'CUSTOM':
|
|
400
|
+
this.handleCustomEvent(chunk)
|
|
456
401
|
break
|
|
457
402
|
|
|
458
403
|
default:
|
|
459
|
-
//
|
|
404
|
+
// RUN_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_END, STEP_STARTED,
|
|
405
|
+
// STATE_SNAPSHOT, STATE_DELTA - no special handling needed
|
|
460
406
|
break
|
|
461
407
|
}
|
|
462
408
|
}
|
|
463
409
|
|
|
464
410
|
/**
|
|
465
|
-
* Handle
|
|
411
|
+
* Handle TEXT_MESSAGE_CONTENT event
|
|
466
412
|
*/
|
|
467
|
-
private
|
|
468
|
-
chunk: Extract<StreamChunk, { type: '
|
|
413
|
+
private handleTextMessageContentEvent(
|
|
414
|
+
chunk: Extract<StreamChunk, { type: 'TEXT_MESSAGE_CONTENT' }>,
|
|
469
415
|
): void {
|
|
470
416
|
// Content arriving means all current tool calls are complete
|
|
471
417
|
this.completeAllToolCalls()
|
|
@@ -495,7 +441,7 @@ export class StreamProcessor {
|
|
|
495
441
|
// Prefer delta over content - delta is the incremental change
|
|
496
442
|
if (chunk.delta !== '') {
|
|
497
443
|
nextText = currentText + chunk.delta
|
|
498
|
-
} else if (chunk.content !== '') {
|
|
444
|
+
} else if (chunk.content && chunk.content !== '') {
|
|
499
445
|
// Fallback: use content if delta is not provided
|
|
500
446
|
if (chunk.content.startsWith(currentText)) {
|
|
501
447
|
nextText = chunk.content
|
|
@@ -512,8 +458,7 @@ export class StreamProcessor {
|
|
|
512
458
|
this.totalTextContent += textDelta
|
|
513
459
|
|
|
514
460
|
// Use delta for chunk strategy if available
|
|
515
|
-
|
|
516
|
-
const chunkPortion = chunk.delta ?? chunk.content ?? ''
|
|
461
|
+
const chunkPortion = chunk.delta || chunk.content || ''
|
|
517
462
|
const shouldEmit = this.chunkStrategy.shouldEmit(
|
|
518
463
|
chunkPortion,
|
|
519
464
|
this.currentSegmentText,
|
|
@@ -524,100 +469,75 @@ export class StreamProcessor {
|
|
|
524
469
|
}
|
|
525
470
|
|
|
526
471
|
/**
|
|
527
|
-
* Handle
|
|
472
|
+
* Handle TOOL_CALL_START event
|
|
528
473
|
*/
|
|
529
|
-
private
|
|
530
|
-
chunk: Extract<StreamChunk, { type: '
|
|
474
|
+
private handleToolCallStartEvent(
|
|
475
|
+
chunk: Extract<StreamChunk, { type: 'TOOL_CALL_START' }>,
|
|
531
476
|
): void {
|
|
532
477
|
// Mark that we've seen tool calls since the last text segment
|
|
533
478
|
this.hasToolCallsSinceTextStart = true
|
|
534
479
|
|
|
535
|
-
const toolCallId = chunk.
|
|
480
|
+
const toolCallId = chunk.toolCallId
|
|
536
481
|
const existingToolCall = this.toolCalls.get(toolCallId)
|
|
537
482
|
|
|
538
483
|
if (!existingToolCall) {
|
|
539
484
|
// New tool call starting
|
|
540
|
-
const initialState: ToolCallState =
|
|
541
|
-
? 'input-streaming'
|
|
542
|
-
: 'awaiting-input'
|
|
485
|
+
const initialState: ToolCallState = 'awaiting-input'
|
|
543
486
|
|
|
544
487
|
const newToolCall: InternalToolCallState = {
|
|
545
|
-
id: chunk.
|
|
546
|
-
name: chunk.
|
|
547
|
-
arguments:
|
|
488
|
+
id: chunk.toolCallId,
|
|
489
|
+
name: chunk.toolName,
|
|
490
|
+
arguments: '',
|
|
548
491
|
state: initialState,
|
|
549
492
|
parsedArguments: undefined,
|
|
550
|
-
index: chunk.index,
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
// Try to parse the arguments
|
|
554
|
-
if (chunk.toolCall.function.arguments) {
|
|
555
|
-
newToolCall.parsedArguments = this.jsonParser.parse(
|
|
556
|
-
chunk.toolCall.function.arguments,
|
|
557
|
-
)
|
|
493
|
+
index: chunk.index ?? this.toolCalls.size,
|
|
558
494
|
}
|
|
559
495
|
|
|
560
496
|
this.toolCalls.set(toolCallId, newToolCall)
|
|
561
497
|
this.toolCallOrder.push(toolCallId)
|
|
562
498
|
|
|
563
|
-
// Get actual index for this tool call (based on order)
|
|
564
|
-
const actualIndex = this.toolCallOrder.indexOf(toolCallId)
|
|
565
|
-
|
|
566
|
-
// Emit legacy lifecycle event
|
|
567
|
-
this.handlers.onToolCallStart?.(
|
|
568
|
-
actualIndex,
|
|
569
|
-
chunk.toolCall.id,
|
|
570
|
-
chunk.toolCall.function.name,
|
|
571
|
-
)
|
|
572
|
-
|
|
573
|
-
// Emit legacy state change event
|
|
574
|
-
this.handlers.onToolCallStateChange?.(
|
|
575
|
-
actualIndex,
|
|
576
|
-
chunk.toolCall.id,
|
|
577
|
-
chunk.toolCall.function.name,
|
|
578
|
-
initialState,
|
|
579
|
-
chunk.toolCall.function.arguments || '',
|
|
580
|
-
newToolCall.parsedArguments,
|
|
581
|
-
)
|
|
582
|
-
|
|
583
|
-
// Emit initial delta
|
|
584
|
-
if (chunk.toolCall.function.arguments) {
|
|
585
|
-
this.handlers.onToolCallDelta?.(
|
|
586
|
-
actualIndex,
|
|
587
|
-
chunk.toolCall.function.arguments,
|
|
588
|
-
)
|
|
589
|
-
}
|
|
590
|
-
|
|
591
499
|
// Update UIMessage
|
|
592
500
|
if (this.currentAssistantMessageId) {
|
|
593
501
|
this.messages = updateToolCallPart(
|
|
594
502
|
this.messages,
|
|
595
503
|
this.currentAssistantMessageId,
|
|
596
504
|
{
|
|
597
|
-
id: chunk.
|
|
598
|
-
name: chunk.
|
|
599
|
-
arguments:
|
|
505
|
+
id: chunk.toolCallId,
|
|
506
|
+
name: chunk.toolName,
|
|
507
|
+
arguments: '',
|
|
600
508
|
state: initialState,
|
|
601
509
|
},
|
|
602
510
|
)
|
|
603
511
|
this.emitMessagesChange()
|
|
604
512
|
|
|
605
|
-
// Emit
|
|
513
|
+
// Emit granular event
|
|
606
514
|
this.events.onToolCallStateChange?.(
|
|
607
515
|
this.currentAssistantMessageId,
|
|
608
|
-
chunk.
|
|
516
|
+
chunk.toolCallId,
|
|
609
517
|
initialState,
|
|
610
|
-
|
|
518
|
+
'',
|
|
611
519
|
)
|
|
612
520
|
}
|
|
613
|
-
}
|
|
614
|
-
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Handle TOOL_CALL_ARGS event
|
|
526
|
+
*/
|
|
527
|
+
private handleToolCallArgsEvent(
|
|
528
|
+
chunk: Extract<StreamChunk, { type: 'TOOL_CALL_ARGS' }>,
|
|
529
|
+
): void {
|
|
530
|
+
const toolCallId = chunk.toolCallId
|
|
531
|
+
const existingToolCall = this.toolCalls.get(toolCallId)
|
|
532
|
+
|
|
533
|
+
if (existingToolCall) {
|
|
615
534
|
const wasAwaitingInput = existingToolCall.state === 'awaiting-input'
|
|
616
535
|
|
|
617
|
-
|
|
536
|
+
// Accumulate arguments from delta
|
|
537
|
+
existingToolCall.arguments += chunk.delta || ''
|
|
618
538
|
|
|
619
539
|
// Update state
|
|
620
|
-
if (wasAwaitingInput && chunk.
|
|
540
|
+
if (wasAwaitingInput && chunk.delta) {
|
|
621
541
|
existingToolCall.state = 'input-streaming'
|
|
622
542
|
}
|
|
623
543
|
|
|
@@ -626,27 +546,6 @@ export class StreamProcessor {
|
|
|
626
546
|
existingToolCall.arguments,
|
|
627
547
|
)
|
|
628
548
|
|
|
629
|
-
// Get actual index for this tool call
|
|
630
|
-
const actualIndex = this.toolCallOrder.indexOf(toolCallId)
|
|
631
|
-
|
|
632
|
-
// Emit legacy state change event
|
|
633
|
-
this.handlers.onToolCallStateChange?.(
|
|
634
|
-
actualIndex,
|
|
635
|
-
existingToolCall.id,
|
|
636
|
-
existingToolCall.name,
|
|
637
|
-
existingToolCall.state,
|
|
638
|
-
existingToolCall.arguments,
|
|
639
|
-
existingToolCall.parsedArguments,
|
|
640
|
-
)
|
|
641
|
-
|
|
642
|
-
// Emit delta
|
|
643
|
-
if (chunk.toolCall.function.arguments) {
|
|
644
|
-
this.handlers.onToolCallDelta?.(
|
|
645
|
-
actualIndex,
|
|
646
|
-
chunk.toolCall.function.arguments,
|
|
647
|
-
)
|
|
648
|
-
}
|
|
649
|
-
|
|
650
549
|
// Update UIMessage
|
|
651
550
|
if (this.currentAssistantMessageId) {
|
|
652
551
|
this.messages = updateToolCallPart(
|
|
@@ -661,7 +560,7 @@ export class StreamProcessor {
|
|
|
661
560
|
)
|
|
662
561
|
this.emitMessagesChange()
|
|
663
562
|
|
|
664
|
-
// Emit
|
|
563
|
+
// Emit granular event
|
|
665
564
|
this.events.onToolCallStateChange?.(
|
|
666
565
|
this.currentAssistantMessageId,
|
|
667
566
|
existingToolCall.id,
|
|
@@ -673,27 +572,20 @@ export class StreamProcessor {
|
|
|
673
572
|
}
|
|
674
573
|
|
|
675
574
|
/**
|
|
676
|
-
* Handle
|
|
575
|
+
* Handle TOOL_CALL_END event
|
|
677
576
|
*/
|
|
678
|
-
private
|
|
679
|
-
chunk: Extract<StreamChunk, { type: '
|
|
577
|
+
private handleToolCallEndEvent(
|
|
578
|
+
chunk: Extract<StreamChunk, { type: 'TOOL_CALL_END' }>,
|
|
680
579
|
): void {
|
|
681
580
|
const state: ToolResultState = 'complete'
|
|
682
581
|
|
|
683
|
-
// Emit legacy handler
|
|
684
|
-
this.handlers.onToolResultStateChange?.(
|
|
685
|
-
chunk.toolCallId,
|
|
686
|
-
chunk.content,
|
|
687
|
-
state,
|
|
688
|
-
)
|
|
689
|
-
|
|
690
582
|
// Update UIMessage if we have a current assistant message
|
|
691
|
-
if (this.currentAssistantMessageId) {
|
|
583
|
+
if (this.currentAssistantMessageId && chunk.result) {
|
|
692
584
|
this.messages = updateToolResultPart(
|
|
693
585
|
this.messages,
|
|
694
586
|
this.currentAssistantMessageId,
|
|
695
587
|
chunk.toolCallId,
|
|
696
|
-
chunk.
|
|
588
|
+
chunk.result,
|
|
697
589
|
state,
|
|
698
590
|
)
|
|
699
591
|
this.emitMessagesChange()
|
|
@@ -701,32 +593,31 @@ export class StreamProcessor {
|
|
|
701
593
|
}
|
|
702
594
|
|
|
703
595
|
/**
|
|
704
|
-
* Handle
|
|
596
|
+
* Handle RUN_FINISHED event
|
|
705
597
|
*/
|
|
706
|
-
private
|
|
598
|
+
private handleRunFinishedEvent(
|
|
599
|
+
chunk: Extract<StreamChunk, { type: 'RUN_FINISHED' }>,
|
|
600
|
+
): void {
|
|
707
601
|
this.finishReason = chunk.finishReason
|
|
708
602
|
this.isDone = true
|
|
709
603
|
this.completeAllToolCalls()
|
|
710
604
|
}
|
|
711
605
|
|
|
712
606
|
/**
|
|
713
|
-
* Handle
|
|
607
|
+
* Handle RUN_ERROR event
|
|
714
608
|
*/
|
|
715
|
-
private
|
|
716
|
-
chunk: Extract<StreamChunk, { type: '
|
|
609
|
+
private handleRunErrorEvent(
|
|
610
|
+
chunk: Extract<StreamChunk, { type: 'RUN_ERROR' }>,
|
|
717
611
|
): void {
|
|
718
|
-
// Emit
|
|
719
|
-
this.
|
|
720
|
-
|
|
721
|
-
// Emit new event
|
|
722
|
-
this.events.onError?.(new Error(chunk.error.message))
|
|
612
|
+
// Emit error event
|
|
613
|
+
this.events.onError?.(new Error(chunk.error.message || 'An error occurred'))
|
|
723
614
|
}
|
|
724
615
|
|
|
725
616
|
/**
|
|
726
|
-
* Handle
|
|
617
|
+
* Handle STEP_FINISHED event (for thinking/reasoning content)
|
|
727
618
|
*/
|
|
728
|
-
private
|
|
729
|
-
chunk: Extract<StreamChunk, { type: '
|
|
619
|
+
private handleStepFinishedEvent(
|
|
620
|
+
chunk: Extract<StreamChunk, { type: 'STEP_FINISHED' }>,
|
|
730
621
|
): void {
|
|
731
622
|
const previous = this.thinkingContent
|
|
732
623
|
let nextThinking = previous
|
|
@@ -734,7 +625,7 @@ export class StreamProcessor {
|
|
|
734
625
|
// Prefer delta over content
|
|
735
626
|
if (chunk.delta && chunk.delta !== '') {
|
|
736
627
|
nextThinking = previous + chunk.delta
|
|
737
|
-
} else if (chunk.content !== '') {
|
|
628
|
+
} else if (chunk.content && chunk.content !== '') {
|
|
738
629
|
if (chunk.content.startsWith(previous)) {
|
|
739
630
|
nextThinking = chunk.content
|
|
740
631
|
} else if (previous.startsWith(chunk.content)) {
|
|
@@ -746,9 +637,6 @@ export class StreamProcessor {
|
|
|
746
637
|
|
|
747
638
|
this.thinkingContent = nextThinking
|
|
748
639
|
|
|
749
|
-
// Emit legacy handler
|
|
750
|
-
this.handlers.onThinkingUpdate?.(this.thinkingContent)
|
|
751
|
-
|
|
752
640
|
// Update UIMessage
|
|
753
641
|
if (this.currentAssistantMessageId) {
|
|
754
642
|
this.messages = updateThinkingPart(
|
|
@@ -758,7 +646,7 @@ export class StreamProcessor {
|
|
|
758
646
|
)
|
|
759
647
|
this.emitMessagesChange()
|
|
760
648
|
|
|
761
|
-
// Emit
|
|
649
|
+
// Emit granular event
|
|
762
650
|
this.events.onThinkingUpdate?.(
|
|
763
651
|
this.currentAssistantMessageId,
|
|
764
652
|
this.thinkingContent,
|
|
@@ -767,69 +655,68 @@ export class StreamProcessor {
|
|
|
767
655
|
}
|
|
768
656
|
|
|
769
657
|
/**
|
|
770
|
-
* Handle
|
|
658
|
+
* Handle CUSTOM event
|
|
659
|
+
* Handles special custom events like 'tool-input-available' for client-side tool execution
|
|
660
|
+
* and 'approval-requested' for tool approval flows
|
|
771
661
|
*/
|
|
772
|
-
private
|
|
773
|
-
chunk: Extract<StreamChunk, { type: '
|
|
662
|
+
private handleCustomEvent(
|
|
663
|
+
chunk: Extract<StreamChunk, { type: 'CUSTOM' }>,
|
|
774
664
|
): void {
|
|
775
|
-
//
|
|
776
|
-
|
|
777
|
-
chunk.
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
665
|
+
// Handle client tool input availability - trigger client-side execution
|
|
666
|
+
if (chunk.name === 'tool-input-available' && chunk.data) {
|
|
667
|
+
const { toolCallId, toolName, input } = chunk.data as {
|
|
668
|
+
toolCallId: string
|
|
669
|
+
toolName: string
|
|
670
|
+
input: any
|
|
671
|
+
}
|
|
782
672
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
chunk.approval.id,
|
|
790
|
-
)
|
|
791
|
-
this.emitMessagesChange()
|
|
673
|
+
// Emit onToolCall event for the client to execute the tool
|
|
674
|
+
this.events.onToolCall?.({
|
|
675
|
+
toolCallId,
|
|
676
|
+
toolName,
|
|
677
|
+
input,
|
|
678
|
+
})
|
|
792
679
|
}
|
|
793
680
|
|
|
794
|
-
//
|
|
795
|
-
|
|
796
|
-
toolCallId
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
681
|
+
// Handle approval requests
|
|
682
|
+
if (chunk.name === 'approval-requested' && chunk.data) {
|
|
683
|
+
const { toolCallId, toolName, input, approval } = chunk.data as {
|
|
684
|
+
toolCallId: string
|
|
685
|
+
toolName: string
|
|
686
|
+
input: any
|
|
687
|
+
approval: { id: string; needsApproval: boolean }
|
|
688
|
+
}
|
|
802
689
|
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
chunk.input,
|
|
814
|
-
)
|
|
690
|
+
// Update the tool call part with approval state
|
|
691
|
+
if (this.currentAssistantMessageId) {
|
|
692
|
+
this.messages = updateToolCallApproval(
|
|
693
|
+
this.messages,
|
|
694
|
+
this.currentAssistantMessageId,
|
|
695
|
+
toolCallId,
|
|
696
|
+
approval.id,
|
|
697
|
+
)
|
|
698
|
+
this.emitMessagesChange()
|
|
699
|
+
}
|
|
815
700
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
701
|
+
// Emit approval request event
|
|
702
|
+
this.events.onApprovalRequest?.({
|
|
703
|
+
toolCallId,
|
|
704
|
+
toolName,
|
|
705
|
+
input,
|
|
706
|
+
approvalId: approval.id,
|
|
707
|
+
})
|
|
708
|
+
}
|
|
822
709
|
}
|
|
823
710
|
|
|
824
711
|
/**
|
|
825
712
|
* Detect if an incoming content chunk represents a NEW text segment
|
|
826
713
|
*/
|
|
827
714
|
private isNewTextSegment(
|
|
828
|
-
chunk: Extract<StreamChunk, { type: '
|
|
715
|
+
chunk: Extract<StreamChunk, { type: 'TEXT_MESSAGE_CONTENT' }>,
|
|
829
716
|
previous: string,
|
|
830
717
|
): boolean {
|
|
831
|
-
//
|
|
832
|
-
if (chunk.
|
|
718
|
+
// Check if content is present (delta is always defined but may be empty string)
|
|
719
|
+
if (chunk.content !== undefined) {
|
|
833
720
|
if (chunk.content.length < previous.length) {
|
|
834
721
|
return true
|
|
835
722
|
}
|
|
@@ -859,7 +746,7 @@ export class StreamProcessor {
|
|
|
859
746
|
* Mark a tool call as complete and emit event
|
|
860
747
|
*/
|
|
861
748
|
private completeToolCall(
|
|
862
|
-
|
|
749
|
+
_index: number,
|
|
863
750
|
toolCall: InternalToolCallState,
|
|
864
751
|
): void {
|
|
865
752
|
toolCall.state = 'input-complete'
|
|
@@ -867,24 +754,6 @@ export class StreamProcessor {
|
|
|
867
754
|
// Try final parse
|
|
868
755
|
toolCall.parsedArguments = this.jsonParser.parse(toolCall.arguments)
|
|
869
756
|
|
|
870
|
-
// Emit legacy state change event
|
|
871
|
-
this.handlers.onToolCallStateChange?.(
|
|
872
|
-
index,
|
|
873
|
-
toolCall.id,
|
|
874
|
-
toolCall.name,
|
|
875
|
-
'input-complete',
|
|
876
|
-
toolCall.arguments,
|
|
877
|
-
toolCall.parsedArguments,
|
|
878
|
-
)
|
|
879
|
-
|
|
880
|
-
// Emit legacy complete event
|
|
881
|
-
this.handlers.onToolCallComplete?.(
|
|
882
|
-
index,
|
|
883
|
-
toolCall.id,
|
|
884
|
-
toolCall.name,
|
|
885
|
-
toolCall.arguments,
|
|
886
|
-
)
|
|
887
|
-
|
|
888
757
|
// Update UIMessage
|
|
889
758
|
if (this.currentAssistantMessageId) {
|
|
890
759
|
this.messages = updateToolCallPart(
|
|
@@ -899,7 +768,7 @@ export class StreamProcessor {
|
|
|
899
768
|
)
|
|
900
769
|
this.emitMessagesChange()
|
|
901
770
|
|
|
902
|
-
// Emit
|
|
771
|
+
// Emit granular event
|
|
903
772
|
this.events.onToolCallStateChange?.(
|
|
904
773
|
this.currentAssistantMessageId,
|
|
905
774
|
toolCall.id,
|
|
@@ -915,9 +784,6 @@ export class StreamProcessor {
|
|
|
915
784
|
private emitTextUpdate(): void {
|
|
916
785
|
this.lastEmittedText = this.currentSegmentText
|
|
917
786
|
|
|
918
|
-
// Emit legacy handler
|
|
919
|
-
this.handlers.onTextUpdate?.(this.currentSegmentText)
|
|
920
|
-
|
|
921
787
|
// Update UIMessage
|
|
922
788
|
if (this.currentAssistantMessageId) {
|
|
923
789
|
this.messages = updateTextPart(
|
|
@@ -927,7 +793,7 @@ export class StreamProcessor {
|
|
|
927
793
|
)
|
|
928
794
|
this.emitMessagesChange()
|
|
929
795
|
|
|
930
|
-
// Emit
|
|
796
|
+
// Emit granular event
|
|
931
797
|
this.events.onTextUpdate?.(
|
|
932
798
|
this.currentAssistantMessageId,
|
|
933
799
|
this.currentSegmentText,
|
|
@@ -954,14 +820,7 @@ export class StreamProcessor {
|
|
|
954
820
|
this.emitTextUpdate()
|
|
955
821
|
}
|
|
956
822
|
|
|
957
|
-
// Emit
|
|
958
|
-
const toolCalls = this.getCompletedToolCalls()
|
|
959
|
-
this.handlers.onStreamEnd?.(
|
|
960
|
-
this.totalTextContent,
|
|
961
|
-
toolCalls.length > 0 ? toolCalls : undefined,
|
|
962
|
-
)
|
|
963
|
-
|
|
964
|
-
// Emit new stream end event
|
|
823
|
+
// Emit stream end event
|
|
965
824
|
if (this.currentAssistantMessageId) {
|
|
966
825
|
const assistantMessage = this.messages.find(
|
|
967
826
|
(m) => m.id === this.currentAssistantMessageId,
|
|
@@ -1002,7 +861,7 @@ export class StreamProcessor {
|
|
|
1002
861
|
}
|
|
1003
862
|
|
|
1004
863
|
/**
|
|
1005
|
-
* Get current processor state
|
|
864
|
+
* Get current processor state
|
|
1006
865
|
*/
|
|
1007
866
|
getState(): ProcessorState {
|
|
1008
867
|
return {
|