WIP: Add DeepSeek Anthropic-compatible route#3449
Conversation
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
There was a problem hiding this comment.
Code Review
This pull request introduces a new DeepseekAnthropic provider variant, allowing users to opt-in to a DeepSeek route that communicates via the Anthropic Messages wire protocol. The changes span configuration structures, provider registries, and TUI client implementations to support the new endpoint, authentication headers, and aliases. The review feedback highlights three key areas for improvement: a security risk where ANTHROPIC_API_KEY could be leaked to DeepSeek servers if configured as a fallback, missing hyphenated aliases in the subagent provider key matching logic, and an inconsistency in EnvRuntimeOverrides that prevents overriding the base URL for the new provider via environment variables.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| fn env_vars(&self) -> &'static [&'static str] { | ||
| &["DEEPSEEK_API_KEY", "ANTHROPIC_API_KEY"] | ||
| } |
There was a problem hiding this comment.
Including ANTHROPIC_API_KEY in the list of environment variables for DeepseekAnthropic poses a security risk. If a user has ANTHROPIC_API_KEY set in their environment (which is common for Anthropic users) but has not set DEEPSEEK_API_KEY, the application will fall back to using the Anthropic API key and send it to DeepSeek's servers (https://api.deepseek.com/anthropic). This results in credential exposure to a third party. Since DeepSeek's Anthropic-compatible endpoint requires a DeepSeek API key and cannot authenticate with an Anthropic key, ANTHROPIC_API_KEY should be removed from this list.
| fn env_vars(&self) -> &'static [&'static str] { | |
| &["DEEPSEEK_API_KEY", "ANTHROPIC_API_KEY"] | |
| } | |
| fn env_vars(&self) -> &'static [&'static str] { | |
| &["DEEPSEEK_API_KEY"] | |
| } |
| ApiProvider::DeepseekAnthropic => matches!( | ||
| normalized.as_str(), | ||
| "deepseek_anthropic" | "deepseek_claude" | "deepseek_anthropic_api" | ||
| ), |
There was a problem hiding this comment.
The subagent provider key matching is missing the hyphenated aliases (deepseek-anthropic and deepseek-claude), which are supported elsewhere in the configuration (e.g., in Serde aliases). If a user configures a subagent using the hyphenated format, it will fail to match. We should include the hyphenated versions to ensure consistency and robustness.
| ApiProvider::DeepseekAnthropic => matches!( | |
| normalized.as_str(), | |
| "deepseek_anthropic" | "deepseek_claude" | "deepseek_anthropic_api" | |
| ), | |
| ApiProvider::DeepseekAnthropic => matches!( | |
| normalized.as_str(), | |
| "deepseek_anthropic" | "deepseek-anthropic" | "deepseek_claude" | "deepseek-claude" | "deepseek_anthropic_api" | |
| ), |
| // values (`providers.<name>.base_url`) still win when env is unset. | ||
| match provider { | ||
| ProviderKind::Deepseek => self.deepseek_base_url.clone(), | ||
| ProviderKind::DeepseekAnthropic => None, |
There was a problem hiding this comment.
Returning None here means that EnvRuntimeOverrides does not support overriding the base URL for the deepseek-anthropic provider via environment variables, unlike other providers (e.g., Deepseek uses self.deepseek_base_url.clone()). This creates an inconsistency between crates/config and crates/tui (where DEEPSEEK_ANTHROPIC_BASE_URL or similar is handled). Consider adding a deepseek_anthropic_base_url field to EnvRuntimeOverrides to support environment-based base URL overrides consistently.
c63864c to
69d198f
Compare
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
Add an opt-in deepseek-anthropic provider that resolves to DeepSeek's Anthropic-compatible endpoint and model defaults while leaving the existing DeepSeek chat-completions route unchanged. Route the provider through the existing Anthropic Messages adapter, x-api-key header dialect, and TUI provider config table, with runtime capability metadata marking it as AnthropicMessages. Update the provider docs, provider registry drift checker, and web facts maps so the manual provider implementation stays covered by generated guards. Verified with: cargo fmt --all -- --check; cargo test -p codewhale-config --locked provider_metadata_defaults_match_runtime_helpers; cargo test -p codewhale-config --locked deepseek_anthropic_route_defaults_to_anthropic_endpoint; cargo test -p codewhale-tui --bin codewhale-tui --locked messages_url_tolerates_v1_suffix; cargo test -p codewhale-tui --bin codewhale-tui --locked deepseek_anthropic_uses_anthropic_header_dialect; cargo test -p codewhale-tui --bin codewhale-tui --locked provider_capability_deepseek_anthropic_uses_messages_payload; cargo test -p codewhale-tui --bin codewhale-tui --locked body_maps_reasoning_effort_to_adaptive_thinking_and_effort; cargo test -p codewhale-tui --bin codewhale-tui --locked sse_fixture_decodes_text_thinking_signature_and_tool_use; cargo test -p codewhale-tui --bin codewhale-tui --locked parse_usage_reads_deepseek_cache_and_reasoning_tokens; cargo test -p codewhale-tui --bin codewhale-tui --locked api_provider_metadata_helpers_follow_config_provider_metadata; cargo test -p codewhale-tui --bin codewhale-tui --locked provider_config_key_follows_config_provider_metadata; node web/scripts/derive-facts.mjs; python3 scripts/check-provider-registry.py; ./scripts/release/check-versions.sh; ./scripts/release/check-ohos-deps.sh; git diff --check
69d198f to
e93cc8f
Compare
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
Goal
Add a first-class opt-in route for DeepSeek's Anthropic-compatible API without changing the existing DeepSeek Chat Completions path.
Refs #2963.
Changes
deepseek-anthropic/deepseek_anthropicprovider metadata, config tables, aliases, defaults, and env var wiring.https://api.deepseek.com/anthropicwithdeepseek-v4-pro.x-api-key/anthropic-versionheader dialect.AnthropicMessages, while keeping DeepSeek-native cache telemetry scoped to the existing DeepSeek routes.Upstream Docs Checked
Verification
cargo fmt --all -- --checkcargo test -p codewhale-config --locked provider_metadata_defaults_match_runtime_helperscargo test -p codewhale-config --locked deepseek_anthropic_route_defaults_to_anthropic_endpointcargo test -p codewhale-tui --bin codewhale-tui --locked messages_url_tolerates_v1_suffixcargo test -p codewhale-tui --bin codewhale-tui --locked deepseek_anthropic_uses_anthropic_header_dialectcargo test -p codewhale-tui --bin codewhale-tui --locked provider_capability_deepseek_anthropic_uses_messages_payloadcargo test -p codewhale-tui --bin codewhale-tui --locked body_maps_reasoning_effort_to_adaptive_thinking_and_effortcargo test -p codewhale-tui --bin codewhale-tui --locked sse_fixture_decodes_text_thinking_signature_and_tool_usecargo test -p codewhale-tui --bin codewhale-tui --locked parse_usage_reads_deepseek_cache_and_reasoning_tokenscargo test -p codewhale-tui --bin codewhale-tui --locked api_provider_metadata_helpers_follow_config_provider_metadatacargo test -p codewhale-tui --bin codewhale-tui --locked provider_config_key_follows_config_provider_metadatanode web/scripts/derive-facts.mjspython3 scripts/check-provider-registry.py./scripts/release/check-versions.sh./scripts/release/check-ohos-deps.shgit diff --checkRemaining Risk
This wires the documented API shape and adapter path, but does not prove account-specific server-tool behavior against a live DeepSeek key. That should stay as a follow-up manual probe before marking #2963 fully done.