Skip to content

Commit 5e81196

Browse files
fix(cli): auto-propagate LLM_API_KEY to provider-specific env vars via config-driven detection (#59)
* fix(cli): propagate LLM_API_KEY to DEEPSEEK_API_KEY for DeepSeek provider * fix(cli): auto-propagate LLM_API_KEY to provider-specific env vars via config-driven detection * fix(cli): Enhance LLM Provider Support and Streamline API Key Configuration * fix(cli): simplify LLM provider keys and env configuration example --------- Co-authored-by: wutongyuoncce <zhang3304984553@gmail.com>
1 parent 51b6d4f commit 5e81196

2 files changed

Lines changed: 50 additions & 2 deletions

File tree

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
# OpenAI: LLM_API_KEY=sk-...
33
# Anthropic: LLM_API_KEY=sk-ant-...
44
# Gemini: LLM_API_KEY=AIza...
5+
# DeepSeek: LLM_API_KEY=sk-...
56
LLM_API_KEY=your-key-here

openkb/cli.py

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,27 @@ def filter(self, record: logging.LogRecord) -> bool:
5252
load_dotenv() # load from cwd (covers running inside the KB dir)
5353

5454

55+
_KNOWN_PROVIDER_KEYS = (
56+
"OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GEMINI_API_KEY",
57+
"DEEPSEEK_API_KEY", "MISTRAL_API_KEY", "MOONSHOT_API_KEY",
58+
"ZHIPUAI_API_KEY", "DASHSCOPE_API_KEY",
59+
)
60+
61+
62+
def _extract_provider(model: str) -> str | None:
63+
"""Extract the LiteLLM provider name from a model string.
64+
65+
``model`` uses ``provider/model`` LiteLLM format.
66+
OpenAI models can omit the prefix; default to ``"openai"``.
67+
"""
68+
model = model.strip()
69+
if not model:
70+
return None
71+
if "/" in model:
72+
return model.split("/")[0].lower()
73+
return "openai"
74+
75+
5576
def _setup_llm_key(kb_dir: Path | None = None) -> None:
5677
"""Set LiteLLM API key from LLM_API_KEY env var if present.
5778
@@ -62,6 +83,8 @@ def _setup_llm_key(kb_dir: Path | None = None) -> None:
6283
6384
Also propagates to provider-specific env vars (OPENAI_API_KEY, etc.)
6485
so that the Agents SDK litellm provider can pick them up.
86+
Provider is auto-detected from the KB config when available; otherwise
87+
a common provider set is used as a fallback.
6588
"""
6689
if kb_dir is not None:
6790
env_file = kb_dir / ".env"
@@ -74,9 +97,23 @@ def _setup_llm_key(kb_dir: Path | None = None) -> None:
7497
load_dotenv(global_env, override=False)
7598

7699
api_key = os.environ.get("LLM_API_KEY", "")
100+
101+
# Try to resolve the active provider from the KB config
102+
provider: str | None = None
103+
if kb_dir is not None:
104+
config_path = kb_dir / ".openkb" / "config.yaml"
105+
if config_path.exists():
106+
config = load_config(config_path)
107+
model = config.get("model", "")
108+
provider = _extract_provider(str(model))
109+
77110
if not api_key:
78111
# Check if any provider key is already set
79-
has_key = any(os.environ.get(k) for k in ("OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GEMINI_API_KEY"))
112+
check_keys = (
113+
(f"{provider.upper()}_API_KEY",) if provider
114+
else _KNOWN_PROVIDER_KEYS
115+
)
116+
has_key = any(os.environ.get(k) for k in check_keys)
80117
if not has_key:
81118
click.echo(
82119
"Warning: No LLM API key found. Set one of:\n"
@@ -86,7 +123,16 @@ def _setup_llm_key(kb_dir: Path | None = None) -> None:
86123
)
87124
else:
88125
litellm.api_key = api_key
89-
for env_var in ("OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GEMINI_API_KEY"):
126+
127+
# Dynamically set the provider-specific env var when possible
128+
if provider:
129+
provider_env = f"{provider.upper()}_API_KEY"
130+
if not os.environ.get(provider_env):
131+
os.environ[provider_env] = api_key
132+
133+
# Fallback: also set common provider keys so multi-provider
134+
# configs (e.g. PageIndex Cloud) still work
135+
for env_var in _KNOWN_PROVIDER_KEYS:
90136
if not os.environ.get(env_var):
91137
os.environ[env_var] = api_key
92138

@@ -462,6 +508,7 @@ def init(model, language):
462508
click.echo(" OpenAI: gpt-5.4-mini, gpt-5.4")
463509
click.echo(" Anthropic: anthropic/claude-sonnet-4-6, anthropic/claude-opus-4-6")
464510
click.echo(" Gemini: gemini/gemini-3.1-pro-preview, gemini/gemini-3-flash-preview")
511+
click.echo(" DeepSeek: deepseek/deepseek-v4-flash, deepseek/deepseek-v4-pro")
465512
click.echo(" Others: see https://docs.litellm.ai/docs/providers")
466513
click.echo()
467514
if model is None and _stdin_is_tty():

0 commit comments

Comments
 (0)