ai 7.0.152 → 7.0.154

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/index.d.ts +224 -9
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +440 -120
  5. package/dist/index.js.map +1 -1
  6. package/dist/internal/index.d.ts +52 -4
  7. package/dist/internal/index.d.ts.map +1 -1
  8. package/dist/internal/index.js +26 -20
  9. package/dist/internal/index.js.map +1 -1
  10. package/docs/02-getting-started/02-nextjs-app-router.mdx +2 -2
  11. package/docs/02-getting-started/08-angular.mdx +327 -0
  12. package/docs/02-getting-started/{03-nextjs-pages-router.mdx → 10-nextjs-pages-router.mdx} +12 -20
  13. package/docs/02-getting-started/index.mdx +2 -0
  14. package/docs/03-agents/01-overview.mdx +1 -0
  15. package/docs/03-agents/04-loop-control.mdx +117 -0
  16. package/docs/03-agents/06-tool-approvals.mdx +1 -0
  17. package/docs/03-agents/09-chat-platforms.mdx +164 -0
  18. package/docs/03-agents/index.mdx +6 -0
  19. package/docs/03-ai-sdk-core/60-telemetry.mdx +16 -3
  20. package/docs/03-ai-sdk-core/65-lifecycle-callbacks.mdx +10 -0
  21. package/docs/04-ai-sdk-ui/21-transport.mdx +86 -0
  22. package/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx +46 -0
  23. package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +46 -0
  24. package/docs/07-reference/01-ai-sdk-core/16-tool-loop-agent.mdx +35 -0
  25. package/package.json +12 -12
  26. package/src/agent/create-agent-ui-stream-response.ts +3 -0
  27. package/src/agent/create-agent-ui-stream.ts +16 -0
  28. package/src/agent/pipe-agent-ui-stream-to-response.ts +3 -0
  29. package/src/agent/tool-loop-agent-settings.ts +37 -1
  30. package/src/agent/tool-loop-agent.ts +43 -7
  31. package/src/generate-object/generate-object.ts +1 -1
  32. package/src/generate-text/generate-text-events.ts +37 -0
  33. package/src/generate-text/generate-text.ts +528 -374
  34. package/src/generate-text/index.ts +8 -0
  35. package/src/generate-text/prepare-step.ts +12 -0
  36. package/src/generate-text/restricted-telemetry-dispatcher.ts +31 -18
  37. package/src/generate-text/steering.ts +293 -0
  38. package/src/generate-text/step-result.ts +18 -0
  39. package/src/generate-text/stream-text.ts +664 -473
  40. package/src/middleware/extract-json-middleware.ts +8 -2
  41. package/src/middleware/extract-reasoning-middleware.ts +42 -30
  42. package/src/telemetry/create-telemetry-dispatcher.ts +3 -0
  43. package/src/telemetry/telemetry.ts +15 -1
  44. package/src/util/is-caused-by-abort.ts +20 -0
@@ -73,8 +73,10 @@ import type {
73
73
  GenerateTextOnEndCallback,
74
74
  GenerateTextOnStartCallback,
75
75
  GenerateTextOnStepEndCallback,
76
+ GenerateTextOnStepErrorCallback,
76
77
  GenerateTextOnStepFinishCallback,
77
78
  GenerateTextOnStepStartCallback,
79
+ GenerateTextStepStartEvent,
78
80
  } from './generate-text-events';
79
81
  import { DefaultGenerateTextResult } from './default-generate-text-result';
80
82
  import type { GenerateTextResult } from './generate-text-result';
@@ -95,6 +97,12 @@ import {
95
97
  type StepResult,
96
98
  type StepResultPerformance,
97
99
  } from './step-result';
100
+ import {
101
+ startSteeringRun,
102
+ type Steering,
103
+ type SteeringNotDeliveredReason,
104
+ type SteeringRun,
105
+ } from './steering';
98
106
  import {
99
107
  isStepCount,
100
108
  isStopConditionMet,
@@ -208,6 +216,7 @@ export type GenerateTextInclude = {
208
216
  * @param headers - Additional HTTP headers to be sent with the request. Only applicable for HTTP-based providers.
209
217
  *
210
218
  * @param experimental_sandbox - The sandbox environment that is passed through to tool execution.
219
+ * @param experimental_steering - A steering object that adds user messages to the generation at the next step boundary.
211
220
  * @param runtimeContext - User-defined runtime context that flows through the entire generation lifecycle.
212
221
  * @param experimental_refineToolInput - Optional mapping of tool names to functions that refine parsed tool inputs before tools are executed and before outputs, callbacks, and telemetry are recorded.
213
222
  * @param onStart - Callback invoked when generation begins, before any LLM calls.
@@ -226,6 +235,7 @@ export type GenerateTextInclude = {
226
235
  * Uses a discriminated union: check `success` to determine if `output` or `error` is present.
227
236
  * @param experimental_onToolCallFinish - Deprecated alias for `onToolExecutionEnd`.
228
237
  * @param onStepFinish - Callback that is called when each step (LLM call) is finished, including intermediate steps.
238
+ * @param onStepError - Callback that is called when a step that started fails before it produces a step result, i.e. when the provider call throws or rejects, or when the call is aborted or times out.
229
239
  * @param onEnd - Callback that is called when all steps are finished and the response is complete.
230
240
  * @param onFinish - Deprecated alias for `onEnd`.
231
241
  *
@@ -236,348 +246,406 @@ export async function generateText<
236
246
  TOOLS extends ToolSet,
237
247
  RUNTIME_CONTEXT extends Context = Context,
238
248
  OUTPUT extends Output = Output<string, string>,
239
- >({
240
- model: modelArg,
241
- tools,
242
- toolChoice,
243
- instructions,
244
- system,
245
- prompt,
246
- messages,
247
- allowSystemInMessages,
248
- maxRetries: maxRetriesArg,
249
- abortSignal,
250
- timeout,
251
- headers,
252
- stopWhen = isStepCount(1),
253
- experimental_sandbox: sandbox,
254
- output,
255
- toolApproval,
256
- experimental_toolCallers,
257
- experimental_toolApprovalSecret,
258
- experimental_telemetry,
259
- telemetry = experimental_telemetry,
260
- providerOptions,
261
- activeTools,
262
- toolOrder,
263
- toolCallConcurrency,
264
- prepareStep,
265
- experimental_repairToolCall,
266
- repairToolCall = experimental_repairToolCall,
267
- experimental_refineToolInput: refineToolInput,
268
- experimental_download: download,
269
- runtimeContext = {} as RUNTIME_CONTEXT,
270
- toolsContext = {} as InferToolSetContext<TOOLS>,
271
- experimental_include,
272
- include = experimental_include,
273
- _internal: {
274
- generateId = originalGenerateId,
275
- generateCallId = originalGenerateCallId,
276
- now = originalNow,
277
- } = {},
278
- onStart,
279
- experimental_onStart,
280
- onStepStart,
281
- experimental_onStepStart,
282
- onLanguageModelCallStart,
283
- experimental_onLanguageModelCallStart,
284
- onLanguageModelCallEnd,
285
- experimental_onLanguageModelCallEnd,
286
- onToolExecutionStart,
287
- onToolExecutionEnd,
288
- experimental_onToolCallStart,
289
- experimental_onToolCallFinish,
290
- onStepEnd,
291
- onStepFinish,
292
- onFinish,
293
- onEnd = onFinish,
294
- ...settings
295
- }: LanguageModelCallOptions &
296
- RequestOptions<TOOLS> &
297
- Prompt &
298
- ToolsContextParameter<TOOLS> & {
299
- /**
300
- * The language model to use.
301
- */
302
- model: LanguageModel;
303
-
304
- /**
305
- * The tool choice strategy. Default: 'auto'.
306
- */
307
- toolChoice?: ToolChoice<NoInfer<TOOLS>>;
308
-
309
- /**
310
- * Condition for stopping the generation when there are tool results in the last step.
311
- * When the condition is an array, any of the conditions can be met to stop the generation.
312
- *
313
- * @default isStepCount(1)
314
- */
315
- stopWhen?: Arrayable<StopCondition<NoInfer<TOOLS>, RUNTIME_CONTEXT>>;
316
-
317
- /**
318
- * Optional telemetry configuration.
319
- */
320
- telemetry?: TelemetryOptions<RUNTIME_CONTEXT, NoInfer<TOOLS>>;
321
-
322
- /**
323
- * Optional telemetry configuration.
324
- *
325
- * @deprecated Use `telemetry` instead. This alias will be removed in a future major release.
326
- */
327
- experimental_telemetry?: TelemetryOptions<RUNTIME_CONTEXT, NoInfer<TOOLS>>;
328
-
329
- /**
330
- * Additional provider-specific options. They are passed through
331
- * to the provider from the AI SDK and enable provider-specific
332
- * functionality that can be fully encapsulated in the provider.
333
- */
334
- providerOptions?: ProviderOptions;
335
-
336
- /**
337
- * The sandbox environment that is passed through to tool execution.
338
- */
339
- experimental_sandbox?: SandboxSession;
340
-
341
- /**
342
- * Runtime context. Treat runtime context as immutable.
343
- * If you need to mutate runtime context, update it in `prepareStep`.
344
- */
345
- runtimeContext?: RUNTIME_CONTEXT;
346
-
347
- /**
348
- * Limits the tools that are available for the model to call without
349
- * changing the tool call and result types in the result.
350
- */
351
- activeTools?: ActiveTools<NoInfer<TOOLS>>;
352
-
353
- /**
354
- * Controls the order in which tools are sent to the provider.
355
- *
356
- * The list can be partial. Tools not listed in `toolOrder` are sent after
357
- * the listed tools, sorted alphabetically. This can improve provider-side
358
- * caching by keeping tool definitions in a stable order.
359
- */
360
- toolOrder?: ToolOrder<NoInfer<TOOLS>>;
361
-
362
- /**
363
- * Maximum number of tool calls that may execute concurrently within a step.
364
- *
365
- * Set to `1` to execute tool calls sequentially in the order they were
366
- * generated. By default, all tool calls execute concurrently.
367
- */
368
- toolCallConcurrency?: number;
369
-
370
- /**
371
- * Optional specification for parsing structured outputs from the LLM response.
372
- */
373
- output?: OUTPUT;
374
-
375
- /**
376
- * Optional tool approval configuration.
377
- *
378
- * This configuration takes precedence over tool-defined approval settings.
379
- */
380
- toolApproval?: ToolApprovalConfiguration<TOOLS, RUNTIME_CONTEXT>;
381
-
382
- /**
383
- * Configures which caller tools may invoke each tool.
384
- */
385
- experimental_toolCallers?: Experimental_ToolCallers<NoInfer<TOOLS>>;
386
-
387
- /**
388
- * Secret for HMAC-signing tool approval requests. When set, the server
389
- * signs each approval request at issuance and verifies the signature when
390
- * the approval is replayed, preventing client-forged approvals.
391
- */
392
- experimental_toolApprovalSecret?: string | Uint8Array;
393
-
394
- /**
395
- * Custom download function to use for URLs.
396
- *
397
- * By default, files are downloaded if the model does not support the URL for the given media type.
398
- */
399
- experimental_download?: DownloadFunction | undefined;
400
-
401
- /**
402
- * Optional function that you can use to provide different settings for a step.
403
- */
404
- prepareStep?: PrepareStepFunction<NoInfer<TOOLS>, RUNTIME_CONTEXT>;
405
-
406
- /**
407
- * A function that attempts to repair a tool call that failed to parse.
408
- */
409
- repairToolCall?: ToolCallRepairFunction<NoInfer<TOOLS>>;
410
-
411
- /**
412
- * A function that attempts to repair a tool call that failed to parse.
413
- *
414
- * @deprecated Use `repairToolCall` instead.
415
- */
416
- experimental_repairToolCall?: ToolCallRepairFunction<NoInfer<TOOLS>>;
417
-
418
- /**
419
- * Optional mapping of tool names to functions that refine parsed tool inputs.
420
- *
421
- * The refined input must have the same type shape as the tool input. Refined
422
- * inputs are used for tool execution, outputs, callbacks, and telemetry.
423
- */
424
- experimental_refineToolInput?: ToolInputRefinement<NoInfer<TOOLS>>;
425
-
426
- /**
427
- * Callback that is called when the generateText operation begins,
428
- * before any LLM calls are made.
429
- */
430
- onStart?: GenerateTextOnStartCallback<
431
- NoInfer<TOOLS>,
432
- NoInfer<RUNTIME_CONTEXT>,
433
- NoInfer<OUTPUT>
434
- >;
435
-
436
- /**
437
- * Callback that is called when the generateText operation begins,
438
- * before any LLM calls are made.
439
- *
440
- * @deprecated Use `onStart` instead.
441
- */
442
- experimental_onStart?: GenerateTextOnStartCallback<
443
- NoInfer<TOOLS>,
444
- NoInfer<RUNTIME_CONTEXT>,
445
- NoInfer<OUTPUT>
446
- >;
447
-
448
- /**
449
- * Callback that is called when a step (LLM call) begins,
450
- * before the provider is called.
451
- */
452
- onStepStart?: GenerateTextOnStepStartCallback<
453
- NoInfer<TOOLS>,
454
- NoInfer<RUNTIME_CONTEXT>,
455
- NoInfer<OUTPUT>
456
- >;
457
-
458
- /**
459
- * Callback that is called when a step (LLM call) begins,
460
- * before the provider is called.
461
- *
462
- * @deprecated Use `onStepStart` instead.
463
- */
464
- experimental_onStepStart?: GenerateTextOnStepStartCallback<
465
- NoInfer<TOOLS>,
466
- NoInfer<RUNTIME_CONTEXT>,
467
- NoInfer<OUTPUT>
468
- >;
469
-
470
- /**
471
- * Callback that is called immediately before the provider model call begins.
472
- */
473
- onLanguageModelCallStart?: OnLanguageModelCallStartCallback;
474
-
475
- /**
476
- * Callback that is called immediately before the provider model call begins.
477
- *
478
- * @deprecated Use `onLanguageModelCallStart` instead.
479
- */
480
- experimental_onLanguageModelCallStart?: OnLanguageModelCallStartCallback;
481
-
482
- /**
483
- * Callback that is called after the model response has been normalized and parsed,
484
- * but before any client-side tool execution begins.
485
- */
486
- onLanguageModelCallEnd?: OnLanguageModelCallEndCallback<NoInfer<TOOLS>>;
487
-
488
- /**
489
- * Callback that is called after the model response has been normalized and parsed,
490
- * but before any client-side tool execution begins.
491
- *
492
- * @deprecated Use `onLanguageModelCallEnd` instead.
493
- */
494
- experimental_onLanguageModelCallEnd?: OnLanguageModelCallEndCallback<
495
- NoInfer<TOOLS>
496
- >;
497
-
498
- /**
499
- * Callback that is called right before a tool's execute function runs.
500
- */
501
- onToolExecutionStart?: OnToolExecutionStartCallback<NoInfer<TOOLS>>;
502
-
503
- /**
504
- * Callback that is called right before a tool's execute function runs.
505
- *
506
- * @deprecated Use `onToolExecutionStart` instead.
507
- */
508
- experimental_onToolCallStart?: OnToolExecutionStartCallback<NoInfer<TOOLS>>;
509
-
510
- /**
511
- * Callback that is called right after a tool's execute function completes (or errors).
512
- */
513
- onToolExecutionEnd?: OnToolExecutionEndCallback<NoInfer<TOOLS>>;
514
-
515
- /**
516
- * Callback that is called right after a tool's execute function completes (or errors).
517
- *
518
- * @deprecated Use `onToolExecutionEnd` instead.
519
- */
520
- experimental_onToolCallFinish?: OnToolExecutionEndCallback<NoInfer<TOOLS>>;
521
-
522
- /**
523
- * Callback that is called when each step (LLM call) ends, including intermediate steps.
524
- */
525
- onStepEnd?: GenerateTextOnStepEndCallback<
526
- NoInfer<TOOLS>,
527
- NoInfer<RUNTIME_CONTEXT>
528
- >;
529
-
530
- /**
531
- * Callback that is called when each step (LLM call) ends, including intermediate steps.
532
- *
533
- * @deprecated Use `onStepEnd` instead.
534
- */
535
- onStepFinish?: GenerateTextOnStepFinishCallback<
536
- NoInfer<TOOLS>,
537
- NoInfer<RUNTIME_CONTEXT>
538
- >;
539
-
540
- /**
541
- * Callback that is called when all steps are finished and the response is complete.
542
- */
543
- onEnd?: GenerateTextOnEndCallback<NoInfer<TOOLS>, NoInfer<RUNTIME_CONTEXT>>;
544
-
545
- /**
546
- * Callback that is called when all steps are finished and the response is complete.
547
- *
548
- * @deprecated Use `onEnd` instead.
549
- */
550
- onFinish?: GenerateTextOnEndCallback<
551
- NoInfer<TOOLS>,
552
- NoInfer<RUNTIME_CONTEXT>
553
- >;
554
-
555
- /**
556
- * Settings for controlling what data is included in step results.
557
- * Disabling inclusion can help reduce memory usage when processing
558
- * large payloads like images.
559
- *
560
- * By default, request bodies, request messages, and response bodies are
561
- * excluded.
562
- */
563
- include?: GenerateTextInclude;
564
-
565
- /**
566
- * Settings for controlling what data is included in step results.
567
- *
568
- * @deprecated Use `include` instead.
569
- */
570
- experimental_include?: GenerateTextInclude;
571
-
572
- /**
573
- * Internal. For test use only. May change without notice.
574
- */
575
- _internal?: {
576
- generateId?: IdGenerator;
577
- generateCallId?: IdGenerator;
578
- now?: () => number;
579
- };
580
- }): Promise<GenerateTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>> {
249
+ >(
250
+ options: GenerateTextOptions<TOOLS, RUNTIME_CONTEXT, OUTPUT>,
251
+ ): Promise<GenerateTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>> {
252
+ const steeringRun = startSteeringRun(options.experimental_steering);
253
+
254
+ try {
255
+ return await generateTextInternal<TOOLS, RUNTIME_CONTEXT, OUTPUT>(
256
+ options,
257
+ steeringRun,
258
+ );
259
+ } catch (error) {
260
+ // the call can fail before its loop starts, e.g. when the prompt is invalid:
261
+ steeringRun?.end(options.abortSignal?.aborted ? 'aborted' : 'error');
262
+ throw error;
263
+ }
264
+ }
265
+
266
+ type GenerateTextOptions<
267
+ TOOLS extends ToolSet,
268
+ RUNTIME_CONTEXT extends Context,
269
+ OUTPUT extends Output,
270
+ > = Parameters<typeof generateTextInternal<TOOLS, RUNTIME_CONTEXT, OUTPUT>>[0];
271
+
272
+ async function generateTextInternal<
273
+ TOOLS extends ToolSet,
274
+ RUNTIME_CONTEXT extends Context = Context,
275
+ OUTPUT extends Output = Output<string, string>,
276
+ >(
277
+ {
278
+ model: modelArg,
279
+ tools,
280
+ toolChoice,
281
+ instructions,
282
+ system,
283
+ prompt,
284
+ messages,
285
+ allowSystemInMessages,
286
+ maxRetries: maxRetriesArg,
287
+ abortSignal,
288
+ timeout,
289
+ headers,
290
+ stopWhen = isStepCount(1),
291
+ experimental_sandbox: sandbox,
292
+ output,
293
+ toolApproval,
294
+ experimental_toolCallers,
295
+ experimental_toolApprovalSecret,
296
+ experimental_telemetry,
297
+ telemetry = experimental_telemetry,
298
+ providerOptions,
299
+ activeTools,
300
+ toolOrder,
301
+ toolCallConcurrency,
302
+ prepareStep,
303
+ experimental_repairToolCall,
304
+ repairToolCall = experimental_repairToolCall,
305
+ experimental_refineToolInput: refineToolInput,
306
+ experimental_download: download,
307
+ runtimeContext = {} as RUNTIME_CONTEXT,
308
+ toolsContext = {} as InferToolSetContext<TOOLS>,
309
+ experimental_include,
310
+ include = experimental_include,
311
+ _internal: {
312
+ generateId = originalGenerateId,
313
+ generateCallId = originalGenerateCallId,
314
+ now = originalNow,
315
+ } = {},
316
+ onStart,
317
+ experimental_onStart,
318
+ onStepStart,
319
+ experimental_onStepStart,
320
+ onLanguageModelCallStart,
321
+ experimental_onLanguageModelCallStart,
322
+ onLanguageModelCallEnd,
323
+ experimental_onLanguageModelCallEnd,
324
+ onToolExecutionStart,
325
+ onToolExecutionEnd,
326
+ experimental_onToolCallStart,
327
+ experimental_onToolCallFinish,
328
+ onStepEnd,
329
+ onStepError,
330
+ onStepFinish,
331
+ onFinish,
332
+ onEnd = onFinish,
333
+ ...settings
334
+ }: LanguageModelCallOptions &
335
+ RequestOptions<TOOLS> &
336
+ Prompt &
337
+ ToolsContextParameter<TOOLS> & {
338
+ /**
339
+ * The language model to use.
340
+ */
341
+ model: LanguageModel;
342
+
343
+ /**
344
+ * The tool choice strategy. Default: 'auto'.
345
+ */
346
+ toolChoice?: ToolChoice<NoInfer<TOOLS>>;
347
+
348
+ /**
349
+ * Condition for stopping the generation when there are tool results in the last step.
350
+ * When the condition is an array, any of the conditions can be met to stop the generation.
351
+ *
352
+ * @default isStepCount(1)
353
+ */
354
+ stopWhen?: Arrayable<StopCondition<NoInfer<TOOLS>, RUNTIME_CONTEXT>>;
355
+
356
+ /**
357
+ * Optional telemetry configuration.
358
+ */
359
+ telemetry?: TelemetryOptions<RUNTIME_CONTEXT, NoInfer<TOOLS>>;
360
+
361
+ /**
362
+ * Optional telemetry configuration.
363
+ *
364
+ * @deprecated Use `telemetry` instead. This alias will be removed in a future major release.
365
+ */
366
+ experimental_telemetry?: TelemetryOptions<
367
+ RUNTIME_CONTEXT,
368
+ NoInfer<TOOLS>
369
+ >;
370
+
371
+ /**
372
+ * Additional provider-specific options. They are passed through
373
+ * to the provider from the AI SDK and enable provider-specific
374
+ * functionality that can be fully encapsulated in the provider.
375
+ */
376
+ providerOptions?: ProviderOptions;
377
+
378
+ /**
379
+ * The sandbox environment that is passed through to tool execution.
380
+ */
381
+ experimental_sandbox?: SandboxSession;
382
+
383
+ /**
384
+ * A steering object created with `experimental_createSteering()`.
385
+ * Messages sent with it are added to the generation at the next step
386
+ * boundary.
387
+ */
388
+ experimental_steering?: Steering;
389
+
390
+ /**
391
+ * Runtime context. Treat runtime context as immutable.
392
+ * If you need to mutate runtime context, update it in `prepareStep`.
393
+ */
394
+ runtimeContext?: RUNTIME_CONTEXT;
395
+
396
+ /**
397
+ * Limits the tools that are available for the model to call without
398
+ * changing the tool call and result types in the result.
399
+ */
400
+ activeTools?: ActiveTools<NoInfer<TOOLS>>;
401
+
402
+ /**
403
+ * Controls the order in which tools are sent to the provider.
404
+ *
405
+ * The list can be partial. Tools not listed in `toolOrder` are sent after
406
+ * the listed tools, sorted alphabetically. This can improve provider-side
407
+ * caching by keeping tool definitions in a stable order.
408
+ */
409
+ toolOrder?: ToolOrder<NoInfer<TOOLS>>;
410
+
411
+ /**
412
+ * Maximum number of tool calls that may execute concurrently within a step.
413
+ *
414
+ * Set to `1` to execute tool calls sequentially in the order they were
415
+ * generated. By default, all tool calls execute concurrently.
416
+ */
417
+ toolCallConcurrency?: number;
418
+
419
+ /**
420
+ * Optional specification for parsing structured outputs from the LLM response.
421
+ */
422
+ output?: OUTPUT;
423
+
424
+ /**
425
+ * Optional tool approval configuration.
426
+ *
427
+ * This configuration takes precedence over tool-defined approval settings.
428
+ */
429
+ toolApproval?: ToolApprovalConfiguration<TOOLS, RUNTIME_CONTEXT>;
430
+
431
+ /**
432
+ * Configures which caller tools may invoke each tool.
433
+ */
434
+ experimental_toolCallers?: Experimental_ToolCallers<NoInfer<TOOLS>>;
435
+
436
+ /**
437
+ * Secret for HMAC-signing tool approval requests. When set, the server
438
+ * signs each approval request at issuance and verifies the signature when
439
+ * the approval is replayed, preventing client-forged approvals.
440
+ */
441
+ experimental_toolApprovalSecret?: string | Uint8Array;
442
+
443
+ /**
444
+ * Custom download function to use for URLs.
445
+ *
446
+ * By default, files are downloaded if the model does not support the URL for the given media type.
447
+ */
448
+ experimental_download?: DownloadFunction | undefined;
449
+
450
+ /**
451
+ * Optional function that you can use to provide different settings for a step.
452
+ */
453
+ prepareStep?: PrepareStepFunction<NoInfer<TOOLS>, RUNTIME_CONTEXT>;
454
+
455
+ /**
456
+ * A function that attempts to repair a tool call that failed to parse.
457
+ */
458
+ repairToolCall?: ToolCallRepairFunction<NoInfer<TOOLS>>;
459
+
460
+ /**
461
+ * A function that attempts to repair a tool call that failed to parse.
462
+ *
463
+ * @deprecated Use `repairToolCall` instead.
464
+ */
465
+ experimental_repairToolCall?: ToolCallRepairFunction<NoInfer<TOOLS>>;
466
+
467
+ /**
468
+ * Optional mapping of tool names to functions that refine parsed tool inputs.
469
+ *
470
+ * The refined input must have the same type shape as the tool input. Refined
471
+ * inputs are used for tool execution, outputs, callbacks, and telemetry.
472
+ */
473
+ experimental_refineToolInput?: ToolInputRefinement<NoInfer<TOOLS>>;
474
+
475
+ /**
476
+ * Callback that is called when the generateText operation begins,
477
+ * before any LLM calls are made.
478
+ */
479
+ onStart?: GenerateTextOnStartCallback<
480
+ NoInfer<TOOLS>,
481
+ NoInfer<RUNTIME_CONTEXT>,
482
+ NoInfer<OUTPUT>
483
+ >;
484
+
485
+ /**
486
+ * Callback that is called when the generateText operation begins,
487
+ * before any LLM calls are made.
488
+ *
489
+ * @deprecated Use `onStart` instead.
490
+ */
491
+ experimental_onStart?: GenerateTextOnStartCallback<
492
+ NoInfer<TOOLS>,
493
+ NoInfer<RUNTIME_CONTEXT>,
494
+ NoInfer<OUTPUT>
495
+ >;
496
+
497
+ /**
498
+ * Callback that is called when a step (LLM call) begins,
499
+ * before the provider is called.
500
+ */
501
+ onStepStart?: GenerateTextOnStepStartCallback<
502
+ NoInfer<TOOLS>,
503
+ NoInfer<RUNTIME_CONTEXT>,
504
+ NoInfer<OUTPUT>
505
+ >;
506
+
507
+ /**
508
+ * Callback that is called when a step (LLM call) begins,
509
+ * before the provider is called.
510
+ *
511
+ * @deprecated Use `onStepStart` instead.
512
+ */
513
+ experimental_onStepStart?: GenerateTextOnStepStartCallback<
514
+ NoInfer<TOOLS>,
515
+ NoInfer<RUNTIME_CONTEXT>,
516
+ NoInfer<OUTPUT>
517
+ >;
518
+
519
+ /**
520
+ * Callback that is called immediately before the provider model call begins.
521
+ */
522
+ onLanguageModelCallStart?: OnLanguageModelCallStartCallback;
523
+
524
+ /**
525
+ * Callback that is called immediately before the provider model call begins.
526
+ *
527
+ * @deprecated Use `onLanguageModelCallStart` instead.
528
+ */
529
+ experimental_onLanguageModelCallStart?: OnLanguageModelCallStartCallback;
530
+
531
+ /**
532
+ * Callback that is called after the model response has been normalized and parsed,
533
+ * but before any client-side tool execution begins.
534
+ */
535
+ onLanguageModelCallEnd?: OnLanguageModelCallEndCallback<NoInfer<TOOLS>>;
536
+
537
+ /**
538
+ * Callback that is called after the model response has been normalized and parsed,
539
+ * but before any client-side tool execution begins.
540
+ *
541
+ * @deprecated Use `onLanguageModelCallEnd` instead.
542
+ */
543
+ experimental_onLanguageModelCallEnd?: OnLanguageModelCallEndCallback<
544
+ NoInfer<TOOLS>
545
+ >;
546
+
547
+ /**
548
+ * Callback that is called right before a tool's execute function runs.
549
+ */
550
+ onToolExecutionStart?: OnToolExecutionStartCallback<NoInfer<TOOLS>>;
551
+
552
+ /**
553
+ * Callback that is called right before a tool's execute function runs.
554
+ *
555
+ * @deprecated Use `onToolExecutionStart` instead.
556
+ */
557
+ experimental_onToolCallStart?: OnToolExecutionStartCallback<
558
+ NoInfer<TOOLS>
559
+ >;
560
+
561
+ /**
562
+ * Callback that is called right after a tool's execute function completes (or errors).
563
+ */
564
+ onToolExecutionEnd?: OnToolExecutionEndCallback<NoInfer<TOOLS>>;
565
+
566
+ /**
567
+ * Callback that is called right after a tool's execute function completes (or errors).
568
+ *
569
+ * @deprecated Use `onToolExecutionEnd` instead.
570
+ */
571
+ experimental_onToolCallFinish?: OnToolExecutionEndCallback<
572
+ NoInfer<TOOLS>
573
+ >;
574
+
575
+ /**
576
+ * Callback that is called when each step (LLM call) ends, including intermediate steps.
577
+ */
578
+ onStepEnd?: GenerateTextOnStepEndCallback<
579
+ NoInfer<TOOLS>,
580
+ NoInfer<RUNTIME_CONTEXT>
581
+ >;
582
+
583
+ /**
584
+ * Callback that is called when a step that started fails before it
585
+ * produces a step result. `onStepEnd` is not called for such a step.
586
+ */
587
+ onStepError?: GenerateTextOnStepErrorCallback<
588
+ NoInfer<TOOLS>,
589
+ NoInfer<RUNTIME_CONTEXT>,
590
+ NoInfer<OUTPUT>
591
+ >;
592
+
593
+ /**
594
+ * Callback that is called when each step (LLM call) ends, including intermediate steps.
595
+ *
596
+ * @deprecated Use `onStepEnd` instead.
597
+ */
598
+ onStepFinish?: GenerateTextOnStepFinishCallback<
599
+ NoInfer<TOOLS>,
600
+ NoInfer<RUNTIME_CONTEXT>
601
+ >;
602
+
603
+ /**
604
+ * Callback that is called when all steps are finished and the response is complete.
605
+ */
606
+ onEnd?: GenerateTextOnEndCallback<
607
+ NoInfer<TOOLS>,
608
+ NoInfer<RUNTIME_CONTEXT>
609
+ >;
610
+
611
+ /**
612
+ * Callback that is called when all steps are finished and the response is complete.
613
+ *
614
+ * @deprecated Use `onEnd` instead.
615
+ */
616
+ onFinish?: GenerateTextOnEndCallback<
617
+ NoInfer<TOOLS>,
618
+ NoInfer<RUNTIME_CONTEXT>
619
+ >;
620
+
621
+ /**
622
+ * Settings for controlling what data is included in step results.
623
+ * Disabling inclusion can help reduce memory usage when processing
624
+ * large payloads like images.
625
+ *
626
+ * By default, request bodies, request messages, and response bodies are
627
+ * excluded.
628
+ */
629
+ include?: GenerateTextInclude;
630
+
631
+ /**
632
+ * Settings for controlling what data is included in step results.
633
+ *
634
+ * @deprecated Use `include` instead.
635
+ */
636
+ experimental_include?: GenerateTextInclude;
637
+
638
+ /**
639
+ * Internal. For test use only. May change without notice.
640
+ */
641
+ _internal?: {
642
+ generateId?: IdGenerator;
643
+ generateCallId?: IdGenerator;
644
+ now?: () => number;
645
+ };
646
+ },
647
+ steeringRun: SteeringRun | undefined,
648
+ ): Promise<GenerateTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>> {
581
649
  // assign default values to include:
582
650
  include = {
583
651
  requestBody: include?.requestBody ?? false,
@@ -718,6 +786,16 @@ export async function generateText<
718
786
  callbacks: [resolvedOnStart, telemetryDispatcher.onStart],
719
787
  });
720
788
 
789
+ // the step that has started but not ended, reported to onStepError when
790
+ // the call fails before the step produces a result:
791
+ let openStep:
792
+ | GenerateTextStepStartEvent<
793
+ NoInfer<TOOLS>,
794
+ NoInfer<RUNTIME_CONTEXT>,
795
+ NoInfer<OUTPUT>
796
+ >
797
+ | undefined;
798
+
721
799
  try {
722
800
  const initialMessages = initialPrompt.messages;
723
801
  const initialResponseMessages: Array<ResponseMessage> = [];
@@ -880,6 +958,49 @@ export async function generateText<
880
958
  // These tools may not return their results in the same turn as their call.
881
959
  const pendingDeferredToolCalls = new Map<string, { toolName: string }>();
882
960
 
961
+ // why waiting steering messages are not delivered when the loop ends:
962
+ let steeringEndReason: SteeringNotDeliveredReason = 'finished';
963
+
964
+ const shouldStartNextStep = async () => {
965
+ if (steps[steps.length - 1].finishReason === 'interrupted') {
966
+ return false;
967
+ }
968
+
969
+ // Continue only after all client tool calls have been executed or denied:
970
+ if (
971
+ clientToolOutputs.length + deniedToolApprovalResponses.length !==
972
+ clientToolCalls.length
973
+ ) {
974
+ steeringEndReason = 'waiting-for-tool-results';
975
+ return false;
976
+ }
977
+
978
+ // Continue if there are client results, pending deferred provider
979
+ // results, or steering messages:
980
+ if (
981
+ clientToolCalls.length === 0 &&
982
+ pendingDeferredToolCalls.size === 0
983
+ ) {
984
+ if (!steeringRun?.hasPendingMessages()) {
985
+ return false;
986
+ }
987
+
988
+ // steering messages do not continue a failed step:
989
+ if (steps[steps.length - 1].finishReason === 'error') {
990
+ steeringEndReason = 'error';
991
+ return false;
992
+ }
993
+ }
994
+
995
+ // continue until a stop condition is met:
996
+ if (await isStopConditionMet({ stopConditions, steps })) {
997
+ steeringEndReason = 'stop-condition';
998
+ return false;
999
+ }
1000
+
1001
+ return true;
1002
+ };
1003
+
883
1004
  do {
884
1005
  if (steps.length > 0) {
885
1006
  mergedAbortSignal?.throwIfAborted();
@@ -893,6 +1014,11 @@ export async function generateText<
893
1014
  });
894
1015
  const stepNumber = steps.length;
895
1016
 
1017
+ const steeringMessages = steeringRun?.takeMessages() ?? [];
1018
+ if (steeringMessages.length > 0) {
1019
+ messagesForNextStep = [...messagesForNextStep, ...steeringMessages];
1020
+ }
1021
+
896
1022
  try {
897
1023
  await runInTracingChannelSpan({
898
1024
  type: 'step',
@@ -913,6 +1039,9 @@ export async function generateText<
913
1039
  messages: stepInputMessages,
914
1040
  initialMessages,
915
1041
  responseMessages: accumulatedResponseMessages,
1042
+ ...(steeringMessages.length > 0
1043
+ ? { experimental_steeringMessages: steeringMessages }
1044
+ : {}),
916
1045
  runtimeContext,
917
1046
  toolsContext,
918
1047
  experimental_sandbox: sandbox,
@@ -977,6 +1106,14 @@ export async function generateText<
977
1106
  toolCallerMessages,
978
1107
  });
979
1108
 
1109
+ // steering messages are delivered when they are in the messages
1110
+ // that are sent to the model after prepareStep:
1111
+ const deliveredSteeringMessages =
1112
+ steeringRun?.resolveTakenMessages({
1113
+ stepNumber,
1114
+ sentMessages: stepMessages,
1115
+ }) ?? [];
1116
+
980
1117
  const promptMessages = await convertToLanguageModelPrompt({
981
1118
  prompt: {
982
1119
  instructions: stepInstructions,
@@ -998,33 +1135,37 @@ export async function generateText<
998
1135
  stepSettings: prepareStepResult,
999
1136
  });
1000
1137
 
1138
+ const stepStartEvent = {
1139
+ callId,
1140
+ provider: stepModel.provider,
1141
+ modelId: stepModel.modelId,
1142
+ stepNumber,
1143
+ instructions: stepInstructions,
1144
+ messages: stepMessages,
1145
+ tools,
1146
+ toolChoice: prepareStepResult?.toolChoice ?? toolChoice,
1147
+ activeTools: prepareStepResult?.activeTools ?? activeTools,
1148
+ toolOrder: stepToolOrder,
1149
+ steps: [...steps],
1150
+ providerOptions: stepProviderOptions,
1151
+ output,
1152
+ runtimeContext,
1153
+ promptMessages,
1154
+ stepTools,
1155
+ stepToolChoice,
1156
+ toolsContext,
1157
+ };
1158
+
1001
1159
  await notify({
1002
- event: {
1003
- callId,
1004
- provider: stepModel.provider,
1005
- modelId: stepModel.modelId,
1006
- stepNumber,
1007
- instructions: stepInstructions,
1008
- messages: stepMessages,
1009
- tools,
1010
- toolChoice: prepareStepResult?.toolChoice ?? toolChoice,
1011
- activeTools: prepareStepResult?.activeTools ?? activeTools,
1012
- toolOrder: stepToolOrder,
1013
- steps: [...steps],
1014
- providerOptions: stepProviderOptions,
1015
- output,
1016
- runtimeContext,
1017
- promptMessages,
1018
- stepTools,
1019
- stepToolChoice,
1020
- toolsContext,
1021
- },
1160
+ event: stepStartEvent,
1022
1161
  callbacks: [
1023
1162
  resolvedOnStepStart,
1024
1163
  telemetryDispatcher.onStepStart,
1025
1164
  ],
1026
1165
  });
1027
1166
 
1167
+ openStep = stepStartEvent;
1168
+
1028
1169
  const languageModelCallContext = {
1029
1170
  provider: stepModel.provider,
1030
1171
  modelId: stepModel.modelId,
@@ -1516,6 +1657,7 @@ export async function generateText<
1516
1657
  request: stepRequest,
1517
1658
  response: stepResponse,
1518
1659
  toolsContext,
1660
+ steeringMessages: deliveredSteeringMessages,
1519
1661
  });
1520
1662
 
1521
1663
  logWarnings({
@@ -1528,6 +1670,8 @@ export async function generateText<
1528
1670
  instructionsForNextStep = stepInstructions;
1529
1671
  messagesForNextStep = [...stepMessages, ...stepResponseMessages];
1530
1672
 
1673
+ openStep = undefined;
1674
+
1531
1675
  await notify({
1532
1676
  event: currentStepResult,
1533
1677
  callbacks: [resolvedOnStepEnd, telemetryDispatcher.onStepEnd],
@@ -1541,16 +1685,9 @@ export async function generateText<
1541
1685
  clearTimeout(stepTimeoutId);
1542
1686
  }
1543
1687
  }
1544
- } while (
1545
- steps[steps.length - 1].finishReason !== 'interrupted' &&
1546
- // Continue only after all client tool calls have been executed or denied,
1547
- // and if there are client results or pending deferred provider results.
1548
- clientToolOutputs.length + deniedToolApprovalResponses.length ===
1549
- clientToolCalls.length &&
1550
- (clientToolCalls.length > 0 || pendingDeferredToolCalls.size > 0) &&
1551
- // continue until a stop condition is met:
1552
- !(await isStopConditionMet({ stopConditions, steps }))
1553
- );
1688
+ } while (await shouldStartNextStep());
1689
+
1690
+ steeringRun?.end(steeringEndReason);
1554
1691
 
1555
1692
  const lastStep = steps[steps.length - 1];
1556
1693
 
@@ -1631,8 +1768,14 @@ export async function generateText<
1631
1768
  (lastStep.finishReason !== 'tool-calls' && lastStep.text.length > 0)
1632
1769
  ) {
1633
1770
  const outputSpecification = output ?? text();
1771
+ // Select the structured output without changing the complete response
1772
+ // content, text, or messages exposed to callers.
1773
+ const textForOutput =
1774
+ (await outputSpecification.responseFormat)?.type === 'json'
1775
+ ? (currentModelResponse!.structuredOutputText ?? lastStep.text)
1776
+ : lastStep.text;
1634
1777
  resolvedOutput = await outputSpecification.parseCompleteOutput(
1635
- { text: lastStep.text },
1778
+ { text: textForOutput },
1636
1779
  {
1637
1780
  response: lastStep.response,
1638
1781
  usage: lastStep.usage,
@@ -1648,8 +1791,19 @@ export async function generateText<
1648
1791
  output: resolvedOutput,
1649
1792
  });
1650
1793
  } catch (error) {
1794
+ const wrappedError = wrapGatewayError(error);
1795
+
1796
+ steeringRun?.end(mergedAbortSignal?.aborted ? 'aborted' : 'error');
1797
+
1798
+ // generateText has no onAbort, so aborts and timeouts also end the step here:
1799
+ if (openStep != null) {
1800
+ await notify({
1801
+ event: { ...openStep, error: wrappedError },
1802
+ callbacks: [onStepError, telemetryDispatcher.onStepError],
1803
+ });
1804
+ }
1651
1805
  await telemetryDispatcher.onError?.({ callId, error });
1652
- throw wrapGatewayError(error);
1806
+ throw wrappedError;
1653
1807
  }
1654
1808
  };
1655
1809