Skip to Content
ExamplesWorkflows (vNext)Human in the Loop

Human in the Loop Workflow ✅

Human-in-the-loop workflows allow you to pause execution at specific points to collect user input, make decisions, or perform actions that require human judgment. This example demonstrates how to create a workflow with human intervention points.

Define Agents ✅

Define the travel agents.

agents/travel-agents.ts
import { Agent } from '@kastrax/core/agent' import { openai } from '@ai-sdk/openai' const llm = openai('gpt-4o') export const summaryAgent = new Agent({ name: 'summaryTravelAgent', model: llm, instructions: ` You are a travel agent who is given a user prompt about what kind of holiday they want to go on. You then generate 3 different options for the holiday. Return the suggestions as a JSON array {"location": "string", "description": "string"}[]. Don't format as markdown. Make the options as different as possible from each other. Also make the plan very short and summarized. `, }) export const travelAgent = new Agent({ name: 'travelAgent', model: llm, instructions: ` You are a travel agent who is given a user prompt about what kind of holiday they want to go on. A summary of the plan is provided as well as the location. You then generate a detailed travel plan for the holiday. `, })

Define Suspendable workflow ✅

Defines a workflow which includes a suspending step: humanInputStep.

workflows/human-in-the-loop-workflow.ts
import { createWorkflow, createStep } from '@kastrax/core/workflows/vNext' import { z } from 'zod' const generateSuggestionsStep = createStep({ id: 'generate-suggestions', inputSchema: z.object({ vacationDescription: z.string().describe('The description of the vacation'), }), outputSchema: z.object({ suggestions: z.array(z.string()), vacationDescription: z.string(), }), execute: async ({ inputData, kastrax, container }) => { if (!kastrax) { throw new Error('Kastrax is not initialized') } const { vacationDescription } = inputData const result = await kastrax.getAgent('summaryTravelAgent').generate([ { role: 'user', content: vacationDescription, }, ]) console.log(result.text) return { suggestions: JSON.parse(result.text), vacationDescription } }, }) const humanInputStep = createStep({ id: 'human-input', inputSchema: z.object({ suggestions: z.array(z.string()), vacationDescription: z.string(), }), outputSchema: z.object({ selection: z.string().describe('The selection of the user'), vacationDescription: z.string(), }), resumeSchema: z.object({ selection: z.string().describe('The selection of the user'), }), suspendSchema: z.object({ suggestions: z.array(z.string()), }), execute: async ({ inputData, resumeData, suspend, getInitData }) => { if (!resumeData?.selection) { await suspend({ suggestions: inputData?.suggestions }) return { selection: '', vacationDescription: inputData?.vacationDescription, } } return { selection: resumeData?.selection, vacationDescription: inputData?.vacationDescription, } }, }) const travelPlannerStep = createStep({ id: 'travel-planner', inputSchema: z.object({ selection: z.string().describe('The selection of the user'), vacationDescription: z.string(), }), outputSchema: z.object({ travelPlan: z.string(), }), execute: async ({ inputData, kastrax }) => { const travelAgent = kastrax?.getAgent('travelAgent') if (!travelAgent) { throw new Error('Travel agent is not initialized') } const { selection, vacationDescription } = inputData const result = await travelAgent.generate([ { role: 'assistant', content: vacationDescription }, { role: 'user', content: selection || '' }, ]) console.log(result.text) return { travelPlan: result.text } }, }) const weatherWorkflow = createWorkflow({ id: 'weather-workflow', inputSchema: z.object({ vacationDescription: z.string().describe('The description of the vacation'), }), outputSchema: z.object({ travelPlan: z.string(), }), }) .then(generateSuggestionsStep) .then(humanInputStep) .then(travelPlannerStep) travelAgentWorkflow.commit() export { weatherWorkflow, humanInputStep }

Register Agent and Workflow instances with Kastrax class ✅

Register the agents and the weather workflow with the kastrax instance. This is critical for enabling access to the agents within the workflow.

index.ts
import { Kastrax } from '@kastrax/core/kastrax' import { createLogger } from '@kastrax/core/logger' import { weatherWorkflow } from './workflows' import { travelAgent, summaryAgent } from './agents' const kastrax = new Kastrax({ vnext_workflows: { weatherWorkflow, }, agents: { travelAgent, summaryAgent }, logger: createLogger({ name: 'Kastrax', level: 'info', }), }) export { kastrax }

Execute the suspendable weather workflow ✅

Here, we’ll get the weather workflow from the kastrax instance, then create a run and execute the created run with the required inputData. In addition to this, we’ll resume the humanInputStep after collecting user input with the readline package.

exec.ts
import { kastrax } from "./" import { createInterface } from 'readline' import { humanInputStep } from './workflows' const workflow = kastrax.vnext_getWorkflow('weather-workflow') const run = workflow.createRun({}) const result = await run.start({ inputData: { vacationDescription: 'I want to go to the beach' }, }) console.log('result', result) const suggStep = result?.steps?.['generate-suggestions'] if (suggStep.status === 'success') { const suggestions = suggStep.output?.suggestions console.log( suggestions .map(({ location, description }) => `- ${location}: ${description}`) .join('\n') ) const userInput = await readInput() console.log('Selected:', userInput) console.log('resuming from', result, 'with', { inputData: { selection: userInput, vacationDescription: 'I want to go to the beach', suggestions: suggStep?.output?.suggestions, }, step: humanInputStep, }) const result2 = await run.resume({ resumeData: { selection: userInput, vacationDescription: 'I want to go to the beach', suggestions: suggStep?.output?.suggestions, }, step: humanInputStep, }) console.dir(result2, { depth: null }) }

Human-in-the-loop workflows are powerful for building systems that blend automation with human judgment, such as:

  • Content moderation systems
  • Approval workflows
  • Supervised AI systems
  • Customer service automation with escalation





View Example on GitHub
Last updated on