ai 3.4.2 → 3.4.4

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/dist/index.mjs CHANGED
@@ -2915,6 +2915,19 @@ function prepareToolsAndToolChoice({
2915
2915
  };
2916
2916
  }
2917
2917
 
2918
+ // core/util/split-on-last-whitespace.ts
2919
+ var lastWhitespaceRegexp = /^([\s\S]*?)(\s+)(\S*)$/;
2920
+ function splitOnLastWhitespace(text) {
2921
+ const match = text.match(lastWhitespaceRegexp);
2922
+ return match ? { prefix: match[1], whitespace: match[2], suffix: match[3] } : void 0;
2923
+ }
2924
+
2925
+ // core/util/remove-text-after-last-whitespace.ts
2926
+ function removeTextAfterLastWhitespace(text) {
2927
+ const match = splitOnLastWhitespace(text);
2928
+ return match ? match.prefix + match.whitespace : text;
2929
+ }
2930
+
2918
2931
  // core/generate-text/parse-tool-call.ts
2919
2932
  import { safeParseJSON as safeParseJSON2, safeValidateTypes as safeValidateTypes3 } from "@ai-sdk/provider-utils";
2920
2933
  import { asSchema as asSchema3 } from "@ai-sdk/ui-utils";
@@ -2990,7 +3003,8 @@ async function generateText({
2990
3003
  maxAutomaticRoundtrips = 0,
2991
3004
  maxToolRoundtrips = maxAutomaticRoundtrips,
2992
3005
  maxSteps = maxToolRoundtrips != null ? maxToolRoundtrips + 1 : 1,
2993
- experimental_continuationSteps: continuationSteps = false,
3006
+ experimental_continuationSteps,
3007
+ experimental_continueSteps: continueSteps = experimental_continuationSteps != null ? experimental_continuationSteps : false,
2994
3008
  experimental_telemetry: telemetry,
2995
3009
  experimental_providerMetadata: providerMetadata,
2996
3010
  _internal: {
@@ -3034,7 +3048,7 @@ async function generateText({
3034
3048
  }),
3035
3049
  tracer,
3036
3050
  fn: async (span) => {
3037
- var _a12, _b, _c, _d, _e, _f;
3051
+ var _a12, _b, _c, _d, _e;
3038
3052
  const retry = retryWithExponentialBackoff({ maxRetries });
3039
3053
  const validatedPrompt = validatePrompt({
3040
3054
  system,
@@ -3094,7 +3108,7 @@ async function generateText({
3094
3108
  }),
3095
3109
  tracer,
3096
3110
  fn: async (span2) => {
3097
- var _a13, _b2, _c2, _d2, _e2, _f2;
3111
+ var _a13, _b2, _c2, _d2, _e2, _f;
3098
3112
  const result = await model.doGenerate({
3099
3113
  mode,
3100
3114
  ...callSettings,
@@ -3107,7 +3121,7 @@ async function generateText({
3107
3121
  const responseData = {
3108
3122
  id: (_b2 = (_a13 = result.response) == null ? void 0 : _a13.id) != null ? _b2 : generateId3(),
3109
3123
  timestamp: (_d2 = (_c2 = result.response) == null ? void 0 : _c2.timestamp) != null ? _d2 : currentDate(),
3110
- modelId: (_f2 = (_e2 = result.response) == null ? void 0 : _e2.modelId) != null ? _f2 : model.modelId
3124
+ modelId: (_f = (_e2 = result.response) == null ? void 0 : _e2.modelId) != null ? _f : model.modelId
3111
3125
  };
3112
3126
  span2.setAttributes(
3113
3127
  selectTelemetryAttributes({
@@ -3161,13 +3175,24 @@ async function generateText({
3161
3175
  usage.completionTokens += currentUsage.completionTokens;
3162
3176
  usage.promptTokens += currentUsage.promptTokens;
3163
3177
  usage.totalTokens += currentUsage.totalTokens;
3164
- if (stepType === "continuation") {
3165
- text += " " + ((_b = currentModelResponse.text) != null ? _b : "");
3166
- } else {
3167
- text = (_c = currentModelResponse.text) != null ? _c : "";
3178
+ let nextStepType = "done";
3179
+ if (++stepCount < maxSteps) {
3180
+ if (continueSteps && currentModelResponse.finishReason === "length" && // only use continue when there are no tool calls:
3181
+ currentToolCalls.length === 0) {
3182
+ nextStepType = "continue";
3183
+ } else if (
3184
+ // there are tool calls:
3185
+ currentToolCalls.length > 0 && // all current tool calls have results:
3186
+ currentToolResults.length === currentToolCalls.length
3187
+ ) {
3188
+ nextStepType = "tool-result";
3189
+ }
3168
3190
  }
3191
+ const stepText = nextStepType === "continue" ? removeTextAfterLastWhitespace((_b = currentModelResponse.text) != null ? _b : "") : (_c = currentModelResponse.text) != null ? _c : "";
3192
+ text = nextStepType === "continue" || stepType === "continue" ? text + stepText : stepText;
3169
3193
  const currentStep = {
3170
- text: (_d = currentModelResponse.text) != null ? _d : "",
3194
+ stepType,
3195
+ text: stepText,
3171
3196
  toolCalls: currentToolCalls,
3172
3197
  toolResults: currentToolResults,
3173
3198
  finishReason: currentModelResponse.finishReason,
@@ -3176,20 +3201,20 @@ async function generateText({
3176
3201
  logprobs: currentModelResponse.logprobs,
3177
3202
  response: {
3178
3203
  ...currentModelResponse.response,
3179
- headers: (_e = currentModelResponse.rawResponse) == null ? void 0 : _e.headers
3204
+ headers: (_d = currentModelResponse.rawResponse) == null ? void 0 : _d.headers
3180
3205
  },
3181
3206
  experimental_providerMetadata: currentModelResponse.providerMetadata
3182
3207
  };
3183
3208
  steps.push(currentStep);
3184
3209
  await (onStepFinish == null ? void 0 : onStepFinish(currentStep));
3185
- if (stepType === "continuation") {
3210
+ if (stepType === "continue") {
3186
3211
  const lastResponseMessage = responseMessages.pop();
3187
3212
  promptMessages.pop();
3188
3213
  if (typeof lastResponseMessage.content === "string") {
3189
3214
  lastResponseMessage.content = text;
3190
3215
  } else {
3191
3216
  lastResponseMessage.content.push({
3192
- text: " " + currentModelResponse.text,
3217
+ text: stepText,
3193
3218
  type: "text"
3194
3219
  });
3195
3220
  }
@@ -3197,6 +3222,18 @@ async function generateText({
3197
3222
  promptMessages.push(
3198
3223
  convertToLanguageModelMessage(lastResponseMessage, null)
3199
3224
  );
3225
+ } else if (nextStepType === "continue") {
3226
+ const newResponseMessages = toResponseMessages({
3227
+ text,
3228
+ toolCalls: currentToolCalls,
3229
+ toolResults: currentToolResults
3230
+ });
3231
+ responseMessages.push(...newResponseMessages);
3232
+ promptMessages.push(
3233
+ ...newResponseMessages.map(
3234
+ (message) => convertToLanguageModelMessage(message, null)
3235
+ )
3236
+ );
3200
3237
  } else {
3201
3238
  const newResponseMessages = toResponseMessages({
3202
3239
  text: currentModelResponse.text,
@@ -3210,20 +3247,7 @@ async function generateText({
3210
3247
  )
3211
3248
  );
3212
3249
  }
3213
- if (++stepCount >= maxSteps) {
3214
- stepType = "done";
3215
- } else if (continuationSteps === true && currentStep.finishReason === "length" && // only use continuation when there are no tool calls:
3216
- currentToolCalls.length === 0) {
3217
- stepType = "continuation";
3218
- } else if (
3219
- // there are tool calls:
3220
- currentToolCalls.length > 0 && // all current tool calls have results:
3221
- currentToolResults.length === currentToolCalls.length
3222
- ) {
3223
- stepType = "tool-result";
3224
- } else {
3225
- stepType = "done";
3226
- }
3250
+ stepType = nextStepType;
3227
3251
  } while (stepType !== "done");
3228
3252
  span.setAttributes(
3229
3253
  selectTelemetryAttributes({
@@ -3258,7 +3282,7 @@ async function generateText({
3258
3282
  warnings: currentModelResponse.warnings,
3259
3283
  response: {
3260
3284
  ...currentModelResponse.response,
3261
- headers: (_f = currentModelResponse.rawResponse) == null ? void 0 : _f.headers
3285
+ headers: (_e = currentModelResponse.rawResponse) == null ? void 0 : _e.headers
3262
3286
  },
3263
3287
  logprobs: currentModelResponse.logprobs,
3264
3288
  responseMessages,
@@ -3704,6 +3728,7 @@ async function streamText({
3704
3728
  headers,
3705
3729
  maxToolRoundtrips = 0,
3706
3730
  maxSteps = maxToolRoundtrips != null ? maxToolRoundtrips + 1 : 1,
3731
+ experimental_continueSteps: continueSteps = false,
3707
3732
  experimental_telemetry: telemetry,
3708
3733
  experimental_providerMetadata: providerMetadata,
3709
3734
  experimental_toolCallStreaming: toolCallStreaming = false,
@@ -3848,6 +3873,7 @@ async function streamText({
3848
3873
  telemetry,
3849
3874
  startTimestampMs,
3850
3875
  maxSteps,
3876
+ continueSteps,
3851
3877
  startStep,
3852
3878
  promptMessages,
3853
3879
  modelId: model.modelId,
@@ -3871,6 +3897,7 @@ var DefaultStreamTextResult = class {
3871
3897
  telemetry,
3872
3898
  startTimestampMs,
3873
3899
  maxSteps,
3900
+ continueSteps,
3874
3901
  startStep,
3875
3902
  promptMessages,
3876
3903
  modelId,
@@ -3922,7 +3949,9 @@ var DefaultStreamTextResult = class {
3922
3949
  promptTokens: 0,
3923
3950
  completionTokens: 0,
3924
3951
  totalTokens: 0
3925
- }
3952
+ },
3953
+ stepType,
3954
+ previousStepText = ""
3926
3955
  }) {
3927
3956
  const stepToolCalls = [];
3928
3957
  const stepToolResults = [];
@@ -3935,12 +3964,25 @@ var DefaultStreamTextResult = class {
3935
3964
  let stepProviderMetadata;
3936
3965
  let stepFirstChunk = true;
3937
3966
  let stepText = "";
3967
+ let fullStepText = stepType === "continue" ? previousStepText : "";
3938
3968
  let stepLogProbs;
3939
3969
  let stepResponse = {
3940
3970
  id: generateId3(),
3941
3971
  timestamp: currentDate(),
3942
3972
  modelId
3943
3973
  };
3974
+ let chunkBuffer = "";
3975
+ let chunkTextPublished = false;
3976
+ async function publishTextChunk({
3977
+ controller,
3978
+ chunk
3979
+ }) {
3980
+ controller.enqueue(chunk);
3981
+ stepText += chunk.textDelta;
3982
+ fullStepText += chunk.textDelta;
3983
+ chunkTextPublished = true;
3984
+ await (onChunk == null ? void 0 : onChunk({ chunk }));
3985
+ }
3944
3986
  addStream(
3945
3987
  stream2.pipeThrough(
3946
3988
  new TransformStream({
@@ -3966,9 +4008,22 @@ var DefaultStreamTextResult = class {
3966
4008
  const chunkType = chunk.type;
3967
4009
  switch (chunkType) {
3968
4010
  case "text-delta": {
3969
- controller.enqueue(chunk);
3970
- stepText += chunk.textDelta;
3971
- await (onChunk == null ? void 0 : onChunk({ chunk }));
4011
+ if (continueSteps) {
4012
+ chunkBuffer += chunk.textDelta;
4013
+ const split = splitOnLastWhitespace(chunkBuffer);
4014
+ if (split != null) {
4015
+ chunkBuffer = split.suffix;
4016
+ await publishTextChunk({
4017
+ controller,
4018
+ chunk: {
4019
+ type: "text-delta",
4020
+ textDelta: split.prefix + split.whitespace
4021
+ }
4022
+ });
4023
+ }
4024
+ } else {
4025
+ await publishTextChunk({ controller, chunk });
4026
+ }
3972
4027
  break;
3973
4028
  }
3974
4029
  case "tool-call": {
@@ -4024,6 +4079,30 @@ var DefaultStreamTextResult = class {
4024
4079
  // invoke onFinish callback and resolve toolResults promise when the stream is about to close:
4025
4080
  async flush(controller) {
4026
4081
  const stepToolCallsJson = stepToolCalls.length > 0 ? JSON.stringify(stepToolCalls) : void 0;
4082
+ let nextStepType = "done";
4083
+ if (currentStep + 1 < maxSteps) {
4084
+ if (continueSteps && stepFinishReason === "length" && // only use continue when there are no tool calls:
4085
+ stepToolCalls.length === 0) {
4086
+ nextStepType = "continue";
4087
+ } else if (
4088
+ // there are tool calls:
4089
+ stepToolCalls.length > 0 && // all current tool calls have results:
4090
+ stepToolResults.length === stepToolCalls.length
4091
+ ) {
4092
+ nextStepType = "tool-result";
4093
+ }
4094
+ }
4095
+ if (continueSteps && chunkBuffer.length > 0 && (nextStepType !== "continue" || // when the next step is a regular step, publish the buffer
4096
+ stepType === "continue" && !chunkTextPublished)) {
4097
+ await publishTextChunk({
4098
+ controller,
4099
+ chunk: {
4100
+ type: "text-delta",
4101
+ textDelta: chunkBuffer
4102
+ }
4103
+ });
4104
+ chunkBuffer = "";
4105
+ }
4027
4106
  try {
4028
4107
  doStreamSpan2.setAttributes(
4029
4108
  selectTelemetryAttributes({
@@ -4067,6 +4146,7 @@ var DefaultStreamTextResult = class {
4067
4146
  response: stepResponse
4068
4147
  });
4069
4148
  const stepResult = {
4149
+ stepType,
4070
4150
  text: stepText,
4071
4151
  toolCalls: stepToolCalls,
4072
4152
  toolResults: stepToolResults,
@@ -4085,21 +4165,24 @@ var DefaultStreamTextResult = class {
4085
4165
  completionTokens: usage.completionTokens + stepUsage.completionTokens,
4086
4166
  totalTokens: usage.totalTokens + stepUsage.totalTokens
4087
4167
  };
4088
- if (
4089
- // there are tool calls:
4090
- stepToolCalls.length > 0 && // all current tool calls have results:
4091
- stepToolResults.length === stepToolCalls.length && // the number of steps is less than the maximum:
4092
- currentStep + 1 < maxSteps
4093
- ) {
4094
- promptMessages2.push(
4095
- ...toResponseMessages({
4168
+ if (nextStepType !== "done") {
4169
+ if (stepType === "continue") {
4170
+ const lastPromptMessage = promptMessages2[promptMessages2.length - 1];
4171
+ lastPromptMessage.content.push({
4096
4172
  text: stepText,
4097
- toolCalls: stepToolCalls,
4098
- toolResults: stepToolResults
4099
- }).map(
4100
- (message) => convertToLanguageModelMessage(message, null)
4101
- )
4102
- );
4173
+ type: "text"
4174
+ });
4175
+ } else {
4176
+ promptMessages2.push(
4177
+ ...toResponseMessages({
4178
+ text: stepText,
4179
+ toolCalls: stepToolCalls,
4180
+ toolResults: stepToolResults
4181
+ }).map(
4182
+ (message) => convertToLanguageModelMessage(message, null)
4183
+ )
4184
+ );
4185
+ }
4103
4186
  const {
4104
4187
  result,
4105
4188
  doStreamSpan: doStreamSpan3,
@@ -4116,7 +4199,9 @@ var DefaultStreamTextResult = class {
4116
4199
  doStreamSpan: doStreamSpan3,
4117
4200
  currentStep: currentStep + 1,
4118
4201
  promptMessages: promptMessages2,
4119
- usage: combinedUsage
4202
+ usage: combinedUsage,
4203
+ stepType: nextStepType,
4204
+ previousStepText: fullStepText
4120
4205
  });
4121
4206
  return;
4122
4207
  }
@@ -4135,7 +4220,7 @@ var DefaultStreamTextResult = class {
4135
4220
  telemetry,
4136
4221
  attributes: {
4137
4222
  "ai.response.finishReason": stepFinishReason,
4138
- "ai.response.text": { output: () => stepText },
4223
+ "ai.response.text": { output: () => fullStepText },
4139
4224
  "ai.response.toolCalls": {
4140
4225
  output: () => stepToolCallsJson
4141
4226
  },
@@ -4143,27 +4228,38 @@ var DefaultStreamTextResult = class {
4143
4228
  "ai.usage.completionTokens": combinedUsage.completionTokens,
4144
4229
  // deprecated
4145
4230
  "ai.finishReason": stepFinishReason,
4146
- "ai.result.text": { output: () => stepText },
4231
+ "ai.result.text": { output: () => fullStepText },
4147
4232
  "ai.result.toolCalls": {
4148
4233
  output: () => stepToolCallsJson
4149
4234
  }
4150
4235
  }
4151
4236
  })
4152
4237
  );
4153
- const responseMessages = stepResults.reduce(
4154
- (responseMessages2, step) => [
4238
+ const responseMessages = stepResults.reduce((responseMessages2, step) => {
4239
+ if (step.stepType === "continue") {
4240
+ const lastResponseMessage = responseMessages2.pop();
4241
+ if (typeof lastResponseMessage.content === "string") {
4242
+ lastResponseMessage.content += step.text;
4243
+ } else {
4244
+ lastResponseMessage.content.push({
4245
+ text: step.text,
4246
+ type: "text"
4247
+ });
4248
+ }
4249
+ return [...responseMessages2, lastResponseMessage];
4250
+ }
4251
+ return [
4155
4252
  ...responseMessages2,
4156
4253
  ...toResponseMessages({
4157
4254
  text: step.text,
4158
4255
  toolCalls: step.toolCalls,
4159
4256
  toolResults: step.toolResults
4160
4257
  })
4161
- ],
4162
- []
4163
- );
4258
+ ];
4259
+ }, []);
4164
4260
  resolveUsage(combinedUsage);
4165
4261
  resolveFinishReason(stepFinishReason);
4166
- resolveText(stepText);
4262
+ resolveText(fullStepText);
4167
4263
  resolveToolCalls(stepToolCalls);
4168
4264
  resolveProviderMetadata(stepProviderMetadata);
4169
4265
  resolveToolResults(stepToolResults);
@@ -4177,7 +4273,7 @@ var DefaultStreamTextResult = class {
4177
4273
  finishReason: stepFinishReason,
4178
4274
  logprobs: stepLogProbs,
4179
4275
  usage: combinedUsage,
4180
- text: stepText,
4276
+ text: fullStepText,
4181
4277
  toolCalls: stepToolCalls,
4182
4278
  // The tool results are inferred as a never[] type, because they are
4183
4279
  // optional and the execute method with an inferred result type is
@@ -4210,7 +4306,8 @@ var DefaultStreamTextResult = class {
4210
4306
  doStreamSpan,
4211
4307
  currentStep: 0,
4212
4308
  promptMessages,
4213
- usage: void 0
4309
+ usage: void 0,
4310
+ stepType: "initial"
4214
4311
  });
4215
4312
  }
4216
4313
  /**