@mastra/mcp-docs-server 0.0.5 → 0.0.6-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/.docs/organized/changelogs/%40mastra%2Fastra.md +52 -52
  2. package/.docs/organized/changelogs/%40mastra%2Fchroma.md +50 -50
  3. package/.docs/organized/changelogs/%40mastra%2Fclickhouse.md +11 -0
  4. package/.docs/organized/changelogs/%40mastra%2Fclient-js.md +55 -55
  5. package/.docs/organized/changelogs/%40mastra%2Fcore.md +52 -52
  6. package/.docs/organized/changelogs/%40mastra%2Fdeployer-cloudflare.md +61 -61
  7. package/.docs/organized/changelogs/%40mastra%2Fdeployer-netlify.md +61 -61
  8. package/.docs/organized/changelogs/%40mastra%2Fdeployer-vercel.md +61 -61
  9. package/.docs/organized/changelogs/%40mastra%2Fdeployer.md +61 -61
  10. package/.docs/organized/changelogs/%40mastra%2Fevals.md +51 -51
  11. package/.docs/organized/changelogs/%40mastra%2Ffirecrawl.md +55 -55
  12. package/.docs/organized/changelogs/%40mastra%2Fgithub.md +50 -50
  13. package/.docs/organized/changelogs/%40mastra%2Floggers.md +50 -50
  14. package/.docs/organized/changelogs/%40mastra%2Fmcp-docs-server.md +49 -0
  15. package/.docs/organized/changelogs/%40mastra%2Fmcp.md +50 -50
  16. package/.docs/organized/changelogs/%40mastra%2Fmem0.md +50 -0
  17. package/.docs/organized/changelogs/%40mastra%2Fmemory.md +61 -61
  18. package/.docs/organized/changelogs/%40mastra%2Fpg.md +54 -54
  19. package/.docs/organized/changelogs/%40mastra%2Fpinecone.md +51 -51
  20. package/.docs/organized/changelogs/%40mastra%2Fplayground-ui.md +64 -64
  21. package/.docs/organized/changelogs/%40mastra%2Fqdrant.md +51 -51
  22. package/.docs/organized/changelogs/%40mastra%2Frag.md +52 -52
  23. package/.docs/organized/changelogs/%40mastra%2Fragie.md +50 -50
  24. package/.docs/organized/changelogs/%40mastra%2Fserver.md +302 -0
  25. package/.docs/organized/changelogs/%40mastra%2Fspeech-azure.md +50 -50
  26. package/.docs/organized/changelogs/%40mastra%2Fspeech-deepgram.md +50 -50
  27. package/.docs/organized/changelogs/%40mastra%2Fspeech-elevenlabs.md +50 -50
  28. package/.docs/organized/changelogs/%40mastra%2Fspeech-google.md +51 -51
  29. package/.docs/organized/changelogs/%40mastra%2Fspeech-ibm.md +50 -50
  30. package/.docs/organized/changelogs/%40mastra%2Fspeech-murf.md +50 -50
  31. package/.docs/organized/changelogs/%40mastra%2Fspeech-openai.md +50 -50
  32. package/.docs/organized/changelogs/%40mastra%2Fspeech-playai.md +50 -50
  33. package/.docs/organized/changelogs/%40mastra%2Fspeech-replicate.md +50 -50
  34. package/.docs/organized/changelogs/%40mastra%2Fspeech-speechify.md +50 -50
  35. package/.docs/organized/changelogs/%40mastra%2Fturbopuffer.md +49 -0
  36. package/.docs/organized/changelogs/%40mastra%2Fupstash.md +50 -50
  37. package/.docs/organized/changelogs/%40mastra%2Fvectorize.md +51 -51
  38. package/.docs/organized/changelogs/%40mastra%2Fvoice-azure.md +50 -0
  39. package/.docs/organized/changelogs/%40mastra%2Fvoice-cloudflare.md +50 -0
  40. package/.docs/organized/changelogs/%40mastra%2Fvoice-deepgram.md +51 -51
  41. package/.docs/organized/changelogs/%40mastra%2Fvoice-elevenlabs.md +51 -51
  42. package/.docs/organized/changelogs/%40mastra%2Fvoice-google.md +51 -51
  43. package/.docs/organized/changelogs/%40mastra%2Fvoice-murf.md +51 -51
  44. package/.docs/organized/changelogs/%40mastra%2Fvoice-openai-realtime.md +55 -0
  45. package/.docs/organized/changelogs/%40mastra%2Fvoice-openai.md +51 -51
  46. package/.docs/organized/changelogs/%40mastra%2Fvoice-playai.md +51 -51
  47. package/.docs/organized/changelogs/%40mastra%2Fvoice-sarvam.md +50 -0
  48. package/.docs/organized/changelogs/%40mastra%2Fvoice-speechify.md +51 -51
  49. package/.docs/organized/changelogs/create-mastra.md +18 -18
  50. package/.docs/organized/changelogs/mastra.md +70 -70
  51. package/.docs/organized/code-examples/agent-network.md +53 -0
  52. package/.docs/organized/code-examples/crypto-chatbot.md +3 -3
  53. package/.docs/raw/agents/{02-adding-tools.mdx → adding-tools.mdx} +1 -1
  54. package/.docs/raw/agents/{03-adding-voice.mdx → adding-voice.mdx} +3 -3
  55. package/.docs/raw/agents/{00-overview.mdx → overview.mdx} +4 -4
  56. package/.docs/raw/community/discord.mdx +12 -0
  57. package/.docs/raw/deployment/server.mdx +66 -11
  58. package/.docs/raw/evals/{02-custom-eval.mdx → custom-eval.mdx} +1 -1
  59. package/.docs/raw/evals/{00-overview.mdx → overview.mdx} +3 -3
  60. package/.docs/raw/evals/{01-textual-evals.mdx → textual-evals.mdx} +1 -1
  61. package/.docs/raw/frameworks/{02-ai-sdk.mdx → ai-sdk.mdx} +3 -3
  62. package/.docs/raw/getting-started/installation.mdx +1 -1
  63. package/.docs/raw/index.mdx +4 -4
  64. package/.docs/raw/integrations/index.mdx +1 -1
  65. package/.docs/raw/local-dev/mastra-dev.mdx +1 -1
  66. package/.docs/raw/observability/nextjs-tracing.mdx +43 -37
  67. package/.docs/raw/observability/tracing.mdx +7 -2
  68. package/.docs/raw/rag/chunking-and-embedding.mdx +32 -4
  69. package/.docs/raw/rag/vector-databases.mdx +2 -0
  70. package/.docs/raw/reference/client-js/workflows.mdx +4 -6
  71. package/.docs/raw/reference/memory/Memory.mdx +1 -1
  72. package/.docs/raw/reference/memory/memory-processors.mdx +229 -0
  73. package/.docs/raw/reference/rag/astra.mdx +1 -1
  74. package/.docs/raw/reference/rag/chroma.mdx +1 -1
  75. package/.docs/raw/reference/rag/chunk.mdx +2 -4
  76. package/.docs/raw/reference/rag/document.mdx +2 -4
  77. package/.docs/raw/reference/rag/extract-params.mdx +192 -40
  78. package/.docs/raw/reference/rag/libsql.mdx +1 -1
  79. package/.docs/raw/reference/rag/pg.mdx +1 -1
  80. package/.docs/raw/reference/rag/pinecone.mdx +36 -4
  81. package/.docs/raw/reference/rag/qdrant.mdx +1 -1
  82. package/.docs/raw/reference/rag/turbopuffer.mdx +1 -1
  83. package/.docs/raw/reference/rag/upstash.mdx +1 -1
  84. package/.docs/raw/reference/rag/vectorize.mdx +1 -1
  85. package/.docs/raw/reference/storage/postgresql.mdx +1 -1
  86. package/.docs/raw/reference/workflows/createRun.mdx +1 -1
  87. package/.docs/raw/reference/workflows/resumeWithEvent.mdx +23 -24
  88. package/.docs/raw/reference/workflows/snapshots.mdx +36 -33
  89. package/.docs/raw/reference/workflows/suspend.mdx +0 -10
  90. package/.docs/raw/reference/workflows/watch.mdx +22 -22
  91. package/.docs/raw/storage/overview.mdx +97 -59
  92. package/.docs/raw/voice/overview.mdx +1 -1
  93. package/.docs/raw/voice/speech-to-text.mdx +1 -1
  94. package/.docs/raw/voice/text-to-speech.mdx +1 -1
  95. package/.docs/raw/voice/voice-to-voice.mdx +1 -1
  96. package/.docs/raw/workflows/error-handling.mdx +3 -3
  97. package/.docs/raw/workflows/nested-workflows.mdx +352 -0
  98. package/.docs/raw/workflows/{00-overview.mdx → overview.mdx} +1 -1
  99. package/.docs/raw/workflows/suspend-and-resume.mdx +73 -70
  100. package/package.json +4 -4
  101. package/.docs/raw/agents/02b-discord-mcp-bot.mdx +0 -87
  102. /package/.docs/raw/agents/{01-agent-memory.mdx → agent-memory.mdx} +0 -0
  103. /package/.docs/raw/agents/{02a-mcp-guide.mdx → mcp-guide.mdx} +0 -0
  104. /package/.docs/raw/{faq/index.mdx → community/licensing.mdx} +0 -0
  105. /package/.docs/raw/evals/{03-running-in-ci.mdx → running-in-ci.mdx} +0 -0
  106. /package/.docs/raw/frameworks/{01-next-js.mdx → next-js.mdx} +0 -0
  107. /package/.docs/raw/guides/{03-recruiter.mdx → ai-recruiter.mdx} +0 -0
  108. /package/.docs/raw/guides/{01-chef-michel.mdx → chef-michel.mdx} +0 -0
  109. /package/.docs/raw/guides/{04-research-assistant.mdx → research-assistant.mdx} +0 -0
  110. /package/.docs/raw/guides/{02-stock-agent.mdx → stock-agent.mdx} +0 -0
@@ -0,0 +1,352 @@
1
+ # Nested Workflows
2
+
3
+ Mastra allows you to use workflows as steps within other workflows, enabling you to create modular and reusable workflow components. This feature helps in organizing complex workflows into smaller, manageable pieces and promotes code reuse.
4
+
5
+ It is also visually easier to understand the flow of a workflow when you can see the nested workflows as steps in the parent workflow.
6
+
7
+ ## Basic Usage
8
+
9
+ You can use a workflow as a step directly in another workflow using the `step()` method:
10
+
11
+ ```typescript
12
+ // Create a nested workflow
13
+ const nestedWorkflow = new Workflow({ name: "nested-workflow" })
14
+ .step(stepA)
15
+ .then(stepB)
16
+ .commit();
17
+
18
+ // Use the nested workflow in a parent workflow
19
+ const parentWorkflow = new Workflow({ name: "parent-workflow" })
20
+ .step(nestedWorkflow, {
21
+ variables: {
22
+ city: {
23
+ step: "trigger",
24
+ path: "myTriggerInput",
25
+ },
26
+ },
27
+ })
28
+ .then(stepC)
29
+ .commit();
30
+ ```
31
+
32
+ When a workflow is used as a step:
33
+
34
+ - It is automatically converted to a step using the workflow's name as the step ID
35
+ - The workflow's results are available in the parent workflow's context
36
+ - The nested workflow's steps are executed in their defined order
37
+
38
+ ## Accessing Results
39
+
40
+ Results from a nested workflow are available in the parent workflow's context under the nested workflow's name. The results include all step outputs from the nested workflow:
41
+
42
+ ```typescript
43
+ const { results } = await parentWorkflow.start();
44
+ // Access nested workflow results
45
+ const nestedWorkflowResult = results["nested-workflow"];
46
+ if (nestedWorkflowResult.status === "success") {
47
+ const nestedResults = nestedWorkflowResult.output.results;
48
+ }
49
+ ```
50
+
51
+ ## Control Flow with Nested Workflows
52
+
53
+ Nested workflows support all the control flow features available to regular steps:
54
+
55
+ ### Parallel Execution
56
+
57
+ Multiple nested workflows can be executed in parallel:
58
+
59
+ ```typescript
60
+ parentWorkflow
61
+ .step(nestedWorkflowA)
62
+ .step(nestedWorkflowB)
63
+ .after([nestedWorkflowA, nestedWorkflowB])
64
+ .step(finalStep);
65
+ ```
66
+
67
+ Or using `step()` with an array of workflows:
68
+
69
+ ```typescript
70
+ parentWorkflow.step([nestedWorkflowA, nestedWorkflowB]).then(finalStep);
71
+ ```
72
+
73
+ In this case, `then()` will implicitly wait for all the workflows to finish before executing the final step.
74
+
75
+ ### If-Else Branching
76
+
77
+ Nested workflows can be used in if-else branches using the new syntax that accepts both branches as arguments:
78
+
79
+ ```typescript
80
+ // Create nested workflows for different paths
81
+ const workflowA = new Workflow({ name: "workflow-a" })
82
+ .step(stepA1)
83
+ .then(stepA2)
84
+ .commit();
85
+
86
+ const workflowB = new Workflow({ name: "workflow-b" })
87
+ .step(stepB1)
88
+ .then(stepB2)
89
+ .commit();
90
+
91
+ // Use the new if-else syntax with nested workflows
92
+ parentWorkflow
93
+ .step(initialStep)
94
+ .if(
95
+ async ({ context }) => {
96
+ // Your condition here
97
+ return someCondition;
98
+ },
99
+ workflowA, // if branch
100
+ workflowB, // else branch
101
+ )
102
+ .then(finalStep)
103
+ .commit();
104
+ ```
105
+
106
+ The new syntax is more concise and clearer when working with nested workflows. When the condition is:
107
+
108
+ - `true`: The first workflow (if branch) is executed
109
+ - `false`: The second workflow (else branch) is executed
110
+
111
+ The skipped workflow will have a status of `skipped` in the results:
112
+
113
+ The `.then(finalStep)` call following the if-else block will merge the if and else branches back into a single execution path.
114
+
115
+ ### Looping
116
+
117
+ Nested workflows can use `.until()` and `.while()` loops same as any other step. One interesting new pattern is to pass a workflow directly as the loop-back argument to keep executing that nested workflow until something is true about its results:
118
+
119
+ ```typescript
120
+ parentWorkflow
121
+ .step(firstStep)
122
+ .while(
123
+ ({ context }) =>
124
+ context.getStepResult("nested-workflow").output.results.someField ===
125
+ "someValue",
126
+ nestedWorkflow,
127
+ )
128
+ .step(finalStep)
129
+ .commit();
130
+ ```
131
+
132
+ ## Watching Nested Workflows
133
+
134
+ You can watch the state changes of nested workflows using the `watch` method on the parent workflow. This is useful for monitoring the progress and state transitions of complex workflows:
135
+
136
+ ```typescript
137
+ const parentWorkflow = new Workflow({ name: "parent-workflow" })
138
+ .step([nestedWorkflowA, nestedWorkflowB])
139
+ .then(finalStep)
140
+ .commit();
141
+
142
+ const run = parentWorkflow.createRun();
143
+ const unwatch = parentWorkflow.watch((state) => {
144
+ console.log("Current state:", state.value);
145
+ // Access nested workflow states in state.context
146
+ });
147
+
148
+ await run.start();
149
+ unwatch(); // Stop watching when done
150
+ ```
151
+
152
+ ## Suspending and Resuming
153
+
154
+ Nested workflows support suspension and resumption, allowing you to pause and continue workflow execution at specific points. You can suspend either the entire nested workflow or specific steps within it:
155
+
156
+ ```typescript
157
+ // Define a step that may need to suspend
158
+ const suspendableStep = new Step({
159
+ id: "other",
160
+ description: "Step that may need to suspend",
161
+ execute: async ({ context, suspend }) => {
162
+ if (!wasSuspended) {
163
+ wasSuspended = true;
164
+ await suspend();
165
+ }
166
+ return { other: 26 };
167
+ },
168
+ });
169
+
170
+ // Create a nested workflow with suspendable steps
171
+ const nestedWorkflow = new Workflow({ name: "nested-workflow-a" })
172
+ .step(startStep)
173
+ .then(suspendableStep)
174
+ .then(finalStep)
175
+ .commit();
176
+
177
+ // Use in parent workflow
178
+ const parentWorkflow = new Workflow({ name: "parent-workflow" })
179
+ .step(beginStep)
180
+ .then(nestedWorkflow)
181
+ .then(lastStep)
182
+ .commit();
183
+
184
+ // Start the workflow
185
+ const run = parentWorkflow.createRun();
186
+ const { runId, results } = await run.start({ triggerData: { startValue: 1 } });
187
+
188
+ // Check if a specific step in the nested workflow is suspended
189
+ if (results["nested-workflow-a"].output.results.other.status === "suspended") {
190
+ // Resume the specific suspended step using dot notation
191
+ const resumedResults = await run.resume({
192
+ stepId: "nested-workflow-a.other",
193
+ context: { startValue: 1 },
194
+ });
195
+
196
+ // The resumed results will contain the completed nested workflow
197
+ expect(resumedResults.results["nested-workflow-a"].output.results).toEqual({
198
+ start: { output: { newValue: 1 }, status: "success" },
199
+ other: { output: { other: 26 }, status: "success" },
200
+ final: { output: { finalValue: 27 }, status: "success" },
201
+ });
202
+ }
203
+ ```
204
+
205
+ When resuming a nested workflow:
206
+
207
+ - Use the nested workflow's name as the `stepId` when calling `resume()` to resume the entire workflow
208
+ - Use dot notation (`nested-workflow.step-name`) to resume a specific step within the nested workflow
209
+ - The nested workflow will continue from the suspended step with the provided context
210
+ - You can check the status of specific steps in the nested workflow's results using `results["nested-workflow"].output.results`
211
+
212
+ ## Result Schemas and Mapping
213
+
214
+ Nested workflows can define their result schema and mapping, which helps in type safety and data transformation. This is particularly useful when you want to ensure the nested workflow's output matches a specific structure or when you need to transform the results before they're used in the parent workflow.
215
+
216
+ ```typescript
217
+ // Create a nested workflow with result schema and mapping
218
+ const nestedWorkflow = new Workflow({
219
+ name: "nested-workflow",
220
+ result: {
221
+ schema: z.object({
222
+ total: z.number(),
223
+ items: z.array(
224
+ z.object({
225
+ id: z.string(),
226
+ value: z.number(),
227
+ }),
228
+ ),
229
+ }),
230
+ mapping: {
231
+ // Map values from step results using variables syntax
232
+ total: { step: "step-a", path: "count" },
233
+ items: { step: "step-b", path: "items" },
234
+ },
235
+ },
236
+ })
237
+ .step(stepA)
238
+ .then(stepB)
239
+ .commit();
240
+
241
+ // Use in parent workflow with type-safe results
242
+ const parentWorkflow = new Workflow({ name: "parent-workflow" })
243
+ .step(nestedWorkflow)
244
+ .then(async ({ context }) => {
245
+ const result = context.getStepResult("nested-workflow");
246
+ // TypeScript knows the structure of result
247
+ console.log(result.total); // number
248
+ console.log(result.items); // Array<{ id: string, value: number }>
249
+ return { success: true };
250
+ })
251
+ .commit();
252
+ ```
253
+
254
+ ## Best Practices
255
+
256
+ 1. **Modularity**: Use nested workflows to encapsulate related steps and create reusable workflow components.
257
+ 2. **Naming**: Give nested workflows descriptive names as they will be used as step IDs in the parent workflow.
258
+ 3. **Error Handling**: Nested workflows propagate their errors to the parent workflow, so handle errors appropriately.
259
+ 4. **State Management**: Each nested workflow maintains its own state but can access the parent workflow's context.
260
+ 5. **Suspension**: When using suspension in nested workflows, consider the entire workflow's state and handle resumption appropriately.
261
+
262
+ ## Example
263
+
264
+ Here's a complete example showing various features of nested workflows:
265
+
266
+ ```typescript
267
+ const workflowA = new Workflow({
268
+ name: "workflow-a",
269
+ result: {
270
+ schema: z.object({
271
+ activities: z.string(),
272
+ }),
273
+ mapping: {
274
+ activities: {
275
+ step: planActivities,
276
+ path: "activities",
277
+ },
278
+ },
279
+ },
280
+ })
281
+ .step(fetchWeather)
282
+ .then(planActivities)
283
+ .commit();
284
+
285
+ const workflowB = new Workflow({
286
+ name: "workflow-b",
287
+ result: {
288
+ schema: z.object({
289
+ activities: z.string(),
290
+ }),
291
+ mapping: {
292
+ activities: {
293
+ step: planActivities,
294
+ path: "activities",
295
+ },
296
+ },
297
+ },
298
+ })
299
+ .step(fetchWeather)
300
+ .then(planActivities)
301
+ .commit();
302
+
303
+ const weatherWorkflow = new Workflow({
304
+ name: "weather-workflow",
305
+ triggerSchema: z.object({
306
+ cityA: z.string().describe("The city to get the weather for"),
307
+ cityB: z.string().describe("The city to get the weather for"),
308
+ }),
309
+ result: {
310
+ schema: z.object({
311
+ activitiesA: z.string(),
312
+ activitiesB: z.string(),
313
+ }),
314
+ mapping: {
315
+ activitiesA: {
316
+ step: workflowA,
317
+ path: "result.activities",
318
+ },
319
+ activitiesB: {
320
+ step: workflowB,
321
+ path: "result.activities",
322
+ },
323
+ },
324
+ },
325
+ })
326
+ .step(workflowA, {
327
+ variables: {
328
+ city: {
329
+ step: "trigger",
330
+ path: "cityA",
331
+ },
332
+ },
333
+ })
334
+ .step(workflowB, {
335
+ variables: {
336
+ city: {
337
+ step: "trigger",
338
+ path: "cityB",
339
+ },
340
+ },
341
+ });
342
+
343
+ weatherWorkflow.commit();
344
+ ```
345
+
346
+ In this example:
347
+
348
+ 1. We define schemas for type safety across all workflows
349
+ 2. Each step has proper input and output schemas
350
+ 3. The nested workflows have their own trigger schemas and result mappings
351
+ 4. Data is passed through using variables syntax in the `.step()` calls
352
+ 5. The main workflow combines data from both nested workflows
@@ -162,7 +162,7 @@ You can:
162
162
 
163
163
  ## More Resources
164
164
 
165
- - The [Workflow Guide](../guides/04-recruiter.mdx) in the Guides section is a tutorial that covers the main concepts.
165
+ - The [Workflow Guide](../guides/ai-recruiter.mdx) in the Guides section is a tutorial that covers the main concepts.
166
166
  - [Sequential Steps workflow example](../../examples/workflows/sequential-steps.mdx)
167
167
  - [Parallel Steps workflow example](../../examples/workflows/parallel-steps.mdx)
168
168
  - [Branching Paths workflow example](../../examples/workflows/branching-paths.mdx)
@@ -67,36 +67,36 @@ Here's an example of a workflow with multiple steps that can suspend:
67
67
  ```typescript
68
68
  // Define steps with suspend capability
69
69
  const promptAgentStep = new Step({
70
- id: 'promptAgent',
70
+ id: "promptAgent",
71
71
  execute: async ({ context, suspend }) => {
72
72
  // Some condition that determines if we need to suspend
73
73
  if (needHumanInput) {
74
74
  // Optionally pass payload data that will be stored with suspended state
75
- await suspend({ requestReason: 'Need human input for prompt' });
75
+ await suspend({ requestReason: "Need human input for prompt" });
76
76
  // Code after suspend() will execute when the step is resumed
77
77
  return { modelOutput: context.userInput };
78
78
  }
79
- return { modelOutput: 'AI generated output' };
79
+ return { modelOutput: "AI generated output" };
80
80
  },
81
81
  outputSchema: z.object({ modelOutput: z.string() }),
82
82
  });
83
83
 
84
84
  const improveResponseStep = new Step({
85
- id: 'improveResponse',
85
+ id: "improveResponse",
86
86
  execute: async ({ context, suspend }) => {
87
87
  // Another condition for suspension
88
88
  if (needFurtherRefinement) {
89
89
  await suspend();
90
90
  return { improvedOutput: context.refinedOutput };
91
91
  }
92
- return { improvedOutput: 'Improved output' };
92
+ return { improvedOutput: "Improved output" };
93
93
  },
94
94
  outputSchema: z.object({ improvedOutput: z.string() }),
95
95
  });
96
96
 
97
97
  // Build the workflow
98
98
  const workflow = new Workflow({
99
- name: 'multi-suspend-workflow',
99
+ name: "multi-suspend-workflow",
100
100
  triggerSchema: z.object({ input: z.string() }),
101
101
  });
102
102
 
@@ -108,50 +108,53 @@ workflow
108
108
  .then(evaluateImproved)
109
109
  .commit();
110
110
 
111
- // Register the workflow with Mastra
112
- export const mastra = new Mastra({
113
- workflows: { workflow },
114
- });
111
+ // Register the workflow with Mastra
112
+ export const mastra = new Mastra({
113
+ workflows: { workflow },
114
+ });
115
115
  ```
116
116
 
117
117
  ### Starting and Resuming the Workflow
118
118
 
119
119
  ```typescript
120
120
  // Get the workflow and create a run
121
- const wf = mastra.getWorkflow('multi-suspend-workflow');
121
+ const wf = mastra.getWorkflow("multi-suspend-workflow");
122
122
  const run = wf.createRun();
123
123
 
124
124
  // Start the workflow
125
- const initialResult = await run.start({ triggerData: { input: 'initial input' } });
125
+ const initialResult = await run.start({
126
+ triggerData: { input: "initial input" },
127
+ });
126
128
 
127
- let promptAgentStepResult = initialResult.activePaths.get('promptAgent');
129
+ let promptAgentStepResult = initialResult.activePaths.get("promptAgent");
128
130
  let promptAgentResumeResult = undefined;
129
131
 
130
132
  // Check if a step is suspended
131
- if (promptAgentStepResult?.status === 'suspended') {
132
- console.log('Workflow suspended at promptAgent step');
133
+ if (promptAgentStepResult?.status === "suspended") {
134
+ console.log("Workflow suspended at promptAgent step");
133
135
 
134
136
  // Resume the workflow with new context
135
137
  const resumeResult = await run.resume({
136
- stepId: 'promptAgent',
137
- context: { userInput: 'Human provided input' }
138
+ stepId: "promptAgent",
139
+ context: { userInput: "Human provided input" },
138
140
  });
139
141
 
140
142
  promptAgentResumeResult = resumeResult;
141
143
  }
142
144
 
143
- const improveResponseStepResult = promptAgentResumeResult?.activePaths.get('improveResponse');
145
+ const improveResponseStepResult =
146
+ promptAgentResumeResult?.activePaths.get("improveResponse");
144
147
 
145
- if (improveResponseStepResult?.status === 'suspended') {
146
- console.log('Workflow suspended at improveResponse step');
148
+ if (improveResponseStepResult?.status === "suspended") {
149
+ console.log("Workflow suspended at improveResponse step");
147
150
 
148
151
  // Resume again with different context
149
152
  const finalResult = await run.resume({
150
- stepId: 'improveResponse',
151
- context: { refinedOutput: 'Human refined output' }
153
+ stepId: "improveResponse",
154
+ context: { refinedOutput: "Human refined output" },
152
155
  });
153
156
 
154
- console.log('Workflow completed:', finalResult?.results);
157
+ console.log("Workflow completed:", finalResult?.results);
155
158
  }
156
159
  ```
157
160
 
@@ -174,30 +177,30 @@ Here's how it works:
174
177
  ```typescript
175
178
  // Define steps
176
179
  const getUserInput = new Step({
177
- id: 'getUserInput',
178
- execute: async () => ({ userInput: 'initial input' }),
180
+ id: "getUserInput",
181
+ execute: async () => ({ userInput: "initial input" }),
179
182
  outputSchema: z.object({ userInput: z.string() }),
180
183
  });
181
184
 
182
185
  const processApproval = new Step({
183
- id: 'processApproval',
186
+ id: "processApproval",
184
187
  execute: async ({ context }) => {
185
188
  // Access the event data from the context
186
189
  const approvalData = context.inputData?.resumedEvent;
187
190
  return {
188
191
  approved: approvalData?.approved,
189
- approvedBy: approvalData?.approverName
192
+ approvedBy: approvalData?.approverName,
190
193
  };
191
194
  },
192
195
  outputSchema: z.object({
193
196
  approved: z.boolean(),
194
- approvedBy: z.string()
197
+ approvedBy: z.string(),
195
198
  }),
196
199
  });
197
200
 
198
201
  // Create workflow with event definition
199
202
  const approvalWorkflow = new Workflow({
200
- name: 'approval-workflow',
203
+ name: "approval-workflow",
201
204
  triggerSchema: z.object({ requestId: z.string() }),
202
205
  events: {
203
206
  approvalReceived: {
@@ -212,8 +215,8 @@ const approvalWorkflow = new Workflow({
212
215
  // Build workflow with event-based suspension
213
216
  approvalWorkflow
214
217
  .step(getUserInput)
215
- .afterEvent('approvalReceived') // Workflow will automatically suspend here
216
- .step(processApproval) // This step runs after the event is received
218
+ .afterEvent("approvalReceived") // Workflow will automatically suspend here
219
+ .step(processApproval) // This step runs after the event is received
217
220
  .commit();
218
221
  ```
219
222
 
@@ -221,15 +224,15 @@ approvalWorkflow
221
224
 
222
225
  ```typescript
223
226
  // Get the workflow
224
- const workflow = mastra.getWorkflow('approval-workflow');
227
+ const workflow = mastra.getWorkflow("approval-workflow");
225
228
  const run = workflow.createRun();
226
229
 
227
230
  // Start the workflow
228
231
  const initialResult = await run.start({
229
- triggerData: { requestId: 'request-123' }
232
+ triggerData: { requestId: "request-123" },
230
233
  });
231
234
 
232
- console.log('Workflow started, waiting for approval event');
235
+ console.log("Workflow started, waiting for approval event");
233
236
  console.log(initialResult.results);
234
237
  // Output will show the workflow is suspended at the event step:
235
238
  // {
@@ -238,12 +241,12 @@ console.log(initialResult.results);
238
241
  // }
239
242
 
240
243
  // Later, when the approval event occurs:
241
- const resumeResult = await run.resumeWithEvent('approvalReceived', {
244
+ const resumeResult = await run.resumeWithEvent("approvalReceived", {
242
245
  approved: true,
243
- approverName: 'Jane Doe'
246
+ approverName: "Jane Doe",
244
247
  });
245
248
 
246
- console.log('Workflow resumed with event data:', resumeResult.results);
249
+ console.log("Workflow resumed with event data:", resumeResult.results);
247
250
  // Output will show the completed workflow:
248
251
  // {
249
252
  // getUserInput: { status: 'success', output: { userInput: 'initial input' } },
@@ -277,8 +280,8 @@ When a workflow is suspended using `await suspend()`, Mastra automatically persi
277
280
  By default, Mastra uses LibSQL as its storage engine:
278
281
 
279
282
  ```typescript
280
- import { Mastra } from '@mastra/core/mastra';
281
- import { DefaultStorage } from '@mastra/core/storage/libsql';
283
+ import { Mastra } from "@mastra/core/mastra";
284
+ import { DefaultStorage } from "@mastra/core/storage/libsql";
282
285
 
283
286
  const mastra = new Mastra({
284
287
  storage: new DefaultStorage({
@@ -287,12 +290,13 @@ const mastra = new Mastra({
287
290
  // For production, use a persistent URL:
288
291
  // url: process.env.DATABASE_URL,
289
292
  // authToken: process.env.DATABASE_AUTH_TOKEN, // Optional for authenticated connections
290
- }
293
+ },
291
294
  }),
292
295
  });
293
296
  ```
294
297
 
295
298
  The LibSQL storage can be configured in different modes:
299
+
296
300
  - In-memory database (testing): `:memory:`
297
301
  - File-based database (development): `file:storage.db`
298
302
  - Remote database (production): URLs like `libsql://your-database.turso.io`
@@ -308,7 +312,7 @@ npm install @mastra/upstash
308
312
  ```
309
313
 
310
314
  ```typescript
311
- import { Mastra } from '@mastra/core/mastra';
315
+ import { Mastra } from "@mastra/core/mastra";
312
316
  import { UpstashStore } from "@mastra/upstash";
313
317
 
314
318
  const mastra = new Mastra({
@@ -318,6 +322,7 @@ const mastra = new Mastra({
318
322
  }),
319
323
  });
320
324
  ```
325
+
321
326
  ### Storage Considerations
322
327
 
323
328
  - All storage options support suspend and resume functionality identically
@@ -333,24 +338,22 @@ To handle suspended workflows, use the `watch` method to monitor workflow status
333
338
  import { mastra } from "./index";
334
339
 
335
340
  // Get the workflow
336
- const myWorkflow = mastra.getWorkflow('myWorkflow');
341
+ const myWorkflow = mastra.getWorkflow("myWorkflow");
337
342
  const { start, watch, resume } = myWorkflow.createRun();
338
343
 
339
344
  // Start watching the workflow before executing it
340
- watch(async ({ context, activePaths }) => {
341
- for (const _path of activePaths) {
342
- const stepTwoStatus = context.steps?.stepTwo?.status;
343
- if (stepTwoStatus === 'suspended') {
344
- console.log("Workflow suspended, resuming with new value");
345
-
346
- // Resume the workflow with new context
347
- await resume({
348
- stepId: 'stepTwo',
349
- context: { secondValue: 100 },
350
- });
351
- }
345
+ watch(async ({ activePaths }) => {
346
+ const isStepTwoSuspended = activePaths.get("stepTwo")?.status === "suspended";
347
+ if (isStepTwoSuspended) {
348
+ console.log("Workflow suspended, resuming with new value");
349
+
350
+ // Resume the workflow with new context
351
+ await resume({
352
+ stepId: "stepTwo",
353
+ context: { secondValue: 100 },
354
+ });
352
355
  }
353
- })
356
+ });
354
357
 
355
358
  // Start the workflow execution
356
359
  await start({ triggerData: { inputValue: 45 } });
@@ -364,25 +367,25 @@ You can use the same watching pattern with event-based workflows:
364
367
  const { start, watch, resumeWithEvent } = workflow.createRun();
365
368
 
366
369
  // Watch for suspended event steps
367
- watch(async ({ context, activePaths }) => {
368
- for (const path of activePaths) {
369
- if (path.stepId === '__approvalReceived_event' && path.status === 'suspended') {
370
- console.log("Workflow waiting for approval event");
371
-
372
- // In a real scenario, you would wait for the actual event to occur
373
- // For example, this could be triggered by a webhook or user interaction
374
- setTimeout(async () => {
375
- await resumeWithEvent('approvalReceived', {
376
- approved: true,
377
- approverName: 'Auto Approver',
378
- });
379
- }, 5000); // Simulate event after 5 seconds
380
- }
370
+ watch(async ({ activePaths }) => {
371
+ const isApprovalReceivedSuspended =
372
+ activePaths.get("__approvalReceived_event")?.status === "suspended";
373
+ if (isApprovalReceivedSuspended) {
374
+ console.log("Workflow waiting for approval event");
375
+
376
+ // In a real scenario, you would wait for the actual event to occur
377
+ // For example, this could be triggered by a webhook or user interaction
378
+ setTimeout(async () => {
379
+ await resumeWithEvent("approvalReceived", {
380
+ approved: true,
381
+ approverName: "Auto Approver",
382
+ });
383
+ }, 5000); // Simulate event after 5 seconds
381
384
  }
382
385
  });
383
386
 
384
387
  // Start the workflow
385
- await start({ triggerData: { requestId: 'auto-123' } });
388
+ await start({ triggerData: { requestId: "auto-123" } });
386
389
  ```
387
390
 
388
391
  ## Further Reading