Skip to main content

Overview

Stepkit makes it easy to build AI workflows with parallel execution, conditional steps, and composable pipelines. This guide shows practical patterns for integrating AI SDK and building intelligent systems.

Parallel Execution with Conditional Steps

This example shows how to build an AI-powered idea evaluator that runs market research in parallel, then conditionally executes forecasting based on market size.
import { openai } from '@ai-sdk/openai'
import { generateText } from 'ai'

const evaluator = stepkit<{ idea: string }>()
  // Run market signals in parallel
  .step(
    'gather-market-signals',
    async ({ idea }) => ({ marketSize: await fetchMarketSize(idea) }),
    async ({ idea }) => ({ competitors: await fetchCompetitors(idea) }),
  )
  // Conditional: only run forecasting when the market is large
  .step(
    { name: 'run-forecast', condition: ({ marketSize }) => marketSize === 'large' },
    async ({ idea }) => ({ forecast: await forecastROI(idea) }),
  )
  .step('evaluate', async ({ idea, marketSize, competitors, forecast }) => {
    const { text } = await generateText({
      model: openai('gpt-4.1'),
      prompt: `Rate this idea (1-10): "${idea}"\nMarket: ${marketSize}\nCompetitors: ${competitors.length}\nForecast: ${forecast ?? 'n/a'}`,
    })
    return { evaluation: text }
  })

await evaluator.run({ idea: 'AI-powered plant waterer' })

Key Features

  • Parallel execution: Market size and competitor research run simultaneously
  • Conditional steps: Forecasting only runs when the market is large
  • Type safety: Context flows through each step with full TypeScript support
  • AI SDK integration: Works seamlessly with Vercel AI SDK
Use { parallelMode: 'settled' } on a step to continue merging successful parallel outputs even if some functions fail.

Composable AI Pipelines

Build reusable pipeline components that can be composed together with full type safety.
import { StepOutput } from 'stepkit'

// Classify input
const classify = stepkit<{ prompt: string }>()
  .step('classify', async ({ prompt }) => {
    const { text } = await generateText({
      model: openai('gpt-4.1'),
      prompt: `Is this a question or statement? One word.\n\n${prompt}`,
    })
    return { type: text.trim().toLowerCase() }
  })

// Extract type for reusable branches
type Classified = StepOutput<typeof classify, 'classify'>

// Reusable pipelines (can live in separate files)
const handleQuestion = stepkit<Classified>()
  .step('answer', async ({ prompt }) => {
    const { text } = await generateText({
      model: openai('gpt-4.1'),
      prompt: `Answer: ${prompt}`,
    })
    return { response: text }
  })

const handleStatement = stepkit<Classified>()
  .step('acknowledge', () => ({ response: 'Thanks for sharing!' }))

// Compose with full type safety (branch)
const responder = classify
  .branchOn(
    {
      name: 'question',
      when: ({ type }) => type === 'question',
      then: handleQuestion,
    },
    { name: 'statement', default: handleStatement },
  )
  .step('finalize', ({ response }) => ({ done: true, response }))

await responder.run({ prompt: 'What is AI?' })

Benefits of Composition

  • Reusability: Define pipelines once, use them in multiple places
  • Type extraction: Use StepOutput to extract types between pipelines
  • Separation of concerns: Keep different workflows in separate files
  • Full type safety: TypeScript validates the entire composed pipeline

Content Moderation

Build branching logic for content safety workflows

Human Approval

Implement checkpoint-based approval flows

Build docs developers (and LLMs) love