(aiDataDir: string)
| 43 | // ==================== Config Loading ==================== |
| 44 | |
| 45 | export function loadLlmConfig(aiDataDir: string): AIConfigStore { |
| 46 | const configPath = path.join(aiDataDir, 'llm-config.json') |
| 47 | if (!fs.existsSync(configPath)) { |
| 48 | return { configs: [], defaultAssistant: null, fastModel: null } |
| 49 | } |
| 50 | |
| 51 | try { |
| 52 | const data = JSON.parse(fs.readFileSync(configPath, 'utf-8')) |
| 53 | |
| 54 | const configs = (data.configs || []).map((c: Record<string, unknown>) => { |
| 55 | const provider = (c.provider as string) || '' |
| 56 | const authProfile = c.authProfile as string | undefined |
| 57 | const profileKey = resolveApiKey(provider, authProfile) |
| 58 | const rawKey = (c.apiKey as string) || '' |
| 59 | const fallbackKey = rawKey.startsWith('enc:') ? '' : rawKey |
| 60 | return { |
| 61 | ...c, |
| 62 | apiKey: profileKey || fallbackKey, |
| 63 | } |
| 64 | }) |
| 65 | return { |
| 66 | configs, |
| 67 | defaultAssistant: data.defaultAssistant ?? null, |
| 68 | fastModel: data.fastModel ?? null, |
| 69 | } |
| 70 | } catch { |
| 71 | return { configs: [], defaultAssistant: null, fastModel: null } |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | function resolveSlot(slot: ModelSlot | null | undefined, configs: AIServiceConfig[]): ModelSlot | null { |
| 76 | if (slot && configs.some((c) => c.id === slot.configId)) return slot |
no test coverage detected