aios-core
Version:
Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework
350 lines (296 loc) โข 10.6 kB
JavaScript
/**
* @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);
}
})();
}