@ai-sdk/workflow 1.0.0-canary.39 → 1.0.0-canary.41

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.
@@ -6,6 +6,12 @@ import type {
6
6
  LanguageModelV4ToolResultPart,
7
7
  SharedV4ProviderOptions,
8
8
  } from '@ai-sdk/provider';
9
+ import {
10
+ validateTypes,
11
+ type Context,
12
+ type HasRequiredKey,
13
+ type InferToolSetContext,
14
+ } from '@ai-sdk/provider-utils';
9
15
  import {
10
16
  Output,
11
17
  experimental_filterActiveTools as filterActiveTools,
@@ -44,13 +50,14 @@ export type { CompatibleLanguageModel } from './types.js';
44
50
  */
45
51
  export type WorkflowAgentOnStepFinishCallback<
46
52
  TTools extends ToolSet = ToolSet,
47
- > = GenerateTextOnStepFinishCallback<TTools, any>;
53
+ TRuntimeContext extends Context = Context,
54
+ > = GenerateTextOnStepFinishCallback<TTools, TRuntimeContext>;
48
55
 
49
56
  /**
50
57
  * Infer the type of the tools of a workflow agent.
51
58
  */
52
59
  export type InferWorkflowAgentTools<WORKFLOW_AGENT> =
53
- WORKFLOW_AGENT extends WorkflowAgent<infer TOOLS> ? TOOLS : never;
60
+ WORKFLOW_AGENT extends WorkflowAgent<infer TOOLS, any> ? TOOLS : never;
54
61
 
55
62
  /**
56
63
  * Infer the UI message type of a workflow agent.
@@ -91,6 +98,11 @@ export interface OutputSpecification<OUTPUT, PARTIAL> {
91
98
  */
92
99
  export type ProviderOptions = SharedV4ProviderOptions;
93
100
 
101
+ type WorkflowAgentToolsContextParameter<TTools extends ToolSet> =
102
+ HasRequiredKey<InferToolSetContext<TTools>> extends true
103
+ ? { toolsContext: InferToolSetContext<TTools> }
104
+ : { toolsContext?: never };
105
+
94
106
  /**
95
107
  * Telemetry settings for observability.
96
108
  */
@@ -255,7 +267,10 @@ export interface GenerationSettings {
255
267
  /**
256
268
  * Information passed to the prepareStep callback.
257
269
  */
258
- export interface PrepareStepInfo<TTools extends ToolSet = ToolSet> {
270
+ export interface PrepareStepInfo<
271
+ TTools extends ToolSet = ToolSet,
272
+ TRuntimeContext extends Context = Context,
273
+ > {
259
274
  /**
260
275
  * The current model configuration (string or function).
261
276
  * The function should return a LanguageModelV4 instance.
@@ -270,7 +285,7 @@ export interface PrepareStepInfo<TTools extends ToolSet = ToolSet> {
270
285
  /**
271
286
  * All previous steps with their results.
272
287
  */
273
- steps: StepResult<TTools, any>[];
288
+ steps: StepResult<TTools, TRuntimeContext>[];
274
289
 
275
290
  /**
276
291
  * The messages that will be sent to the model.
@@ -279,16 +294,29 @@ export interface PrepareStepInfo<TTools extends ToolSet = ToolSet> {
279
294
  messages: LanguageModelV4Prompt;
280
295
 
281
296
  /**
282
- * The context passed via the experimental_context setting (experimental).
297
+ * The runtime context that flows through the agent loop.
298
+ * Treat the value as immutable; return a new `runtimeContext` from
299
+ * `prepareStep` to update it for the current and subsequent steps.
283
300
  */
284
- experimental_context: unknown;
301
+ runtimeContext: TRuntimeContext;
302
+
303
+ /**
304
+ * Per-tool context, keyed by tool name. Each tool receives only its own
305
+ * validated entry as `context` during execution.
306
+ * Treat the value as immutable; return a new `toolsContext` from
307
+ * `prepareStep` to update it for the current and subsequent steps.
308
+ */
309
+ toolsContext: InferToolSetContext<TTools>;
285
310
  }
286
311
 
287
312
  /**
288
313
  * Return type from the prepareStep callback.
289
314
  * All properties are optional - only return the ones you want to override.
290
315
  */
291
- export interface PrepareStepResult extends Partial<GenerationSettings> {
316
+ export interface PrepareStepResult<
317
+ TTools extends ToolSet = ToolSet,
318
+ TRuntimeContext extends Context = Context,
319
+ > extends Partial<GenerationSettings> {
292
320
  /**
293
321
  * Override the model for this step.
294
322
  */
@@ -317,25 +345,38 @@ export interface PrepareStepResult extends Partial<GenerationSettings> {
317
345
  activeTools?: string[];
318
346
 
319
347
  /**
320
- * Context that is passed into tool execution. Experimental.
321
- * Changing the context will affect the context in this step and all subsequent steps.
348
+ * Updated runtime context for the current and subsequent steps.
349
+ * Returning a value replaces the agent's runtime context.
350
+ */
351
+ runtimeContext?: TRuntimeContext;
352
+
353
+ /**
354
+ * Updated per-tool context for the current and subsequent steps.
355
+ * Returning a value replaces the agent's tools context.
322
356
  */
323
- experimental_context?: unknown;
357
+ toolsContext?: InferToolSetContext<TTools>;
324
358
  }
325
359
 
326
360
  /**
327
361
  * Callback function called before each step in the agent loop.
328
362
  * Use this to modify settings, manage context, or implement dynamic behavior.
329
363
  */
330
- export type PrepareStepCallback<TTools extends ToolSet = ToolSet> = (
331
- info: PrepareStepInfo<TTools>,
332
- ) => PrepareStepResult | Promise<PrepareStepResult>;
364
+ export type PrepareStepCallback<
365
+ TTools extends ToolSet = ToolSet,
366
+ TRuntimeContext extends Context = Context,
367
+ > = (
368
+ info: PrepareStepInfo<TTools, TRuntimeContext>,
369
+ ) =>
370
+ | PrepareStepResult<TTools, TRuntimeContext>
371
+ | undefined
372
+ | Promise<PrepareStepResult<TTools, TRuntimeContext> | undefined>;
333
373
 
334
374
  /**
335
375
  * Options passed to the prepareCall callback.
336
376
  */
337
377
  export interface PrepareCallOptions<
338
378
  TTools extends ToolSet = ToolSet,
379
+ TRuntimeContext extends Context = Context,
339
380
  > extends Partial<GenerationSettings> {
340
381
  model: LanguageModel;
341
382
  tools: TTools;
@@ -346,7 +387,15 @@ export interface PrepareCallOptions<
346
387
  * @deprecated Use `telemetry` instead. This alias will be removed in a future major release.
347
388
  */
348
389
  experimental_telemetry?: TelemetryOptions;
349
- experimental_context?: unknown;
390
+ /**
391
+ * Runtime context that flows through the agent loop.
392
+ * Treat as immutable; return a new `runtimeContext` to update it for the call.
393
+ */
394
+ runtimeContext?: TRuntimeContext;
395
+ /**
396
+ * Per-tool context, keyed by tool name.
397
+ */
398
+ toolsContext?: InferToolSetContext<TTools>;
350
399
  messages: ModelMessage[];
351
400
  }
352
401
 
@@ -356,179 +405,200 @@ export interface PrepareCallOptions<
356
405
  * Note: `tools` cannot be overridden via prepareCall because they are
357
406
  * bound at construction time for type safety.
358
407
  */
359
- export type PrepareCallResult<TTools extends ToolSet = ToolSet> = Partial<
360
- Omit<PrepareCallOptions<TTools>, 'tools'>
361
- >;
408
+ export type PrepareCallResult<
409
+ TTools extends ToolSet = ToolSet,
410
+ TRuntimeContext extends Context = Context,
411
+ > = Partial<Omit<PrepareCallOptions<TTools, TRuntimeContext>, 'tools'>>;
362
412
 
363
413
  /**
364
414
  * Callback called once before the agent loop starts to transform call parameters.
365
415
  */
366
- export type PrepareCallCallback<TTools extends ToolSet = ToolSet> = (
367
- options: PrepareCallOptions<TTools>,
368
- ) => PrepareCallResult<TTools> | Promise<PrepareCallResult<TTools>>;
416
+ export type PrepareCallCallback<
417
+ TTools extends ToolSet = ToolSet,
418
+ TRuntimeContext extends Context = Context,
419
+ > = (
420
+ options: PrepareCallOptions<TTools, TRuntimeContext>,
421
+ ) =>
422
+ | PrepareCallResult<TTools, TRuntimeContext>
423
+ | Promise<PrepareCallResult<TTools, TRuntimeContext>>;
369
424
 
370
425
  /**
371
426
  * Configuration options for creating a {@link WorkflowAgent} instance.
372
427
  */
373
- export interface WorkflowAgentOptions<
428
+ export type WorkflowAgentOptions<
374
429
  TTools extends ToolSet = ToolSet,
375
- > extends GenerationSettings {
376
- /**
377
- * The id of the agent.
378
- */
379
- id?: string;
430
+ TRuntimeContext extends Context = Context,
431
+ > = GenerationSettings &
432
+ WorkflowAgentToolsContextParameter<TTools> & {
433
+ /**
434
+ * The id of the agent.
435
+ */
436
+ id?: string;
380
437
 
381
- /**
382
- * The model provider to use for the agent.
383
- *
384
- * This should be a string compatible with the Vercel AI Gateway (e.g., 'anthropic/claude-opus'),
385
- * or a LanguageModelV4 instance from a provider.
386
- */
387
- model: LanguageModel;
438
+ /**
439
+ * The model provider to use for the agent.
440
+ *
441
+ * This should be a string compatible with the Vercel AI Gateway (e.g., 'anthropic/claude-opus'),
442
+ * or a LanguageModelV4 instance from a provider.
443
+ */
444
+ model: LanguageModel;
388
445
 
389
- /**
390
- * A set of tools available to the agent.
391
- * Tools can be implemented as workflow steps for automatic retries and persistence,
392
- * or as regular workflow-level logic using core library features like sleep() and Hooks.
393
- */
394
- tools?: TTools;
446
+ /**
447
+ * A set of tools available to the agent.
448
+ * Tools can be implemented as workflow steps for automatic retries and persistence,
449
+ * or as regular workflow-level logic using core library features like sleep() and Hooks.
450
+ */
451
+ tools?: TTools;
395
452
 
396
- /**
397
- * Agent instructions. Can be a string, a SystemModelMessage, or an array of SystemModelMessages.
398
- * Supports provider-specific options (e.g., caching) when using the SystemModelMessage form.
399
- */
400
- instructions?: string | SystemModelMessage | Array<SystemModelMessage>;
453
+ /**
454
+ * Agent instructions. Can be a string, a SystemModelMessage, or an array of SystemModelMessages.
455
+ * Supports provider-specific options (e.g., caching) when using the SystemModelMessage form.
456
+ */
457
+ instructions?: string | SystemModelMessage | Array<SystemModelMessage>;
401
458
 
402
- /**
403
- * Optional system prompt to guide the agent's behavior.
404
- * @deprecated Use `instructions` instead.
405
- */
406
- system?: string;
459
+ /**
460
+ * Optional system prompt to guide the agent's behavior.
461
+ * @deprecated Use `instructions` instead.
462
+ */
463
+ system?: string;
407
464
 
408
- /**
409
- * The tool choice strategy. Default: 'auto'.
410
- */
411
- toolChoice?: ToolChoice<TTools>;
465
+ /**
466
+ * The tool choice strategy. Default: 'auto'.
467
+ */
468
+ toolChoice?: ToolChoice<TTools>;
412
469
 
413
- /**
414
- * Optional telemetry configuration.
415
- */
416
- telemetry?: TelemetryOptions;
470
+ /**
471
+ * Optional telemetry configuration.
472
+ */
473
+ telemetry?: TelemetryOptions;
417
474
 
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;
475
+ /**
476
+ * Optional telemetry configuration.
477
+ *
478
+ * @deprecated Use `telemetry` instead. This alias will be removed in a future major release.
479
+ */
480
+ experimental_telemetry?: TelemetryOptions;
424
481
 
425
- /**
426
- * Default context that is passed into tool execution for every stream call on this agent.
427
- *
428
- * Per-stream `experimental_context` values passed to `stream()` override this default.
429
- * Experimental (can break in patch releases).
430
- * @default undefined
431
- */
432
- experimental_context?: unknown;
482
+ /**
483
+ * Default runtime context for every stream call on this agent.
484
+ *
485
+ * The runtime context flows through `prepareStep`, lifecycle callbacks,
486
+ * and step results.
487
+ * Treat as immutable; return a new `runtimeContext` from `prepareStep`
488
+ * to update it between steps.
489
+ *
490
+ * In workflow context, keep values serializable so they can cross workflow
491
+ * and step boundaries.
492
+ *
493
+ * Per-stream `runtimeContext` values passed to `stream()` override this default.
494
+ */
495
+ runtimeContext?: TRuntimeContext;
433
496
 
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>>;
497
+ /**
498
+ * Default stop condition for the agent loop. When the condition is an array,
499
+ * any of the conditions can be met to stop the generation.
500
+ *
501
+ * Per-stream `stopWhen` values passed to `stream()` override this default.
502
+ */
503
+ stopWhen?:
504
+ | StopCondition<NoInfer<ToolSet>, any>
505
+ | Array<StopCondition<NoInfer<ToolSet>, any>>;
443
506
 
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>>;
507
+ /**
508
+ * Default set of active tools that limits which tools the model can call,
509
+ * without changing the tool call and result types in the result.
510
+ *
511
+ * Per-stream `activeTools` values passed to `stream()` override this default.
512
+ */
513
+ activeTools?: ActiveTools<NoInfer<TTools>>;
451
514
 
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>;
515
+ /**
516
+ * Default output specification for structured outputs.
517
+ * Use `Output.object({ schema })` for structured output or `Output.text()` for text output.
518
+ *
519
+ * Per-stream `output` values passed to `stream()` override this default.
520
+ */
521
+ output?: OutputSpecification<any, any>;
459
522
 
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>;
523
+ /**
524
+ * Default function that attempts to repair a tool call that failed to parse.
525
+ *
526
+ * Per-stream `experimental_repairToolCall` values passed to `stream()` override this default.
527
+ */
528
+ experimental_repairToolCall?: ToolCallRepairFunction<TTools>;
466
529
 
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;
530
+ /**
531
+ * Default custom download function to use for URLs.
532
+ *
533
+ * Per-stream `experimental_download` values passed to `stream()` override this default.
534
+ */
535
+ experimental_download?: DownloadFunction;
473
536
 
474
- /**
475
- * Default callback function called before each step in the agent loop.
476
- * Use this to modify settings, manage context, or inject messages dynamically
477
- * for every stream call on this agent instance.
478
- *
479
- * Per-stream `prepareStep` values passed to `stream()` override this default.
480
- */
481
- prepareStep?: PrepareStepCallback<TTools>;
537
+ /**
538
+ * Default callback function called before each step in the agent loop.
539
+ * Use this to modify settings, manage context, or inject messages dynamically
540
+ * for every stream call on this agent instance.
541
+ *
542
+ * Per-stream `prepareStep` values passed to `stream()` override this default.
543
+ */
544
+ prepareStep?: PrepareStepCallback<TTools, TRuntimeContext>;
482
545
 
483
- /**
484
- * Callback function to be called after each step completes.
485
- */
486
- onStepFinish?: WorkflowAgentOnStepFinishCallback<ToolSet>;
546
+ /**
547
+ * Callback function to be called after each step completes.
548
+ */
549
+ onStepFinish?: WorkflowAgentOnStepFinishCallback<TTools, TRuntimeContext>;
487
550
 
488
- /**
489
- * Callback that is called when the LLM response and all request tool executions are finished.
490
- */
491
- onFinish?: WorkflowAgentOnFinishCallback<ToolSet>;
551
+ /**
552
+ * Callback that is called when the LLM response and all request tool executions are finished.
553
+ */
554
+ onFinish?: WorkflowAgentOnFinishCallback<TTools, TRuntimeContext>;
492
555
 
493
- /**
494
- * Callback called when the agent starts streaming, before any LLM calls.
495
- */
496
- experimental_onStart?: WorkflowAgentOnStartCallback;
556
+ /**
557
+ * Callback called when the agent starts streaming, before any LLM calls.
558
+ */
559
+ experimental_onStart?: WorkflowAgentOnStartCallback<
560
+ TTools,
561
+ TRuntimeContext
562
+ >;
497
563
 
498
- /**
499
- * Callback called before each step (LLM call) begins.
500
- */
501
- experimental_onStepStart?: WorkflowAgentOnStepStartCallback;
564
+ /**
565
+ * Callback called before each step (LLM call) begins.
566
+ */
567
+ experimental_onStepStart?: WorkflowAgentOnStepStartCallback<
568
+ TTools,
569
+ TRuntimeContext
570
+ >;
502
571
 
503
- /**
504
- * Callback called before a tool's execute function runs.
505
- */
506
- onToolExecutionStart?: WorkflowAgentOnToolExecutionStartCallback;
572
+ /**
573
+ * Callback called before a tool's execute function runs.
574
+ */
575
+ onToolExecutionStart?: WorkflowAgentOnToolExecutionStartCallback<TTools>;
507
576
 
508
- /**
509
- * Callback called after a tool execution completes.
510
- */
511
- onToolExecutionEnd?: WorkflowAgentOnToolExecutionEndCallback;
577
+ /**
578
+ * Callback called after a tool execution completes.
579
+ */
580
+ onToolExecutionEnd?: WorkflowAgentOnToolExecutionEndCallback<TTools>;
512
581
 
513
- /**
514
- * Prepare the parameters for the stream call.
515
- * Called once before the agent loop starts. Use this to transform
516
- * model, tools, instructions, or other settings based on runtime context.
517
- */
518
- prepareCall?: PrepareCallCallback<TTools>;
519
- }
582
+ /**
583
+ * Prepare the parameters for the stream call.
584
+ * Called once before the agent loop starts. Use this to transform
585
+ * model, tools, instructions, or other settings based on runtime context.
586
+ */
587
+ prepareCall?: PrepareCallCallback<TTools, TRuntimeContext>;
588
+ };
520
589
 
521
590
  /**
522
591
  * Callback that is called when the LLM response and all request tool executions are finished.
523
592
  */
524
593
  export type WorkflowAgentOnFinishCallback<
525
594
  TTools extends ToolSet = ToolSet,
595
+ TRuntimeContext extends Context = Context,
526
596
  OUTPUT = never,
527
597
  > = (event: {
528
598
  /**
529
599
  * Details for all steps.
530
600
  */
531
- readonly steps: StepResult<TTools, any>[];
601
+ readonly steps: StepResult<TTools, TRuntimeContext>[];
532
602
 
533
603
  /**
534
604
  * The final messages including all tool calls and results.
@@ -551,9 +621,14 @@ export type WorkflowAgentOnFinishCallback<
551
621
  readonly totalUsage: LanguageModelUsage;
552
622
 
553
623
  /**
554
- * Context that is passed into tool execution.
624
+ * The runtime context at the end of the agent loop.
555
625
  */
556
- readonly experimental_context: unknown;
626
+ readonly runtimeContext: TRuntimeContext;
627
+
628
+ /**
629
+ * The per-tool context at the end of the agent loop.
630
+ */
631
+ readonly toolsContext: InferToolSetContext<TTools>;
557
632
 
558
633
  /**
559
634
  * The generated structured output. It uses the `output` specification.
@@ -583,36 +658,57 @@ export type WorkflowAgentOnAbortCallback<TTools extends ToolSet = ToolSet> =
583
658
  /**
584
659
  * Callback that is called when the agent starts streaming, before any LLM calls.
585
660
  */
586
- export type WorkflowAgentOnStartCallback = (event: {
661
+ export type WorkflowAgentOnStartCallback<
662
+ TTools extends ToolSet = ToolSet,
663
+ TRuntimeContext extends Context = Context,
664
+ > = (event: {
587
665
  /** The model being used */
588
666
  readonly model: LanguageModel;
589
667
  /** The messages being sent */
590
668
  readonly messages: ModelMessage[];
669
+ /** Shared runtime context for this agent loop */
670
+ readonly runtimeContext: TRuntimeContext;
671
+ /** Per-tool context map for this agent loop */
672
+ readonly toolsContext: InferToolSetContext<TTools>;
591
673
  }) => PromiseLike<void> | void;
592
674
 
593
675
  /**
594
676
  * Callback that is called before each step (LLM call) begins.
595
677
  */
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;
678
+ export type WorkflowAgentOnStepStartCallback<
679
+ TTools extends ToolSet = ToolSet,
680
+ TRuntimeContext extends Context = Context,
681
+ > = (event: {
682
+ /** The current step number (0-based) */
683
+ readonly stepNumber: number;
684
+ /** The model being used for this step */
685
+ readonly model: LanguageModel;
686
+ /** The messages being sent for this step */
687
+ readonly messages: ModelMessage[];
688
+ /** Results from all previously finished steps */
689
+ readonly steps: ReadonlyArray<StepResult<TTools, TRuntimeContext>>;
690
+ /** Shared runtime context for this step */
691
+ readonly runtimeContext: TRuntimeContext;
692
+ /** Per-tool context map for this step */
693
+ readonly toolsContext: InferToolSetContext<TTools>;
694
+ }) => PromiseLike<void> | void;
607
695
 
608
696
  /**
609
697
  * Callback that is called before a tool's execute function runs.
610
698
  */
611
- export type WorkflowAgentOnToolExecutionStartCallback = (event: {
699
+ export type WorkflowAgentOnToolExecutionStartCallback<
700
+ TTools extends ToolSet = ToolSet,
701
+ > = (event: {
612
702
  /** The tool call being executed */
613
703
  readonly toolCall: ToolCall;
614
704
  /** The current step number (0-based) */
615
705
  readonly stepNumber: number;
706
+ /** Messages sent to the language model for the step that produced the call */
707
+ readonly messages: ModelMessage[];
708
+ /** Tool-specific context passed to the tool */
709
+ readonly toolContext:
710
+ | InferToolSetContext<TTools>[keyof InferToolSetContext<TTools>]
711
+ | undefined;
616
712
  }) => PromiseLike<void> | void;
617
713
 
618
714
  /**
@@ -620,7 +716,9 @@ export type WorkflowAgentOnToolExecutionStartCallback = (event: {
620
716
  * Uses a discriminated union pattern: check `success` to determine
621
717
  * whether `output` or `error` is available.
622
718
  */
623
- export type WorkflowAgentOnToolExecutionEndCallback = (
719
+ export type WorkflowAgentOnToolExecutionEndCallback<
720
+ TTools extends ToolSet = ToolSet,
721
+ > = (
624
722
  event:
625
723
  | {
626
724
  /** The tool call that was executed */
@@ -629,6 +727,12 @@ export type WorkflowAgentOnToolExecutionEndCallback = (
629
727
  readonly stepNumber: number;
630
728
  /** Execution time in milliseconds */
631
729
  readonly durationMs: number;
730
+ /** Messages sent to the language model for the step that produced the call */
731
+ readonly messages: ModelMessage[];
732
+ /** Tool-specific context passed to the tool */
733
+ readonly toolContext:
734
+ | InferToolSetContext<TTools>[keyof InferToolSetContext<TTools>]
735
+ | undefined;
632
736
  /** Whether the tool call succeeded */
633
737
  readonly success: true;
634
738
  /** The tool result */
@@ -642,6 +746,12 @@ export type WorkflowAgentOnToolExecutionEndCallback = (
642
746
  readonly stepNumber: number;
643
747
  /** Execution time in milliseconds */
644
748
  readonly durationMs: number;
749
+ /** Messages sent to the language model for the step that produced the call */
750
+ readonly messages: ModelMessage[];
751
+ /** Tool-specific context passed to the tool */
752
+ readonly toolContext:
753
+ | InferToolSetContext<TTools>[keyof InferToolSetContext<TTools>]
754
+ | undefined;
645
755
  /** Whether the tool call succeeded */
646
756
  readonly success: false;
647
757
  /** The error that occurred */
@@ -655,6 +765,7 @@ export type WorkflowAgentOnToolExecutionEndCallback = (
655
765
  */
656
766
  export type WorkflowAgentStreamOptions<
657
767
  TTools extends ToolSet = ToolSet,
768
+ TRuntimeContext extends Context = Context,
658
769
  OUTPUT = never,
659
770
  PARTIAL_OUTPUT = never,
660
771
  > = Partial<GenerationSettings> &
@@ -752,11 +863,29 @@ export type WorkflowAgentStreamOptions<
752
863
  experimental_telemetry?: TelemetryOptions;
753
864
 
754
865
  /**
755
- * Context that is passed into tool execution.
756
- * Experimental (can break in patch releases).
757
- * @default undefined
866
+ * Runtime context that flows through the agent loop.
867
+ *
868
+ * Treat as immutable; return a new `runtimeContext` from `prepareStep`
869
+ * to update it between steps.
870
+ *
871
+ * In workflow context, keep values serializable so they can cross workflow
872
+ * and step boundaries.
873
+ *
874
+ * Overrides the constructor-level `runtimeContext` if provided.
875
+ */
876
+ runtimeContext?: TRuntimeContext;
877
+
878
+ /**
879
+ * Per-tool context, keyed by tool name. Each tool receives only its own
880
+ * validated entry as `context` during execution. Tools that declare a
881
+ * `contextSchema` validate their entry against the schema.
882
+ *
883
+ * In workflow context, keep values serializable so they can cross workflow
884
+ * and step boundaries.
885
+ *
886
+ * Overrides the constructor-level `toolsContext` if provided.
758
887
  */
759
- experimental_context?: unknown;
888
+ toolsContext?: InferToolSetContext<TTools>;
760
889
 
761
890
  /**
762
891
  * Optional specification for parsing structured outputs from the LLM response.
@@ -814,7 +943,7 @@ export type WorkflowAgentStreamOptions<
814
943
  /**
815
944
  * Callback function to be called after each step completes.
816
945
  */
817
- onStepFinish?: WorkflowAgentOnStepFinishCallback<TTools>;
946
+ onStepFinish?: WorkflowAgentOnStepFinishCallback<TTools, TRuntimeContext>;
818
947
 
819
948
  /**
820
949
  * Callback that is invoked when an error occurs during streaming.
@@ -826,7 +955,7 @@ export type WorkflowAgentStreamOptions<
826
955
  * Callback that is called when the LLM response and all request tool executions
827
956
  * (for tools that have an `execute` function) are finished.
828
957
  */
829
- onFinish?: WorkflowAgentOnFinishCallback<TTools, OUTPUT>;
958
+ onFinish?: WorkflowAgentOnFinishCallback<TTools, TRuntimeContext, OUTPUT>;
830
959
 
831
960
  /**
832
961
  * Callback that is called when the operation is aborted.
@@ -836,22 +965,28 @@ export type WorkflowAgentStreamOptions<
836
965
  /**
837
966
  * Callback called when the agent starts streaming, before any LLM calls.
838
967
  */
839
- experimental_onStart?: WorkflowAgentOnStartCallback;
968
+ experimental_onStart?: WorkflowAgentOnStartCallback<
969
+ TTools,
970
+ TRuntimeContext
971
+ >;
840
972
 
841
973
  /**
842
974
  * Callback called before each step (LLM call) begins.
843
975
  */
844
- experimental_onStepStart?: WorkflowAgentOnStepStartCallback;
976
+ experimental_onStepStart?: WorkflowAgentOnStepStartCallback<
977
+ TTools,
978
+ TRuntimeContext
979
+ >;
845
980
 
846
981
  /**
847
982
  * Callback called before a tool's execute function runs.
848
983
  */
849
- onToolExecutionStart?: WorkflowAgentOnToolExecutionStartCallback;
984
+ onToolExecutionStart?: WorkflowAgentOnToolExecutionStartCallback<TTools>;
850
985
 
851
986
  /**
852
987
  * Callback called after a tool execution completes.
853
988
  */
854
- onToolExecutionEnd?: WorkflowAgentOnToolExecutionEndCallback;
989
+ onToolExecutionEnd?: WorkflowAgentOnToolExecutionEndCallback<TTools>;
855
990
 
856
991
  /**
857
992
  * Callback function called before each step in the agent loop.
@@ -871,7 +1006,7 @@ export type WorkflowAgentStreamOptions<
871
1006
  * }
872
1007
  * ```
873
1008
  */
874
- prepareStep?: PrepareStepCallback<TTools>;
1009
+ prepareStep?: PrepareStepCallback<TTools, TRuntimeContext>;
875
1010
 
876
1011
  /**
877
1012
  * Timeout in milliseconds for the stream operation.
@@ -1001,7 +1136,10 @@ export interface WorkflowAgentStreamResult<
1001
1136
  * });
1002
1137
  * ```
1003
1138
  */
1004
- export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1139
+ export class WorkflowAgent<
1140
+ TBaseTools extends ToolSet = ToolSet,
1141
+ TRuntimeContext extends Context = Context,
1142
+ > {
1005
1143
  /**
1006
1144
  * The id of the agent.
1007
1145
  */
@@ -1019,7 +1157,8 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1019
1157
  private generationSettings: GenerationSettings;
1020
1158
  private toolChoice?: ToolChoice<TBaseTools>;
1021
1159
  private telemetry?: TelemetryOptions;
1022
- private experimentalContext: unknown;
1160
+ private runtimeContext?: TRuntimeContext;
1161
+ private toolsContext?: InferToolSetContext<TBaseTools>;
1023
1162
  private stopWhen?:
1024
1163
  | StopCondition<ToolSet, any>
1025
1164
  | Array<StopCondition<ToolSet, any>>;
@@ -1027,16 +1166,28 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1027
1166
  private output?: OutputSpecification<any, any>;
1028
1167
  private experimentalRepairToolCall?: ToolCallRepairFunction<TBaseTools>;
1029
1168
  private experimentalDownload?: DownloadFunction;
1030
- private prepareStep?: PrepareStepCallback<TBaseTools>;
1031
- private constructorOnStepFinish?: WorkflowAgentOnStepFinishCallback<ToolSet>;
1032
- private constructorOnFinish?: WorkflowAgentOnFinishCallback<ToolSet>;
1033
- private constructorOnStart?: WorkflowAgentOnStartCallback;
1034
- private constructorOnStepStart?: WorkflowAgentOnStepStartCallback;
1035
- private constructorOnToolExecutionStart?: WorkflowAgentOnToolExecutionStartCallback;
1036
- private constructorOnToolExecutionEnd?: WorkflowAgentOnToolExecutionEndCallback;
1037
- private prepareCall?: PrepareCallCallback<TBaseTools>;
1038
-
1039
- constructor(options: WorkflowAgentOptions<TBaseTools>) {
1169
+ private prepareStep?: PrepareStepCallback<TBaseTools, TRuntimeContext>;
1170
+ private constructorOnStepFinish?: WorkflowAgentOnStepFinishCallback<
1171
+ TBaseTools,
1172
+ TRuntimeContext
1173
+ >;
1174
+ private constructorOnFinish?: WorkflowAgentOnFinishCallback<
1175
+ TBaseTools,
1176
+ TRuntimeContext
1177
+ >;
1178
+ private constructorOnStart?: WorkflowAgentOnStartCallback<
1179
+ TBaseTools,
1180
+ TRuntimeContext
1181
+ >;
1182
+ private constructorOnStepStart?: WorkflowAgentOnStepStartCallback<
1183
+ TBaseTools,
1184
+ TRuntimeContext
1185
+ >;
1186
+ private constructorOnToolExecutionStart?: WorkflowAgentOnToolExecutionStartCallback<TBaseTools>;
1187
+ private constructorOnToolExecutionEnd?: WorkflowAgentOnToolExecutionEndCallback<TBaseTools>;
1188
+ private prepareCall?: PrepareCallCallback<TBaseTools, TRuntimeContext>;
1189
+
1190
+ constructor(options: WorkflowAgentOptions<TBaseTools, TRuntimeContext>) {
1040
1191
  this.id = options.id;
1041
1192
  this.model = options.model;
1042
1193
  this.tools = (options.tools ?? {}) as TBaseTools;
@@ -1044,7 +1195,8 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1044
1195
  this.instructions = options.instructions ?? options.system;
1045
1196
  this.toolChoice = options.toolChoice;
1046
1197
  this.telemetry = options.telemetry ?? options.experimental_telemetry;
1047
- this.experimentalContext = options.experimental_context;
1198
+ this.runtimeContext = options.runtimeContext;
1199
+ this.toolsContext = options.toolsContext;
1048
1200
  this.stopWhen = options.stopWhen;
1049
1201
  this.activeTools = options.activeTools;
1050
1202
  this.output = options.output;
@@ -1085,7 +1237,12 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1085
1237
  OUTPUT = never,
1086
1238
  PARTIAL_OUTPUT = never,
1087
1239
  >(
1088
- options: WorkflowAgentStreamOptions<TTools, OUTPUT, PARTIAL_OUTPUT>,
1240
+ options: WorkflowAgentStreamOptions<
1241
+ TTools,
1242
+ TRuntimeContext,
1243
+ OUTPUT,
1244
+ PARTIAL_OUTPUT
1245
+ >,
1089
1246
  ): Promise<WorkflowAgentStreamResult<TTools, OUTPUT>> {
1090
1247
  // Call prepareCall to transform parameters before the agent loop
1091
1248
  let effectiveModel: LanguageModel = this.model;
@@ -1094,8 +1251,14 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1094
1251
  options.prompt;
1095
1252
  let effectiveMessages: Array<ModelMessage> | undefined = options.messages;
1096
1253
  let effectiveGenerationSettings = { ...this.generationSettings };
1097
- let effectiveExperimentalContext =
1098
- options.experimental_context ?? this.experimentalContext;
1254
+ let effectiveRuntimeContext: TRuntimeContext = (options.runtimeContext ??
1255
+ this.runtimeContext ??
1256
+ {}) as TRuntimeContext;
1257
+ let effectiveToolsContext: Record<string, Context | undefined> =
1258
+ (options.toolsContext ?? this.toolsContext ?? {}) as unknown as Record<
1259
+ string,
1260
+ Context | undefined
1261
+ >;
1099
1262
  let effectiveToolChoiceFromPrepare = options.toolChoice ?? this.toolChoice;
1100
1263
  let effectiveTelemetryFromPrepare =
1101
1264
  options.telemetry ?? options.experimental_telemetry ?? this.telemetry;
@@ -1116,10 +1279,11 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1116
1279
  toolChoice: effectiveToolChoiceFromPrepare as ToolChoice<TBaseTools>,
1117
1280
  telemetry: effectiveTelemetryFromPrepare,
1118
1281
  experimental_telemetry: effectiveTelemetryFromPrepare,
1119
- experimental_context: effectiveExperimentalContext,
1282
+ runtimeContext: effectiveRuntimeContext,
1283
+ toolsContext: effectiveToolsContext as InferToolSetContext<TBaseTools>,
1120
1284
  messages: resolvedMessagesForPrepareCall,
1121
1285
  ...effectiveGenerationSettings,
1122
- } as PrepareCallOptions<TBaseTools>);
1286
+ } as PrepareCallOptions<TBaseTools, TRuntimeContext>);
1123
1287
 
1124
1288
  if (prepared.model !== undefined) effectiveModel = prepared.model;
1125
1289
  if (prepared.instructions !== undefined)
@@ -1128,8 +1292,13 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1128
1292
  effectiveMessages = prepared.messages as Array<ModelMessage>;
1129
1293
  effectivePrompt = undefined; // messages from prepareCall take precedence
1130
1294
  }
1131
- if (prepared.experimental_context !== undefined)
1132
- effectiveExperimentalContext = prepared.experimental_context;
1295
+ if (prepared.runtimeContext !== undefined)
1296
+ effectiveRuntimeContext = prepared.runtimeContext;
1297
+ if (prepared.toolsContext !== undefined)
1298
+ effectiveToolsContext = prepared.toolsContext as Record<
1299
+ string,
1300
+ Context | undefined
1301
+ >;
1133
1302
  if (prepared.toolChoice !== undefined)
1134
1303
  effectiveToolChoiceFromPrepare =
1135
1304
  prepared.toolChoice as ToolChoice<TBaseTools>;
@@ -1193,10 +1362,15 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1193
1362
  if (tool && typeof tool.execute === 'function') {
1194
1363
  try {
1195
1364
  const { execute } = tool;
1365
+ const resolvedContext = await resolveToolContext({
1366
+ toolName: approval.toolName,
1367
+ tool,
1368
+ toolsContext: effectiveToolsContext,
1369
+ });
1196
1370
  const toolResult = await execute(approval.input, {
1197
1371
  toolCallId: approval.toolCallId,
1198
1372
  messages: [],
1199
- context: effectiveExperimentalContext,
1373
+ context: resolvedContext,
1200
1374
  });
1201
1375
  toolResultContent.push({
1202
1376
  type: 'tool-result' as const,
@@ -1338,22 +1512,26 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1338
1512
  // Merge constructor + stream callbacks (constructor first, then stream)
1339
1513
  const mergedOnStepFinish = mergeCallbacks(
1340
1514
  this.constructorOnStepFinish as
1341
- | WorkflowAgentOnStepFinishCallback<TTools>
1515
+ | WorkflowAgentOnStepFinishCallback<TTools, TRuntimeContext>
1342
1516
  | undefined,
1343
1517
  options.onStepFinish,
1344
1518
  );
1345
1519
  const mergedOnFinish = mergeCallbacks(
1346
1520
  this.constructorOnFinish as
1347
- | WorkflowAgentOnFinishCallback<TTools, OUTPUT>
1521
+ | WorkflowAgentOnFinishCallback<TTools, TRuntimeContext, OUTPUT>
1348
1522
  | undefined,
1349
1523
  options.onFinish,
1350
1524
  );
1351
1525
  const mergedOnStart = mergeCallbacks(
1352
- this.constructorOnStart,
1526
+ this.constructorOnStart as
1527
+ | WorkflowAgentOnStartCallback<TTools, TRuntimeContext>
1528
+ | undefined,
1353
1529
  options.experimental_onStart,
1354
1530
  );
1355
1531
  const mergedOnStepStart = mergeCallbacks(
1356
- this.constructorOnStepStart,
1532
+ this.constructorOnStepStart as
1533
+ | WorkflowAgentOnStepStartCallback<TTools, TRuntimeContext>
1534
+ | undefined,
1357
1535
  options.experimental_onStepStart,
1358
1536
  );
1359
1537
  const mergedOnToolExecutionStart = mergeCallbacks(
@@ -1382,9 +1560,11 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1382
1560
  : this.tools;
1383
1561
 
1384
1562
  // Initialize context
1385
- let experimentalContext = effectiveExperimentalContext;
1563
+ let runtimeContext: TRuntimeContext = effectiveRuntimeContext;
1564
+ let toolsContext: Record<string, Context | undefined> =
1565
+ effectiveToolsContext;
1386
1566
 
1387
- const steps: StepResult<TTools, any>[] = [];
1567
+ const steps: StepResult<TTools, TRuntimeContext>[] = [];
1388
1568
 
1389
1569
  // Track tool calls and results from the last step for the result
1390
1570
  let lastStepToolCalls: ToolCall[] = [];
@@ -1395,6 +1575,8 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1395
1575
  await mergedOnStart({
1396
1576
  model: effectiveModel,
1397
1577
  messages: prompt.messages,
1578
+ runtimeContext,
1579
+ toolsContext: toolsContext as unknown as InferToolSetContext<TTools>,
1398
1580
  });
1399
1581
  }
1400
1582
 
@@ -1403,7 +1585,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1403
1585
  toolCall: { toolCallId: string; toolName: string; input: unknown },
1404
1586
  tools: ToolSet,
1405
1587
  messages: LanguageModelV4Prompt,
1406
- context?: unknown,
1588
+ perToolContexts: Record<string, Context | undefined>,
1407
1589
  currentStepNumber: number = 0,
1408
1590
  ): Promise<LanguageModelV4ToolResultPart> => {
1409
1591
  const toolCallEvent: ToolCall = {
@@ -1413,17 +1595,31 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1413
1595
  input: toolCall.input,
1414
1596
  };
1415
1597
 
1598
+ const tool = tools[toolCall.toolName];
1599
+ const resolvedContext = tool
1600
+ ? await resolveToolContext({
1601
+ toolName: toolCall.toolName,
1602
+ tool,
1603
+ toolsContext: perToolContexts,
1604
+ })
1605
+ : undefined;
1606
+ const modelMessages = getToolCallbackMessages(messages);
1607
+
1416
1608
  if (mergedOnToolExecutionStart) {
1417
1609
  await mergedOnToolExecutionStart({
1418
1610
  toolCall: toolCallEvent,
1419
1611
  stepNumber: currentStepNumber,
1612
+ messages: modelMessages,
1613
+ toolContext: resolvedContext as
1614
+ | InferToolSetContext<TTools>[keyof InferToolSetContext<TTools>]
1615
+ | undefined,
1420
1616
  });
1421
1617
  }
1422
1618
 
1423
1619
  const startTime = Date.now();
1424
1620
  let result: LanguageModelV4ToolResultPart;
1425
1621
  try {
1426
- result = await executeTool(toolCall, tools, messages, context);
1622
+ result = await executeTool(toolCall, tools, messages, resolvedContext);
1427
1623
  } catch (err) {
1428
1624
  const durationMs = Date.now() - startTime;
1429
1625
  if (mergedOnToolExecutionEnd) {
@@ -1431,6 +1627,10 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1431
1627
  toolCall: toolCallEvent,
1432
1628
  stepNumber: currentStepNumber,
1433
1629
  durationMs,
1630
+ messages: modelMessages,
1631
+ toolContext: resolvedContext as
1632
+ | InferToolSetContext<TTools>[keyof InferToolSetContext<TTools>]
1633
+ | undefined,
1434
1634
  success: false,
1435
1635
  error: err,
1436
1636
  });
@@ -1450,6 +1650,10 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1450
1650
  toolCall: toolCallEvent,
1451
1651
  stepNumber: currentStepNumber,
1452
1652
  durationMs,
1653
+ messages: modelMessages,
1654
+ toolContext: resolvedContext as
1655
+ | InferToolSetContext<TTools>[keyof InferToolSetContext<TTools>]
1656
+ | undefined,
1453
1657
  success: false,
1454
1658
  error: 'value' in result.output ? result.output.value : undefined,
1455
1659
  });
@@ -1458,6 +1662,10 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1458
1662
  toolCall: toolCallEvent,
1459
1663
  stepNumber: currentStepNumber,
1460
1664
  durationMs,
1665
+ messages: modelMessages,
1666
+ toolContext: resolvedContext as
1667
+ | InferToolSetContext<TTools>[keyof InferToolSetContext<TTools>]
1668
+ | undefined,
1461
1669
  success: true,
1462
1670
  output:
1463
1671
  result.output && 'value' in result.output
@@ -1490,15 +1698,17 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1490
1698
  prompt: modelPrompt,
1491
1699
  stopConditions: options.stopWhen ?? this.stopWhen,
1492
1700
 
1493
- onStepFinish: mergedOnStepFinish,
1494
- onStepStart: mergedOnStepStart,
1701
+ onStepFinish: mergedOnStepFinish as any,
1702
+ onStepStart: mergedOnStepStart as any,
1495
1703
  onError: options.onError,
1496
- prepareStep:
1497
- options.prepareStep ??
1498
- (this.prepareStep as PrepareStepCallback<ToolSet> | undefined),
1704
+ prepareStep: (options.prepareStep ??
1705
+ (this.prepareStep as
1706
+ | PrepareStepCallback<ToolSet, TRuntimeContext>
1707
+ | undefined)) as any,
1499
1708
  generationSettings: mergedGenerationSettings,
1500
1709
  toolChoice: effectiveToolChoice as ToolChoice<ToolSet>,
1501
- experimental_context: experimentalContext,
1710
+ runtimeContext,
1711
+ toolsContext,
1502
1712
  telemetry: effectiveTelemetry,
1503
1713
  includeRawChunks: options.includeRawChunks ?? false,
1504
1714
  repairToolCall: (options.experimental_repairToolCall ??
@@ -1529,16 +1739,20 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1529
1739
  toolCalls,
1530
1740
  messages: iterMessages,
1531
1741
  step,
1532
- context,
1742
+ runtimeContext: yieldedRuntimeContext,
1743
+ toolsContext: yieldedToolsContext,
1533
1744
  providerExecutedToolResults,
1534
1745
  } = result.value;
1535
1746
  // Capture current step number before pushing (0-based)
1536
1747
  const currentStepNumber = steps.length;
1537
1748
  if (step) {
1538
- steps.push(step as unknown as StepResult<TTools, any>);
1749
+ steps.push(step as unknown as StepResult<TTools, TRuntimeContext>);
1750
+ }
1751
+ if (yieldedRuntimeContext !== undefined) {
1752
+ runtimeContext = yieldedRuntimeContext as TRuntimeContext;
1539
1753
  }
1540
- if (context !== undefined) {
1541
- experimentalContext = context;
1754
+ if (yieldedToolsContext !== undefined) {
1755
+ toolsContext = yieldedToolsContext;
1542
1756
  }
1543
1757
 
1544
1758
  // Only execute tools if there are tool calls
@@ -1562,10 +1776,16 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1562
1776
  if (tool.needsApproval == null) return false;
1563
1777
  if (typeof tool.needsApproval === 'boolean')
1564
1778
  return tool.needsApproval;
1779
+ const resolvedContext = await resolveToolContext({
1780
+ toolName: tc.toolName,
1781
+ tool,
1782
+ toolsContext:
1783
+ toolsContext as unknown as InferToolSetContext<TTools>,
1784
+ });
1565
1785
  return tool.needsApproval(tc.input, {
1566
1786
  toolCallId: tc.toolCallId,
1567
1787
  messages: iterMessages as unknown as ModelMessage[],
1568
- context: experimentalContext,
1788
+ context: resolvedContext,
1569
1789
  });
1570
1790
  }),
1571
1791
  );
@@ -1601,7 +1821,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1601
1821
  toolCall,
1602
1822
  effectiveTools as ToolSet,
1603
1823
  iterMessages,
1604
- experimentalContext,
1824
+ toolsContext,
1605
1825
  currentStepNumber,
1606
1826
  ),
1607
1827
  ),
@@ -1659,7 +1879,9 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1659
1879
  text: lastStep?.text ?? '',
1660
1880
  finishReason: lastStep?.finishReason ?? 'other',
1661
1881
  totalUsage: aggregateUsage(steps),
1662
- experimental_context: experimentalContext,
1882
+ runtimeContext,
1883
+ toolsContext:
1884
+ toolsContext as unknown as InferToolSetContext<TTools>,
1663
1885
  output: undefined as OUTPUT,
1664
1886
  });
1665
1887
  }
@@ -1710,7 +1932,7 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1710
1932
  toolCall,
1711
1933
  effectiveTools as ToolSet,
1712
1934
  iterMessages,
1713
- experimentalContext,
1935
+ toolsContext,
1714
1936
  currentStepNumber,
1715
1937
  ),
1716
1938
  ),
@@ -1846,7 +2068,8 @@ export class WorkflowAgent<TBaseTools extends ToolSet = ToolSet> {
1846
2068
  text: lastStep?.text ?? '',
1847
2069
  finishReason: lastStep?.finishReason ?? 'other',
1848
2070
  totalUsage: aggregateUsage(steps),
1849
- experimental_context: experimentalContext,
2071
+ runtimeContext,
2072
+ toolsContext: toolsContext as unknown as InferToolSetContext<TTools>,
1850
2073
  output: experimentalOutput,
1851
2074
  });
1852
2075
  }
@@ -2003,6 +2226,33 @@ async function writeApprovalToolResults(
2003
2226
  }
2004
2227
  }
2005
2228
 
2229
+ /**
2230
+ * Resolve the per-tool context that gets passed into a tool's `execute`
2231
+ * (and `needsApproval`) function. When the tool declares a `contextSchema`,
2232
+ * the entry is validated against it.
2233
+ */
2234
+ async function resolveToolContext({
2235
+ toolName,
2236
+ tool,
2237
+ toolsContext,
2238
+ }: {
2239
+ toolName: string;
2240
+ tool: ToolSet[string];
2241
+ toolsContext: Record<string, Context | undefined> | undefined;
2242
+ }): Promise<unknown> {
2243
+ const contextSchema = (tool as { contextSchema?: unknown }).contextSchema;
2244
+ const entry = toolsContext?.[toolName];
2245
+ if (contextSchema == null) {
2246
+ return entry;
2247
+ }
2248
+
2249
+ return await validateTypes({
2250
+ value: entry,
2251
+ schema: contextSchema as Parameters<typeof validateTypes>[0]['schema'],
2252
+ context: { field: 'tool context', entityName: toolName },
2253
+ });
2254
+ }
2255
+
2006
2256
  function aggregateUsage(steps: StepResult<any, any>[]): LanguageModelUsage {
2007
2257
  let inputTokens = 0;
2008
2258
  let outputTokens = 0;
@@ -2097,11 +2347,19 @@ function createInvalidToolResult(toolCall: {
2097
2347
  };
2098
2348
  }
2099
2349
 
2350
+ function getToolCallbackMessages(
2351
+ messages: LanguageModelV4Prompt,
2352
+ ): ModelMessage[] {
2353
+ const withoutAssistantToolCall =
2354
+ messages.at(-1)?.role === 'assistant' ? messages.slice(0, -1) : messages;
2355
+ return withoutAssistantToolCall as unknown as ModelMessage[];
2356
+ }
2357
+
2100
2358
  async function executeTool(
2101
2359
  toolCall: { toolCallId: string; toolName: string; input: unknown },
2102
2360
  tools: ToolSet,
2103
2361
  messages: LanguageModelV4Prompt,
2104
- experimentalContext?: unknown,
2362
+ context?: unknown,
2105
2363
  ): Promise<LanguageModelV4ToolResultPart> {
2106
2364
  const tool = tools[toolCall.toolName];
2107
2365
  if (!tool) throw new Error(`Tool "${toolCall.toolName}" not found`);
@@ -2125,8 +2383,8 @@ async function executeTool(
2125
2383
  toolCallId: toolCall.toolCallId,
2126
2384
  // Pass the conversation messages to the tool so it has context about the conversation
2127
2385
  messages,
2128
- // Pass context to the tool
2129
- context: experimentalContext,
2386
+ // Pass per-tool context to the tool (resolved from `toolsContext`)
2387
+ context,
2130
2388
  });
2131
2389
 
2132
2390
  // Use the appropriate output type based on the result