@ai-sdk/workflow 1.0.0-beta.3 → 1.0.0-beta.5

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.
@@ -367,6 +367,11 @@ export type PrepareCallCallback<TTools extends ToolSet = ToolSet> = (
367
367
  export interface WorkflowAgentOptions<
368
368
  TTools extends ToolSet = ToolSet,
369
369
  > extends GenerationSettings {
370
+ /**
371
+ * The id of the agent.
372
+ */
373
+ id?: string;
374
+
370
375
  /**
371
376
  * The model provider to use for the agent.
372
377
  *
@@ -413,6 +418,46 @@ export interface WorkflowAgentOptions<
413
418
  */
414
419
  experimental_context?: unknown;
415
420
 
421
+ /**
422
+ * Default stop condition for the agent loop. When the condition is an array,
423
+ * any of the conditions can be met to stop the generation.
424
+ *
425
+ * Per-stream `stopWhen` values passed to `stream()` override this default.
426
+ */
427
+ stopWhen?:
428
+ | StopCondition<NoInfer<ToolSet>, any>
429
+ | Array<StopCondition<NoInfer<ToolSet>, any>>;
430
+
431
+ /**
432
+ * Default set of active tools that limits which tools the model can call,
433
+ * without changing the tool call and result types in the result.
434
+ *
435
+ * Per-stream `activeTools` values passed to `stream()` override this default.
436
+ */
437
+ activeTools?: Array<keyof NoInfer<TTools>>;
438
+
439
+ /**
440
+ * Default output specification for structured outputs.
441
+ * Use `Output.object({ schema })` for structured output or `Output.text()` for text output.
442
+ *
443
+ * Per-stream `output` values passed to `stream()` override this default.
444
+ */
445
+ output?: OutputSpecification<any, any>;
446
+
447
+ /**
448
+ * Default function that attempts to repair a tool call that failed to parse.
449
+ *
450
+ * Per-stream `experimental_repairToolCall` values passed to `stream()` override this default.
451
+ */
452
+ experimental_repairToolCall?: ToolCallRepairFunction<TTools>;
453
+
454
+ /**
455
+ * Default custom download function to use for URLs.
456
+ *
457
+ * Per-stream `experimental_download` values passed to `stream()` override this default.
458
+ */
459
+ experimental_download?: DownloadFunction;
460
+
416
461
  /**
417
462
  * Default callback function called before each step in the agent loop.
418
463
  * Use this to modify settings, manage context, or inject messages dynamically
@@ -567,218 +612,245 @@ export type WorkflowAgentOnToolCallFinishCallback = (event: {
567
612
  /**
568
613
  * Options for the {@link WorkflowAgent.stream} method.
569
614
  */
570
- export interface WorkflowAgentStreamOptions<
615
+ export type WorkflowAgentStreamOptions<
571
616
  TTools extends ToolSet = ToolSet,
572
617
  OUTPUT = never,
573
618
  PARTIAL_OUTPUT = never,
574
- > extends Partial<GenerationSettings> {
575
- /**
576
- * The conversation messages to process. Should follow the AI SDK's ModelMessage format.
577
- */
578
- messages: ModelMessage[];
579
-
580
- /**
581
- * Optional system prompt override. If provided, overrides the system prompt from the constructor.
582
- */
583
- system?: string;
619
+ > = Partial<GenerationSettings> &
620
+ (
621
+ | {
622
+ /**
623
+ * A prompt. It can be either a text prompt or a list of messages.
624
+ *
625
+ * You can either use `prompt` or `messages` but not both.
626
+ */
627
+ prompt: string | Array<ModelMessage>;
628
+
629
+ /**
630
+ * A list of messages.
631
+ *
632
+ * You can either use `prompt` or `messages` but not both.
633
+ */
634
+ messages?: never;
635
+ }
636
+ | {
637
+ /**
638
+ * The conversation messages to process. Should follow the AI SDK's ModelMessage format.
639
+ *
640
+ * You can either use `prompt` or `messages` but not both.
641
+ */
642
+ messages: Array<ModelMessage>;
643
+
644
+ /**
645
+ * A prompt. It can be either a text prompt or a list of messages.
646
+ *
647
+ * You can either use `prompt` or `messages` but not both.
648
+ */
649
+ prompt?: never;
650
+ }
651
+ ) & {
652
+ /**
653
+ * Optional system prompt override. If provided, overrides the system prompt from the constructor.
654
+ */
655
+ system?: string;
584
656
 
585
- /**
586
- * A WritableStream that receives raw LanguageModelV4StreamPart chunks in real-time
587
- * as the model generates them. This enables streaming to the client without
588
- * coupling WorkflowAgent to UIMessageChunk format.
589
- *
590
- * Convert to UIMessageChunks at the response boundary using
591
- * `createUIMessageChunkTransform()` from `@ai-sdk/workflow`.
592
- *
593
- * @example
594
- * ```typescript
595
- * // In the workflow:
596
- * await agent.stream({
597
- * messages,
598
- * writable: getWritable<ModelCallStreamPart>(),
599
- * });
600
- *
601
- * // In the route handler:
602
- * return createUIMessageStreamResponse({
603
- * stream: run.readable.pipeThrough(createModelCallToUIChunkTransform()),
604
- * });
605
- * ```
606
- */
607
- writable?: WritableStream<ModelCallStreamPart<ToolSet>>;
657
+ /**
658
+ * A WritableStream that receives raw LanguageModelV4StreamPart chunks in real-time
659
+ * as the model generates them. This enables streaming to the client without
660
+ * coupling WorkflowAgent to UIMessageChunk format.
661
+ *
662
+ * Convert to UIMessageChunks at the response boundary using
663
+ * `createUIMessageChunkTransform()` from `@ai-sdk/workflow`.
664
+ *
665
+ * @example
666
+ * ```typescript
667
+ * // In the workflow:
668
+ * await agent.stream({
669
+ * messages,
670
+ * writable: getWritable<ModelCallStreamPart>(),
671
+ * });
672
+ *
673
+ * // In the route handler:
674
+ * return createUIMessageStreamResponse({
675
+ * stream: run.readable.pipeThrough(createModelCallToUIChunkTransform()),
676
+ * });
677
+ * ```
678
+ */
679
+ writable?: WritableStream<ModelCallStreamPart<ToolSet>>;
608
680
 
609
- /**
610
- * Condition for stopping the generation when there are tool results in the last step.
611
- * When the condition is an array, any of the conditions can be met to stop the generation.
612
- */
613
- stopWhen?:
614
- | StopCondition<NoInfer<ToolSet>, any>
615
- | Array<StopCondition<NoInfer<ToolSet>, any>>;
681
+ /**
682
+ * Condition for stopping the generation when there are tool results in the last step.
683
+ * When the condition is an array, any of the conditions can be met to stop the generation.
684
+ */
685
+ stopWhen?:
686
+ | StopCondition<NoInfer<ToolSet>, any>
687
+ | Array<StopCondition<NoInfer<ToolSet>, any>>;
616
688
 
617
- /**
618
- * Maximum number of sequential LLM calls (steps), e.g. when you use tool calls.
619
- * A maximum number can be set to prevent infinite loops in the case of misconfigured tools.
620
- * By default, it's unlimited (the agent loops until completion).
621
- */
622
- maxSteps?: number;
689
+ /**
690
+ * Maximum number of sequential LLM calls (steps), e.g. when you use tool calls.
691
+ * A maximum number can be set to prevent infinite loops in the case of misconfigured tools.
692
+ * By default, it's unlimited (the agent loops until completion).
693
+ */
694
+ maxSteps?: number;
623
695
 
624
- /**
625
- * The tool choice strategy. Default: 'auto'.
626
- * Overrides the toolChoice from the constructor if provided.
627
- */
628
- toolChoice?: ToolChoice<TTools>;
696
+ /**
697
+ * The tool choice strategy. Default: 'auto'.
698
+ * Overrides the toolChoice from the constructor if provided.
699
+ */
700
+ toolChoice?: ToolChoice<TTools>;
629
701
 
630
- /**
631
- * Limits the tools that are available for the model to call without
632
- * changing the tool call and result types in the result.
633
- */
634
- activeTools?: Array<keyof NoInfer<TTools>>;
702
+ /**
703
+ * Limits the tools that are available for the model to call without
704
+ * changing the tool call and result types in the result.
705
+ */
706
+ activeTools?: Array<keyof NoInfer<TTools>>;
635
707
 
636
- /**
637
- * Optional telemetry configuration (experimental).
638
- */
639
- experimental_telemetry?: TelemetrySettings;
708
+ /**
709
+ * Optional telemetry configuration (experimental).
710
+ */
711
+ experimental_telemetry?: TelemetrySettings;
640
712
 
641
- /**
642
- * Context that is passed into tool execution.
643
- * Experimental (can break in patch releases).
644
- * @default undefined
645
- */
646
- experimental_context?: unknown;
713
+ /**
714
+ * Context that is passed into tool execution.
715
+ * Experimental (can break in patch releases).
716
+ * @default undefined
717
+ */
718
+ experimental_context?: unknown;
647
719
 
648
- /**
649
- * Optional specification for parsing structured outputs from the LLM response.
650
- * Use `Output.object({ schema })` for structured output or `Output.text()` for text output.
651
- *
652
- * @example
653
- * ```typescript
654
- * import { Output } from '@workflow/ai';
655
- * import { z } from 'zod';
656
- *
657
- * const result = await agent.stream({
658
- * messages: [...],
659
- * writable: getWritable(),
660
- * output: Output.object({
661
- * schema: z.object({
662
- * sentiment: z.enum(['positive', 'negative', 'neutral']),
663
- * confidence: z.number(),
664
- * }),
665
- * }),
666
- * });
667
- *
668
- * console.log(result.output); // { sentiment: 'positive', confidence: 0.95 }
669
- * ```
670
- */
671
- output?: OutputSpecification<OUTPUT, PARTIAL_OUTPUT>;
720
+ /**
721
+ * Optional specification for parsing structured outputs from the LLM response.
722
+ * Use `Output.object({ schema })` for structured output or `Output.text()` for text output.
723
+ *
724
+ * @example
725
+ * ```typescript
726
+ * import { Output } from '@workflow/ai';
727
+ * import { z } from 'zod';
728
+ *
729
+ * const result = await agent.stream({
730
+ * messages: [...],
731
+ * writable: getWritable(),
732
+ * output: Output.object({
733
+ * schema: z.object({
734
+ * sentiment: z.enum(['positive', 'negative', 'neutral']),
735
+ * confidence: z.number(),
736
+ * }),
737
+ * }),
738
+ * });
739
+ *
740
+ * console.log(result.output); // { sentiment: 'positive', confidence: 0.95 }
741
+ * ```
742
+ */
743
+ output?: OutputSpecification<OUTPUT, PARTIAL_OUTPUT>;
672
744
 
673
- /**
674
- * Whether to include raw chunks from the provider in the stream.
675
- * When enabled, you will receive raw chunks with type 'raw' that contain the unprocessed data from the provider.
676
- * This allows access to cutting-edge provider features not yet wrapped by the AI SDK.
677
- * Defaults to false.
678
- */
679
- includeRawChunks?: boolean;
745
+ /**
746
+ * Whether to include raw chunks from the provider in the stream.
747
+ * When enabled, you will receive raw chunks with type 'raw' that contain the unprocessed data from the provider.
748
+ * This allows access to cutting-edge provider features not yet wrapped by the AI SDK.
749
+ * Defaults to false.
750
+ */
751
+ includeRawChunks?: boolean;
680
752
 
681
- /**
682
- * A function that attempts to repair a tool call that failed to parse.
683
- */
684
- experimental_repairToolCall?: ToolCallRepairFunction<TTools>;
753
+ /**
754
+ * A function that attempts to repair a tool call that failed to parse.
755
+ */
756
+ experimental_repairToolCall?: ToolCallRepairFunction<TTools>;
685
757
 
686
- /**
687
- * Optional stream transformations.
688
- * They are applied in the order they are provided.
689
- * The stream transformations must maintain the stream structure for streamText to work correctly.
690
- */
691
- experimental_transform?:
692
- | StreamTextTransform<TTools>
693
- | Array<StreamTextTransform<TTools>>;
758
+ /**
759
+ * Optional stream transformations.
760
+ * They are applied in the order they are provided.
761
+ * The stream transformations must maintain the stream structure for streamText to work correctly.
762
+ */
763
+ experimental_transform?:
764
+ | StreamTextTransform<TTools>
765
+ | Array<StreamTextTransform<TTools>>;
694
766
 
695
- /**
696
- * Custom download function to use for URLs.
697
- * By default, files are downloaded if the model does not support the URL for the given media type.
698
- */
699
- experimental_download?: DownloadFunction;
767
+ /**
768
+ * Custom download function to use for URLs.
769
+ * By default, files are downloaded if the model does not support the URL for the given media type.
770
+ */
771
+ experimental_download?: DownloadFunction;
700
772
 
701
- /**
702
- * Callback function to be called after each step completes.
703
- */
704
- onStepFinish?: WorkflowAgentOnStepFinishCallback<TTools>;
773
+ /**
774
+ * Callback function to be called after each step completes.
775
+ */
776
+ onStepFinish?: WorkflowAgentOnStepFinishCallback<TTools>;
705
777
 
706
- /**
707
- * Callback that is invoked when an error occurs during streaming.
708
- * You can use it to log errors.
709
- */
710
- onError?: WorkflowAgentOnErrorCallback;
778
+ /**
779
+ * Callback that is invoked when an error occurs during streaming.
780
+ * You can use it to log errors.
781
+ */
782
+ onError?: WorkflowAgentOnErrorCallback;
711
783
 
712
- /**
713
- * Callback that is called when the LLM response and all request tool executions
714
- * (for tools that have an `execute` function) are finished.
715
- */
716
- onFinish?: WorkflowAgentOnFinishCallback<TTools, OUTPUT>;
784
+ /**
785
+ * Callback that is called when the LLM response and all request tool executions
786
+ * (for tools that have an `execute` function) are finished.
787
+ */
788
+ onFinish?: WorkflowAgentOnFinishCallback<TTools, OUTPUT>;
717
789
 
718
- /**
719
- * Callback that is called when the operation is aborted.
720
- */
721
- onAbort?: WorkflowAgentOnAbortCallback<TTools>;
790
+ /**
791
+ * Callback that is called when the operation is aborted.
792
+ */
793
+ onAbort?: WorkflowAgentOnAbortCallback<TTools>;
722
794
 
723
- /**
724
- * Callback called when the agent starts streaming, before any LLM calls.
725
- */
726
- experimental_onStart?: WorkflowAgentOnStartCallback;
795
+ /**
796
+ * Callback called when the agent starts streaming, before any LLM calls.
797
+ */
798
+ experimental_onStart?: WorkflowAgentOnStartCallback;
727
799
 
728
- /**
729
- * Callback called before each step (LLM call) begins.
730
- */
731
- experimental_onStepStart?: WorkflowAgentOnStepStartCallback;
800
+ /**
801
+ * Callback called before each step (LLM call) begins.
802
+ */
803
+ experimental_onStepStart?: WorkflowAgentOnStepStartCallback;
732
804
 
733
- /**
734
- * Callback called before a tool's execute function runs.
735
- */
736
- experimental_onToolCallStart?: WorkflowAgentOnToolCallStartCallback;
805
+ /**
806
+ * Callback called before a tool's execute function runs.
807
+ */
808
+ experimental_onToolCallStart?: WorkflowAgentOnToolCallStartCallback;
737
809
 
738
- /**
739
- * Callback called after a tool execution completes.
740
- */
741
- experimental_onToolCallFinish?: WorkflowAgentOnToolCallFinishCallback;
810
+ /**
811
+ * Callback called after a tool execution completes.
812
+ */
813
+ experimental_onToolCallFinish?: WorkflowAgentOnToolCallFinishCallback;
742
814
 
743
- /**
744
- * Callback function called before each step in the agent loop.
745
- * Use this to modify settings, manage context, or inject messages dynamically.
746
- *
747
- * @example
748
- * ```typescript
749
- * prepareStep: async ({ messages, stepNumber }) => {
750
- * // Inject messages from a queue
751
- * const queuedMessages = await getQueuedMessages();
752
- * if (queuedMessages.length > 0) {
753
- * return {
754
- * messages: [...messages, ...queuedMessages],
755
- * };
756
- * }
757
- * return {};
758
- * }
759
- * ```
760
- */
761
- prepareStep?: PrepareStepCallback<TTools>;
815
+ /**
816
+ * Callback function called before each step in the agent loop.
817
+ * Use this to modify settings, manage context, or inject messages dynamically.
818
+ *
819
+ * @example
820
+ * ```typescript
821
+ * prepareStep: async ({ messages, stepNumber }) => {
822
+ * // Inject messages from a queue
823
+ * const queuedMessages = await getQueuedMessages();
824
+ * if (queuedMessages.length > 0) {
825
+ * return {
826
+ * messages: [...messages, ...queuedMessages],
827
+ * };
828
+ * }
829
+ * return {};
830
+ * }
831
+ * ```
832
+ */
833
+ prepareStep?: PrepareStepCallback<TTools>;
762
834
 
763
- /**
764
- * Timeout in milliseconds for the stream operation.
765
- * When specified, creates an AbortSignal that will abort the operation after the given time.
766
- * If both `timeout` and `abortSignal` are provided, whichever triggers first will abort.
767
- */
768
- timeout?: number;
835
+ /**
836
+ * Timeout in milliseconds for the stream operation.
837
+ * When specified, creates an AbortSignal that will abort the operation after the given time.
838
+ * If both `timeout` and `abortSignal` are provided, whichever triggers first will abort.
839
+ */
840
+ timeout?: number;
769
841
 
770
- /**
771
- * Whether to send a 'finish' chunk to the writable stream when streaming completes.
772
- * @default true
773
- */
774
- sendFinish?: boolean;
842
+ /**
843
+ * Whether to send a 'finish' chunk to the writable stream when streaming completes.
844
+ * @default true
845
+ */
846
+ sendFinish?: boolean;
775
847
 
776
- /**
777
- * Whether to prevent the writable stream from being closed after streaming completes.
778
- * @default false
779
- */
780
- preventClose?: boolean;
781
- }
848
+ /**
849
+ * Whether to prevent the writable stream from being closed after streaming completes.
850
+ * @default false
851
+ */
852
+ preventClose?: boolean;
853
+ };
782
854
 
783
855
  /**
784
856
  * A tool call made by the model. Matches the AI SDK's tool call shape.
@@ -889,6 +961,11 @@ export interface WorkflowAgentStreamResult<
889
961
  * ```
890
962
  */
891
963
  export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
964
+ /**
965
+ * The id of the agent.
966
+ */
967
+ public readonly id: string | undefined;
968
+
892
969
  private model: LanguageModel;
893
970
  /**
894
971
  * The tool set configured for this agent.
@@ -902,6 +979,13 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
902
979
  private toolChoice?: ToolChoice<TBaseTools>;
903
980
  private telemetry?: TelemetrySettings;
904
981
  private experimentalContext: unknown;
982
+ private stopWhen?:
983
+ | StopCondition<ToolSet, any>
984
+ | Array<StopCondition<ToolSet, any>>;
985
+ private activeTools?: Array<keyof TBaseTools>;
986
+ private output?: OutputSpecification<any, any>;
987
+ private experimentalRepairToolCall?: ToolCallRepairFunction<TBaseTools>;
988
+ private experimentalDownload?: DownloadFunction;
905
989
  private prepareStep?: PrepareStepCallback<TBaseTools>;
906
990
  private constructorOnStepFinish?: WorkflowAgentOnStepFinishCallback<ToolSet>;
907
991
  private constructorOnFinish?: WorkflowAgentOnFinishCallback<ToolSet>;
@@ -912,6 +996,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
912
996
  private prepareCall?: PrepareCallCallback<TBaseTools>;
913
997
 
914
998
  constructor(options: WorkflowAgentOptions<TBaseTools>) {
999
+ this.id = options.id;
915
1000
  this.model = options.model;
916
1001
  this.tools = (options.tools ?? {}) as TBaseTools;
917
1002
  // `instructions` takes precedence over deprecated `system`
@@ -919,6 +1004,11 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
919
1004
  this.toolChoice = options.toolChoice;
920
1005
  this.telemetry = options.experimental_telemetry;
921
1006
  this.experimentalContext = options.experimental_context;
1007
+ this.stopWhen = options.stopWhen;
1008
+ this.activeTools = options.activeTools;
1009
+ this.output = options.output;
1010
+ this.experimentalRepairToolCall = options.experimental_repairToolCall;
1011
+ this.experimentalDownload = options.experimental_download;
922
1012
  this.prepareStep = options.prepareStep;
923
1013
  this.constructorOnStepFinish = options.onStepFinish;
924
1014
  this.constructorOnFinish = options.onFinish;
@@ -959,7 +1049,9 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
959
1049
  // Call prepareCall to transform parameters before the agent loop
960
1050
  let effectiveModel: LanguageModel = this.model;
961
1051
  let effectiveInstructions = options.system ?? this.instructions;
962
- let effectiveMessages = options.messages;
1052
+ let effectivePrompt: string | Array<ModelMessage> | undefined =
1053
+ options.prompt;
1054
+ let effectiveMessages: Array<ModelMessage> | undefined = options.messages;
963
1055
  let effectiveGenerationSettings = { ...this.generationSettings };
964
1056
  let effectiveExperimentalContext =
965
1057
  options.experimental_context ?? this.experimentalContext;
@@ -967,6 +1059,14 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
967
1059
  let effectiveTelemetryFromPrepare =
968
1060
  options.experimental_telemetry ?? this.telemetry;
969
1061
 
1062
+ // Resolve messages for prepareCall: use messages directly, or convert prompt
1063
+ const resolvedMessagesForPrepareCall: ModelMessage[] =
1064
+ effectiveMessages ??
1065
+ (typeof effectivePrompt === 'string'
1066
+ ? [{ role: 'user' as const, content: effectivePrompt }]
1067
+ : (effectivePrompt as ModelMessage[])) ??
1068
+ [];
1069
+
970
1070
  if (this.prepareCall) {
971
1071
  const prepared = await this.prepareCall({
972
1072
  model: effectiveModel,
@@ -975,16 +1075,17 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
975
1075
  toolChoice: effectiveToolChoiceFromPrepare as ToolChoice<TBaseTools>,
976
1076
  experimental_telemetry: effectiveTelemetryFromPrepare,
977
1077
  experimental_context: effectiveExperimentalContext,
978
- messages: effectiveMessages as ModelMessage[],
1078
+ messages: resolvedMessagesForPrepareCall,
979
1079
  ...effectiveGenerationSettings,
980
1080
  } as PrepareCallOptions<TBaseTools>);
981
1081
 
982
1082
  if (prepared.model !== undefined) effectiveModel = prepared.model;
983
1083
  if (prepared.instructions !== undefined)
984
1084
  effectiveInstructions = prepared.instructions;
985
- if (prepared.messages !== undefined)
986
- effectiveMessages =
987
- prepared.messages as WorkflowAgentStreamOptions<TTools>['messages'];
1085
+ if (prepared.messages !== undefined) {
1086
+ effectiveMessages = prepared.messages as Array<ModelMessage>;
1087
+ effectivePrompt = undefined; // messages from prepareCall take precedence
1088
+ }
988
1089
  if (prepared.experimental_context !== undefined)
989
1090
  effectiveExperimentalContext = prepared.experimental_context;
990
1091
  if (prepared.toolChoice !== undefined)
@@ -1017,7 +1118,9 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1017
1118
 
1018
1119
  const prompt = await standardizePrompt({
1019
1120
  system: effectiveInstructions,
1020
- messages: effectiveMessages,
1121
+ ...(effectivePrompt != null
1122
+ ? { prompt: effectivePrompt }
1123
+ : { messages: effectiveMessages! }),
1021
1124
  });
1022
1125
 
1023
1126
  // Process tool approval responses before starting the agent loop.
@@ -1146,7 +1249,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1146
1249
  const modelPrompt = await convertToLanguageModelPrompt({
1147
1250
  prompt,
1148
1251
  supportedUrls: {},
1149
- download: options.experimental_download,
1252
+ download: options.experimental_download ?? this.experimentalDownload,
1150
1253
  });
1151
1254
 
1152
1255
  const effectiveAbortSignal = mergeAbortSignals(
@@ -1225,10 +1328,11 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1225
1328
  // Merge telemetry settings
1226
1329
  const effectiveTelemetry = effectiveTelemetryFromPrepare;
1227
1330
 
1228
- // Filter tools if activeTools is specified
1331
+ // Filter tools if activeTools is specified (stream-level overrides constructor default)
1332
+ const effectiveActiveTools = options.activeTools ?? this.activeTools;
1229
1333
  const effectiveTools =
1230
- options.activeTools && options.activeTools.length > 0
1231
- ? filterTools(this.tools, options.activeTools as string[])
1334
+ effectiveActiveTools && effectiveActiveTools.length > 0
1335
+ ? filterTools(this.tools, effectiveActiveTools as string[])
1232
1336
  : this.tools;
1233
1337
 
1234
1338
  // Initialize context
@@ -1244,7 +1348,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1244
1348
  if (mergedOnStart) {
1245
1349
  await mergedOnStart({
1246
1350
  model: effectiveModel,
1247
- messages: effectiveMessages as ModelMessage[],
1351
+ messages: prompt.messages,
1248
1352
  });
1249
1353
  }
1250
1354
 
@@ -1317,7 +1421,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1317
1421
  await options.onAbort({ steps });
1318
1422
  }
1319
1423
  return {
1320
- messages: options.messages as unknown as ModelMessage[],
1424
+ messages: prompt.messages,
1321
1425
  steps,
1322
1426
  toolCalls: [],
1323
1427
  toolResults: [],
@@ -1330,7 +1434,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1330
1434
  tools: effectiveTools as ToolSet,
1331
1435
  writable: options.writable,
1332
1436
  prompt: modelPrompt,
1333
- stopConditions: options.stopWhen,
1437
+ stopConditions: options.stopWhen ?? this.stopWhen,
1334
1438
  maxSteps: options.maxSteps,
1335
1439
  onStepFinish: mergedOnStepFinish,
1336
1440
  onStepStart: mergedOnStepStart,
@@ -1343,9 +1447,11 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1343
1447
  experimental_context: experimentalContext,
1344
1448
  experimental_telemetry: effectiveTelemetry,
1345
1449
  includeRawChunks: options.includeRawChunks ?? false,
1346
- repairToolCall:
1347
- options.experimental_repairToolCall as ToolCallRepairFunction<ToolSet>,
1348
- responseFormat: await options.output?.responseFormat,
1450
+ repairToolCall: (options.experimental_repairToolCall ??
1451
+ this.experimentalRepairToolCall) as
1452
+ | ToolCallRepairFunction<ToolSet>
1453
+ | undefined,
1454
+ responseFormat: await (options.output ?? this.output)?.responseFormat,
1349
1455
  });
1350
1456
 
1351
1457
  // Track the final conversation messages from the iterator
@@ -1623,18 +1729,19 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1623
1729
  // Don't throw yet - we want to call onFinish first
1624
1730
  }
1625
1731
 
1626
- // Use the final messages from the iterator, or fall back to original messages
1732
+ // Use the final messages from the iterator, or fall back to standardized messages
1627
1733
  const messages = (finalMessages ??
1628
- options.messages) as unknown as ModelMessage[];
1734
+ prompt.messages) as unknown as ModelMessage[];
1629
1735
 
1630
- // Parse structured output if output is specified
1736
+ // Parse structured output if output is specified (stream-level overrides constructor default)
1737
+ const effectiveOutput = options.output ?? this.output;
1631
1738
  let experimentalOutput: OUTPUT = undefined as OUTPUT;
1632
- if (options.output && steps.length > 0) {
1739
+ if (effectiveOutput && steps.length > 0) {
1633
1740
  const lastStep = steps[steps.length - 1];
1634
1741
  const text = lastStep.text;
1635
1742
  if (text) {
1636
1743
  try {
1637
- experimentalOutput = await options.output.parseCompleteOutput(
1744
+ experimentalOutput = await effectiveOutput.parseCompleteOutput(
1638
1745
  { text },
1639
1746
  {
1640
1747
  response: lastStep.response,