@mastra/ai-sdk 0.3.1 → 0.3.2

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
@@ -8,6 +8,45 @@ import { DefaultGeneratedFile, DefaultGeneratedFileWithType } from '@mastra/core
8
8
  var isDataChunkType = (chunk) => {
9
9
  return chunk && typeof chunk === "object" && "type" in chunk && chunk.type?.startsWith("data-");
10
10
  };
11
+ var isMastraTextStreamChunk = (chunk) => {
12
+ return chunk && typeof chunk === "object" && "type" in chunk && typeof chunk.type === "string" && [
13
+ "text-start",
14
+ "text-delta",
15
+ "text-end",
16
+ "reasoning-start",
17
+ "reasoning-delta",
18
+ "reasoning-end",
19
+ "file",
20
+ "source",
21
+ "tool-input-start",
22
+ "tool-input-delta",
23
+ "tool-call",
24
+ "tool-result",
25
+ "tool-error",
26
+ "error",
27
+ "start-step",
28
+ "finish-step",
29
+ "start",
30
+ "finish",
31
+ "abort",
32
+ "tool-input-end",
33
+ "raw"
34
+ ].includes(chunk.type);
35
+ };
36
+ function safeParseErrorObject(obj) {
37
+ if (typeof obj !== "object" || obj === null) {
38
+ return String(obj);
39
+ }
40
+ try {
41
+ const stringified = JSON.stringify(obj);
42
+ if (stringified === "{}") {
43
+ return String(obj);
44
+ }
45
+ return stringified;
46
+ } catch {
47
+ return String(obj);
48
+ }
49
+ }
11
50
  var isAgentExecutionDataChunkType = (chunk) => {
12
51
  return chunk && typeof chunk === "object" && "type" in chunk && chunk.type?.startsWith("agent-execution-event-") && "payload" in chunk && typeof chunk.payload === "object" && "type" in chunk.payload && chunk.payload.type?.startsWith("data-");
13
52
  };
@@ -475,7 +514,10 @@ function convertFullStreamChunkToUIMessageStream({
475
514
  }
476
515
 
477
516
  // src/transformers.ts
478
- function WorkflowStreamToAISDKTransformer() {
517
+ var PRIMITIVE_CACHE_SYMBOL = Symbol("primitive-cache");
518
+ function WorkflowStreamToAISDKTransformer({
519
+ includeTextStreamParts
520
+ } = {}) {
479
521
  const bufferedWorkflows = /* @__PURE__ */ new Map();
480
522
  return new TransformStream({
481
523
  start(controller) {
@@ -489,7 +531,7 @@ function WorkflowStreamToAISDKTransformer() {
489
531
  });
490
532
  },
491
533
  transform(chunk, controller) {
492
- const transformed = transformWorkflow(chunk, bufferedWorkflows);
534
+ const transformed = transformWorkflow(chunk, bufferedWorkflows, false, includeTextStreamParts);
493
535
  if (transformed) controller.enqueue(transformed);
494
536
  }
495
537
  });
@@ -518,7 +560,9 @@ function AgentStreamToAISDKTransformer({
518
560
  sendStart,
519
561
  sendFinish,
520
562
  sendReasoning,
521
- sendSources
563
+ sendSources,
564
+ messageMetadata,
565
+ onError
522
566
  }) {
523
567
  let bufferedSteps = /* @__PURE__ */ new Map();
524
568
  let tripwireOccurred = false;
@@ -536,11 +580,12 @@ function AgentStreamToAISDKTransformer({
536
580
  part,
537
581
  sendReasoning,
538
582
  sendSources,
583
+ messageMetadataValue: messageMetadata?.({ part }),
539
584
  sendStart,
540
585
  sendFinish,
541
586
  responseMessageId: lastMessageId,
542
- onError() {
543
- return "Error";
587
+ onError(error) {
588
+ return onError ? onError(error) : safeParseErrorObject(error);
544
589
  }
545
590
  });
546
591
  if (transformedChunk) {
@@ -707,7 +752,7 @@ function transformAgent(payload, bufferedSteps) {
707
752
  }
708
753
  return null;
709
754
  }
710
- function transformWorkflow(payload, bufferedWorkflows, isNested) {
755
+ function transformWorkflow(payload, bufferedWorkflows, isNested, includeTextStreamParts) {
711
756
  switch (payload.type) {
712
757
  case "workflow-start":
713
758
  bufferedWorkflows.set(payload.runId, {
@@ -800,6 +845,29 @@ function transformWorkflow(payload, bufferedWorkflows, isNested) {
800
845
  }
801
846
  };
802
847
  }
848
+ case "workflow-step-output": {
849
+ const output = payload.payload.output;
850
+ if (includeTextStreamParts && output && isMastraTextStreamChunk(output)) {
851
+ const part = convertMastraChunkToAISDKv5({ chunk: output, mode: "stream" });
852
+ const transformedChunk = convertFullStreamChunkToUIMessageStream({
853
+ part,
854
+ onError(error) {
855
+ return safeParseErrorObject(error);
856
+ }
857
+ });
858
+ return transformedChunk;
859
+ }
860
+ if (output && isDataChunkType(output)) {
861
+ if (!("data" in output)) {
862
+ throw new Error(
863
+ `UI Messages require a data property when using data- prefixed chunks
864
+ ${JSON.stringify(output)}`
865
+ );
866
+ }
867
+ return output;
868
+ }
869
+ return null;
870
+ }
803
871
  default: {
804
872
  if (isDataChunkType(payload)) {
805
873
  if (!("data" in payload)) {
@@ -819,12 +887,29 @@ function transformNetwork(payload, bufferedNetworks, isNested) {
819
887
  case "routing-agent-start": {
820
888
  if (!bufferedNetworks.has(payload.runId)) {
821
889
  bufferedNetworks.set(payload.runId, {
822
- name: payload.payload.agentId,
890
+ name: payload.payload.networkId,
823
891
  steps: [],
824
892
  usage: null,
825
893
  output: null
826
894
  });
827
895
  }
896
+ const current = bufferedNetworks.get(payload.runId);
897
+ current.steps.push({
898
+ id: payload.payload.runId,
899
+ name: payload.payload.agentId,
900
+ status: "running",
901
+ iteration: payload.payload.inputData.iteration,
902
+ input: {
903
+ task: payload.payload.inputData.task,
904
+ threadId: payload.payload.inputData.threadId,
905
+ threadResourceId: payload.payload.inputData.threadResourceId
906
+ },
907
+ output: "",
908
+ task: null,
909
+ suspendPayload: null,
910
+ resumePayload: null,
911
+ [PRIMITIVE_CACHE_SYMBOL]: /* @__PURE__ */ new Map()
912
+ });
828
913
  return {
829
914
  type: isNested ? "data-tool-network" : "data-network",
830
915
  id: payload.runId,
@@ -855,14 +940,19 @@ function transformNetwork(payload, bufferedNetworks, isNested) {
855
940
  };
856
941
  }
857
942
  case "agent-execution-start": {
858
- const current = bufferedNetworks.get(payload.runId) || { name: "", steps: [], usage: null, output: null };
943
+ const current = bufferedNetworks.get(payload.runId);
944
+ if (!current) return null;
859
945
  current.steps.push({
946
+ id: payload.payload.runId,
860
947
  name: payload.payload.agentId,
861
948
  status: "running",
862
- input: payload.payload.args || null,
949
+ iteration: payload.payload.args?.iteration ?? 0,
950
+ input: { prompt: payload.payload.args?.prompt ?? "" },
863
951
  output: null,
952
+ task: null,
864
953
  suspendPayload: null,
865
- resumePayload: null
954
+ resumePayload: null,
955
+ [PRIMITIVE_CACHE_SYMBOL]: /* @__PURE__ */ new Map()
866
956
  });
867
957
  bufferedNetworks.set(payload.runId, current);
868
958
  return {
@@ -875,14 +965,19 @@ function transformNetwork(payload, bufferedNetworks, isNested) {
875
965
  };
876
966
  }
877
967
  case "workflow-execution-start": {
878
- const current = bufferedNetworks.get(payload.runId) || { name: "", steps: [], usage: null, output: null };
968
+ const current = bufferedNetworks.get(payload.runId);
969
+ if (!current) return null;
879
970
  current.steps.push({
880
- name: payload.payload.name,
971
+ id: payload.payload.runId,
972
+ name: payload.payload.workflowId,
881
973
  status: "running",
882
- input: payload.payload.args || null,
974
+ iteration: payload.payload.args?.iteration ?? 0,
975
+ input: { prompt: payload.payload.args?.prompt ?? "" },
883
976
  output: null,
977
+ task: null,
884
978
  suspendPayload: null,
885
- resumePayload: null
979
+ resumePayload: null,
980
+ [PRIMITIVE_CACHE_SYMBOL]: /* @__PURE__ */ new Map()
886
981
  });
887
982
  bufferedNetworks.set(payload.runId, current);
888
983
  return {
@@ -895,14 +990,21 @@ function transformNetwork(payload, bufferedNetworks, isNested) {
895
990
  };
896
991
  }
897
992
  case "tool-execution-start": {
898
- const current = bufferedNetworks.get(payload.runId) || { name: "", steps: [], usage: null, output: null };
993
+ const current = bufferedNetworks.get(payload.runId);
994
+ if (!current) return null;
899
995
  current.steps.push({
996
+ id: payload.payload.args.toolCallId,
900
997
  name: payload.payload.args?.toolName,
901
998
  status: "running",
999
+ iteration: payload.payload.args?.iteration ? Number(payload.payload.args.iteration) : 0,
1000
+ task: {
1001
+ id: payload.payload.args?.toolName
1002
+ },
902
1003
  input: payload.payload.args?.args || null,
903
1004
  output: null,
904
1005
  suspendPayload: null,
905
- resumePayload: null
1006
+ resumePayload: null,
1007
+ [PRIMITIVE_CACHE_SYMBOL]: /* @__PURE__ */ new Map()
906
1008
  });
907
1009
  bufferedNetworks.set(payload.runId, current);
908
1010
  return {
@@ -917,14 +1019,13 @@ function transformNetwork(payload, bufferedNetworks, isNested) {
917
1019
  case "agent-execution-end": {
918
1020
  const current = bufferedNetworks.get(payload.runId);
919
1021
  if (!current) return null;
920
- current.steps.push({
921
- name: payload.payload.agentId,
922
- status: "success",
923
- input: null,
924
- output: payload.payload.result,
925
- suspendPayload: null,
926
- resumePayload: null
927
- });
1022
+ const stepId = payload.payload.runId;
1023
+ const step = current.steps.find((step2) => step2.id === stepId);
1024
+ if (!step) {
1025
+ return null;
1026
+ }
1027
+ step.status = "success";
1028
+ step.output = payload.payload.result;
928
1029
  return {
929
1030
  type: isNested ? "data-tool-network" : "data-network",
930
1031
  id: payload.runId,
@@ -939,14 +1040,13 @@ function transformNetwork(payload, bufferedNetworks, isNested) {
939
1040
  case "tool-execution-end": {
940
1041
  const current = bufferedNetworks.get(payload.runId);
941
1042
  if (!current) return null;
942
- current.steps.push({
943
- name: payload.payload.toolName,
944
- status: "success",
945
- input: null,
946
- output: payload.payload.result,
947
- suspendPayload: null,
948
- resumePayload: null
949
- });
1043
+ const stepId = payload.payload.toolCallId;
1044
+ const step = current.steps.find((step2) => step2.id === stepId);
1045
+ if (!step) {
1046
+ return null;
1047
+ }
1048
+ step.status = "success";
1049
+ step.output = payload.payload.result;
950
1050
  return {
951
1051
  type: isNested ? "data-tool-network" : "data-network",
952
1052
  id: payload.runId,
@@ -960,14 +1060,13 @@ function transformNetwork(payload, bufferedNetworks, isNested) {
960
1060
  case "workflow-execution-end": {
961
1061
  const current = bufferedNetworks.get(payload.runId);
962
1062
  if (!current) return null;
963
- current.steps.push({
964
- name: payload.payload.name,
965
- status: "success",
966
- input: null,
967
- output: payload.payload.result,
968
- suspendPayload: null,
969
- resumePayload: null
970
- });
1063
+ const stepId = payload.payload.runId;
1064
+ const step = current.steps.find((step2) => step2.id === stepId);
1065
+ if (!step) {
1066
+ return null;
1067
+ }
1068
+ step.status = "success";
1069
+ step.output = payload.payload.result;
971
1070
  return {
972
1071
  type: isNested ? "data-tool-network" : "data-network",
973
1072
  id: payload.runId,
@@ -982,12 +1081,24 @@ function transformNetwork(payload, bufferedNetworks, isNested) {
982
1081
  case "routing-agent-end": {
983
1082
  const current = bufferedNetworks.get(payload.runId);
984
1083
  if (!current) return null;
1084
+ const stepId = payload.payload.runId;
1085
+ const step = current.steps.find((step2) => step2.id === stepId);
1086
+ if (!step) {
1087
+ return null;
1088
+ }
1089
+ step.status = "success";
1090
+ step.task = {
1091
+ id: payload.payload.primitiveId,
1092
+ type: payload.payload.primitiveType,
1093
+ name: payload.payload.task,
1094
+ reason: payload.payload.selectionReason
1095
+ };
1096
+ step.output = payload.payload.result;
985
1097
  return {
986
1098
  type: isNested ? "data-tool-network" : "data-network",
987
1099
  id: payload.runId,
988
1100
  data: {
989
1101
  ...current,
990
- status: "finished",
991
1102
  usage: payload.payload?.usage ?? current.usage,
992
1103
  output: payload.payload?.result ?? current.output
993
1104
  }
@@ -1021,6 +1132,39 @@ function transformNetwork(payload, bufferedNetworks, isNested) {
1021
1132
  };
1022
1133
  }
1023
1134
  default: {
1135
+ if (payload.type.startsWith("agent-execution-event-")) {
1136
+ const stepId = payload.payload.runId;
1137
+ const current = bufferedNetworks.get(payload.runId);
1138
+ if (!current) return null;
1139
+ const step = current.steps.find((step2) => step2.id === stepId);
1140
+ if (!step) {
1141
+ return null;
1142
+ }
1143
+ step[PRIMITIVE_CACHE_SYMBOL] = step[PRIMITIVE_CACHE_SYMBOL] || /* @__PURE__ */ new Map();
1144
+ const result = transformAgent(payload.payload, step[PRIMITIVE_CACHE_SYMBOL]);
1145
+ if (result) {
1146
+ const { request, response, ...data } = result.data;
1147
+ step.task = data;
1148
+ }
1149
+ }
1150
+ if (payload.type.startsWith("workflow-execution-event-")) {
1151
+ const stepId = payload.payload.runId;
1152
+ const current = bufferedNetworks.get(payload.runId);
1153
+ if (!current) return null;
1154
+ const step = current.steps.find((step2) => step2.id === stepId);
1155
+ if (!step) {
1156
+ return null;
1157
+ }
1158
+ step[PRIMITIVE_CACHE_SYMBOL] = step[PRIMITIVE_CACHE_SYMBOL] || /* @__PURE__ */ new Map();
1159
+ const result = transformWorkflow(payload.payload, step[PRIMITIVE_CACHE_SYMBOL]);
1160
+ if (result && "data" in result) {
1161
+ const data = result.data;
1162
+ step.task = data;
1163
+ if (data.name && step.task) {
1164
+ step.task.id = data.name;
1165
+ }
1166
+ }
1167
+ }
1024
1168
  if (isDataChunkType(payload)) {
1025
1169
  if (!("data" in payload)) {
1026
1170
  throw new Error(
@@ -1028,7 +1172,8 @@ function transformNetwork(payload, bufferedNetworks, isNested) {
1028
1172
  ${JSON.stringify(payload)}`
1029
1173
  );
1030
1174
  }
1031
- return payload;
1175
+ const { type, data } = payload;
1176
+ return { type, data };
1032
1177
  }
1033
1178
  if (isAgentExecutionDataChunkType(payload)) {
1034
1179
  if (!("data" in payload.payload)) {
@@ -1037,7 +1182,8 @@ function transformNetwork(payload, bufferedNetworks, isNested) {
1037
1182
  ${JSON.stringify(payload)}`
1038
1183
  );
1039
1184
  }
1040
- return payload.payload;
1185
+ const { type, data } = payload.payload;
1186
+ return { type, data };
1041
1187
  }
1042
1188
  if (isWorkflowExecutionDataChunkType(payload)) {
1043
1189
  if (!("data" in payload.payload)) {
@@ -1046,7 +1192,8 @@ function transformNetwork(payload, bufferedNetworks, isNested) {
1046
1192
  ${JSON.stringify(payload)}`
1047
1193
  );
1048
1194
  }
1049
- return payload.payload;
1195
+ const { type, data } = payload.payload;
1196
+ return { type, data };
1050
1197
  }
1051
1198
  return null;
1052
1199
  }
@@ -1061,7 +1208,10 @@ function toAISdkFormat(stream, options = {
1061
1208
  }) {
1062
1209
  const from = options?.from;
1063
1210
  if (from === "workflow") {
1064
- return stream.pipeThrough(WorkflowStreamToAISDKTransformer());
1211
+ const includeTextStreamParts = options?.includeTextStreamParts ?? false;
1212
+ return stream.pipeThrough(
1213
+ WorkflowStreamToAISDKTransformer({ includeTextStreamParts })
1214
+ );
1065
1215
  }
1066
1216
  if (from === "network") {
1067
1217
  return stream.pipeThrough(AgentNetworkToAISDKTransformer());
@@ -1073,7 +1223,9 @@ function toAISdkFormat(stream, options = {
1073
1223
  sendStart: options?.sendStart,
1074
1224
  sendFinish: options?.sendFinish,
1075
1225
  sendReasoning: options?.sendReasoning,
1076
- sendSources: options?.sendSources
1226
+ sendSources: options?.sendSources,
1227
+ messageMetadata: options?.messageMetadata,
1228
+ onError: options?.onError
1077
1229
  })
1078
1230
  );
1079
1231
  }
@@ -1204,7 +1356,7 @@ function chatRoute({
1204
1356
  if (!agentToUse) {
1205
1357
  throw new Error("Agent ID is required");
1206
1358
  }
1207
- const agentObj = mastra.getAgent(agentToUse);
1359
+ const agentObj = mastra.getAgentById(agentToUse);
1208
1360
  if (!agentObj) {
1209
1361
  throw new Error(`Agent ${agentToUse} not found`);
1210
1362
  }
@@ -1240,7 +1392,8 @@ function chatRoute({
1240
1392
  }
1241
1393
  function workflowRoute({
1242
1394
  path = "/api/workflows/:workflowId/stream",
1243
- workflow
1395
+ workflow,
1396
+ includeTextStreamParts = false
1244
1397
  }) {
1245
1398
  if (!workflow && !path.includes("/:workflowId")) {
1246
1399
  throw new Error("Path must include :workflowId to route to the correct workflow or pass the workflow explicitly");
@@ -1293,6 +1446,7 @@ function workflowRoute({
1293
1446
  handler: async (c) => {
1294
1447
  const { runId, resourceId, inputData, resumeData, ...rest } = await c.req.json();
1295
1448
  const mastra = c.get("mastra");
1449
+ const runtimeContext = c.get("runtimeContext");
1296
1450
  let workflowToUse = workflow;
1297
1451
  if (!workflow) {
1298
1452
  const workflowId = c.req.param("workflowId");
@@ -1306,15 +1460,20 @@ function workflowRoute({
1306
1460
  if (!workflowToUse) {
1307
1461
  throw new Error("Workflow ID is required");
1308
1462
  }
1309
- const workflowObj = mastra.getWorkflow(workflowToUse);
1463
+ const workflowObj = mastra.getWorkflowById(workflowToUse);
1310
1464
  if (!workflowObj) {
1311
1465
  throw new Error(`Workflow ${workflowToUse} not found`);
1312
1466
  }
1467
+ if (runtimeContext && rest.runtimeContext) {
1468
+ mastra.getLogger()?.warn(
1469
+ `"runtimeContext" from the request body will be ignored because "runtimeContext" is already set in the route options.`
1470
+ );
1471
+ }
1313
1472
  const run = await workflowObj.createRunAsync({ runId, resourceId, ...rest });
1314
- const stream = resumeData ? run.resumeStream({ resumeData, ...rest }) : run.stream({ inputData, ...rest });
1473
+ const stream = resumeData ? run.resumeStream({ resumeData, ...rest, runtimeContext: runtimeContext || rest.runtimeContext }) : run.stream({ inputData, ...rest, runtimeContext: runtimeContext || rest.runtimeContext });
1315
1474
  const uiMessageStream = createUIMessageStream({
1316
1475
  execute: async ({ writer }) => {
1317
- for await (const part of toAISdkFormat(stream, { from: "workflow" })) {
1476
+ for await (const part of toAISdkFormat(stream, { from: "workflow", includeTextStreamParts })) {
1318
1477
  writer.write(part);
1319
1478
  }
1320
1479
  }
@@ -1399,7 +1558,7 @@ function networkRoute({
1399
1558
  if (!agentToUse) {
1400
1559
  throw new Error("Agent ID is required");
1401
1560
  }
1402
- const agentObj = mastra.getAgent(agentToUse);
1561
+ const agentObj = mastra.getAgentById(agentToUse);
1403
1562
  if (!agentObj) {
1404
1563
  throw new Error(`Agent ${agentToUse} not found`);
1405
1564
  }