feat(llm): add DeepSeek V4 Pro/Flash as LLM provider
From the PR description
Summary
Adds DeepSeek V4 Pro and V4 Flash as a first-class LLM provider in Mike.
Changes
Backend:
- New
deepseek.tsadapter - Chat Completions API with streaming, tool calls, and thinking/reasoning support models.ts-deepseek-v4-pro(main tier),deepseek-v4-flash(mid/low tier)types.ts-deepseekadded to Provider and UserApiKeysindex.ts- routing to DeepSeek adapterenv.ts-DEEPSEEK_API_KEYin Zod schema + provider key checkuserApiKeys.ts-deepseekin ApiKeyProvider, PROVIDERS, envApiKeyuserSettings.ts- DeepSeek considered in resolveTitleModeluser.tsroute - DeepSeek in title fallback chain
Frontend:
ModelToggle.tsx- DeepSeek group with V4 Pro (main) and V4 Flash (settings)modelAvailability.ts-deepseekin ModelProvider, providerLabel, modelGroupToProvidermikeApi.ts-deepseekin ApiKeyProviderapi-keys/page.tsx- DeepSeek API key fieldUserProfileContext.tsx-deepseekin providers list and emptyApiKeysTabularReviewView.tsx-deepseekin provider validation array
Tests:
env.test.ts-DEEPSEEK_API_KEYcleanup in provider key testlogger.test.ts-DEEPSEEK_API_KEYin sensitive env vars listenv-isolation.test.ts-DEEPSEEKin forbidden name tokens
Docs:
ENVIRONMENT-VARIABLES.md-DEEPSEEK_API_KEYrow.env.example-DEEPSEEK_API_KEY=placeholder
Why a separate adapter?
DeepSeek API is OpenAI-compatible but uses Chat Completions API (/v1/chat/completions), not the Responses API (/v1/responses) that the existing openai.ts adapter uses. These are different endpoints with different request/response formats.
Test results
- Backend typecheck: pass
- Frontend typecheck: pass
- Backend tests: 142 passed
- Frontend tests: 85 passed
- Backend lint: pass
- Frontend lint: pass
Security
- API key stored in
.env(gitignored) and AWS Secrets Manager - never in Git - No secrets in diff (verified with grep)
- Key is optional - app runs without it
Our analysis
Add DeepSeek as an LLM provider — read the full analysis →
Think the analysis missed something the PR description covers?
Capture this PR into my fork
Download a Markdown prompt that tells Claude how to port every
commit in this PR into your working tree. Run it via
claude -p < capture-pull-9.md from
inside the repo you want the changes in.