LemonCore.Config.Providers (lemon_core v0.1.0)

View Source

LLM provider configuration for API keys and base URLs.

Inspired by Ironclaw's modular config pattern, this module handles provider-specific configuration including API keys, base URLs, and secret references for LLM providers like Anthropic, OpenAI, etc.

Configuration

Configuration is loaded from the TOML config file under [providers]:

[providers.anthropic]
api_key_secret = "llm_anthropic_api_key_raw"
base_url = "https://api.anthropic.com"

[providers.openai]
api_key = "sk-..."
api_key_secret = "openai_api_key"  # Reference to secret store

[providers.openai-codex]
auth_source = "oauth"              # Required: "oauth" or "api_key"
oauth_secret = "llm_openai_codex_api_key"

Environment variables override file configuration:

  • ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL
  • OPENAI_API_KEY, OPENAI_BASE_URL
  • OPENAI_CODEX_API_KEY
  • OPENCODE_API_KEY, OPENCODE_BASE_URL (OpenCode and OpenCode Go)
  • GITHUB_COPILOT_API_KEY

The api_key_secret field allows referencing secrets from the secret store instead of hardcoding API keys in config files.

For providers that support OAuth payloads (anthropic, openai-codex, google_gemini_cli), set auth_source = "oauth" to resolve credential payloads from encrypted secrets. Anthropic keeps raw API keys in llm_anthropic_api_key_raw and Claude Code OAuth payloads in llm_anthropic_api_key to avoid mixing header modes. google_gemini_cli stores its OAuth payload in api_key_secret because the runtime provider expects a JSON {"token","projectId"} value.

Summary

Functions

Returns the default providers configuration as a map.

Gets the API key for a specific provider.

Gets a specific provider's configuration.

Lists all configured provider names.

Resolves providers configuration from settings and environment variables.

Types

provider_config()

@type provider_config() :: %{
  api_key: String.t() | nil,
  base_url: String.t() | nil,
  api_key_secret: String.t() | nil,
  auth_source: String.t() | nil,
  oauth_secret: String.t() | nil,
  project: String.t() | nil,
  project_id: String.t() | nil,
  project_secret: String.t() | nil,
  location: String.t() | nil,
  location_secret: String.t() | nil,
  service_account_json: String.t() | nil,
  service_account_json_secret: String.t() | nil
}

t()

@type t() :: %LemonCore.Config.Providers{
  providers: %{optional(String.t()) => provider_config()}
}

Functions

defaults()

@spec defaults() :: map()

Returns the default providers configuration as a map.

This is used as the base configuration that gets overridden by user settings.

get_api_key(providers, name)

@spec get_api_key(t(), String.t()) :: String.t() | nil

Gets the API key for a specific provider.

Checks both api_key and falls back to resolving api_key_secret if the secret store is available.

Examples

iex> providers = Config.Providers.resolve(%{"providers" => %{"anthropic" => %{"api_key" => "sk-..."}}})
iex> Config.Providers.get_api_key(providers, "anthropic")
"sk-..."

iex> Config.Providers.get_api_key(providers, "unknown")
nil

get_provider(providers, name)

@spec get_provider(t(), String.t()) :: provider_config()

Gets a specific provider's configuration.

Examples

iex> providers = Config.Providers.resolve(%{"providers" => %{"anthropic" => %{"api_key" => "sk-..."}}})
iex> Config.Providers.get_provider(providers, "anthropic")
%{api_key: "sk-..."}

iex> Config.Providers.get_provider(providers, "unknown")
%{}

list_providers(providers)

@spec list_providers(t()) :: [String.t()]

Lists all configured provider names.

Examples

iex> providers = Config.Providers.resolve(%{"providers" => %{"anthropic" => %{}, "openai" => %{}}})
iex> Config.Providers.list_providers(providers)
["anthropic", "openai"]

resolve(settings)

@spec resolve(map()) :: t()

Resolves providers configuration from settings and environment variables.

Priority: environment variables > TOML config > defaults