pdca
Version:
🎯 AI 驅動的 PDCA 多代理開發系統 - 智能循環控制 + 成本管理 + Token 優化 + 多 AI 引擎支援
447 lines • 15.7 kB
JavaScript
/**
* 高級配置載入器
* 支援多層配置合併、預設配置集、環境變數和 CLI 參數覆蓋
*/
import { readFileSync, existsSync } from 'fs';
import { join, resolve } from 'path';
import { parse } from 'yaml';
import { homedir } from 'os';
import { ConfigLoader } from './config-loader.js';
/**
* 內建配置集
*/
const BUILTIN_PROFILES = {
economic: {
name: 'Economic',
description: '經濟實惠型:最小成本,基本品質',
execution: {
max_agents: 2,
loop_control: {
max_iterations: 1,
quality_target: 0.75,
marginal_threshold: 0.20,
token_budget: 5000,
time_budget_minutes: 10,
auto_continue: false,
require_confirmation: false
},
cost_control: {
show_realtime: true,
warn_at_percent: 80,
hard_stop_at_tokens: 8000,
track_by_agent: true,
currency: 'USD'
}
}
},
balanced: {
name: 'Balanced',
description: '平衡型:合理成本,良好品質(預設)',
execution: {
max_agents: 4,
loop_control: {
max_iterations: 3,
quality_target: 0.85,
marginal_threshold: 0.10,
token_budget: 10000,
time_budget_minutes: 20,
auto_continue: false,
require_confirmation: true
},
cost_control: {
show_realtime: true,
warn_at_percent: 80,
hard_stop_at_tokens: 15000,
track_by_agent: true,
currency: 'USD'
}
}
},
premium: {
name: 'Premium',
description: '品質優先型:較高成本,優秀品質',
execution: {
max_agents: 5,
loop_control: {
max_iterations: 5,
quality_target: 0.95,
marginal_threshold: 0.05,
token_budget: 50000,
time_budget_minutes: 60,
auto_continue: false,
require_confirmation: true
},
cost_control: {
show_realtime: true,
warn_at_percent: 90,
hard_stop_at_tokens: 80000,
track_by_agent: true,
currency: 'USD'
}
}
},
unlimited: {
name: 'Unlimited',
description: '無限制型:追求極致,不考慮成本',
execution: {
max_agents: 5,
loop_control: {
max_iterations: null,
quality_target: 0.99,
marginal_threshold: 0.01,
token_budget: null,
time_budget_minutes: null,
auto_continue: true,
require_confirmation: false
},
cost_control: {
show_realtime: false,
warn_at_percent: null,
hard_stop_at_tokens: null,
track_by_agent: false,
currency: 'USD'
}
}
}
};
/**
* 預設執行配置
*/
const DEFAULT_EXECUTION_CONFIG = {
parallel: true,
max_agents: 4,
startup_delay: 1000,
health_check_interval: 5000,
error_recovery: 'automatic',
loop_control: {
max_iterations: 3,
quality_target: 0.85,
marginal_threshold: 0.10,
token_budget: 10000,
time_budget_minutes: 20,
auto_continue: false,
require_confirmation: true
},
cost_control: {
show_realtime: true,
warn_at_percent: 80,
hard_stop_at_tokens: 15000,
track_by_agent: true,
currency: 'USD'
}
};
export class AdvancedConfigLoader extends ConfigLoader {
globalConfigPath;
projectConfigPath;
constructor(baseDir) {
super(baseDir);
// 全域配置路徑
this.globalConfigPath = join(homedir(), '.pdca', 'config.yaml');
// 專案配置路徑
const base = baseDir || process.cwd();
this.projectConfigPath = join(base, '.pdca', 'project.yaml');
}
/**
* 載入完整的運行時配置
*/
async loadRuntimeConfig(options = {}) {
console.log('🔧 載入配置中...');
// 1. 載入基礎配置(agent profiles)
const profileName = options.profile || this.getDefaultProfile();
const baseConfig = await this.loadProfile(profileName);
// 2. 載入層次配置
const layeredConfig = await this.loadLayeredConfig(options);
// 3. 合併所有配置
const mergedConfig = this.mergeAllConfigs(baseConfig, layeredConfig, options);
// 4. 創建運行時配置
const runtimeConfig = {
...mergedConfig,
sessionId: this.generateSessionId(),
startTime: new Date(),
workingDirectory: process.cwd(),
commandLineOverrides: options.cliOverrides,
environmentOverrides: options.envOverrides
};
// 5. 驗證最終配置
this.validateRuntimeConfig(runtimeConfig);
console.log(`✅ 配置載入完成 (模式: ${this.getEffectiveProfile(options)})`);
return runtimeConfig;
}
/**
* 載入層次配置
*/
async loadLayeredConfig(options) {
const configs = [];
// 1. 內建預設值
configs.push(this.getDefaultConfig());
// 2. 全域配置
if (existsSync(this.globalConfigPath)) {
console.log('📂 載入全域配置');
configs.push(this.loadYamlConfig(this.globalConfigPath));
}
// 3. 專案配置
if (existsSync(this.projectConfigPath)) {
console.log('📂 載入專案配置');
configs.push(this.loadYamlConfig(this.projectConfigPath));
}
// 4. 自定義配置檔
if (options.configFile) {
console.log(`📂 載入自定義配置: ${options.configFile}`);
configs.push(this.loadYamlConfig(resolve(options.configFile)));
}
// 5. 配置集覆蓋
const profileOverride = this.getProfileOverride(options);
if (profileOverride) {
console.log(`🎯 應用配置集: ${this.getEffectiveProfile(options)}`);
configs.push(profileOverride);
}
// 6. 環境變數覆蓋
const envOverride = this.loadEnvironmentOverrides();
if (Object.keys(envOverride).length > 0) {
console.log('🌍 應用環境變數覆蓋');
configs.push(envOverride);
}
// 7. CLI 參數覆蓋
if (options.cliOverrides && Object.keys(options.cliOverrides).length > 0) {
console.log('⚡ 應用 CLI 參數覆蓋');
configs.push(this.buildConfigFromCliOverrides(options.cliOverrides));
}
// 8. 手動覆蓋
if (options.overrides) {
configs.push(options.overrides);
}
return this.deepMergeConfigs(configs);
}
/**
* 獲取預設配置
*/
getDefaultConfig() {
return {
execution: DEFAULT_EXECUTION_CONFIG
};
}
/**
* 獲取配置集覆蓋
*/
getProfileOverride(options) {
const profileName = this.getEffectiveProfile(options);
const profile = BUILTIN_PROFILES[profileName];
if (!profile) {
return null;
}
return {
execution: profile.execution
};
}
/**
* 獲取有效的配置集名稱
*/
getEffectiveProfile(options) {
return options.profile || 'balanced';
}
/**
* 載入環境變數覆蓋
*/
loadEnvironmentOverrides() {
const env = process.env;
const override = {};
// 循環控制
if (env.PDCA_MAX_ITERATIONS) {
const value = env.PDCA_MAX_ITERATIONS === 'null' ? null : parseInt(env.PDCA_MAX_ITERATIONS);
this.setNestedValue(override, 'execution.loop_control.max_iterations', value);
}
if (env.PDCA_QUALITY_TARGET) {
this.setNestedValue(override, 'execution.loop_control.quality_target', parseFloat(env.PDCA_QUALITY_TARGET));
}
if (env.PDCA_TOKEN_BUDGET) {
const value = env.PDCA_TOKEN_BUDGET === 'null' ? null : parseInt(env.PDCA_TOKEN_BUDGET);
this.setNestedValue(override, 'execution.loop_control.token_budget', value);
}
if (env.PDCA_AUTO_CONTINUE) {
this.setNestedValue(override, 'execution.loop_control.auto_continue', env.PDCA_AUTO_CONTINUE === 'true');
}
// 成本控制
if (env.PDCA_SHOW_COST) {
this.setNestedValue(override, 'execution.cost_control.show_realtime', env.PDCA_SHOW_COST === 'true');
}
if (env.PDCA_CURRENCY) {
this.setNestedValue(override, 'execution.cost_control.currency', env.PDCA_CURRENCY);
}
return override;
}
/**
* 從 CLI 覆蓋參數建構配置
*/
buildConfigFromCliOverrides(overrides) {
const config = {};
// 映射 CLI 參數到配置路徑
const mapping = {
'max-iterations': 'execution.loop_control.max_iterations',
'quality-target': 'execution.loop_control.quality_target',
'token-budget': 'execution.loop_control.token_budget',
'time-budget': 'execution.loop_control.time_budget_minutes',
'auto-continue': 'execution.loop_control.auto_continue',
'require-confirmation': 'execution.loop_control.require_confirmation',
'show-cost': 'execution.cost_control.show_realtime',
'currency': 'execution.cost_control.currency',
'max-agents': 'execution.max_agents'
};
for (const [cliKey, configPath] of Object.entries(mapping)) {
if (overrides[cliKey] !== undefined) {
this.setNestedValue(config, configPath, overrides[cliKey]);
}
}
return config;
}
/**
* 載入 YAML 配置檔
*/
loadYamlConfig(path) {
try {
const content = readFileSync(path, 'utf-8');
return parse(content);
}
catch (error) {
console.warn(`⚠️ 無法載入配置檔: ${path}`, error);
return {};
}
}
/**
* 深度合併多個配置
*/
deepMergeConfigs(configs) {
const result = {};
for (const config of configs) {
this.deepMerge(result, config);
}
return result;
}
/**
* 合併所有配置
*/
mergeAllConfigs(baseConfig, layeredConfig, options) {
const merged = { ...baseConfig };
// 合併 execution 配置
if (layeredConfig.execution) {
merged.execution = this.deepMerge(merged.execution || {}, layeredConfig.execution);
}
// 合併其他配置
Object.keys(layeredConfig).forEach(key => {
if (key !== 'execution' && layeredConfig[key]) {
merged[key] = this.deepMerge(merged[key] || {}, layeredConfig[key]);
}
});
return merged;
}
/**
* 深度合併物件
*/
deepMerge(target, source) {
if (source === null || source === undefined) {
return target;
}
if (Array.isArray(source)) {
return [...source];
}
if (typeof source === 'object') {
const result = { ...target };
for (const key in source) {
if (source.hasOwnProperty(key)) {
if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key])) {
result[key] = this.deepMerge(result[key] || {}, source[key]);
}
else {
result[key] = source[key];
}
}
}
return result;
}
return source;
}
/**
* 設定嵌套值
*/
setNestedValue(obj, path, value) {
const keys = path.split('.');
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!(key in current) || typeof current[key] !== 'object') {
current[key] = {};
}
current = current[key];
}
current[keys[keys.length - 1]] = value;
}
/**
* 驗證運行時配置
*/
validateRuntimeConfig(config) {
if (!config.execution) {
throw new Error('執行配置不能為空');
}
const { loop_control, cost_control } = config.execution;
// 驗證循環控制
if (loop_control.quality_target < 0 || loop_control.quality_target > 1) {
throw new Error('品質目標必須在 0-1 之間');
}
if (loop_control.marginal_threshold < 0 || loop_control.marginal_threshold > 1) {
throw new Error('邊際改進閾值必須在 0-1 之間');
}
if (loop_control.max_iterations !== null && loop_control.max_iterations < 1) {
throw new Error('最大迭代次數必須大於 0');
}
if (loop_control.token_budget !== null && loop_control.token_budget < 1) {
throw new Error('Token 預算必須大於 0');
}
// 驗證成本控制
if (cost_control.warn_at_percent !== null &&
(cost_control.warn_at_percent < 0 || cost_control.warn_at_percent > 100)) {
throw new Error('成本警告百分比必須在 0-100 之間');
}
}
/**
* 生成 session ID
*/
generateSessionId() {
return `pdca_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
/**
* 獲取可用的配置集
*/
async getAvailableProfiles() {
// 先獲取內建配置集
const builtinProfiles = Object.keys(BUILTIN_PROFILES);
// 再獲取檔案系統中的配置集
const fileProfiles = await super.getAvailableProfiles();
// 合併並去重
const allProfiles = [...new Set([...builtinProfiles, ...fileProfiles])];
return allProfiles.sort();
}
/**
* 獲取配置集描述
*/
getProfileDescription(profileName) {
const profile = BUILTIN_PROFILES[profileName];
return profile ? profile.description : null;
}
/**
* 顯示當前配置摘要
*/
displayConfigSummary(config) {
const { loop_control, cost_control } = config.execution;
console.log('\n📋 配置摘要');
console.log('─'.repeat(50));
console.log(`🎯 最大迭代: ${loop_control.max_iterations ?? '無限制'}`);
console.log(`📊 品質目標: ${(loop_control.quality_target * 100).toFixed(0)}%`);
console.log(`💰 Token 預算: ${loop_control.token_budget?.toLocaleString() ?? '無限制'}`);
console.log(`⏱️ 時間預算: ${loop_control.time_budget_minutes ?? '無限制'} 分鐘`);
console.log(`🔄 自動繼續: ${loop_control.auto_continue ? '是' : '否'}`);
console.log(`✋ 需要確認: ${loop_control.require_confirmation ? '是' : '否'}`);
console.log(`💸 即時成本: ${cost_control.show_realtime ? '顯示' : '隱藏'}`);
console.log(`⚠️ 成本警告: ${cost_control.warn_at_percent ?? '關閉'}%`);
console.log('─'.repeat(50));
}
}
//# sourceMappingURL=advanced-config-loader.js.map