@ai-sdk/workflow 1.0.0-beta.3 → 1.0.0-beta.30
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/CHANGELOG.md +255 -0
- package/dist/index.d.mts +135 -34
- package/dist/index.mjs +174 -125
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -6
- package/src/do-stream-step.ts +7 -6
- package/src/index.ts +3 -3
- package/src/serializable-schema.ts +4 -0
- package/src/stream-text-iterator.ts +18 -37
- package/src/telemetry.ts +5 -5
- package/src/test/agent-e2e-workflows.ts +9 -9
- package/src/to-ui-message-chunk.ts +5 -2
- package/src/workflow-agent.ts +514 -324
- package/src/workflow-chat-transport.ts +2 -2
package/src/workflow-agent.ts
CHANGED
|
@@ -7,21 +7,24 @@ import type {
|
|
|
7
7
|
SharedV4ProviderOptions,
|
|
8
8
|
} from '@ai-sdk/provider';
|
|
9
9
|
import {
|
|
10
|
-
|
|
10
|
+
Output,
|
|
11
|
+
experimental_filterActiveTools as filterActiveTools,
|
|
11
12
|
type FinishReason,
|
|
12
13
|
type LanguageModelResponseMetadata,
|
|
13
14
|
type LanguageModelUsage,
|
|
15
|
+
type Experimental_LanguageModelStreamPart as ModelCallStreamPart,
|
|
14
16
|
type ModelMessage,
|
|
15
|
-
Output,
|
|
16
17
|
type StepResult,
|
|
17
18
|
type StopCondition,
|
|
18
|
-
type
|
|
19
|
+
type GenerateTextOnStepFinishCallback,
|
|
19
20
|
type SystemModelMessage,
|
|
21
|
+
type ActiveTools,
|
|
20
22
|
type ToolCallRepairFunction,
|
|
21
23
|
type ToolChoice,
|
|
22
24
|
type ToolSet,
|
|
23
25
|
type UIMessage,
|
|
24
|
-
LanguageModel,
|
|
26
|
+
type LanguageModel,
|
|
27
|
+
type Prompt,
|
|
25
28
|
} from 'ai';
|
|
26
29
|
import {
|
|
27
30
|
convertToLanguageModelPrompt,
|
|
@@ -30,19 +33,18 @@ import {
|
|
|
30
33
|
standardizePrompt,
|
|
31
34
|
} from 'ai/internal';
|
|
32
35
|
import { streamTextIterator } from './stream-text-iterator.js';
|
|
33
|
-
import type { CompatibleLanguageModel } from './types.js';
|
|
34
36
|
|
|
35
37
|
// Re-export for consumers
|
|
36
38
|
export type { CompatibleLanguageModel } from './types.js';
|
|
37
39
|
|
|
38
40
|
/**
|
|
39
41
|
* Callback function to be called after each step completes.
|
|
40
|
-
* Alias for the AI SDK's
|
|
42
|
+
* Alias for the AI SDK's GenerateTextOnStepFinishCallback, using
|
|
41
43
|
* WorkflowAgent-consistent naming.
|
|
42
44
|
*/
|
|
43
45
|
export type WorkflowAgentOnStepFinishCallback<
|
|
44
46
|
TTools extends ToolSet = ToolSet,
|
|
45
|
-
> =
|
|
47
|
+
> = GenerateTextOnStepFinishCallback<TTools, any>;
|
|
46
48
|
|
|
47
49
|
/**
|
|
48
50
|
* Infer the type of the tools of a workflow agent.
|
|
@@ -92,7 +94,7 @@ export type ProviderOptions = SharedV4ProviderOptions;
|
|
|
92
94
|
/**
|
|
93
95
|
* Telemetry settings for observability.
|
|
94
96
|
*/
|
|
95
|
-
export interface
|
|
97
|
+
export interface TelemetryOptions {
|
|
96
98
|
/**
|
|
97
99
|
* Enable or disable telemetry. Defaults to true.
|
|
98
100
|
*/
|
|
@@ -339,7 +341,11 @@ export interface PrepareCallOptions<
|
|
|
339
341
|
tools: TTools;
|
|
340
342
|
instructions?: string | SystemModelMessage | Array<SystemModelMessage>;
|
|
341
343
|
toolChoice?: ToolChoice<TTools>;
|
|
342
|
-
|
|
344
|
+
telemetry?: TelemetryOptions;
|
|
345
|
+
/**
|
|
346
|
+
* @deprecated Use `telemetry` instead. This alias will be removed in a future major release.
|
|
347
|
+
*/
|
|
348
|
+
experimental_telemetry?: TelemetryOptions;
|
|
343
349
|
experimental_context?: unknown;
|
|
344
350
|
messages: ModelMessage[];
|
|
345
351
|
}
|
|
@@ -367,6 +373,11 @@ export type PrepareCallCallback<TTools extends ToolSet = ToolSet> = (
|
|
|
367
373
|
export interface WorkflowAgentOptions<
|
|
368
374
|
TTools extends ToolSet = ToolSet,
|
|
369
375
|
> extends GenerationSettings {
|
|
376
|
+
/**
|
|
377
|
+
* The id of the agent.
|
|
378
|
+
*/
|
|
379
|
+
id?: string;
|
|
380
|
+
|
|
370
381
|
/**
|
|
371
382
|
* The model provider to use for the agent.
|
|
372
383
|
*
|
|
@@ -400,9 +411,16 @@ export interface WorkflowAgentOptions<
|
|
|
400
411
|
toolChoice?: ToolChoice<TTools>;
|
|
401
412
|
|
|
402
413
|
/**
|
|
403
|
-
* Optional telemetry configuration
|
|
414
|
+
* Optional telemetry configuration.
|
|
404
415
|
*/
|
|
405
|
-
|
|
416
|
+
telemetry?: TelemetryOptions;
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Optional telemetry configuration.
|
|
420
|
+
*
|
|
421
|
+
* @deprecated Use `telemetry` instead. This alias will be removed in a future major release.
|
|
422
|
+
*/
|
|
423
|
+
experimental_telemetry?: TelemetryOptions;
|
|
406
424
|
|
|
407
425
|
/**
|
|
408
426
|
* Default context that is passed into tool execution for every stream call on this agent.
|
|
@@ -413,6 +431,46 @@ export interface WorkflowAgentOptions<
|
|
|
413
431
|
*/
|
|
414
432
|
experimental_context?: unknown;
|
|
415
433
|
|
|
434
|
+
/**
|
|
435
|
+
* Default stop condition for the agent loop. When the condition is an array,
|
|
436
|
+
* any of the conditions can be met to stop the generation.
|
|
437
|
+
*
|
|
438
|
+
* Per-stream `stopWhen` values passed to `stream()` override this default.
|
|
439
|
+
*/
|
|
440
|
+
stopWhen?:
|
|
441
|
+
| StopCondition<NoInfer<ToolSet>, any>
|
|
442
|
+
| Array<StopCondition<NoInfer<ToolSet>, any>>;
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Default set of active tools that limits which tools the model can call,
|
|
446
|
+
* without changing the tool call and result types in the result.
|
|
447
|
+
*
|
|
448
|
+
* Per-stream `activeTools` values passed to `stream()` override this default.
|
|
449
|
+
*/
|
|
450
|
+
activeTools?: ActiveTools<NoInfer<TTools>>;
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Default output specification for structured outputs.
|
|
454
|
+
* Use `Output.object({ schema })` for structured output or `Output.text()` for text output.
|
|
455
|
+
*
|
|
456
|
+
* Per-stream `output` values passed to `stream()` override this default.
|
|
457
|
+
*/
|
|
458
|
+
output?: OutputSpecification<any, any>;
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Default function that attempts to repair a tool call that failed to parse.
|
|
462
|
+
*
|
|
463
|
+
* Per-stream `experimental_repairToolCall` values passed to `stream()` override this default.
|
|
464
|
+
*/
|
|
465
|
+
experimental_repairToolCall?: ToolCallRepairFunction<TTools>;
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Default custom download function to use for URLs.
|
|
469
|
+
*
|
|
470
|
+
* Per-stream `experimental_download` values passed to `stream()` override this default.
|
|
471
|
+
*/
|
|
472
|
+
experimental_download?: DownloadFunction;
|
|
473
|
+
|
|
416
474
|
/**
|
|
417
475
|
* Default callback function called before each step in the agent loop.
|
|
418
476
|
* Use this to modify settings, manage context, or inject messages dynamically
|
|
@@ -445,12 +503,12 @@ export interface WorkflowAgentOptions<
|
|
|
445
503
|
/**
|
|
446
504
|
* Callback called before a tool's execute function runs.
|
|
447
505
|
*/
|
|
448
|
-
|
|
506
|
+
experimental_onToolExecutionStart?: WorkflowAgentOnToolExecutionStartCallback;
|
|
449
507
|
|
|
450
508
|
/**
|
|
451
509
|
* Callback called after a tool execution completes.
|
|
452
510
|
*/
|
|
453
|
-
|
|
511
|
+
experimental_onToolExecutionEnd?: WorkflowAgentOnToolExecutionEndCallback;
|
|
454
512
|
|
|
455
513
|
/**
|
|
456
514
|
* Prepare the parameters for the stream call.
|
|
@@ -535,250 +593,305 @@ export type WorkflowAgentOnStartCallback = (event: {
|
|
|
535
593
|
/**
|
|
536
594
|
* Callback that is called before each step (LLM call) begins.
|
|
537
595
|
*/
|
|
538
|
-
export type WorkflowAgentOnStepStartCallback =
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
596
|
+
export type WorkflowAgentOnStepStartCallback<TTools extends ToolSet = ToolSet> =
|
|
597
|
+
(event: {
|
|
598
|
+
/** The current step number (0-based) */
|
|
599
|
+
readonly stepNumber: number;
|
|
600
|
+
/** The model being used for this step */
|
|
601
|
+
readonly model: LanguageModel;
|
|
602
|
+
/** The messages being sent for this step */
|
|
603
|
+
readonly messages: ModelMessage[];
|
|
604
|
+
/** Results from all previously finished steps */
|
|
605
|
+
readonly steps: ReadonlyArray<StepResult<TTools, any>>;
|
|
606
|
+
}) => PromiseLike<void> | void;
|
|
546
607
|
|
|
547
608
|
/**
|
|
548
609
|
* Callback that is called before a tool's execute function runs.
|
|
549
610
|
*/
|
|
550
|
-
export type
|
|
611
|
+
export type WorkflowAgentOnToolExecutionStartCallback = (event: {
|
|
551
612
|
/** The tool call being executed */
|
|
552
613
|
readonly toolCall: ToolCall;
|
|
614
|
+
/** The current step number (0-based) */
|
|
615
|
+
readonly stepNumber: number;
|
|
553
616
|
}) => PromiseLike<void> | void;
|
|
554
617
|
|
|
555
618
|
/**
|
|
556
619
|
* Callback that is called after a tool execution completes.
|
|
620
|
+
* Uses a discriminated union pattern: check `success` to determine
|
|
621
|
+
* whether `output` or `error` is available.
|
|
557
622
|
*/
|
|
558
|
-
export type
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
623
|
+
export type WorkflowAgentOnToolExecutionEndCallback = (
|
|
624
|
+
event:
|
|
625
|
+
| {
|
|
626
|
+
/** The tool call that was executed */
|
|
627
|
+
readonly toolCall: ToolCall;
|
|
628
|
+
/** The current step number (0-based) */
|
|
629
|
+
readonly stepNumber: number;
|
|
630
|
+
/** Execution time in milliseconds */
|
|
631
|
+
readonly durationMs: number;
|
|
632
|
+
/** Whether the tool call succeeded */
|
|
633
|
+
readonly success: true;
|
|
634
|
+
/** The tool result */
|
|
635
|
+
readonly output: unknown;
|
|
636
|
+
readonly error?: never;
|
|
637
|
+
}
|
|
638
|
+
| {
|
|
639
|
+
/** The tool call that was executed */
|
|
640
|
+
readonly toolCall: ToolCall;
|
|
641
|
+
/** The current step number (0-based) */
|
|
642
|
+
readonly stepNumber: number;
|
|
643
|
+
/** Execution time in milliseconds */
|
|
644
|
+
readonly durationMs: number;
|
|
645
|
+
/** Whether the tool call succeeded */
|
|
646
|
+
readonly success: false;
|
|
647
|
+
/** The error that occurred */
|
|
648
|
+
readonly error: unknown;
|
|
649
|
+
readonly output?: never;
|
|
650
|
+
},
|
|
651
|
+
) => PromiseLike<void> | void;
|
|
566
652
|
|
|
567
653
|
/**
|
|
568
654
|
* Options for the {@link WorkflowAgent.stream} method.
|
|
569
655
|
*/
|
|
570
|
-
export
|
|
656
|
+
export type WorkflowAgentStreamOptions<
|
|
571
657
|
TTools extends ToolSet = ToolSet,
|
|
572
658
|
OUTPUT = never,
|
|
573
659
|
PARTIAL_OUTPUT = never,
|
|
574
|
-
>
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
660
|
+
> = Partial<GenerationSettings> &
|
|
661
|
+
(
|
|
662
|
+
| {
|
|
663
|
+
/**
|
|
664
|
+
* A prompt. It can be either a text prompt or a list of messages.
|
|
665
|
+
*
|
|
666
|
+
* You can either use `prompt` or `messages` but not both.
|
|
667
|
+
*/
|
|
668
|
+
prompt: string | Array<ModelMessage>;
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* A list of messages.
|
|
672
|
+
*
|
|
673
|
+
* You can either use `prompt` or `messages` but not both.
|
|
674
|
+
*/
|
|
675
|
+
messages?: never;
|
|
676
|
+
}
|
|
677
|
+
| {
|
|
678
|
+
/**
|
|
679
|
+
* The conversation messages to process. Should follow the AI SDK's ModelMessage format.
|
|
680
|
+
*
|
|
681
|
+
* You can either use `prompt` or `messages` but not both.
|
|
682
|
+
*/
|
|
683
|
+
messages: Array<ModelMessage>;
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* A prompt. It can be either a text prompt or a list of messages.
|
|
687
|
+
*
|
|
688
|
+
* You can either use `prompt` or `messages` but not both.
|
|
689
|
+
*/
|
|
690
|
+
prompt?: never;
|
|
691
|
+
}
|
|
692
|
+
) & {
|
|
693
|
+
/**
|
|
694
|
+
* Optional system prompt override. If provided, overrides the system prompt from the constructor.
|
|
695
|
+
*/
|
|
696
|
+
system?: string;
|
|
584
697
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
698
|
+
/**
|
|
699
|
+
* A WritableStream that receives raw LanguageModelV4StreamPart chunks in real-time
|
|
700
|
+
* as the model generates them. This enables streaming to the client without
|
|
701
|
+
* coupling WorkflowAgent to UIMessageChunk format.
|
|
702
|
+
*
|
|
703
|
+
* Convert to UIMessageChunks at the response boundary using
|
|
704
|
+
* `createUIMessageChunkTransform()` from `@ai-sdk/workflow`.
|
|
705
|
+
*
|
|
706
|
+
* @example
|
|
707
|
+
* ```typescript
|
|
708
|
+
* // In the workflow:
|
|
709
|
+
* await agent.stream({
|
|
710
|
+
* messages,
|
|
711
|
+
* writable: getWritable<ModelCallStreamPart>(),
|
|
712
|
+
* });
|
|
713
|
+
*
|
|
714
|
+
* // In the route handler:
|
|
715
|
+
* return createUIMessageStreamResponse({
|
|
716
|
+
* stream: run.readable.pipeThrough(createModelCallToUIChunkTransform()),
|
|
717
|
+
* });
|
|
718
|
+
* ```
|
|
719
|
+
*/
|
|
720
|
+
writable?: WritableStream<ModelCallStreamPart<ToolSet>>;
|
|
608
721
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
722
|
+
/**
|
|
723
|
+
* Condition for stopping the generation when there are tool results in the last step.
|
|
724
|
+
* When the condition is an array, any of the conditions can be met to stop the generation.
|
|
725
|
+
*/
|
|
726
|
+
stopWhen?:
|
|
727
|
+
| StopCondition<NoInfer<ToolSet>, any>
|
|
728
|
+
| Array<StopCondition<NoInfer<ToolSet>, any>>;
|
|
616
729
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
maxSteps?: number;
|
|
730
|
+
/**
|
|
731
|
+
* The tool choice strategy. Default: 'auto'.
|
|
732
|
+
* Overrides the toolChoice from the constructor if provided.
|
|
733
|
+
*/
|
|
734
|
+
toolChoice?: ToolChoice<TTools>;
|
|
623
735
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
736
|
+
/**
|
|
737
|
+
* Limits the tools that are available for the model to call without
|
|
738
|
+
* changing the tool call and result types in the result.
|
|
739
|
+
*/
|
|
740
|
+
activeTools?: ActiveTools<NoInfer<TTools>>;
|
|
629
741
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
activeTools?: Array<keyof NoInfer<TTools>>;
|
|
742
|
+
/**
|
|
743
|
+
* Optional telemetry configuration.
|
|
744
|
+
*/
|
|
745
|
+
telemetry?: TelemetryOptions;
|
|
635
746
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
747
|
+
/**
|
|
748
|
+
* Optional telemetry configuration.
|
|
749
|
+
*
|
|
750
|
+
* @deprecated Use `telemetry` instead. This alias will be removed in a future major release.
|
|
751
|
+
*/
|
|
752
|
+
experimental_telemetry?: TelemetryOptions;
|
|
640
753
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
754
|
+
/**
|
|
755
|
+
* Context that is passed into tool execution.
|
|
756
|
+
* Experimental (can break in patch releases).
|
|
757
|
+
* @default undefined
|
|
758
|
+
*/
|
|
759
|
+
experimental_context?: unknown;
|
|
647
760
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
761
|
+
/**
|
|
762
|
+
* Optional specification for parsing structured outputs from the LLM response.
|
|
763
|
+
* Use `Output.object({ schema })` for structured output or `Output.text()` for text output.
|
|
764
|
+
*
|
|
765
|
+
* @example
|
|
766
|
+
* ```typescript
|
|
767
|
+
* import { Output } from '@workflow/ai';
|
|
768
|
+
* import { z } from 'zod';
|
|
769
|
+
*
|
|
770
|
+
* const result = await agent.stream({
|
|
771
|
+
* messages: [...],
|
|
772
|
+
* writable: getWritable(),
|
|
773
|
+
* output: Output.object({
|
|
774
|
+
* schema: z.object({
|
|
775
|
+
* sentiment: z.enum(['positive', 'negative', 'neutral']),
|
|
776
|
+
* confidence: z.number(),
|
|
777
|
+
* }),
|
|
778
|
+
* }),
|
|
779
|
+
* });
|
|
780
|
+
*
|
|
781
|
+
* console.log(result.output); // { sentiment: 'positive', confidence: 0.95 }
|
|
782
|
+
* ```
|
|
783
|
+
*/
|
|
784
|
+
output?: OutputSpecification<OUTPUT, PARTIAL_OUTPUT>;
|
|
672
785
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
786
|
+
/**
|
|
787
|
+
* Whether to include raw chunks from the provider in the stream.
|
|
788
|
+
* When enabled, you will receive raw chunks with type 'raw' that contain the unprocessed data from the provider.
|
|
789
|
+
* This allows access to cutting-edge provider features not yet wrapped by the AI SDK.
|
|
790
|
+
* Defaults to false.
|
|
791
|
+
*/
|
|
792
|
+
includeRawChunks?: boolean;
|
|
680
793
|
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
794
|
+
/**
|
|
795
|
+
* A function that attempts to repair a tool call that failed to parse.
|
|
796
|
+
*/
|
|
797
|
+
experimental_repairToolCall?: ToolCallRepairFunction<TTools>;
|
|
685
798
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
799
|
+
/**
|
|
800
|
+
* Optional stream transformations.
|
|
801
|
+
* They are applied in the order they are provided.
|
|
802
|
+
* The stream transformations must maintain the stream structure for streamText to work correctly.
|
|
803
|
+
*/
|
|
804
|
+
experimental_transform?:
|
|
805
|
+
| StreamTextTransform<TTools>
|
|
806
|
+
| Array<StreamTextTransform<TTools>>;
|
|
694
807
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
808
|
+
/**
|
|
809
|
+
* Custom download function to use for URLs.
|
|
810
|
+
* By default, files are downloaded if the model does not support the URL for the given media type.
|
|
811
|
+
*/
|
|
812
|
+
experimental_download?: DownloadFunction;
|
|
700
813
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
814
|
+
/**
|
|
815
|
+
* Callback function to be called after each step completes.
|
|
816
|
+
*/
|
|
817
|
+
onStepFinish?: WorkflowAgentOnStepFinishCallback<TTools>;
|
|
705
818
|
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
819
|
+
/**
|
|
820
|
+
* Callback that is invoked when an error occurs during streaming.
|
|
821
|
+
* You can use it to log errors.
|
|
822
|
+
*/
|
|
823
|
+
onError?: WorkflowAgentOnErrorCallback;
|
|
711
824
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
825
|
+
/**
|
|
826
|
+
* Callback that is called when the LLM response and all request tool executions
|
|
827
|
+
* (for tools that have an `execute` function) are finished.
|
|
828
|
+
*/
|
|
829
|
+
onFinish?: WorkflowAgentOnFinishCallback<TTools, OUTPUT>;
|
|
717
830
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
831
|
+
/**
|
|
832
|
+
* Callback that is called when the operation is aborted.
|
|
833
|
+
*/
|
|
834
|
+
onAbort?: WorkflowAgentOnAbortCallback<TTools>;
|
|
722
835
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
836
|
+
/**
|
|
837
|
+
* Callback called when the agent starts streaming, before any LLM calls.
|
|
838
|
+
*/
|
|
839
|
+
experimental_onStart?: WorkflowAgentOnStartCallback;
|
|
727
840
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
841
|
+
/**
|
|
842
|
+
* Callback called before each step (LLM call) begins.
|
|
843
|
+
*/
|
|
844
|
+
experimental_onStepStart?: WorkflowAgentOnStepStartCallback;
|
|
732
845
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
846
|
+
/**
|
|
847
|
+
* Callback called before a tool's execute function runs.
|
|
848
|
+
*/
|
|
849
|
+
experimental_onToolExecutionStart?: WorkflowAgentOnToolExecutionStartCallback;
|
|
737
850
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
851
|
+
/**
|
|
852
|
+
* Callback called after a tool execution completes.
|
|
853
|
+
*/
|
|
854
|
+
experimental_onToolExecutionEnd?: WorkflowAgentOnToolExecutionEndCallback;
|
|
742
855
|
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
856
|
+
/**
|
|
857
|
+
* Callback function called before each step in the agent loop.
|
|
858
|
+
* Use this to modify settings, manage context, or inject messages dynamically.
|
|
859
|
+
*
|
|
860
|
+
* @example
|
|
861
|
+
* ```typescript
|
|
862
|
+
* prepareStep: async ({ messages, stepNumber }) => {
|
|
863
|
+
* // Inject messages from a queue
|
|
864
|
+
* const queuedMessages = await getQueuedMessages();
|
|
865
|
+
* if (queuedMessages.length > 0) {
|
|
866
|
+
* return {
|
|
867
|
+
* messages: [...messages, ...queuedMessages],
|
|
868
|
+
* };
|
|
869
|
+
* }
|
|
870
|
+
* return {};
|
|
871
|
+
* }
|
|
872
|
+
* ```
|
|
873
|
+
*/
|
|
874
|
+
prepareStep?: PrepareStepCallback<TTools>;
|
|
762
875
|
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
876
|
+
/**
|
|
877
|
+
* Timeout in milliseconds for the stream operation.
|
|
878
|
+
* When specified, creates an AbortSignal that will abort the operation after the given time.
|
|
879
|
+
* If both `timeout` and `abortSignal` are provided, whichever triggers first will abort.
|
|
880
|
+
*/
|
|
881
|
+
timeout?: number;
|
|
769
882
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
883
|
+
/**
|
|
884
|
+
* Whether to send a 'finish' chunk to the writable stream when streaming completes.
|
|
885
|
+
* @default true
|
|
886
|
+
*/
|
|
887
|
+
sendFinish?: boolean;
|
|
775
888
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
}
|
|
889
|
+
/**
|
|
890
|
+
* Whether to prevent the writable stream from being closed after streaming completes.
|
|
891
|
+
* @default false
|
|
892
|
+
*/
|
|
893
|
+
preventClose?: boolean;
|
|
894
|
+
};
|
|
782
895
|
|
|
783
896
|
/**
|
|
784
897
|
* A tool call made by the model. Matches the AI SDK's tool call shape.
|
|
@@ -889,6 +1002,11 @@ export interface WorkflowAgentStreamResult<
|
|
|
889
1002
|
* ```
|
|
890
1003
|
*/
|
|
891
1004
|
export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
1005
|
+
/**
|
|
1006
|
+
* The id of the agent.
|
|
1007
|
+
*/
|
|
1008
|
+
public readonly id: string | undefined;
|
|
1009
|
+
|
|
892
1010
|
private model: LanguageModel;
|
|
893
1011
|
/**
|
|
894
1012
|
* The tool set configured for this agent.
|
|
@@ -900,32 +1018,47 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
900
1018
|
| Array<SystemModelMessage>;
|
|
901
1019
|
private generationSettings: GenerationSettings;
|
|
902
1020
|
private toolChoice?: ToolChoice<TBaseTools>;
|
|
903
|
-
private telemetry?:
|
|
1021
|
+
private telemetry?: TelemetryOptions;
|
|
904
1022
|
private experimentalContext: unknown;
|
|
1023
|
+
private stopWhen?:
|
|
1024
|
+
| StopCondition<ToolSet, any>
|
|
1025
|
+
| Array<StopCondition<ToolSet, any>>;
|
|
1026
|
+
private activeTools?: ActiveTools<TBaseTools>;
|
|
1027
|
+
private output?: OutputSpecification<any, any>;
|
|
1028
|
+
private experimentalRepairToolCall?: ToolCallRepairFunction<TBaseTools>;
|
|
1029
|
+
private experimentalDownload?: DownloadFunction;
|
|
905
1030
|
private prepareStep?: PrepareStepCallback<TBaseTools>;
|
|
906
1031
|
private constructorOnStepFinish?: WorkflowAgentOnStepFinishCallback<ToolSet>;
|
|
907
1032
|
private constructorOnFinish?: WorkflowAgentOnFinishCallback<ToolSet>;
|
|
908
1033
|
private constructorOnStart?: WorkflowAgentOnStartCallback;
|
|
909
1034
|
private constructorOnStepStart?: WorkflowAgentOnStepStartCallback;
|
|
910
|
-
private
|
|
911
|
-
private
|
|
1035
|
+
private constructorOnToolExecutionStart?: WorkflowAgentOnToolExecutionStartCallback;
|
|
1036
|
+
private constructorOnToolExecutionEnd?: WorkflowAgentOnToolExecutionEndCallback;
|
|
912
1037
|
private prepareCall?: PrepareCallCallback<TBaseTools>;
|
|
913
1038
|
|
|
914
1039
|
constructor(options: WorkflowAgentOptions<TBaseTools>) {
|
|
1040
|
+
this.id = options.id;
|
|
915
1041
|
this.model = options.model;
|
|
916
1042
|
this.tools = (options.tools ?? {}) as TBaseTools;
|
|
917
1043
|
// `instructions` takes precedence over deprecated `system`
|
|
918
1044
|
this.instructions = options.instructions ?? options.system;
|
|
919
1045
|
this.toolChoice = options.toolChoice;
|
|
920
|
-
this.telemetry = options.experimental_telemetry;
|
|
1046
|
+
this.telemetry = options.telemetry ?? options.experimental_telemetry;
|
|
921
1047
|
this.experimentalContext = options.experimental_context;
|
|
1048
|
+
this.stopWhen = options.stopWhen;
|
|
1049
|
+
this.activeTools = options.activeTools;
|
|
1050
|
+
this.output = options.output;
|
|
1051
|
+
this.experimentalRepairToolCall = options.experimental_repairToolCall;
|
|
1052
|
+
this.experimentalDownload = options.experimental_download;
|
|
922
1053
|
this.prepareStep = options.prepareStep;
|
|
923
1054
|
this.constructorOnStepFinish = options.onStepFinish;
|
|
924
1055
|
this.constructorOnFinish = options.onFinish;
|
|
925
1056
|
this.constructorOnStart = options.experimental_onStart;
|
|
926
1057
|
this.constructorOnStepStart = options.experimental_onStepStart;
|
|
927
|
-
this.
|
|
928
|
-
|
|
1058
|
+
this.constructorOnToolExecutionStart =
|
|
1059
|
+
options.experimental_onToolExecutionStart;
|
|
1060
|
+
this.constructorOnToolExecutionEnd =
|
|
1061
|
+
options.experimental_onToolExecutionEnd;
|
|
929
1062
|
this.prepareCall = options.prepareCall;
|
|
930
1063
|
|
|
931
1064
|
// Extract generation settings
|
|
@@ -959,13 +1092,23 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
959
1092
|
// Call prepareCall to transform parameters before the agent loop
|
|
960
1093
|
let effectiveModel: LanguageModel = this.model;
|
|
961
1094
|
let effectiveInstructions = options.system ?? this.instructions;
|
|
962
|
-
let
|
|
1095
|
+
let effectivePrompt: string | Array<ModelMessage> | undefined =
|
|
1096
|
+
options.prompt;
|
|
1097
|
+
let effectiveMessages: Array<ModelMessage> | undefined = options.messages;
|
|
963
1098
|
let effectiveGenerationSettings = { ...this.generationSettings };
|
|
964
1099
|
let effectiveExperimentalContext =
|
|
965
1100
|
options.experimental_context ?? this.experimentalContext;
|
|
966
1101
|
let effectiveToolChoiceFromPrepare = options.toolChoice ?? this.toolChoice;
|
|
967
1102
|
let effectiveTelemetryFromPrepare =
|
|
968
|
-
options.experimental_telemetry ?? this.telemetry;
|
|
1103
|
+
options.telemetry ?? options.experimental_telemetry ?? this.telemetry;
|
|
1104
|
+
|
|
1105
|
+
// Resolve messages for prepareCall: use messages directly, or convert prompt
|
|
1106
|
+
const resolvedMessagesForPrepareCall: ModelMessage[] =
|
|
1107
|
+
effectiveMessages ??
|
|
1108
|
+
(typeof effectivePrompt === 'string'
|
|
1109
|
+
? [{ role: 'user' as const, content: effectivePrompt }]
|
|
1110
|
+
: (effectivePrompt as ModelMessage[])) ??
|
|
1111
|
+
[];
|
|
969
1112
|
|
|
970
1113
|
if (this.prepareCall) {
|
|
971
1114
|
const prepared = await this.prepareCall({
|
|
@@ -973,24 +1116,28 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
973
1116
|
tools: this.tools,
|
|
974
1117
|
instructions: effectiveInstructions,
|
|
975
1118
|
toolChoice: effectiveToolChoiceFromPrepare as ToolChoice<TBaseTools>,
|
|
1119
|
+
telemetry: effectiveTelemetryFromPrepare,
|
|
976
1120
|
experimental_telemetry: effectiveTelemetryFromPrepare,
|
|
977
1121
|
experimental_context: effectiveExperimentalContext,
|
|
978
|
-
messages:
|
|
1122
|
+
messages: resolvedMessagesForPrepareCall,
|
|
979
1123
|
...effectiveGenerationSettings,
|
|
980
1124
|
} as PrepareCallOptions<TBaseTools>);
|
|
981
1125
|
|
|
982
1126
|
if (prepared.model !== undefined) effectiveModel = prepared.model;
|
|
983
1127
|
if (prepared.instructions !== undefined)
|
|
984
1128
|
effectiveInstructions = prepared.instructions;
|
|
985
|
-
if (prepared.messages !== undefined)
|
|
986
|
-
effectiveMessages =
|
|
987
|
-
|
|
1129
|
+
if (prepared.messages !== undefined) {
|
|
1130
|
+
effectiveMessages = prepared.messages as Array<ModelMessage>;
|
|
1131
|
+
effectivePrompt = undefined; // messages from prepareCall take precedence
|
|
1132
|
+
}
|
|
988
1133
|
if (prepared.experimental_context !== undefined)
|
|
989
1134
|
effectiveExperimentalContext = prepared.experimental_context;
|
|
990
1135
|
if (prepared.toolChoice !== undefined)
|
|
991
1136
|
effectiveToolChoiceFromPrepare =
|
|
992
1137
|
prepared.toolChoice as ToolChoice<TBaseTools>;
|
|
993
|
-
if (prepared.
|
|
1138
|
+
if (prepared.telemetry !== undefined)
|
|
1139
|
+
effectiveTelemetryFromPrepare = prepared.telemetry;
|
|
1140
|
+
else if (prepared.experimental_telemetry !== undefined)
|
|
994
1141
|
effectiveTelemetryFromPrepare = prepared.experimental_telemetry;
|
|
995
1142
|
if (prepared.maxOutputTokens !== undefined)
|
|
996
1143
|
effectiveGenerationSettings.maxOutputTokens = prepared.maxOutputTokens;
|
|
@@ -1017,8 +1164,11 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1017
1164
|
|
|
1018
1165
|
const prompt = await standardizePrompt({
|
|
1019
1166
|
system: effectiveInstructions,
|
|
1020
|
-
|
|
1021
|
-
|
|
1167
|
+
allowSystemInMessages: true, // TODO: consider exposing this as a parameter
|
|
1168
|
+
...(effectivePrompt != null
|
|
1169
|
+
? { prompt: effectivePrompt }
|
|
1170
|
+
: { messages: effectiveMessages! }),
|
|
1171
|
+
} as Prompt);
|
|
1022
1172
|
|
|
1023
1173
|
// Process tool approval responses before starting the agent loop.
|
|
1024
1174
|
// This mirrors how stream-text.ts handles tool-approval-response parts:
|
|
@@ -1146,14 +1296,12 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1146
1296
|
const modelPrompt = await convertToLanguageModelPrompt({
|
|
1147
1297
|
prompt,
|
|
1148
1298
|
supportedUrls: {},
|
|
1149
|
-
download: options.experimental_download,
|
|
1299
|
+
download: options.experimental_download ?? this.experimentalDownload,
|
|
1150
1300
|
});
|
|
1151
1301
|
|
|
1152
1302
|
const effectiveAbortSignal = mergeAbortSignals(
|
|
1153
1303
|
options.abortSignal ?? effectiveGenerationSettings.abortSignal,
|
|
1154
|
-
options.timeout
|
|
1155
|
-
? AbortSignal.timeout(options.timeout)
|
|
1156
|
-
: undefined,
|
|
1304
|
+
options.timeout,
|
|
1157
1305
|
);
|
|
1158
1306
|
|
|
1159
1307
|
// Merge generation settings: constructor defaults < prepareCall < stream options
|
|
@@ -1210,13 +1358,13 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1210
1358
|
this.constructorOnStepStart,
|
|
1211
1359
|
options.experimental_onStepStart,
|
|
1212
1360
|
);
|
|
1213
|
-
const
|
|
1214
|
-
this.
|
|
1215
|
-
options.
|
|
1361
|
+
const mergedOnToolExecutionStart = mergeCallbacks(
|
|
1362
|
+
this.constructorOnToolExecutionStart,
|
|
1363
|
+
options.experimental_onToolExecutionStart,
|
|
1216
1364
|
);
|
|
1217
|
-
const
|
|
1218
|
-
this.
|
|
1219
|
-
options.
|
|
1365
|
+
const mergedOnToolExecutionEnd = mergeCallbacks(
|
|
1366
|
+
this.constructorOnToolExecutionEnd,
|
|
1367
|
+
options.experimental_onToolExecutionEnd,
|
|
1220
1368
|
);
|
|
1221
1369
|
|
|
1222
1370
|
// Determine effective tool choice
|
|
@@ -1225,10 +1373,14 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1225
1373
|
// Merge telemetry settings
|
|
1226
1374
|
const effectiveTelemetry = effectiveTelemetryFromPrepare;
|
|
1227
1375
|
|
|
1228
|
-
// Filter tools if activeTools is specified
|
|
1376
|
+
// Filter tools if activeTools is specified (stream-level overrides constructor default)
|
|
1377
|
+
const effectiveActiveTools = options.activeTools ?? this.activeTools;
|
|
1229
1378
|
const effectiveTools =
|
|
1230
|
-
|
|
1231
|
-
?
|
|
1379
|
+
effectiveActiveTools && effectiveActiveTools.length > 0
|
|
1380
|
+
? (filterActiveTools({
|
|
1381
|
+
tools: this.tools,
|
|
1382
|
+
activeTools: effectiveActiveTools,
|
|
1383
|
+
}) ?? this.tools)
|
|
1232
1384
|
: this.tools;
|
|
1233
1385
|
|
|
1234
1386
|
// Initialize context
|
|
@@ -1244,69 +1396,77 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1244
1396
|
if (mergedOnStart) {
|
|
1245
1397
|
await mergedOnStart({
|
|
1246
1398
|
model: effectiveModel,
|
|
1247
|
-
messages:
|
|
1399
|
+
messages: prompt.messages,
|
|
1248
1400
|
});
|
|
1249
1401
|
}
|
|
1250
1402
|
|
|
1251
|
-
// Helper to wrap executeTool with
|
|
1403
|
+
// Helper to wrap executeTool with onToolExecutionStart/onToolExecutionEnd callbacks
|
|
1252
1404
|
const executeToolWithCallbacks = async (
|
|
1253
1405
|
toolCall: { toolCallId: string; toolName: string; input: unknown },
|
|
1254
1406
|
tools: ToolSet,
|
|
1255
1407
|
messages: LanguageModelV4Prompt,
|
|
1256
1408
|
context?: unknown,
|
|
1409
|
+
currentStepNumber: number = 0,
|
|
1257
1410
|
): Promise<LanguageModelV4ToolResultPart> => {
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1411
|
+
const toolCallEvent: ToolCall = {
|
|
1412
|
+
type: 'tool-call',
|
|
1413
|
+
toolCallId: toolCall.toolCallId,
|
|
1414
|
+
toolName: toolCall.toolName,
|
|
1415
|
+
input: toolCall.input,
|
|
1416
|
+
};
|
|
1417
|
+
|
|
1418
|
+
if (mergedOnToolExecutionStart) {
|
|
1419
|
+
await mergedOnToolExecutionStart({
|
|
1420
|
+
toolCall: toolCallEvent,
|
|
1421
|
+
stepNumber: currentStepNumber,
|
|
1266
1422
|
});
|
|
1267
1423
|
}
|
|
1424
|
+
|
|
1425
|
+
const startTime = Date.now();
|
|
1268
1426
|
let result: LanguageModelV4ToolResultPart;
|
|
1269
1427
|
try {
|
|
1270
1428
|
result = await executeTool(toolCall, tools, messages, context);
|
|
1271
1429
|
} catch (err) {
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
},
|
|
1430
|
+
const durationMs = Date.now() - startTime;
|
|
1431
|
+
if (mergedOnToolExecutionEnd) {
|
|
1432
|
+
await mergedOnToolExecutionEnd({
|
|
1433
|
+
toolCall: toolCallEvent,
|
|
1434
|
+
stepNumber: currentStepNumber,
|
|
1435
|
+
durationMs,
|
|
1436
|
+
success: false,
|
|
1280
1437
|
error: err,
|
|
1281
1438
|
});
|
|
1282
1439
|
}
|
|
1283
1440
|
throw err;
|
|
1284
1441
|
}
|
|
1285
|
-
|
|
1442
|
+
|
|
1443
|
+
const durationMs = Date.now() - startTime;
|
|
1444
|
+
if (mergedOnToolExecutionEnd) {
|
|
1286
1445
|
const isError =
|
|
1287
1446
|
result.output &&
|
|
1288
1447
|
'type' in result.output &&
|
|
1289
1448
|
(result.output.type === 'error-text' ||
|
|
1290
1449
|
result.output.type === 'error-json');
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1450
|
+
if (isError) {
|
|
1451
|
+
await mergedOnToolExecutionEnd({
|
|
1452
|
+
toolCall: toolCallEvent,
|
|
1453
|
+
stepNumber: currentStepNumber,
|
|
1454
|
+
durationMs,
|
|
1455
|
+
success: false,
|
|
1456
|
+
error: 'value' in result.output ? result.output.value : undefined,
|
|
1457
|
+
});
|
|
1458
|
+
} else {
|
|
1459
|
+
await mergedOnToolExecutionEnd({
|
|
1460
|
+
toolCall: toolCallEvent,
|
|
1461
|
+
stepNumber: currentStepNumber,
|
|
1462
|
+
durationMs,
|
|
1463
|
+
success: true,
|
|
1464
|
+
output:
|
|
1465
|
+
result.output && 'value' in result.output
|
|
1466
|
+
? result.output.value
|
|
1467
|
+
: undefined,
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1310
1470
|
}
|
|
1311
1471
|
return result;
|
|
1312
1472
|
};
|
|
@@ -1317,7 +1477,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1317
1477
|
await options.onAbort({ steps });
|
|
1318
1478
|
}
|
|
1319
1479
|
return {
|
|
1320
|
-
messages:
|
|
1480
|
+
messages: prompt.messages,
|
|
1321
1481
|
steps,
|
|
1322
1482
|
toolCalls: [],
|
|
1323
1483
|
toolResults: [],
|
|
@@ -1330,8 +1490,8 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1330
1490
|
tools: effectiveTools as ToolSet,
|
|
1331
1491
|
writable: options.writable,
|
|
1332
1492
|
prompt: modelPrompt,
|
|
1333
|
-
stopConditions: options.stopWhen,
|
|
1334
|
-
|
|
1493
|
+
stopConditions: options.stopWhen ?? this.stopWhen,
|
|
1494
|
+
|
|
1335
1495
|
onStepFinish: mergedOnStepFinish,
|
|
1336
1496
|
onStepStart: mergedOnStepStart,
|
|
1337
1497
|
onError: options.onError,
|
|
@@ -1341,11 +1501,13 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1341
1501
|
generationSettings: mergedGenerationSettings,
|
|
1342
1502
|
toolChoice: effectiveToolChoice as ToolChoice<ToolSet>,
|
|
1343
1503
|
experimental_context: experimentalContext,
|
|
1344
|
-
|
|
1504
|
+
telemetry: effectiveTelemetry,
|
|
1345
1505
|
includeRawChunks: options.includeRawChunks ?? false,
|
|
1346
|
-
repairToolCall:
|
|
1347
|
-
|
|
1348
|
-
|
|
1506
|
+
repairToolCall: (options.experimental_repairToolCall ??
|
|
1507
|
+
this.experimentalRepairToolCall) as
|
|
1508
|
+
| ToolCallRepairFunction<ToolSet>
|
|
1509
|
+
| undefined,
|
|
1510
|
+
responseFormat: await (options.output ?? this.output)?.responseFormat,
|
|
1349
1511
|
});
|
|
1350
1512
|
|
|
1351
1513
|
// Track the final conversation messages from the iterator
|
|
@@ -1372,6 +1534,8 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1372
1534
|
context,
|
|
1373
1535
|
providerExecutedToolResults,
|
|
1374
1536
|
} = result.value;
|
|
1537
|
+
// Capture current step number before pushing (0-based)
|
|
1538
|
+
const currentStepNumber = steps.length;
|
|
1375
1539
|
if (step) {
|
|
1376
1540
|
steps.push(step as unknown as StepResult<TTools, any>);
|
|
1377
1541
|
}
|
|
@@ -1381,11 +1545,16 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1381
1545
|
|
|
1382
1546
|
// Only execute tools if there are tool calls
|
|
1383
1547
|
if (toolCalls.length > 0) {
|
|
1548
|
+
const invalidToolCalls = toolCalls.filter(tc => tc.invalid === true);
|
|
1549
|
+
const validToolCalls = toolCalls.filter(tc => tc.invalid !== true);
|
|
1550
|
+
|
|
1384
1551
|
// Separate provider-executed tool calls from client-executed ones
|
|
1385
|
-
const nonProviderToolCalls =
|
|
1552
|
+
const nonProviderToolCalls = validToolCalls.filter(
|
|
1386
1553
|
tc => !tc.providerExecuted,
|
|
1387
1554
|
);
|
|
1388
|
-
const providerToolCalls =
|
|
1555
|
+
const providerToolCalls = validToolCalls.filter(
|
|
1556
|
+
tc => tc.providerExecuted,
|
|
1557
|
+
);
|
|
1389
1558
|
|
|
1390
1559
|
// Check which tools need approval (can be async)
|
|
1391
1560
|
const approvalNeeded = await Promise.all(
|
|
@@ -1435,6 +1604,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1435
1604
|
effectiveTools as ToolSet,
|
|
1436
1605
|
iterMessages,
|
|
1437
1606
|
experimentalContext,
|
|
1607
|
+
currentStepNumber,
|
|
1438
1608
|
),
|
|
1439
1609
|
),
|
|
1440
1610
|
);
|
|
@@ -1448,7 +1618,15 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1448
1618
|
),
|
|
1449
1619
|
);
|
|
1450
1620
|
|
|
1451
|
-
const
|
|
1621
|
+
const continuationInvalidResults = invalidToolCalls.map(
|
|
1622
|
+
createInvalidToolResult,
|
|
1623
|
+
);
|
|
1624
|
+
const resolvedResults = [
|
|
1625
|
+
...executableResults,
|
|
1626
|
+
...providerResults,
|
|
1627
|
+
...continuationInvalidResults,
|
|
1628
|
+
];
|
|
1629
|
+
const executedResults = [...executableResults, ...providerResults];
|
|
1452
1630
|
|
|
1453
1631
|
const allToolCalls: ToolCall[] = toolCalls.map(tc => ({
|
|
1454
1632
|
type: 'tool-call' as const,
|
|
@@ -1457,7 +1635,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1457
1635
|
input: tc.input,
|
|
1458
1636
|
}));
|
|
1459
1637
|
|
|
1460
|
-
const allToolResults: ToolResult[] =
|
|
1638
|
+
const allToolResults: ToolResult[] = executedResults.map(r => ({
|
|
1461
1639
|
type: 'tool-result' as const,
|
|
1462
1640
|
toolCallId: r.toolCallId,
|
|
1463
1641
|
toolName: r.toolName,
|
|
@@ -1535,6 +1713,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1535
1713
|
effectiveTools as ToolSet,
|
|
1536
1714
|
iterMessages,
|
|
1537
1715
|
experimentalContext,
|
|
1716
|
+
currentStepNumber,
|
|
1538
1717
|
),
|
|
1539
1718
|
),
|
|
1540
1719
|
);
|
|
@@ -1544,25 +1723,32 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1544
1723
|
providerToolCalls.map(toolCall =>
|
|
1545
1724
|
resolveProviderToolResult(toolCall, providerExecutedToolResults),
|
|
1546
1725
|
);
|
|
1726
|
+
const continuationInvalidToolResults = invalidToolCalls.map(
|
|
1727
|
+
createInvalidToolResult,
|
|
1728
|
+
);
|
|
1547
1729
|
|
|
1548
|
-
// Combine results in the original order
|
|
1549
|
-
|
|
1730
|
+
// Combine executable/provider results in the original order,
|
|
1731
|
+
// while preserving invalid tool calls as error results for the
|
|
1732
|
+
// next model step without emitting them as synthetic UI success.
|
|
1733
|
+
const continuationToolResults = toolCalls.flatMap(tc => {
|
|
1734
|
+
const invalidResult = continuationInvalidToolResults.find(
|
|
1735
|
+
r => r.toolCallId === tc.toolCallId,
|
|
1736
|
+
);
|
|
1737
|
+
if (invalidResult) return [invalidResult];
|
|
1550
1738
|
const clientResult = clientToolResults.find(
|
|
1551
1739
|
r => r.toolCallId === tc.toolCallId,
|
|
1552
1740
|
);
|
|
1553
|
-
if (clientResult) return clientResult;
|
|
1741
|
+
if (clientResult) return [clientResult];
|
|
1554
1742
|
const providerResult = providerToolResults.find(
|
|
1555
1743
|
r => r.toolCallId === tc.toolCallId,
|
|
1556
1744
|
);
|
|
1557
|
-
if (providerResult) return providerResult;
|
|
1558
|
-
|
|
1559
|
-
return {
|
|
1560
|
-
type: 'tool-result' as const,
|
|
1561
|
-
toolCallId: tc.toolCallId,
|
|
1562
|
-
toolName: tc.toolName,
|
|
1563
|
-
output: { type: 'text' as const, value: '' },
|
|
1564
|
-
};
|
|
1745
|
+
if (providerResult) return [providerResult];
|
|
1746
|
+
return [];
|
|
1565
1747
|
});
|
|
1748
|
+
const executedToolResults = continuationToolResults.filter(
|
|
1749
|
+
result =>
|
|
1750
|
+
!invalidToolCalls.some(tc => tc.toolCallId === result.toolCallId),
|
|
1751
|
+
);
|
|
1566
1752
|
|
|
1567
1753
|
// Write tool results and step boundaries to the stream so the
|
|
1568
1754
|
// UI can transition tool parts to output-available state and
|
|
@@ -1570,7 +1756,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1570
1756
|
if (options.writable) {
|
|
1571
1757
|
await writeToolResultsWithStepBoundary(
|
|
1572
1758
|
options.writable,
|
|
1573
|
-
|
|
1759
|
+
executedToolResults.map(r => ({
|
|
1574
1760
|
toolCallId: r.toolCallId,
|
|
1575
1761
|
toolName: r.toolName,
|
|
1576
1762
|
input: toolCalls.find(tc => tc.toolCallId === r.toolCallId)
|
|
@@ -1587,7 +1773,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1587
1773
|
toolName: tc.toolName,
|
|
1588
1774
|
input: tc.input,
|
|
1589
1775
|
}));
|
|
1590
|
-
lastStepToolResults =
|
|
1776
|
+
lastStepToolResults = executedToolResults.map(r => ({
|
|
1591
1777
|
type: 'tool-result' as const,
|
|
1592
1778
|
toolCallId: r.toolCallId,
|
|
1593
1779
|
toolName: r.toolName,
|
|
@@ -1595,7 +1781,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1595
1781
|
output: 'value' in r.output ? r.output.value : undefined,
|
|
1596
1782
|
}));
|
|
1597
1783
|
|
|
1598
|
-
result = await iterator.next(
|
|
1784
|
+
result = await iterator.next(continuationToolResults);
|
|
1599
1785
|
} else {
|
|
1600
1786
|
// Final step with no tool calls - reset tracking
|
|
1601
1787
|
lastStepToolCalls = [];
|
|
@@ -1623,18 +1809,19 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
|
|
|
1623
1809
|
// Don't throw yet - we want to call onFinish first
|
|
1624
1810
|
}
|
|
1625
1811
|
|
|
1626
|
-
// Use the final messages from the iterator, or fall back to
|
|
1812
|
+
// Use the final messages from the iterator, or fall back to standardized messages
|
|
1627
1813
|
const messages = (finalMessages ??
|
|
1628
|
-
|
|
1814
|
+
prompt.messages) as unknown as ModelMessage[];
|
|
1629
1815
|
|
|
1630
|
-
// Parse structured output if output is specified
|
|
1816
|
+
// Parse structured output if output is specified (stream-level overrides constructor default)
|
|
1817
|
+
const effectiveOutput = options.output ?? this.output;
|
|
1631
1818
|
let experimentalOutput: OUTPUT = undefined as OUTPUT;
|
|
1632
|
-
if (
|
|
1819
|
+
if (effectiveOutput && steps.length > 0) {
|
|
1633
1820
|
const lastStep = steps[steps.length - 1];
|
|
1634
1821
|
const text = lastStep.text;
|
|
1635
1822
|
if (text) {
|
|
1636
1823
|
try {
|
|
1637
|
-
experimentalOutput = await
|
|
1824
|
+
experimentalOutput = await effectiveOutput.parseCompleteOutput(
|
|
1638
1825
|
{ text },
|
|
1639
1826
|
{
|
|
1640
1827
|
response: lastStep.response,
|
|
@@ -1832,19 +2019,6 @@ function aggregateUsage(steps: StepResult<any, any>[]): LanguageModelUsage {
|
|
|
1832
2019
|
} as LanguageModelUsage;
|
|
1833
2020
|
}
|
|
1834
2021
|
|
|
1835
|
-
function filterTools<TTools extends ToolSet>(
|
|
1836
|
-
tools: TTools,
|
|
1837
|
-
activeTools: string[],
|
|
1838
|
-
): ToolSet {
|
|
1839
|
-
const filtered: ToolSet = {};
|
|
1840
|
-
for (const toolName of activeTools) {
|
|
1841
|
-
if (toolName in tools) {
|
|
1842
|
-
filtered[toolName] = tools[toolName];
|
|
1843
|
-
}
|
|
1844
|
-
}
|
|
1845
|
-
return filtered;
|
|
1846
|
-
}
|
|
1847
|
-
|
|
1848
2022
|
// Matches AI SDK's getErrorMessage from @ai-sdk/provider-utils
|
|
1849
2023
|
function getErrorMessage(error: unknown): string {
|
|
1850
2024
|
if (error == null) {
|
|
@@ -1909,6 +2083,22 @@ function resolveProviderToolResult(
|
|
|
1909
2083
|
};
|
|
1910
2084
|
}
|
|
1911
2085
|
|
|
2086
|
+
function createInvalidToolResult(toolCall: {
|
|
2087
|
+
toolCallId: string;
|
|
2088
|
+
toolName: string;
|
|
2089
|
+
error?: unknown;
|
|
2090
|
+
}): LanguageModelV4ToolResultPart {
|
|
2091
|
+
return {
|
|
2092
|
+
type: 'tool-result' as const,
|
|
2093
|
+
toolCallId: toolCall.toolCallId,
|
|
2094
|
+
toolName: toolCall.toolName,
|
|
2095
|
+
output: {
|
|
2096
|
+
type: 'error-text' as const,
|
|
2097
|
+
value: getErrorMessage(toolCall.error),
|
|
2098
|
+
},
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
|
|
1912
2102
|
async function executeTool(
|
|
1913
2103
|
toolCall: { toolCallId: string; toolName: string; input: unknown },
|
|
1914
2104
|
tools: ToolSet,
|