feat: add native DeepSeek provider#11
Conversation
Add native DeepSeek API provider (api.deepseek.com) using the OpenAI-compatible SDK pattern. Supports deepseek-chat (V3) and deepseek-reasoner (R1) models with reasoning_content extraction for the reasoner model. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: zhujian <jiazhu@redhat.com>
|
/hold |
- Fix llm.IsReady to use secret.Resolve instead of os.Getenv, so provider readiness checks are consistent with the UI layer (RenderEnvVarStatus and providerIsEnvReady). This fixes the API key input prompt not appearing. - Update DeepSeek catalog to V4 models (deepseek-v4-flash, deepseek-v4-pro) with 1M context and current pricing; keep legacy chat/reasoner as aliases. - Default model changed to deepseek-v4-flash. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: zhujian <jiazhu@redhat.com>
|
/hold cancel |
yanmxa
left a comment
There was a problem hiding this comment.
Six inline comments on the items I think need addressing before merge. Full review context in the PR conversation.
| var catalog = []modelCatalogEntry{ | ||
| { | ||
| info: llm.ModelInfo{ | ||
| ID: "deepseek-v4-flash", |
There was a problem hiding this comment.
PR description says V3/R1, but the catalog ships deepseek-v4-flash / deepseek-v4-pro as primary entries with 1M input / 384K output limits and a specific deprecation date for the legacy names (line 38). These IDs aren't in DeepSeek's published lineup — please cite the source for the V4 family + pricing, or drop the V4 entries and keep only deepseek-chat / deepseek-reasoner.
There was a problem hiding this comment.
DeepSeek V4 launched April 2025 and is the current production lineup. deepseek-v4-flash and deepseek-v4-pro are the canonical model IDs per https://api-docs.deepseek.com/quick_start/pricing. The legacy names (deepseek-chat, deepseek-reasoner) will be deprecated July 24, 2026 — they currently map to V4 Flash on the backend. Updated the PR description accordingly.
There was a problem hiding this comment.
the PR description updated, we still use the deepseek-v4-flash / deepseek-v4-pro as "The model names deepseek-chat and deepseek-reasoner will be deprecated on 2026/07/24"
There was a problem hiding this comment.
and I removed the deepseek-chat / deepseek-reasoner, because when I call the deepseek list models api: these 2 are removed:
╰─$ curl -s https://api.deepseek.com/models -H "Authorization: Bearer $DEEPSEEK_API_KEY"
{"object":"list","data":[{"id":"deepseek-v4-flash","object":"model","owned_by":"deepseek"},{"id":"deepseek-v4-pro","object":"model","owned_by":"deepseek"}]}%
| return llm.ModelInfo{}, false | ||
| } | ||
|
|
||
| func EstimateCost(modelID string, usage llm.Usage) (llm.Money, bool) { |
There was a problem hiding this comment.
EstimateCost is dead code — internal/app/model.go only switches on llm.MinMax for cost roll-up, nothing calls this. Either add a case llm.DeepSeek: branch in model.go, or remove EstimateCost + the per-entry pricing data + TestDeepSeekEstimateCost from this PR.
| // V4 models (deepseek-v4-*) and legacy deepseek-reasoner all support thinking. | ||
| func supportsThinking(model string) bool { | ||
| lower := strings.ToLower(model) | ||
| return strings.Contains(lower, "reasoner") || strings.Contains(lower, "v4") |
There was a problem hiding this comment.
Allow-list defaults unknown IDs to non-thinking. BigModel uses the opposite shape (bigmodel/client.go:58-68): switch on known non-thinking IDs and default true. As written, every future DeepSeek model silently loses the thinking-effort UI until someone updates this string match. Recommend flipping to a deny-list.
| func (c *Client) ListModels(ctx context.Context) ([]llm.ModelInfo, error) { | ||
| page, err := c.client.Models.List(ctx) | ||
| if err != nil { | ||
| return StaticModels(), nil |
There was a problem hiding this comment.
Silently swallowing the API error and returning the static catalog masks real failures (bad/expired key, network) — user sees a populated model list, then gets a confusing 401 mid-stream. Moonshot/BigModel propagate the error; please match. (Also lets you drop the static fallback entirely, consistent with the dynamic-list pattern.)
| func NewAPIKeyClient(ctx context.Context) (llm.Provider, error) { | ||
| baseURL := os.Getenv("DEEPSEEK_BASE_URL") | ||
| if baseURL == "" { | ||
| baseURL = "https://api.deepseek.com" |
There was a problem hiding this comment.
Missing /v1. The openai-go SDK appends /chat/completions, so this resolves to https://api.deepseek.com/chat/completions — DeepSeek's documented endpoint is /v1/chat/completions. Moonshot/BigModel both include /v1 in the default. Suggest https://api.deepseek.com/v1.
There was a problem hiding this comment.
Per the DeepSeek API docs, both /chat/completions and /v1/chat/completions are valid endpoints. The base URL https://api.deepseek.com is the documented default. Additionally, the Models.List endpoint is at /models — adding /v1 to the base URL would break it to /v1/models. Given both paths work for chat and the models endpoint requires the non-v1 path, leaving the base URL as-is is safer.
There was a problem hiding this comment.
| case "bigmodel": | ||
| return "glm-5.1" | ||
| case "deepseek": | ||
| return "deepseek-v4-flash" |
There was a problem hiding this comment.
Default depends on deepseek-v4-flash actually existing at the API. If the V4 IDs aren't real (see catalog.go comment), every fresh user picks a model the API will reject. Recommend deepseek-chat as a safer default until V4 ships.
There was a problem hiding this comment.
DeepSeek V4 is the current production lineup (launched April 2025). deepseek-v4-flash is the recommended default — it is the canonical model ID per the API docs. The legacy deepseek-chat name will be deprecated July 24, 2026.
- Wire up DeepSeek cost estimation in model.go - Remove legacy deepseek-chat/deepseek-reasoner (API only returns V4) - Propagate ListModels error instead of silently falling back - Simplify supportsThinking (all V4 models support reasoning_effort) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: zhujian <jiazhu@redhat.com>
|
@yanmxa PTAL |
Summary
deepseek-v4-flashanddeepseek-v4-promodels with reasoning_effort extractionTest plan
🤖 Generated with Claude Code