ai 6.0.99 → 6.0.101

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "6.0.99",
3
+ "version": "6.0.101",
4
4
  "description": "AI SDK by Vercel - The AI Toolkit for TypeScript and JavaScript",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -1,5 +1,6 @@
1
1
  import { executeTool, ModelMessage } from '@ai-sdk/provider-utils';
2
2
  import { Tracer } from '@opentelemetry/api';
3
+ import { notify } from '../util/notify';
3
4
  import { assembleOperationName } from '../telemetry/assemble-operation-name';
4
5
  import { recordErrorOnSpan, recordSpan } from '../telemetry/record-span';
5
6
  import { selectTelemetryAttributes } from '../telemetry/select-telemetry-attributes';
@@ -91,11 +92,7 @@ export async function executeToolCall<TOOLS extends ToolSet>({
91
92
  fn: async span => {
92
93
  let output: unknown;
93
94
 
94
- try {
95
- await onToolCallStart?.(baseCallbackEvent);
96
- } catch (_ignored) {
97
- // Errors in callbacks should not break the generation flow.
98
- }
95
+ await notify({ event: baseCallbackEvent, callbacks: onToolCallStart });
99
96
 
100
97
  const startTime = now();
101
98
 
@@ -126,16 +123,15 @@ export async function executeToolCall<TOOLS extends ToolSet>({
126
123
  } catch (error) {
127
124
  const durationMs = now() - startTime;
128
125
 
129
- try {
130
- await onToolCallFinish?.({
126
+ await notify({
127
+ event: {
131
128
  ...baseCallbackEvent,
132
- success: false,
129
+ success: false as const,
133
130
  error,
134
131
  durationMs,
135
- });
136
- } catch (_ignored) {
137
- // Errors in callbacks should not break the generation flow.
138
- }
132
+ },
133
+ callbacks: onToolCallFinish,
134
+ });
139
135
 
140
136
  recordErrorOnSpan(span, error);
141
137
  return {
@@ -153,16 +149,15 @@ export async function executeToolCall<TOOLS extends ToolSet>({
153
149
 
154
150
  const durationMs = now() - startTime;
155
151
 
156
- try {
157
- await onToolCallFinish?.({
152
+ await notify({
153
+ event: {
158
154
  ...baseCallbackEvent,
159
- success: true,
155
+ success: true as const,
160
156
  output,
161
157
  durationMs,
162
- });
163
- } catch (_ignored) {
164
- // Errors in callbacks should not break the generation flow.
165
- }
158
+ },
159
+ callbacks: onToolCallFinish,
160
+ });
166
161
 
167
162
  try {
168
163
  span.setAttributes(
@@ -15,6 +15,7 @@ import {
15
15
  } from '@ai-sdk/provider-utils';
16
16
  import { Tracer } from '@opentelemetry/api';
17
17
  import { NoOutputGeneratedError } from '../error';
18
+ import { notify } from '../util/notify';
18
19
  import { logWarnings } from '../logger/log-warnings';
19
20
  import { resolveLanguageModel } from '../model/resolve-model';
20
21
  import { ModelMessage } from '../prompt';
@@ -479,8 +480,8 @@ export async function generateText<
479
480
  messages,
480
481
  } as Prompt);
481
482
 
482
- try {
483
- await onStart?.({
483
+ await notify({
484
+ event: {
484
485
  model: modelInfo,
485
486
  system,
486
487
  prompt,
@@ -507,10 +508,9 @@ export async function generateText<
507
508
  functionId: telemetry?.functionId,
508
509
  metadata: telemetry?.metadata as Record<string, unknown> | undefined,
509
510
  experimental_context,
510
- });
511
- } catch (_ignored) {
512
- // Errors in callbacks should not break the generation flow.
513
- }
511
+ },
512
+ callbacks: onStart,
513
+ });
514
514
 
515
515
  const tracer = getTracer(telemetry);
516
516
 
@@ -712,8 +712,8 @@ export async function generateText<
712
712
  prepareStepResult?.providerOptions,
713
713
  );
714
714
 
715
- try {
716
- await onStepStart?.({
715
+ await notify({
716
+ event: {
717
717
  stepNumber: steps.length,
718
718
  model: stepModelInfo,
719
719
  system: stepSystem,
@@ -734,10 +734,9 @@ export async function generateText<
734
734
  | Record<string, unknown>
735
735
  | undefined,
736
736
  experimental_context,
737
- });
738
- } catch (_ignored) {
739
- // Errors in callbacks should not break the generation flow.
740
- }
737
+ },
738
+ callbacks: onStepStart,
739
+ });
741
740
 
742
741
  currentModelResponse = await retry(() =>
743
742
  recordSpan({
@@ -1056,7 +1055,8 @@ export async function generateText<
1056
1055
  });
1057
1056
 
1058
1057
  steps.push(currentStepResult);
1059
- await onStepFinish?.(currentStepResult);
1058
+
1059
+ await notify({ event: currentStepResult, callbacks: onStepFinish });
1060
1060
  } finally {
1061
1061
  if (stepTimeoutId != null) {
1062
1062
  clearTimeout(stepTimeoutId);
@@ -1123,33 +1123,36 @@ export async function generateText<
1123
1123
  } as LanguageModelUsage,
1124
1124
  );
1125
1125
 
1126
- await onFinish?.({
1127
- stepNumber: lastStep.stepNumber,
1128
- model: lastStep.model,
1129
- functionId: lastStep.functionId,
1130
- metadata: lastStep.metadata,
1131
- experimental_context: lastStep.experimental_context,
1132
- finishReason: lastStep.finishReason,
1133
- rawFinishReason: lastStep.rawFinishReason,
1134
- usage: lastStep.usage,
1135
- content: lastStep.content,
1136
- text: lastStep.text,
1137
- reasoningText: lastStep.reasoningText,
1138
- reasoning: lastStep.reasoning,
1139
- files: lastStep.files,
1140
- sources: lastStep.sources,
1141
- toolCalls: lastStep.toolCalls,
1142
- staticToolCalls: lastStep.staticToolCalls,
1143
- dynamicToolCalls: lastStep.dynamicToolCalls,
1144
- toolResults: lastStep.toolResults,
1145
- staticToolResults: lastStep.staticToolResults,
1146
- dynamicToolResults: lastStep.dynamicToolResults,
1147
- request: lastStep.request,
1148
- response: lastStep.response,
1149
- warnings: lastStep.warnings,
1150
- providerMetadata: lastStep.providerMetadata,
1151
- steps,
1152
- totalUsage,
1126
+ await notify({
1127
+ event: {
1128
+ stepNumber: lastStep.stepNumber,
1129
+ model: lastStep.model,
1130
+ functionId: lastStep.functionId,
1131
+ metadata: lastStep.metadata,
1132
+ experimental_context: lastStep.experimental_context,
1133
+ finishReason: lastStep.finishReason,
1134
+ rawFinishReason: lastStep.rawFinishReason,
1135
+ usage: lastStep.usage,
1136
+ content: lastStep.content,
1137
+ text: lastStep.text,
1138
+ reasoningText: lastStep.reasoningText,
1139
+ reasoning: lastStep.reasoning,
1140
+ files: lastStep.files,
1141
+ sources: lastStep.sources,
1142
+ toolCalls: lastStep.toolCalls,
1143
+ staticToolCalls: lastStep.staticToolCalls,
1144
+ dynamicToolCalls: lastStep.dynamicToolCalls,
1145
+ toolResults: lastStep.toolResults,
1146
+ staticToolResults: lastStep.staticToolResults,
1147
+ dynamicToolResults: lastStep.dynamicToolResults,
1148
+ request: lastStep.request,
1149
+ response: lastStep.response,
1150
+ warnings: lastStep.warnings,
1151
+ providerMetadata: lastStep.providerMetadata,
1152
+ steps,
1153
+ totalUsage,
1154
+ },
1155
+ callbacks: onFinish,
1153
1156
  });
1154
1157
 
1155
1158
  // parse output only if the last step was finished with "stop":
@@ -19,6 +19,7 @@ import {
19
19
  import { Span } from '@opentelemetry/api';
20
20
  import { ServerResponse } from 'node:http';
21
21
  import { NoOutputGeneratedError } from '../error';
22
+ import { notify } from '../util/notify';
22
23
  import { logWarnings } from '../logger/log-warnings';
23
24
  import { resolveLanguageModel } from '../model/resolve-model';
24
25
  import {
@@ -1028,7 +1029,7 @@ class DefaultStreamTextResult<TOOLS extends ToolSet, OUTPUT extends Output>
1028
1029
  providerMetadata: part.providerMetadata,
1029
1030
  });
1030
1031
 
1031
- await onStepFinish?.(currentStepResult);
1032
+ await notify({ event: currentStepResult, callbacks: onStepFinish });
1032
1033
 
1033
1034
  logWarnings({
1034
1035
  warnings: recordedWarnings,
@@ -1084,33 +1085,37 @@ class DefaultStreamTextResult<TOOLS extends ToolSet, OUTPUT extends Output>
1084
1085
 
1085
1086
  // call onFinish callback:
1086
1087
  const finalStep = recordedSteps[recordedSteps.length - 1];
1087
- await onFinish?.({
1088
- stepNumber: finalStep.stepNumber,
1089
- model: finalStep.model,
1090
- functionId: finalStep.functionId,
1091
- metadata: finalStep.metadata,
1092
- experimental_context: finalStep.experimental_context,
1093
- finishReason: finalStep.finishReason,
1094
- rawFinishReason: finalStep.rawFinishReason,
1095
- totalUsage,
1096
- usage: finalStep.usage,
1097
- content: finalStep.content,
1098
- text: finalStep.text,
1099
- reasoningText: finalStep.reasoningText,
1100
- reasoning: finalStep.reasoning,
1101
- files: finalStep.files,
1102
- sources: finalStep.sources,
1103
- toolCalls: finalStep.toolCalls,
1104
- staticToolCalls: finalStep.staticToolCalls,
1105
- dynamicToolCalls: finalStep.dynamicToolCalls,
1106
- toolResults: finalStep.toolResults,
1107
- staticToolResults: finalStep.staticToolResults,
1108
- dynamicToolResults: finalStep.dynamicToolResults,
1109
- request: finalStep.request,
1110
- response: finalStep.response,
1111
- warnings: finalStep.warnings,
1112
- providerMetadata: finalStep.providerMetadata,
1113
- steps: recordedSteps,
1088
+
1089
+ await notify({
1090
+ event: {
1091
+ stepNumber: finalStep.stepNumber,
1092
+ model: finalStep.model,
1093
+ functionId: finalStep.functionId,
1094
+ metadata: finalStep.metadata,
1095
+ experimental_context: finalStep.experimental_context,
1096
+ finishReason: finalStep.finishReason,
1097
+ rawFinishReason: finalStep.rawFinishReason,
1098
+ totalUsage,
1099
+ usage: finalStep.usage,
1100
+ content: finalStep.content,
1101
+ text: finalStep.text,
1102
+ reasoningText: finalStep.reasoningText,
1103
+ reasoning: finalStep.reasoning,
1104
+ files: finalStep.files,
1105
+ sources: finalStep.sources,
1106
+ toolCalls: finalStep.toolCalls,
1107
+ staticToolCalls: finalStep.staticToolCalls,
1108
+ dynamicToolCalls: finalStep.dynamicToolCalls,
1109
+ toolResults: finalStep.toolResults,
1110
+ staticToolResults: finalStep.staticToolResults,
1111
+ dynamicToolResults: finalStep.dynamicToolResults,
1112
+ request: finalStep.request,
1113
+ response: finalStep.response,
1114
+ warnings: finalStep.warnings,
1115
+ providerMetadata: finalStep.providerMetadata,
1116
+ steps: recordedSteps,
1117
+ },
1118
+ callbacks: onFinish,
1114
1119
  });
1115
1120
 
1116
1121
  // Add response information to the root span:
@@ -1271,8 +1276,8 @@ class DefaultStreamTextResult<TOOLS extends ToolSet, OUTPUT extends Output>
1271
1276
  messages,
1272
1277
  } as Prompt);
1273
1278
 
1274
- try {
1275
- await onStart?.({
1279
+ await notify({
1280
+ event: {
1276
1281
  model: modelInfo,
1277
1282
  system,
1278
1283
  prompt,
@@ -1298,10 +1303,9 @@ class DefaultStreamTextResult<TOOLS extends ToolSet, OUTPUT extends Output>
1298
1303
  include,
1299
1304
  ...callbackTelemetryProps,
1300
1305
  experimental_context,
1301
- });
1302
- } catch (_ignored) {
1303
- // Errors in callbacks should not break the generation flow.
1304
- }
1306
+ },
1307
+ callbacks: onStart,
1308
+ });
1305
1309
 
1306
1310
  const initialMessages = initialPrompt.messages;
1307
1311
  const initialResponseMessages: Array<ResponseMessage> = [];
@@ -1549,8 +1553,8 @@ class DefaultStreamTextResult<TOOLS extends ToolSet, OUTPUT extends Output>
1549
1553
  prepareStepResult?.providerOptions,
1550
1554
  );
1551
1555
 
1552
- try {
1553
- await onStepStart?.({
1556
+ await notify({
1557
+ event: {
1554
1558
  stepNumber: recordedSteps.length,
1555
1559
  model: stepModelInfo,
1556
1560
  system: stepSystem,
@@ -1568,10 +1572,9 @@ class DefaultStreamTextResult<TOOLS extends ToolSet, OUTPUT extends Output>
1568
1572
  include,
1569
1573
  ...callbackTelemetryProps,
1570
1574
  experimental_context,
1571
- });
1572
- } catch (_ignored) {
1573
- // Errors in callbacks should not break the generation flow.
1574
- }
1575
+ },
1576
+ callbacks: onStepStart,
1577
+ });
1575
1578
 
1576
1579
  const {
1577
1580
  result: { stream, response, request },
@@ -558,7 +558,18 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
558
558
  }
559
559
 
560
560
  case 'tool-input-error': {
561
- if (chunk.dynamic) {
561
+ // When a part already exists for this toolCallId (e.g. from
562
+ // tool-input-start), honour its type so we update in place
563
+ // instead of creating a duplicate with a mismatched type.
564
+ const existingPart = state.message.parts
565
+ .filter(isToolUIPart)
566
+ .find(p => p.toolCallId === chunk.toolCallId);
567
+ const isDynamic =
568
+ existingPart != null
569
+ ? existingPart.type === 'dynamic-tool'
570
+ : !!chunk.dynamic;
571
+
572
+ if (isDynamic) {
562
573
  updateDynamicToolPart({
563
574
  toolCallId: chunk.toolCallId,
564
575
  toolName: chunk.toolName,
@@ -0,0 +1,18 @@
1
+ import { asArray } from './as-array';
2
+
3
+ export type Listener<EVENT> = (event: EVENT) => PromiseLike<void> | void;
4
+
5
+ /**
6
+ * Notifies all provided callbacks with the given event.
7
+ * Errors in callbacks do not break the generation flow.
8
+ */
9
+ export async function notify<EVENT>(options: {
10
+ event: EVENT;
11
+ callbacks?: Listener<EVENT> | Array<Listener<EVENT>>;
12
+ }): Promise<void> {
13
+ for (const callback of asArray(options.callbacks)) {
14
+ try {
15
+ await callback(options.event);
16
+ } catch (_ignored) {}
17
+ }
18
+ }