Bootstrap
Implementation Examples
Practical examples and recipes for building agents with the bootstrap plugin
Examples - Building with @elizaos/plugin-bootstrap
This document provides practical examples of building agents using the plugin-bootstrap package.
Basic Agent Setup
Minimal Agent
Copy
Ask AI
import { type Character } from '@elizaos/core';
// Define a minimal character
export const character: Character = {
name: 'Assistant',
description: 'A helpful AI assistant',
plugins: [
'@elizaos/plugin-sql', // For memory storage
'@elizaos/plugin-openai',
'@elizaos/plugin-bootstrap', // Essential for message handling
],
settings: {
secrets: {},
},
system: 'Respond to messages in a helpful and concise manner.',
bio: [
'Provides helpful responses',
'Keeps answers concise and clear',
'Engages in a friendly manner',
],
style: {
all: [
'Be helpful and informative',
'Keep responses concise',
'Use clear language',
],
chat: [
'Be conversational',
'Show understanding',
],
},
};
Custom Character Agent
Copy
Ask AI
import { type Character } from '@elizaos/core';
export const techBotCharacter: Character = {
name: 'TechBot',
description: 'A technical support specialist',
plugins: [
'@elizaos/plugin-bootstrap',
'@elizaos/plugin-sql',
// Add platform plugins as needed
...(process.env.DISCORD_API_TOKEN ? ['@elizaos/plugin-discord'] : []),
],
settings: {
secrets: {},
avatar: 'https://example.com/techbot-avatar.png',
},
system: 'You are a technical support specialist. Provide clear, patient, and detailed assistance with technical issues. Break down complex problems into simple steps.',
bio: [
'Expert in software development and troubleshooting',
'Patient and detail-oriented problem solver',
'Specializes in clear technical communication',
'Helps users at all skill levels',
],
topics: [
'software development',
'debugging',
'technical support',
'programming languages',
'system troubleshooting',
],
style: {
all: [
'Be professional yet friendly',
'Use technical vocabulary but keep it accessible',
'Provide step-by-step guidance',
'Ask clarifying questions when needed',
],
chat: [
'Be patient and understanding',
'Break down complex topics',
'Offer examples when helpful',
],
},
// Custom templates
templates: {
messageHandlerTemplate: `<task>Generate a technical support response as {{agentName}}</task>
{{providers}}
<guidelines>
- Assess the user's technical level from their message
- Consider the complexity of their problem
- Provide appropriate solutions
- Use clear, step-by-step guidance
- Include code examples when relevant
</guidelines>
<output>
<response>
<thought>Analysis of the technical issue</thought>
<text>Your helpful technical response</text>
</response>
</output>`,
shouldRespondTemplate: `<task>Decide if {{agentName}} should respond</task>
{{recentMessages}}
<respond-if>
- User asks a technical question
- User reports an issue or bug
- User needs clarification on technical topics
- Direct mention of {{agentName}}
- Discussion about programming or software
</respond-if>
<ignore-if>
- Casual conversation between others
- Non-technical discussions
- Already resolved issues
</ignore-if>
<output>
<response>
<reasoning>Brief explanation</reasoning>
<action>RESPOND | IGNORE | STOP</action>
</response>
</output>`,
},
};
Custom Actions
Creating a Custom Help Action
Copy
Ask AI
import { Action, ActionExample } from '@elizaos/core';
const helpAction: Action = {
name: 'HELP',
similes: ['SUPPORT', 'ASSIST', 'GUIDE'],
description: 'Provides detailed help on a specific topic',
validate: async (runtime) => {
// Always available
return true;
},
handler: async (runtime, message, state, options, callback) => {
// Extract help topic from message
const topic = extractHelpTopic(message.content.text);
// Get relevant documentation
const helpContent = await getHelpContent(topic);
// Generate response
const response = {
thought: `User needs help with ${topic}`,
text: helpContent,
actions: ['HELP'],
attachments: topic.includes('screenshot')
? [{ url: '/help/screenshots/' + topic + '.png' }]
: [],
};
await callback(response);
return true;
},
examples: [
[
{
name: '{{user}}',
content: { text: 'How do I reset my password?' },
},
{
name: '{{agent}}',
content: {
text: "Here's how to reset your password:\n1. Click 'Forgot Password'\n2. Enter your email\n3. Check your inbox for reset link",
actions: ['HELP'],
},
},
],
],
};
// Add to agent
const agentWithHelp = new AgentRuntime({
character: {
/* ... */
},
plugins: [
bootstrapPlugin,
{
name: 'custom-help',
actions: [helpAction],
},
],
});
Action that Calls External API
Copy
Ask AI
const weatherAction: Action = {
name: 'CHECK_WEATHER',
similes: ['WEATHER', 'FORECAST'],
description: 'Checks current weather for a location',
validate: async (runtime) => {
// Check if API key is configured
return !!runtime.getSetting('WEATHER_API_KEY');
},
handler: async (runtime, message, state, options, callback) => {
const location = extractLocation(message.content.text);
const apiKey = runtime.getSetting('WEATHER_API_KEY');
try {
const response = await fetch(
`https://api.weather.com/v1/current?location=${location}&key=${apiKey}`
);
const weather = await response.json();
await callback({
thought: `Checking weather for ${location}`,
text: `Current weather in ${location}: ${weather.temp}°F, ${weather.condition}`,
actions: ['CHECK_WEATHER'],
metadata: { weather },
});
} catch (error) {
await callback({
thought: `Failed to get weather for ${location}`,
text: "Sorry, I couldn't fetch the weather information right now.",
actions: ['CHECK_WEATHER'],
error: error.message,
});
}
return true;
},
};
Custom Providers
Creating a System Status Provider
Copy
Ask AI
import { Provider } from '@elizaos/core';
const systemStatusProvider: Provider = {
name: 'SYSTEM_STATUS',
description: 'Provides current system status and metrics',
position: 50,
get: async (runtime, message) => {
// Gather system metrics
const metrics = await gatherSystemMetrics();
// Format for prompt
const statusText = `
# System Status
- CPU Usage: ${metrics.cpu}%
- Memory: ${metrics.memory}% used
- Active Users: ${metrics.activeUsers}
- Response Time: ${metrics.avgResponseTime}ms
- Uptime: ${metrics.uptime}
`.trim();
return {
data: metrics,
values: {
cpuUsage: metrics.cpu,
memoryUsage: metrics.memory,
isHealthy: metrics.cpu < 80 && metrics.memory < 90,
},
text: statusText,
};
},
};
// Use in agent
const monitoringAgent = new AgentRuntime({
character: {
name: 'SystemMonitor',
// ...
},
plugins: [
bootstrapPlugin,
{
name: 'monitoring',
providers: [systemStatusProvider],
},
],
});
Context-Aware Provider
Copy
Ask AI
const userPreferencesProvider: Provider = {
name: 'USER_PREFERENCES',
description: 'User preferences and settings',
get: async (runtime, message) => {
const userId = message.entityId;
const prefs = await runtime.getMemories({
tableName: 'preferences',
agentId: runtime.agentId,
entityId: userId,
count: 1,
});
if (!prefs.length) {
return {
data: {},
values: {},
text: 'No user preferences found.',
};
}
const preferences = prefs[0].content;
return {
data: preferences,
values: {
language: preferences.language || 'en',
timezone: preferences.timezone || 'UTC',
notifications: preferences.notifications ?? true,
},
text: `User Preferences:
- Language: ${preferences.language || 'English'}
- Timezone: ${preferences.timezone || 'UTC'}
- Notifications: ${preferences.notifications ? 'Enabled' : 'Disabled'}`,
};
},
};
Custom Evaluators
Creating a Sentiment Analyzer
Copy
Ask AI
import { Evaluator } from '@elizaos/core';
const sentimentEvaluator: Evaluator = {
name: 'SENTIMENT_ANALYSIS',
similes: ['ANALYZE_MOOD', 'CHECK_SENTIMENT'],
description: 'Analyzes conversation sentiment and adjusts agent mood',
validate: async (runtime, message) => {
// Run every 5 messages
const messages = await runtime.getMemories({
tableName: 'messages',
roomId: message.roomId,
count: 5,
});
return messages.length >= 5;
},
handler: async (runtime, message, state) => {
const prompt = `Analyze the sentiment of the recent conversation.
${state.recentMessages}
Provide a sentiment analysis with:
- Overall sentiment (positive/negative/neutral)
- Emotional tone
- Suggested agent mood adjustment`;
const analysis = await runtime.useModel(ModelType.TEXT_SMALL, { prompt });
// Store sentiment data
await runtime.createMemory(
{
entityId: runtime.agentId,
agentId: runtime.agentId,
roomId: message.roomId,
content: {
type: 'sentiment_analysis',
analysis: analysis,
timestamp: Date.now(),
},
},
'analysis'
);
// Adjust agent mood if needed
if (analysis.suggestedMood) {
await runtime.updateCharacterMood(analysis.suggestedMood);
}
return analysis;
},
};
Task Services
Scheduled Daily Summary
Copy
Ask AI
// Register a daily summary task
runtime.registerTaskWorker({
name: 'DAILY_SUMMARY',
validate: async (runtime, message, state) => {
const hour = new Date().getHours();
return hour === 9; // Run at 9 AM
},
execute: async (runtime, options) => {
// Gather yesterday's data
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
const messages = await runtime.getMemories({
tableName: 'messages',
startTime: yesterday.setHours(0, 0, 0, 0),
endTime: yesterday.setHours(23, 59, 59, 999),
});
// Generate summary
const summary = await generateDailySummary(messages);
// Post to main channel
await runtime.emitEvent(EventType.POST_GENERATED, {
runtime,
worldId: options.worldId,
userId: runtime.agentId,
roomId: options.mainChannelId,
source: 'task',
callback: async (content) => {
// Handle posted summary
console.log('Daily summary posted:', content.text);
},
});
},
});
// Create the scheduled task
await runtime.createTask({
name: 'DAILY_SUMMARY',
description: 'Posts daily activity summary',
metadata: {
updateInterval: 1000 * 60 * 60, // Check hourly
worldId: 'main-world',
mainChannelId: 'general',
},
tags: ['queue', 'repeat'],
});
Event-Driven Task
Copy
Ask AI
// Task that triggers on specific events
runtime.registerTaskWorker({
name: 'NEW_USER_WELCOME',
execute: async (runtime, options) => {
const { userId, userName } = options;
// Send welcome message
await runtime.sendMessage({
roomId: options.roomId,
content: {
text: `Welcome ${userName}! 👋 I'm here to help you get started.`,
actions: ['WELCOME'],
},
});
// Schedule follow-up
await runtime.createTask({
name: 'WELCOME_FOLLOWUP',
metadata: {
userId,
executeAt: Date.now() + 1000 * 60 * 60 * 24, // 24 hours later
},
tags: ['queue'],
});
},
});
// Trigger on new user
runtime.on(EventType.ENTITY_JOINED, async (payload) => {
await runtime.createTask({
name: 'NEW_USER_WELCOME',
metadata: {
userId: payload.entityId,
userName: payload.entity.name,
roomId: payload.roomId,
},
tags: ['queue', 'immediate'],
});
});
Complete Bot Example
Support Bot with Custom Features
Copy
Ask AI
import { AgentRuntime, Plugin, EventType, ChannelType } from '@elizaos/core';
import { bootstrapPlugin } from '@elizaos/plugin-bootstrap';
import { sqlitePlugin } from '@elizaos/plugin-sql';
// Custom support plugin
const supportPlugin: Plugin = {
name: 'support-features',
description: 'Custom support bot features',
actions: [
{
name: 'CREATE_TICKET',
similes: ['TICKET', 'ISSUE', 'REPORT'],
description: 'Creates a support ticket',
validate: async (runtime) => true,
handler: async (runtime, message, state, options, callback) => {
const ticket = {
id: generateTicketId(),
userId: message.entityId,
issue: message.content.text,
status: 'open',
createdAt: Date.now(),
};
await runtime.createMemory(
{
entityId: runtime.agentId,
agentId: runtime.agentId,
roomId: message.roomId,
content: {
type: 'ticket',
...ticket,
},
},
'tickets'
);
await callback({
thought: 'Creating support ticket',
text: `I've created ticket #${ticket.id} for your issue. Our team will review it shortly.`,
actions: ['CREATE_TICKET'],
metadata: { ticketId: ticket.id },
});
return true;
},
},
],
providers: [
{
name: 'OPEN_TICKETS',
description: 'Lists open support tickets',
get: async (runtime, message) => {
const tickets = await runtime.getMemories({
tableName: 'tickets',
agentId: runtime.agentId,
filter: { status: 'open' },
count: 10,
});
const ticketList = tickets
.map((t) => `- #${t.content.id}: ${t.content.issue.substring(0, 50)}...`)
.join('\n');
return {
data: { tickets },
values: { openCount: tickets.length },
text: `Open Tickets (${tickets.length}):\n${ticketList}`,
};
},
},
],
evaluators: [
{
name: 'TICKET_ESCALATION',
description: 'Checks if tickets need escalation',
validate: async (runtime, message) => {
// Check every 10 messages
return message.content.type === 'ticket';
},
handler: async (runtime, message, state) => {
const urgentKeywords = ['urgent', 'critical', 'emergency', 'asap'];
const needsEscalation = urgentKeywords.some((word) =>
message.content.text.toLowerCase().includes(word)
);
if (needsEscalation) {
await runtime.emitEvent('TICKET_ESCALATED', {
ticketId: message.content.ticketId,
reason: 'Urgent keywords detected',
});
}
return { escalated: needsEscalation };
},
},
],
services: [],
events: {
[EventType.MESSAGE_RECEIVED]: [
async (payload) => {
// Auto-respond to DMs with ticket creation prompt
const room = await payload.runtime.getRoom(payload.message.roomId);
if (room?.type === ChannelType.DM) {
// Check if this is a new conversation
const messages = await payload.runtime.getMemories({
tableName: 'messages',
roomId: payload.message.roomId,
count: 2,
});
if (messages.length === 1) {
await payload.callback({
text: "Hello! I'm here to help. Would you like to create a support ticket?",
actions: ['GREET'],
suggestions: ['Create ticket', 'Check ticket status', 'Get help'],
});
}
}
},
],
},
};
// Create the support bot
const supportBot = new AgentRuntime({
character: {
name: 'SupportBot',
description: '24/7 customer support specialist',
bio: 'I help users resolve issues and create support tickets',
modelProvider: 'openai',
templates: {
messageHandlerTemplate: `# Support Bot Response
{{providers}}
Guidelines:
- Be empathetic and professional
- Gather all necessary information
- Offer to create tickets for unresolved issues
- Provide ticket numbers for tracking
`,
},
},
plugins: [bootstrapPlugin, sqlitePlugin, supportPlugin],
settings: {
CONVERSATION_LENGTH: 50, // Longer context for support
SHOULD_RESPOND_BYPASS_TYPES: ['dm', 'support', 'ticket'],
},
});
// Start the bot
await supportBot.start();
Integration Examples
Discord Integration
Copy
Ask AI
import { DiscordClient } from '@elizaos/discord';
const discordBot = new AgentRuntime({
character: {
/* ... */
},
plugins: [bootstrapPlugin],
clients: [new DiscordClient()],
});
// Discord-specific room handling
discordBot.on(EventType.MESSAGE_RECEIVED, async (payload) => {
const room = await payload.runtime.getRoom(payload.message.roomId);
// Handle Discord-specific features
if (room?.metadata?.discordType === 'thread') {
// Special handling for threads
}
});
Multi-Platform Bot
Copy
Ask AI
import { DiscordClient } from '@elizaos/discord';
import { TelegramClient } from '@elizaos/telegram';
import { TwitterClient } from '@elizaos/twitter';
const multiPlatformBot = new AgentRuntime({
character: {
name: 'OmniBot',
description: 'Available everywhere',
},
plugins: [
bootstrapPlugin,
{
name: 'platform-adapter',
providers: [
{
name: 'PLATFORM_INFO',
get: async (runtime, message) => {
const source = message.content.source;
const platformTips = {
discord: 'Use /commands for Discord-specific features',
telegram: 'Use inline keyboards for better UX',
twitter: 'Keep responses under 280 characters',
};
return {
data: { platform: source },
values: { isTwitter: source === 'twitter' },
text: `Platform: ${source}\nTip: ${platformTips[source] || 'None'}`,
};
},
},
],
},
],
clients: [new DiscordClient(), new TelegramClient(), new TwitterClient()],
});
Best Practices
- Always include bootstrapPlugin - It’s the foundation
- Use providers for context - Don’t query database in actions
- Chain actions thoughtfully - Order matters
- Handle errors gracefully - Users should get helpful messages
- Test with different scenarios - DMs, groups, mentions
- Monitor evaluator output - Learn from your bot’s analysis
- Configure templates - Match your bot’s personality
Debugging Tips
Copy
Ask AI
// Enable debug logging
process.env.DEBUG = 'elizaos:*';
// Log action execution
const debugAction = {
...originalAction,
handler: async (...args) => {
console.log(`Executing ${debugAction.name}`, args[1].content);
const result = await originalAction.handler(...args);
console.log(`${debugAction.name} completed`, result);
return result;
},
};
// Monitor provider data
runtime.on('state:composed', (state) => {
console.log(
'State providers:',
state.providerData.map((p) => p.providerName)
);
});
// Track message flow
runtime.on(EventType.MESSAGE_RECEIVED, (payload) => {
console.log(`Message flow: ${payload.message.entityId} -> ${payload.runtime.agentId}`);
});
These examples demonstrate the flexibility and power of the plugin-bootstrap system. Start with simple examples and gradually add complexity as needed!
Understanding the Callback Mechanism
Every action handler receives a callback function that sends messages back to the user. Here’s how it works:
Copy
Ask AI
const explainAction: Action = {
name: 'EXPLAIN',
description: 'Explains a concept in detail',
handler: async (runtime, message, state, options, callback) => {
// Extract topic from message
const topic = extractTopic(message.content.text);
// First message - acknowledge the request
await callback({
text: `Let me explain ${topic} for you...`,
actions: ['ACKNOWLEDGE'],
});
// Fetch explanation (simulating delay)
const explanation = await fetchExplanation(topic);
// Second message - deliver the explanation
await callback({
text: explanation,
actions: ['EXPLAIN'],
thought: `Explained ${topic} to the user`,
});
// Third message - offer follow-up
await callback({
text: 'Would you like me to explain anything else about this topic?',
actions: ['FOLLOW_UP'],
});
return true;
},
};
Template Customization Examples
Example 1: Gaming Bot with Custom Templates
Copy
Ask AI
import { AgentRuntime, Character } from '@elizaos/core';
import { bootstrapPlugin } from '@elizaos/plugin-bootstrap';
const gamingBotCharacter: Character = {
name: 'GameMaster',
description: 'A gaming companion and guide',
templates: {
// Custom shouldRespond for gaming context
shouldRespondTemplate: `<task>Decide if {{agentName}} should respond to gaming-related messages.</task>
{{providers}}
<gaming-rules>
- ALWAYS respond to: game questions, strategy requests, team coordination
- RESPOND to: patch notes discussion, build advice, gameplay tips
- IGNORE: off-topic chat, real-world discussions (unless directly asked)
- STOP if: asked to stop giving advice or to be quiet
</gaming-rules>
<output>
<response>
<reasoning>Gaming context assessment</reasoning>
<action>RESPOND | IGNORE | STOP</action>
</response>
</output>`,
// Gaming-focused message handler
messageHandlerTemplate: `<task>Generate gaming advice as {{agentName}}.</task>
{{providers}}
Available actions: {{actionNames}}
<gaming-personality>
- Use gaming terminology naturally
- Reference game mechanics when relevant
- Be encouraging to new players
- Share pro tips for experienced players
- React enthusiastically to achievements
</gaming-personality>
<communication-style>
- Short, punchy responses for in-game chat
- Detailed explanations for strategy questions
- Use gaming emotes and expressions
- Reference popular gaming memes appropriately
</communication-style>
<output>
<response>
<thought>Gaming situation analysis</thought>
<actions>REPLY</actions>
<providers>GAME_STATE,PLAYER_STATS</providers>
<text>Your gaming response</text>
</response>
</output>`,
// Gaming-specific reflection
reflectionTemplate: `<task>Analyze gaming interactions for improvement.</task>
{{recentMessages}}
<gaming-focus>
- Track player skill progression
- Note frequently asked game mechanics
- Identify team dynamics and roles
- Record successful strategies shared
- Monitor player frustration levels
</gaming-focus>
<output>
{
"thought": "Gaming insight",
"facts": [{
"claim": "Gaming fact or strategy",
"type": "strategy|mechanic|meta",
"game": "specific game name"
}],
"playerProfile": {
"skillLevel": "beginner|intermediate|advanced|pro",
"preferredRole": "tank|dps|support|flex",
"interests": ["pvp", "pve", "competitive"]
}
}
</output>`,
},
// Gaming-related bio and style
bio: [
'Expert in multiple game genres',
'Provides real-time strategy advice',
'Helps teams coordinate effectively',
'Explains complex game mechanics simply',
],
style: {
chat: [
'Use gaming slang appropriately',
'Quick responses during matches',
'Detailed guides when asked',
'Supportive and encouraging tone',
],
},
};
// Create the gaming bot
const gamingBot = new AgentRuntime({
character: gamingBotCharacter,
plugins: [bootstrapPlugin],
});
Example 2: Customer Support Bot with Templates
Copy
Ask AI
const supportBotCharacter: Character = {
name: 'SupportAgent',
description: '24/7 customer support specialist',
templates: {
// Support-focused shouldRespond
shouldRespondTemplate: `<task>Determine if {{agentName}} should handle this support request.</task>
{{providers}}
<support-priorities>
PRIORITY 1 (Always respond):
- Error messages or bug reports
- Account issues or login problems
- Payment or billing questions
- Direct help requests
PRIORITY 2 (Respond):
- Feature questions
- How-to requests
- General feedback
PRIORITY 3 (Conditionally respond):
- Complaints (respond with empathy)
- Feature requests (acknowledge and log)
NEVER IGNORE:
- Frustrated customers
- Urgent issues
- Security concerns
</support-priorities>
<output>
<response>
<reasoning>Support priority assessment</reasoning>
<action>RESPOND | ESCALATE | ACKNOWLEDGE</action>
</response>
</output>`,
// Professional support message handler
messageHandlerTemplate: `<task>Provide professional support as {{agentName}}.</task>
{{providers}}
Available actions: {{actionNames}}
<support-guidelines>
- Acknowledge the issue immediately
- Express empathy for any inconvenience
- Provide clear, step-by-step solutions
- Offer alternatives if primary solution unavailable
- Always follow up on open issues
</support-guidelines>
<tone>
- Professional yet friendly
- Patient and understanding
- Solution-oriented
- Proactive in preventing future issues
</tone>
<output>
<response>
<thought>Issue analysis and solution approach</thought>
<actions>REPLY,CREATE_TICKET</actions>
<providers>USER_HISTORY,KNOWLEDGE_BASE,OPEN_TICKETS</providers>
<text>Your support response</text>
</response>
</output>`,
// Support interaction reflection
reflectionTemplate: `<task>Analyze support interaction for quality and improvement.</task>
{{recentMessages}}
<support-metrics>
- Issue resolved: yes/no/escalated
- Customer satisfaction indicators
- Response time and efficiency
- Knowledge gaps identified
- Common issues pattern
</support-metrics>
<output>
{
"thought": "Support interaction analysis",
"resolution": {
"status": "resolved|unresolved|escalated",
"issueType": "technical|billing|account|other",
"satisfactionIndicators": ["positive", "negative", "neutral"]
},
"facts": [{
"claim": "Issue or solution discovered",
"type": "bug|workaround|feature_request",
"frequency": "first_time|recurring|common"
}],
"improvements": ["suggested FAQ entries", "documentation needs"]
}
</output>`,
},
};
Example 3: Educational Bot with Adaptive Templates
Copy
Ask AI
const educatorCharacter: Character = {
name: 'EduBot',
description: 'Adaptive educational assistant',
templates: {
// Education-focused templates with learning level adaptation
messageHandlerTemplate: `<task>Provide educational guidance as {{agentName}}.</task>
{{providers}}
<student-context>
Current Level: {{studentLevel}}
Subject: {{subject}}
Learning Style: {{learningStyle}}
</student-context>
<teaching-approach>
For BEGINNERS:
- Use simple language and analogies
- Break down complex concepts
- Provide many examples
- Check understanding frequently
For INTERMEDIATE:
- Build on existing knowledge
- Introduce technical terminology
- Encourage critical thinking
- Suggest practice problems
For ADVANCED:
- Discuss edge cases and exceptions
- Explore theoretical foundations
- Connect to real-world applications
- Recommend further reading
</teaching-approach>
<output>
<response>
<thought>Pedagogical approach for this student</thought>
<actions>REPLY,GENERATE_QUIZ</actions>
<providers>STUDENT_PROGRESS,CURRICULUM,LEARNING_HISTORY</providers>
<text>Your educational response</text>
</response>
</output>`,
},
};
Advanced Callback Patterns
Progressive Disclosure Pattern
Copy
Ask AI
const teachAction: Action = {
name: 'TEACH_CONCEPT',
handler: async (runtime, message, state, options, callback) => {
const concept = extractConcept(message.content.text);
const userLevel = await getUserLevel(runtime, message.entityId);
if (userLevel === 'beginner') {
// Start with simple explanation
await callback({
text: `Let's start with the basics of ${concept}...`,
actions: ['TEACH_INTRO'],
});
// Add an analogy
await callback({
text: `Think of it like ${getAnalogy(concept)}`,
actions: ['TEACH_ANALOGY'],
});
// Check understanding
await callback({
text: 'Does this make sense so far? Would you like me to explain differently?',
actions: ['CHECK_UNDERSTANDING'],
});
} else {
// Advanced explanation
await callback({
text: `${concept} involves several key principles...`,
actions: ['TEACH_ADVANCED'],
attachments: [
{
url: `/diagrams/${concept}.png`,
contentType: 'image/png',
},
],
});
}
return true;
},
};
Error Recovery Pattern
Copy
Ask AI
const processAction: Action = {
name: 'PROCESS_REQUEST',
handler: async (runtime, message, state, options, callback) => {
try {
// Acknowledge request
await callback({
text: 'Processing your request...',
actions: ['ACKNOWLEDGE'],
});
// Attempt processing
const result = await processUserRequest(message);
// Success response
await callback({
text: `Successfully completed! ${result.summary}`,
actions: ['SUCCESS'],
metadata: { processId: result.id },
});
} catch (error) {
// Error response with helpful information
await callback({
text: 'I encountered an issue processing your request.',
actions: ['ERROR'],
});
// Provide specific error details
if (error.code === 'RATE_LIMIT') {
await callback({
text: "You've exceeded the rate limit. Please try again in a few minutes.",
actions: ['RATE_LIMIT_ERROR'],
});
} else if (error.code === 'INVALID_INPUT') {
await callback({
text: `The input seems invalid. Please check: ${error.details}`,
actions: ['VALIDATION_ERROR'],
});
} else {
// Generic error with support option
await callback({
text: 'An unexpected error occurred. Would you like me to create a support ticket?',
actions: ['OFFER_SUPPORT'],
metadata: { errorId: generateErrorId() },
});
}
}
return true;
},
};
Streaming Response Pattern
Copy
Ask AI
const streamingAction: Action = {
name: 'STREAM_DATA',
handler: async (runtime, message, state, options, callback) => {
const dataStream = await getDataStream(message.content.query);
// Initial response
await callback({
text: 'Streaming data as it arrives...',
actions: ['STREAM_START'],
});
// Stream chunks
for await (const chunk of dataStream) {
await callback({
text: chunk.data,
actions: ['STREAM_CHUNK'],
metadata: {
chunkId: chunk.id,
isPartial: true,
},
});
// Rate limit streaming
await new Promise((resolve) => setTimeout(resolve, 100));
}
// Final summary
await callback({
text: "Streaming complete! Here's a summary of the data...",
actions: ['STREAM_COMPLETE'],
metadata: { totalChunks: dataStream.length },
});
return true;
},
};
Was this page helpful?
On this page
- Examples - Building with @elizaos/plugin-bootstrap
- Basic Agent Setup
- Minimal Agent
- Custom Character Agent
- Custom Actions
- Creating a Custom Help Action
- Action that Calls External API
- Custom Providers
- Creating a System Status Provider
- Context-Aware Provider
- Custom Evaluators
- Creating a Sentiment Analyzer
- Task Services
- Scheduled Daily Summary
- Event-Driven Task
- Complete Bot Example
- Support Bot with Custom Features
- Integration Examples
- Discord Integration
- Multi-Platform Bot
- Best Practices
- Debugging Tips
- Understanding the Callback Mechanism
- Template Customization Examples
- Example 1: Gaming Bot with Custom Templates
- Example 2: Customer Support Bot with Templates
- Example 3: Educational Bot with Adaptive Templates
- Advanced Callback Patterns
- Progressive Disclosure Pattern
- Error Recovery Pattern
- Streaming Response Pattern
Assistant
Responses are generated using AI and may contain mistakes.