Skip to content

feat(models): add DeepSeek provider support - #265

Open
luw2007 wants to merge 1 commit into
yc-software:mainfrom
luw2007:deepseek-provider-pr
Open

feat(models): add DeepSeek provider support#265
luw2007 wants to merge 1 commit into
yc-software:mainfrom
luw2007:deepseek-provider-pr

Conversation

@luw2007

@luw2007 luw2007 commented Aug 7, 2026

Copy link
Copy Markdown

Summary

Adds deepseek as a first-class model provider alongside anthropic, openai, and openrouter, 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:

  • a local Keychain credential-resolution mechanism (localKeychainModelOwner in config, LOCAL_KEYCHAIN_MODEL_OWNER secret-schema gating, localKeychainResolver in the credential store, keychain wiring in wiring.ts)
  • an unrelated secure-drop proxy / browser-uuid feature in plugins/web-ui (browser-uuid.ts, the /drop proxy 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_HARNESSES gain deepseek (scoped to pi and mock, the same harnesses openrouter gets — DeepSeek has no opencode wiring yet).
  • cli/src/secrets.ts: DEEPSEEK_API_KEY joins 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_REGISTRY gains deepseek-v4-flash; modelServiceable, ALL_PROVIDERS_AVAILABLE, onlyProvider, and the opencode branch of modelProviderAvailabilityFor all treat deepseek the same way they already treat openrouter (including opencode exclusion, since DeepSeek has no opencode wiring).
  • src/model/provider-endpoints.ts: deepseek joins PROVIDER_IDS with a DEEPSEEK_BASE_URL override. 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: deepseekApiKey plumbed through PiHarnessOptions/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 include deepseek too.
  • src/config.ts: deepseekApiKey field, wired into providerKeysPresent and env loading (env.DEEPSEEK_API_KEY) — no local-keychain field.
  • src/deployment/secret-schema.ts: DEEPSEEK_API_KEY gated by model-deepseek, whose predicate is a plain MODEL_PROVIDER === "deepseek" check — no LOCAL_KEYCHAIN_MODEL_OWNER exception.
  • src/model/model-credential-store.ts: deepseek added to the availability status map — no localKeychainResolver mechanism/source.
  • src/wiring.ts: deepseek key resolution in the credential fallback and resolveModelProviderKeysno localKeychainResolver/keychain wiring.
  • plugins/web-ui/src/pi-models.ts: KNOWN_PROVIDERS gains deepseek.
  • Test updates across 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, and cli/src/backends/doctor.ts's probe map — no local-keychain assertions.

Verification

Ran locally (Node v24.18.0, via fnm use v24.18.0):

  • Root: 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/require mismatches, a $PAGER environment difference, and sandboxed git-remote networking) — confirmed identical on origin/main with 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 typecheck clean.
  • plugins/web-ui/: full suite (node --test "test/**/*.test.ts") — all pass (500/500).
  • Root npm run typecheck clean.
  • eslint on every changed file — clean.

Self-review

Before opening this PR: no comments were introduced (verified with git diff against the "no comments" convention); grepped openrouter across src/, plugins/, test/, cli/ and brought every sibling list up to date with deepseek, including two gaps an independent reviewer pass caught and I fixed before this push — deepseek was initially declared servable on the opencode harness (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 (see provider-endpoints.ts and the opencode branch of modelProviderAvailabilityFor). The diff contains only DeepSeek-provider files — no local-keychain or secure-drop/browser-uuid content.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant