ResolveUserProviderKeys computes effective API keys and per-provider availability for a given user. It considers the provider's credential policy flags alongside central (DB/deployment) keys and the user's personal keys.
( fallback ProviderAPIKeys, providers []ConfiguredProvider, userKeys []UserProviderKey, )
| 278 | // policy flags alongside central (DB/deployment) keys and the user's |
| 279 | // personal keys. |
| 280 | func ResolveUserProviderKeys( |
| 281 | fallback ProviderAPIKeys, |
| 282 | providers []ConfiguredProvider, |
| 283 | userKeys []UserProviderKey, |
| 284 | ) (ProviderAPIKeys, map[string]ProviderAvailability) { |
| 285 | merged := ProviderAPIKeys{ |
| 286 | OpenAI: strings.TrimSpace(fallback.OpenAI), |
| 287 | Anthropic: strings.TrimSpace(fallback.Anthropic), |
| 288 | ByProvider: map[string]string{}, |
| 289 | BaseURLByProvider: map[string]string{}, |
| 290 | } |
| 291 | for provider, apiKey := range fallback.ByProvider { |
| 292 | normalizedProvider := NormalizeProvider(provider) |
| 293 | if normalizedProvider == "" { |
| 294 | continue |
| 295 | } |
| 296 | if key := strings.TrimSpace(apiKey); key != "" { |
| 297 | merged.ByProvider[normalizedProvider] = key |
| 298 | } |
| 299 | } |
| 300 | for provider, baseURL := range fallback.BaseURLByProvider { |
| 301 | normalizedProvider := NormalizeProvider(provider) |
| 302 | if normalizedProvider == "" { |
| 303 | continue |
| 304 | } |
| 305 | if url := strings.TrimSpace(baseURL); url != "" { |
| 306 | merged.BaseURLByProvider[normalizedProvider] = url |
| 307 | } |
| 308 | } |
| 309 | if merged.OpenAI != "" { |
| 310 | merged.ByProvider[fantasyopenai.Name] = merged.OpenAI |
| 311 | } |
| 312 | if merged.Anthropic != "" { |
| 313 | merged.ByProvider[fantasyanthropic.Name] = merged.Anthropic |
| 314 | } |
| 315 | |
| 316 | userKeyByProviderID := make(map[uuid.UUID]string, len(userKeys)) |
| 317 | for _, userKey := range userKeys { |
| 318 | if userKey.ChatProviderID == uuid.Nil { |
| 319 | continue |
| 320 | } |
| 321 | if key := strings.TrimSpace(userKey.APIKey); key != "" { |
| 322 | userKeyByProviderID[userKey.ChatProviderID] = key |
| 323 | } |
| 324 | } |
| 325 | |
| 326 | availabilityByProvider := make(map[string]ProviderAvailability, len(providers)) |
| 327 | for _, provider := range providers { |
| 328 | normalizedProvider := NormalizeProvider(provider.Provider) |
| 329 | if normalizedProvider == "" { |
| 330 | continue |
| 331 | } |
| 332 | |
| 333 | if url := strings.TrimSpace(provider.BaseURL); url != "" { |
| 334 | merged.BaseURLByProvider[normalizedProvider] = url |
| 335 | } |
| 336 | |
| 337 | var userKey string |