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