From Character configuration to live Agent execution in elizaOS
AgentRuntime
. For character structure details, see Character Interface.
// From TypeScript file
import { character } from './character';
// From JSON file
import characterJson from './character.json';
// From environment
const character = {
name: process.env.AGENT_NAME || 'DefaultAgent',
bio: process.env.AGENT_BIO || 'A helpful assistant',
// ... other properties from env
};
// Dynamic loading
async function loadCharacter(source: string): Promise<Character> {
if (source.endsWith('.json')) {
const data = await fs.readFile(source, 'utf-8');
return JSON.parse(data);
} else if (source.endsWith('.ts')) {
const module = await import(source);
return module.character || module.default;
} else if (source.startsWith('http')) {
const response = await fetch(source);
return await response.json();
}
throw new Error(`Unknown character source: ${source}`);
}
import { validateCharacter } from '@elizaos/core';
function validateAndPrepareCharacter(character: Partial<Character>): Character {
// Required fields
if (!character.name) {
throw new Error('Character name is required');
}
if (!character.bio || (Array.isArray(character.bio) && character.bio.length === 0)) {
throw new Error('Character bio is required');
}
// Set defaults
const prepared: Character = {
...character,
id: character.id || stringToUuid(character.name),
username: character.username || character.name.toLowerCase().replace(/\s+/g, '_'),
topics: character.topics || [],
adjectives: character.adjectives || [],
messageExamples: character.messageExamples || [],
postExamples: character.postExamples || [],
style: {
all: character.style?.all || [],
chat: character.style?.chat || [],
post: character.style?.post || [],
},
settings: character.settings || {},
secrets: character.secrets || {},
plugins: character.plugins || [],
};
// Validate structure
const validation = validateCharacter(prepared);
if (!validation.valid) {
throw new Error(`Character validation failed: ${validation.errors.join(', ')}`);
}
return prepared;
}
interface Agent extends Character {
enabled?: boolean;
status?: AgentStatus;
createdAt: number;
updatedAt: number;
}
enum AgentStatus {
ACTIVE = 'active',
INACTIVE = 'inactive',
}
// Creating an Agent from a Character
function createAgent(character: Character): Agent {
return {
...character,
enabled: true,
status: AgentStatus.INACTIVE, // Will become ACTIVE after initialization
createdAt: Date.now(),
updatedAt: Date.now()
};
}
AgentRuntime
is the central orchestrator:
export class AgentRuntime implements IAgentRuntime {
readonly agentId: UUID;
readonly character: Character;
public adapter!: IDatabaseAdapter;
readonly actions: Action[] = [];
readonly evaluators: Evaluator[] = [];
readonly providers: Provider[] = [];
readonly plugins: Plugin[] = [];
services = new Map<ServiceTypeName, Service[]>();
models = new Map<string, ModelHandler[]>();
constructor(opts: {
character: Character;
adapter?: IDatabaseAdapter;
plugins?: Plugin[];
settings?: RuntimeSettings;
}) {
this.agentId = opts.character.id || stringToUuid(opts.character.name);
this.character = opts.character;
if (opts.adapter) {
this.registerDatabaseAdapter(opts.adapter);
}
this.characterPlugins = opts.plugins || [];
this.settings = opts.settings || {};
this.logger = createLogger({
namespace: this.character.name
});
}
async initialize(): Promise<void> {
this.logger.info('Initializing AgentRuntime...');
// 1. Connect to database
await this.adapter.init();
// 2. Resolve and load plugins
await this.loadPlugins();
// 3. Start services
await this.startServices();
// 4. Initialize providers
await this.initializeProviders();
// 5. Set agent status
await this.updateAgentStatus(AgentStatus.ACTIVE);
this.isInitialized = true;
this.logger.info('AgentRuntime initialized successfully');
}
}
class AgentRuntime {
// Action registration and management
registerAction(action: Action): void {
if (this.actions.find(a => a.name === action.name)) {
throw new Error(`Action ${action.name} already registered`);
}
this.actions.push(action);
this.logger.debug(`Registered action: ${action.name}`);
}
// Provider registration and management
registerProvider(provider: Provider): void {
if (this.providers.find(p => p.name === provider.name)) {
throw new Error(`Provider ${provider.name} already registered`);
}
this.providers.push(provider);
this.logger.debug(`Registered provider: ${provider.name}`);
}
// Service registration and lifecycle
async registerService(ServiceClass: typeof Service): Promise<Service> {
const serviceName = ServiceClass.serviceType;
// Check if already registered
if (this.services.has(serviceName)) {
return this.services.get(serviceName)[0];
}
// Create and start service
const service = new ServiceClass(this);
await service.start();
this.services.set(serviceName, [service]);
this.logger.info(`Service ${serviceName} started`);
return service;
}
// Get a registered service
getService<T extends Service>(name: ServiceTypeName): T | null {
const services = this.services.get(name);
return services?.[0] as T || null;
}
}
class AgentRuntime {
private async loadPlugins(): Promise<void> {
// 1. Resolve all plugin dependencies
const pluginsToLoad = await this.resolvePluginDependencies(this.characterPlugins);
// 2. Sort plugins by dependency order
const sortedPlugins = this.topologicalSort(pluginsToLoad);
// 3. Load each plugin in order
for (const plugin of sortedPlugins) {
await this.registerPlugin(plugin);
}
}
private async resolvePluginDependencies(plugins: Plugin[]): Promise<Plugin[]> {
const resolved = new Map<string, Plugin>();
const queue = [...plugins];
while (queue.length > 0) {
const plugin = queue.shift()!;
if (resolved.has(plugin.name)) continue;
resolved.set(plugin.name, plugin);
// Add dependencies to queue
if (plugin.dependencies) {
for (const depName of plugin.dependencies) {
const dep = this.allAvailablePlugins.get(depName);
if (dep && !resolved.has(depName)) {
queue.push(dep);
}
}
}
}
return Array.from(resolved.values());
}
async registerPlugin(plugin: Plugin): Promise<void> {
this.logger.info(`Registering plugin: ${plugin.name}`);
// 1. Call plugin's init function
if (plugin.init) {
await plugin.init(plugin.config || {}, this);
}
// 2. Register services
if (plugin.services) {
for (const ServiceClass of plugin.services) {
await this.registerService(ServiceClass);
}
}
// 3. Register actions
if (plugin.actions) {
for (const action of plugin.actions) {
this.registerAction(action);
}
}
// 4. Register providers
if (plugin.providers) {
for (const provider of plugin.providers) {
this.registerProvider(provider);
}
}
// 5. Register evaluators
if (plugin.evaluators) {
for (const evaluator of plugin.evaluators) {
this.registerEvaluator(evaluator);
}
}
// 6. Register models
if (plugin.models) {
for (const [type, handler] of Object.entries(plugin.models)) {
this.registerModel(type, handler, plugin.name, plugin.priority);
}
}
this.plugins.push(plugin);
this.logger.info(`Plugin ${plugin.name} registered successfully`);
}
}
interface Plugin {
// Initialization - called when plugin is loaded
init?: (config: any, runtime: IAgentRuntime) => Promise<void>;
// Start - called when runtime starts
start?: (runtime: IAgentRuntime) => Promise<void>;
// Stop - called when runtime stops
stop?: (runtime: IAgentRuntime) => Promise<void>;
// Message hooks
beforeMessage?: (message: Memory, runtime: IAgentRuntime) => Promise<Memory>;
afterMessage?: (message: Memory, response: Memory, runtime: IAgentRuntime) => Promise<void>;
// Action hooks
beforeAction?: (action: Action, message: Memory, runtime: IAgentRuntime) => Promise<boolean>;
afterAction?: (action: Action, result: any, runtime: IAgentRuntime) => Promise<void>;
}
// Example plugin with lifecycle hooks
const lifecyclePlugin: Plugin = {
name: 'lifecycle-example',
async init(config, runtime) {
console.log('Plugin initializing...');
// Setup plugin resources
},
async start(runtime) {
console.log('Plugin starting...');
// Start background tasks
},
async stop(runtime) {
console.log('Plugin stopping...');
// Cleanup resources
},
async beforeMessage(message, runtime) {
// Modify or validate message before processing
return {
...message,
metadata: {
...message.metadata,
preprocessed: true
}
};
},
async afterMessage(message, response, runtime) {
// Log, analyze, or store conversation
await runtime.createMemory({
content: {
text: `Processed: ${message.content.text}`,
metadata: { type: 'conversation_log' }
}
});
}
};
class ActionOrchestrator {
async selectAction(
runtime: IAgentRuntime,
message: Memory,
state: State
): Promise<Action | null> {
// 1. Get all available actions
const availableActions = runtime.actions;
// 2. Validate which actions can handle this message
const validActions = await Promise.all(
availableActions.map(async action => {
try {
const isValid = await action.validate?.(runtime, message, state);
return isValid ? action : null;
} catch (error) {
runtime.logger.error(`Validation error for ${action.name}:`, error);
return null;
}
})
);
const candidates = validActions.filter(Boolean);
if (candidates.length === 0) return null;
// 3. Use LLM to select best action
const selectedAction = await this.selectWithLLM(
runtime,
candidates,
message,
state
);
return selectedAction;
}
async executeAction(
runtime: IAgentRuntime,
action: Action,
message: Memory,
state: State
): Promise<ActionResult> {
const startTime = Date.now();
try {
// Pre-execution hook
if (runtime.currentPlugin?.beforeAction) {
const shouldContinue = await runtime.currentPlugin.beforeAction(
action,
message,
runtime
);
if (!shouldContinue) {
return { success: false, reason: 'Blocked by plugin' };
}
}
// Execute action
const result = await action.handler(
runtime,
message,
state,
{},
(response) => {
// Callback for streaming responses
runtime.emit('action:response', { action: action.name, response });
}
);
// Post-execution hook
if (runtime.currentPlugin?.afterAction) {
await runtime.currentPlugin.afterAction(action, result, runtime);
}
// Log execution
runtime.logger.info(`Action ${action.name} executed in ${Date.now() - startTime}ms`);
return {
success: true,
data: result,
executionTime: Date.now() - startTime
};
} catch (error) {
runtime.logger.error(`Action ${action.name} failed:`, error);
return {
success: false,
error: error.message,
executionTime: Date.now() - startTime
};
}
}
}
class ProviderOrchestrator {
async composeState(
runtime: IAgentRuntime,
message: Memory
): Promise<State> {
const state: State = {
messages: [],
facts: [],
providers: {},
context: '',
metadata: {
roomId: message.roomId,
entityId: message.entityId,
timestamp: Date.now(),
tokenCount: 0
}
};
// 1. Get recent messages
state.messages = await runtime.getMemories({
roomId: message.roomId,
count: runtime.conversationLength
});
// 2. Run all providers in parallel
const providerPromises = runtime.providers.map(async provider => {
try {
const result = await provider.get(runtime, message, state);
return { name: provider.name, result };
} catch (error) {
runtime.logger.error(`Provider ${provider.name} failed:`, error);
return null;
}
});
const providerResults = await Promise.all(providerPromises);
// 3. Merge provider data into state
for (const item of providerResults) {
if (!item) continue;
state.providers[item.name] = {
text: item.result.text || '',
data: item.result.data || {}
};
// Add to context
if (item.result.text) {
state.context += `\n[${item.name.toUpperCase()}]\n${item.result.text}\n`;
}
}
// 4. Calculate token count
state.metadata.tokenCount = this.estimateTokens(state.context);
return state;
}
}
class EvaluatorOrchestrator {
async runEvaluators(
runtime: IAgentRuntime,
message: Memory,
response: Memory,
state: State
): Promise<EvaluationResults> {
const results: EvaluationResults = {};
// Filter evaluators that should run
const evaluatorsToRun = runtime.evaluators.filter(evaluator => {
// Always run if marked as alwaysRun
if (evaluator.alwaysRun) return true;
// Run if agent responded
if (response) return true;
// Check custom conditions
return evaluator.shouldRun?.(message, state);
});
// Run evaluators in parallel
const evaluationPromises = evaluatorsToRun.map(async evaluator => {
try {
const result = await evaluator.handler(
runtime,
message,
state,
{},
() => {}, // Callback
[response] // Response array
);
return { name: evaluator.name, result };
} catch (error) {
runtime.logger.error(`Evaluator ${evaluator.name} failed:`, error);
return { name: evaluator.name, error };
}
});
const evaluations = await Promise.all(evaluationPromises);
// Process results
for (const evaluation of evaluations) {
if (evaluation.error) {
results[evaluation.name] = { success: false, error: evaluation.error };
} else {
results[evaluation.name] = { success: true, data: evaluation.result };
}
}
// Store evaluation results
await this.storeEvaluations(runtime, message, response, results);
return results;
}
}
abstract class Service {
static serviceType: ServiceTypeName;
status: ServiceStatus = ServiceStatus.STOPPED;
runtime: IAgentRuntime;
constructor(runtime: IAgentRuntime) {
this.runtime = runtime;
}
abstract start(): Promise<void>;
abstract stop(): Promise<void>;
}
// Example service implementation
class WebSocketService extends Service {
static serviceType = 'websocket' as ServiceTypeName;
private ws: WebSocket | null = null;
async start(): Promise<void> {
this.ws = new WebSocket(this.runtime.getSetting('WS_URL'));
this.ws.on('open', () => {
this.status = ServiceStatus.RUNNING;
this.runtime.logger.info('WebSocket connected');
});
this.ws.on('message', async (data) => {
await this.handleMessage(data);
});
this.ws.on('error', (error) => {
this.runtime.logger.error('WebSocket error:', error);
this.status = ServiceStatus.ERROR;
});
}
async stop(): Promise<void> {
if (this.ws) {
this.ws.close();
this.ws = null;
}
this.status = ServiceStatus.STOPPED;
}
private async handleMessage(data: any) {
// Process incoming websocket messages
const message = JSON.parse(data);
await this.runtime.processMessage(message);
}
}
class ServiceManager {
private services = new Map<ServiceTypeName, Service>();
private startOrder: ServiceTypeName[] = [];
async startServices(runtime: IAgentRuntime): Promise<void> {
// Determine start order based on dependencies
this.startOrder = this.resolveServiceDependencies();
for (const serviceName of this.startOrder) {
const ServiceClass = this.getServiceClass(serviceName);
if (!ServiceClass) continue;
try {
const service = new ServiceClass(runtime);
await service.start();
this.services.set(serviceName, service);
runtime.logger.info(`Service ${serviceName} started`);
} catch (error) {
runtime.logger.error(`Failed to start service ${serviceName}:`, error);
// Decide whether to continue or abort
if (this.isRequiredService(serviceName)) {
throw error;
}
}
}
}
async stopServices(runtime: IAgentRuntime): Promise<void> {
// Stop in reverse order
const stopOrder = [...this.startOrder].reverse();
for (const serviceName of stopOrder) {
const service = this.services.get(serviceName);
if (!service) continue;
try {
await service.stop();
runtime.logger.info(`Service ${serviceName} stopped`);
} catch (error) {
runtime.logger.error(`Error stopping service ${serviceName}:`, error);
}
}
this.services.clear();
}
async restartService(
runtime: IAgentRuntime,
serviceName: ServiceTypeName
): Promise<void> {
const service = this.services.get(serviceName);
if (service) {
await service.stop();
}
const ServiceClass = this.getServiceClass(serviceName);
const newService = new ServiceClass(runtime);
await newService.start();
this.services.set(serviceName, newService);
}
}
class MultiAgentCoordinator {
private agents = new Map<UUID, IAgentRuntime>();
private messageQueue = new Map<UUID, Memory[]>();
async registerAgent(agent: IAgentRuntime): Promise<void> {
this.agents.set(agent.agentId, agent);
this.messageQueue.set(agent.agentId, []);
// Setup inter-agent communication
agent.on('message:send', async (data) => {
await this.routeMessage(data.from, data.to, data.message);
});
}
async routeMessage(
fromAgent: UUID,
toAgent: UUID,
message: Memory
): Promise<void> {
const targetAgent = this.agents.get(toAgent);
if (!targetAgent) {
// Queue message for offline agent
this.messageQueue.get(toAgent)?.push(message);
return;
}
// Deliver message
await targetAgent.processMessage({
...message,
metadata: {
...message.metadata,
fromAgent,
interAgent: true
}
});
}
async broadcastMessage(
fromAgent: UUID,
message: Memory
): Promise<void> {
const promises = Array.from(this.agents.entries())
.filter(([id]) => id !== fromAgent)
.map(([id, agent]) => agent.processMessage(message));
await Promise.all(promises);
}
}
interface AgentHierarchy {
parent?: UUID;
children: UUID[];
permissions: {
canCreateChildren: boolean;
canControlChildren: boolean;
canAccessParentMemory: boolean;
};
}
class HierarchicalAgentSystem {
private hierarchy = new Map<UUID, AgentHierarchy>();
async createChildAgent(
parentRuntime: IAgentRuntime,
childCharacter: Character
): Promise<IAgentRuntime> {
// Inherit settings from parent
const childCharacter: Character = {
...childCharacter,
settings: {
...parentRuntime.character.settings,
...childCharacter.settings
},
// Inherit some plugins
plugins: [
...parentRuntime.character.plugins.filter(p => this.isInheritable(p)),
...childCharacter.plugins
]
};
// Create child runtime
const childRuntime = new AgentRuntime({
character: childCharacter,
adapter: parentRuntime.adapter, // Share database
settings: parentRuntime.settings
});
await childRuntime.initialize();
// Update hierarchy
this.hierarchy.set(childRuntime.agentId, {
parent: parentRuntime.agentId,
children: [],
permissions: {
canCreateChildren: false,
canControlChildren: false,
canAccessParentMemory: true
}
});
// Update parent's children list
const parentHierarchy = this.hierarchy.get(parentRuntime.agentId);
if (parentHierarchy) {
parentHierarchy.children.push(childRuntime.agentId);
}
return childRuntime;
}
async delegateTask(
parentRuntime: IAgentRuntime,
childId: UUID,
task: Task
): Promise<TaskResult> {
const childRuntime = this.agents.get(childId);
if (!childRuntime) {
throw new Error(`Child agent ${childId} not found`);
}
// Check permissions
const hierarchy = this.hierarchy.get(parentRuntime.agentId);
if (!hierarchy?.children.includes(childId)) {
throw new Error('No authority over this agent');
}
// Delegate task
return await childRuntime.executeTask(task);
}
}
// Lazy initialization - start minimal, load as needed
class LazyRuntime extends AgentRuntime {
private loadedPlugins = new Set<string>();
async initialize(): Promise<void> {
// Load only core plugins
await this.loadCorePlugins();
this.isInitialized = true;
}
async loadPlugin(pluginName: string): Promise<void> {
if (this.loadedPlugins.has(pluginName)) return;
const plugin = await this.fetchPlugin(pluginName);
await this.registerPlugin(plugin);
this.loadedPlugins.add(pluginName);
}
// Load plugin on first use
async getAction(name: string): Promise<Action | null> {
let action = this.actions.find(a => a.name === name);
if (!action) {
// Try to load plugin that provides this action
const pluginName = this.findPluginForAction(name);
if (pluginName) {
await this.loadPlugin(pluginName);
action = this.actions.find(a => a.name === name);
}
}
return action;
}
}
// Eager initialization - load everything upfront
class EagerRuntime extends AgentRuntime {
async initialize(): Promise<void> {
// Load all plugins immediately
await this.loadAllPlugins();
// Pre-warm caches
await this.prewarmCaches();
// Pre-compile templates
await this.compileTemplates();
this.isInitialized = true;
}
}
class ResilientRuntime extends AgentRuntime {
private errorCount = new Map<string, number>();
private circuitBreakers = new Map<string, CircuitBreaker>();
async processMessageWithRecovery(message: Memory): Promise<void> {
const maxRetries = 3;
let lastError: Error | null = null;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
// Check circuit breaker
const breaker = this.circuitBreakers.get('message_processing');
if (breaker?.isOpen()) {
throw new Error('Circuit breaker is open');
}
await this.processMessage(message);
// Reset error count on success
this.errorCount.set('message_processing', 0);
return;
} catch (error) {
lastError = error;
this.logger.error(`Attempt ${attempt} failed:`, error);
// Update error count
const count = (this.errorCount.get('message_processing') || 0) + 1;
this.errorCount.set('message_processing', count);
// Trip circuit breaker if too many errors
if (count > 10) {
this.circuitBreakers.get('message_processing')?.trip();
}
// Exponential backoff
if (attempt < maxRetries) {
await this.sleep(Math.pow(2, attempt) * 1000);
}
}
}
// All retries failed
await this.handleCriticalError(lastError!, message);
}
private async handleCriticalError(
error: Error,
message: Memory
): Promise<void> {
// Log to error tracking service
await this.logToErrorService(error, {
message,
agentId: this.agentId,
timestamp: Date.now()
});
// Send fallback response
await this.sendFallbackResponse(message);
// Notify administrators
await this.notifyAdmins(error);
}
}
interface RuntimeMetrics {
messagesProcessed: number;
averageResponseTime: number;
errorRate: number;
memoryUsage: number;
activeServices: number;
pluginPerformance: Map<string, PluginMetrics>;
}
class MonitoredRuntime extends AgentRuntime {
private metrics: RuntimeMetrics = {
messagesProcessed: 0,
averageResponseTime: 0,
errorRate: 0,
memoryUsage: 0,
activeServices: 0,
pluginPerformance: new Map()
};
async processMessage(message: Memory): Promise<void> {
const startTime = Date.now();
try {
await super.processMessage(message);
// Update metrics
this.metrics.messagesProcessed++;
this.updateAverageResponseTime(Date.now() - startTime);
} catch (error) {
this.metrics.errorRate = this.calculateErrorRate();
throw error;
} finally {
// Collect memory usage
this.metrics.memoryUsage = process.memoryUsage().heapUsed;
// Send metrics
await this.sendMetrics();
}
}
private async sendMetrics(): Promise<void> {
// Send to monitoring service (e.g., Prometheus, DataDog)
await fetch(process.env.METRICS_ENDPOINT!, {
method: 'POST',
body: JSON.stringify({
agentId: this.agentId,
timestamp: Date.now(),
metrics: this.metrics
})
});
}
// Health check endpoint
async getHealth(): Promise<HealthStatus> {
return {
status: this.isHealthy() ? 'healthy' : 'unhealthy',
uptime: process.uptime(),
metrics: this.metrics,
services: Array.from(this.services.entries()).map(([name, services]) => ({
name,
status: services[0]?.status || 'unknown'
}))
};
}
}
// Load balancer for multiple agent instances
class AgentLoadBalancer {
private instances: IAgentRuntime[] = [];
private currentIndex = 0;
async addInstance(character: Character): Promise<void> {
const runtime = new AgentRuntime({ character });
await runtime.initialize();
this.instances.push(runtime);
}
// Round-robin load balancing
getNextInstance(): IAgentRuntime {
const instance = this.instances[this.currentIndex];
this.currentIndex = (this.currentIndex + 1) % this.instances.length;
return instance;
}
// Load-based routing
getLeastLoadedInstance(): IAgentRuntime {
return this.instances.reduce((least, current) => {
const leastLoad = least.getMetrics().activeRequests;
const currentLoad = current.getMetrics().activeRequests;
return currentLoad < leastLoad ? current : least;
});
}
async scaleUp(): Promise<void> {
const baseCharacter = this.instances[0].character;
await this.addInstance(baseCharacter);
}
async scaleDown(): Promise<void> {
if (this.instances.length <= 1) return;
const instance = this.instances.pop();
await instance?.stop();
}
}
// server.ts
import { AgentRuntime } from '@elizaos/core';
import { PostgresDatabaseAdapter } from '@elizaos/plugin-sql';
import { character } from './character';
async function startAgent() {
// Create database adapter
const adapter = new PostgresDatabaseAdapter({
connectionString: process.env.DATABASE_URL
});
// Create runtime
const runtime = new AgentRuntime({
character,
adapter,
settings: {
logLevel: process.env.LOG_LEVEL || 'info'
}
});
// Initialize
await runtime.initialize();
// Start HTTP server for API
const app = express();
app.post('/message', async (req, res) => {
try {
const response = await runtime.processMessage(req.body);
res.json(response);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.get('/health', async (req, res) => {
const health = await runtime.getHealth();
res.json(health);
});
app.listen(process.env.PORT || 3000);
// Graceful shutdown
process.on('SIGTERM', async () => {
await runtime.stop();
process.exit(0);
});
}
startAgent().catch(console.error);
class AgentSwarm {
private agents = new Map<UUID, IAgentRuntime>();
private coordinator: MultiAgentCoordinator;
async deploySwarm(characters: Character[]): Promise<void> {
// Shared database for all agents
const adapter = new PostgresDatabaseAdapter({
connectionString: process.env.DATABASE_URL
});
// Deploy each agent
for (const character of characters) {
const runtime = new AgentRuntime({
character,
adapter,
settings: this.getSwarmSettings()
});
await runtime.initialize();
this.agents.set(runtime.agentId, runtime);
// Register with coordinator
await this.coordinator.registerAgent(runtime);
}
// Setup swarm communication
await this.setupSwarmCommunication();
}
private async setupSwarmCommunication(): Promise<void> {
// Create message bus for inter-agent communication
const messageBus = new EventEmitter();
for (const [id, agent] of this.agents) {
// Subscribe to agent's outgoing messages
agent.on('message:external', (data) => {
messageBus.emit('swarm:message', {
from: id,
...data
});
});
// Route swarm messages to agent
messageBus.on('swarm:message', async (data) => {
if (data.to === id || data.broadcast) {
await agent.processMessage(data.message);
}
});
}
}
}
class EdgeRuntime extends AgentRuntime {
constructor(opts: EdgeRuntimeOptions) {
super({
...opts,
// Use lightweight alternatives
adapter: new SQLiteAdapter({
path: './agent.db'
}),
settings: {
...opts.settings,
// Reduce resource usage
maxMemorySize: 100, // Smaller memory buffer
conversationLength: 10, // Shorter context
cacheSize: 50 // Smaller cache
}
});
}
async initialize(): Promise<void> {
// Load only essential plugins
const essentialPlugins = this.characterPlugins.filter(
p => this.isEssential(p.name)
);
this.characterPlugins = essentialPlugins;
await super.initialize();
// Enable offline mode
await this.enableOfflineMode();
}
private async enableOfflineMode(): Promise<void> {
// Cache common responses
await this.cacheCommonResponses();
// Use local models if available
if (await this.hasLocalModel()) {
this.registerModel('local', this.localModelHandler);
}
// Setup sync when online
this.setupSyncWhenOnline();
}
private setupSyncWhenOnline(): void {
setInterval(async () => {
if (await this.isOnline()) {
await this.syncWithCloud();
}
}, 60000); // Check every minute
}
}
async function debugUnresponsiveAgent(runtime: IAgentRuntime) {
// Check initialization
console.log('Is initialized:', runtime.isInitialized);
// Check services
const services = runtime.getServices();
for (const [name, service] of services) {
console.log(`Service ${name}: ${service.status}`);
}
// Check action availability
console.log('Available actions:', runtime.actions.map(a => a.name));
// Check database connection
try {
await runtime.adapter.ping();
console.log('Database: Connected');
} catch (error) {
console.log('Database: Disconnected', error);
}
// Check memory usage
const usage = process.memoryUsage();
console.log('Memory usage:', {
rss: `${Math.round(usage.rss / 1024 / 1024)}MB`,
heap: `${Math.round(usage.heapUsed / 1024 / 1024)}MB`
});
}
async function debugPluginLoading(runtime: IAgentRuntime, pluginName: string) {
try {
// Check if plugin exists
const plugin = runtime.allAvailablePlugins.get(pluginName);
if (!plugin) {
console.log(`Plugin ${pluginName} not found in available plugins`);
return;
}
// Check dependencies
if (plugin.dependencies) {
for (const dep of plugin.dependencies) {
const depPlugin = runtime.plugins.find(p => p.name === dep);
if (!depPlugin) {
console.log(`Missing dependency: ${dep}`);
}
}
}
// Try loading manually
await runtime.registerPlugin(plugin);
console.log(`Plugin ${pluginName} loaded successfully`);
} catch (error) {
console.log(`Plugin loading error:`, error);
}
}
Was this page helpful?