Looping step execution
Setup
npm install @ai-sdk/openai @mastra/core
Define Looping workflow
Defines a workflow which calls the executes a nested workflow until the provided condition is met.
looping-workflow.ts
import { createWorkflow, createStep } from "@mastra/core/workflows/vNext";
import { z } from "zod";
// Step that increments the input value by 1
const incrementStep = createStep({
id: "increment",
inputSchema: z.object({
value: z.number(),
}),
outputSchema: z.object({
value: z.number(),
}),
execute: async ({ inputData }) => {
return { value: inputData.value + 1 };
},
});
// Step that logs the current value (side effect)
const sideEffectStep = createStep({
id: "side-effect",
inputSchema: z.object({
value: z.number(),
}),
outputSchema: z.object({
value: z.number(),
}),
execute: async ({ inputData }) => {
console.log("log", inputData.value);
return { value: inputData.value };
},
});
// Final step that returns the final value
const finalStep = createStep({
id: "final",
inputSchema: z.object({
value: z.number(),
}),
outputSchema: z.object({
value: z.number(),
}),
execute: async ({ inputData }) => {
return { value: inputData.value };
},
});
// Create a workflow that:
// 1. Increments a number until it reaches 10
// 2. Logs each increment (side effect)
// 3. Returns the final value
const workflow = createWorkflow({
id: "increment-workflow",
inputSchema: z.object({
value: z.number(),
}),
outputSchema: z.object({
value: z.number(),
}),
})
.dountil(
// Nested workflow that performs the increment and logging
createWorkflow({
id: "increment-workflow",
inputSchema: z.object({
value: z.number(),
}),
outputSchema: z.object({
value: z.number(),
}),
steps: [incrementStep, sideEffectStep],
})
.then(incrementStep)
.then(sideEffectStep)
.commit(),
// Condition to check if we should stop the loop
async ({ inputData }) => inputData.value >= 10
)
.then(finalStep);
workflow.commit();
export { workflow as incrementWorkflow };
Register Workflow instance with Mastra class
Register the workflow with the mastra instance.
index.ts
import { Mastra } from "@mastra/core/mastra";
import { PinoLogger } from "@mastra/loggers";
import { incrementWorkflow } from "./workflows";
// Initialize Mastra with the increment workflow
// This enables the workflow to be executed
const mastra = new Mastra({
vnext_workflows: {
incrementWorkflow,
},
logger: new PinoLogger({
name: "Mastra",
level: "info",
}),
});
export { mastra };
Execute the workflow
Here, we’ll get the increment workflow from the mastra instance, then create a run and execute the created run with the required inputData.
exec.ts
import { mastra } from "./";
const workflow = mastra.vnext_getWorkflow("incrementWorkflow");
const run = workflow.createRun();
// Start the workflow with initial value 0
// This will increment until reaching 10
const result = await run.start({ inputData: { value: 0 } })
console.dir(result, { depth: null })