UNPKG

aios-core

Version:

Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework

350 lines (296 loc) โ€ข 10.6 kB
/** * @deprecated Use agent-config-loader.js instead * This file will be removed in a future version. * * Migration guide: * - Old: const { loadAgentConfig } = require('./config-loader'); * - New: const { AgentConfigLoader } = require('./agent-config-loader'); * const loader = new AgentConfigLoader(agentId); * const config = await loader.load(coreConfig); * * AIOS Config Loader with Lazy Loading * * Intelligent configuration loader that only loads what each agent needs, * significantly reducing memory footprint and load times. * * @module config-loader * @version 1.0.0 * @created 2025-01-16 (Story 6.1.2.6) * @deprecated Since Story 6.1.4 - Use agent-config-loader.js instead */ const fs = require('fs').promises; const path = require('path'); const yaml = require('js-yaml'); /** * Config cache with TTL */ const configCache = { full: null, sections: {}, lastLoad: null, TTL: 5 * 60 * 1000, // 5 minutes }; /** * Agent requirements mapping (from agent-config-requirements.yaml) */ const agentRequirements = { dev: ['frameworkDocsLocation', 'projectDocsLocation', 'devLoadAlwaysFiles', 'lazyLoading', 'toolConfigurations', 'pvMindContext', 'hybridOpsConfig'], qa: ['frameworkDocsLocation', 'projectDocsLocation', 'devLoadAlwaysFiles', 'lazyLoading', 'toolConfigurations'], po: ['frameworkDocsLocation', 'projectDocsLocation', 'devLoadAlwaysFiles', 'lazyLoading', 'toolConfigurations'], pm: ['frameworkDocsLocation', 'projectDocsLocation', 'devLoadAlwaysFiles', 'lazyLoading'], sm: ['frameworkDocsLocation', 'projectDocsLocation', 'devLoadAlwaysFiles', 'lazyLoading', 'toolConfigurations'], architect: ['frameworkDocsLocation', 'projectDocsLocation', 'devLoadAlwaysFiles', 'lazyLoading', 'toolConfigurations'], analyst: ['frameworkDocsLocation', 'projectDocsLocation', 'devLoadAlwaysFiles', 'lazyLoading', 'toolConfigurations'], 'data-engineer': ['frameworkDocsLocation', 'projectDocsLocation', 'devLoadAlwaysFiles', 'lazyLoading', 'toolConfigurations', 'pvMindContext', 'hybridOpsConfig'], devops: ['frameworkDocsLocation', 'projectDocsLocation', 'devLoadAlwaysFiles', 'lazyLoading', 'toolConfigurations'], 'aios-master': ['frameworkDocsLocation', 'projectDocsLocation', 'devLoadAlwaysFiles', 'lazyLoading', 'registry', 'expansionPacks', 'toolConfigurations'], 'ux-expert': ['frameworkDocsLocation', 'projectDocsLocation', 'devLoadAlwaysFiles', 'lazyLoading', 'toolConfigurations'], 'db-sage': ['frameworkDocsLocation', 'projectDocsLocation', 'devLoadAlwaysFiles', 'lazyLoading', 'toolConfigurations', 'pvMindContext', 'hybridOpsConfig'], security: ['frameworkDocsLocation', 'projectDocsLocation', 'devLoadAlwaysFiles', 'lazyLoading', 'toolConfigurations'], }; /** * Always-loaded sections (lightweight, needed by all) */ const ALWAYS_LOADED = [ 'frameworkDocsLocation', 'projectDocsLocation', 'devLoadAlwaysFiles', 'lazyLoading', ]; /** * Performance tracking */ const performanceMetrics = { loads: 0, cacheHits: 0, cacheMisses: 0, avgLoadTime: 0, totalLoadTime: 0, }; /** * Checks if cache is still valid */ function isCacheValid() { if (!configCache.lastLoad) return false; const now = Date.now(); const age = now - configCache.lastLoad; return age < configCache.TTL; } /** * Loads full config file (used for initial load or cache refresh) */ async function loadFullConfig() { const configPath = path.join('.aios-core', 'core-config.yaml'); const startTime = Date.now(); try { const content = await fs.readFile(configPath, 'utf8'); const config = yaml.load(content); const loadTime = Date.now() - startTime; // Update performance metrics performanceMetrics.loads++; performanceMetrics.totalLoadTime += loadTime; performanceMetrics.avgLoadTime = performanceMetrics.totalLoadTime / performanceMetrics.loads; // Cache full config configCache.full = config; configCache.lastLoad = Date.now(); return config; } catch (error) { console.error('Failed to load core-config.yaml:', error.message); throw new Error(`Config load failed: ${error.message}`); } } /** * Loads specific config sections on demand * * @param {string[]} sections - Array of section names to load * @returns {Promise<Object>} Config object with requested sections */ async function loadConfigSections(sections) { const startTime = Date.now(); // Check cache first if (isCacheValid() && configCache.full) { performanceMetrics.cacheHits++; const config = {}; sections.forEach(section => { if (configCache.full[section] !== undefined) { config[section] = configCache.full[section]; } }); return config; } // Cache miss - load full config performanceMetrics.cacheMisses++; const fullConfig = await loadFullConfig(); // Extract requested sections const config = {}; sections.forEach(section => { if (fullConfig[section] !== undefined) { config[section] = fullConfig[section]; } }); const loadTime = Date.now() - startTime; console.log(`โšก Loaded ${sections.length} sections in ${loadTime}ms`); return config; } /** * Loads config for specific agent with lazy loading * * @param {string} agentId - Agent ID (e.g., 'dev', 'qa', 'po') * @returns {Promise<Object>} Config object with sections needed by agent */ async function loadAgentConfig(agentId) { const startTime = Date.now(); // Get required sections for this agent const requiredSections = agentRequirements[agentId] || ALWAYS_LOADED; console.log(`๐Ÿ“ฆ Loading config for @${agentId} (${requiredSections.length} sections)...`); const config = await loadConfigSections(requiredSections); const loadTime = Date.now() - startTime; // Calculate size estimate const sizeKB = (JSON.stringify(config).length / 1024).toFixed(1); console.log(`โœ… Config loaded in ${loadTime}ms (~${sizeKB} KB)`); return config; } /** * Loads always-loaded sections (minimal config) * * @returns {Promise<Object>} Minimal config with always-loaded sections */ async function loadMinimalConfig() { return await loadConfigSections(ALWAYS_LOADED); } /** * Preloads config into cache (useful for startup optimization) */ async function preloadConfig() { console.log('๐Ÿ”„ Preloading config into cache...'); await loadFullConfig(); console.log('โœ… Config preloaded'); } /** * Clears config cache (useful for testing or forcing reload) */ function clearCache() { configCache.full = null; configCache.sections = {}; configCache.lastLoad = null; console.log('๐Ÿ—‘๏ธ Config cache cleared'); } /** * Gets performance metrics * * @returns {Object} Performance statistics */ function getPerformanceMetrics() { return { ...performanceMetrics, cacheHitRate: performanceMetrics.loads > 0 ? ((performanceMetrics.cacheHits / performanceMetrics.loads) * 100).toFixed(1) + '%' : '0%', avgLoadTimeMs: Math.round(performanceMetrics.avgLoadTime), }; } /** * Validates that required sections exist in config * * @param {string} agentId - Agent ID to validate * @returns {Promise<Object>} Validation result */ async function validateAgentConfig(agentId) { const requiredSections = agentRequirements[agentId] || ALWAYS_LOADED; const config = await loadFullConfig(); const missingSections = requiredSections.filter( section => config[section] === undefined, ); return { valid: missingSections.length === 0, agentId, requiredSections, missingSections, availableSections: Object.keys(config), }; } /** * Gets config section on demand (async lazy load) * * @param {string} sectionName - Section to load * @returns {Promise<any>} Section content */ async function getConfigSection(sectionName) { const config = await loadConfigSections([sectionName]); return config[sectionName]; } // Export functions module.exports = { loadAgentConfig, loadConfigSections, loadMinimalConfig, loadFullConfig, preloadConfig, clearCache, getPerformanceMetrics, validateAgentConfig, getConfigSection, agentRequirements, ALWAYS_LOADED, }; // CLI support for testing if (require.main === module) { const command = process.argv[2]; const arg = process.argv[3]; (async () => { try { switch (command) { case 'load': const config = await loadAgentConfig(arg || 'dev'); console.log(JSON.stringify(config, null, 2)); break; case 'preload': await preloadConfig(); break; case 'validate': const validation = await validateAgentConfig(arg || 'dev'); console.log(JSON.stringify(validation, null, 2)); break; case 'metrics': const metrics = getPerformanceMetrics(); console.log(JSON.stringify(metrics, null, 2)); break; case 'test': console.log('\n๐Ÿงช Testing config loader...\n'); // Test 1: Load minimal console.log('Test 1: Load minimal config'); const minimal = await loadMinimalConfig(); console.log(` โœ… Loaded ${Object.keys(minimal).length} sections\n`); // Test 2: Load agent config console.log('Test 2: Load agent config (@dev)'); const devConfig = await loadAgentConfig('dev'); console.log(` โœ… Loaded ${Object.keys(devConfig).length} sections\n`); // Test 3: Cache hit console.log('Test 3: Load again (should hit cache)'); const devConfig2 = await loadAgentConfig('dev'); console.log(` โœ… Loaded ${Object.keys(devConfig2).length} sections\n`); // Test 4: Metrics console.log('Test 4: Performance metrics'); const testMetrics = getPerformanceMetrics(); console.log(` Loads: ${testMetrics.loads}`); console.log(` Cache hits: ${testMetrics.cacheHits}`); console.log(` Cache hit rate: ${testMetrics.cacheHitRate}`); console.log(` Avg load time: ${testMetrics.avgLoadTimeMs}ms\n`); console.log('โœ… All tests passed!\n'); break; default: console.log(` Usage: node config-loader.js load [agentId] - Load config for agent node config-loader.js preload - Preload config into cache node config-loader.js validate [agent] - Validate agent config node config-loader.js metrics - Show performance metrics node config-loader.js test - Run test suite `); } } catch (error) { console.error('Error:', error.message); process.exit(1); } })(); }