@mastra/ai-sdk 1.7.1 → 1.8.0-alpha.0

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.js CHANGED
@@ -9,7 +9,7 @@ import { MASTRA_RESOURCE_ID_KEY } from "@mastra/core/request-context";
9
9
  import { MessageList, TripWire, aiV5ModelMessageToV2PromptMessage } from "@mastra/core/agent";
10
10
  import { RequestContext } from "@mastra/core/di";
11
11
  import { MessageHistory, SemanticRecall, WorkingMemory } from "@mastra/core/processors";
12
- //#region ../../packages/_vendored/ai_v5/dist/dist-Qv-F35RT.js
12
+ //#region ../../packages/_vendored/ai_v5/dist/dist-BuEMdYEn.js
13
13
  var marker$1$4 = "vercel.ai.error";
14
14
  var symbol$1$5 = Symbol.for(marker$1$4);
15
15
  var _a$1$5;
@@ -533,6 +533,26 @@ async function cancelResponseBody$1(response) {
533
533
  await ((_a2 = response.body) == null ? void 0 : _a2.cancel());
534
534
  } catch (e) {}
535
535
  }
536
+ var initialGlobalFetch$1 = globalThis.fetch;
537
+ isNodeDefaultFetch$1(initialGlobalFetch$1);
538
+ function isNodeDefaultFetch$1(fetch) {
539
+ const source = Function.prototype.toString.call(fetch);
540
+ return source.includes("internal/deps/undici") || source.includes("lazy loading of undici");
541
+ }
542
+ function getCurrentModulePath$1() {
543
+ const originalPrepareStackTrace = Error.prepareStackTrace;
544
+ try {
545
+ Error.prepareStackTrace = (_error, callSites) => callSites;
546
+ const error = /* @__PURE__ */ new Error("Capture current module path");
547
+ Error.captureStackTrace(error, getCurrentModulePath$1);
548
+ const [caller] = error.stack;
549
+ const fileName = caller == null ? void 0 : caller.getFileName();
550
+ if (fileName == null) throw new Error("Unable to determine the current module path");
551
+ return fileName;
552
+ } finally {
553
+ Error.prepareStackTrace = originalPrepareStackTrace;
554
+ }
555
+ }
536
556
  var DEFAULT_MAX_DOWNLOAD_SIZE$1 = 2 * 1024 * 1024 * 1024;
537
557
  async function readResponseWithSizeLimit$1({ response, url, maxBytes = DEFAULT_MAX_DOWNLOAD_SIZE$1 }) {
538
558
  const contentLength = response.headers.get("content-length");
@@ -636,11 +656,11 @@ function withUserAgentSuffix$1(headers, ...userAgentSuffixParts) {
636
656
  normalizedHeaders.set("user-agent", [currentUserAgentHeader, ...userAgentSuffixParts].filter(Boolean).join(" "));
637
657
  return Object.fromEntries(normalizedHeaders.entries());
638
658
  }
639
- var VERSION$4 = "3.0.30";
659
+ var VERSION$4 = "3.0.31";
640
660
  var getOriginalFetch = () => globalThis.fetch;
641
- var getFromApi = async ({ url, headers = {}, successfulResponseHandler, failedResponseHandler, abortSignal, fetch: fetch2 = getOriginalFetch() }) => {
661
+ var getFromApi = async ({ url, headers = {}, successfulResponseHandler, failedResponseHandler, abortSignal, fetch = getOriginalFetch() }) => {
642
662
  try {
643
- const response = await fetch2(url, {
663
+ const response = await fetch(url, {
644
664
  method: "GET",
645
665
  headers: withUserAgentSuffix$1(headers, `ai-sdk/provider-utils/${VERSION$4}`, getRuntimeEnvironmentUserAgent$1()),
646
666
  signal: abortSignal
@@ -866,7 +886,7 @@ function parseJsonEventStream({ stream, schema }) {
866
886
  } }));
867
887
  }
868
888
  var getOriginalFetch2 = () => globalThis.fetch;
869
- var postJsonToApi = async ({ url, headers, body, failedResponseHandler, successfulResponseHandler, abortSignal, fetch: fetch2 }) => postToApi({
889
+ var postJsonToApi = async ({ url, headers, body, failedResponseHandler, successfulResponseHandler, abortSignal, fetch }) => postToApi({
870
890
  url,
871
891
  headers: {
872
892
  "Content-Type": "application/json",
@@ -879,11 +899,11 @@ var postJsonToApi = async ({ url, headers, body, failedResponseHandler, successf
879
899
  failedResponseHandler,
880
900
  successfulResponseHandler,
881
901
  abortSignal,
882
- fetch: fetch2
902
+ fetch
883
903
  });
884
- var postToApi = async ({ url, headers = {}, body, successfulResponseHandler, failedResponseHandler, abortSignal, fetch: fetch2 = getOriginalFetch2() }) => {
904
+ var postToApi = async ({ url, headers = {}, body, successfulResponseHandler, failedResponseHandler, abortSignal, fetch = getOriginalFetch2() }) => {
885
905
  try {
886
- const response = await fetch2(url, {
906
+ const response = await fetch(url, {
887
907
  method: "POST",
888
908
  headers: withUserAgentSuffix$1(headers, `ai-sdk/provider-utils/${VERSION$4}`, getRuntimeEnvironmentUserAgent$1()),
889
909
  body: body.content,
@@ -2945,7 +2965,7 @@ async function getVercelRequestId() {
2945
2965
  var _a10;
2946
2966
  return (_a10 = getContext().headers) == null ? void 0 : _a10["x-vercel-id"];
2947
2967
  }
2948
- var VERSION$2 = "2.0.115";
2968
+ var VERSION$2 = "2.0.125";
2949
2969
  var AI_GATEWAY_PROTOCOL_VERSION = "0.0.1";
2950
2970
  function createGatewayProvider(options = {}) {
2951
2971
  var _a10, _b10;
@@ -4395,19 +4415,48 @@ function processUIMessageStream$1({ stream, messageMetadataSchema, dataPartSchem
4395
4415
  return stream.pipeThrough(new TransformStream({ async transform(chunk, controller) {
4396
4416
  await runUpdateMessageJob(async ({ state, write }) => {
4397
4417
  var _a16, _b, _c, _d;
4418
+ function getCurrentStepParts() {
4419
+ const parts = state.message.parts;
4420
+ let currentStepStartIndex = parts.length - 1;
4421
+ while (currentStepStartIndex >= 0 && parts[currentStepStartIndex].type !== "step-start") currentStepStartIndex--;
4422
+ return parts.slice(currentStepStartIndex + 1);
4423
+ }
4424
+ function getCurrentStepToolInvocations() {
4425
+ return getCurrentStepParts().filter(isToolUIPart$1);
4426
+ }
4398
4427
  function getToolInvocation(toolCallId) {
4399
- const toolInvocation = state.message.parts.filter(isToolUIPart$1).find((invocation) => invocation.toolCallId === toolCallId);
4428
+ let toolInvocation = getCurrentStepToolInvocations().find((invocation) => invocation.toolCallId === toolCallId);
4429
+ if (toolInvocation == null) {
4430
+ const parts = state.message.parts;
4431
+ for (let i = parts.length - 1; i >= 0; i--) {
4432
+ const part = parts[i];
4433
+ if (isToolUIPart$1(part) && part.toolCallId === toolCallId) {
4434
+ toolInvocation = part;
4435
+ break;
4436
+ }
4437
+ }
4438
+ }
4400
4439
  if (toolInvocation == null) throw new Error("tool-output-error must be preceded by a tool-input-available");
4401
4440
  return toolInvocation;
4402
4441
  }
4403
4442
  function getDynamicToolInvocation(toolCallId) {
4404
- const toolInvocation = state.message.parts.filter((part) => part.type === "dynamic-tool").find((invocation) => invocation.toolCallId === toolCallId);
4443
+ let toolInvocation = getCurrentStepParts().filter((part) => part.type === "dynamic-tool").find((invocation) => invocation.toolCallId === toolCallId);
4444
+ if (toolInvocation == null) {
4445
+ const parts = state.message.parts;
4446
+ for (let i = parts.length - 1; i >= 0; i--) {
4447
+ const part = parts[i];
4448
+ if (part.type === "dynamic-tool" && part.toolCallId === toolCallId) {
4449
+ toolInvocation = part;
4450
+ break;
4451
+ }
4452
+ }
4453
+ }
4405
4454
  if (toolInvocation == null) throw new Error("tool-output-error must be preceded by a tool-input-available");
4406
4455
  return toolInvocation;
4407
4456
  }
4408
- function updateToolPart(options) {
4457
+ function updateToolPart(options, existingPart) {
4409
4458
  var _a17;
4410
- const part = state.message.parts.find((part2) => isToolUIPart$1(part2) && part2.toolCallId === options.toolCallId);
4459
+ const part = existingPart != null ? existingPart : getCurrentStepParts().find((part2) => isToolUIPart$1(part2) && part2.toolCallId === options.toolCallId);
4411
4460
  const anyOptions = options;
4412
4461
  const anyPart = part;
4413
4462
  if (part != null) {
@@ -4432,9 +4481,9 @@ function processUIMessageStream$1({ stream, messageMetadataSchema, dataPartSchem
4432
4481
  ...anyOptions.providerMetadata != null ? { callProviderMetadata: anyOptions.providerMetadata } : {}
4433
4482
  });
4434
4483
  }
4435
- function updateDynamicToolPart(options) {
4484
+ function updateDynamicToolPart(options, existingPart) {
4436
4485
  var _a17, _b2;
4437
- const part = state.message.parts.find((part2) => part2.type === "dynamic-tool" && part2.toolCallId === options.toolCallId);
4486
+ const part = existingPart != null ? existingPart : getCurrentStepParts().find((part2) => part2.type === "dynamic-tool" && part2.toolCallId === options.toolCallId);
4438
4487
  const anyOptions = options;
4439
4488
  const anyPart = part;
4440
4489
  if (part != null) {
@@ -4555,7 +4604,7 @@ function processUIMessageStream$1({ stream, messageMetadataSchema, dataPartSchem
4555
4604
  write();
4556
4605
  break;
4557
4606
  case "tool-input-start": {
4558
- const toolInvocations = state.message.parts.filter(isToolUIPart$1);
4607
+ const toolInvocations = getCurrentStepParts().filter(isToolUIPart$1);
4559
4608
  state.partialToolCalls[chunk.toolCallId] = {
4560
4609
  text: "",
4561
4610
  toolName: chunk.toolName,
@@ -4650,7 +4699,7 @@ function processUIMessageStream$1({ stream, messageMetadataSchema, dataPartSchem
4650
4699
  input: toolInvocation.input,
4651
4700
  output: chunk.output,
4652
4701
  preliminary: chunk.preliminary
4653
- });
4702
+ }, toolInvocation);
4654
4703
  } else {
4655
4704
  const toolInvocation = getToolInvocation(chunk.toolCallId);
4656
4705
  updateToolPart({
@@ -4661,7 +4710,7 @@ function processUIMessageStream$1({ stream, messageMetadataSchema, dataPartSchem
4661
4710
  output: chunk.output,
4662
4711
  providerExecuted: chunk.providerExecuted,
4663
4712
  preliminary: chunk.preliminary
4664
- });
4713
+ }, toolInvocation);
4665
4714
  }
4666
4715
  write();
4667
4716
  break;
@@ -4675,7 +4724,7 @@ function processUIMessageStream$1({ stream, messageMetadataSchema, dataPartSchem
4675
4724
  input: toolInvocation.input,
4676
4725
  errorText: chunk.errorText,
4677
4726
  providerExecuted: chunk.providerExecuted
4678
- });
4727
+ }, toolInvocation);
4679
4728
  } else {
4680
4729
  const toolInvocation = getToolInvocation(chunk.toolCallId);
4681
4730
  updateToolPart({
@@ -4686,7 +4735,7 @@ function processUIMessageStream$1({ stream, messageMetadataSchema, dataPartSchem
4686
4735
  rawInput: toolInvocation.rawInput,
4687
4736
  errorText: chunk.errorText,
4688
4737
  providerExecuted: chunk.providerExecuted
4689
- });
4738
+ }, toolInvocation);
4690
4739
  }
4691
4740
  write();
4692
4741
  break;
@@ -4977,7 +5026,7 @@ function createUIMessageStream$1({ execute, onError = () => "An error occurred."
4977
5026
  });
4978
5027
  }
4979
5028
  //#endregion
4980
- //#region ../../packages/_vendored/ai_v6/dist/dist-BomuqvJJ.js
5029
+ //#region ../../packages/_vendored/ai_v6/dist/dist-BTWHzT8H.js
4981
5030
  var marker$1 = "vercel.ai.error";
4982
5031
  var symbol$1 = Symbol.for(marker$1);
4983
5032
  var _a$1;
@@ -5317,6 +5366,26 @@ var _b;
5317
5366
  return AISDKError.hasMarker(error, marker$2);
5318
5367
  }
5319
5368
  });
5369
+ var initialGlobalFetch = globalThis.fetch;
5370
+ isNodeDefaultFetch(initialGlobalFetch);
5371
+ function isNodeDefaultFetch(fetch) {
5372
+ const source = Function.prototype.toString.call(fetch);
5373
+ return source.includes("internal/deps/undici") || source.includes("lazy loading of undici");
5374
+ }
5375
+ function getCurrentModulePath() {
5376
+ const originalPrepareStackTrace = Error.prepareStackTrace;
5377
+ try {
5378
+ Error.prepareStackTrace = (_error, callSites) => callSites;
5379
+ const error = /* @__PURE__ */ new Error("Capture current module path");
5380
+ Error.captureStackTrace(error, getCurrentModulePath);
5381
+ const [caller] = error.stack;
5382
+ const fileName = caller == null ? void 0 : caller.getFileName();
5383
+ if (fileName == null) throw new Error("Unable to determine the current module path");
5384
+ return fileName;
5385
+ } finally {
5386
+ Error.prepareStackTrace = originalPrepareStackTrace;
5387
+ }
5388
+ }
5320
5389
  var createIdGenerator = ({ prefix, size = 16, alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", separator = "-" } = {}) => {
5321
5390
  const generator = () => {
5322
5391
  const alphabetLength = alphabet.length;
@@ -7267,6 +7336,25 @@ _a16 = symbol16;
7267
7336
  function asArray(value) {
7268
7337
  return value === void 0 ? [] : Array.isArray(value) ? value : [value];
7269
7338
  }
7339
+ function mergeObjects(base, overrides) {
7340
+ if (base === void 0 && overrides === void 0) return;
7341
+ if (base === void 0) return overrides;
7342
+ if (overrides === void 0) return base;
7343
+ const result = { ...base };
7344
+ for (const key in overrides) {
7345
+ if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
7346
+ if (Object.prototype.hasOwnProperty.call(overrides, key)) {
7347
+ const overridesValue = overrides[key];
7348
+ if (overridesValue === void 0) continue;
7349
+ const baseValue = key in base ? base[key] : void 0;
7350
+ const isSourceObject = overridesValue !== null && typeof overridesValue === "object" && !Array.isArray(overridesValue) && !(overridesValue instanceof Date) && !(overridesValue instanceof RegExp);
7351
+ const isTargetObject = baseValue !== null && baseValue !== void 0 && typeof baseValue === "object" && !Array.isArray(baseValue) && !(baseValue instanceof Date) && !(baseValue instanceof RegExp);
7352
+ if (isSourceObject && isTargetObject) result[key] = mergeObjects(baseValue, overridesValue);
7353
+ else result[key] = overridesValue;
7354
+ }
7355
+ }
7356
+ return result;
7357
+ }
7270
7358
  var dataContentSchema = z.union([
7271
7359
  z.string(),
7272
7360
  z.instanceof(Uint8Array),
@@ -7450,25 +7538,6 @@ z.union([
7450
7538
  assistantModelMessageSchema,
7451
7539
  toolModelMessageSchema
7452
7540
  ]);
7453
- function mergeObjects(base, overrides) {
7454
- if (base === void 0 && overrides === void 0) return;
7455
- if (base === void 0) return overrides;
7456
- if (overrides === void 0) return base;
7457
- const result = { ...base };
7458
- for (const key in overrides) {
7459
- if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
7460
- if (Object.prototype.hasOwnProperty.call(overrides, key)) {
7461
- const overridesValue = overrides[key];
7462
- if (overridesValue === void 0) continue;
7463
- const baseValue = key in base ? base[key] : void 0;
7464
- const isSourceObject = overridesValue !== null && typeof overridesValue === "object" && !Array.isArray(overridesValue) && !(overridesValue instanceof Date) && !(overridesValue instanceof RegExp);
7465
- const isTargetObject = baseValue !== null && baseValue !== void 0 && typeof baseValue === "object" && !Array.isArray(baseValue) && !(baseValue instanceof Date) && !(baseValue instanceof RegExp);
7466
- if (isSourceObject && isTargetObject) result[key] = mergeObjects(baseValue, overridesValue);
7467
- else result[key] = overridesValue;
7468
- }
7469
- }
7470
- return result;
7471
- }
7472
7541
  new TextEncoder();
7473
7542
  __export({}, {
7474
7543
  array: () => array,
@@ -8080,8 +8149,27 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8080
8149
  return stream.pipeThrough(new TransformStream({ async transform(chunk, controller) {
8081
8150
  await runUpdateMessageJob(async ({ state, write }) => {
8082
8151
  var _a22, _b, _c, _d;
8152
+ function getCurrentStepParts() {
8153
+ const parts = state.message.parts;
8154
+ let currentStepStartIndex = parts.length - 1;
8155
+ while (currentStepStartIndex >= 0 && parts[currentStepStartIndex].type !== "step-start") currentStepStartIndex--;
8156
+ return parts.slice(currentStepStartIndex + 1);
8157
+ }
8158
+ function getCurrentStepToolInvocations() {
8159
+ return getCurrentStepParts().filter(isToolUIPart);
8160
+ }
8083
8161
  function getToolInvocation(toolCallId) {
8084
- const toolInvocation = state.message.parts.filter(isToolUIPart).find((invocation) => invocation.toolCallId === toolCallId);
8162
+ let toolInvocation = getCurrentStepToolInvocations().find((invocation) => invocation.toolCallId === toolCallId);
8163
+ if (toolInvocation == null) {
8164
+ const parts = state.message.parts;
8165
+ for (let i = parts.length - 1; i >= 0; i--) {
8166
+ const part = parts[i];
8167
+ if (isToolUIPart(part) && part.toolCallId === toolCallId) {
8168
+ toolInvocation = part;
8169
+ break;
8170
+ }
8171
+ }
8172
+ }
8085
8173
  if (toolInvocation == null) throw new UIMessageStreamError({
8086
8174
  chunkType: "tool-invocation",
8087
8175
  chunkId: toolCallId,
@@ -8089,9 +8177,9 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8089
8177
  });
8090
8178
  return toolInvocation;
8091
8179
  }
8092
- function updateToolPart(options) {
8180
+ function updateToolPart(options, existingPart) {
8093
8181
  var _a23;
8094
- const part = state.message.parts.find((part2) => isStaticToolUIPart(part2) && part2.toolCallId === options.toolCallId);
8182
+ const part = existingPart != null ? existingPart : getCurrentStepParts().find((part2) => isStaticToolUIPart(part2) && part2.toolCallId === options.toolCallId);
8095
8183
  const anyOptions = options;
8096
8184
  const anyPart = part;
8097
8185
  if (part != null) {
@@ -8125,9 +8213,9 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8125
8213
  ...anyOptions.providerMetadata != null && !(options.state === "output-available" || options.state === "output-error") ? { callProviderMetadata: anyOptions.providerMetadata } : {}
8126
8214
  });
8127
8215
  }
8128
- function updateDynamicToolPart(options) {
8216
+ function updateDynamicToolPart(options, existingPart) {
8129
8217
  var _a23, _b2;
8130
- const part = state.message.parts.find((part2) => part2.type === "dynamic-tool" && part2.toolCallId === options.toolCallId);
8218
+ const part = existingPart != null ? existingPart : getCurrentStepParts().find((part2) => part2.type === "dynamic-tool" && part2.toolCallId === options.toolCallId);
8131
8219
  const anyOptions = options;
8132
8220
  const anyPart = part;
8133
8221
  if (part != null) {
@@ -8282,7 +8370,7 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8282
8370
  write();
8283
8371
  break;
8284
8372
  case "tool-input-start": {
8285
- const toolInvocations = state.message.parts.filter(isStaticToolUIPart);
8373
+ const toolInvocations = getCurrentStepParts().filter(isStaticToolUIPart);
8286
8374
  state.partialToolCalls[chunk.toolCallId] = {
8287
8375
  text: "",
8288
8376
  toolName: chunk.toolName,
@@ -8367,7 +8455,7 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8367
8455
  if (onToolCall && !chunk.providerExecuted) await onToolCall({ toolCall: chunk });
8368
8456
  break;
8369
8457
  case "tool-input-error": {
8370
- const existingPart = state.message.parts.filter(isToolUIPart).find((p) => p.toolCallId === chunk.toolCallId);
8458
+ const existingPart = getCurrentStepParts().filter(isToolUIPart).find((p) => p.toolCallId === chunk.toolCallId);
8371
8459
  if (existingPart != null ? existingPart.type === "dynamic-tool" : !!chunk.dynamic) updateDynamicToolPart({
8372
8460
  toolCallId: chunk.toolCallId,
8373
8461
  toolName: chunk.toolName,
@@ -8421,7 +8509,7 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8421
8509
  providerMetadata: chunk.providerMetadata,
8422
8510
  title: toolInvocation.title,
8423
8511
  toolMetadata: toolInvocation.toolMetadata
8424
- });
8512
+ }, toolInvocation);
8425
8513
  else updateToolPart({
8426
8514
  toolCallId: chunk.toolCallId,
8427
8515
  toolName: getStaticToolName(toolInvocation),
@@ -8433,7 +8521,7 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8433
8521
  providerMetadata: chunk.providerMetadata,
8434
8522
  title: toolInvocation.title,
8435
8523
  toolMetadata: toolInvocation.toolMetadata
8436
- });
8524
+ }, toolInvocation);
8437
8525
  write();
8438
8526
  break;
8439
8527
  }
@@ -8449,7 +8537,7 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8449
8537
  providerMetadata: chunk.providerMetadata,
8450
8538
  title: toolInvocation.title,
8451
8539
  toolMetadata: toolInvocation.toolMetadata
8452
- });
8540
+ }, toolInvocation);
8453
8541
  else updateToolPart({
8454
8542
  toolCallId: chunk.toolCallId,
8455
8543
  toolName: getStaticToolName(toolInvocation),
@@ -8461,7 +8549,7 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8461
8549
  providerMetadata: chunk.providerMetadata,
8462
8550
  title: toolInvocation.title,
8463
8551
  toolMetadata: toolInvocation.toolMetadata
8464
- });
8552
+ }, toolInvocation);
8465
8553
  write();
8466
8554
  break;
8467
8555
  }
@@ -9316,6 +9404,7 @@ function convertFullStreamChunkToUIMessageStream({ part, messageMetadataValue, s
9316
9404
  //#endregion
9317
9405
  //#region src/transformers.ts
9318
9406
  const PRIMITIVE_CACHE_SYMBOL = Symbol("primitive-cache");
9407
+ const COMPLETED_STEPS_SYMBOL = Symbol("completed-steps-cache");
9319
9408
  function cloneWorkflowStep(step, includeOutput) {
9320
9409
  return {
9321
9410
  name: step.name,
@@ -9443,7 +9532,8 @@ function createAgentStreamToAISDKTransformer(convertMastraChunkToAISDK, { lastMe
9443
9532
  if (transformedChunk) if (transformedChunk.type === "tool-agent") {
9444
9533
  const payload = transformedChunk.payload;
9445
9534
  const agentTransformed = transformAgent(payload, bufferedSteps);
9446
- if (agentTransformed) controller.enqueue(agentTransformed);
9535
+ if (agentTransformed) if (Array.isArray(agentTransformed)) for (const part of agentTransformed) controller.enqueue(part);
9536
+ else controller.enqueue(agentTransformed);
9447
9537
  } else if (transformedChunk.type === "tool-workflow") {
9448
9538
  const payload = transformedChunk.payload;
9449
9539
  const workflowChunk = transformWorkflow(payload, bufferedSteps, true, void 0, void 0, convertMastraChunkToAISDK);
@@ -9526,30 +9616,7 @@ function AgentStreamToAISDKV6Transformer({ lastMessageId, sendStart = true, send
9526
9616
  });
9527
9617
  }
9528
9618
  function ensureAgentRunState(bufferedSteps, runId) {
9529
- if (!bufferedSteps.has(runId)) bufferedSteps.set(runId, {
9530
- id: "",
9531
- object: null,
9532
- finishReason: null,
9533
- usage: null,
9534
- warnings: [],
9535
- text: "",
9536
- reasoning: [],
9537
- sources: [],
9538
- files: [],
9539
- toolCalls: [],
9540
- pendingToolCalls: [],
9541
- toolResults: [],
9542
- request: {},
9543
- response: {
9544
- id: "",
9545
- timestamp: /* @__PURE__ */ new Date(),
9546
- modelId: "",
9547
- messages: []
9548
- },
9549
- providerMetadata: void 0,
9550
- steps: [],
9551
- status: "running"
9552
- });
9619
+ if (!bufferedSteps.has(runId)) bufferedSteps.set(runId, createAgentRunState());
9553
9620
  return bufferedSteps.get(runId);
9554
9621
  }
9555
9622
  function upsertPendingToolCall(pendingToolCalls = [], toolCallId, updates) {
@@ -9585,36 +9652,109 @@ function appendPendingToolCallArgs(pendingToolCalls = [], payload) {
9585
9652
  function removePendingToolCall(pendingToolCalls = [], toolCallId) {
9586
9653
  return pendingToolCalls.filter((call) => call.toolCallId !== toolCallId);
9587
9654
  }
9655
+ function createAgentResponseState() {
9656
+ return {
9657
+ id: "",
9658
+ timestamp: /* @__PURE__ */ new Date(),
9659
+ modelId: "",
9660
+ messages: []
9661
+ };
9662
+ }
9663
+ function createAgentRunState(id = "") {
9664
+ return {
9665
+ id,
9666
+ object: null,
9667
+ finishReason: null,
9668
+ usage: null,
9669
+ warnings: [],
9670
+ text: "",
9671
+ reasoning: [],
9672
+ sources: [],
9673
+ files: [],
9674
+ toolCalls: [],
9675
+ pendingToolCalls: [],
9676
+ toolResults: [],
9677
+ request: {},
9678
+ response: createAgentResponseState(),
9679
+ providerMetadata: void 0,
9680
+ steps: [],
9681
+ status: "running"
9682
+ };
9683
+ }
9684
+ function cloneAgentResponse(response, { includeMessages }) {
9685
+ if (!response) return response;
9686
+ return {
9687
+ ...response,
9688
+ ...Object.prototype.hasOwnProperty.call(response, "messages") ? { messages: includeMessages ? response.messages : [] } : {},
9689
+ ...Object.prototype.hasOwnProperty.call(response, "dbMessages") ? { dbMessages: includeMessages ? response.dbMessages : [] } : {},
9690
+ ...Object.prototype.hasOwnProperty.call(response, "uiMessages") ? { uiMessages: includeMessages ? response.uiMessages : [] } : {}
9691
+ };
9692
+ }
9693
+ function cloneAgentStep(step, { includeDetails }) {
9694
+ if (includeDetails) return {
9695
+ ...step,
9696
+ response: cloneAgentResponse(step.response, { includeMessages: true })
9697
+ };
9698
+ return {
9699
+ ...step,
9700
+ object: null,
9701
+ files: [],
9702
+ sources: [],
9703
+ toolCalls: [],
9704
+ pendingToolCalls: [],
9705
+ toolResults: [],
9706
+ dynamicToolCalls: [],
9707
+ dynamicToolResults: [],
9708
+ staticToolCalls: [],
9709
+ staticToolResults: [],
9710
+ text: "",
9711
+ reasoning: [],
9712
+ content: Array.isArray(step.content) ? [] : step.content,
9713
+ reasoningText: typeof step.reasoningText === "string" ? "" : step.reasoningText,
9714
+ response: cloneAgentResponse(step.response, { includeMessages: false })
9715
+ };
9716
+ }
9717
+ function serializeAgentRun(current, { includeCompletedStepDetails, includeResponseMessages }) {
9718
+ const { _textOffset: _to, _reasoningOffset: _ro, ...data } = current;
9719
+ return {
9720
+ ...data,
9721
+ response: cloneAgentResponse(data.response, { includeMessages: includeResponseMessages }),
9722
+ steps: data.steps.map((step) => cloneAgentStep(step, { includeDetails: includeCompletedStepDetails }))
9723
+ };
9724
+ }
9725
+ function createAgentDataPart(args) {
9726
+ const { current, runId, includeCompletedStepDetails, includeResponseMessages } = args;
9727
+ return {
9728
+ type: "data-tool-agent",
9729
+ id: runId,
9730
+ data: serializeAgentRun(current, {
9731
+ includeCompletedStepDetails,
9732
+ includeResponseMessages
9733
+ })
9734
+ };
9735
+ }
9736
+ function createAgentStepDataPart(args) {
9737
+ const { runId, stepIndex, step } = args;
9738
+ return {
9739
+ type: "data-tool-agent-step",
9740
+ id: `${runId}:${stepIndex}`,
9741
+ data: {
9742
+ runId,
9743
+ stepIndex,
9744
+ step: cloneAgentStep(step, { includeDetails: true })
9745
+ }
9746
+ };
9747
+ }
9588
9748
  function transformAgent(payload, bufferedSteps) {
9589
9749
  let hasChanged = false;
9750
+ let completedStep = null;
9590
9751
  switch (payload.type) {
9591
- case "start":
9592
- bufferedSteps.set(payload.runId, {
9593
- id: payload.payload.id,
9594
- object: null,
9595
- finishReason: null,
9596
- usage: null,
9597
- warnings: [],
9598
- text: "",
9599
- reasoning: [],
9600
- sources: [],
9601
- files: [],
9602
- toolCalls: [],
9603
- pendingToolCalls: [],
9604
- toolResults: [],
9605
- request: {},
9606
- response: {
9607
- id: "",
9608
- timestamp: /* @__PURE__ */ new Date(),
9609
- modelId: "",
9610
- messages: []
9611
- },
9612
- providerMetadata: void 0,
9613
- steps: [],
9614
- status: "running"
9615
- });
9752
+ case "start": {
9753
+ const startState = createAgentRunState(payload.payload.id);
9754
+ bufferedSteps.set(payload.runId, startState);
9616
9755
  hasChanged = true;
9617
9756
  break;
9757
+ }
9618
9758
  case "tool-call-input-streaming-start": {
9619
9759
  const toolInputStartRun = ensureAgentRunState(bufferedSteps, payload.runId);
9620
9760
  const existing = toolInputStartRun.pendingToolCalls?.find((call) => call.toolCallId === payload.payload.toolCallId);
@@ -9745,6 +9885,7 @@ function transformAgent(payload, bufferedSteps) {
9745
9885
  break;
9746
9886
  case "step-finish": {
9747
9887
  const stepRun = ensureAgentRunState(bufferedSteps, payload.runId);
9888
+ const stepIndex = stepRun.steps.length;
9748
9889
  const { steps: _steps, _textOffset, _reasoningOffset, ...stepRunWithoutSteps } = stepRun;
9749
9890
  const textOffset = _textOffset || 0;
9750
9891
  const reasoningOffset = _reasoningOffset || 0;
@@ -9786,18 +9927,28 @@ function transformAgent(payload, bufferedSteps) {
9786
9927
  _textOffset: stepRun.text.length,
9787
9928
  _reasoningOffset: stepRun.reasoning.length
9788
9929
  });
9930
+ completedStep = {
9931
+ stepIndex,
9932
+ step: stepResult
9933
+ };
9789
9934
  hasChanged = true;
9790
9935
  break;
9791
9936
  }
9792
9937
  default: break;
9793
9938
  }
9794
9939
  if (hasChanged) {
9795
- const { _textOffset: _to, _reasoningOffset: _ro, ...data } = bufferedSteps.get(payload.runId);
9796
- return {
9797
- type: "data-tool-agent",
9798
- id: payload.runId,
9799
- data
9800
- };
9940
+ const snapshot = createAgentDataPart({
9941
+ current: bufferedSteps.get(payload.runId),
9942
+ runId: payload.runId,
9943
+ includeCompletedStepDetails: payload.type === "finish",
9944
+ includeResponseMessages: payload.type === "finish"
9945
+ });
9946
+ if (completedStep) return [snapshot, createAgentStepDataPart({
9947
+ runId: payload.runId,
9948
+ stepIndex: completedStep.stepIndex,
9949
+ step: completedStep.step
9950
+ })];
9951
+ return snapshot;
9801
9952
  }
9802
9953
  return null;
9803
9954
  }
@@ -10223,10 +10374,24 @@ function transformNetwork(payload, bufferedNetworks, isNested) {
10223
10374
  const step = current.steps.find((step) => step.id === stepId);
10224
10375
  if (!step) return null;
10225
10376
  step[PRIMITIVE_CACHE_SYMBOL] = step[PRIMITIVE_CACHE_SYMBOL] || /* @__PURE__ */ new Map();
10377
+ if (payload.payload.type === "start") delete step[COMPLETED_STEPS_SYMBOL];
10226
10378
  const result = transformAgent(payload.payload, step[PRIMITIVE_CACHE_SYMBOL]);
10227
- if (result) {
10228
- const { request, response, ...data } = result.data;
10379
+ const snapshot = Array.isArray(result) ? result[0] : result;
10380
+ if (snapshot) {
10381
+ const { request, response, ...data } = snapshot.data;
10382
+ if (Array.isArray(result)) {
10383
+ const { stepIndex, step: completedStepDetail } = result[1].data;
10384
+ step[COMPLETED_STEPS_SYMBOL] = step[COMPLETED_STEPS_SYMBOL] || /* @__PURE__ */ new Map();
10385
+ step[COMPLETED_STEPS_SYMBOL].set(stepIndex, completedStepDetail);
10386
+ }
10229
10387
  step.task = data;
10388
+ const completedSteps = step[COMPLETED_STEPS_SYMBOL];
10389
+ if (completedSteps && completedSteps.size > 0 && Array.isArray(data.steps)) {
10390
+ for (const [stepIndex, completedStepDetail] of completedSteps) if (stepIndex < data.steps.length) data.steps[stepIndex] = {
10391
+ ...data.steps[stepIndex],
10392
+ ...completedStepDetail
10393
+ };
10394
+ }
10230
10395
  }
10231
10396
  bufferedNetworks.set(payload.runId, current);
10232
10397
  return {
@@ -10350,6 +10515,124 @@ function toAISdkStream(stream, options = {
10350
10515
  }));
10351
10516
  }
10352
10517
  //#endregion
10518
+ //#region src/sse-heartbeat.ts
10519
+ const SSE_HEARTBEAT_BYTES = new TextEncoder().encode(": heartbeat\n\n");
10520
+ const LF_BYTE = 10;
10521
+ const MAX_TIMEOUT_MS = 2147483647;
10522
+ /** Throws when an enabled heartbeat interval cannot be scheduled with a timer. */
10523
+ function assertValidHeartbeatMs(heartbeatMs) {
10524
+ if (heartbeatMs !== void 0 && !(heartbeatMs <= 0) && (!Number.isFinite(heartbeatMs) || heartbeatMs > MAX_TIMEOUT_MS)) throw new RangeError(`heartbeatMs must be a finite number no greater than ${MAX_TIMEOUT_MS}`);
10525
+ }
10526
+ /**
10527
+ * Adds periodic SSE comment heartbeats to an AI SDK response body.
10528
+ * AI SDK serialization uses LF-delimited frames, which this private wrapper preserves and relies on.
10529
+ */
10530
+ function withSseHeartbeat(response, heartbeatMs) {
10531
+ assertValidHeartbeatMs(heartbeatMs);
10532
+ if (heartbeatMs === void 0 || heartbeatMs <= 0 || !response.body) return response;
10533
+ const reader = response.body.getReader();
10534
+ let heartbeatTimeout;
10535
+ let wakePull;
10536
+ let readResult;
10537
+ let readError;
10538
+ let hasReadError = false;
10539
+ let reading = false;
10540
+ let finished = false;
10541
+ let readerReleased = false;
10542
+ let atFrameBoundary = true;
10543
+ let lastByte;
10544
+ let nextHeartbeatAt = performance.now() + heartbeatMs;
10545
+ const clearHeartbeat = () => {
10546
+ if (heartbeatTimeout !== void 0) {
10547
+ clearTimeout(heartbeatTimeout);
10548
+ heartbeatTimeout = void 0;
10549
+ }
10550
+ };
10551
+ const releaseReader = () => {
10552
+ if (readerReleased) return;
10553
+ readerReleased = true;
10554
+ reader.releaseLock();
10555
+ };
10556
+ const updateFrameBoundary = (chunk) => {
10557
+ if (chunk.byteLength === 0) return;
10558
+ atFrameBoundary = chunk.byteLength === 1 ? lastByte === LF_BYTE && chunk[0] === LF_BYTE : chunk[chunk.byteLength - 2] === LF_BYTE && chunk[chunk.byteLength - 1] === LF_BYTE;
10559
+ lastByte = chunk[chunk.byteLength - 1];
10560
+ };
10561
+ const startRead = () => {
10562
+ if (reading || readResult || hasReadError || finished) return;
10563
+ reading = true;
10564
+ reader.read().then((result) => {
10565
+ reading = false;
10566
+ readResult = result;
10567
+ wakePull?.("read");
10568
+ }, (error) => {
10569
+ reading = false;
10570
+ readError = error;
10571
+ hasReadError = true;
10572
+ wakePull?.("read");
10573
+ });
10574
+ };
10575
+ const forwardRead = (controller) => {
10576
+ if (hasReadError) {
10577
+ finished = true;
10578
+ releaseReader();
10579
+ controller.error(readError);
10580
+ return;
10581
+ }
10582
+ if (!readResult) return;
10583
+ const result = readResult;
10584
+ readResult = void 0;
10585
+ if (result.done) {
10586
+ finished = true;
10587
+ releaseReader();
10588
+ controller.close();
10589
+ return;
10590
+ }
10591
+ updateFrameBoundary(result.value);
10592
+ controller.enqueue(result.value);
10593
+ };
10594
+ const stream = new ReadableStream({
10595
+ async pull(controller) {
10596
+ if (finished) return;
10597
+ startRead();
10598
+ if (readResult || hasReadError) {
10599
+ forwardRead(controller);
10600
+ return;
10601
+ }
10602
+ const next = await new Promise((resolve) => {
10603
+ wakePull = resolve;
10604
+ if (atFrameBoundary) heartbeatTimeout = setTimeout(() => resolve("heartbeat"), Math.max(0, nextHeartbeatAt - performance.now()));
10605
+ });
10606
+ wakePull = void 0;
10607
+ clearHeartbeat();
10608
+ if (finished) return;
10609
+ if (readResult || hasReadError) {
10610
+ forwardRead(controller);
10611
+ return;
10612
+ }
10613
+ if (next === "heartbeat") {
10614
+ controller.enqueue(SSE_HEARTBEAT_BYTES.slice());
10615
+ nextHeartbeatAt = performance.now() + heartbeatMs;
10616
+ }
10617
+ },
10618
+ async cancel(reason) {
10619
+ if (finished) return;
10620
+ finished = true;
10621
+ clearHeartbeat();
10622
+ try {
10623
+ await reader.cancel(reason);
10624
+ } finally {
10625
+ releaseReader();
10626
+ }
10627
+ }
10628
+ });
10629
+ return new Response(stream, {
10630
+ status: response.status,
10631
+ statusText: response.statusText,
10632
+ headers: response.headers
10633
+ });
10634
+ }
10635
+ //#endregion
10353
10636
  //#region src/chat-route.ts
10354
10637
  /**
10355
10638
  * Collects every approval response across all assistant messages in a v6
@@ -10552,11 +10835,13 @@ async function handleChatStream({ mastra, agentId, agentVersion, params, default
10552
10835
  * @param {boolean} [options.sendFinish=true] - Whether to send finish events in the stream
10553
10836
  * @param {boolean} [options.sendReasoning=false] - Whether to include reasoning steps in the stream
10554
10837
  * @param {boolean} [options.sendSources=false] - Whether to include source citations in the stream
10838
+ * @param {number} [options.heartbeatMs] - Target interval for periodic SSE comment heartbeats. Already-buffered source events and stream lifecycle signals take priority. Values up to 0 disable heartbeats. `NaN`, positive infinity, and values above 2,147,483,647 throw a `RangeError`.
10555
10839
  * @param {(error: unknown) => string} [options.onError] - Custom error serializer streamed to the client. When omitted, errors are passed through a default serializer that strips sensitive fields (e.g. `APICallError.requestBodyValues`, which holds the system prompt) before they reach the client.
10556
10840
  *
10557
10841
  * @returns {ReturnType<typeof registerApiRoute>} A registered API route handler
10558
10842
  *
10559
10843
  * @throws {Error} When path doesn't include `:agentId` and no fixed agent is specified
10844
+ * @throws {RangeError} When `heartbeatMs` is `NaN`, positive infinity, or greater than 2,147,483,647
10560
10845
  * @throws {Error} When agent ID is missing at runtime
10561
10846
  * @throws {Error} When specified agent is not found in Mastra instance
10562
10847
  *
@@ -10579,12 +10864,13 @@ async function handleChatStream({ mastra, agentId, agentVersion, params, default
10579
10864
  * @remarks
10580
10865
  * - The route handler expects a JSON body with a `messages` array
10581
10866
  * - Messages should follow the format: `{ role: 'user' | 'assistant' | 'system', content: string }`
10582
- * - The response is a Server-Sent Events (SSE) stream compatible with AI SDK v5
10867
+ * - The response is a Server-Sent Events (SSE) stream compatible with the selected AI SDK version
10583
10868
  * - If both `agent` and `:agentId` are present, a warning is logged and the fixed `agent` takes precedence
10584
10869
  * - Request context from the incoming request overrides `defaultOptions.requestContext` if both are present
10585
10870
  */
10586
- function chatRoute({ path = "/chat/:agentId", agent, defaultOptions, experimentalTransform, version = "v5", agentVersion, sendStart = true, sendFinish = true, sendReasoning = false, sendSources = false, onError }) {
10871
+ function chatRoute({ path = "/chat/:agentId", agent, defaultOptions, experimentalTransform, version = "v5", agentVersion, sendStart = true, sendFinish = true, sendReasoning = false, sendSources = false, heartbeatMs, onError }) {
10587
10872
  if (!agent && !path.includes("/:agentId")) throw new Error("Path must include :agentId to route to the correct agent or pass the agent explicitly");
10873
+ assertValidHeartbeatMs(heartbeatMs);
10588
10874
  return registerApiRoute(path, {
10589
10875
  method: "POST",
10590
10876
  openapi: {
@@ -10713,11 +10999,13 @@ function chatRoute({ path = "/chat/:agentId", agent, defaultOptions, experimenta
10713
10999
  sendSources,
10714
11000
  onError
10715
11001
  };
10716
- if (version === "v6") return createUIMessageStreamResponse({ stream: await handleChatStream({
11002
+ let response;
11003
+ if (version === "v6") response = createUIMessageStreamResponse({ stream: await handleChatStream({
10717
11004
  ...handlerOptions,
10718
11005
  version: "v6"
10719
11006
  }) });
10720
- return createUIMessageStreamResponse$1({ stream: await handleChatStream(handlerOptions) });
11007
+ else response = createUIMessageStreamResponse$1({ stream: await handleChatStream(handlerOptions) });
11008
+ return withSseHeartbeat(response, heartbeatMs);
10721
11009
  }
10722
11010
  });
10723
11011
  }