feat(models): add DeepSeek provider support - #265
Open
luw2007 wants to merge 1 commit into
Open
Conversation
Add "deepseek" as a first-class model provider alongside anthropic, openai, and openrouter: - cli: MODEL_PROVIDERS/MODEL_PROVIDER_KEYS/MODEL_PROVIDER_HARNESSES gain deepseek (pi and mock only — DeepSeek has no opencode wiring, mirroring how openrouter is scoped); DEEPSEEK_API_KEY joins the first-party secret catalog with a setup playbook, format hint, and doctor live-key probe; the dev-ci bootstrap and the deployment scaffold/docs mention it too. - core: MODEL_REGISTRY gains deepseek-v4-flash; modelServiceable, ALL_PROVIDERS_AVAILABLE, onlyProvider, and the opencode branch of modelProviderAvailabilityFor all handle deepseek the same way they already handle openrouter; deepseekApiKey is plumbed through Config, the Pi harness's ProviderKeys/buildModelRuntime, the admin model-providers validation route, the model-credential store's availability map, and wiring's resolveModelProviderKeys. - deepseek joins provider-endpoints.ts's PROVIDER_IDS (with a DEEPSEEK_BASE_URL override), which both reserves the "deepseek" slug against a colliding admin-registered custom provider and gives it the same base-URL override support anthropic/openai/openrouter already have. - every other place that enumerated anthropic/openai/openrouter as a closed set (the built-in model catalog filter, the admin scope-config "current model survives a catalog miss" fallback) now includes deepseek too, so the new provider isn't silently dropped from surfaces that iterate the provider list. - plugins/web-ui: KNOWN_PROVIDERS gains deepseek so the web UI can render and resolve the built-in DeepSeek model. This is a narrower extraction of the DeepSeek-only plumbing split out of a larger local commit that also introduced two unrelated features — a local Keychain credential-resolution mechanism and a secure-drop/browser-uuid proxy feature — both intentionally excluded from this PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
deepseekas a first-class model provider alongsideanthropic,openai, andopenrouter, wired end to end: CLI config/secrets/setup/doctor, core config, the Pi harness, the admin model-providers validation route, the model-credential store, wiring's credential resolution, the built-in model catalog, and the web UI's model picker.Scope note
This PR is a narrower extraction of DeepSeek-only plumbing split out of a larger local commit (
luw2007/qm@a0592bf) that also introduced two unrelated features:localKeychainModelOwnerin config,LOCAL_KEYCHAIN_MODEL_OWNERsecret-schema gating,localKeychainResolverin the credential store, keychain wiring inwiring.ts)plugins/web-ui(browser-uuid.ts, the/dropproxy route, portal identity minting fallback,crypto.randomUUID()→browserUuid()swaps)Both are intentionally excluded here — this PR contains only the DeepSeek provider wiring.
What changed
cli/src/config.ts:MODEL_PROVIDERS/MODEL_PROVIDER_KEYS/MODEL_PROVIDER_HARNESSESgaindeepseek(scoped topiandmock, the same harnessesopenroutergets — DeepSeek has noopencodewiring yet).cli/src/secrets.ts:DEEPSEEK_API_KEYjoins the first-party secret catalog.cli/src/commands/setup.ts,cli/src/backends/doctor.ts,cli/src/backends/dev-ci.ts,cli/src/provider-scaffold.ts,cli/templates/deployment/deployment.md,.env.example: the setup wizard playbook/format hint, the live-key doctor probe, the dev-CI bootstrap check, and the deployment docs/scaffold all mention DeepSeek alongside the existing three providers.src/model/pi-models.ts:MODEL_REGISTRYgainsdeepseek-v4-flash;modelServiceable,ALL_PROVIDERS_AVAILABLE,onlyProvider, and theopencodebranch ofmodelProviderAvailabilityForall treatdeepseekthe same way they already treatopenrouter(including opencode exclusion, since DeepSeek has no opencode wiring).src/model/provider-endpoints.ts:deepseekjoinsPROVIDER_IDSwith aDEEPSEEK_BASE_URLoverride. This both reserves the"deepseek"provider slug against a colliding admin-registered custom provider and gives it the same base-URL override support the other three built-ins have.src/harness/pi-harness.ts:deepseekApiKeyplumbed throughPiHarnessOptions/ProviderKeys/createPiHarness.src/api/routes/admin/model-providers.ts: DeepSeek key-validation request (https://api.deepseek.com/models).src/api/routes/admin/scope-config.ts,src/model/model-catalog.ts,src/api/app-turn.ts: the remaining spots that enumerated{anthropic, openai, openrouter}as a closed set (built-in catalog filter, the "current model survives a catalog miss" fallback, the default provider-keys fallback) now includedeepseektoo.src/config.ts:deepseekApiKeyfield, wired intoproviderKeysPresentand env loading (env.DEEPSEEK_API_KEY) — no local-keychain field.src/deployment/secret-schema.ts:DEEPSEEK_API_KEYgated bymodel-deepseek, whose predicate is a plainMODEL_PROVIDER === "deepseek"check — noLOCAL_KEYCHAIN_MODEL_OWNERexception.src/model/model-credential-store.ts:deepseekadded to the availability status map — nolocalKeychainResolvermechanism/source.src/wiring.ts:deepseekkey resolution in the credential fallback andresolveModelProviderKeys— nolocalKeychainResolver/keychain wiring.plugins/web-ui/src/pi-models.ts:KNOWN_PROVIDERSgainsdeepseek.test/pi-models.test.ts,test/model-registry.test.ts,test/model-credential-route.test.ts,test/secret-schema-drift.test.ts,test/config.test.ts,test/custom-providers.test.ts,test/base-model-serviceability.test.ts,test/public-architecture-docs.test.ts,plugins/web-ui/test/model-options.test.ts,plugins/web-ui/test/pi-models.test.ts, andcli/src/backends/doctor.ts's probe map — no local-keychain assertions.Verification
Ran locally (Node v24.18.0, via
fnm use v24.18.0):test/pi-models.test.ts,test/model-registry.test.ts,test/model-credential-route.test.ts,test/secret-schema-drift.test.ts,test/config.test.ts,test/base-model-serviceability.test.ts,test/webui-model-allowlist.test.ts,test/custom-providers.test.ts,test/admin-resources.test.ts,test/admin-scopes-directory.test.ts,test/provider-endpoints.test.ts,test/public-architecture-docs.test.ts,test/deployment-skill.test.ts,test/slack-index.integration.test.ts— all pass. Also ran the full root suite (test/*.test.ts, 3817 tests) for extra confidence given the change touches shared provider-list plumbing; the only 18 failures are pre-existing environment artifacts unrelated to this change (Codex/OpenCode child-process ESM/requiremismatches, a$PAGERenvironment difference, and sandboxed git-remote networking) — confirmed identical onorigin/mainwith this diff reverted.cli/:test/config.test.ts,test/dev-ci-routing.test.ts,test/doctor.test.ts,test/providers.test.ts,test/secrets.test.ts,test/setup.test.ts,test/stack-configs.test.ts— all pass (108/108).npm run typecheckclean.plugins/web-ui/: full suite (node --test "test/**/*.test.ts") — all pass (500/500).npm run typecheckclean.eslinton every changed file — clean.Self-review
Before opening this PR: no comments were introduced (verified with
git diffagainst the "no comments" convention); greppedopenrouteracrosssrc/,plugins/,test/,cli/and brought every sibling list up to date withdeepseek, including two gaps an independent reviewer pass caught and I fixed before this push —deepseekwas initially declared servable on theopencodeharness (with no actual opencode wiring, which would have booted a deployment that silently couldn't route turns) and the"deepseek"slug wasn't reserved against a colliding custom-provider registration; both are fixed in this diff (seeprovider-endpoints.tsand theopencodebranch ofmodelProviderAvailabilityFor). The diff contains only DeepSeek-provider files — no local-keychain or secure-drop/browser-uuid content.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.