(
filePath: string,
{ providerSettingsManager, contextProxy, customModesManager }: ImportOptions,
)
| 133 | * - Warnings are returned for any issues encountered |
| 134 | */ |
| 135 | export async function importSettingsFromPath( |
| 136 | filePath: string, |
| 137 | { providerSettingsManager, contextProxy, customModesManager }: ImportOptions, |
| 138 | ) { |
| 139 | // Use a lenient schema that accepts any apiConfigs, then validate each individually |
| 140 | const lenientProviderProfilesSchema = providerProfilesSchema.extend({ |
| 141 | apiConfigs: z.record(z.string(), z.any()), |
| 142 | }) |
| 143 | |
| 144 | const lenientSchema = z.object({ |
| 145 | providerProfiles: lenientProviderProfilesSchema, |
| 146 | globalSettings: z.unknown().optional(), |
| 147 | }) |
| 148 | |
| 149 | try { |
| 150 | const previousProviderProfiles = await providerSettingsManager.export() |
| 151 | |
| 152 | const rawData = JSON.parse(await fs.readFile(filePath, "utf-8")) |
| 153 | const { providerProfiles: rawProviderProfiles, globalSettings: rawGlobalSettings } = |
| 154 | lenientSchema.parse(rawData) |
| 155 | |
| 156 | // Track warnings for profiles that had issues |
| 157 | const warnings: string[] = [] |
| 158 | const validApiConfigs: Record<string, ProviderSettingsWithId> = {} |
| 159 | |
| 160 | // Process each apiConfig individually with sanitization |
| 161 | for (const [configName, rawConfig] of Object.entries(rawProviderProfiles.apiConfigs)) { |
| 162 | // First sanitize to handle invalid apiProvider values |
| 163 | const { config: sanitizedConfig, warning } = sanitizeProviderConfig(configName, rawConfig) |
| 164 | if (warning) { |
| 165 | warnings.push(warning) |
| 166 | } |
| 167 | |
| 168 | // Then validate the sanitized config |
| 169 | const result = providerSettingsWithIdSchema.safeParse(sanitizedConfig) |
| 170 | if (result.success) { |
| 171 | validApiConfigs[configName] = result.data |
| 172 | } else { |
| 173 | // Profile is completely invalid - skip it |
| 174 | const issues = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join(", ") |
| 175 | warnings.push(`Profile "${configName}" was skipped: ${issues}`) |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | // If no valid configs were imported and there were issues, report them |
| 180 | if (Object.keys(validApiConfigs).length === 0 && warnings.length > 0) { |
| 181 | return { |
| 182 | success: false, |
| 183 | error: `No valid profiles could be imported:\n${warnings.join("\n")}`, |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | // Determine the currentApiConfigName: |
| 188 | // 1. If the imported currentApiConfigName exists in validApiConfigs, use it |
| 189 | // 2. Otherwise, fall back to the first valid imported profile |
| 190 | // 3. If no valid profiles were imported, keep the previous currentApiConfigName |
| 191 | let currentApiConfigName = rawProviderProfiles.currentApiConfigName |
| 192 | const validProfileNames = Object.keys(validApiConfigs) |
no test coverage detected