oneie
Version:
🤝 ONE Personal Collaborative Intelligence - Creates personalized AI workspace from your me.md profile. Simple: npx oneie → edit me.md → generate personalized agents, workflows & missions. From students to enterprises, ONE adapts to your context.
609 lines (530 loc) • 19.3 kB
JavaScript
/**
* Background Agent Loader System
* Loads and executes agents from .claude/agents/ directory
*/
import { promises as fs } from 'fs';
import path from 'path';
import yaml from 'js-yaml';
import chalk from 'chalk';
// License validation removed for simplified deployment
import { AdvancedCache, MemoryMonitor, PerformanceProfiler, LazyLoader } from './performance-optimizer.js';
/**
* BackgroundAgentLoader class for loading and executing agents
*/
export class BackgroundAgentLoader {
constructor(options = {}) {
this.agentsPath = options.agentsPath || '.claude/agents';
// Advanced caching system
this.cache = new AdvancedCache({
maxSize: options.cacheMaxSize || 200,
ttl: options.cacheTTL || 600000, // 10 minutes
});
// Memory monitoring
this.memoryMonitor = new MemoryMonitor({
maxHeapSize: options.maxHeapSize || 500 * 1024 * 1024, // 500MB
warningThreshold: options.memoryWarningThreshold || 0.8
});
// Performance profiling
this.profiler = new PerformanceProfiler();
// Lazy loading system
this.lazyLoader = new LazyLoader({
maxConcurrentLoads: options.maxConcurrentLoads || 5,
loadTimeout: options.loadTimeout || 5000
});
// Legacy performance metrics for backward compatibility
this.performanceMetrics = {
loadTimes: [],
memoryUsage: [],
cacheHits: 0,
cacheMisses: 0
};
// Initialize license validator for premium agent gating
// License validation removed for simplified deployment
// Coordination will be handled externally to avoid circular dependencies
this.coordinator = null;
this.enableCoordination = options.enableCoordination !== false; // Default true
// Performance optimization settings
this.enableProfiling = options.enableProfiling !== false;
this.enablePreloading = options.enablePreloading !== false;
this.preloadCommonAgents = options.preloadCommonAgents !== false;
// Preload common agents if enabled
if (this.preloadCommonAgents) {
this.initializeCommonAgents();
}
}
/**
* Initialize common agents for preloading
*/
async initializeCommonAgents() {
const commonAgents = [
'engineering-director',
'engineering-architect',
'engineering-developer',
'content-team-manager',
'research-foundation-analyst'
];
try {
console.log(chalk.blue('🚀 Preloading common agents...'));
const results = await this.cache.preload(commonAgents, async (agentName) => {
try {
const agentPath = path.join(this.agentsPath, `${agentName}.md`);
return await this.parseAgentFile(agentPath);
} catch (error) {
console.log(chalk.yellow(`⚠️ Failed to preload ${agentName}: ${error.message}`));
return null;
}
});
const successful = results.filter(r => r.success && !r.cached).length;
console.log(chalk.green(`✅ Preloaded ${successful} common agents`));
} catch (error) {
console.log(chalk.yellow(`⚠️ Preloading failed: ${error.message}`));
}
}
/**
* Load an agent from the .claude/agents/ directory
* @param {string} agentName - Name of the agent (without .md extension)
* @returns {Promise<BackgroundAgent>} Loaded agent instance
*/
async loadAgent(agentName) {
const startTime = performance.now();
const profileId = this.enableProfiling ? this.profiler.start(`loadAgent-${agentName}`, {
operation: 'loadAgent',
agentName
}) : null;
try {
// No premium gating - all agents are accessible
const accessValidation = { hasAccess: true, tier: 'free', reason: 'No restrictions' };
if (profileId) this.profiler.mark(profileId, 'license-validated');
// Check advanced cache first
const cachedAgent = this.cache.get(agentName);
if (cachedAgent) {
this.performanceMetrics.cacheHits++;
if (profileId) {
this.profiler.mark(profileId, 'cache-hit');
this.profiler.end(profileId);
}
// Add license info to cached agent
return new BackgroundAgent({
...cachedAgent,
licenseInfo: accessValidation
});
}
this.performanceMetrics.cacheMisses++;
if (profileId) this.profiler.mark(profileId, 'cache-miss');
// Use lazy loading for optimal performance
const agentConfig = await this.lazyLoader.load(agentName, async (name) => {
// Construct agent file path
const agentPath = path.join(this.agentsPath, `${name}.md`);
if (profileId) this.profiler.mark(profileId, 'file-loading');
// Parse agent file with optimized parsing
const config = await this.parseAgentFile(agentPath);
if (profileId) this.profiler.mark(profileId, 'file-parsed');
return config;
});
// Add license information to agent config
agentConfig.licenseInfo = accessValidation;
// Create agent instance
const agent = new BackgroundAgent(agentConfig);
// Cache for future use with advanced cache
this.cache.set(agentName, agentConfig);
// Record performance metrics (legacy support)
const loadTime = performance.now() - startTime;
this.performanceMetrics.loadTimes.push(loadTime);
if (profileId) {
this.profiler.mark(profileId, 'agent-created');
this.profiler.end(profileId);
}
return agent;
} catch (error) {
// If it's already an AgentLoadError, re-throw as-is
if (error instanceof AgentLoadError) {
throw error;
}
throw new AgentLoadError(`Failed to load agent '${agentName}': ${error.message}`);
}
}
/**
* Parse agent file and extract configuration
* @param {string} agentPath - Path to agent markdown file
* @returns {Promise<Object>} Agent configuration object
*/
async parseAgentFile(agentPath) {
try {
// Check if file exists
const exists = await fs.access(agentPath).then(() => true).catch(() => false);
if (!exists) {
throw new Error(`Agent file not found: ${agentPath}`);
}
// Read agent file
const content = await fs.readFile(agentPath, 'utf8');
// Extract YAML frontmatter if present
let config = {};
let yamlMatch = content.match(/^---\n([\s\S]*?)\n---/);
if (yamlMatch) {
try {
config = yaml.load(yamlMatch[1]) || {};
} catch (yamlError) {
console.warn(`Warning: Invalid YAML in ${agentPath}: ${yamlError.message}`);
}
}
// Extract basic agent info from markdown
const lines = content.split('\n');
let title = '';
let description = '';
for (const line of lines) {
if (line.startsWith('# ') && !title) {
title = line.substring(2).trim();
} else if (line.trim() && !line.startsWith('#') && !line.startsWith('---') && !description) {
description = line.trim();
break;
}
}
// Return comprehensive config
return {
name: config.name || title || path.basename(agentPath, '.md'),
title: config.title || title,
description: config.description || description,
content: content,
config: config,
filePath: agentPath,
lastModified: (await fs.stat(agentPath)).mtime
};
} catch (error) {
throw new Error(`Failed to parse agent file ${agentPath}: ${error.message}`);
}
}
/**
* Execute an agent with given context and arguments
* @param {string} agentName - Name of the agent to execute
* @param {Object} context - Execution context
* @param {Array} args - Arguments for the agent
* @param {Object} options - Execution options
* @returns {Promise<Object>} Execution result
*/
async executeAgent(agentName, context = {}, args = [], options = {}) {
const startTime = performance.now();
try {
// Load the agent
const agent = await this.loadAgent(agentName);
// Check if coordination should be enabled for this execution
let coordinationResult = null;
if (this.coordinator && this.enableCoordination && options.enableCoordination !== false) {
try {
// Spawn related agents and coordinate if context is complex enough
const contextString = typeof context === 'string' ? context : JSON.stringify(context);
if (contextString.length > 50) { // Only coordinate for complex contexts
coordinationResult = await this.coordinator.spawnRelatedAgents(
agentName,
contextString,
{
maxSpawn: options.maxSpawn || 2,
executeImmediately: options.executeSpawnedAgents || false
}
);
}
} catch (coordError) {
console.log(`⚠️ Agent coordination failed: ${coordError.message}`);
// Continue with normal execution even if coordination fails
}
}
// Execute the primary agent with context and arguments
const result = await agent.execute(context, args);
// Record execution time
const executionTime = performance.now() - startTime;
return {
success: true,
result: result,
agent: agentName,
executionTime: executionTime,
timestamp: new Date().toISOString(),
coordination: coordinationResult
};
} catch (error) {
return {
success: false,
error: error.message,
agent: agentName,
timestamp: new Date().toISOString()
};
}
}
/**
* List all available agents in the .claude/agents/ directory
* @returns {Promise<Array<string>>} Array of agent names
*/
async listAvailableAgents() {
try {
const files = await fs.readdir(this.agentsPath);
return files
.filter(file => file.endsWith('.md'))
.map(file => path.basename(file, '.md'))
.sort();
} catch (error) {
throw new Error(`Failed to list agents: ${error.message}`);
}
}
/**
* Get license status and agent access summary
* @returns {Promise<Object>} License status information
*/
async getLicenseStatus() {
return { status: 'free', licenseType: 'open-source' }; // All agents are free
}
/**
* Check if an agent requires premium access
* @param {string} agentName - Agent name
* @returns {boolean} True if premium license required
*/
isPremiumAgent(agentName) {
return false; // All agents are free - no premium restriction
}
/**
* Generate upgrade prompt for premium agents
* @param {string} agentName - Agent name
* @returns {Promise<string>} Formatted upgrade prompt
*/
async generateUpgradePrompt(agentName) {
return ''; // No upgrade prompts needed - all agents are free
}
/**
* List available agents with premium status indicators
* @returns {Promise<Array<Object>>} Array of agent info with premium status
*/
async listAgentsWithStatus() {
const agents = await this.listAvailableAgents();
const agentList = [];
for (const agentName of agents) {
const isPremium = this.isPremiumAgent(agentName);
const accessValidation = { hasAccess: true, reason: 'All agents are free' }; // No access restrictions
agentList.push({
name: agentName,
isPremium: isPremium,
hasAccess: accessValidation.hasAccess,
tier: accessValidation.tier,
reason: accessValidation.reason
});
}
return agentList;
}
/**
* Create a trial license for testing premium features
* @param {number} durationDays - Trial duration in days
* @returns {Promise<Object>} Trial license information
*/
async createTrialLicense(durationDays = 7) {
return { status: 'free', message: 'No trial needed - all agents are free' }; // No trials needed
}
/**
* Get comprehensive performance metrics
* @returns {Object} Performance metrics
*/
getPerformanceMetrics() {
const loadTimes = this.performanceMetrics.loadTimes;
const legacyMetrics = {
totalLoads: loadTimes.length,
averageLoadTime: loadTimes.length > 0 ? loadTimes.reduce((a, b) => a + b, 0) / loadTimes.length : 0,
cacheHitRate: this.performanceMetrics.cacheHits / (this.performanceMetrics.cacheHits + this.performanceMetrics.cacheMisses) || 0,
memoryUsage: process.memoryUsage(),
cacheSize: this.cache instanceof Map ? this.cache.size : this.cache.getStats().size
};
// Enhanced metrics from advanced systems
const cacheStats = this.cache.getStats ? this.cache.getStats() : {};
const memoryStats = this.memoryMonitor.getStats();
const lazyStats = this.lazyLoader.getStats();
return {
...legacyMetrics,
advanced: {
cache: {
...cacheStats,
efficiency: cacheStats.hitRate > 0.8 ? 'excellent' :
cacheStats.hitRate > 0.6 ? 'good' :
cacheStats.hitRate > 0.4 ? 'fair' : 'poor'
},
memory: memoryStats ? {
current: memoryStats.current,
average: memoryStats.average,
peak: memoryStats.peak,
status: memoryStats.percentages?.heapTotal < 0.8 ? 'healthy' :
memoryStats.percentages?.heapTotal < 0.9 ? 'warning' : 'critical'
} : null,
lazyLoading: lazyStats,
profiling: {
enabled: this.enableProfiling,
profiles: this.profiler.getProfiles().length
}
}
};
}
/**
* Get detailed profiling report for specific operation
* @param {string} operationType - Type of operation to analyze
* @returns {Object} Profiling summary
*/
getProfilingReport(operationType = 'loadAgent') {
if (!this.enableProfiling) {
return { enabled: false, message: 'Profiling is disabled' };
}
return this.profiler.getSummary(operationType);
}
/**
* Optimize cache based on usage patterns
*/
optimizeCache() {
if (this.cache.cleanup) {
this.cache.cleanup();
}
console.log(chalk.blue('🔧 Cache optimization completed'));
}
/**
* Preload specific agents
* @param {Array<string>} agentNames - Names of agents to preload
* @returns {Promise<Array>} Preload results
*/
async preloadAgents(agentNames) {
if (!this.cache.preload) {
console.log(chalk.yellow('⚠️ Advanced caching not available for preloading'));
return [];
}
const results = await this.cache.preload(agentNames, async (agentName) => {
const agentPath = path.join(this.agentsPath, `${agentName}.md`);
return await this.parseAgentFile(agentPath);
});
const successful = results.filter(r => r.success).length;
console.log(chalk.green(`✅ Preloaded ${successful}/${agentNames.length} agents`));
return results;
}
/**
* Check if performance targets are met
* @returns {Object} Performance target status
*/
checkPerformanceTargets() {
const metrics = this.getPerformanceMetrics();
const memoryPerAgent = metrics.advanced?.memory?.current?.heapUsed /
(metrics.cacheSize || 1) / 1024 / 1024; // MB per agent
return {
loadTimeTarget: {
target: 2000, // 2 seconds
current: metrics.averageLoadTime,
met: metrics.averageLoadTime < 2000,
status: metrics.averageLoadTime < 500 ? 'excellent' :
metrics.averageLoadTime < 1000 ? 'good' :
metrics.averageLoadTime < 2000 ? 'acceptable' : 'needs_improvement'
},
memoryTarget: {
target: 100, // 100MB per agent
current: memoryPerAgent || 0,
met: (memoryPerAgent || 0) < 100,
status: memoryPerAgent < 10 ? 'excellent' :
memoryPerAgent < 25 ? 'good' :
memoryPerAgent < 50 ? 'acceptable' : 'needs_improvement'
},
cacheTarget: {
target: 0.8, // 80% hit rate
current: metrics.cacheHitRate,
met: metrics.cacheHitRate > 0.8,
status: metrics.cacheHitRate > 0.9 ? 'excellent' :
metrics.cacheHitRate > 0.8 ? 'good' :
metrics.cacheHitRate > 0.6 ? 'acceptable' : 'needs_improvement'
}
};
}
/**
* Set the agent coordinator (to avoid circular dependencies)
* @param {AgentCoordinator} coordinator - Agent coordinator instance
*/
setCoordinator(coordinator) {
this.coordinator = coordinator;
}
/**
* Get agent coordination statistics
* @returns {Object} Coordination statistics
*/
getCoordinationStats() {
if (!this.coordinator) {
return { enabled: false, message: 'Agent coordination is disabled' };
}
return {
enabled: true,
...this.coordinator.getCoordinationStats()
};
}
/**
* Get active coordination sessions
* @returns {Array} Active coordination sessions
*/
getActiveCoordinationSessions() {
if (!this.coordinator) return [];
return this.coordinator.getActiveSessions();
}
/**
* Clear agent cache
*/
clearCache() {
this.cache.clear();
this.performanceMetrics.cacheHits = 0;
this.performanceMetrics.cacheMisses = 0;
}
}
/**
* BackgroundAgent class representing a loaded agent
*/
export class BackgroundAgent {
constructor(config) {
this.name = config.name;
this.title = config.title;
this.description = config.description;
this.content = config.content;
this.config = config.config || {};
this.filePath = config.filePath;
this.lastModified = config.lastModified;
this.state = {};
}
/**
* Execute the agent with given context and arguments
* @param {Object} context - Execution context
* @param {Array} args - Arguments for execution
* @returns {Promise<Object>} Execution result
*/
async execute(context = {}, args = []) {
// For now, return agent info and basic execution
// In a full implementation, this would process the agent's instructions
return {
agent: this.name,
title: this.title,
description: this.description,
context: context,
arguments: args,
state: this.state,
executed: true,
timestamp: new Date().toISOString()
};
}
/**
* Get agent metadata
* @returns {Object} Agent metadata
*/
getMetadata() {
return {
name: this.name,
title: this.title,
description: this.description,
filePath: this.filePath,
lastModified: this.lastModified,
configKeys: Object.keys(this.config)
};
}
}
/**
* Custom error class for agent loading errors
*/
export class AgentLoadError extends Error {
constructor(message, code = 'AGENT_LOAD_FAILED', details = null) {
super(message);
this.name = 'AgentLoadError';
this.code = code;
this.details = details;
}
}
// Export default instance
export default new BackgroundAgentLoader();