Step class
The Step class defines individual units of work within a workflow, encapsulating execution logic, data validation, and input/output handling. It can take either a tool or an agent as a parameter to automatically create a step from them.
Usage exampleDirect link to Usage example
import { createWorkflow, createStep } from '@mastra/core/workflows'
import { z } from 'zod'
const step1 = createStep({
id: 'step-1',
description: 'passes value from input to output',
inputSchema: z.object({
value: z.number(),
}),
outputSchema: z.object({
value: z.number(),
}),
execute: async ({ inputData }) => {
const { value } = inputData
return {
value,
}
},
})
Define schemasDirect link to Define schemas
You can define the step's inputSchema and outputSchema with any library that supports Standard JSON Schema. This includes libraries like Zod, Valibot, and ArkType.
- Zod
- Valibot
- ArkType
import { createStep } from '@mastra/core/workflows'
import { z } from 'zod'
const step1 = createStep({
id: 'step-1',
inputSchema: z.object({
message: z.string(),
}),
outputSchema: z.object({
formatted: z.string(),
}),
execute: async ({ inputData }) => {
const { message } = inputData
return {
formatted: message.toUpperCase(),
}
},
})
import { createStep } from '@mastra/core/workflows'
import * as v from 'valibot'
import { toStandardJsonSchema } from '@valibot/to-json-schema'
const step1 = createStep({
id: 'step-1',
inputSchema: toStandardJsonSchema(
v.object({
message: v.string(),
}),
),
outputSchema: toStandardJsonSchema(
v.object({
formatted: v.string(),
}),
),
execute: async ({ inputData }) => {
const { message } = inputData
return {
formatted: message.toUpperCase(),
}
},
})
import { createStep } from '@mastra/core/workflows'
import { type } from 'arktype'
const step1 = createStep({
id: 'step-1',
inputSchema: type({
message: 'string',
}),
outputSchema: type({
formatted: 'string',
}),
execute: async ({ inputData }) => {
const { message } = inputData
return {
formatted: message.toUpperCase(),
}
},
})
Creating steps from agentsDirect link to Creating steps from agents
You can create a step directly from an agent. The step will use the agent's name as its ID.
Basic agent stepDirect link to Basic agent step
import { testAgent } from '../agents/test-agent'
const agentStep = createStep(testAgent)
// inputSchema: { prompt: string }
// outputSchema: { text: string }
Agent step with structured outputDirect link to Agent step with structured output
Pass structuredOutput to have the agent return typed structured data:
const articleSchema = z.object({
title: z.string(),
summary: z.string(),
tags: z.array(z.string()),
})
const agentStep = createStep(testAgent, {
structuredOutput: { schema: articleSchema },
})
// inputSchema: { prompt: string }
// outputSchema: { title: string, summary: string, tags: string[] }
Agent step optionsDirect link to Agent step options
structuredOutput:
onFinish:
Constructor parametersDirect link to Constructor parameters
id:
description:
inputSchema:
outputSchema:
resumeSchema:
suspendSchema:
stateSchema:
requestContextSchema:
execute:
inputData:
resumeData:
suspendData:
mastra:
getStepResult:
getInitData:
suspend:
state:
setState:
runId:
requestContext?:
retryCount?:
scorers:
{ [name]: { scorer, sampling? } }, or a function that returns one. Scoring runs asynchronously and doesn't block the workflow. See Scoring step output.retries:
execute function if it throws.metadata:
Scoring step outputDirect link to Scoring step output
Attach scorers to a step to evaluate that step's output automatically, at the point it runs, instead of only scoring the workflow's final answer. This is useful for multi-step and RAG workflows, where you want to see which step degraded quality, for example whether a retrieval step returned relevant chunks before later steps reason over them.
Each scorer receives the step's own input and output. Scoring runs asynchronously after the step succeeds, and the result is stored against the step's trace. Use sampling to control how often a scorer runs.
The following example attaches a scorer to a retrieval step so every execution is scored:
import { createStep } from '@mastra/core/workflows'
import { z } from 'zod'
import { retrievalRelevanceScorer } from '../scorers/retrieval-relevance'
const retrievalStep = createStep({
id: 'retrieval',
inputSchema: z.object({ query: z.string() }),
outputSchema: z.object({ query: z.string(), chunks: z.array(z.string()) }),
scorers: {
retrievalRelevance: {
scorer: retrievalRelevanceScorer(),
sampling: { type: 'ratio', rate: 1 },
},
},
execute: async ({ inputData }) => {
const chunks = await retrieve(inputData.query)
return { query: inputData.query, chunks }
},
})
Attach a scorer to each step you want to measure to build per-step scores across a multi-step workflow. Because scoring is scoped to a single step, you don't need a dedicated cross-step metric to see where quality changes.
Agent and tool steps added with Workflow.agent() and Workflow.tool() accept the same scorers option in their step options.
Visit the Scorers overview to learn how live evaluations run and where results are stored, and Custom scorers to build your own.