From 4b16bc31125018ad3d3e46706881596a226f5352 Mon Sep 17 00:00:00 2001 From: asepharyana Date: Wed, 15 Jul 2026 01:06:36 +0700 Subject: [PATCH] feat(provider): enhance Claude provider configuration to support environment variable fallback --- src/model/app_config.rs | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/model/app_config.rs b/src/model/app_config.rs index 3f21a3c..101f850 100644 --- a/src/model/app_config.rs +++ b/src/model/app_config.rs @@ -143,15 +143,19 @@ struct ClaudeSettings { env: Option, } -/// Read `~/.claude/settings.json` and return a `ProviderConfig` if the file -/// contains `ANTHROPIC_BASE_URL` and `ANTHROPIC_API_KEY` in its `env` block. +/// Return a `ProviderConfig` for the Claude provider, checking both +/// `~/.claude/settings.json` and the process environment. +/// +/// Flow: try the file (`env.ANTHROPIC_BASE_URL` + `env.ANTHROPIC_API_KEY`) +/// first → fall back to the `ANTHROPIC_BASE_URL` / `ANTHROPIC_API_KEY` env +/// vars → if neither source has both values, return `None`. +/// +/// Why: Claude Code may inject credentials via env vars (OAuth session) rather +/// than through its settings file, so reading only the file misses them. fn detect_claude_settings_provider() -> Option { - let path = dirs::home_dir()?.join(".claude").join("settings.json"); - let content = std::fs::read_to_string(&path).ok()?; - let settings: ClaudeSettings = serde_json::from_str(&content).ok()?; - let env = settings.env?; - let base_url = env.anthropic_base_url?; - let _ = env.anthropic_api_key?; // presence check — stored as env var, not in config. + // Prefer the file, then fall back to env vars. + let (base_url, _key) = claude_credentials_from_file() + .or_else(claude_credentials_from_env)?; Some(ProviderConfig { api_base: base_url, api_key_env: Some("ANTHROPIC_API_KEY".to_string()), @@ -159,3 +163,22 @@ fn detect_claude_settings_provider() -> Option { default_api_key: None, }) } + +/// Try to read Claude credentials from `~/.claude/settings.json`'s `env` block. +fn claude_credentials_from_file() -> Option<(String, String)> { + let path = dirs::home_dir()?.join(".claude").join("settings.json"); + let content = std::fs::read_to_string(&path).ok()?; + let settings: ClaudeSettings = serde_json::from_str(&content).ok()?; + let env = settings.env?; + let base_url = env.anthropic_base_url?; + let key = env.anthropic_api_key?; + Some((base_url, key)) +} + +/// Try to read Claude credentials from `ANTHROPIC_BASE_URL` / +/// `ANTHROPIC_API_KEY` environment variables. +fn claude_credentials_from_env() -> Option<(String, String)> { + let base_url = std::env::var("ANTHROPIC_BASE_URL").ok()?; + let key = std::env::var("ANTHROPIC_API_KEY").ok()?; + Some((base_url, key)) +}