* 从 config.yaml 解析配置(纯解析,不含环境变量覆盖)
(defaults: AppConfig)
| 21 | * 从 config.yaml 解析配置(纯解析,不含环境变量覆盖) |
| 22 | */ |
| 23 | function parseYamlConfig(defaults: AppConfig): { config: AppConfig; raw: Record<string, unknown> | null } { |
| 24 | const result = { ...defaults, fingerprint: { ...defaults.fingerprint } }; |
| 25 | let raw: Record<string, unknown> | null = null; |
| 26 | |
| 27 | if (!existsSync('config.yaml')) return { config: result, raw }; |
| 28 | |
| 29 | try { |
| 30 | const content = readFileSync('config.yaml', 'utf-8'); |
| 31 | const yaml = parseYaml(content); |
| 32 | raw = yaml; |
| 33 | |
| 34 | if (yaml.port) result.port = yaml.port; |
| 35 | if (yaml.timeout) result.timeout = yaml.timeout; |
| 36 | if (yaml.proxy) result.proxy = yaml.proxy; |
| 37 | if (yaml.cursor_model) result.cursorModel = yaml.cursor_model; |
| 38 | if (typeof yaml.max_auto_continue === 'number') result.maxAutoContinue = yaml.max_auto_continue; |
| 39 | if (typeof yaml.max_history_messages === 'number') result.maxHistoryMessages = yaml.max_history_messages; |
| 40 | if (typeof yaml.max_history_tokens === 'number') result.maxHistoryTokens = yaml.max_history_tokens; |
| 41 | if (yaml.fingerprint) { |
| 42 | if (yaml.fingerprint.user_agent) result.fingerprint.userAgent = yaml.fingerprint.user_agent; |
| 43 | } |
| 44 | if (yaml.vision) { |
| 45 | result.vision = { |
| 46 | enabled: yaml.vision.enabled !== false, |
| 47 | mode: yaml.vision.mode || 'ocr', |
| 48 | baseUrl: yaml.vision.base_url || 'https://api.openai.com/v1/chat/completions', |
| 49 | apiKey: yaml.vision.api_key || '', |
| 50 | model: yaml.vision.model || 'gpt-4o-mini', |
| 51 | proxy: yaml.vision.proxy || undefined, |
| 52 | }; |
| 53 | } |
| 54 | // ★ API 鉴权 token |
| 55 | if (yaml.auth_tokens) { |
| 56 | result.authTokens = Array.isArray(yaml.auth_tokens) |
| 57 | ? yaml.auth_tokens.map(String) |
| 58 | : String(yaml.auth_tokens).split(',').map((s: string) => s.trim()).filter(Boolean); |
| 59 | } |
| 60 | // ★ 历史压缩配置 |
| 61 | if (yaml.compression !== undefined) { |
| 62 | const c = yaml.compression; |
| 63 | result.compression = { |
| 64 | enabled: c.enabled !== false, // 默认启用 |
| 65 | level: [1, 2, 3].includes(c.level) ? c.level : 1, |
| 66 | keepRecent: typeof c.keep_recent === 'number' ? c.keep_recent : 10, |
| 67 | earlyMsgMaxChars: typeof c.early_msg_max_chars === 'number' ? c.early_msg_max_chars : 4000, |
| 68 | }; |
| 69 | } |
| 70 | // ★ Thinking 开关(最高优先级) |
| 71 | if (yaml.thinking !== undefined) { |
| 72 | result.thinking = { |
| 73 | enabled: yaml.thinking.enabled !== false, // 默认启用 |
| 74 | }; |
| 75 | } |
| 76 | // ★ 日志文件持久化 |
| 77 | if (yaml.logging !== undefined) { |
| 78 | const persistModes = ['compact', 'full', 'summary']; |
| 79 | result.logging = { |
| 80 | file_enabled: yaml.logging.file_enabled === true, // 默认关闭 |
no test coverage detected