@mastra/core 1.1.0 → 1.2.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.
Files changed (205) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/dist/agent/agent.d.ts.map +1 -1
  3. package/dist/agent/index.cjs +8 -8
  4. package/dist/agent/index.js +1 -1
  5. package/dist/{chunk-RYVRCT7Z.cjs → chunk-22EV7GMK.cjs} +55 -19
  6. package/dist/chunk-22EV7GMK.cjs.map +1 -0
  7. package/dist/chunk-2QXNHEDL.js +8 -0
  8. package/dist/chunk-2QXNHEDL.js.map +1 -0
  9. package/dist/{chunk-OSIE5L6N.js → chunk-66BWIF4S.js} +7 -7
  10. package/dist/{chunk-OSIE5L6N.js.map → chunk-66BWIF4S.js.map} +1 -1
  11. package/dist/{chunk-IDDFKLI7.js → chunk-AC63Y6KP.js} +865 -1471
  12. package/dist/chunk-AC63Y6KP.js.map +1 -0
  13. package/dist/{chunk-4QJBNJI4.cjs → chunk-BLXWTBLL.cjs} +168 -168
  14. package/dist/{chunk-4QJBNJI4.cjs.map → chunk-BLXWTBLL.cjs.map} +1 -1
  15. package/dist/{chunk-KPIJA2R5.js → chunk-CILDTRXD.js} +2 -2
  16. package/dist/{chunk-KPIJA2R5.js.map → chunk-CILDTRXD.js.map} +1 -1
  17. package/dist/{chunk-OW7H7G5N.js → chunk-DWD5DB6W.js} +4 -4
  18. package/dist/{chunk-OW7H7G5N.js.map → chunk-DWD5DB6W.js.map} +1 -1
  19. package/dist/{chunk-MGOFRL36.cjs → chunk-EYUXOOSQ.cjs} +106 -39
  20. package/dist/chunk-EYUXOOSQ.cjs.map +1 -0
  21. package/dist/{chunk-FVVQY6UU.js → chunk-FAJYC6PA.js} +375 -23
  22. package/dist/chunk-FAJYC6PA.js.map +1 -0
  23. package/dist/{chunk-YQMDMIP6.js → chunk-FYMM4PKR.js} +1337 -312
  24. package/dist/chunk-FYMM4PKR.js.map +1 -0
  25. package/dist/{chunk-FAM74XPO.js → chunk-G6E3QNJC.js} +3741 -2912
  26. package/dist/chunk-G6E3QNJC.js.map +1 -0
  27. package/dist/{chunk-YSFYUEEG.cjs → chunk-I6PWV32C.cjs} +42 -10
  28. package/dist/chunk-I6PWV32C.cjs.map +1 -0
  29. package/dist/{chunk-VNGQXHUE.cjs → chunk-MCI7M6AT.cjs} +7 -7
  30. package/dist/{chunk-VNGQXHUE.cjs.map → chunk-MCI7M6AT.cjs.map} +1 -1
  31. package/dist/{chunk-4KQEQ4NM.js → chunk-NS33UC72.js} +55 -20
  32. package/dist/chunk-NS33UC72.js.map +1 -0
  33. package/dist/{chunk-4PERRFZD.cjs → chunk-OAOMKZXU.cjs} +1378 -353
  34. package/dist/chunk-OAOMKZXU.cjs.map +1 -0
  35. package/dist/{chunk-4ACKGMN2.cjs → chunk-ODNSWEMV.cjs} +7 -7
  36. package/dist/{chunk-4ACKGMN2.cjs.map → chunk-ODNSWEMV.cjs.map} +1 -1
  37. package/dist/{chunk-H4C5NORS.js → chunk-OQPAOUDS.js} +36 -5
  38. package/dist/chunk-OQPAOUDS.js.map +1 -0
  39. package/dist/{chunk-VAJRNUEF.js → chunk-SPVI7HCP.js} +76 -76
  40. package/dist/chunk-SPVI7HCP.js.map +1 -0
  41. package/dist/{chunk-ENLG644T.cjs → chunk-STNSGW7W.cjs} +1514 -2120
  42. package/dist/chunk-STNSGW7W.cjs.map +1 -0
  43. package/dist/{chunk-FZZI2V2T.js → chunk-USHB3SPM.js} +4 -4
  44. package/dist/{chunk-FZZI2V2T.js.map → chunk-USHB3SPM.js.map} +1 -1
  45. package/dist/{chunk-4NGQR4ML.cjs → chunk-UZL4H5P2.cjs} +5092 -4247
  46. package/dist/chunk-UZL4H5P2.cjs.map +1 -0
  47. package/dist/{chunk-DOVI2C5F.cjs → chunk-VZXYBFCX.cjs} +8 -8
  48. package/dist/{chunk-DOVI2C5F.cjs.map → chunk-VZXYBFCX.cjs.map} +1 -1
  49. package/dist/{chunk-4FUG3CNY.js → chunk-W3AQUG66.js} +3 -3
  50. package/dist/{chunk-4FUG3CNY.js.map → chunk-W3AQUG66.js.map} +1 -1
  51. package/dist/{chunk-SLMSUZBA.cjs → chunk-W57QS6F6.cjs} +400 -46
  52. package/dist/chunk-W57QS6F6.cjs.map +1 -0
  53. package/dist/{chunk-BG6DCMO2.js → chunk-XS2MED4Y.js} +105 -38
  54. package/dist/chunk-XS2MED4Y.js.map +1 -0
  55. package/dist/{chunk-HR67B4UM.cjs → chunk-XVHK5IAO.cjs} +15 -15
  56. package/dist/{chunk-HR67B4UM.cjs.map → chunk-XVHK5IAO.cjs.map} +1 -1
  57. package/dist/{chunk-RIPKI7ON.cjs → chunk-Y2SVKUOQ.cjs} +2 -2
  58. package/dist/{chunk-RIPKI7ON.cjs.map → chunk-Y2SVKUOQ.cjs.map} +1 -1
  59. package/dist/{chunk-LJOQ7WYC.cjs → chunk-ZCBG4ZQT.cjs} +4 -2
  60. package/dist/chunk-ZCBG4ZQT.cjs.map +1 -0
  61. package/dist/docs/README.md +2 -2
  62. package/dist/docs/SKILL.md +3 -3
  63. package/dist/docs/SOURCE_MAP.json +280 -270
  64. package/dist/docs/agents/01-overview.md +6 -2
  65. package/dist/docs/agents/02-using-tools.md +1 -0
  66. package/dist/docs/agents/06-processors.md +87 -1
  67. package/dist/docs/evals/01-overview.md +5 -5
  68. package/dist/docs/mcp/01-overview.md +2 -2
  69. package/dist/docs/observability/01-overview.md +1 -1
  70. package/dist/docs/observability/03-overview.md +3 -3
  71. package/dist/docs/processors/01-reference.md +100 -1
  72. package/dist/docs/rag/01-overview.md +1 -1
  73. package/dist/docs/rag/03-vector-databases.md +10 -1
  74. package/dist/docs/server/04-request-context.md +168 -0
  75. package/dist/docs/tools-mcp/01-mcp-overview.md +2 -2
  76. package/dist/docs/voice/01-overview.md +1 -1
  77. package/dist/docs/workflows/01-overview.md +9 -5
  78. package/dist/docs/workspace/01-overview.md +38 -31
  79. package/dist/docs/workspace/02-filesystem.md +9 -11
  80. package/dist/docs/workspace/03-sandbox.md +8 -10
  81. package/dist/docs/workspace/04-skills.md +24 -25
  82. package/dist/docs/workspace/05-search.md +34 -31
  83. package/dist/docs/workspace/06-reference.md +24 -149
  84. package/dist/evals/index.cjs +20 -20
  85. package/dist/evals/index.js +3 -3
  86. package/dist/evals/scoreTraces/index.cjs +5 -5
  87. package/dist/evals/scoreTraces/index.js +2 -2
  88. package/dist/index.cjs +2 -2
  89. package/dist/index.js +1 -1
  90. package/dist/llm/index.cjs +15 -15
  91. package/dist/llm/index.js +5 -5
  92. package/dist/llm/model/gateways/models-dev.d.ts.map +1 -1
  93. package/dist/llm/model/provider-types.generated.d.ts +44 -15
  94. package/dist/loop/index.cjs +12 -12
  95. package/dist/loop/index.js +1 -1
  96. package/dist/loop/network/index.d.ts.map +1 -1
  97. package/dist/mastra/index.cjs +2 -2
  98. package/dist/mastra/index.js +1 -1
  99. package/dist/memory/index.cjs +11 -11
  100. package/dist/memory/index.js +1 -1
  101. package/dist/memory/memory.d.ts +6 -0
  102. package/dist/memory/memory.d.ts.map +1 -1
  103. package/dist/models-dev-2HBSVUOS.js +3 -0
  104. package/dist/{models-dev-B2ESSYRH.js.map → models-dev-2HBSVUOS.js.map} +1 -1
  105. package/dist/models-dev-SOIECXXQ.cjs +12 -0
  106. package/dist/{models-dev-IQ54YHQ4.cjs.map → models-dev-SOIECXXQ.cjs.map} +1 -1
  107. package/dist/netlify-SSWMYSAX.js +3 -0
  108. package/dist/{netlify-KPCOQ52P.js.map → netlify-SSWMYSAX.js.map} +1 -1
  109. package/dist/netlify-TXZZCT6N.cjs +12 -0
  110. package/dist/{netlify-D6LNGTDH.cjs.map → netlify-TXZZCT6N.cjs.map} +1 -1
  111. package/dist/processors/index.cjs +44 -40
  112. package/dist/processors/index.js +1 -1
  113. package/dist/processors/processors/index.d.ts +1 -0
  114. package/dist/processors/processors/index.d.ts.map +1 -1
  115. package/dist/processors/processors/tool-search.d.ts +176 -0
  116. package/dist/processors/processors/tool-search.d.ts.map +1 -0
  117. package/dist/provider-registry-K5L4DHRK.js +3 -0
  118. package/dist/{provider-registry-B3CGX3OF.js.map → provider-registry-K5L4DHRK.js.map} +1 -1
  119. package/dist/provider-registry-ML2VWWLB.cjs +40 -0
  120. package/dist/{provider-registry-CHV3DFFA.cjs.map → provider-registry-ML2VWWLB.cjs.map} +1 -1
  121. package/dist/provider-registry.json +101 -34
  122. package/dist/relevance/index.cjs +3 -3
  123. package/dist/relevance/index.js +1 -1
  124. package/dist/storage/constants.cjs +16 -16
  125. package/dist/storage/constants.js +1 -1
  126. package/dist/storage/domains/workflows/inmemory.d.ts.map +1 -1
  127. package/dist/storage/index.cjs +101 -101
  128. package/dist/storage/index.js +2 -2
  129. package/dist/storage/types.d.ts +4 -0
  130. package/dist/storage/types.d.ts.map +1 -1
  131. package/dist/stream/aisdk/v5/compat/prepare-tools.d.ts.map +1 -1
  132. package/dist/stream/index.cjs +8 -8
  133. package/dist/stream/index.js +1 -1
  134. package/dist/tool-loop-agent/index.cjs +4 -4
  135. package/dist/tool-loop-agent/index.js +1 -1
  136. package/dist/vector/index.cjs +7 -7
  137. package/dist/vector/index.js +1 -1
  138. package/dist/workflows/constants.cjs +7 -3
  139. package/dist/workflows/constants.d.ts +1 -0
  140. package/dist/workflows/constants.d.ts.map +1 -1
  141. package/dist/workflows/constants.js +1 -1
  142. package/dist/workflows/default.d.ts.map +1 -1
  143. package/dist/workflows/evented/execution-engine.d.ts +8 -1
  144. package/dist/workflows/evented/execution-engine.d.ts.map +1 -1
  145. package/dist/workflows/evented/helpers.d.ts +68 -0
  146. package/dist/workflows/evented/helpers.d.ts.map +1 -0
  147. package/dist/workflows/evented/index.cjs +10 -10
  148. package/dist/workflows/evented/index.js +1 -1
  149. package/dist/workflows/evented/step-executor.d.ts +9 -17
  150. package/dist/workflows/evented/step-executor.d.ts.map +1 -1
  151. package/dist/workflows/evented/types.d.ts +29 -0
  152. package/dist/workflows/evented/types.d.ts.map +1 -0
  153. package/dist/workflows/evented/workflow-event-processor/index.d.ts +12 -3
  154. package/dist/workflows/evented/workflow-event-processor/index.d.ts.map +1 -1
  155. package/dist/workflows/evented/workflow-event-processor/loop.d.ts +2 -2
  156. package/dist/workflows/evented/workflow-event-processor/loop.d.ts.map +1 -1
  157. package/dist/workflows/evented/workflow-event-processor/parallel.d.ts +2 -2
  158. package/dist/workflows/evented/workflow-event-processor/parallel.d.ts.map +1 -1
  159. package/dist/workflows/evented/workflow-event-processor/sleep.d.ts.map +1 -1
  160. package/dist/workflows/evented/workflow-event-processor/utils.d.ts.map +1 -1
  161. package/dist/workflows/evented/workflow.d.ts +54 -3
  162. package/dist/workflows/evented/workflow.d.ts.map +1 -1
  163. package/dist/workflows/index.cjs +28 -24
  164. package/dist/workflows/index.js +1 -1
  165. package/dist/workflows/utils.d.ts +27 -0
  166. package/dist/workflows/utils.d.ts.map +1 -1
  167. package/dist/workflows/workflow.d.ts.map +1 -1
  168. package/dist/workspace/filesystem/local-filesystem.d.ts +3 -0
  169. package/dist/workspace/filesystem/local-filesystem.d.ts.map +1 -1
  170. package/dist/workspace/index.cjs +32 -32
  171. package/dist/workspace/index.js +1 -1
  172. package/dist/workspace/lifecycle.d.ts +2 -0
  173. package/dist/workspace/lifecycle.d.ts.map +1 -1
  174. package/dist/workspace/sandbox/local-sandbox.d.ts +1 -2
  175. package/dist/workspace/sandbox/local-sandbox.d.ts.map +1 -1
  176. package/dist/workspace/sandbox/sandbox.d.ts +0 -2
  177. package/dist/workspace/sandbox/sandbox.d.ts.map +1 -1
  178. package/dist/workspace/search/bm25.d.ts +2 -0
  179. package/dist/workspace/search/bm25.d.ts.map +1 -1
  180. package/package.json +4 -4
  181. package/src/llm/model/provider-types.generated.d.ts +44 -15
  182. package/dist/chunk-4KQEQ4NM.js.map +0 -1
  183. package/dist/chunk-4NGQR4ML.cjs.map +0 -1
  184. package/dist/chunk-4PERRFZD.cjs.map +0 -1
  185. package/dist/chunk-BG6DCMO2.js.map +0 -1
  186. package/dist/chunk-ENLG644T.cjs.map +0 -1
  187. package/dist/chunk-FAM74XPO.js.map +0 -1
  188. package/dist/chunk-FVVQY6UU.js.map +0 -1
  189. package/dist/chunk-H4C5NORS.js.map +0 -1
  190. package/dist/chunk-IDDFKLI7.js.map +0 -1
  191. package/dist/chunk-LJOQ7WYC.cjs.map +0 -1
  192. package/dist/chunk-MGOFRL36.cjs.map +0 -1
  193. package/dist/chunk-RYVRCT7Z.cjs.map +0 -1
  194. package/dist/chunk-SLMSUZBA.cjs.map +0 -1
  195. package/dist/chunk-VAJRNUEF.js.map +0 -1
  196. package/dist/chunk-YEQB4VUA.js +0 -7
  197. package/dist/chunk-YEQB4VUA.js.map +0 -1
  198. package/dist/chunk-YQMDMIP6.js.map +0 -1
  199. package/dist/chunk-YSFYUEEG.cjs.map +0 -1
  200. package/dist/models-dev-B2ESSYRH.js +0 -3
  201. package/dist/models-dev-IQ54YHQ4.cjs +0 -12
  202. package/dist/netlify-D6LNGTDH.cjs +0 -12
  203. package/dist/netlify-KPCOQ52P.js +0 -3
  204. package/dist/provider-registry-B3CGX3OF.js +0 -3
  205. package/dist/provider-registry-CHV3DFFA.cjs +0 -40
@@ -1,14 +1,17 @@
1
- import { validateStepInput, createDeprecationProxy, EventEmitterPubSub, getStepResult, validateStepSuspendData, runCountDeprecationMessage, createTimeTravelExecutionParams, validateStepResumeData, Workflow, ProcessorStepOutputSchema, ProcessorStepSchema, Run, ExecutionEngine, hydrateSerializedStepErrors, Agent, TripWire, ProcessorRunner } from './chunk-FVVQY6UU.js';
2
- import { STREAM_FORMAT_SYMBOL, PUBSUB_SYMBOL } from './chunk-YEQB4VUA.js';
1
+ import { validateStepInput, createDeprecationProxy, getStepResult, validateStepSuspendData, runCountDeprecationMessage, TripWire, createTimeTravelExecutionParams, validateStepResumeData, Workflow, isSupportedLanguageModel, ProcessorStepOutputSchema, ProcessorStepSchema, Run, WorkflowRunOutput, ExecutionEngine, cleanStepResult, hydrateSerializedStepErrors, Agent, ProcessorRunner } from './chunk-FAJYC6PA.js';
2
+ import { STREAM_FORMAT_SYMBOL, PUBSUB_SYMBOL } from './chunk-2QXNHEDL.js';
3
+ import { createPendingMarker } from './chunk-OQPAOUDS.js';
3
4
  import { MessageList } from './chunk-HIP5W3LZ.js';
4
5
  import { getErrorFromUnknown, MastraError } from './chunk-FJEVLHJT.js';
6
+ import { ToolStream } from './chunk-DD2VNRQM.js';
5
7
  import { Tool } from './chunk-IW3BNL7A.js';
6
8
  import { RequestContext } from './chunk-CCLV5CAA.js';
7
9
  import { MastraBase } from './chunk-JIT2OY3X.js';
8
10
  import { RegisteredLogger } from './chunk-X2WMFSPB.js';
9
- import EventEmitter from 'events';
10
11
  import { randomUUID } from 'crypto';
12
+ import { ReadableStream } from 'stream/web';
11
13
  import { z } from 'zod';
14
+ import EventEmitter from 'events';
12
15
 
13
16
  var StepExecutor = class extends MastraBase {
14
17
  mastra;
@@ -19,6 +22,26 @@ var StepExecutor = class extends MastraBase {
19
22
  __registerMastra(mastra) {
20
23
  this.mastra = mastra;
21
24
  }
25
+ /**
26
+ * Creates an output writer function that publishes chunks to the workflow event stream.
27
+ * @param runId - The workflow run ID
28
+ * @returns An async function that writes chunks to the pubsub
29
+ */
30
+ createOutputWriter(runId) {
31
+ return async (chunk) => {
32
+ try {
33
+ if (this.mastra?.pubsub) {
34
+ await this.mastra.pubsub.publish(`workflow.events.v2.${runId}`, {
35
+ type: "watch",
36
+ runId,
37
+ data: chunk
38
+ });
39
+ }
40
+ } catch (err) {
41
+ this.logger.debug("Failed to publish workflow watch event", { runId, error: err });
42
+ }
43
+ };
44
+ }
22
45
  async execute(params) {
23
46
  const { step, stepResults, runId, requestContext, retryCount = 0, perStep } = params;
24
47
  const abortController = params.abortController ?? new AbortController();
@@ -36,9 +59,12 @@ var StepExecutor = class extends MastraBase {
36
59
  payload: (typeof params.foreachIdx === "number" ? params.input : inputData) ?? {}
37
60
  };
38
61
  if (params.resumeData) {
39
- delete stepInfo.suspendPayload?.["__workflow_meta"];
40
62
  stepInfo.resumePayload = params.resumeData;
41
63
  stepInfo.resumedAt = Date.now();
64
+ if (stepInfo.suspendPayload && "__workflow_meta" in stepInfo.suspendPayload) {
65
+ const { __workflow_meta, ...userSuspendPayload } = stepInfo.suspendPayload;
66
+ stepInfo.suspendPayload = userSuspendPayload;
67
+ }
42
68
  }
43
69
  let suspendDataToUse = params.stepResults[step.id]?.status === "suspended" ? params.stepResults[step.id]?.suspendPayload : void 0;
44
70
  if (suspendDataToUse && "__workflow_meta" in suspendDataToUse) {
@@ -49,6 +75,8 @@ var StepExecutor = class extends MastraBase {
49
75
  if (validationError) {
50
76
  throw validationError;
51
77
  }
78
+ const callId = randomUUID();
79
+ const outputWriter = this.createOutputWriter(runId);
52
80
  const stepOutput = await step.execute(
53
81
  createDeprecationProxy(
54
82
  {
@@ -58,15 +86,15 @@ var StepExecutor = class extends MastraBase {
58
86
  requestContext,
59
87
  inputData,
60
88
  state: params.state,
61
- setState: async (state) => {
62
- params.state = state;
89
+ setState: async (newState) => {
90
+ Object.assign(params.state, newState);
63
91
  },
64
92
  retryCount,
65
93
  resumeData: params.resumeData,
66
94
  suspendData: suspendDataToUse,
67
95
  getInitData: () => stepResults?.input,
68
96
  getStepResult: getStepResult.bind(this, stepResults),
69
- suspend: async (suspendPayload) => {
97
+ suspend: async (suspendPayload, suspendOptions) => {
70
98
  const { suspendData, validationError: validationError2 } = await validateStepSuspendData({
71
99
  suspendData: suspendPayload,
72
100
  step,
@@ -75,17 +103,44 @@ var StepExecutor = class extends MastraBase {
75
103
  if (validationError2) {
76
104
  throw validationError2;
77
105
  }
78
- suspended = { payload: { ...suspendData, __workflow_meta: { runId, path: [step.id] } } };
106
+ const resumeLabels = {};
107
+ if (suspendOptions?.resumeLabel) {
108
+ const labels = Array.isArray(suspendOptions.resumeLabel) ? suspendOptions.resumeLabel : [suspendOptions.resumeLabel];
109
+ for (const label of labels) {
110
+ resumeLabels[label] = {
111
+ stepId: step.id,
112
+ foreachIndex: params.foreachIdx
113
+ };
114
+ }
115
+ }
116
+ suspended = {
117
+ payload: {
118
+ ...suspendData,
119
+ __workflow_meta: {
120
+ runId,
121
+ path: [step.id],
122
+ foreachIndex: params.foreachIdx,
123
+ resumeLabels: Object.keys(resumeLabels).length > 0 ? resumeLabels : void 0
124
+ }
125
+ }
126
+ };
79
127
  },
80
128
  bail: (result) => {
81
129
  bailed = { payload: result };
82
130
  },
83
- // TODO
84
- writer: void 0,
131
+ writer: new ToolStream(
132
+ {
133
+ prefix: "workflow-step",
134
+ callId,
135
+ name: step.id,
136
+ runId
137
+ },
138
+ outputWriter
139
+ ),
85
140
  abort: () => {
86
141
  abortController?.abort();
87
142
  },
88
- [PUBSUB_SYMBOL]: this.mastra?.pubsub ?? new EventEmitterPubSub(params.emitter),
143
+ [PUBSUB_SYMBOL]: this.mastra.pubsub,
89
144
  [STREAM_FORMAT_SYMBOL]: void 0,
90
145
  // TODO
91
146
  engine: {},
@@ -109,7 +164,8 @@ var StepExecutor = class extends MastraBase {
109
164
  ...stepInfo,
110
165
  status: "suspended",
111
166
  suspendedAt: endedAt,
112
- ...stepOutput ? { suspendOutput: stepOutput } : {}
167
+ ...stepOutput ? { suspendOutput: stepOutput } : {},
168
+ __state: params.state
113
169
  };
114
170
  if (suspended.payload) {
115
171
  finalResult.suspendPayload = suspended.payload;
@@ -120,19 +176,22 @@ var StepExecutor = class extends MastraBase {
120
176
  // @ts-expect-error - bailed status not in type
121
177
  status: "bailed",
122
178
  endedAt,
123
- output: bailed.payload
179
+ output: bailed.payload,
180
+ __state: params.state
124
181
  };
125
182
  } else if (nestedWflowStepPaused) {
126
183
  finalResult = {
127
184
  ...stepInfo,
128
- status: "paused"
185
+ status: "paused",
186
+ __state: params.state
129
187
  };
130
188
  } else {
131
189
  finalResult = {
132
190
  ...stepInfo,
133
191
  status: "success",
134
192
  endedAt,
135
- output: stepOutput
193
+ output: stepOutput,
194
+ __state: params.state
136
195
  };
137
196
  }
138
197
  return finalResult;
@@ -146,14 +205,22 @@ var StepExecutor = class extends MastraBase {
146
205
  ...stepInfo,
147
206
  status: "failed",
148
207
  endedAt,
149
- error: errorInstance
208
+ error: errorInstance,
209
+ // Preserve TripWire data as plain object for proper serialization
210
+ // Important: Check `error` not `errorInstance` because getErrorFromUnknown
211
+ // converts the error and loses the prototype chain
212
+ tripwire: error instanceof TripWire ? {
213
+ reason: error.message,
214
+ retry: error.options?.retry,
215
+ metadata: error.options?.metadata,
216
+ processorId: error.processorId
217
+ } : void 0
150
218
  };
151
219
  }
152
220
  }
153
221
  async evaluateConditions(params) {
154
222
  const { step, stepResults, runId, requestContext, retryCount = 0 } = params;
155
223
  const abortController = params.abortController ?? new AbortController();
156
- const ee = new EventEmitter();
157
224
  const results = await Promise.all(
158
225
  step.conditions.map((condition) => {
159
226
  try {
@@ -168,7 +235,6 @@ var StepExecutor = class extends MastraBase {
168
235
  resumeData: params.resumeData,
169
236
  abortController,
170
237
  stepResults,
171
- emitter: ee,
172
238
  iterationCount: 0
173
239
  });
174
240
  } catch (e) {
@@ -194,11 +260,12 @@ var StepExecutor = class extends MastraBase {
194
260
  stepResults,
195
261
  state,
196
262
  requestContext,
197
- emitter,
198
263
  abortController,
199
264
  retryCount = 0,
200
265
  iterationCount
201
266
  }) {
267
+ const callId = randomUUID();
268
+ const outputWriter = this.createOutputWriter(runId);
202
269
  return condition(
203
270
  createDeprecationProxy(
204
271
  {
@@ -215,12 +282,19 @@ var StepExecutor = class extends MastraBase {
215
282
  bail: (_result) => {
216
283
  throw new Error("Not implemented");
217
284
  },
218
- // TODO
219
- writer: void 0,
285
+ writer: new ToolStream(
286
+ {
287
+ prefix: "workflow-step",
288
+ callId,
289
+ name: "condition",
290
+ runId
291
+ },
292
+ outputWriter
293
+ ),
220
294
  abort: () => {
221
295
  abortController?.abort();
222
296
  },
223
- [PUBSUB_SYMBOL]: this.mastra?.pubsub ?? new EventEmitterPubSub(emitter),
297
+ [PUBSUB_SYMBOL]: this.mastra.pubsub,
224
298
  [STREAM_FORMAT_SYMBOL]: void 0,
225
299
  // TODO
226
300
  engine: {},
@@ -239,8 +313,8 @@ var StepExecutor = class extends MastraBase {
239
313
  }
240
314
  async resolveSleep(params) {
241
315
  const { step, stepResults, runId, requestContext, retryCount = 0 } = params;
316
+ const currentState = params.state ?? stepResults?.__state ?? {};
242
317
  const abortController = params.abortController ?? new AbortController();
243
- const ee = new EventEmitter();
244
318
  if (step.duration) {
245
319
  return step.duration;
246
320
  }
@@ -248,6 +322,8 @@ var StepExecutor = class extends MastraBase {
248
322
  return 0;
249
323
  }
250
324
  try {
325
+ const callId = randomUUID();
326
+ const outputWriter = this.createOutputWriter(runId);
251
327
  return await step.fn(
252
328
  createDeprecationProxy(
253
329
  {
@@ -256,9 +332,9 @@ var StepExecutor = class extends MastraBase {
256
332
  mastra: this.mastra,
257
333
  requestContext,
258
334
  inputData: params.input,
259
- // TODO: implement state
260
- state: {},
261
- setState: async (_state) => {
335
+ state: currentState,
336
+ setState: async (newState) => {
337
+ Object.assign(currentState, newState);
262
338
  },
263
339
  retryCount,
264
340
  resumeData: params.resumeData,
@@ -273,9 +349,16 @@ var StepExecutor = class extends MastraBase {
273
349
  abort: () => {
274
350
  abortController?.abort();
275
351
  },
276
- // TODO
277
- writer: void 0,
278
- [PUBSUB_SYMBOL]: this.mastra?.pubsub ?? new EventEmitterPubSub(ee),
352
+ writer: new ToolStream(
353
+ {
354
+ prefix: "workflow-step",
355
+ callId,
356
+ name: step.id,
357
+ runId
358
+ },
359
+ outputWriter
360
+ ),
361
+ [PUBSUB_SYMBOL]: this.mastra.pubsub,
279
362
  [STREAM_FORMAT_SYMBOL]: void 0,
280
363
  // TODO
281
364
  engine: {},
@@ -297,8 +380,8 @@ var StepExecutor = class extends MastraBase {
297
380
  }
298
381
  async resolveSleepUntil(params) {
299
382
  const { step, stepResults, runId, requestContext, retryCount = 0 } = params;
383
+ const currentState = params.state ?? stepResults?.__state ?? {};
300
384
  const abortController = params.abortController ?? new AbortController();
301
- const ee = new EventEmitter();
302
385
  if (step.date) {
303
386
  return step.date.getTime() - Date.now();
304
387
  }
@@ -306,6 +389,8 @@ var StepExecutor = class extends MastraBase {
306
389
  return 0;
307
390
  }
308
391
  try {
392
+ const callId = randomUUID();
393
+ const outputWriter = this.createOutputWriter(runId);
309
394
  const result = await step.fn(
310
395
  createDeprecationProxy(
311
396
  {
@@ -314,9 +399,9 @@ var StepExecutor = class extends MastraBase {
314
399
  mastra: this.mastra,
315
400
  requestContext,
316
401
  inputData: params.input,
317
- // TODO: implement state
318
- state: {},
319
- setState: async (_state) => {
402
+ state: currentState,
403
+ setState: async (newState) => {
404
+ Object.assign(currentState, newState);
320
405
  },
321
406
  retryCount,
322
407
  resumeData: params.resumeData,
@@ -331,9 +416,16 @@ var StepExecutor = class extends MastraBase {
331
416
  abort: () => {
332
417
  abortController?.abort();
333
418
  },
334
- // TODO
335
- writer: void 0,
336
- [PUBSUB_SYMBOL]: this.mastra?.pubsub ?? new EventEmitterPubSub(ee),
419
+ writer: new ToolStream(
420
+ {
421
+ prefix: "workflow-step",
422
+ callId,
423
+ name: step.id,
424
+ runId
425
+ },
426
+ outputWriter
427
+ ),
428
+ [PUBSUB_SYMBOL]: this.mastra.pubsub,
337
429
  [STREAM_FORMAT_SYMBOL]: void 0,
338
430
  // TODO
339
431
  engine: {},
@@ -356,6 +448,32 @@ var StepExecutor = class extends MastraBase {
356
448
  }
357
449
  };
358
450
 
451
+ // src/workflows/evented/helpers.ts
452
+ function isTripwireChunk(chunk) {
453
+ return chunk !== null && typeof chunk === "object" && "type" in chunk && chunk.type === "tripwire" && "payload" in chunk;
454
+ }
455
+ function createTripWireFromChunk(chunk) {
456
+ const { payload } = chunk;
457
+ return new TripWire(
458
+ payload.reason || "Agent tripwire triggered",
459
+ {
460
+ retry: payload.retry,
461
+ metadata: payload.metadata
462
+ },
463
+ payload.processorId
464
+ );
465
+ }
466
+ function getTextDeltaFromChunk(chunk, isV2Model) {
467
+ if (chunk.type !== "text-delta") {
468
+ return void 0;
469
+ }
470
+ return isV2Model ? chunk.payload?.text : chunk.textDelta;
471
+ }
472
+ function resolveCurrentState(params) {
473
+ const { stepResult, stepResults, state } = params;
474
+ return stepResult?.__state ?? stepResults?.__state ?? state ?? {};
475
+ }
476
+
359
477
  // src/events/processor.ts
360
478
  var EventProcessor = class {
361
479
  mastra;
@@ -366,6 +484,8 @@ var EventProcessor = class {
366
484
  this.mastra = mastra;
367
485
  }
368
486
  };
487
+
488
+ // src/workflows/evented/workflow-event-processor/loop.ts
369
489
  async function processWorkflowLoop({
370
490
  workflowId,
371
491
  prevResult,
@@ -378,30 +498,31 @@ async function processWorkflowLoop({
378
498
  parentWorkflow,
379
499
  requestContext,
380
500
  retryCount = 0,
381
- perStep
501
+ perStep,
502
+ state,
503
+ outputOptions
382
504
  }, {
383
505
  pubsub,
384
506
  stepExecutor,
385
507
  step,
386
508
  stepResult
387
509
  }) {
510
+ const currentState = resolveCurrentState({ stepResult, stepResults, state });
511
+ const reqContext = new RequestContext(Object.entries(requestContext ?? {}));
512
+ const prevIterationCount = stepResults[step.step?.id]?.metadata?.iterationCount ?? 0;
513
+ const iterationCount = prevIterationCount + 1;
388
514
  const loopCondition = await stepExecutor.evaluateCondition({
389
515
  workflowId,
390
516
  condition: step.condition,
391
517
  runId,
392
518
  stepResults,
393
- // TODO: implement state
394
- state: {},
395
- emitter: new EventEmitter(),
396
- // TODO
397
- requestContext: new RequestContext(),
398
- // TODO
519
+ state: currentState,
520
+ requestContext: reqContext,
399
521
  inputData: prevResult?.status === "success" ? prevResult.output : void 0,
400
522
  resumeData,
401
523
  abortController: new AbortController(),
402
524
  retryCount,
403
- iterationCount: 0
404
- //TODO: implement
525
+ iterationCount
405
526
  });
406
527
  if (step.loopType === "dountil") {
407
528
  if (loopCondition) {
@@ -419,7 +540,9 @@ async function processWorkflowLoop({
419
540
  resumeData,
420
541
  activeSteps,
421
542
  requestContext,
422
- perStep
543
+ perStep,
544
+ state: currentState,
545
+ outputOptions
423
546
  }
424
547
  });
425
548
  } else {
@@ -433,6 +556,8 @@ async function processWorkflowLoop({
433
556
  executionPath,
434
557
  resumeSteps,
435
558
  stepResults,
559
+ state: currentState,
560
+ outputOptions,
436
561
  prevResult: stepResult,
437
562
  resumeData,
438
563
  activeSteps,
@@ -459,7 +584,9 @@ async function processWorkflowLoop({
459
584
  activeSteps,
460
585
  requestContext,
461
586
  retryCount,
462
- perStep
587
+ perStep,
588
+ state: currentState,
589
+ outputOptions
463
590
  }
464
591
  });
465
592
  } else {
@@ -477,7 +604,9 @@ async function processWorkflowLoop({
477
604
  resumeData,
478
605
  activeSteps,
479
606
  requestContext,
480
- perStep
607
+ perStep,
608
+ state: currentState,
609
+ outputOptions
481
610
  }
482
611
  });
483
612
  }
@@ -495,15 +624,180 @@ async function processWorkflowForEach({
495
624
  resumeData,
496
625
  parentWorkflow,
497
626
  requestContext,
498
- perStep
627
+ perStep,
628
+ state,
629
+ outputOptions,
630
+ forEachIndex
499
631
  }, {
500
632
  pubsub,
501
633
  mastra,
502
634
  step
503
635
  }) {
636
+ const currentState = resolveCurrentState({ stepResults, state });
504
637
  const currentResult = stepResults[step.step.id];
505
638
  const idx = currentResult?.output?.length ?? 0;
506
639
  const targetLen = prevResult?.output?.length ?? 0;
640
+ if (forEachIndex !== void 0 && resumeSteps?.length > 0 && idx > 0) {
641
+ const outputArray = currentResult?.output;
642
+ const outputLength = Array.isArray(outputArray) ? outputArray.length : 0;
643
+ if (!Array.isArray(outputArray) || forEachIndex < 0 || forEachIndex >= outputLength) {
644
+ const error = new Error(
645
+ `Invalid forEachIndex ${forEachIndex} for forEach resume: expected index in range [0, ${outputLength - 1}] but output array has length ${outputLength}`
646
+ );
647
+ await pubsub.publish("workflows", {
648
+ type: "workflow.fail",
649
+ runId,
650
+ data: {
651
+ parentWorkflow,
652
+ workflowId,
653
+ runId,
654
+ executionPath,
655
+ resumeSteps,
656
+ stepResults,
657
+ prevResult: { status: "failed", error },
658
+ activeSteps,
659
+ requestContext,
660
+ state: currentState,
661
+ outputOptions
662
+ }
663
+ });
664
+ return;
665
+ }
666
+ const iterationResult = currentResult?.output?.[forEachIndex];
667
+ if (iterationResult?.status === "suspended" || iterationResult === null) {
668
+ const isNestedWorkflow2 = step.step.component === "WORKFLOW";
669
+ const targetArray2 = prevResult?.output;
670
+ const iterationPrevResult2 = isNestedWorkflow2 && prevResult.status === "success" && Array.isArray(targetArray2) ? { status: "success", output: targetArray2[forEachIndex] } : prevResult;
671
+ await pubsub.publish("workflows", {
672
+ type: "workflow.step.run",
673
+ runId,
674
+ data: {
675
+ parentWorkflow,
676
+ workflowId,
677
+ runId,
678
+ executionPath: [executionPath[0], forEachIndex],
679
+ resumeSteps,
680
+ timeTravel,
681
+ stepResults,
682
+ prevResult: iterationPrevResult2,
683
+ resumeData,
684
+ activeSteps,
685
+ requestContext,
686
+ perStep,
687
+ state: currentState,
688
+ outputOptions
689
+ }
690
+ });
691
+ return;
692
+ }
693
+ const pendingIterations = currentResult.output.filter((r) => r === null || r?.status === "suspended");
694
+ if (pendingIterations.length > 0) {
695
+ const collectedResumeLabels = {};
696
+ for (let i = 0; i < currentResult.output.length; i++) {
697
+ const iterResult = currentResult.output[i];
698
+ if (iterResult?.status === "suspended" && iterResult.suspendPayload?.__workflow_meta?.resumeLabels) {
699
+ Object.assign(collectedResumeLabels, iterResult.suspendPayload.__workflow_meta.resumeLabels);
700
+ }
701
+ }
702
+ const suspendMeta = {
703
+ foreachIndex: forEachIndex
704
+ };
705
+ if (Object.keys(collectedResumeLabels).length > 0) {
706
+ suspendMeta.resumeLabels = collectedResumeLabels;
707
+ }
708
+ await pubsub.publish("workflows", {
709
+ type: "workflow.step.end",
710
+ runId,
711
+ data: {
712
+ parentWorkflow,
713
+ workflowId,
714
+ runId,
715
+ executionPath,
716
+ resumeSteps,
717
+ stepResults: {
718
+ ...stepResults,
719
+ [step.step.id]: {
720
+ ...currentResult,
721
+ status: "suspended",
722
+ suspendedAt: Date.now(),
723
+ suspendPayload: { __workflow_meta: suspendMeta }
724
+ }
725
+ },
726
+ prevResult: {
727
+ status: "suspended",
728
+ output: currentResult.output,
729
+ suspendPayload: { __workflow_meta: suspendMeta },
730
+ payload: currentResult.payload,
731
+ startedAt: currentResult.startedAt,
732
+ suspendedAt: Date.now()
733
+ },
734
+ activeSteps,
735
+ requestContext,
736
+ state: currentState,
737
+ outputOptions
738
+ }
739
+ });
740
+ return;
741
+ }
742
+ return;
743
+ }
744
+ if (resumeData !== void 0 && forEachIndex === void 0 && currentResult?.output?.length > 0) {
745
+ const suspendedIndices = [];
746
+ for (let i = 0; i < currentResult.output.length; i++) {
747
+ const iterResult = currentResult.output[i];
748
+ if (iterResult && typeof iterResult === "object" && iterResult.status === "suspended") {
749
+ suspendedIndices.push(i);
750
+ }
751
+ }
752
+ if (suspendedIndices.length > 0) {
753
+ const concurrency = step.opts.concurrency ?? 1;
754
+ const indicesToResume = suspendedIndices.slice(0, concurrency);
755
+ const workflowsStore2 = await mastra.getStorage()?.getStore("workflows");
756
+ const updatedOutput = [...currentResult.output];
757
+ for (const suspIdx of indicesToResume) {
758
+ updatedOutput[suspIdx] = createPendingMarker();
759
+ }
760
+ await workflowsStore2?.updateWorkflowResults({
761
+ workflowName: workflowId,
762
+ runId,
763
+ stepId: step.step.id,
764
+ result: {
765
+ ...currentResult,
766
+ output: updatedOutput
767
+ },
768
+ requestContext
769
+ });
770
+ const isNestedWorkflow2 = step.step.component === "WORKFLOW";
771
+ for (const suspIdx of indicesToResume) {
772
+ const targetArray2 = prevResult?.output;
773
+ const iterationPrevResult2 = isNestedWorkflow2 && prevResult.status === "success" && Array.isArray(targetArray2) ? { status: "success", output: targetArray2[suspIdx] } : prevResult;
774
+ try {
775
+ await pubsub.publish("workflows", {
776
+ type: "workflow.step.run",
777
+ runId,
778
+ data: {
779
+ parentWorkflow,
780
+ workflowId,
781
+ runId,
782
+ executionPath: [executionPath[0], suspIdx],
783
+ resumeSteps,
784
+ timeTravel,
785
+ stepResults,
786
+ prevResult: iterationPrevResult2,
787
+ resumeData,
788
+ activeSteps,
789
+ requestContext,
790
+ perStep,
791
+ state: currentState,
792
+ outputOptions
793
+ }
794
+ });
795
+ } catch {
796
+ }
797
+ }
798
+ return;
799
+ }
800
+ }
507
801
  if (idx >= targetLen && currentResult.output.filter((r) => r !== null).length >= targetLen) {
508
802
  await pubsub.publish("workflows", {
509
803
  type: "workflow.step.run",
@@ -517,10 +811,13 @@ async function processWorkflowForEach({
517
811
  stepResults,
518
812
  timeTravel,
519
813
  prevResult: currentResult,
520
- resumeData,
814
+ resumeData: void 0,
815
+ // No resumeData when advancing past foreach
521
816
  activeSteps,
522
817
  requestContext,
523
- perStep
818
+ perStep,
819
+ state: currentState,
820
+ outputOptions
524
821
  }
525
822
  });
526
823
  return;
@@ -543,7 +840,10 @@ async function processWorkflowForEach({
543
840
  },
544
841
  requestContext
545
842
  });
843
+ const isNestedWorkflow2 = step.step.component === "WORKFLOW";
546
844
  for (let i = 0; i < concurrency; i++) {
845
+ const targetArray2 = prevResult?.output;
846
+ const iterationPrevResult2 = isNestedWorkflow2 && prevResult.status === "success" && Array.isArray(targetArray2) ? { status: "success", output: targetArray2[i] } : prevResult;
547
847
  await pubsub.publish("workflows", {
548
848
  type: "workflow.step.run",
549
849
  runId,
@@ -555,11 +855,13 @@ async function processWorkflowForEach({
555
855
  resumeSteps,
556
856
  stepResults,
557
857
  timeTravel,
558
- prevResult,
858
+ prevResult: iterationPrevResult2,
559
859
  resumeData,
560
860
  activeSteps,
561
861
  requestContext,
562
- perStep
862
+ perStep,
863
+ state: currentState,
864
+ outputOptions
563
865
  }
564
866
  });
565
867
  }
@@ -578,6 +880,9 @@ async function processWorkflowForEach({
578
880
  },
579
881
  requestContext
580
882
  });
883
+ const isNestedWorkflow = step.step.component === "WORKFLOW";
884
+ const targetArray = prevResult?.output;
885
+ const iterationPrevResult = isNestedWorkflow && prevResult.status === "success" && Array.isArray(targetArray) ? { status: "success", output: targetArray[idx] } : prevResult;
581
886
  await pubsub.publish("workflows", {
582
887
  type: "workflow.step.run",
583
888
  runId,
@@ -589,14 +894,18 @@ async function processWorkflowForEach({
589
894
  resumeSteps,
590
895
  timeTravel,
591
896
  stepResults,
592
- prevResult,
897
+ prevResult: iterationPrevResult,
593
898
  resumeData,
594
899
  activeSteps,
595
900
  requestContext,
596
- perStep
901
+ perStep,
902
+ state: currentState,
903
+ outputOptions
597
904
  }
598
905
  });
599
906
  }
907
+
908
+ // src/workflows/evented/workflow-event-processor/parallel.ts
600
909
  async function processWorkflowParallel({
601
910
  workflowId,
602
911
  runId,
@@ -609,11 +918,14 @@ async function processWorkflowParallel({
609
918
  resumeData,
610
919
  parentWorkflow,
611
920
  requestContext,
612
- perStep
921
+ perStep,
922
+ state,
923
+ outputOptions
613
924
  }, {
614
925
  pubsub,
615
926
  step
616
927
  }) {
928
+ const currentState = resolveCurrentState({ stepResults, state });
617
929
  for (let i = 0; i < step.steps.length; i++) {
618
930
  const nestedStep = step.steps[i];
619
931
  if (nestedStep?.type === "step") {
@@ -640,7 +952,9 @@ async function processWorkflowParallel({
640
952
  parentWorkflow,
641
953
  activeSteps,
642
954
  requestContext,
643
- perStep
955
+ perStep,
956
+ state: currentState,
957
+ outputOptions
644
958
  }
645
959
  });
646
960
  })
@@ -658,23 +972,23 @@ async function processWorkflowConditional({
658
972
  resumeData,
659
973
  parentWorkflow,
660
974
  requestContext,
661
- perStep
975
+ perStep,
976
+ state,
977
+ outputOptions
662
978
  }, {
663
979
  pubsub,
664
980
  stepExecutor,
665
981
  step
666
982
  }) {
983
+ const currentState = resolveCurrentState({ stepResults, state });
984
+ const reqContext = new RequestContext(Object.entries(requestContext ?? {}));
667
985
  const idxs = await stepExecutor.evaluateConditions({
668
986
  workflowId,
669
987
  step,
670
988
  runId,
671
989
  stepResults,
672
- // TODO: implement state
673
- state: {},
674
- emitter: new EventEmitter(),
675
- // TODO
676
- requestContext: new RequestContext(),
677
- // TODO
990
+ state: currentState,
991
+ requestContext: reqContext,
678
992
  input: prevResult?.status === "success" ? prevResult.output : void 0,
679
993
  resumeData
680
994
  });
@@ -705,7 +1019,9 @@ async function processWorkflowConditional({
705
1019
  parentWorkflow,
706
1020
  activeSteps,
707
1021
  requestContext,
708
- perStep
1022
+ perStep,
1023
+ state: currentState,
1024
+ outputOptions
709
1025
  }
710
1026
  });
711
1027
  } else {
@@ -730,7 +1046,9 @@ async function processWorkflowConditional({
730
1046
  parentWorkflow,
731
1047
  activeSteps,
732
1048
  requestContext,
733
- perStep
1049
+ perStep,
1050
+ state: currentState,
1051
+ outputOptions
734
1052
  }
735
1053
  });
736
1054
  } else {
@@ -748,7 +1066,9 @@ async function processWorkflowConditional({
748
1066
  parentWorkflow,
749
1067
  activeSteps,
750
1068
  requestContext,
751
- perStep
1069
+ perStep,
1070
+ state: currentState,
1071
+ outputOptions
752
1072
  }
753
1073
  });
754
1074
  }
@@ -756,6 +1076,8 @@ async function processWorkflowConditional({
756
1076
  );
757
1077
  }
758
1078
  }
1079
+
1080
+ // src/workflows/evented/workflow-event-processor/sleep.ts
759
1081
  async function processWorkflowWaitForEvent(workflowData, {
760
1082
  pubsub,
761
1083
  eventName,
@@ -820,15 +1142,13 @@ async function processWorkflowSleep({
820
1142
  }
821
1143
  }
822
1144
  });
1145
+ const reqContext = new RequestContext(Object.entries(requestContext ?? {}));
823
1146
  const duration = await stepExecutor.resolveSleep({
824
1147
  workflowId,
825
1148
  step,
826
1149
  runId,
827
1150
  stepResults,
828
- emitter: new EventEmitter(),
829
- // TODO
830
- requestContext: new RequestContext(),
831
- // TODO
1151
+ requestContext: reqContext,
832
1152
  input: prevResult?.status === "success" ? prevResult.output : void 0,
833
1153
  resumeData
834
1154
  });
@@ -901,15 +1221,13 @@ async function processWorkflowSleepUntil({
901
1221
  step
902
1222
  }) {
903
1223
  const startedAt = Date.now();
1224
+ const reqContext = new RequestContext(Object.entries(requestContext ?? {}));
904
1225
  const duration = await stepExecutor.resolveSleepUntil({
905
1226
  workflowId,
906
1227
  step,
907
1228
  runId,
908
1229
  stepResults,
909
- emitter: new EventEmitter(),
910
- // TODO
911
- requestContext: new RequestContext(),
912
- // TODO
1230
+ requestContext: reqContext,
913
1231
  input: prevResult?.status === "success" ? prevResult.output : void 0,
914
1232
  resumeData
915
1233
  });
@@ -1095,8 +1413,12 @@ var WorkflowEventProcessor = class extends EventProcessor {
1095
1413
  executionPath,
1096
1414
  stepResults,
1097
1415
  requestContext,
1098
- perStep
1416
+ perStep,
1417
+ state,
1418
+ outputOptions,
1419
+ forEachIndex
1099
1420
  }) {
1421
+ const initialState = arguments[0].initialState ?? state ?? {};
1100
1422
  this.getOrCreateAbortController(runId);
1101
1423
  if (parentWorkflow?.runId) {
1102
1424
  this.parentChildRelationships.set(runId, parentWorkflow.runId);
@@ -1104,26 +1426,35 @@ var WorkflowEventProcessor = class extends EventProcessor {
1104
1426
  const workflowsStore = await this.mastra.getStorage()?.getStore("workflows");
1105
1427
  const existingRun = await workflowsStore?.getWorkflowRunById({ runId, workflowName: workflow.id });
1106
1428
  const resourceId = existingRun?.resourceId;
1107
- await workflowsStore?.persistWorkflowSnapshot({
1108
- workflowName: workflow.id,
1109
- runId,
1110
- resourceId,
1111
- snapshot: {
1112
- activePaths: [],
1113
- suspendedPaths: {},
1114
- resumeLabels: {},
1115
- waitingPaths: {},
1116
- activeStepsPath: {},
1117
- serializedStepGraph: workflow.serializedStepGraph,
1118
- timestamp: Date.now(),
1429
+ const shouldPersist = workflow?.options?.shouldPersistSnapshot?.({
1430
+ stepResults: stepResults ?? {},
1431
+ workflowStatus: "running"
1432
+ }) ?? true;
1433
+ if (shouldPersist) {
1434
+ await workflowsStore?.persistWorkflowSnapshot({
1435
+ workflowName: workflow.id,
1119
1436
  runId,
1120
- context: stepResults ?? {
1121
- input: prevResult?.status === "success" ? prevResult.output : void 0
1122
- },
1123
- status: "running",
1124
- value: {}
1125
- }
1126
- });
1437
+ resourceId,
1438
+ snapshot: {
1439
+ activePaths: [],
1440
+ suspendedPaths: {},
1441
+ resumeLabels: {},
1442
+ waitingPaths: {},
1443
+ activeStepsPath: {},
1444
+ serializedStepGraph: workflow.serializedStepGraph,
1445
+ timestamp: Date.now(),
1446
+ runId,
1447
+ context: {
1448
+ ...stepResults ?? {
1449
+ input: prevResult?.status === "success" ? prevResult.output : void 0
1450
+ },
1451
+ __state: initialState
1452
+ },
1453
+ status: "running",
1454
+ value: initialState
1455
+ }
1456
+ });
1457
+ }
1127
1458
  await this.mastra.pubsub.publish("workflows", {
1128
1459
  type: "workflow.step.run",
1129
1460
  runId,
@@ -1133,29 +1464,42 @@ var WorkflowEventProcessor = class extends EventProcessor {
1133
1464
  runId,
1134
1465
  executionPath: executionPath ?? [0],
1135
1466
  resumeSteps,
1136
- stepResults: stepResults ?? {
1137
- input: prevResult?.status === "success" ? prevResult.output : void 0
1467
+ stepResults: {
1468
+ ...stepResults ?? {
1469
+ input: prevResult?.status === "success" ? prevResult.output : void 0
1470
+ },
1471
+ __state: initialState
1138
1472
  },
1139
1473
  prevResult,
1140
1474
  timeTravel,
1141
1475
  requestContext,
1142
1476
  resumeData,
1143
1477
  activeSteps: {},
1144
- perStep
1478
+ perStep,
1479
+ state: initialState,
1480
+ outputOptions,
1481
+ forEachIndex
1145
1482
  }
1146
1483
  });
1147
1484
  }
1148
1485
  async endWorkflow(args, status = "success") {
1149
- const { workflowId, runId, prevResult, perStep } = args;
1486
+ const { workflowId, runId, prevResult, perStep, workflow, stepResults } = args;
1150
1487
  const workflowsStore = await this.mastra.getStorage()?.getStore("workflows");
1151
- await workflowsStore?.updateWorkflowState({
1152
- workflowName: workflowId,
1153
- runId,
1154
- opts: {
1155
- status: perStep && status === "success" ? "paused" : status,
1156
- result: prevResult
1157
- }
1158
- });
1488
+ const finalStatus = perStep && status === "success" ? "paused" : status;
1489
+ const shouldPersist = workflow?.options?.shouldPersistSnapshot?.({
1490
+ stepResults: stepResults ?? {},
1491
+ workflowStatus: finalStatus
1492
+ }) ?? true;
1493
+ if (shouldPersist) {
1494
+ await workflowsStore?.updateWorkflowState({
1495
+ workflowName: workflowId,
1496
+ runId,
1497
+ opts: {
1498
+ status: finalStatus,
1499
+ result: prevResult
1500
+ }
1501
+ });
1502
+ }
1159
1503
  if (perStep) {
1160
1504
  await this.mastra.pubsub.publish(`workflow.events.v2.${runId}`, {
1161
1505
  type: "watch",
@@ -1192,13 +1536,16 @@ var WorkflowEventProcessor = class extends EventProcessor {
1192
1536
  requestContext,
1193
1537
  runId,
1194
1538
  timeTravel,
1195
- perStep
1196
- } = args;
1539
+ perStep,
1540
+ stepResults,
1541
+ state} = args;
1542
+ const finalState = resolveCurrentState({ stepResults, state });
1197
1543
  this.cleanupRun(runId);
1198
1544
  if (parentWorkflow) {
1199
1545
  await this.mastra.pubsub.publish("workflows", {
1200
1546
  type: "workflow.step.end",
1201
- runId,
1547
+ runId: parentWorkflow.runId,
1548
+ // Use parent's runId for event routing
1202
1549
  data: {
1203
1550
  workflowId: parentWorkflow.workflowId,
1204
1551
  runId: parentWorkflow.runId,
@@ -1212,22 +1559,39 @@ var WorkflowEventProcessor = class extends EventProcessor {
1212
1559
  parentContext: parentWorkflow,
1213
1560
  requestContext,
1214
1561
  timeTravel,
1215
- perStep
1562
+ perStep,
1563
+ state: finalState,
1564
+ nestedRunId: runId
1565
+ // Pass nested workflow's runId for step retrieval
1216
1566
  }
1217
1567
  });
1218
1568
  }
1219
1569
  await this.mastra.pubsub.publish("workflows-finish", {
1220
1570
  type: "workflow.end",
1221
1571
  runId,
1222
- data: { ...args, workflow: void 0 }
1572
+ data: { ...args, workflow: void 0, state: finalState }
1223
1573
  });
1224
1574
  }
1225
1575
  async processWorkflowSuspend(args) {
1226
- const { resumeSteps, prevResult, resumeData, parentWorkflow, activeSteps, runId, requestContext, timeTravel } = args;
1576
+ const {
1577
+ resumeSteps,
1578
+ prevResult,
1579
+ resumeData,
1580
+ parentWorkflow,
1581
+ activeSteps,
1582
+ runId,
1583
+ requestContext,
1584
+ timeTravel,
1585
+ stepResults,
1586
+ state,
1587
+ outputOptions
1588
+ } = args;
1589
+ const finalState = resolveCurrentState({ stepResults, state });
1227
1590
  if (parentWorkflow) {
1228
1591
  await this.mastra.pubsub.publish("workflows", {
1229
1592
  type: "workflow.step.end",
1230
- runId,
1593
+ runId: parentWorkflow.runId,
1594
+ // Use parent's runId for event routing
1231
1595
  data: {
1232
1596
  workflowId: parentWorkflow.workflowId,
1233
1597
  runId: parentWorkflow.runId,
@@ -1249,14 +1613,18 @@ var WorkflowEventProcessor = class extends EventProcessor {
1249
1613
  activeSteps,
1250
1614
  requestContext,
1251
1615
  parentWorkflow: parentWorkflow.parentWorkflow,
1252
- parentContext: parentWorkflow
1616
+ parentContext: parentWorkflow,
1617
+ state: finalState,
1618
+ outputOptions,
1619
+ nestedRunId: runId
1620
+ // Pass nested workflow's runId for step retrieval
1253
1621
  }
1254
1622
  });
1255
1623
  }
1256
1624
  await this.mastra.pubsub.publish("workflows-finish", {
1257
1625
  type: "workflow.suspend",
1258
1626
  runId,
1259
- data: { ...args, workflow: void 0 }
1627
+ data: { ...args, workflow: void 0, state: finalState }
1260
1628
  });
1261
1629
  }
1262
1630
  async processWorkflowFail(args) {
@@ -1269,22 +1637,34 @@ var WorkflowEventProcessor = class extends EventProcessor {
1269
1637
  parentWorkflow,
1270
1638
  activeSteps,
1271
1639
  requestContext,
1272
- timeTravel
1640
+ timeTravel,
1641
+ stepResults,
1642
+ state,
1643
+ outputOptions,
1644
+ workflow
1273
1645
  } = args;
1646
+ const finalState = resolveCurrentState({ stepResults, state });
1274
1647
  this.cleanupRun(runId);
1275
1648
  const workflowsStore = await this.mastra.getStorage()?.getStore("workflows");
1276
- await workflowsStore?.updateWorkflowState({
1277
- workflowName: workflowId,
1278
- runId,
1279
- opts: {
1280
- status: "failed",
1281
- error: prevResult.error
1282
- }
1283
- });
1649
+ const shouldPersist = workflow?.options?.shouldPersistSnapshot?.({
1650
+ stepResults: stepResults ?? {},
1651
+ workflowStatus: "failed"
1652
+ }) ?? true;
1653
+ if (shouldPersist) {
1654
+ await workflowsStore?.updateWorkflowState({
1655
+ workflowName: workflowId,
1656
+ runId,
1657
+ opts: {
1658
+ status: "failed",
1659
+ error: prevResult.error
1660
+ }
1661
+ });
1662
+ }
1284
1663
  if (parentWorkflow) {
1285
1664
  await this.mastra.pubsub.publish("workflows", {
1286
1665
  type: "workflow.step.end",
1287
- runId,
1666
+ runId: parentWorkflow.runId,
1667
+ // Use parent's runId for event routing
1288
1668
  data: {
1289
1669
  workflowId: parentWorkflow.workflowId,
1290
1670
  runId: parentWorkflow.runId,
@@ -1297,14 +1677,18 @@ var WorkflowEventProcessor = class extends EventProcessor {
1297
1677
  activeSteps,
1298
1678
  requestContext,
1299
1679
  parentWorkflow: parentWorkflow.parentWorkflow,
1300
- parentContext: parentWorkflow
1680
+ parentContext: parentWorkflow,
1681
+ state: finalState,
1682
+ outputOptions,
1683
+ nestedRunId: runId
1684
+ // Pass nested workflow's runId for step retrieval
1301
1685
  }
1302
1686
  });
1303
1687
  }
1304
1688
  await this.mastra.pubsub.publish("workflows-finish", {
1305
1689
  type: "workflow.fail",
1306
1690
  runId,
1307
- data: { ...args, workflow: void 0 }
1691
+ data: { ...args, workflow: void 0, state: finalState }
1308
1692
  });
1309
1693
  }
1310
1694
  async processWorkflowStepRun({
@@ -1321,8 +1705,12 @@ var WorkflowEventProcessor = class extends EventProcessor {
1321
1705
  parentWorkflow,
1322
1706
  requestContext,
1323
1707
  retryCount = 0,
1324
- perStep
1708
+ perStep,
1709
+ state,
1710
+ outputOptions,
1711
+ forEachIndex
1325
1712
  }) {
1713
+ const currentState = resolveCurrentState({ stepResults, state });
1326
1714
  let stepGraph = workflow.stepGraph;
1327
1715
  if (!executionPath?.length) {
1328
1716
  return this.errorWorkflow(
@@ -1348,6 +1736,24 @@ var WorkflowEventProcessor = class extends EventProcessor {
1348
1736
  }
1349
1737
  let step = stepGraph[executionPath[0]];
1350
1738
  if (!step) {
1739
+ if (executionPath[0] >= stepGraph.length) {
1740
+ return this.endWorkflow({
1741
+ workflow,
1742
+ parentWorkflow,
1743
+ workflowId,
1744
+ runId,
1745
+ executionPath,
1746
+ resumeSteps,
1747
+ stepResults,
1748
+ prevResult,
1749
+ activeSteps,
1750
+ requestContext,
1751
+ // Use currentState (resolved from stepResults.__state and state) instead of
1752
+ // the possibly-undefined state parameter, to ensure final state is preserved
1753
+ state: currentState,
1754
+ outputOptions
1755
+ });
1756
+ }
1351
1757
  return this.errorWorkflow(
1352
1758
  {
1353
1759
  workflowId,
@@ -1385,7 +1791,9 @@ var WorkflowEventProcessor = class extends EventProcessor {
1385
1791
  resumeData,
1386
1792
  parentWorkflow,
1387
1793
  requestContext,
1388
- perStep
1794
+ perStep,
1795
+ state: currentState,
1796
+ outputOptions
1389
1797
  },
1390
1798
  {
1391
1799
  pubsub: this.mastra.pubsub,
@@ -1406,7 +1814,9 @@ var WorkflowEventProcessor = class extends EventProcessor {
1406
1814
  resumeData,
1407
1815
  parentWorkflow,
1408
1816
  requestContext,
1409
- perStep
1817
+ perStep,
1818
+ state: currentState,
1819
+ outputOptions
1410
1820
  },
1411
1821
  {
1412
1822
  pubsub: this.mastra.pubsub,
@@ -1428,8 +1838,7 @@ var WorkflowEventProcessor = class extends EventProcessor {
1428
1838
  resumeData,
1429
1839
  parentWorkflow,
1430
1840
  requestContext,
1431
- perStep
1432
- },
1841
+ perStep},
1433
1842
  {
1434
1843
  pubsub: this.mastra.pubsub,
1435
1844
  stepExecutor: this.stepExecutor,
@@ -1450,8 +1859,7 @@ var WorkflowEventProcessor = class extends EventProcessor {
1450
1859
  resumeData,
1451
1860
  parentWorkflow,
1452
1861
  requestContext,
1453
- perStep
1454
- },
1862
+ perStep},
1455
1863
  {
1456
1864
  pubsub: this.mastra.pubsub,
1457
1865
  stepExecutor: this.stepExecutor,
@@ -1472,7 +1880,10 @@ var WorkflowEventProcessor = class extends EventProcessor {
1472
1880
  resumeData,
1473
1881
  parentWorkflow,
1474
1882
  requestContext,
1475
- perStep
1883
+ perStep,
1884
+ state: currentState,
1885
+ outputOptions,
1886
+ forEachIndex
1476
1887
  },
1477
1888
  {
1478
1889
  pubsub: this.mastra.pubsub,
@@ -1505,7 +1916,7 @@ var WorkflowEventProcessor = class extends EventProcessor {
1505
1916
  }
1506
1917
  activeSteps[step.step.id] = true;
1507
1918
  const workflowsStore = await this.mastra?.getStorage()?.getStore("workflows");
1508
- if (step.step instanceof EventedWorkflow) {
1919
+ if (step.step instanceof EventedWorkflow || step.step.component === "WORKFLOW") {
1509
1920
  if (resumeSteps?.length > 1) {
1510
1921
  const stepData = stepResults[step.step.id];
1511
1922
  const nestedRunId = stepData?.suspendPayload?.__workflow_meta?.runId;
@@ -1560,7 +1971,10 @@ var WorkflowEventProcessor = class extends EventProcessor {
1560
1971
  resumeData,
1561
1972
  activeSteps,
1562
1973
  requestContext,
1563
- perStep
1974
+ perStep,
1975
+ initialState: currentState,
1976
+ state: currentState,
1977
+ outputOptions
1564
1978
  }
1565
1979
  });
1566
1980
  } else if (timeTravel && timeTravel.steps?.length > 1 && timeTravel.steps[0] === step.step.id) {
@@ -1568,6 +1982,7 @@ var WorkflowEventProcessor = class extends EventProcessor {
1568
1982
  workflowName: step.step.id,
1569
1983
  runId
1570
1984
  }) ?? { context: {} };
1985
+ const nestedWorkflow = step.step;
1571
1986
  const timeTravelParams = createTimeTravelExecutionParams({
1572
1987
  steps: timeTravel.steps.slice(1),
1573
1988
  inputData: timeTravel.inputData,
@@ -1575,10 +1990,10 @@ var WorkflowEventProcessor = class extends EventProcessor {
1575
1990
  context: timeTravel.nestedStepResults?.[step.step.id] ?? {},
1576
1991
  nestedStepsContext: timeTravel.nestedStepResults ?? {},
1577
1992
  snapshot,
1578
- graph: step.step.buildExecutionGraph(),
1993
+ graph: nestedWorkflow.buildExecutionGraph(),
1579
1994
  perStep
1580
1995
  });
1581
- const nestedPrevStep = getStep(step.step, timeTravelParams.executionPath);
1996
+ const nestedPrevStep = getStep(nestedWorkflow, timeTravelParams.executionPath);
1582
1997
  const nestedPrevResult = timeTravelParams.stepResults[nestedPrevStep?.id ?? "input"];
1583
1998
  await this.mastra.pubsub.publish("workflows", {
1584
1999
  type: "workflow.start",
@@ -1603,7 +2018,10 @@ var WorkflowEventProcessor = class extends EventProcessor {
1603
2018
  timeTravel: timeTravelParams,
1604
2019
  activeSteps,
1605
2020
  requestContext,
1606
- perStep
2021
+ perStep,
2022
+ initialState: currentState,
2023
+ state: currentState,
2024
+ outputOptions
1607
2025
  }
1608
2026
  });
1609
2027
  } else {
@@ -1629,7 +2047,10 @@ var WorkflowEventProcessor = class extends EventProcessor {
1629
2047
  resumeData,
1630
2048
  activeSteps,
1631
2049
  requestContext,
1632
- perStep
2050
+ perStep,
2051
+ initialState: currentState,
2052
+ state: currentState,
2053
+ outputOptions
1633
2054
  }
1634
2055
  });
1635
2056
  }
@@ -1683,9 +2104,7 @@ var WorkflowEventProcessor = class extends EventProcessor {
1683
2104
  step: step.step,
1684
2105
  runId,
1685
2106
  stepResults,
1686
- // TODO: implement state
1687
- state: {},
1688
- emitter: ee,
2107
+ state: currentState,
1689
2108
  requestContext: rc,
1690
2109
  input: prevResult?.output,
1691
2110
  resumeData: resumeDataToUse,
@@ -1713,7 +2132,9 @@ var WorkflowEventProcessor = class extends EventProcessor {
1713
2132
  prevResult: stepResult,
1714
2133
  activeSteps,
1715
2134
  requestContext,
1716
- perStep
2135
+ perStep,
2136
+ state: currentState,
2137
+ outputOptions
1717
2138
  });
1718
2139
  return;
1719
2140
  }
@@ -1732,7 +2153,9 @@ var WorkflowEventProcessor = class extends EventProcessor {
1732
2153
  stepResults,
1733
2154
  prevResult: stepResult,
1734
2155
  activeSteps,
1735
- requestContext
2156
+ requestContext,
2157
+ state: currentState,
2158
+ outputOptions
1736
2159
  }
1737
2160
  });
1738
2161
  } else {
@@ -1750,7 +2173,9 @@ var WorkflowEventProcessor = class extends EventProcessor {
1750
2173
  prevResult,
1751
2174
  activeSteps,
1752
2175
  requestContext,
1753
- retryCount: retryCount + 1
2176
+ retryCount: retryCount + 1,
2177
+ state: currentState,
2178
+ outputOptions
1754
2179
  }
1755
2180
  });
1756
2181
  }
@@ -1778,6 +2203,7 @@ var WorkflowEventProcessor = class extends EventProcessor {
1778
2203
  }
1779
2204
  );
1780
2205
  } else {
2206
+ const updatedState = stepResult.__state ?? currentState;
1781
2207
  await this.mastra.pubsub.publish("workflows", {
1782
2208
  type: "workflow.step.end",
1783
2209
  runId,
@@ -1789,11 +2215,17 @@ var WorkflowEventProcessor = class extends EventProcessor {
1789
2215
  resumeSteps,
1790
2216
  timeTravel,
1791
2217
  //timeTravel is passed in as workflow.step.end ends the step, not the workflow, the timeTravel info is passed to the next step to run.
1792
- stepResults,
2218
+ stepResults: {
2219
+ ...stepResults,
2220
+ __state: updatedState
2221
+ },
1793
2222
  prevResult: stepResult,
1794
2223
  activeSteps,
1795
2224
  requestContext,
1796
- perStep
2225
+ perStep,
2226
+ state: updatedState,
2227
+ outputOptions,
2228
+ forEachIndex
1797
2229
  }
1798
2230
  });
1799
2231
  }
@@ -1811,8 +2243,15 @@ var WorkflowEventProcessor = class extends EventProcessor {
1811
2243
  activeSteps,
1812
2244
  parentContext,
1813
2245
  requestContext,
1814
- perStep
2246
+ perStep,
2247
+ state,
2248
+ outputOptions,
2249
+ forEachIndex,
2250
+ nestedRunId
1815
2251
  }) {
2252
+ const currentState = parentContext ? state ?? prevResult?.__state ?? stepResults?.__state ?? {} : prevResult?.__state ?? stepResults?.__state ?? state ?? {};
2253
+ const { __state: _removedState, ...cleanPrevResult } = prevResult;
2254
+ prevResult = cleanPrevResult;
1816
2255
  let step = workflow.stepGraph[executionPath[0]];
1817
2256
  if ((step?.type === "parallel" || step?.type === "conditional") && executionPath.length > 1) {
1818
2257
  step = step.steps[executionPath[1]];
@@ -1844,15 +2283,62 @@ var WorkflowEventProcessor = class extends EventProcessor {
1844
2283
  runId
1845
2284
  });
1846
2285
  const currentIdx = executionPath[1];
1847
- const currentResult = snapshot?.context?.[step.step.id]?.output;
2286
+ const existingStepResult = snapshot?.context?.[step.step.id];
2287
+ const currentResult = existingStepResult?.output;
2288
+ const originalPayload = existingStepResult?.payload;
1848
2289
  let newResult = prevResult;
1849
2290
  if (currentIdx !== void 0) {
1850
- if (currentResult) {
1851
- currentResult[currentIdx] = prevResult.output;
1852
- newResult = { ...prevResult, output: currentResult };
1853
- } else {
1854
- newResult = { ...prevResult, output: [prevResult.output] };
1855
- }
2291
+ if (prevResult.status === "bailed") {
2292
+ const bailedResult = {
2293
+ status: "success",
2294
+ output: prevResult.output,
2295
+ startedAt: existingStepResult?.startedAt ?? Date.now(),
2296
+ endedAt: Date.now(),
2297
+ payload: originalPayload
2298
+ };
2299
+ await workflowsStore?.updateWorkflowResults({
2300
+ workflowName: workflow.id,
2301
+ runId,
2302
+ stepId: step.step.id,
2303
+ result: bailedResult,
2304
+ requestContext
2305
+ });
2306
+ return this.endWorkflow({
2307
+ workflow,
2308
+ parentWorkflow,
2309
+ workflowId,
2310
+ runId,
2311
+ executionPath: [executionPath[0]],
2312
+ resumeSteps,
2313
+ stepResults: { ...stepResults, [step.step.id]: bailedResult },
2314
+ prevResult: bailedResult,
2315
+ activeSteps,
2316
+ requestContext,
2317
+ perStep,
2318
+ state: currentState,
2319
+ outputOptions
2320
+ });
2321
+ }
2322
+ const iterationResult = prevResult.status === "suspended" ? prevResult : prevResult.output;
2323
+ if (currentResult) {
2324
+ currentResult[currentIdx] = iterationResult;
2325
+ newResult = {
2326
+ ...existingStepResult,
2327
+ // Preserve step-level properties
2328
+ ...prevResult,
2329
+ // Get iteration timing info
2330
+ output: currentResult,
2331
+ payload: originalPayload,
2332
+ // Preserve suspend metadata from first suspension
2333
+ suspendPayload: existingStepResult?.suspendPayload ?? prevResult.suspendPayload,
2334
+ suspendedAt: existingStepResult?.suspendedAt ?? prevResult.suspendedAt,
2335
+ // Update resume metadata to most recent resume (new iteration takes precedence)
2336
+ resumePayload: prevResult.resumePayload ?? existingStepResult?.resumePayload,
2337
+ resumedAt: prevResult.resumedAt ?? existingStepResult?.resumedAt
2338
+ };
2339
+ } else {
2340
+ newResult = { ...prevResult, output: [iterationResult], payload: originalPayload };
2341
+ }
1856
2342
  }
1857
2343
  const newStepResults = await workflowsStore?.updateWorkflowResults({
1858
2344
  workflowName: workflow.id,
@@ -1865,12 +2351,159 @@ var WorkflowEventProcessor = class extends EventProcessor {
1865
2351
  return;
1866
2352
  }
1867
2353
  stepResults = newStepResults;
2354
+ if (currentIdx !== void 0) {
2355
+ const foreachResult = stepResults[step.step.id];
2356
+ const iterationResults = foreachResult?.output ?? [];
2357
+ const targetLen = foreachResult?.payload?.length ?? 0;
2358
+ const pendingCount = iterationResults.filter((r) => r === null).length;
2359
+ const suspendedCount = iterationResults.filter(
2360
+ (r) => r && typeof r === "object" && r.status === "suspended"
2361
+ ).length;
2362
+ const iterationsStarted = iterationResults.length;
2363
+ if (pendingCount > 0) {
2364
+ return;
2365
+ }
2366
+ if (iterationsStarted < targetLen) {
2367
+ await processWorkflowForEach(
2368
+ {
2369
+ workflowId,
2370
+ prevResult: { status: "success", output: foreachResult.payload },
2371
+ runId,
2372
+ executionPath: [executionPath[0]],
2373
+ stepResults,
2374
+ activeSteps,
2375
+ resumeSteps,
2376
+ timeTravel,
2377
+ resumeData: void 0,
2378
+ // Don't pass resumeData when starting new iterations
2379
+ parentWorkflow,
2380
+ requestContext,
2381
+ perStep,
2382
+ state: currentState,
2383
+ outputOptions
2384
+ },
2385
+ {
2386
+ pubsub: this.mastra.pubsub,
2387
+ mastra: this.mastra,
2388
+ step
2389
+ }
2390
+ );
2391
+ return;
2392
+ }
2393
+ if (suspendedCount > 0) {
2394
+ const collectedResumeLabels = {};
2395
+ const suspendedPaths = {
2396
+ [step.step.id]: [executionPath[0]]
2397
+ };
2398
+ for (let i = 0; i < iterationResults.length; i++) {
2399
+ const iterResult = iterationResults[i];
2400
+ if (iterResult && typeof iterResult === "object" && iterResult.status === "suspended") {
2401
+ if (iterResult.suspendPayload?.__workflow_meta?.resumeLabels) {
2402
+ Object.assign(collectedResumeLabels, iterResult.suspendPayload.__workflow_meta.resumeLabels);
2403
+ }
2404
+ }
2405
+ }
2406
+ const foreachSuspendResult = {
2407
+ status: "suspended",
2408
+ output: iterationResults,
2409
+ payload: foreachResult.payload,
2410
+ suspendedAt: Date.now(),
2411
+ startedAt: foreachResult.startedAt,
2412
+ suspendPayload: {
2413
+ __workflow_meta: {
2414
+ path: executionPath,
2415
+ resumeLabels: collectedResumeLabels
2416
+ }
2417
+ }
2418
+ };
2419
+ await workflowsStore?.updateWorkflowResults({
2420
+ workflowName: workflow.id,
2421
+ runId,
2422
+ stepId: step.step.id,
2423
+ result: foreachSuspendResult,
2424
+ requestContext
2425
+ });
2426
+ const shouldPersist = workflow?.options?.shouldPersistSnapshot?.({
2427
+ stepResults: stepResults ?? {},
2428
+ workflowStatus: "suspended"
2429
+ }) ?? true;
2430
+ if (shouldPersist) {
2431
+ await workflowsStore?.updateWorkflowResults({
2432
+ workflowName: workflow.id,
2433
+ runId,
2434
+ stepId: "__state",
2435
+ result: currentState,
2436
+ requestContext
2437
+ });
2438
+ await workflowsStore?.updateWorkflowState({
2439
+ workflowName: workflowId,
2440
+ runId,
2441
+ opts: {
2442
+ status: "suspended",
2443
+ result: foreachSuspendResult,
2444
+ suspendedPaths,
2445
+ resumeLabels: collectedResumeLabels
2446
+ }
2447
+ });
2448
+ }
2449
+ await this.mastra.pubsub.publish("workflows", {
2450
+ type: "workflow.suspend",
2451
+ runId,
2452
+ data: {
2453
+ workflowId,
2454
+ runId,
2455
+ executionPath: [executionPath[0]],
2456
+ resumeSteps,
2457
+ parentWorkflow,
2458
+ stepResults: { ...stepResults, [step.step.id]: foreachSuspendResult },
2459
+ prevResult: foreachSuspendResult,
2460
+ activeSteps,
2461
+ requestContext,
2462
+ timeTravel,
2463
+ state: currentState,
2464
+ outputOptions
2465
+ }
2466
+ });
2467
+ return;
2468
+ }
2469
+ await processWorkflowForEach(
2470
+ {
2471
+ workflowId,
2472
+ prevResult: { status: "success", output: foreachResult.payload },
2473
+ runId,
2474
+ executionPath: [executionPath[0]],
2475
+ stepResults,
2476
+ activeSteps,
2477
+ resumeSteps,
2478
+ timeTravel,
2479
+ resumeData: void 0,
2480
+ parentWorkflow,
2481
+ requestContext,
2482
+ perStep,
2483
+ state: currentState,
2484
+ outputOptions
2485
+ },
2486
+ {
2487
+ pubsub: this.mastra.pubsub,
2488
+ mastra: this.mastra,
2489
+ step
2490
+ }
2491
+ );
2492
+ return;
2493
+ }
1868
2494
  } else if (isExecutableStep(step)) {
1869
2495
  delete activeSteps[step.step.id];
1870
2496
  if (parentContext) {
1871
2497
  prevResult = stepResults[step.step.id] = {
1872
2498
  ...prevResult,
1873
- payload: parentContext.input?.output ?? {}
2499
+ payload: parentContext.input?.output ?? {},
2500
+ // Store nestedRunId in metadata for getWorkflowRunById retrieval
2501
+ ...nestedRunId && {
2502
+ metadata: {
2503
+ ...prevResult.metadata,
2504
+ nestedRunId
2505
+ }
2506
+ }
1874
2507
  };
1875
2508
  }
1876
2509
  const newStepResults = await workflowsStore?.updateWorkflowResults({
@@ -1885,6 +2518,7 @@ var WorkflowEventProcessor = class extends EventProcessor {
1885
2518
  }
1886
2519
  stepResults = newStepResults;
1887
2520
  }
2521
+ stepResults = { ...stepResults, __state: currentState };
1888
2522
  if (!prevResult?.status || prevResult.status === "failed") {
1889
2523
  await this.mastra.pubsub.publish("workflows", {
1890
2524
  type: "workflow.fail",
@@ -1899,7 +2533,9 @@ var WorkflowEventProcessor = class extends EventProcessor {
1899
2533
  timeTravel,
1900
2534
  prevResult,
1901
2535
  activeSteps,
1902
- requestContext
2536
+ requestContext,
2537
+ state: currentState,
2538
+ outputOptions
1903
2539
  }
1904
2540
  });
1905
2541
  return;
@@ -1909,15 +2545,30 @@ var WorkflowEventProcessor = class extends EventProcessor {
1909
2545
  if (suspendedStep) {
1910
2546
  suspendedPaths[suspendedStep.id] = executionPath;
1911
2547
  }
1912
- await workflowsStore?.updateWorkflowState({
1913
- workflowName: workflowId,
1914
- runId,
1915
- opts: {
1916
- status: "suspended",
1917
- result: prevResult,
1918
- suspendedPaths
1919
- }
1920
- });
2548
+ const resumeLabels = prevResult.suspendPayload?.__workflow_meta?.resumeLabels ?? {};
2549
+ const shouldPersist = workflow?.options?.shouldPersistSnapshot?.({
2550
+ stepResults: stepResults ?? {},
2551
+ workflowStatus: "suspended"
2552
+ }) ?? true;
2553
+ if (shouldPersist) {
2554
+ await workflowsStore?.updateWorkflowResults({
2555
+ workflowName: workflow.id,
2556
+ runId,
2557
+ stepId: "__state",
2558
+ result: currentState,
2559
+ requestContext
2560
+ });
2561
+ await workflowsStore?.updateWorkflowState({
2562
+ workflowName: workflowId,
2563
+ runId,
2564
+ opts: {
2565
+ status: "suspended",
2566
+ result: prevResult,
2567
+ suspendedPaths,
2568
+ resumeLabels
2569
+ }
2570
+ });
2571
+ }
1921
2572
  await this.mastra.pubsub.publish("workflows", {
1922
2573
  type: "workflow.suspend",
1923
2574
  runId,
@@ -1931,7 +2582,9 @@ var WorkflowEventProcessor = class extends EventProcessor {
1931
2582
  prevResult,
1932
2583
  activeSteps,
1933
2584
  requestContext,
1934
- timeTravel
2585
+ timeTravel,
2586
+ state: currentState,
2587
+ outputOptions
1935
2588
  }
1936
2589
  });
1937
2590
  await this.mastra.pubsub.publish(`workflow.events.v2.${runId}`, {
@@ -2040,10 +2693,14 @@ var WorkflowEventProcessor = class extends EventProcessor {
2040
2693
  prevResult: { status: "success", output: allResults },
2041
2694
  activeSteps,
2042
2695
  requestContext,
2043
- timeTravel
2696
+ timeTravel,
2697
+ state: currentState,
2698
+ outputOptions
2044
2699
  }
2045
2700
  });
2046
2701
  } else if (step?.type === "foreach") {
2702
+ const foreachStepResult = stepResults[step.step.id];
2703
+ const originalArray = foreachStepResult?.payload;
2047
2704
  await this.mastra.pubsub.publish("workflows", {
2048
2705
  type: "workflow.step.run",
2049
2706
  runId,
@@ -2054,10 +2711,13 @@ var WorkflowEventProcessor = class extends EventProcessor {
2054
2711
  resumeSteps,
2055
2712
  parentWorkflow,
2056
2713
  stepResults,
2057
- prevResult: { ...prevResult, output: prevResult?.payload },
2714
+ prevResult: { ...prevResult, output: originalArray },
2058
2715
  activeSteps,
2059
2716
  requestContext,
2060
- timeTravel
2717
+ timeTravel,
2718
+ state: currentState,
2719
+ outputOptions,
2720
+ forEachIndex
2061
2721
  }
2062
2722
  });
2063
2723
  } else if (executionPath[0] >= workflow.stepGraph.length - 1) {
@@ -2071,7 +2731,9 @@ var WorkflowEventProcessor = class extends EventProcessor {
2071
2731
  stepResults,
2072
2732
  prevResult,
2073
2733
  activeSteps,
2074
- requestContext
2734
+ requestContext,
2735
+ state: currentState,
2736
+ outputOptions
2075
2737
  });
2076
2738
  } else {
2077
2739
  await this.mastra.pubsub.publish("workflows", {
@@ -2087,7 +2749,9 @@ var WorkflowEventProcessor = class extends EventProcessor {
2087
2749
  prevResult,
2088
2750
  activeSteps,
2089
2751
  requestContext,
2090
- timeTravel
2752
+ timeTravel,
2753
+ state: currentState,
2754
+ outputOptions
2091
2755
  }
2092
2756
  });
2093
2757
  }
@@ -2288,6 +2952,57 @@ function createStepFromParams(params) {
2288
2952
  execute: params.execute.bind(params)
2289
2953
  };
2290
2954
  }
2955
+ async function processAgentStream(params) {
2956
+ const { fullStream, isV2Model, pubsub, runId, toolData, logger } = params;
2957
+ try {
2958
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
2959
+ type: "watch",
2960
+ runId,
2961
+ data: { type: "tool-call-streaming-start", ...toolData }
2962
+ });
2963
+ } catch (err) {
2964
+ logger?.debug("Failed to publish stream start event", { runId, error: err });
2965
+ }
2966
+ let tripwireChunk = null;
2967
+ for await (const chunk of fullStream) {
2968
+ if (isTripwireChunk(chunk)) {
2969
+ tripwireChunk = chunk;
2970
+ break;
2971
+ }
2972
+ if (typeof chunk === "object" && chunk !== null && "type" in chunk && chunk.type === "text-delta") {
2973
+ const textDelta = getTextDeltaFromChunk(chunk, isV2Model);
2974
+ if (textDelta) {
2975
+ try {
2976
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
2977
+ type: "watch",
2978
+ runId,
2979
+ data: { type: "tool-call-delta", ...toolData, argsTextDelta: textDelta }
2980
+ });
2981
+ } catch (err) {
2982
+ logger?.debug("Failed to publish stream delta event", { runId, error: err });
2983
+ }
2984
+ }
2985
+ }
2986
+ }
2987
+ try {
2988
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
2989
+ type: "watch",
2990
+ runId,
2991
+ data: { type: "tool-call-streaming-finish", ...toolData }
2992
+ });
2993
+ } catch (err) {
2994
+ logger?.debug("Failed to publish stream finish event", { runId, error: err });
2995
+ }
2996
+ return { tripwireChunk };
2997
+ }
2998
+ async function safeOnFinish(callback, result, logger) {
2999
+ if (!callback) return;
3000
+ try {
3001
+ await callback(result);
3002
+ } catch (err) {
3003
+ logger?.warn("User onFinish callback threw an error", { error: err });
3004
+ }
3005
+ }
2291
3006
  function createStepFromAgent(params, agentOrToolOptions) {
2292
3007
  const options = agentOrToolOptions ?? {};
2293
3008
  const outputSchema = options?.structuredOutput?.schema ?? z.object({ text: z.string() });
@@ -2304,54 +3019,80 @@ function createStepFromAgent(params, agentOrToolOptions) {
2304
3019
  execute: async ({
2305
3020
  inputData,
2306
3021
  runId,
3022
+ mastra,
2307
3023
  [PUBSUB_SYMBOL]: pubsub,
2308
3024
  requestContext,
2309
3025
  tracingContext,
2310
3026
  abortSignal,
2311
3027
  abort
2312
3028
  }) => {
2313
- let streamPromise = {};
2314
- streamPromise.promise = new Promise((resolve, reject) => {
2315
- streamPromise.resolve = resolve;
2316
- streamPromise.reject = reject;
2317
- });
2318
- const { fullStream } = await params.streamLegacy(inputData.prompt, {
2319
- ...agentOptions ?? {},
2320
- tracingContext,
2321
- requestContext,
2322
- onFinish: (result) => {
2323
- streamPromise.resolve(result.text);
2324
- },
2325
- abortSignal
2326
- });
2327
- if (abortSignal.aborted) {
2328
- return abort();
2329
- }
3029
+ const logger = mastra?.getLogger();
2330
3030
  const toolData = {
2331
3031
  name: params.name,
2332
3032
  args: inputData
2333
3033
  };
2334
- await pubsub.publish(`workflow.events.v2.${runId}`, {
2335
- type: "watch",
2336
- runId,
2337
- data: { type: "tool-call-streaming-start", ...toolData ?? {} }
2338
- });
2339
- for await (const chunk of fullStream) {
2340
- if (chunk.type === "text-delta") {
2341
- await pubsub.publish(`workflow.events.v2.${runId}`, {
2342
- type: "watch",
2343
- runId,
2344
- data: { type: "tool-call-delta", ...toolData ?? {}, argsTextDelta: chunk.textDelta }
2345
- });
3034
+ const llm = await params.getLLM({ requestContext });
3035
+ const modelInfo = llm.getModel();
3036
+ const isV2Model = isSupportedLanguageModel(modelInfo);
3037
+ let structuredResult = null;
3038
+ const handleFinish = (result) => {
3039
+ const resultWithObject = result;
3040
+ if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
3041
+ structuredResult = resultWithObject.object;
2346
3042
  }
3043
+ };
3044
+ let fullStream;
3045
+ let textPromise;
3046
+ if (isV2Model) {
3047
+ const modelOutput = await params.stream(inputData.prompt, {
3048
+ ...agentOptions ?? {},
3049
+ tracingContext,
3050
+ requestContext,
3051
+ onFinish: (result) => {
3052
+ handleFinish(result);
3053
+ void safeOnFinish(agentOptions?.onFinish, result, logger);
3054
+ },
3055
+ abortSignal
3056
+ });
3057
+ fullStream = modelOutput.fullStream;
3058
+ textPromise = modelOutput.text;
3059
+ } else {
3060
+ let resolveText;
3061
+ textPromise = new Promise((resolve) => {
3062
+ resolveText = resolve;
3063
+ });
3064
+ const legacyResult = await params.streamLegacy(inputData.prompt, {
3065
+ ...agentOptions ?? {},
3066
+ tracingContext,
3067
+ requestContext,
3068
+ onFinish: (result) => {
3069
+ handleFinish(result);
3070
+ resolveText(result.text);
3071
+ void safeOnFinish(agentOptions?.onFinish, result, logger);
3072
+ },
3073
+ abortSignal
3074
+ });
3075
+ fullStream = legacyResult.fullStream;
2347
3076
  }
2348
- await pubsub.publish(`workflow.events.v2.${runId}`, {
2349
- type: "watch",
3077
+ if (abortSignal.aborted) {
3078
+ return abort();
3079
+ }
3080
+ const { tripwireChunk } = await processAgentStream({
3081
+ fullStream,
3082
+ isV2Model,
3083
+ pubsub,
2350
3084
  runId,
2351
- data: { type: "tool-call-streaming-finish", ...toolData ?? {} }
3085
+ toolData,
3086
+ logger
2352
3087
  });
3088
+ if (tripwireChunk) {
3089
+ throw createTripWireFromChunk(tripwireChunk);
3090
+ }
3091
+ if (structuredResult !== null) {
3092
+ return structuredResult;
3093
+ }
2353
3094
  return {
2354
- text: await streamPromise.promise
3095
+ text: await textPromise
2355
3096
  };
2356
3097
  },
2357
3098
  component: params.component
@@ -2879,6 +3620,8 @@ var EventedWorkflow = class extends Workflow {
2879
3620
  cleanup: () => this.runs.delete(runIdToUse),
2880
3621
  workflowSteps: this.steps,
2881
3622
  validateInputs: this.options?.validateInputs,
3623
+ inputSchema: this.inputSchema,
3624
+ stateSchema: this.stateSchema,
2882
3625
  workflowEngineType: this.engineType
2883
3626
  });
2884
3627
  this.runs.set(runIdToUse, run);
@@ -2890,6 +3633,9 @@ var EventedWorkflow = class extends Workflow {
2890
3633
  withNestedWorkflows: false
2891
3634
  });
2892
3635
  const existsInStorage = existingRun && !existingRun.isFromInMemory;
3636
+ if (existsInStorage && existingRun.status) {
3637
+ run.workflowRunStatus = existingRun.status;
3638
+ }
2893
3639
  if (!existsInStorage && shouldPersistSnapshot) {
2894
3640
  const workflowsStore = await this.mastra?.getStorage()?.getStore("workflows");
2895
3641
  await workflowsStore?.persistWorkflowSnapshot({
@@ -2944,7 +3690,8 @@ var EventedRun = class extends Run {
2944
3690
  inputData,
2945
3691
  initialState,
2946
3692
  requestContext,
2947
- perStep
3693
+ perStep,
3694
+ outputOptions
2948
3695
  }) {
2949
3696
  if (this.serializedStepGraph.length === 0) {
2950
3697
  throw new Error(
@@ -2984,6 +3731,7 @@ var EventedRun = class extends Run {
2984
3731
  const result = await this.executionEngine.execute({
2985
3732
  workflowId: this.workflowId,
2986
3733
  runId: this.runId,
3734
+ resourceId: this.resourceId,
2987
3735
  graph: this.executionGraph,
2988
3736
  serializedStepGraph: this.serializedStepGraph,
2989
3737
  input: inputDataToUse,
@@ -2992,7 +3740,8 @@ var EventedRun = class extends Run {
2992
3740
  retryConfig: this.retryConfig,
2993
3741
  requestContext,
2994
3742
  abortController: this.abortController,
2995
- perStep
3743
+ perStep,
3744
+ outputOptions
2996
3745
  });
2997
3746
  if (result.status !== "suspended") {
2998
3747
  this.cleanup?.();
@@ -3058,19 +3807,147 @@ var EventedRun = class extends Run {
3058
3807
  });
3059
3808
  return { runId: this.runId };
3060
3809
  }
3061
- // TODO: stream
3062
- async resume(params) {
3063
- let steps = [];
3064
- if (typeof params.step === "string") {
3065
- steps = params.step.split(".");
3066
- } else {
3067
- steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
3068
- (step) => typeof step === "string" ? step : step?.id
3069
- );
3070
- }
3071
- if (steps.length === 0) {
3072
- throw new Error("No steps provided to resume");
3810
+ /**
3811
+ * Starts the workflow execution as a stream, returning a WorkflowRunOutput
3812
+ * with .fullStream for iteration and .result for the final result.
3813
+ */
3814
+ stream({
3815
+ inputData,
3816
+ requestContext,
3817
+ initialState,
3818
+ closeOnSuspend = true,
3819
+ perStep,
3820
+ outputOptions
3821
+ }) {
3822
+ if (this.closeStreamAction && this.streamOutput) {
3823
+ return this.streamOutput;
3073
3824
  }
3825
+ this.closeStreamAction = async () => {
3826
+ };
3827
+ const self = this;
3828
+ const stream = new ReadableStream({
3829
+ async start(controller) {
3830
+ const unwatch = self.watch((event) => {
3831
+ const { type, payload } = event;
3832
+ controller.enqueue({
3833
+ type,
3834
+ runId: self.runId,
3835
+ from: "WORKFLOW" /* WORKFLOW */,
3836
+ payload: {
3837
+ stepName: payload?.id,
3838
+ ...payload
3839
+ }
3840
+ });
3841
+ });
3842
+ self.closeStreamAction = async () => {
3843
+ unwatch();
3844
+ try {
3845
+ if (controller.desiredSize !== null) {
3846
+ controller.close();
3847
+ }
3848
+ } catch (err) {
3849
+ self.mastra?.getLogger()?.error("Error closing stream:", err);
3850
+ }
3851
+ };
3852
+ try {
3853
+ const executionResults = await self.start({
3854
+ inputData,
3855
+ requestContext,
3856
+ initialState,
3857
+ perStep,
3858
+ outputOptions
3859
+ });
3860
+ if (self.streamOutput) {
3861
+ self.streamOutput.updateResults(executionResults);
3862
+ }
3863
+ if (closeOnSuspend) {
3864
+ self.closeStreamAction?.().catch(() => {
3865
+ });
3866
+ } else if (executionResults.status !== "suspended") {
3867
+ self.closeStreamAction?.().catch(() => {
3868
+ });
3869
+ }
3870
+ } catch (err) {
3871
+ self.streamOutput?.rejectResults(err);
3872
+ self.closeStreamAction?.().catch(() => {
3873
+ });
3874
+ }
3875
+ }
3876
+ });
3877
+ this.streamOutput = new WorkflowRunOutput({
3878
+ runId: this.runId,
3879
+ workflowId: this.workflowId,
3880
+ stream
3881
+ });
3882
+ return this.streamOutput;
3883
+ }
3884
+ /**
3885
+ * Resumes a suspended workflow as a stream, returning a WorkflowRunOutput
3886
+ * with .fullStream for iteration and .result for the final result.
3887
+ */
3888
+ resumeStream({
3889
+ step,
3890
+ resumeData,
3891
+ requestContext,
3892
+ perStep,
3893
+ outputOptions
3894
+ } = {}) {
3895
+ this.closeStreamAction = async () => {
3896
+ };
3897
+ const self = this;
3898
+ const stream = new ReadableStream({
3899
+ async start(controller) {
3900
+ const unwatch = self.watch((event) => {
3901
+ const { type, payload } = event;
3902
+ controller.enqueue({
3903
+ type,
3904
+ runId: self.runId,
3905
+ from: "WORKFLOW" /* WORKFLOW */,
3906
+ payload: {
3907
+ stepName: payload?.id,
3908
+ ...payload
3909
+ }
3910
+ });
3911
+ });
3912
+ self.closeStreamAction = async () => {
3913
+ unwatch();
3914
+ try {
3915
+ if (controller.desiredSize !== null) {
3916
+ controller.close();
3917
+ }
3918
+ } catch (err) {
3919
+ self.mastra?.getLogger()?.error("Error closing stream:", err);
3920
+ }
3921
+ };
3922
+ try {
3923
+ const executionResults = await self.resume({
3924
+ resumeData,
3925
+ step,
3926
+ requestContext,
3927
+ perStep,
3928
+ outputOptions
3929
+ });
3930
+ if (self.streamOutput) {
3931
+ self.streamOutput.updateResults(executionResults);
3932
+ }
3933
+ await new Promise((resolve) => setTimeout(resolve, 0));
3934
+ self.closeStreamAction?.().catch(() => {
3935
+ });
3936
+ } catch (err) {
3937
+ self.streamOutput?.rejectResults(err);
3938
+ self.closeStreamAction?.().catch(() => {
3939
+ });
3940
+ }
3941
+ }
3942
+ });
3943
+ this.streamOutput = new WorkflowRunOutput({
3944
+ runId: this.runId,
3945
+ workflowId: this.workflowId,
3946
+ stream
3947
+ });
3948
+ return this.streamOutput;
3949
+ }
3950
+ async resume(params) {
3074
3951
  const workflowsStore = await this.mastra?.getStorage()?.getStore("workflows");
3075
3952
  if (!workflowsStore) {
3076
3953
  throw new Error("Cannot resume workflow: workflows store is required");
@@ -3082,12 +3959,62 @@ var EventedRun = class extends Run {
3082
3959
  if (!snapshot) {
3083
3960
  throw new Error(`Cannot resume workflow: no snapshot found for runId ${this.runId}`);
3084
3961
  }
3085
- const resumePath = snapshot.suspendedPaths?.[steps[0]];
3086
- if (!resumePath) {
3962
+ if (snapshot.status !== "suspended") {
3963
+ throw new Error("This workflow run was not suspended");
3964
+ }
3965
+ const snapshotResumeLabel = params.label ? snapshot?.resumeLabels?.[params.label] : void 0;
3966
+ if (params.label && !snapshotResumeLabel) {
3967
+ const availableLabels = Object.keys(snapshot?.resumeLabels ?? {});
3968
+ throw new Error(
3969
+ `Resume label "${params.label}" not found. Available labels: [${availableLabels.join(", ")}]`
3970
+ );
3971
+ }
3972
+ const stepParam = snapshotResumeLabel?.stepId ?? params.step;
3973
+ let steps;
3974
+ if (stepParam) {
3975
+ if (typeof stepParam === "string") {
3976
+ steps = stepParam.split(".");
3977
+ } else {
3978
+ steps = (Array.isArray(stepParam) ? stepParam : [stepParam]).map(
3979
+ (step) => typeof step === "string" ? step : step?.id
3980
+ );
3981
+ }
3982
+ } else {
3983
+ const suspendedStepPaths = [];
3984
+ Object.entries(snapshot?.suspendedPaths ?? {}).forEach(([stepId, _executionPath]) => {
3985
+ const stepResult = snapshot?.context?.[stepId];
3986
+ if (stepResult && typeof stepResult === "object" && "status" in stepResult) {
3987
+ const stepRes = stepResult;
3988
+ if (stepRes.status === "suspended") {
3989
+ const nestedPath = stepRes.suspendPayload?.__workflow_meta?.path;
3990
+ if (nestedPath && Array.isArray(nestedPath)) {
3991
+ suspendedStepPaths.push([stepId, ...nestedPath]);
3992
+ } else {
3993
+ suspendedStepPaths.push([stepId]);
3994
+ }
3995
+ }
3996
+ }
3997
+ });
3998
+ if (suspendedStepPaths.length === 0) {
3999
+ throw new Error("No suspended steps found in this workflow run");
4000
+ }
4001
+ if (suspendedStepPaths.length === 1) {
4002
+ steps = suspendedStepPaths[0];
4003
+ } else {
4004
+ const pathStrings = suspendedStepPaths.map((path) => `[${path.join(", ")}]`);
4005
+ throw new Error(
4006
+ `Multiple suspended steps found: ${pathStrings.join(", ")}. Please specify which step to resume using the "step" parameter.`
4007
+ );
4008
+ }
4009
+ }
4010
+ const suspendedStepIds = Object.keys(snapshot?.suspendedPaths ?? {});
4011
+ const isStepSuspended = suspendedStepIds.includes(steps?.[0] ?? "");
4012
+ if (!isStepSuspended) {
3087
4013
  throw new Error(
3088
- `No resume path found for step ${JSON.stringify(steps)}, currently suspended paths are ${JSON.stringify(snapshot.suspendedPaths)}`
4014
+ `This workflow step "${steps?.[0]}" was not suspended. Available suspended steps: [${suspendedStepIds.join(", ")}]`
3089
4015
  );
3090
4016
  }
4017
+ const resumePath = snapshot.suspendedPaths?.[steps[0]];
3091
4018
  console.dir(
3092
4019
  { resume: { requestContextObj: snapshot.requestContext, requestContext: params.requestContext } },
3093
4020
  { depth: null }
@@ -3108,22 +4035,26 @@ var EventedRun = class extends Run {
3108
4035
  throw new Error("Mastra instance with pubsub is required for workflow execution");
3109
4036
  }
3110
4037
  this.setupAbortHandler();
4038
+ const resumeState = snapshot?.context?.__state ?? snapshot?.value ?? {};
3111
4039
  const executionResultPromise = this.executionEngine.execute({
3112
4040
  workflowId: this.workflowId,
3113
4041
  runId: this.runId,
3114
4042
  graph: this.executionGraph,
3115
4043
  serializedStepGraph: this.serializedStepGraph,
3116
4044
  input: snapshot?.context?.input,
4045
+ initialState: resumeState,
3117
4046
  resume: {
3118
4047
  steps,
3119
4048
  stepResults: snapshot?.context,
3120
4049
  resumePayload: resumeDataToUse,
3121
- resumePath
4050
+ resumePath,
4051
+ forEachIndex: params.forEachIndex ?? snapshotResumeLabel?.foreachIndex
3122
4052
  },
3123
4053
  pubsub: this.mastra.pubsub,
3124
4054
  requestContext,
3125
4055
  abortController: this.abortController,
3126
- perStep: params.perStep
4056
+ perStep: params.perStep,
4057
+ outputOptions: params.outputOptions
3127
4058
  }).then((result) => {
3128
4059
  if (result.status !== "suspended") {
3129
4060
  this.closeStreamAction?.().catch(() => {
@@ -3178,6 +4109,18 @@ var EventedRun = class extends Run {
3178
4109
  };
3179
4110
 
3180
4111
  // src/workflows/evented/workflow-event-processor/utils.ts
4112
+ function isWorkflowStep(step) {
4113
+ if (!step || typeof step !== "object") {
4114
+ return false;
4115
+ }
4116
+ if (step instanceof EventedWorkflow) {
4117
+ return true;
4118
+ }
4119
+ if ("component" in step && step.component === "WORKFLOW") {
4120
+ return true;
4121
+ }
4122
+ return false;
4123
+ }
3181
4124
  function getNestedWorkflow(mastra, { workflowId, executionPath, parentWorkflow }) {
3182
4125
  let workflow = null;
3183
4126
  if (parentWorkflow) {
@@ -3194,7 +4137,16 @@ function getNestedWorkflow(mastra, { workflowId, executionPath, parentWorkflow }
3194
4137
  parentStep = parentStep.steps[executionPath[1]];
3195
4138
  }
3196
4139
  if (parentStep?.type === "step" || parentStep?.type === "loop") {
3197
- return parentStep.step;
4140
+ if (isWorkflowStep(parentStep.step)) {
4141
+ return parentStep.step;
4142
+ }
4143
+ return null;
4144
+ }
4145
+ if (parentStep?.type === "foreach") {
4146
+ if (isWorkflowStep(parentStep.step)) {
4147
+ return parentStep.step;
4148
+ }
4149
+ return null;
3198
4150
  }
3199
4151
  return null;
3200
4152
  }
@@ -3246,101 +4198,147 @@ var EventedExecutionEngine = class extends ExecutionEngine {
3246
4198
  if (!pubsub) {
3247
4199
  throw new Error("No Pubsub adapter configured on the Mastra instance");
3248
4200
  }
3249
- if (params.resume) {
3250
- const prevStep = getStep(this.mastra.getWorkflow(params.workflowId), params.resume.resumePath);
3251
- const prevResult = params.resume.stepResults[prevStep?.id ?? "input"];
3252
- await pubsub.publish("workflows", {
3253
- type: "workflow.resume",
3254
- runId: params.runId,
3255
- data: {
3256
- workflowId: params.workflowId,
3257
- runId: params.runId,
3258
- executionPath: params.resume.resumePath,
3259
- stepResults: params.resume.stepResults,
3260
- resumeSteps: params.resume.steps,
3261
- prevResult: { status: "success", output: prevResult?.payload },
3262
- resumeData: params.resume.resumePayload,
3263
- requestContext: Object.fromEntries(params.requestContext.entries()),
3264
- format: params.format,
3265
- perStep: params.perStep
4201
+ let resolveResult;
4202
+ let rejectResult;
4203
+ const resultPromise = new Promise((resolve, reject) => {
4204
+ resolveResult = resolve;
4205
+ rejectResult = reject;
4206
+ });
4207
+ const finishCb = async (event, ack) => {
4208
+ if (event.runId !== params.runId) {
4209
+ await ack?.();
4210
+ return;
4211
+ }
4212
+ if (["workflow.end", "workflow.fail", "workflow.suspend"].includes(event.type)) {
4213
+ await ack?.();
4214
+ await pubsub.unsubscribe("workflows-finish", finishCb);
4215
+ if (event.type === "workflow.fail" && event.data.stepResults) {
4216
+ event.data.stepResults = hydrateSerializedStepErrors(event.data.stepResults);
3266
4217
  }
3267
- });
3268
- } else if (params.timeTravel) {
3269
- const prevStep = getStep(this.mastra.getWorkflow(params.workflowId), params.timeTravel.executionPath);
3270
- const prevResult = params.timeTravel.stepResults[prevStep?.id ?? "input"];
3271
- await pubsub.publish("workflows", {
3272
- type: "workflow.start",
3273
- runId: params.runId,
3274
- data: {
3275
- workflowId: params.workflowId,
4218
+ resolveResult(event.data);
4219
+ return;
4220
+ }
4221
+ await ack?.();
4222
+ };
4223
+ try {
4224
+ await pubsub.subscribe("workflows-finish", finishCb);
4225
+ } catch (err) {
4226
+ this.mastra?.getLogger()?.error("Failed to subscribe to workflows-finish:", err);
4227
+ throw err;
4228
+ }
4229
+ try {
4230
+ if (params.resume) {
4231
+ const prevStep = getStep(this.mastra.getWorkflow(params.workflowId), params.resume.resumePath);
4232
+ const prevResult = params.resume.stepResults[prevStep?.id ?? "input"];
4233
+ const resumeState = params.resume.stepResults?.__state ?? params.initialState ?? {};
4234
+ await pubsub.publish("workflows", {
4235
+ type: "workflow.resume",
3276
4236
  runId: params.runId,
3277
- executionPath: params.timeTravel.executionPath,
3278
- stepResults: params.timeTravel.stepResults,
3279
- timeTravel: params.timeTravel,
3280
- prevResult: { status: "success", output: prevResult?.payload },
3281
- requestContext: Object.fromEntries(params.requestContext.entries()),
3282
- format: params.format,
3283
- perStep: params.perStep
3284
- }
3285
- });
3286
- } else {
3287
- await pubsub.publish("workflows", {
3288
- type: "workflow.start",
3289
- runId: params.runId,
3290
- data: {
3291
- workflowId: params.workflowId,
4237
+ data: {
4238
+ workflowId: params.workflowId,
4239
+ runId: params.runId,
4240
+ executionPath: params.resume.resumePath,
4241
+ stepResults: params.resume.stepResults,
4242
+ resumeSteps: params.resume.steps,
4243
+ prevResult: { status: "success", output: prevResult?.payload },
4244
+ resumeData: params.resume.resumePayload,
4245
+ requestContext: Object.fromEntries(params.requestContext.entries()),
4246
+ format: params.format,
4247
+ perStep: params.perStep,
4248
+ initialState: resumeState,
4249
+ state: resumeState,
4250
+ outputOptions: params.outputOptions,
4251
+ forEachIndex: params.resume.forEachIndex
4252
+ }
4253
+ });
4254
+ } else if (params.timeTravel) {
4255
+ const prevStep = getStep(this.mastra.getWorkflow(params.workflowId), params.timeTravel.executionPath);
4256
+ const prevResult = params.timeTravel.stepResults[prevStep?.id ?? "input"];
4257
+ await pubsub.publish("workflows", {
4258
+ type: "workflow.start",
3292
4259
  runId: params.runId,
3293
- prevResult: { status: "success", output: params.input },
3294
- requestContext: Object.fromEntries(params.requestContext.entries()),
3295
- format: params.format,
3296
- perStep: params.perStep
3297
- }
3298
- });
3299
- }
3300
- const resultData = await new Promise((resolve, reject) => {
3301
- const finishCb = async (event, ack) => {
3302
- if (event.runId !== params.runId) {
3303
- await ack?.();
3304
- return;
3305
- }
3306
- if (["workflow.end", "workflow.fail", "workflow.suspend"].includes(event.type)) {
3307
- await ack?.();
3308
- await pubsub.unsubscribe("workflows-finish", finishCb);
3309
- if (event.type === "workflow.fail" && event.data.stepResults) {
3310
- event.data.stepResults = hydrateSerializedStepErrors(event.data.stepResults);
4260
+ data: {
4261
+ workflowId: params.workflowId,
4262
+ runId: params.runId,
4263
+ executionPath: params.timeTravel.executionPath,
4264
+ stepResults: params.timeTravel.stepResults,
4265
+ timeTravel: params.timeTravel,
4266
+ prevResult: { status: "success", output: prevResult?.payload },
4267
+ requestContext: Object.fromEntries(params.requestContext.entries()),
4268
+ format: params.format,
4269
+ perStep: params.perStep
3311
4270
  }
3312
- resolve(event.data);
3313
- return;
3314
- }
3315
- await ack?.();
3316
- };
3317
- pubsub.subscribe("workflows-finish", finishCb).catch((err) => {
3318
- this.mastra?.getLogger()?.error("Failed to subscribe to workflows-finish:", err);
3319
- reject(err);
3320
- });
3321
- });
4271
+ });
4272
+ } else {
4273
+ await pubsub.publish("workflows", {
4274
+ type: "workflow.start",
4275
+ runId: params.runId,
4276
+ data: {
4277
+ workflowId: params.workflowId,
4278
+ runId: params.runId,
4279
+ prevResult: { status: "success", output: params.input },
4280
+ requestContext: Object.fromEntries(params.requestContext.entries()),
4281
+ format: params.format,
4282
+ perStep: params.perStep,
4283
+ initialState: params.initialState,
4284
+ outputOptions: params.outputOptions
4285
+ }
4286
+ });
4287
+ }
4288
+ } catch (err) {
4289
+ await pubsub.unsubscribe("workflows-finish", finishCb);
4290
+ rejectResult(err);
4291
+ throw err;
4292
+ }
4293
+ const resultData = await resultPromise;
4294
+ const finalState = resultData.state ?? resultData.stepResults?.__state ?? params.initialState ?? {};
4295
+ const { __state: _removedState, ...stepResultsWithoutTopLevelState } = resultData.stepResults ?? {};
4296
+ const cleanStepResults = {};
4297
+ for (const [stepId, stepResult] of Object.entries(stepResultsWithoutTopLevelState)) {
4298
+ cleanStepResults[stepId] = cleanStepResult(stepResult);
4299
+ }
3322
4300
  let callbackArg;
3323
4301
  if (resultData.prevResult.status === "failed") {
3324
- callbackArg = {
3325
- status: "failed",
3326
- error: resultData.prevResult.error,
3327
- steps: resultData.stepResults
3328
- };
4302
+ let tripwireData;
4303
+ for (const stepResult of Object.values(cleanStepResults)) {
4304
+ if (stepResult?.status === "failed" && stepResult?.tripwire) {
4305
+ tripwireData = stepResult.tripwire;
4306
+ break;
4307
+ }
4308
+ }
4309
+ if (tripwireData && typeof tripwireData === "object" && "reason" in tripwireData) {
4310
+ callbackArg = {
4311
+ status: "tripwire",
4312
+ steps: cleanStepResults,
4313
+ state: finalState,
4314
+ tripwire: tripwireData
4315
+ };
4316
+ } else {
4317
+ callbackArg = {
4318
+ status: "failed",
4319
+ error: resultData.prevResult.error,
4320
+ steps: cleanStepResults,
4321
+ state: finalState
4322
+ };
4323
+ }
3329
4324
  } else if (resultData.prevResult.status === "suspended") {
3330
4325
  callbackArg = {
3331
4326
  status: "suspended",
3332
- steps: resultData.stepResults
4327
+ steps: cleanStepResults,
4328
+ state: finalState
3333
4329
  };
3334
4330
  } else if (resultData.prevResult.status === "paused" || params.perStep) {
3335
4331
  callbackArg = {
3336
4332
  status: "paused",
3337
- steps: resultData.stepResults
4333
+ steps: cleanStepResults,
4334
+ state: finalState
3338
4335
  };
3339
4336
  } else {
3340
4337
  callbackArg = {
3341
4338
  status: resultData.prevResult.status,
3342
4339
  result: resultData.prevResult?.output,
3343
- steps: resultData.stepResults
4340
+ steps: cleanStepResults,
4341
+ state: finalState
3344
4342
  };
3345
4343
  }
3346
4344
  if (callbackArg.status !== "paused") {
@@ -3349,13 +4347,13 @@ var EventedExecutionEngine = class extends ExecutionEngine {
3349
4347
  result: callbackArg.result,
3350
4348
  error: callbackArg.error,
3351
4349
  steps: callbackArg.steps,
3352
- tripwire: void 0,
4350
+ tripwire: callbackArg.tripwire,
3353
4351
  runId: params.runId,
3354
4352
  workflowId: params.workflowId,
3355
- resourceId: void 0,
4353
+ resourceId: params.resourceId,
3356
4354
  input: params.input,
3357
4355
  requestContext: params.requestContext,
3358
- state: {}
4356
+ state: finalState
3359
4357
  });
3360
4358
  }
3361
4359
  let result;
@@ -3367,16 +4365,43 @@ var EventedExecutionEngine = class extends ExecutionEngine {
3367
4365
  return null;
3368
4366
  }).filter(Boolean);
3369
4367
  result = {
3370
- ...callbackArg,
4368
+ status: callbackArg.status,
4369
+ steps: callbackArg.steps,
3371
4370
  suspended: suspendedSteps
3372
4371
  };
4372
+ } else if (resultData.prevResult.status === "failed") {
4373
+ if (callbackArg.status === "tripwire" && callbackArg.tripwire) {
4374
+ result = {
4375
+ status: "tripwire",
4376
+ tripwire: callbackArg.tripwire,
4377
+ steps: callbackArg.steps
4378
+ };
4379
+ } else {
4380
+ result = {
4381
+ status: callbackArg.status,
4382
+ error: callbackArg.error,
4383
+ steps: callbackArg.steps
4384
+ };
4385
+ }
4386
+ } else if (resultData.prevResult.status === "paused" || params.perStep) {
4387
+ result = {
4388
+ status: "paused",
4389
+ steps: callbackArg.steps
4390
+ };
3373
4391
  } else {
3374
- result = callbackArg;
4392
+ result = {
4393
+ status: callbackArg.status,
4394
+ result: callbackArg.result,
4395
+ steps: callbackArg.steps
4396
+ };
4397
+ }
4398
+ if (params.outputOptions?.includeState) {
4399
+ result.state = finalState;
3375
4400
  }
3376
4401
  return result;
3377
4402
  }
3378
4403
  };
3379
4404
 
3380
4405
  export { EventedExecutionEngine, EventedRun, EventedWorkflow, StepExecutor, WorkflowEventProcessor, cloneStep, cloneWorkflow, createStep, createWorkflow };
3381
- //# sourceMappingURL=chunk-YQMDMIP6.js.map
3382
- //# sourceMappingURL=chunk-YQMDMIP6.js.map
4406
+ //# sourceMappingURL=chunk-FYMM4PKR.js.map
4407
+ //# sourceMappingURL=chunk-FYMM4PKR.js.map