From f7fe5e09a5efd5802c882562c0bdfd8860977780 Mon Sep 17 00:00:00 2001 From: Hunter Bown Date: Sat, 25 Apr 2026 13:52:44 -0500 Subject: [PATCH] fix(#37): make NIM a peer provider in config.example.toml + setup status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A user couldn't find an `NVIDIA_API_KEY` block in `~/.deepseek/config.toml` because the example file only mentioned NIM as commented-out alternates to the top-level keys. Two fixes: - `config.example.toml` now has explicit `[providers.deepseek]` and `[providers.nvidia_nim]` sections (placed after all top-level keys so the TOML still parses cleanly), each documenting `api_key` / `base_url` / `model` plus the env vars that override them. Both providers can be stored at once and toggled via `/provider` or `--provider` without re-entering keys. - `setup --status` "missing api_key" message is now provider-aware: on `nvidia-nim` it points at `NVIDIA_API_KEY` + `[providers.nvidia_nim]` + `deepseek auth set --provider nvidia-nim`, instead of the DeepSeek-only hint. Audit verified: the v0.5.0 multi-turn replay fix path (`should_replay_reasoning_content` → `requires_reasoning_content` in `crates/tui/src/client.rs:1796`) keys off the model name (matches `deepseek-v4`), not the provider, so NIM-hosted V4 models get the replay automatically. No NIM-specific 400-class regression there. Closes #37 (docs/UX); the live multi-turn-against-NIM verification remains a manual smoke step listed in the issue (no NIM creds in CI). --- config.example.toml | 38 +++++++++++++++++++++++++++++--------- crates/tui/src/main.rs | 23 +++++++++++++++++++---- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/config.example.toml b/config.example.toml index f7a475c7..b438f6a0 100644 --- a/config.example.toml +++ b/config.example.toml @@ -7,21 +7,19 @@ # See `docs/CONFIGURATION.md` for how config is loaded (profiles, env overrides, etc.). # ───────────────────────────────────────────────────────────────────────────────── -# API Keys +# Active provider + DeepSeek defaults # ───────────────────────────────────────────────────────────────────────────────── +# Choose which provider to use by default. Per-provider credentials live in the +# `[providers.deepseek]` and `[providers.nvidia_nim]` sections near the bottom of +# this file — keeping both stored at once means `/provider deepseek` and +# `/provider nvidia-nim` (or `--provider nvidia-nim`) toggle without having to +# re-enter keys. Top-level `api_key` / `base_url` are still read as DeepSeek +# defaults when `[providers.deepseek]` is absent (backward compatibility). provider = "deepseek" # deepseek | nvidia-nim api_key = "YOUR_DEEPSEEK_API_KEY" # must be non-empty - -# ───────────────────────────────────────────────────────────────────────────────── -# Base URLs -# ───────────────────────────────────────────────────────────────────────────────── base_url = "https://api.deepseek.com" # base_url = "https://api.deepseeki.com" # China users # base_url = "https://api.deepseek.com/beta" # DeepSeek beta features such as strict tool mode -# For NVIDIA NIM-hosted DeepSeek: -# provider = "nvidia-nim" -# api_key = "YOUR_NVIDIA_API_KEY" -# base_url = "https://integrate.api.nvidia.com/v1" # ───────────────────────────────────────────────────────────────────────────────── # Default Models @@ -70,6 +68,28 @@ max_subagents = 5 # optional (1-20) # managed_config_path = "/etc/deepseek/managed_config.toml" # requirements_path = "/etc/deepseek/requirements.toml" +# ───────────────────────────────────────────────────────────────────────────────── +# Per-provider credentials (peer providers — NIM is first-class, not a flag) +# ───────────────────────────────────────────────────────────────────────────────── +# Both providers can be stored at once; `provider = "..."` (top of file) or +# `/provider deepseek` / `/provider nvidia-nim` switches between them without +# having to re-enter keys. Env vars override anything set here: +# DeepSeek: DEEPSEEK_API_KEY, DEEPSEEK_BASE_URL, DEEPSEEK_MODEL +# NIM: NVIDIA_API_KEY (or NVIDIA_NIM_API_KEY), NIM_BASE_URL +# (or NVIDIA_NIM_BASE_URL / NVIDIA_BASE_URL), NVIDIA_NIM_MODEL + +# DeepSeek Platform (https://platform.deepseek.com) +[providers.deepseek] +# api_key = "YOUR_DEEPSEEK_API_KEY" +# base_url = "https://api.deepseek.com" +# model = "deepseek-v4-pro" + +# NVIDIA NIM-hosted DeepSeek V4 (https://build.nvidia.com) +[providers.nvidia_nim] +# api_key = "YOUR_NVIDIA_API_KEY" +# base_url = "https://integrate.api.nvidia.com/v1" +# model = "deepseek-ai/deepseek-v4-pro" # or deepseek-ai/deepseek-v4-flash + # ───────────────────────────────────────────────────────────────────────────────── # TUI # ───────────────────────────────────────────────────────────────────────────────── diff --git a/crates/tui/src/main.rs b/crates/tui/src/main.rs index 1c57dcfe..4f3d0fec 100644 --- a/crates/tui/src/main.rs +++ b/crates/tui/src/main.rs @@ -1118,10 +1118,25 @@ fn run_setup_status(config: &Config, workspace: &Path) -> Result<()> { " {} api_key: set via config", "✓".truecolor(aqua_r, aqua_g, aqua_b) ), - ApiKeySource::Missing => println!( - " {} api_key: missing (set DEEPSEEK_API_KEY or run `deepseek login`)", - "✗".truecolor(red_r, red_g, red_b) - ), + ApiKeySource::Missing => { + let (env_var, login_hint) = match config.api_provider() { + crate::config::ApiProvider::NvidiaNim => ( + "NVIDIA_API_KEY", + "deepseek auth set --provider nvidia-nim --api-key \"...\"", + ), + crate::config::ApiProvider::Deepseek => { + ("DEEPSEEK_API_KEY", "deepseek login --api-key \"...\"") + } + }; + println!( + " {} api_key: missing (set {env_var} or `[providers.{}].api_key` in ~/.deepseek/config.toml; or run `{login_hint}`)", + "✗".truecolor(red_r, red_g, red_b), + match config.api_provider() { + crate::config::ApiProvider::NvidiaNim => "nvidia_nim", + crate::config::ApiProvider::Deepseek => "deepseek", + } + ); + } } println!( " · base_url: {}",