Using WorkflowDrivenAgent
Introduction
The WorkflowDrivenAgent is a specialized agent that executes workflows instead of using LLM-based reasoning. This agent maintains workflow state and can handle suspension and resumption operations for long-running workflows. Unlike standard agents, WorkflowDrivenAgent focuses on deterministic, step-by-step execution while still allowing you to use LLM SDKs within workflow steps.
For a conceptual overview, see WorkflowDrivenAgent.
Our documentation is available in an LLM-friendly format at docs.kaibanjs.com/llms-full.txt. Feed this URL directly into your AI IDE or coding assistant for enhanced development support!
Features
- Workflow Execution: Executes workflows defined using the
@kaibanjs/workflowpackage - State Management: Maintains workflow state between executions
- Suspension and Resumption: Supports workflows that can be suspended and resumed
- Team Compatibility: Integrates seamlessly with the existing team system
- Error Handling: Robust error handling with detailed logging
- Real-time Logging: Specific logs for workflow events mixed with general team logs
- LLM SDK Integration: Use LangChain, AI SDK, or other LLM libraries within workflow steps
Installation
First, ensure you have the required packages installed:
npm install kaibanjs @kaibanjs/workflow zod
Or with pnpm:
pnpm install kaibanjs @kaibanjs/workflow zod
For LLM SDK integration, you may also need:
npm install @langchain/openai @langchain/community @ai-sdk/openai ai
Basic Usage
Creating a WorkflowDrivenAgent
import { Agent } from 'kaibanjs';
import { createStep, createWorkflow } from '@kaibanjs/workflow';
import { z } from 'zod';
// Create workflow steps
const processStep = createStep({
id: 'process',
inputSchema: z.object({ data: z.string() }),
outputSchema: z.object({ result: z.string() }),
execute: async ({ inputData }) => {
const { data } = inputData as { data: string };
return { result: data.toUpperCase() };
}
});
// Create the workflow
const workflow = createWorkflow({
id: 'example-workflow',
inputSchema: z.object({ data: z.string() }),
outputSchema: z.object({ result: z.string() })
});
workflow.then(processStep);
workflow.commit();
// Create the WorkflowDrivenAgent using the Agent wrapper
const agent = new Agent({
type: 'WorkflowDrivenAgent',
name: 'Workflow Agent',
workflow: workflow
});
// The agent will be automatically initialized when assigned to a team
Using the Agent in a Team
The WorkflowDrivenAgent integrates seamlessly with the existing team system:
import { Agent, Task, Team } from 'kaibanjs';
const team = new Team({
name: 'Workflow Team',
agents: [
new Agent({
type: 'WorkflowDrivenAgent',
name: 'Data Processor',
workflow: workflow
}),
new Agent({
type: 'ReactChampionAgent',
name: 'Analyst',
role: 'Analyze results',
goal: 'Provide insights on processed data',
background: 'Data analysis expert'
})
],
tasks: [
new Task({
description: 'Process the input data using workflow',
expectedOutput: 'Processed data result',
agent: 'Data Processor'
}),
new Task({
description: 'Analyze the processed data',
expectedOutput: 'Analysis insights',
agent: 'Analyst'
})
]
});
// Execute the team
const result = await team.start({ data: 'input data' });
Using LLM SDKs in Workflow Steps
One of the powerful features of WorkflowDrivenAgent is the ability to use LLM SDKs (like LangChain, AI SDK, etc.) within workflow steps. This allows you to combine deterministic workflow orchestration with LLM-powered steps.
Example: LangChain + AI SDK Integration
Here's a complete example showing how to use both LangChain and Vercel AI SDK within a workflow:
import { Agent, Task, Team } from 'kaibanjs';
import { createStep, createWorkflow } from '@kaibanjs/workflow';
import { z } from 'zod';
import { ChatOpenAI } from '@langchain/openai';
import { TavilySearchResults } from '@langchain/community/tools/tavily_search';
import { AgentExecutor, createToolCallingAgent } from 'langchain/agents';
import {
ChatPromptTemplate,
MessagesPlaceholder,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate
} from '@langchain/core/prompts';
import { generateText } from 'ai';
import { createOpenAI } from '@ai-sdk/openai';
const openai = createOpenAI({
apiKey: process.env.OPENAI_API_KEY || ''
});
// Step 1: LangChain-based search agent
const searchStep = createStep({
id: 'search',
inputSchema: z.object({ query: z.string() }),
outputSchema: z.object({
searchResults: z.string(),
sources: z.array(z.string())
}),
execute: async ({ inputData }) => {
const { query } = inputData;
// Create search tool
const searchTool = new TavilySearchResults({
apiKey: process.env.TAVILY_API_KEY || ''
});
// Create search agent with LangChain
const model = new ChatOpenAI({
modelName: 'gpt-4o-mini',
temperature: 0,
apiKey: process.env.OPENAI_API_KEY || ''
});
const prompt = ChatPromptTemplate.fromMessages([
SystemMessagePromptTemplate.fromTemplate(
`You are a search agent that helps find relevant information on the internet.
Your task is to search for information about the given topic and return the most relevant results.
Be thorough and comprehensive in your search.
Focus on finding factual, up-to-date information.`
),
HumanMessagePromptTemplate.fromTemplate('{input}'),
new MessagesPlaceholder('agent_scratchpad')
]);
const agent = createToolCallingAgent({
llm: model,
tools: [searchTool],
prompt
});
const agentExecutor = new AgentExecutor({
agent,
tools: [searchTool]
});
const result = await agentExecutor.invoke({
input: query
});
// Extract sources from the search results
const sources =
result.intermediateSteps?.map(
step => step.action?.toolInput?.query || 'Unknown source'
) || [];
return {
searchResults: result.output,
sources: sources.slice(0, 5) // Limit to 5 sources
};
}
});
// Step 2: AI SDK-based analysis and summarization
const analyzeStep = createStep({
id: 'analyze',
inputSchema: z.object({
searchResults: z.string(),
sources: z.array(z.string())
}),
outputSchema: z.object({
analysis: z.string(),
keyPoints: z.array(z.string()),
summary: z.string(),
confidence: z.number()
}),
execute: async ({ inputData, getInitData }) => {
const { searchResults, sources } = inputData;
const { query } = getInitData();
// Use Vercel AI SDK for analysis
const { text: response } = await generateText({
model: openai('gpt-4o-mini'),
system: `You are an expert analyst that processes search results and provides comprehensive analysis.
Your task is to:
1. Analyze the search results for the query: "${query}"
2. Extract key points and insights
3. Provide a concise summary
4. Assess the confidence level of the information (0-1 scale)
Be objective, factual, and highlight the most important information.`,
prompt: `Search Results: ${searchResults}
Sources: ${sources.join(', ')}
Please provide:
1. A detailed analysis of the findings
2. Key points as a bulleted list
3. A concise summary
4. Confidence level (0-1)`,
temperature: 0.3
});
// Parse the response to extract structured data
const analysis =
response
.split('\n')
.find(
line => line.includes('Analysis:') || line.includes('analysis:')
) || response;
const keyPointsMatch = response.match(
/Key Points?:?\s*([\s\S]*?)(?=Summary:|$)/i
);
const summaryMatch = response.match(
/Summary:?\s*([\s\S]*?)(?=Confidence:|$)/i
);
const confidenceMatch = response.match(/Confidence:?\s*([0-9.]+)/i);
const keyPoints = keyPointsMatch
? keyPointsMatch[1]
.split('\n')
.filter(
line => line.trim().startsWith('-') || line.trim().startsWith('•')
)
.map(point => point.replace(/^[-•]\s*/, '').trim())
.filter(point => point.length > 0)
: ['No key points extracted'];
const summary = summaryMatch
? summaryMatch[1].trim()
: 'Summary not available';
const confidence = confidenceMatch ? parseFloat(confidenceMatch[1]) : 0.7;
return {
analysis: analysis.replace(/Analysis:?\s*/i, '').trim(),
keyPoints: keyPoints.slice(0, 5), // Limit to 5 key points
summary,
confidence: Math.min(Math.max(confidence, 0), 1) // Ensure between 0 and 1
};
}
});
// Create the workflow
const researchWorkflow = createWorkflow({
id: 'research-workflow',
inputSchema: z.object({ query: z.string() }),
outputSchema: z.object({
analysis: z.string(),
keyPoints: z.array(z.string()),
summary: z.string(),
confidence: z.number(),
sources: z.array(z.string())
})
});
// Build the workflow: search -> analyze
researchWorkflow.then(searchStep).then(analyzeStep);
researchWorkflow.commit();
// Define the workflow-driven agent
const researchAgent = new Agent({
name: 'Research Agent',
type: 'WorkflowDrivenAgent',
workflow: researchWorkflow
});
// Define the LLM-based insights agent
const insightsAgent = new Agent({
name: 'Insights Generator',
role: 'Research Insights Expert',
goal: 'Generate additional insights and recommendations based on research findings',
background:
'Expert in research analysis, trend identification, and strategic recommendations',
type: 'ReactChampionAgent',
tools: []
});
// Create a mixed team
const team = new Team({
name: 'Research Team',
agents: [researchAgent, insightsAgent],
tasks: [
new Task({
description: 'Research and analyze information about: {query}',
expectedOutput:
'Comprehensive research analysis with key points, summary, and confidence assessment',
agent: researchAgent
}),
new Task({
description:
'Generate strategic insights and recommendations based on the research findings',
expectedOutput:
'Strategic insights, recommendations, and actionable next steps',
agent: insightsAgent
})
],
env: {
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
TAVILY_API_KEY: process.env.TAVILY_API_KEY
}
});
Benefits of Using LLM SDKs in Workflows
- Flexibility: Use any LLM SDK (LangChain, AI SDK, OpenAI SDK, etc.) within workflow steps
- Type Safety: Maintain type safety with Zod schemas for inputs and outputs
- Orchestration: Combine multiple LLM calls in a structured, deterministic workflow
- Error Handling: Built-in error handling and retry logic at the workflow level
- State Management: Track the state of complex LLM-powered workflows
- Monitoring: Real-time logging and monitoring of each step in the workflow