@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.cjs CHANGED
@@ -32,7 +32,7 @@ let _mastra_core_request_context = require("@mastra/core/request-context");
32
32
  let _mastra_core_agent = require("@mastra/core/agent");
33
33
  let _mastra_core_di = require("@mastra/core/di");
34
34
  let _mastra_core_processors = require("@mastra/core/processors");
35
- //#region ../../packages/_vendored/ai_v5/dist/dist-Qv-F35RT.js
35
+ //#region ../../packages/_vendored/ai_v5/dist/dist-BuEMdYEn.js
36
36
  var marker$1$4 = "vercel.ai.error";
37
37
  var symbol$1$5 = Symbol.for(marker$1$4);
38
38
  var _a$1$5;
@@ -556,6 +556,26 @@ async function cancelResponseBody$1(response) {
556
556
  await ((_a2 = response.body) == null ? void 0 : _a2.cancel());
557
557
  } catch (e) {}
558
558
  }
559
+ var initialGlobalFetch$1 = globalThis.fetch;
560
+ isNodeDefaultFetch$1(initialGlobalFetch$1);
561
+ function isNodeDefaultFetch$1(fetch) {
562
+ const source = Function.prototype.toString.call(fetch);
563
+ return source.includes("internal/deps/undici") || source.includes("lazy loading of undici");
564
+ }
565
+ function getCurrentModulePath$1() {
566
+ const originalPrepareStackTrace = Error.prepareStackTrace;
567
+ try {
568
+ Error.prepareStackTrace = (_error, callSites) => callSites;
569
+ const error = /* @__PURE__ */ new Error("Capture current module path");
570
+ Error.captureStackTrace(error, getCurrentModulePath$1);
571
+ const [caller] = error.stack;
572
+ const fileName = caller == null ? void 0 : caller.getFileName();
573
+ if (fileName == null) throw new Error("Unable to determine the current module path");
574
+ return fileName;
575
+ } finally {
576
+ Error.prepareStackTrace = originalPrepareStackTrace;
577
+ }
578
+ }
559
579
  var DEFAULT_MAX_DOWNLOAD_SIZE$1 = 2 * 1024 * 1024 * 1024;
560
580
  async function readResponseWithSizeLimit$1({ response, url, maxBytes = DEFAULT_MAX_DOWNLOAD_SIZE$1 }) {
561
581
  const contentLength = response.headers.get("content-length");
@@ -659,11 +679,11 @@ function withUserAgentSuffix$1(headers, ...userAgentSuffixParts) {
659
679
  normalizedHeaders.set("user-agent", [currentUserAgentHeader, ...userAgentSuffixParts].filter(Boolean).join(" "));
660
680
  return Object.fromEntries(normalizedHeaders.entries());
661
681
  }
662
- var VERSION$4 = "3.0.30";
682
+ var VERSION$4 = "3.0.31";
663
683
  var getOriginalFetch = () => globalThis.fetch;
664
- var getFromApi = async ({ url, headers = {}, successfulResponseHandler, failedResponseHandler, abortSignal, fetch: fetch2 = getOriginalFetch() }) => {
684
+ var getFromApi = async ({ url, headers = {}, successfulResponseHandler, failedResponseHandler, abortSignal, fetch = getOriginalFetch() }) => {
665
685
  try {
666
- const response = await fetch2(url, {
686
+ const response = await fetch(url, {
667
687
  method: "GET",
668
688
  headers: withUserAgentSuffix$1(headers, `ai-sdk/provider-utils/${VERSION$4}`, getRuntimeEnvironmentUserAgent$1()),
669
689
  signal: abortSignal
@@ -889,7 +909,7 @@ function parseJsonEventStream({ stream, schema }) {
889
909
  } }));
890
910
  }
891
911
  var getOriginalFetch2 = () => globalThis.fetch;
892
- var postJsonToApi = async ({ url, headers, body, failedResponseHandler, successfulResponseHandler, abortSignal, fetch: fetch2 }) => postToApi({
912
+ var postJsonToApi = async ({ url, headers, body, failedResponseHandler, successfulResponseHandler, abortSignal, fetch }) => postToApi({
893
913
  url,
894
914
  headers: {
895
915
  "Content-Type": "application/json",
@@ -902,11 +922,11 @@ var postJsonToApi = async ({ url, headers, body, failedResponseHandler, successf
902
922
  failedResponseHandler,
903
923
  successfulResponseHandler,
904
924
  abortSignal,
905
- fetch: fetch2
925
+ fetch
906
926
  });
907
- var postToApi = async ({ url, headers = {}, body, successfulResponseHandler, failedResponseHandler, abortSignal, fetch: fetch2 = getOriginalFetch2() }) => {
927
+ var postToApi = async ({ url, headers = {}, body, successfulResponseHandler, failedResponseHandler, abortSignal, fetch = getOriginalFetch2() }) => {
908
928
  try {
909
- const response = await fetch2(url, {
929
+ const response = await fetch(url, {
910
930
  method: "POST",
911
931
  headers: withUserAgentSuffix$1(headers, `ai-sdk/provider-utils/${VERSION$4}`, getRuntimeEnvironmentUserAgent$1()),
912
932
  body: body.content,
@@ -2968,7 +2988,7 @@ async function getVercelRequestId() {
2968
2988
  var _a10;
2969
2989
  return (_a10 = getContext().headers) == null ? void 0 : _a10["x-vercel-id"];
2970
2990
  }
2971
- var VERSION$2 = "2.0.115";
2991
+ var VERSION$2 = "2.0.125";
2972
2992
  var AI_GATEWAY_PROTOCOL_VERSION = "0.0.1";
2973
2993
  function createGatewayProvider(options = {}) {
2974
2994
  var _a10, _b10;
@@ -4418,19 +4438,48 @@ function processUIMessageStream$1({ stream, messageMetadataSchema, dataPartSchem
4418
4438
  return stream.pipeThrough(new TransformStream({ async transform(chunk, controller) {
4419
4439
  await runUpdateMessageJob(async ({ state, write }) => {
4420
4440
  var _a16, _b, _c, _d;
4441
+ function getCurrentStepParts() {
4442
+ const parts = state.message.parts;
4443
+ let currentStepStartIndex = parts.length - 1;
4444
+ while (currentStepStartIndex >= 0 && parts[currentStepStartIndex].type !== "step-start") currentStepStartIndex--;
4445
+ return parts.slice(currentStepStartIndex + 1);
4446
+ }
4447
+ function getCurrentStepToolInvocations() {
4448
+ return getCurrentStepParts().filter(isToolUIPart$1);
4449
+ }
4421
4450
  function getToolInvocation(toolCallId) {
4422
- const toolInvocation = state.message.parts.filter(isToolUIPart$1).find((invocation) => invocation.toolCallId === toolCallId);
4451
+ let toolInvocation = getCurrentStepToolInvocations().find((invocation) => invocation.toolCallId === toolCallId);
4452
+ if (toolInvocation == null) {
4453
+ const parts = state.message.parts;
4454
+ for (let i = parts.length - 1; i >= 0; i--) {
4455
+ const part = parts[i];
4456
+ if (isToolUIPart$1(part) && part.toolCallId === toolCallId) {
4457
+ toolInvocation = part;
4458
+ break;
4459
+ }
4460
+ }
4461
+ }
4423
4462
  if (toolInvocation == null) throw new Error("tool-output-error must be preceded by a tool-input-available");
4424
4463
  return toolInvocation;
4425
4464
  }
4426
4465
  function getDynamicToolInvocation(toolCallId) {
4427
- const toolInvocation = state.message.parts.filter((part) => part.type === "dynamic-tool").find((invocation) => invocation.toolCallId === toolCallId);
4466
+ let toolInvocation = getCurrentStepParts().filter((part) => part.type === "dynamic-tool").find((invocation) => invocation.toolCallId === toolCallId);
4467
+ if (toolInvocation == null) {
4468
+ const parts = state.message.parts;
4469
+ for (let i = parts.length - 1; i >= 0; i--) {
4470
+ const part = parts[i];
4471
+ if (part.type === "dynamic-tool" && part.toolCallId === toolCallId) {
4472
+ toolInvocation = part;
4473
+ break;
4474
+ }
4475
+ }
4476
+ }
4428
4477
  if (toolInvocation == null) throw new Error("tool-output-error must be preceded by a tool-input-available");
4429
4478
  return toolInvocation;
4430
4479
  }
4431
- function updateToolPart(options) {
4480
+ function updateToolPart(options, existingPart) {
4432
4481
  var _a17;
4433
- const part = state.message.parts.find((part2) => isToolUIPart$1(part2) && part2.toolCallId === options.toolCallId);
4482
+ const part = existingPart != null ? existingPart : getCurrentStepParts().find((part2) => isToolUIPart$1(part2) && part2.toolCallId === options.toolCallId);
4434
4483
  const anyOptions = options;
4435
4484
  const anyPart = part;
4436
4485
  if (part != null) {
@@ -4455,9 +4504,9 @@ function processUIMessageStream$1({ stream, messageMetadataSchema, dataPartSchem
4455
4504
  ...anyOptions.providerMetadata != null ? { callProviderMetadata: anyOptions.providerMetadata } : {}
4456
4505
  });
4457
4506
  }
4458
- function updateDynamicToolPart(options) {
4507
+ function updateDynamicToolPart(options, existingPart) {
4459
4508
  var _a17, _b2;
4460
- const part = state.message.parts.find((part2) => part2.type === "dynamic-tool" && part2.toolCallId === options.toolCallId);
4509
+ const part = existingPart != null ? existingPart : getCurrentStepParts().find((part2) => part2.type === "dynamic-tool" && part2.toolCallId === options.toolCallId);
4461
4510
  const anyOptions = options;
4462
4511
  const anyPart = part;
4463
4512
  if (part != null) {
@@ -4578,7 +4627,7 @@ function processUIMessageStream$1({ stream, messageMetadataSchema, dataPartSchem
4578
4627
  write();
4579
4628
  break;
4580
4629
  case "tool-input-start": {
4581
- const toolInvocations = state.message.parts.filter(isToolUIPart$1);
4630
+ const toolInvocations = getCurrentStepParts().filter(isToolUIPart$1);
4582
4631
  state.partialToolCalls[chunk.toolCallId] = {
4583
4632
  text: "",
4584
4633
  toolName: chunk.toolName,
@@ -4673,7 +4722,7 @@ function processUIMessageStream$1({ stream, messageMetadataSchema, dataPartSchem
4673
4722
  input: toolInvocation.input,
4674
4723
  output: chunk.output,
4675
4724
  preliminary: chunk.preliminary
4676
- });
4725
+ }, toolInvocation);
4677
4726
  } else {
4678
4727
  const toolInvocation = getToolInvocation(chunk.toolCallId);
4679
4728
  updateToolPart({
@@ -4684,7 +4733,7 @@ function processUIMessageStream$1({ stream, messageMetadataSchema, dataPartSchem
4684
4733
  output: chunk.output,
4685
4734
  providerExecuted: chunk.providerExecuted,
4686
4735
  preliminary: chunk.preliminary
4687
- });
4736
+ }, toolInvocation);
4688
4737
  }
4689
4738
  write();
4690
4739
  break;
@@ -4698,7 +4747,7 @@ function processUIMessageStream$1({ stream, messageMetadataSchema, dataPartSchem
4698
4747
  input: toolInvocation.input,
4699
4748
  errorText: chunk.errorText,
4700
4749
  providerExecuted: chunk.providerExecuted
4701
- });
4750
+ }, toolInvocation);
4702
4751
  } else {
4703
4752
  const toolInvocation = getToolInvocation(chunk.toolCallId);
4704
4753
  updateToolPart({
@@ -4709,7 +4758,7 @@ function processUIMessageStream$1({ stream, messageMetadataSchema, dataPartSchem
4709
4758
  rawInput: toolInvocation.rawInput,
4710
4759
  errorText: chunk.errorText,
4711
4760
  providerExecuted: chunk.providerExecuted
4712
- });
4761
+ }, toolInvocation);
4713
4762
  }
4714
4763
  write();
4715
4764
  break;
@@ -5000,7 +5049,7 @@ function createUIMessageStream$1({ execute, onError = () => "An error occurred."
5000
5049
  });
5001
5050
  }
5002
5051
  //#endregion
5003
- //#region ../../packages/_vendored/ai_v6/dist/dist-BomuqvJJ.js
5052
+ //#region ../../packages/_vendored/ai_v6/dist/dist-BTWHzT8H.js
5004
5053
  var marker$1 = "vercel.ai.error";
5005
5054
  var symbol$1 = Symbol.for(marker$1);
5006
5055
  var _a$1;
@@ -5340,6 +5389,26 @@ var _b;
5340
5389
  return AISDKError.hasMarker(error, marker$2);
5341
5390
  }
5342
5391
  });
5392
+ var initialGlobalFetch = globalThis.fetch;
5393
+ isNodeDefaultFetch(initialGlobalFetch);
5394
+ function isNodeDefaultFetch(fetch) {
5395
+ const source = Function.prototype.toString.call(fetch);
5396
+ return source.includes("internal/deps/undici") || source.includes("lazy loading of undici");
5397
+ }
5398
+ function getCurrentModulePath() {
5399
+ const originalPrepareStackTrace = Error.prepareStackTrace;
5400
+ try {
5401
+ Error.prepareStackTrace = (_error, callSites) => callSites;
5402
+ const error = /* @__PURE__ */ new Error("Capture current module path");
5403
+ Error.captureStackTrace(error, getCurrentModulePath);
5404
+ const [caller] = error.stack;
5405
+ const fileName = caller == null ? void 0 : caller.getFileName();
5406
+ if (fileName == null) throw new Error("Unable to determine the current module path");
5407
+ return fileName;
5408
+ } finally {
5409
+ Error.prepareStackTrace = originalPrepareStackTrace;
5410
+ }
5411
+ }
5343
5412
  var createIdGenerator = ({ prefix, size = 16, alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", separator = "-" } = {}) => {
5344
5413
  const generator = () => {
5345
5414
  const alphabetLength = alphabet.length;
@@ -7290,6 +7359,25 @@ _a16 = symbol16;
7290
7359
  function asArray(value) {
7291
7360
  return value === void 0 ? [] : Array.isArray(value) ? value : [value];
7292
7361
  }
7362
+ function mergeObjects(base, overrides) {
7363
+ if (base === void 0 && overrides === void 0) return;
7364
+ if (base === void 0) return overrides;
7365
+ if (overrides === void 0) return base;
7366
+ const result = { ...base };
7367
+ for (const key in overrides) {
7368
+ if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
7369
+ if (Object.prototype.hasOwnProperty.call(overrides, key)) {
7370
+ const overridesValue = overrides[key];
7371
+ if (overridesValue === void 0) continue;
7372
+ const baseValue = key in base ? base[key] : void 0;
7373
+ const isSourceObject = overridesValue !== null && typeof overridesValue === "object" && !Array.isArray(overridesValue) && !(overridesValue instanceof Date) && !(overridesValue instanceof RegExp);
7374
+ const isTargetObject = baseValue !== null && baseValue !== void 0 && typeof baseValue === "object" && !Array.isArray(baseValue) && !(baseValue instanceof Date) && !(baseValue instanceof RegExp);
7375
+ if (isSourceObject && isTargetObject) result[key] = mergeObjects(baseValue, overridesValue);
7376
+ else result[key] = overridesValue;
7377
+ }
7378
+ }
7379
+ return result;
7380
+ }
7293
7381
  var dataContentSchema = zod_v4.z.union([
7294
7382
  zod_v4.z.string(),
7295
7383
  zod_v4.z.instanceof(Uint8Array),
@@ -7473,25 +7561,6 @@ zod_v4.z.union([
7473
7561
  assistantModelMessageSchema,
7474
7562
  toolModelMessageSchema
7475
7563
  ]);
7476
- function mergeObjects(base, overrides) {
7477
- if (base === void 0 && overrides === void 0) return;
7478
- if (base === void 0) return overrides;
7479
- if (overrides === void 0) return base;
7480
- const result = { ...base };
7481
- for (const key in overrides) {
7482
- if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
7483
- if (Object.prototype.hasOwnProperty.call(overrides, key)) {
7484
- const overridesValue = overrides[key];
7485
- if (overridesValue === void 0) continue;
7486
- const baseValue = key in base ? base[key] : void 0;
7487
- const isSourceObject = overridesValue !== null && typeof overridesValue === "object" && !Array.isArray(overridesValue) && !(overridesValue instanceof Date) && !(overridesValue instanceof RegExp);
7488
- const isTargetObject = baseValue !== null && baseValue !== void 0 && typeof baseValue === "object" && !Array.isArray(baseValue) && !(baseValue instanceof Date) && !(baseValue instanceof RegExp);
7489
- if (isSourceObject && isTargetObject) result[key] = mergeObjects(baseValue, overridesValue);
7490
- else result[key] = overridesValue;
7491
- }
7492
- }
7493
- return result;
7494
- }
7495
7564
  new TextEncoder();
7496
7565
  __export({}, {
7497
7566
  array: () => array,
@@ -8103,8 +8172,27 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8103
8172
  return stream.pipeThrough(new TransformStream({ async transform(chunk, controller) {
8104
8173
  await runUpdateMessageJob(async ({ state, write }) => {
8105
8174
  var _a22, _b, _c, _d;
8175
+ function getCurrentStepParts() {
8176
+ const parts = state.message.parts;
8177
+ let currentStepStartIndex = parts.length - 1;
8178
+ while (currentStepStartIndex >= 0 && parts[currentStepStartIndex].type !== "step-start") currentStepStartIndex--;
8179
+ return parts.slice(currentStepStartIndex + 1);
8180
+ }
8181
+ function getCurrentStepToolInvocations() {
8182
+ return getCurrentStepParts().filter(isToolUIPart);
8183
+ }
8106
8184
  function getToolInvocation(toolCallId) {
8107
- const toolInvocation = state.message.parts.filter(isToolUIPart).find((invocation) => invocation.toolCallId === toolCallId);
8185
+ let toolInvocation = getCurrentStepToolInvocations().find((invocation) => invocation.toolCallId === toolCallId);
8186
+ if (toolInvocation == null) {
8187
+ const parts = state.message.parts;
8188
+ for (let i = parts.length - 1; i >= 0; i--) {
8189
+ const part = parts[i];
8190
+ if (isToolUIPart(part) && part.toolCallId === toolCallId) {
8191
+ toolInvocation = part;
8192
+ break;
8193
+ }
8194
+ }
8195
+ }
8108
8196
  if (toolInvocation == null) throw new UIMessageStreamError({
8109
8197
  chunkType: "tool-invocation",
8110
8198
  chunkId: toolCallId,
@@ -8112,9 +8200,9 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8112
8200
  });
8113
8201
  return toolInvocation;
8114
8202
  }
8115
- function updateToolPart(options) {
8203
+ function updateToolPart(options, existingPart) {
8116
8204
  var _a23;
8117
- const part = state.message.parts.find((part2) => isStaticToolUIPart(part2) && part2.toolCallId === options.toolCallId);
8205
+ const part = existingPart != null ? existingPart : getCurrentStepParts().find((part2) => isStaticToolUIPart(part2) && part2.toolCallId === options.toolCallId);
8118
8206
  const anyOptions = options;
8119
8207
  const anyPart = part;
8120
8208
  if (part != null) {
@@ -8148,9 +8236,9 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8148
8236
  ...anyOptions.providerMetadata != null && !(options.state === "output-available" || options.state === "output-error") ? { callProviderMetadata: anyOptions.providerMetadata } : {}
8149
8237
  });
8150
8238
  }
8151
- function updateDynamicToolPart(options) {
8239
+ function updateDynamicToolPart(options, existingPart) {
8152
8240
  var _a23, _b2;
8153
- const part = state.message.parts.find((part2) => part2.type === "dynamic-tool" && part2.toolCallId === options.toolCallId);
8241
+ const part = existingPart != null ? existingPart : getCurrentStepParts().find((part2) => part2.type === "dynamic-tool" && part2.toolCallId === options.toolCallId);
8154
8242
  const anyOptions = options;
8155
8243
  const anyPart = part;
8156
8244
  if (part != null) {
@@ -8305,7 +8393,7 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8305
8393
  write();
8306
8394
  break;
8307
8395
  case "tool-input-start": {
8308
- const toolInvocations = state.message.parts.filter(isStaticToolUIPart);
8396
+ const toolInvocations = getCurrentStepParts().filter(isStaticToolUIPart);
8309
8397
  state.partialToolCalls[chunk.toolCallId] = {
8310
8398
  text: "",
8311
8399
  toolName: chunk.toolName,
@@ -8390,7 +8478,7 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8390
8478
  if (onToolCall && !chunk.providerExecuted) await onToolCall({ toolCall: chunk });
8391
8479
  break;
8392
8480
  case "tool-input-error": {
8393
- const existingPart = state.message.parts.filter(isToolUIPart).find((p) => p.toolCallId === chunk.toolCallId);
8481
+ const existingPart = getCurrentStepParts().filter(isToolUIPart).find((p) => p.toolCallId === chunk.toolCallId);
8394
8482
  if (existingPart != null ? existingPart.type === "dynamic-tool" : !!chunk.dynamic) updateDynamicToolPart({
8395
8483
  toolCallId: chunk.toolCallId,
8396
8484
  toolName: chunk.toolName,
@@ -8444,7 +8532,7 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8444
8532
  providerMetadata: chunk.providerMetadata,
8445
8533
  title: toolInvocation.title,
8446
8534
  toolMetadata: toolInvocation.toolMetadata
8447
- });
8535
+ }, toolInvocation);
8448
8536
  else updateToolPart({
8449
8537
  toolCallId: chunk.toolCallId,
8450
8538
  toolName: getStaticToolName(toolInvocation),
@@ -8456,7 +8544,7 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8456
8544
  providerMetadata: chunk.providerMetadata,
8457
8545
  title: toolInvocation.title,
8458
8546
  toolMetadata: toolInvocation.toolMetadata
8459
- });
8547
+ }, toolInvocation);
8460
8548
  write();
8461
8549
  break;
8462
8550
  }
@@ -8472,7 +8560,7 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8472
8560
  providerMetadata: chunk.providerMetadata,
8473
8561
  title: toolInvocation.title,
8474
8562
  toolMetadata: toolInvocation.toolMetadata
8475
- });
8563
+ }, toolInvocation);
8476
8564
  else updateToolPart({
8477
8565
  toolCallId: chunk.toolCallId,
8478
8566
  toolName: getStaticToolName(toolInvocation),
@@ -8484,7 +8572,7 @@ function processUIMessageStream({ stream, messageMetadataSchema, dataPartSchemas
8484
8572
  providerMetadata: chunk.providerMetadata,
8485
8573
  title: toolInvocation.title,
8486
8574
  toolMetadata: toolInvocation.toolMetadata
8487
- });
8575
+ }, toolInvocation);
8488
8576
  write();
8489
8577
  break;
8490
8578
  }
@@ -9339,6 +9427,7 @@ function convertFullStreamChunkToUIMessageStream({ part, messageMetadataValue, s
9339
9427
  //#endregion
9340
9428
  //#region src/transformers.ts
9341
9429
  const PRIMITIVE_CACHE_SYMBOL = Symbol("primitive-cache");
9430
+ const COMPLETED_STEPS_SYMBOL = Symbol("completed-steps-cache");
9342
9431
  function cloneWorkflowStep(step, includeOutput) {
9343
9432
  return {
9344
9433
  name: step.name,
@@ -9466,7 +9555,8 @@ function createAgentStreamToAISDKTransformer(convertMastraChunkToAISDK, { lastMe
9466
9555
  if (transformedChunk) if (transformedChunk.type === "tool-agent") {
9467
9556
  const payload = transformedChunk.payload;
9468
9557
  const agentTransformed = transformAgent(payload, bufferedSteps);
9469
- if (agentTransformed) controller.enqueue(agentTransformed);
9558
+ if (agentTransformed) if (Array.isArray(agentTransformed)) for (const part of agentTransformed) controller.enqueue(part);
9559
+ else controller.enqueue(agentTransformed);
9470
9560
  } else if (transformedChunk.type === "tool-workflow") {
9471
9561
  const payload = transformedChunk.payload;
9472
9562
  const workflowChunk = transformWorkflow(payload, bufferedSteps, true, void 0, void 0, convertMastraChunkToAISDK);
@@ -9549,30 +9639,7 @@ function AgentStreamToAISDKV6Transformer({ lastMessageId, sendStart = true, send
9549
9639
  });
9550
9640
  }
9551
9641
  function ensureAgentRunState(bufferedSteps, runId) {
9552
- if (!bufferedSteps.has(runId)) bufferedSteps.set(runId, {
9553
- id: "",
9554
- object: null,
9555
- finishReason: null,
9556
- usage: null,
9557
- warnings: [],
9558
- text: "",
9559
- reasoning: [],
9560
- sources: [],
9561
- files: [],
9562
- toolCalls: [],
9563
- pendingToolCalls: [],
9564
- toolResults: [],
9565
- request: {},
9566
- response: {
9567
- id: "",
9568
- timestamp: /* @__PURE__ */ new Date(),
9569
- modelId: "",
9570
- messages: []
9571
- },
9572
- providerMetadata: void 0,
9573
- steps: [],
9574
- status: "running"
9575
- });
9642
+ if (!bufferedSteps.has(runId)) bufferedSteps.set(runId, createAgentRunState());
9576
9643
  return bufferedSteps.get(runId);
9577
9644
  }
9578
9645
  function upsertPendingToolCall(pendingToolCalls = [], toolCallId, updates) {
@@ -9608,36 +9675,109 @@ function appendPendingToolCallArgs(pendingToolCalls = [], payload) {
9608
9675
  function removePendingToolCall(pendingToolCalls = [], toolCallId) {
9609
9676
  return pendingToolCalls.filter((call) => call.toolCallId !== toolCallId);
9610
9677
  }
9678
+ function createAgentResponseState() {
9679
+ return {
9680
+ id: "",
9681
+ timestamp: /* @__PURE__ */ new Date(),
9682
+ modelId: "",
9683
+ messages: []
9684
+ };
9685
+ }
9686
+ function createAgentRunState(id = "") {
9687
+ return {
9688
+ id,
9689
+ object: null,
9690
+ finishReason: null,
9691
+ usage: null,
9692
+ warnings: [],
9693
+ text: "",
9694
+ reasoning: [],
9695
+ sources: [],
9696
+ files: [],
9697
+ toolCalls: [],
9698
+ pendingToolCalls: [],
9699
+ toolResults: [],
9700
+ request: {},
9701
+ response: createAgentResponseState(),
9702
+ providerMetadata: void 0,
9703
+ steps: [],
9704
+ status: "running"
9705
+ };
9706
+ }
9707
+ function cloneAgentResponse(response, { includeMessages }) {
9708
+ if (!response) return response;
9709
+ return {
9710
+ ...response,
9711
+ ...Object.prototype.hasOwnProperty.call(response, "messages") ? { messages: includeMessages ? response.messages : [] } : {},
9712
+ ...Object.prototype.hasOwnProperty.call(response, "dbMessages") ? { dbMessages: includeMessages ? response.dbMessages : [] } : {},
9713
+ ...Object.prototype.hasOwnProperty.call(response, "uiMessages") ? { uiMessages: includeMessages ? response.uiMessages : [] } : {}
9714
+ };
9715
+ }
9716
+ function cloneAgentStep(step, { includeDetails }) {
9717
+ if (includeDetails) return {
9718
+ ...step,
9719
+ response: cloneAgentResponse(step.response, { includeMessages: true })
9720
+ };
9721
+ return {
9722
+ ...step,
9723
+ object: null,
9724
+ files: [],
9725
+ sources: [],
9726
+ toolCalls: [],
9727
+ pendingToolCalls: [],
9728
+ toolResults: [],
9729
+ dynamicToolCalls: [],
9730
+ dynamicToolResults: [],
9731
+ staticToolCalls: [],
9732
+ staticToolResults: [],
9733
+ text: "",
9734
+ reasoning: [],
9735
+ content: Array.isArray(step.content) ? [] : step.content,
9736
+ reasoningText: typeof step.reasoningText === "string" ? "" : step.reasoningText,
9737
+ response: cloneAgentResponse(step.response, { includeMessages: false })
9738
+ };
9739
+ }
9740
+ function serializeAgentRun(current, { includeCompletedStepDetails, includeResponseMessages }) {
9741
+ const { _textOffset: _to, _reasoningOffset: _ro, ...data } = current;
9742
+ return {
9743
+ ...data,
9744
+ response: cloneAgentResponse(data.response, { includeMessages: includeResponseMessages }),
9745
+ steps: data.steps.map((step) => cloneAgentStep(step, { includeDetails: includeCompletedStepDetails }))
9746
+ };
9747
+ }
9748
+ function createAgentDataPart(args) {
9749
+ const { current, runId, includeCompletedStepDetails, includeResponseMessages } = args;
9750
+ return {
9751
+ type: "data-tool-agent",
9752
+ id: runId,
9753
+ data: serializeAgentRun(current, {
9754
+ includeCompletedStepDetails,
9755
+ includeResponseMessages
9756
+ })
9757
+ };
9758
+ }
9759
+ function createAgentStepDataPart(args) {
9760
+ const { runId, stepIndex, step } = args;
9761
+ return {
9762
+ type: "data-tool-agent-step",
9763
+ id: `${runId}:${stepIndex}`,
9764
+ data: {
9765
+ runId,
9766
+ stepIndex,
9767
+ step: cloneAgentStep(step, { includeDetails: true })
9768
+ }
9769
+ };
9770
+ }
9611
9771
  function transformAgent(payload, bufferedSteps) {
9612
9772
  let hasChanged = false;
9773
+ let completedStep = null;
9613
9774
  switch (payload.type) {
9614
- case "start":
9615
- bufferedSteps.set(payload.runId, {
9616
- id: payload.payload.id,
9617
- object: null,
9618
- finishReason: null,
9619
- usage: null,
9620
- warnings: [],
9621
- text: "",
9622
- reasoning: [],
9623
- sources: [],
9624
- files: [],
9625
- toolCalls: [],
9626
- pendingToolCalls: [],
9627
- toolResults: [],
9628
- request: {},
9629
- response: {
9630
- id: "",
9631
- timestamp: /* @__PURE__ */ new Date(),
9632
- modelId: "",
9633
- messages: []
9634
- },
9635
- providerMetadata: void 0,
9636
- steps: [],
9637
- status: "running"
9638
- });
9775
+ case "start": {
9776
+ const startState = createAgentRunState(payload.payload.id);
9777
+ bufferedSteps.set(payload.runId, startState);
9639
9778
  hasChanged = true;
9640
9779
  break;
9780
+ }
9641
9781
  case "tool-call-input-streaming-start": {
9642
9782
  const toolInputStartRun = ensureAgentRunState(bufferedSteps, payload.runId);
9643
9783
  const existing = toolInputStartRun.pendingToolCalls?.find((call) => call.toolCallId === payload.payload.toolCallId);
@@ -9768,6 +9908,7 @@ function transformAgent(payload, bufferedSteps) {
9768
9908
  break;
9769
9909
  case "step-finish": {
9770
9910
  const stepRun = ensureAgentRunState(bufferedSteps, payload.runId);
9911
+ const stepIndex = stepRun.steps.length;
9771
9912
  const { steps: _steps, _textOffset, _reasoningOffset, ...stepRunWithoutSteps } = stepRun;
9772
9913
  const textOffset = _textOffset || 0;
9773
9914
  const reasoningOffset = _reasoningOffset || 0;
@@ -9809,18 +9950,28 @@ function transformAgent(payload, bufferedSteps) {
9809
9950
  _textOffset: stepRun.text.length,
9810
9951
  _reasoningOffset: stepRun.reasoning.length
9811
9952
  });
9953
+ completedStep = {
9954
+ stepIndex,
9955
+ step: stepResult
9956
+ };
9812
9957
  hasChanged = true;
9813
9958
  break;
9814
9959
  }
9815
9960
  default: break;
9816
9961
  }
9817
9962
  if (hasChanged) {
9818
- const { _textOffset: _to, _reasoningOffset: _ro, ...data } = bufferedSteps.get(payload.runId);
9819
- return {
9820
- type: "data-tool-agent",
9821
- id: payload.runId,
9822
- data
9823
- };
9963
+ const snapshot = createAgentDataPart({
9964
+ current: bufferedSteps.get(payload.runId),
9965
+ runId: payload.runId,
9966
+ includeCompletedStepDetails: payload.type === "finish",
9967
+ includeResponseMessages: payload.type === "finish"
9968
+ });
9969
+ if (completedStep) return [snapshot, createAgentStepDataPart({
9970
+ runId: payload.runId,
9971
+ stepIndex: completedStep.stepIndex,
9972
+ step: completedStep.step
9973
+ })];
9974
+ return snapshot;
9824
9975
  }
9825
9976
  return null;
9826
9977
  }
@@ -10246,10 +10397,24 @@ function transformNetwork(payload, bufferedNetworks, isNested) {
10246
10397
  const step = current.steps.find((step) => step.id === stepId);
10247
10398
  if (!step) return null;
10248
10399
  step[PRIMITIVE_CACHE_SYMBOL] = step[PRIMITIVE_CACHE_SYMBOL] || /* @__PURE__ */ new Map();
10400
+ if (payload.payload.type === "start") delete step[COMPLETED_STEPS_SYMBOL];
10249
10401
  const result = transformAgent(payload.payload, step[PRIMITIVE_CACHE_SYMBOL]);
10250
- if (result) {
10251
- const { request, response, ...data } = result.data;
10402
+ const snapshot = Array.isArray(result) ? result[0] : result;
10403
+ if (snapshot) {
10404
+ const { request, response, ...data } = snapshot.data;
10405
+ if (Array.isArray(result)) {
10406
+ const { stepIndex, step: completedStepDetail } = result[1].data;
10407
+ step[COMPLETED_STEPS_SYMBOL] = step[COMPLETED_STEPS_SYMBOL] || /* @__PURE__ */ new Map();
10408
+ step[COMPLETED_STEPS_SYMBOL].set(stepIndex, completedStepDetail);
10409
+ }
10252
10410
  step.task = data;
10411
+ const completedSteps = step[COMPLETED_STEPS_SYMBOL];
10412
+ if (completedSteps && completedSteps.size > 0 && Array.isArray(data.steps)) {
10413
+ for (const [stepIndex, completedStepDetail] of completedSteps) if (stepIndex < data.steps.length) data.steps[stepIndex] = {
10414
+ ...data.steps[stepIndex],
10415
+ ...completedStepDetail
10416
+ };
10417
+ }
10253
10418
  }
10254
10419
  bufferedNetworks.set(payload.runId, current);
10255
10420
  return {
@@ -10373,6 +10538,124 @@ function toAISdkStream(stream, options = {
10373
10538
  }));
10374
10539
  }
10375
10540
  //#endregion
10541
+ //#region src/sse-heartbeat.ts
10542
+ const SSE_HEARTBEAT_BYTES = new TextEncoder().encode(": heartbeat\n\n");
10543
+ const LF_BYTE = 10;
10544
+ const MAX_TIMEOUT_MS = 2147483647;
10545
+ /** Throws when an enabled heartbeat interval cannot be scheduled with a timer. */
10546
+ function assertValidHeartbeatMs(heartbeatMs) {
10547
+ 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}`);
10548
+ }
10549
+ /**
10550
+ * Adds periodic SSE comment heartbeats to an AI SDK response body.
10551
+ * AI SDK serialization uses LF-delimited frames, which this private wrapper preserves and relies on.
10552
+ */
10553
+ function withSseHeartbeat(response, heartbeatMs) {
10554
+ assertValidHeartbeatMs(heartbeatMs);
10555
+ if (heartbeatMs === void 0 || heartbeatMs <= 0 || !response.body) return response;
10556
+ const reader = response.body.getReader();
10557
+ let heartbeatTimeout;
10558
+ let wakePull;
10559
+ let readResult;
10560
+ let readError;
10561
+ let hasReadError = false;
10562
+ let reading = false;
10563
+ let finished = false;
10564
+ let readerReleased = false;
10565
+ let atFrameBoundary = true;
10566
+ let lastByte;
10567
+ let nextHeartbeatAt = performance.now() + heartbeatMs;
10568
+ const clearHeartbeat = () => {
10569
+ if (heartbeatTimeout !== void 0) {
10570
+ clearTimeout(heartbeatTimeout);
10571
+ heartbeatTimeout = void 0;
10572
+ }
10573
+ };
10574
+ const releaseReader = () => {
10575
+ if (readerReleased) return;
10576
+ readerReleased = true;
10577
+ reader.releaseLock();
10578
+ };
10579
+ const updateFrameBoundary = (chunk) => {
10580
+ if (chunk.byteLength === 0) return;
10581
+ atFrameBoundary = chunk.byteLength === 1 ? lastByte === LF_BYTE && chunk[0] === LF_BYTE : chunk[chunk.byteLength - 2] === LF_BYTE && chunk[chunk.byteLength - 1] === LF_BYTE;
10582
+ lastByte = chunk[chunk.byteLength - 1];
10583
+ };
10584
+ const startRead = () => {
10585
+ if (reading || readResult || hasReadError || finished) return;
10586
+ reading = true;
10587
+ reader.read().then((result) => {
10588
+ reading = false;
10589
+ readResult = result;
10590
+ wakePull?.("read");
10591
+ }, (error) => {
10592
+ reading = false;
10593
+ readError = error;
10594
+ hasReadError = true;
10595
+ wakePull?.("read");
10596
+ });
10597
+ };
10598
+ const forwardRead = (controller) => {
10599
+ if (hasReadError) {
10600
+ finished = true;
10601
+ releaseReader();
10602
+ controller.error(readError);
10603
+ return;
10604
+ }
10605
+ if (!readResult) return;
10606
+ const result = readResult;
10607
+ readResult = void 0;
10608
+ if (result.done) {
10609
+ finished = true;
10610
+ releaseReader();
10611
+ controller.close();
10612
+ return;
10613
+ }
10614
+ updateFrameBoundary(result.value);
10615
+ controller.enqueue(result.value);
10616
+ };
10617
+ const stream = new ReadableStream({
10618
+ async pull(controller) {
10619
+ if (finished) return;
10620
+ startRead();
10621
+ if (readResult || hasReadError) {
10622
+ forwardRead(controller);
10623
+ return;
10624
+ }
10625
+ const next = await new Promise((resolve) => {
10626
+ wakePull = resolve;
10627
+ if (atFrameBoundary) heartbeatTimeout = setTimeout(() => resolve("heartbeat"), Math.max(0, nextHeartbeatAt - performance.now()));
10628
+ });
10629
+ wakePull = void 0;
10630
+ clearHeartbeat();
10631
+ if (finished) return;
10632
+ if (readResult || hasReadError) {
10633
+ forwardRead(controller);
10634
+ return;
10635
+ }
10636
+ if (next === "heartbeat") {
10637
+ controller.enqueue(SSE_HEARTBEAT_BYTES.slice());
10638
+ nextHeartbeatAt = performance.now() + heartbeatMs;
10639
+ }
10640
+ },
10641
+ async cancel(reason) {
10642
+ if (finished) return;
10643
+ finished = true;
10644
+ clearHeartbeat();
10645
+ try {
10646
+ await reader.cancel(reason);
10647
+ } finally {
10648
+ releaseReader();
10649
+ }
10650
+ }
10651
+ });
10652
+ return new Response(stream, {
10653
+ status: response.status,
10654
+ statusText: response.statusText,
10655
+ headers: response.headers
10656
+ });
10657
+ }
10658
+ //#endregion
10376
10659
  //#region src/chat-route.ts
10377
10660
  /**
10378
10661
  * Collects every approval response across all assistant messages in a v6
@@ -10575,11 +10858,13 @@ async function handleChatStream({ mastra, agentId, agentVersion, params, default
10575
10858
  * @param {boolean} [options.sendFinish=true] - Whether to send finish events in the stream
10576
10859
  * @param {boolean} [options.sendReasoning=false] - Whether to include reasoning steps in the stream
10577
10860
  * @param {boolean} [options.sendSources=false] - Whether to include source citations in the stream
10861
+ * @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`.
10578
10862
  * @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.
10579
10863
  *
10580
10864
  * @returns {ReturnType<typeof registerApiRoute>} A registered API route handler
10581
10865
  *
10582
10866
  * @throws {Error} When path doesn't include `:agentId` and no fixed agent is specified
10867
+ * @throws {RangeError} When `heartbeatMs` is `NaN`, positive infinity, or greater than 2,147,483,647
10583
10868
  * @throws {Error} When agent ID is missing at runtime
10584
10869
  * @throws {Error} When specified agent is not found in Mastra instance
10585
10870
  *
@@ -10602,12 +10887,13 @@ async function handleChatStream({ mastra, agentId, agentVersion, params, default
10602
10887
  * @remarks
10603
10888
  * - The route handler expects a JSON body with a `messages` array
10604
10889
  * - Messages should follow the format: `{ role: 'user' | 'assistant' | 'system', content: string }`
10605
- * - The response is a Server-Sent Events (SSE) stream compatible with AI SDK v5
10890
+ * - The response is a Server-Sent Events (SSE) stream compatible with the selected AI SDK version
10606
10891
  * - If both `agent` and `:agentId` are present, a warning is logged and the fixed `agent` takes precedence
10607
10892
  * - Request context from the incoming request overrides `defaultOptions.requestContext` if both are present
10608
10893
  */
10609
- function chatRoute({ path = "/chat/:agentId", agent, defaultOptions, experimentalTransform, version = "v5", agentVersion, sendStart = true, sendFinish = true, sendReasoning = false, sendSources = false, onError }) {
10894
+ function chatRoute({ path = "/chat/:agentId", agent, defaultOptions, experimentalTransform, version = "v5", agentVersion, sendStart = true, sendFinish = true, sendReasoning = false, sendSources = false, heartbeatMs, onError }) {
10610
10895
  if (!agent && !path.includes("/:agentId")) throw new Error("Path must include :agentId to route to the correct agent or pass the agent explicitly");
10896
+ assertValidHeartbeatMs(heartbeatMs);
10611
10897
  return (0, _mastra_core_server.registerApiRoute)(path, {
10612
10898
  method: "POST",
10613
10899
  openapi: {
@@ -10736,11 +11022,13 @@ function chatRoute({ path = "/chat/:agentId", agent, defaultOptions, experimenta
10736
11022
  sendSources,
10737
11023
  onError
10738
11024
  };
10739
- if (version === "v6") return createUIMessageStreamResponse({ stream: await handleChatStream({
11025
+ let response;
11026
+ if (version === "v6") response = createUIMessageStreamResponse({ stream: await handleChatStream({
10740
11027
  ...handlerOptions,
10741
11028
  version: "v6"
10742
11029
  }) });
10743
- return createUIMessageStreamResponse$1({ stream: await handleChatStream(handlerOptions) });
11030
+ else response = createUIMessageStreamResponse$1({ stream: await handleChatStream(handlerOptions) });
11031
+ return withSseHeartbeat(response, heartbeatMs);
10744
11032
  }
10745
11033
  });
10746
11034
  }