adpa-enterprise-framework-automation
Version:
Modular, standards-compliant Node.js/TypeScript automation framework for enterprise requirements, project, and data management. Provides CLI and API for BABOK v3, PMBOK 7th Edition, and DMBOK 2.0 (in progress). Production-ready Express.js API with TypeSpe
301 lines • 12.8 kB
JavaScript
/**
* Enhanced Configuration Manager Module for Requirements Gathering Agent
*
* Advanced configuration management system with validation, caching,
* and multi-provider environment setup for reliable AI service integration.
*
* @version 2.1.3
* @author Requirements Gathering Agent Team
* @created 2024
* @updated June 2025
*
* Key Features:
* - Environment variable validation and caching
* - Multi-provider configuration management
* - Runtime configuration validation
* - Secure credential handling
* - Configuration change detection
*
* @filepath c:\Users\menno\Source\Repos\requirements-gathering-agent\src\modules\ai\ConfigurationManager.ts
*/
import dotenv from "dotenv";
import { readFileSync, existsSync } from "fs";
import { join } from "path";
import { CONFIG_FILENAME } from "../../constants.js";
// Load environment variables once
dotenv.config();
export class ConfigurationManager {
static instance;
config = new Map();
userConfig = {};
validationCache = new Map();
modelTokenLimits = new Map([
['gemini-1.5-flash', 1048576], // 1M tokens
['gemini-1.5-pro', 2097152], // 2M tokens
['gemini-2.0-flash-exp', 1048576], // 1M tokens
['gpt-4', 128000], // 128k tokens
['gpt-4-turbo', 128000], // 128k tokens
['gpt-4o', 128000], // 128k tokens
['gpt-4o-mini', 128000], // 128k tokens
['gpt-4.1-mini', 8000], // 8k tokens
['gpt-4.1', 8000], // 8k tokens
['gpt-3.5-turbo', 16385], // 16k tokens
['claude-3-opus', 200000], // 200k tokens
['claude-3-sonnet', 200000], // 200k tokens
['claude-3-haiku', 200000], // 200k tokens
['llama3.1', 131072], // 128k tokens
['llama3.2', 131072], // 128k tokens
['qwen2.5', 131072], // 128k tokens
['phi3', 131072] // 128k tokens
]);
currentProvider = 'google-ai';
constructor() {
this.loadUserConfig();
this.loadConfiguration();
// Override with CURRENT_PROVIDER environment variable if set
const currentProvider = process.env.CURRENT_PROVIDER;
if (currentProvider && this.isValidProvider(currentProvider)) {
this.currentProvider = currentProvider;
}
}
static getInstance() {
if (!ConfigurationManager.instance) {
ConfigurationManager.instance = new ConfigurationManager();
}
return ConfigurationManager.instance;
}
loadUserConfig() {
const configPath = join(process.cwd(), CONFIG_FILENAME);
if (existsSync(configPath)) {
try {
const raw = readFileSync(configPath, 'utf-8');
this.userConfig = JSON.parse(raw);
if (this.userConfig.currentProvider) {
this.currentProvider = this.userConfig.currentProvider;
}
}
catch (e) {
console.warn('Could not read config-rga.json:', e);
}
}
}
loadConfiguration() {
// Consolidate all environment variable loading
const envVars = {
// Azure OpenAI Configuration
'AZURE_OPENAI_ENDPOINT': process.env.AZURE_OPENAI_ENDPOINT,
'AZURE_OPENAI_API_KEY': process.env.AZURE_OPENAI_API_KEY,
'AZURE_OPENAI_DEPLOYMENT_NAME': process.env.AZURE_OPENAI_DEPLOYMENT_NAME,
'AZURE_OPENAI_API_VERSION': process.env.AZURE_OPENAI_API_VERSION || "2024-02-15-preview",
'USE_ENTRA_ID': process.env.USE_ENTRA_ID === 'true',
'AZURE_CLIENT_ID': process.env.AZURE_CLIENT_ID,
'AZURE_TENANT_ID': process.env.AZURE_TENANT_ID,
// Google AI Configuration
'GOOGLE_AI_API_KEY': process.env.GOOGLE_AI_API_KEY,
'GOOGLE_AI_MODEL': process.env.GOOGLE_AI_MODEL || 'gemini-1.5-flash',
'GOOGLE_AI_ENDPOINT': process.env.GOOGLE_AI_ENDPOINT || 'https://generativelanguage.googleapis.com',
'GITHUB_ENDPOINT': process.env.GITHUB_ENDPOINT || process.env.GITHUB_API_ENDPOINT || 'https://models.github.ai/inference',
'GITHUB_COPILOT_ENDPOINT': process.env.GITHUB_COPILOT_ENDPOINT || 'https://copilot-proxy.githubusercontent.com',
'GITHUB_TOKEN': process.env.GITHUB_TOKEN,
'GITHUB_MODEL': process.env.GITHUB_MODEL || 'openai/gtp-4.1',
'AZURE_AI_ENDPOINT': process.env.AZURE_AI_ENDPOINT || process.env.AZURE_OPENAI_ENDPOINT,
'AZURE_AI_API_KEY': process.env.AZURE_AI_API_KEY || process.env.AZURE_OPENAI_API_KEY,
// Additional mapping for deployment names
'deployment_name': process.env.AZURE_OPENAI_DEPLOYMENT_NAME || process.env.DEPLOYMENT_NAME || process.env.REQUIREMENTS_AGENT_MODEL,
'api_version': process.env.AZURE_OPENAI_API_VERSION || process.env.API_VERSION,
// Ollama Configuration
'OLLAMA_ENDPOINT': process.env.OLLAMA_ENDPOINT || 'http://localhost:11434/api',
'OLLAMA_MODEL': process.env.OLLAMA_MODEL || 'deepseek-coder:latest',
// General Configuration
'max_retries': parseInt(process.env.AI_MAX_RETRIES || '3'),
'timeout_ms': parseInt(process.env.AI_TIMEOUT || '60000'),
'rate_limit_requests_per_minute': parseInt(process.env.RATE_LIMIT_RPM || '60'),
// Provider Selection
'CURRENT_PROVIDER': process.env.CURRENT_PROVIDER
}; // Set all configuration at once (including lowercase versions for compatibility)
Object.entries(envVars).forEach(([key, value]) => {
this.config.set(key, value);
this.config.set(key.toLowerCase(), value);
});
// Override with user config if present
if (this.userConfig.AI_TIMEOUT) {
this.config.set('timeout_ms', this.userConfig.AI_TIMEOUT);
}
if (this.userConfig.EXPERIMENTAL_FEATURES !== undefined) {
this.config.set('experimental_features', this.userConfig.EXPERIMENTAL_FEATURES);
}
if (this.userConfig.showMetrics !== undefined) {
this.config.set('show_metrics', this.userConfig.showMetrics);
}
if (this.userConfig.defaultOutputDir) {
this.config.set('default_output_dir', this.userConfig.defaultOutputDir);
}
if (this.userConfig.preferredFormat) {
this.config.set('preferred_format', this.userConfig.preferredFormat);
}
// ...add more as needed...
}
get(key, defaultValue) {
return this.config.get(key) ?? defaultValue;
}
// Cached validation
validateAzureOpenAIConfig() {
const cacheKey = 'azure-openai';
if (this.validationCache.has(cacheKey)) {
return this.validationCache.get(cacheKey);
}
const result = this.performAzureOpenAIValidation();
this.validationCache.set(cacheKey, result);
return result;
}
performAzureOpenAIValidation() {
const missingVars = [];
const warnings = [];
const endpoint = this.get('AZURE_OPENAI_ENDPOINT');
const apiKey = this.get('AZURE_OPENAI_API_KEY');
const deployment = this.get('AZURE_OPENAI_DEPLOYMENT_NAME');
const apiVersion = this.get('AZURE_OPENAI_API_VERSION');
const useEntra = this.get('USE_ENTRA_ID');
if (!endpoint)
missingVars.push('AZURE_AI_ENDPOINT or AZURE_OPENAI_ENDPOINT');
if (!deployment)
missingVars.push('DEPLOYMENT_NAME or REQUIREMENTS_AGENT_MODEL');
if (!apiVersion)
missingVars.push('AZURE_OPENAI_API_VERSION');
if (!useEntra && !apiKey) {
missingVars.push('AZURE_AI_API_KEY');
}
if (useEntra) {
if (!this.get('azure_client_id'))
missingVars.push('AZURE_CLIENT_ID');
if (!this.get('azure_tenant_id'))
missingVars.push('AZURE_TENANT_ID');
}
// Add warnings for common issues
if (endpoint && !endpoint.includes('https://')) {
warnings.push('Endpoint should use HTTPS');
}
return {
isValid: missingVars.length === 0,
missingVars,
warnings: warnings.length > 0 ? warnings : undefined
};
}
setProvider(provider) {
this.currentProvider = provider;
this.validationCache.clear(); // Clear cache when switching providers
}
getAIProvider() {
return this.currentProvider;
}
validateCurrentConfig() {
const provider = this.getAIProvider();
switch (provider) {
case 'google-ai':
return this.validateGoogleAIConfig();
case 'azure-openai':
return this.validateAzureOpenAIConfig();
case 'github-ai':
return this.validateGitHubAIConfig();
case 'ollama':
return this.validateOllamaConfig();
default:
return { isValid: false, missingVars: ['Unsupported provider'] };
}
}
validateGoogleAIConfig() {
const missingVars = [];
if (!this.get('GOOGLE_AI_API_KEY')) {
missingVars.push('GOOGLE_AI_API_KEY');
}
return { isValid: missingVars.length === 0, missingVars };
}
validateGitHubAIConfig() {
const missingVars = [];
if (!this.get('GITHUB_TOKEN')) {
missingVars.push('GITHUB_TOKEN');
}
// Support both GitHub endpoints (new preview and legacy)
const endpoint = this.get('GITHUB_ENDPOINT') || this.get('AZURE_AI_ENDPOINT');
if (!endpoint || !(endpoint.includes('models.inference.ai.azure.com') ||
endpoint.includes('models.github.ai'))) {
missingVars.push('GITHUB_ENDPOINT or AZURE_AI_ENDPOINT (must contain models.github.ai or models.inference.ai.azure.com)');
}
return { isValid: missingVars.length === 0, missingVars };
}
validateOllamaConfig() {
const missingVars = [];
const endpoint = this.get('OLLAMA_ENDPOINT');
if (!endpoint || !endpoint.startsWith('http')) {
missingVars.push('OLLAMA_ENDPOINT (must be a valid URL)');
}
return { isValid: missingVars.length === 0, missingVars };
}
getModelTokenLimit(model = '') {
if (!model) {
model = this.get('deployment_name', '');
}
model = model.toLowerCase();
// Find the best match for the model
for (const [modelName, limit] of this.modelTokenLimits) {
if (model.includes(modelName.toLowerCase())) {
return limit;
}
}
// Default fallback limits based on provider
switch (this.getAIProvider()) {
case 'google-ai':
return model.includes('pro') ? 2097152 : 1048576; // 2M or 1M tokens
case 'azure-openai':
case 'azure-ai-studio':
return 128000; // 128k tokens default for Azure
case 'github-ai':
return 128000; // 128k tokens for GitHub AI
case 'ollama':
return 131072; // 128k tokens for Ollama models
default:
return 4000; // Conservative default
}
}
getMaxResponseTokens(model) {
const totalTokens = this.getModelTokenLimit(model);
// Reserve 20% for response tokens and system prompts
return Math.floor(totalTokens * 0.2);
}
// Clear validation cache if configuration changes
clearValidationCache() {
this.validationCache.clear();
}
isValidProvider(provider) {
const validProviders = [
'google-ai',
'azure-openai',
'azure-openai-key',
'azure-ai-studio',
'github-ai',
'ollama'
];
return validProviders.includes(provider);
}
getConfigSummary() {
const deployment = this.get('deployment_name', '');
return {
provider: this.getAIProvider(),
hasEndpoint: !!this.get('azure_ai_endpoint'),
hasApiKey: !!this.get('azure_ai_api_key'),
hasDeployment: !!deployment,
useEntraID: this.get('use_entra_id'),
maxRetries: this.get('max_retries'),
timeoutMs: this.get('timeout_ms'),
modelTokenLimit: this.getModelTokenLimit(deployment),
maxResponseTokens: this.getMaxResponseTokens(deployment)
};
}
getOllamaConfig() {
return {
endpoint: this.get('OLLAMA_ENDPOINT') || 'http://localhost:11434',
model: this.get('REQUIREMENTS_AGENT_MODEL') || 'llama3.1'
};
}
}
//# sourceMappingURL=ConfigurationManager.js.map