@mastra/ai-sdk 0.1.1 → 0.2.0-alpha.1

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
@@ -317,6 +317,18 @@ function convertFullStreamChunkToUIMessageStream({
317
317
  toolCallId: part.toolCallId,
318
318
  payload: part.output
319
319
  };
320
+ } else if (part.output.from === "WORKFLOW") {
321
+ return {
322
+ type: "tool-workflow",
323
+ toolCallId: part.toolCallId,
324
+ payload: part.output
325
+ };
326
+ } else if (part.output.from === "NETWORK") {
327
+ return {
328
+ type: "tool-network",
329
+ toolCallId: part.toolCallId,
330
+ payload: part.output
331
+ };
320
332
  }
321
333
  return;
322
334
  }
@@ -374,96 +386,42 @@ function convertFullStreamChunkToUIMessageStream({
374
386
  }
375
387
  }
376
388
 
377
- // src/to-ai-sdk-format.ts
389
+ // src/transformers.ts
378
390
  function WorkflowStreamToAISDKTransformer() {
379
- const steps = {};
391
+ const bufferedWorkflows = /* @__PURE__ */ new Map();
380
392
  return new TransformStream({
381
393
  start(controller) {
382
394
  controller.enqueue({
383
- data: JSON.stringify({
384
- type: "start",
385
- messageId: "1"
386
- })
395
+ type: "start"
387
396
  });
388
397
  },
389
398
  flush(controller) {
390
399
  controller.enqueue({
391
- data: JSON.stringify({
392
- type: "finish"
393
- })
400
+ type: "finish"
401
+ });
402
+ },
403
+ transform(chunk, controller) {
404
+ const transformed = transformWorkflow(chunk, bufferedWorkflows);
405
+ if (transformed) controller.enqueue(transformed);
406
+ }
407
+ });
408
+ }
409
+ function AgentNetworkToAISDKTransformer() {
410
+ const bufferedNetworks = /* @__PURE__ */ new Map();
411
+ return new TransformStream({
412
+ start(controller) {
413
+ controller.enqueue({
414
+ type: "start"
394
415
  });
416
+ },
417
+ flush(controller) {
395
418
  controller.enqueue({
396
- data: "[DONE]"
419
+ type: "finish"
397
420
  });
398
421
  },
399
422
  transform(chunk, controller) {
400
- let workflowName = "";
401
- if (chunk.type === "workflow-start") {
402
- workflowName = chunk.payload.workflowId;
403
- controller.enqueue({
404
- data: JSON.stringify({
405
- type: "data-workflow",
406
- id: chunk.runId,
407
- data: {
408
- name: workflowName,
409
- status: "running",
410
- steps: {},
411
- output: null
412
- }
413
- })
414
- });
415
- } else if (chunk.type === "workflow-step-start") {
416
- steps[chunk.payload.id] = {
417
- // TODO swap with name
418
- name: chunk.payload.id,
419
- status: chunk.payload.status,
420
- input: chunk.payload.payload ?? null,
421
- output: null
422
- };
423
- controller.enqueue({
424
- data: JSON.stringify({
425
- type: "data-workflow",
426
- id: chunk.runId,
427
- data: {
428
- name: workflowName,
429
- status: "running",
430
- steps,
431
- output: null
432
- }
433
- })
434
- });
435
- } else if (chunk.type === "workflow-step-result") {
436
- steps[chunk.payload.id] = {
437
- ...steps[chunk.payload.id],
438
- status: chunk.payload.status,
439
- output: chunk.payload.output ?? null
440
- };
441
- controller.enqueue({
442
- data: JSON.stringify({
443
- type: "data-workflow",
444
- id: chunk.runId,
445
- data: {
446
- name: workflowName,
447
- status: "running",
448
- steps,
449
- output: null
450
- }
451
- })
452
- });
453
- } else if (chunk.type === "workflow-finish") {
454
- controller.enqueue({
455
- data: JSON.stringify({
456
- type: "data-workflow",
457
- id: chunk.runId,
458
- data: {
459
- name: workflowName,
460
- steps,
461
- output: chunk.payload.output ?? null,
462
- status: chunk.payload.workflowStatus
463
- }
464
- })
465
- });
466
- }
423
+ const transformed = transformNetwork(chunk, bufferedNetworks);
424
+ if (transformed) controller.enqueue(transformed);
467
425
  }
468
426
  });
469
427
  }
@@ -488,6 +446,14 @@ function AgentStreamToAISDKTransformer() {
488
446
  const payload = transformedChunk.payload;
489
447
  const agentTransformed = transformAgent(payload, bufferedSteps);
490
448
  if (agentTransformed) controller.enqueue(agentTransformed);
449
+ } else if (transformedChunk.type === "tool-workflow") {
450
+ const payload = transformedChunk.payload;
451
+ const workflowChunk = transformWorkflow(payload, bufferedSteps, true);
452
+ if (workflowChunk) controller.enqueue(workflowChunk);
453
+ } else if (transformedChunk.type === "tool-network") {
454
+ const payload = transformedChunk.payload;
455
+ const networkChunk = transformNetwork(payload, bufferedSteps, true);
456
+ if (networkChunk) controller.enqueue(networkChunk);
491
457
  } else {
492
458
  controller.enqueue(transformedChunk);
493
459
  }
@@ -631,8 +597,278 @@ function transformAgent(payload, bufferedSteps) {
631
597
  }
632
598
  return null;
633
599
  }
634
- function toAISdkFormat(stream) {
635
- return stream.fullStream.pipeThrough(AgentStreamToAISDKTransformer());
600
+ function transformWorkflow(payload, bufferedWorkflows, isNested) {
601
+ switch (payload.type) {
602
+ case "workflow-start":
603
+ bufferedWorkflows.set(payload.runId, {
604
+ name: payload.payload.workflowId,
605
+ steps: {}
606
+ });
607
+ return {
608
+ type: isNested ? "data-tool-workflow" : "data-workflow",
609
+ id: payload.runId,
610
+ data: {
611
+ name: bufferedWorkflows.get(payload.runId).name,
612
+ status: "running",
613
+ steps: bufferedWorkflows.get(payload.runId).steps,
614
+ output: null
615
+ }
616
+ };
617
+ case "workflow-step-start": {
618
+ const current = bufferedWorkflows.get(payload.runId) || { name: "", steps: {} };
619
+ current.steps[payload.payload.id] = {
620
+ name: payload.payload.id,
621
+ status: payload.payload.status,
622
+ input: payload.payload.payload ?? null,
623
+ output: null
624
+ };
625
+ bufferedWorkflows.set(payload.runId, current);
626
+ return {
627
+ type: isNested ? "data-tool-workflow" : "data-workflow",
628
+ id: payload.runId,
629
+ data: {
630
+ name: current.name,
631
+ status: "running",
632
+ steps: current.steps,
633
+ output: null
634
+ }
635
+ };
636
+ }
637
+ case "workflow-step-result": {
638
+ const current = bufferedWorkflows.get(payload.runId);
639
+ if (!current) return null;
640
+ current.steps[payload.payload.id] = {
641
+ ...current.steps[payload.payload.id],
642
+ status: payload.payload.status,
643
+ output: payload.payload.output ?? null
644
+ };
645
+ return {
646
+ type: isNested ? "data-tool-workflow" : "data-workflow",
647
+ id: payload.runId,
648
+ data: {
649
+ name: current.name,
650
+ status: "running",
651
+ steps: current.steps,
652
+ output: null
653
+ }
654
+ };
655
+ }
656
+ case "workflow-finish": {
657
+ const current = bufferedWorkflows.get(payload.runId);
658
+ if (!current) return null;
659
+ return {
660
+ type: isNested ? "data-tool-workflow" : "data-workflow",
661
+ id: payload.runId,
662
+ data: {
663
+ name: current.name,
664
+ steps: current.steps,
665
+ output: payload.payload.output ?? null,
666
+ status: payload.payload.workflowStatus
667
+ }
668
+ };
669
+ }
670
+ default:
671
+ return null;
672
+ }
673
+ }
674
+ function transformNetwork(payload, bufferedNetworks, isNested) {
675
+ switch (payload.type) {
676
+ case "routing-agent-start": {
677
+ if (!bufferedNetworks.has(payload.payload.runId)) {
678
+ bufferedNetworks.set(payload.payload.runId, {
679
+ name: payload.payload.agentId,
680
+ steps: []
681
+ });
682
+ }
683
+ return {
684
+ type: isNested ? "data-tool-network" : "data-network",
685
+ id: payload.payload.runId,
686
+ data: {
687
+ name: bufferedNetworks.get(payload.payload.runId).name,
688
+ status: "running",
689
+ steps: bufferedNetworks.get(payload.payload.runId).steps,
690
+ output: null
691
+ }
692
+ };
693
+ }
694
+ case "agent-execution-start": {
695
+ const current = bufferedNetworks.get(payload.payload.runId) || { name: "", steps: [] };
696
+ current.steps.push({
697
+ name: payload.payload.agentId,
698
+ status: "running",
699
+ input: payload.payload.args || null,
700
+ output: null
701
+ });
702
+ bufferedNetworks.set(payload.payload.runId, current);
703
+ return {
704
+ type: isNested ? "data-tool-network" : "data-network",
705
+ id: payload.payload.runId,
706
+ data: {
707
+ name: current.name,
708
+ status: "running",
709
+ steps: current.steps,
710
+ output: null
711
+ }
712
+ };
713
+ }
714
+ case "workflow-execution-start": {
715
+ const current = bufferedNetworks.get(payload.payload.runId) || { name: "", steps: [] };
716
+ current.steps.push({
717
+ name: payload.payload.name,
718
+ status: "running",
719
+ input: payload.payload.args || null,
720
+ output: null
721
+ });
722
+ bufferedNetworks.set(payload.payload.runId, current);
723
+ return {
724
+ type: isNested ? "data-tool-network" : "data-network",
725
+ id: payload.payload.runId,
726
+ data: {
727
+ name: current.name,
728
+ status: "running",
729
+ steps: current.steps,
730
+ output: null
731
+ }
732
+ };
733
+ }
734
+ case "tool-execution-start": {
735
+ const current = bufferedNetworks.get(payload.payload.runId) || { name: "", steps: [] };
736
+ current.steps.push({
737
+ name: payload.payload.args?.toolName,
738
+ status: "running",
739
+ input: payload.payload.args?.args || null,
740
+ output: null
741
+ });
742
+ bufferedNetworks.set(payload.payload.runId, current);
743
+ return {
744
+ type: isNested ? "data-tool-network" : "data-network",
745
+ id: payload.payload.runId,
746
+ data: {
747
+ name: current.name,
748
+ status: "running",
749
+ steps: current.steps,
750
+ output: null
751
+ }
752
+ };
753
+ }
754
+ case "agent-execution-end": {
755
+ const current = bufferedNetworks.get(payload.runId);
756
+ if (!current) return null;
757
+ current.steps.push({
758
+ name: payload.payload.agentId,
759
+ status: "success",
760
+ input: null,
761
+ output: payload.payload.result
762
+ });
763
+ return {
764
+ type: isNested ? "data-tool-network" : "data-network",
765
+ id: payload.runId,
766
+ data: {
767
+ name: current.name,
768
+ status: "running",
769
+ steps: current.steps,
770
+ output: payload.payload.result ?? null
771
+ }
772
+ };
773
+ }
774
+ case "tool-execution-end": {
775
+ const current = bufferedNetworks.get(payload.runId);
776
+ if (!current) return null;
777
+ current.steps.push({
778
+ name: payload.payload.toolName,
779
+ status: "success",
780
+ input: null,
781
+ output: payload.payload.result
782
+ });
783
+ return {
784
+ type: isNested ? "data-tool-network" : "data-network",
785
+ id: payload.runId,
786
+ data: {
787
+ name: current.name,
788
+ status: "running",
789
+ steps: current.steps,
790
+ output: payload.payload.result ?? null
791
+ }
792
+ };
793
+ }
794
+ case "workflow-execution-end": {
795
+ const current = bufferedNetworks.get(payload.runId);
796
+ if (!current) return null;
797
+ current.steps.push({
798
+ name: payload.payload.name,
799
+ status: "success",
800
+ input: null,
801
+ output: payload.payload.result
802
+ });
803
+ return {
804
+ type: isNested ? "data-tool-network" : "data-network",
805
+ id: payload.runId,
806
+ data: {
807
+ name: current.name,
808
+ status: "running",
809
+ steps: current.steps,
810
+ output: payload.payload.result ?? null
811
+ }
812
+ };
813
+ }
814
+ case "routing-agent-end": {
815
+ const current = bufferedNetworks.get(payload.payload.runId);
816
+ if (!current) return null;
817
+ return {
818
+ type: isNested ? "data-tool-network" : "data-network",
819
+ id: payload.payload.runId,
820
+ data: {
821
+ name: current.name,
822
+ status: "finished",
823
+ steps: current.steps,
824
+ output: payload.payload?.result ?? null
825
+ }
826
+ };
827
+ }
828
+ case "network-execution-event-step-finish": {
829
+ const current = bufferedNetworks.get(payload.payload.runId);
830
+ if (!current) return null;
831
+ return {
832
+ type: isNested ? "data-tool-network" : "data-network",
833
+ id: payload.payload.runId,
834
+ data: {
835
+ name: current.name,
836
+ status: "finished",
837
+ steps: current.steps,
838
+ output: payload.payload?.result ?? null
839
+ }
840
+ };
841
+ }
842
+ case "network-execution-event-finish": {
843
+ const current = bufferedNetworks.get(payload.runId);
844
+ if (!current) return null;
845
+ return {
846
+ type: isNested ? "data-tool-network" : "data-network",
847
+ id: payload.runId,
848
+ data: {
849
+ name: current.name,
850
+ status: "finished",
851
+ steps: current.steps,
852
+ output: payload.payload?.result ?? null
853
+ }
854
+ };
855
+ }
856
+ default:
857
+ return null;
858
+ }
859
+ }
860
+
861
+ // src/to-ai-sdk-format.ts
862
+ function toAISdkFormat(stream, options = { from: "agent" }) {
863
+ const from = options?.from;
864
+ if (from === "workflow") {
865
+ return stream.pipeThrough(WorkflowStreamToAISDKTransformer());
866
+ }
867
+ if (from === "network") {
868
+ return stream.pipeThrough(AgentNetworkToAISDKTransformer());
869
+ }
870
+ const agentReadable = "fullStream" in stream ? stream.fullStream : stream;
871
+ return agentReadable.pipeThrough(AgentStreamToAISDKTransformer());
636
872
  }
637
873
 
638
874
  // src/chat-route.ts
@@ -740,6 +976,7 @@ function chatRoute({
740
976
  handler: async (c) => {
741
977
  const { messages, ...rest } = await c.req.json();
742
978
  const mastra = c.get("mastra");
979
+ const runtimeContext = c.get("runtimeContext");
743
980
  let agentToUse = agent;
744
981
  if (!agent) {
745
982
  const agentId = c.req.param("agentId");
@@ -750,6 +987,9 @@ function chatRoute({
750
987
  `Fixed agent ID was set together with an agentId path parameter. This can lead to unexpected behavior.`
751
988
  );
752
989
  }
990
+ if (runtimeContext && defaultOptions?.runtimeContext) {
991
+ mastra.getLogger()?.warn(`"runtimeContext" set in the route options will be overridden by the request's "runtimeContext".`);
992
+ }
753
993
  if (!agentToUse) {
754
994
  throw new Error("Agent ID is required");
755
995
  }
@@ -759,11 +999,12 @@ function chatRoute({
759
999
  }
760
1000
  const result = await agentObj.stream(messages, {
761
1001
  ...defaultOptions,
762
- ...rest
1002
+ ...rest,
1003
+ runtimeContext: runtimeContext || defaultOptions?.runtimeContext
763
1004
  });
764
1005
  const uiMessageStream = ai.createUIMessageStream({
765
1006
  execute: async ({ writer }) => {
766
- for await (const part of toAISdkFormat(result)) {
1007
+ for await (const part of toAISdkFormat(result, { from: "agent" })) {
767
1008
  writer.write(part);
768
1009
  }
769
1010
  }
@@ -774,9 +1015,186 @@ function chatRoute({
774
1015
  }
775
1016
  });
776
1017
  }
1018
+ function workflowRoute({
1019
+ path = "/api/workflows/:workflowId/stream",
1020
+ workflow
1021
+ }) {
1022
+ if (!workflow && !path.includes("/:workflowId")) {
1023
+ throw new Error("Path must include :workflowId to route to the correct workflow or pass the workflow explicitly");
1024
+ }
1025
+ return server.registerApiRoute(path, {
1026
+ method: "POST",
1027
+ openapi: {
1028
+ summary: "Stream a workflow in AI SDK format",
1029
+ description: "Starts a workflow run and streams events as AI SDK UIMessage chunks",
1030
+ tags: ["ai-sdk"],
1031
+ parameters: [
1032
+ {
1033
+ name: "workflowId",
1034
+ in: "path",
1035
+ required: true,
1036
+ description: "The ID of the workflow to stream",
1037
+ schema: { type: "string" }
1038
+ }
1039
+ ],
1040
+ requestBody: {
1041
+ required: true,
1042
+ content: {
1043
+ "application/json": {
1044
+ schema: {
1045
+ type: "object",
1046
+ properties: {
1047
+ inputData: { type: "object", additionalProperties: true },
1048
+ runtimeContext: { type: "object", additionalProperties: true },
1049
+ tracingOptions: { type: "object", additionalProperties: true }
1050
+ }
1051
+ }
1052
+ }
1053
+ }
1054
+ },
1055
+ responses: {
1056
+ "200": {
1057
+ description: "Workflow UIMessage event stream",
1058
+ content: {
1059
+ "text/plain": {
1060
+ schema: { type: "string", description: "SSE stream" }
1061
+ }
1062
+ }
1063
+ }
1064
+ }
1065
+ },
1066
+ handler: async (c) => {
1067
+ const { inputData, ...rest } = await c.req.json();
1068
+ const mastra = c.get("mastra");
1069
+ let workflowToUse = workflow;
1070
+ if (!workflow) {
1071
+ const workflowId = c.req.param("workflowId");
1072
+ workflowToUse = workflowId;
1073
+ }
1074
+ if (c.req.param("workflowId") && workflow) {
1075
+ mastra.getLogger()?.warn(
1076
+ `Fixed workflow ID was set together with a workflowId path parameter. This can lead to unexpected behavior.`
1077
+ );
1078
+ }
1079
+ if (!workflowToUse) {
1080
+ throw new Error("Workflow ID is required");
1081
+ }
1082
+ const workflowObj = mastra.getWorkflow(workflowToUse);
1083
+ if (!workflowObj) {
1084
+ throw new Error(`Workflow ${workflowToUse} not found`);
1085
+ }
1086
+ const run = await workflowObj.createRunAsync();
1087
+ const stream = run.streamVNext({ inputData, ...rest });
1088
+ const uiMessageStream = ai.createUIMessageStream({
1089
+ execute: async ({ writer }) => {
1090
+ for await (const part of toAISdkFormat(stream, { from: "workflow" })) {
1091
+ writer.write(part);
1092
+ }
1093
+ }
1094
+ });
1095
+ return ai.createUIMessageStreamResponse({ stream: uiMessageStream });
1096
+ }
1097
+ });
1098
+ }
1099
+ function networkRoute({
1100
+ path = "/network/:agentId",
1101
+ agent,
1102
+ defaultOptions
1103
+ }) {
1104
+ if (!agent && !path.includes("/:agentId")) {
1105
+ throw new Error("Path must include :agentId to route to the correct agent or pass the agent explicitly");
1106
+ }
1107
+ return server.registerApiRoute(path, {
1108
+ method: "POST",
1109
+ openapi: {
1110
+ summary: "Execute an agent network and stream AI SDK events",
1111
+ description: "Routes a request to an agent network and streams UIMessage chunks in AI SDK format",
1112
+ tags: ["ai-sdk"],
1113
+ parameters: [
1114
+ {
1115
+ name: "agentId",
1116
+ in: "path",
1117
+ required: true,
1118
+ description: "The ID of the routing agent to execute as a network",
1119
+ schema: { type: "string" }
1120
+ }
1121
+ ],
1122
+ requestBody: {
1123
+ required: true,
1124
+ content: {
1125
+ "application/json": {
1126
+ schema: {
1127
+ type: "object",
1128
+ properties: {
1129
+ messages: { type: "array", items: { type: "object" } },
1130
+ runtimeContext: { type: "object", additionalProperties: true },
1131
+ runId: { type: "string" },
1132
+ maxSteps: { type: "number" },
1133
+ threadId: { type: "string" },
1134
+ resourceId: { type: "string" },
1135
+ modelSettings: { type: "object", additionalProperties: true },
1136
+ telemetry: { type: "object", additionalProperties: true },
1137
+ tools: { type: "array", items: { type: "object" } }
1138
+ },
1139
+ required: ["messages"]
1140
+ }
1141
+ }
1142
+ }
1143
+ },
1144
+ responses: {
1145
+ "200": {
1146
+ description: "Streaming AI SDK UIMessage event stream for the agent network",
1147
+ content: { "text/plain": { schema: { type: "string", description: "SSE stream" } } }
1148
+ },
1149
+ "404": {
1150
+ description: "Agent not found",
1151
+ content: {
1152
+ "application/json": {
1153
+ schema: { type: "object", properties: { error: { type: "string" } } }
1154
+ }
1155
+ }
1156
+ }
1157
+ }
1158
+ },
1159
+ handler: async (c) => {
1160
+ const { messages, ...rest } = await c.req.json();
1161
+ const mastra = c.get("mastra");
1162
+ let agentToUse = agent;
1163
+ if (!agent) {
1164
+ const agentId = c.req.param("agentId");
1165
+ agentToUse = agentId;
1166
+ }
1167
+ if (c.req.param("agentId") && agent) {
1168
+ mastra.getLogger()?.warn(
1169
+ `Fixed agent ID was set together with an agentId path parameter. This can lead to unexpected behavior.`
1170
+ );
1171
+ }
1172
+ if (!agentToUse) {
1173
+ throw new Error("Agent ID is required");
1174
+ }
1175
+ const agentObj = mastra.getAgent(agentToUse);
1176
+ if (!agentObj) {
1177
+ throw new Error(`Agent ${agentToUse} not found`);
1178
+ }
1179
+ const result = await agentObj.network(messages, {
1180
+ ...defaultOptions,
1181
+ ...rest
1182
+ });
1183
+ const uiMessageStream = ai.createUIMessageStream({
1184
+ execute: async ({ writer }) => {
1185
+ for await (const part of toAISdkFormat(result, { from: "network" })) {
1186
+ writer.write(part);
1187
+ }
1188
+ }
1189
+ });
1190
+ return ai.createUIMessageStreamResponse({ stream: uiMessageStream });
1191
+ }
1192
+ });
1193
+ }
777
1194
 
778
- exports.WorkflowStreamToAISDKTransformer = WorkflowStreamToAISDKTransformer;
779
1195
  exports.chatRoute = chatRoute;
1196
+ exports.networkRoute = networkRoute;
780
1197
  exports.toAISdkFormat = toAISdkFormat;
1198
+ exports.workflowRoute = workflowRoute;
781
1199
  //# sourceMappingURL=index.cjs.map
782
1200
  //# sourceMappingURL=index.cjs.map