startupApiKey function

String startupApiKey(
  1. String provider,
  2. SecureKeyCache keys, {
  3. required String? baseUrl,
  4. required List<CustomProviderEntry> customProviders,
  5. required bool defaultRoleResolved,
  6. required bool interactive,
  7. Map<String, String>? env,
})

Headless startup API-key resolution: a base URL other than the catalog default (--base-url or config baseUrl) means a user-configured endpoint: local llama.cpp/Ollama/LM Studio servers need no key at all, so the key is optional there (the hosted presets keep requiring one; the config default IS the OpenRouter URL, so compare values, not nullness). Roles mode already tolerates a missing key; the openai-completions adapter omits the Authorization header entirely when the key is empty. The interactive REPL can start without a key: the user can switch providers, models, or base URLs with slash commands before the first run. Headless mode needs a key immediately because it performs a single run and exits.

Saved custom entries for baseUrl carry name-scoped keys (multi-account); they resolve right after the host-scoped slot.

Throws ConfigException when the key is required and missing — the executable maps that to its fa: usage failure.

Implementation

String startupApiKey(
  String provider,
  SecureKeyCache keys, {
  required String? baseUrl,
  required List<CustomProviderEntry> customProviders,
  required bool defaultRoleResolved,
  required bool interactive,
  Map<String, String>? env,
}) {
  // A base URL other than the catalog default (--base-url or config
  // baseUrl) means a user-configured endpoint: local servers need no key.
  final customEndpoint =
      provider == 'openai-completions' &&
      baseUrl != providerCatalog['openrouter']!.defaultBaseUrl;
  // Saved custom entries for this endpoint carry name-scoped keys
  // (multi-account); they resolve right after the host-scoped slot.
  final entryKeyNames = [
    for (final entry in customProviders)
      if (entry.baseUrl == baseUrl && entry.keyName != null) entry.keyName!,
  ];
  final key = defaultRoleResolved || customEndpoint || interactive
      ? (optionalProviderApiKey(
              provider,
              keys,
              baseUrl: baseUrl,
              scopedKeyNames: entryKeyNames,
              env: env,
            ) ??
            '')
      : _requiredProviderApiKey(
          provider,
          keys,
          baseUrl: baseUrl,
          scopedKeyNames: entryKeyNames,
          env: env,
        );
  return key;
}