---
title: DeepSeek Provider
---

# DeepSeek Provider

## What it is

Omniscio supports spawning Claude-Code-style sessions backed by DeepSeek's Anthropic-compatible API as an additional provider, alongside `claude` (the default), `codex`, `gemini`, `antigravity`, the Anthropic-compatible `kimi` / `glm` / `minimax` / `meta`, `cursor`, `hermes`, `grok`, `pi`, `opencode`, and `openclaw` (the registry defines 26 session-provider keys, 20 of them user-selectable/pickable; the non-pickable ones include `opencode`, `terminal` — the managed inbuilt PTY engine — and `openclaw`).

### What the user sees

A DeepSeek session looks identical in the sidebar and main pane to a Claude session — same status dots, same streaming bubbles, same Ctrl+Enter to send, same Plan / Auto-Accept / Bypass Permissions modes, same tool-call approval UI. The provider is invisible in normal chat. The only user-visible difference is the DeepSeek icon (a non-Claude provider mark, no text label) in the session header.

The _harness_ is identical to Claude — same `claude` CLI binary, same streaming, same tool-call approval flow (there is **no yolo / auto-approve mode** like Gemini or Anti-Gravity). But the _model_ is not: DeepSeek is a cheaper, **weaker autonomous coding agent** than Claude. Omniscio offers DeepSeek's **V4.1** and **V4** models — all unified dual-mode models that drive the Claude-Code tool protocol (DeepSeek's own Claude Code integration uses them). Omniscio **defaults a DeepSeek session to DeepSeek V4.1 Flash** (`deepseek-v4.1-flash`) when you haven't picked a model: DeepSeek bills it below V4 Pro while rating it above, and it reads images natively. Also selectable: `deepseek-v4-flash` (previous generation, fast and general), `deepseek-v4-pro` (high-capability), and the **experimental** **DeepSeek V4 Flash Vision** (`deepseek-v4-flash-vision-exp`, 2026-08), which adds image input to the old Flash tier; images are converted to tokens and billed as input either way.

> **V4.1 Flash stalled for two days, and it was our routing (fixed 2026-09-11).** V4.1 was added to the picker and made the default on 2026-09-09, and from then until 2026-09-11 a DeepSeek session that didn't name a model **silently stalled** — it never errored, it just sat there looking like it was waiting for you. The cause was not DeepSeek. An Omniscio-funded DeepSeek session doesn't call DeepSeek directly; it goes through Omniscio's own gateway, which forwards to a partner whose catalog only carried the older V4 models. V4.1 wasn't in it, so the request came back empty. The commit that added V4.1 updated the picker, the pricing and the docs — but not the gateway's routing file, so nothing knew where to send it. The fix adds that route (V4.1 now goes to a provider that serves it) and keeps the default on V4.1. **The gateway change needs to be deployed for this to take effect.**
>
> Also removed: a second, pre-launch id (`deepseek-v4.1-flash-expires-on-0910`) and the launch-**date** switch that chose between the two. Picking a model by a vendor's announced date, rather than by whether it actually answers, is what let a broken default go unnoticed — a session pinned to that retired id now says "pick another model" instead of stalling.
>
> The older `deepseek-chat` (V3) / `deepseek-reasoner` (R1) aliases are gone from the picker too — DeepSeek **hard-retired** those ids on **2026-07-24 15:59 UTC** and the endpoint rejects them after, which is why the picker moved to the V4 ids.

## Where to find it

### How to enable

> **Master toggle required first.** DeepSeek is an alternative provider — by default Omniscio ships as a Claude-only product, and the entire DeepSeek setup section below is hidden in Settings → Accounts. Flip **Settings → Accounts → Show alternative AI providers** to ON (off by default) and the DeepSeek panel appears alongside Gemini, Codex, Anti-Gravity, and Kimi. With the master off, the per-project "Default provider" radio collapses to a single Claude row and the session header's provider switcher (ChangeProviderButton) hides DeepSeek — DeepSeek effectively does not exist in the UI even if every gate below is configured. Your saved API key and "Allow DeepSeek sessions" toggle are preserved across master-toggle flips.

You need two of these in place (note: no binary check — same `claude` binary as Claude). The opt-in **toggle leads and gates the key field** — the API key input appears only once DeepSeek is turned on, so a key can't be entered into a disabled provider (when off, a hint keeps the `deepseek-api-key` Settings-search anchor landable and a saved key is preserved):

1. **Settings → Account → Allow DeepSeek sessions in any project** — opt-in toggle, off by default; same security stance as the Codex/Gemini spawn guards. Turning it on reveals the key field below.
2. **Settings → Account → DeepSeek → API key** — paste a DeepSeek API key from `platform.deepseek.com` (encrypted at rest via Electron `safeStorage`). **Or skip the key entirely:** who pays for a DeepSeek session is DeepSeek's **supply list** in **Settings → Accounts → Who pays & who serves**, which for a new user starts as your own DeepSeek key first and **Omniscio credits** second (an earlier choice you made carries over). With no key saved, sessions run on Omniscio's key and draw down your prepaid credit balance (signed-in only). Reorder the list to put credits first, or add a reseller row (DeepInfra, RunInfra or InferX) to have one of them serve the model on your own account there. See [model-vendors.md](model-vendors.md).

Once both are green, you can launch a DeepSeek session in three ways:

- **Per-launch override** — on a fresh (zero-message) session, the **ChangeProviderButton** in the new session's main panel (the launch-config pickers on a fresh session) lets you pick a one-off provider before sending the first message. Non-ready providers appear `aria-disabled` with an "Add key…" / "Enable in Settings…" suffix and deep-link to the right Settings panel.
- **Per-project default** — Edit Project dialog (three-dot menu → Edit) has a "Default provider" section listing every enabled provider. Pick DeepSeek and the project's sidebar "+ New Session" button spawns DeepSeek automatically.
- **Programmatically** — anything that creates a session with `provider: 'deepseek'` (recipes, agent-driven sessions, the CLI control HTTP API). Same readiness gates apply on the backend.

## How it behaves

### Choosing the model

A fresh DeepSeek session lets you pick the model in the launch-config pickers (next to the provider chooser): **DeepSeek V4.1 Flash** (`deepseek-v4.1-flash`, newest, reads images), **DeepSeek V4 Flash** (`deepseek-v4-flash`, previous generation), **DeepSeek V4 Pro** (`deepseek-v4-pro`, high-capability), or the experimental **DeepSeek V4 Flash Vision** (`deepseek-v4-flash-vision-exp`, old Flash + image/vision input). All are unified dual-mode models that drive the Claude-Code tool protocol. The pick is staged locally and applied when you send your first message. **Use default** spawns **V4.1 Flash** rather than omitting the model flag — DeepSeek _requires_ a real DeepSeek model id (the shared `claude` binary's built-in default is a Claude id its endpoint would reject), so the registry pins one via `getProviderDefaultModel` (in [provider-models.ts](../../src/shared/providers/provider-models.ts)). On an Omniscio-funded session the id must ALSO have a route in the gateway's own config — that mismatch is what stalled V4.1 for two days (see the note above), and it is now covered by a test that fails if a model is offered here without one. The legacy `deepseek-chat` / `deepseek-reasoner` aliases retire **2026-07-24 15:59 UTC**, which is why the picker now offers the V4 ids directly. DeepSeek has no separate "reasoning effort" knob. The model list is DeepSeek's own — a DeepSeek session never inherits your Claude default model (those are Claude ids its endpoint would reject). See [start-a-new-session.md](start-a-new-session.md).

### Per-project default

Each project remembers a default provider in the `projectDefaultProviders` setting (a `Record<projectId, ProviderId>`). Empty by default — every project falls back to Claude. Change it from the project's three-dot menu → Edit → Default provider radios; the change persists immediately.

When you set a project's default to DeepSeek but DeepSeek isn't ready (toggle off or key missing), an amber **"!" badge** appears on that project's sidebar row. Hover the badge for a tooltip explaining the gap; click it to deep-link straight to the right Settings panel. The badge re-checks on every render, so fixing the gap clears it without a refresh. Claude defaults never show the badge — Claude is always considered ready.

### Error states and fixes

Two gap codes — fewer than Gemini/Codex because there is no separate binary to check:

| Gap           | What it means                                                                                                                                                        | Click-to-fix lands you at…                                                                            |
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `toggle-off`  | "Allow DeepSeek sessions" is OFF in Settings                                                                                                                         | Settings → Account → Allow DeepSeek sessions toggle                                                   |
| `key-missing` | No row of DeepSeek's supply list can serve right now — no DeepSeek API key, and no other row ready (Omniscio credits need you signed in; a reseller row needs its own key and switch) | Settings → Account → DeepSeek API key field, or Settings → Accounts → Who pays & who serves |

**The real reason, not a blanket "model unavailable."** When DeepSeek's endpoint rejects a request mid-session for a reason other than the model — the account is out of balance, the conversation outgrew the context window, the key became invalid, or you're rate-limited — Omniscio reads DeepSeek's actual error (carried on the zero-output synthetic placeholder, the same spot the Consumer-Terms gate reads) and shows the _specific_ cause + fix (recharge / start fresh or pick a larger-context model / check the key in Settings / wait a moment) instead of the generic _"this model may be unavailable — choose another,"_ which now applies only to a genuinely unknown/retired model. Message-only — the session still parks as `needs_you` / `recovery_failed`. **Out of balance is the exception when another row can pay:** if DeepSeek's supply list has another row that can serve, the session moves to it and resends your message instead of parking (see [model-vendors.md](model-vendors.md)). See [provider-spawn-model-availability-contract.md](../../.claude/memory/contracts/provider-spawn-model-availability-contract.md) `vendor-error-is-classified-and-named`.

**Context window — 1M real, but compaction runs at ~167K on the installed Claude (2026-08-22).** DeepSeek V4 runs a real **1,048,576-token** window (1M), far above the `claude` binary's ~200K assumption for a model it has no vendor row for. In practice a DeepSeek session auto-compacts at **~167K** — the binary's own default point (its ~200K working window minus a ~33K reserve). An earlier attempt to push that to 400K via a setting turned out to be a no-op on the Claude version this app runs, so it was removed (see "The 400K story" below). If an overflow ever does slip through, the session auto-recovers on its own (rebuilds from its transcript and continues, bounded) instead of parking on the first hit; only if it genuinely can't recover does it fall back to the "conversation got too long" park. See [context-limit-400-surfacing-contract.md](../../.claude/memory/contracts/context-limit-400-surfacing-contract.md).

**Why not just use the whole 1M.** Bigger is not better past a point: DeepSeek V4's measured recall is ~94% up to 128K and ~82% at 512K, but falls to ~66% at 1M, and the published sweet spot is 128K–512K. This is the industry-wide "context rot" effect — one study found all 18 frontier models tested degraded well before their stated limits. So a smaller working window is actually good for quality here, and the ~167K compaction point sits inside the high-quality band. (Omniscio also still nudges you toward a fresh session around 400K on this same quality basis — a separate suggestion from where the conversation compacts.)

**The 400K story (2026-08-06 → corrected 2026-08-22).** On 2026-08-06 DeepSeek sessions briefly compacted _constantly_ — one live session compacted 10 times in 31 minutes before the CLI's own anti-thrash guard stopped the turn mid-work — because DeepSeek's window had been recorded as a stale 128K. That was corrected the same day to the real 1M, and a setting (`CLAUDE_CODE_AUTO_COMPACT_WINDOW=433000`) was added intending to place compaction at 400K. On 2026-08-22, live testing showed that setting is a **no-op on the Claude version this app runs** — DeepSeek had actually been compacting at ~167K all along (confirmed across 404 of 404 real compactions), so the dead setting was removed and DeepSeek now runs at the binary's ~167K default. A true 400K point would require a newer Claude binary. Full history: [deepseek-compaction-thrash-postmortem.md](../../.claude/memory/postmortems/deepseek-compaction-thrash-postmortem.md). **That ending was itself corrected on 2026-09-13** — the dial was not dead, it was half-set. See the compaction bullet under _How it works under the hood_: the binary resolves the dial as `Math.min(believedWindow, dial)`, so the dial alone could never move a window the binary believed was ~200K. Paired with `CLAUDE_CODE_MAX_CONTEXT_TOKENS`, it works, and DeepSeek now compacts at 750K rather than ~167K.

## Sub-agents on a DeepSeek session (fixed 2026-09-15)

**What you saw.** A sub-agent — anything a session hands a chunk of work to — died the instant it started, with _"There's an issue with the selected model (claude-sonnet-5). It may not exist or you may not have access to it."_ The session itself kept working; only the helper it spawned failed.

**Why.** The `--model` flag pins only the session's MAIN loop. Every other model path the `claude` binary takes — the background model it uses for topic detection and compaction summaries, and **a sub-agent that asks for a model by name** — fell back to the binary's own built-in Claude names (`claude-sonnet-5`, `claude-haiku-4-5-…`). DeepSeek has never heard of those, so the request was rejected. It was invisible until a sub-agent asked for a model explicitly: a sub-agent with no model preference simply inherited the working session model and was fine, which is why this looked intermittent.

**The fix.** Omniscio now pins every model name the binary can fall back to — the opus / sonnet / haiku / fable aliases plus the background model — onto the model your session actually runs. Any sub-agent asking for "sonnet" now gets the DeepSeek model instead of a Claude one it could never reach. The same fix covers Kimi, GLM, MiniMax and Meta, and the aside panel.

## For agents

### How it works under the hood

**Spawn-env redirect, no alternate manager.** DeepSeek publishes an Anthropic-compatible API — same request/response shape as Anthropic's Messages API, just at a different base URL. So Omniscio reuses the existing `claude` CLI binary (the same one Claude sessions use) and redirects every HTTP call at spawn time by setting a handful of environment variables on the child process:

- `ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic` — sends every HTTP request to DeepSeek's compat endpoint instead of `api.anthropic.com`.
- `ANTHROPIC_AUTH_TOKEN=<your DeepSeek API key>` — supersedes the Claude OAuth/API-key for this child only. That is the shape when the row of DeepSeek's supply list that serves is your own DeepSeek key; an Omniscio credits or developer-lane row points `ANTHROPIC_BASE_URL` at Omniscio's gateway with a gateway credential instead, and a reseller row goes through the local model proxy on the reseller's own model id.
- **Model-alias pins** — `ANTHROPIC_DEFAULT_OPUS_MODEL` / `_SONNET_` / `_HAIKU_` / `_FABLE_` and `ANTHROPIC_SMALL_FAST_MODEL`, all set to the id this lane actually sends on `--model`. `--model` alone covers only the main loop, so without these a sub-agent (or the background small-fast model) reaches for a Claude id the vendor cannot serve. The alias vars are the ones that matter for a sub-agent: asking for `model: "sonnet"` requests the sonnet ALIAS, which `ANTHROPIC_MODEL` does not override. The id is read back from the finished argv, never re-resolved, because a model id is lane-specific (the gateway routes by the picker id, the vendor's own endpoint by its own name). See `a-vendor-endpoint-pins-every-model-alias` in [provider-registry-contract.md](../../.claude/memory/contracts/provider-registry-contract.md).
- **Two compaction settings, always together** — `applyGlmAutoCompactEnv` → `usesDeepSeekContextWindow` sets `CLAUDE_CODE_MAX_CONTEXT_TOKENS=1048576` (DeepSeek's real window) **and** `CLAUDE_CODE_AUTO_COMPACT_WINDOW=783000` (the dial), which together derive a 750K compaction point. Neither works alone: the dial is capped at whatever window the binary believes the model has, so setting it by itself leaves the point at ~167K and looks exactly like setting nothing — that is the trap that made this look unfixable from 2026-08-22 to 2026-09-13. `DISABLE_COMPACT` is deliberately NOT set (it would switch compaction off entirely, which is the GLM/GPT lane, not this one). Never re-clamp the window to 128K, never raise the compaction point above ~900K (past the real wall once the reply size is counted), and never set `CLAUDE_CODE_MAX_OUTPUT_TOKENS` for DeepSeek — V4 supports 384K output.

The child process never knows it isn't talking to Anthropic. Streaming, tool calls, `--resume` for multi-turn, `--output-format stream-json` parsing all "just work" because they're handled by the standard `claude` binary against an upstream that speaks the same protocol.

No alternate session manager exists for DeepSeek — `session-handlers.ts` gates readiness, fires the `spawn_non_claude_session` feature event, then falls through to the same `createSessionWithPrompt()` path Claude sessions use. The `provider: 'deepseek'` value is stored on the session row in the database; `process-manager.ts` reads that column and injects the right spawn-env on every CLI invocation (initial spawn, resume, aside-runner).

Compared to:

- **Codex / Anti-Gravity** — separate CLI binaries (`codex`, `agy`) with their own JSON-RPC / stream protocols; need dedicated `*-session-manager.ts` files. DeepSeek does not — that's the entire point of the Anthropic-compat protocol.
- **Gemini** — long-lived `gemini --acp` (ACP / JSON-RPC) resident child, like Codex/Pi. DeepSeek instead keeps the long-lived `claude` child process; resume is via `claude --resume <uuid>` exactly as for Claude.
- **OpenClaw** — remote WebSocket gateway with a custom JSON-RPC envelope. DeepSeek is plain HTTP to a vendor-hosted compat endpoint.

### Cost tracking

Spend hits the standard `api_cost_log` table because the `claude` CLI emits per-turn cost events in its `stream-json` output and `process-manager.ts` already plumbs those into `trackApiCostRaw()`. The `source` field on the cost row carries the provider ID (`deepseek`), so the Settings → Usage dashboard breaks down DeepSeek spend separately from Claude/Codex/Gemini.

**Cost is re-priced, not taken verbatim.** The `claude` binary has no DeepSeek price table, so its `total_cost_usd` bills DeepSeek models at Claude rates. DeepSeek is therefore `costReporting: 'estimated'`, and Omniscio recomputes each turn from the token counts × DeepSeek's real rate (`MODEL_PRICING`) via `applyAnthropicCompatReprice` — the path shared by all four anthropic-compat vendors (DeepSeek/Kimi/GLM/MiniMax). See [central-ai-spend-contract.md](../../.claude/memory/contracts/central-ai-spend-contract.md) `anthropic-compat-cost-is-repriced`.

Telemetry: every successful DeepSeek spawn fires the `spawn_non_claude_session` feature event, recording `{ provider: 'deepseek' }` only — no session ID, project ID, or prompt content.

**Running out of credit.** Spend tracking is backward-looking — it tells you what you already spent. To be warned *before* the account hits zero, switch on the **DeepSeek balance forecast** (Settings → Notifications, off by default): it reads the account balance every 15 minutes, measures the real drain, and raises one inbox card with a Recharge button when the account is projected to empty inside your warning window. See [deepseek-balance-forecast.md](deepseek-balance-forecast.md). Note this reads the account behind **your own** API key; running on Omniscio's DeepSeek credits draws a different balance it cannot see.

### Files

- [src/main/services/provider-setup/provider-readiness.ts](../../src/main/services/provider-setup/provider-readiness.ts) — single source of truth for the 2-gate readiness check (used by ChangeProviderButton, Edit Project radios, project-row cue, spawn guard)
- [src/main/process/process-manager.ts](../../src/main/process/process-manager.ts) — injects `ANTHROPIC_BASE_URL` + `ANTHROPIC_AUTH_TOKEN` per session row's `provider` column
- [src/main/services/providers/supply-connect.ts](../../src/main/services/providers/supply-connect.ts) — walks DeepSeek's supply list at each connection and builds the first row that can serve: your key, a reseller through the proxy, Omniscio credits or the developer lane
- [src/main/ipc/session-handlers.ts](../../src/main/ipc/session-handlers.ts) — DeepSeek/Kimi spawn branch that gates readiness, fires the analytics event, and falls through to the claude path
- [src/shared/types.ts](../../src/shared/types.ts) — `ProviderId` union, `deepseekApiKey`, `allowDeepseekSessionSpawn` setting fields
- [src/renderer/src/features/settings/sections/accounts/AccountSettings.tsx](../../src/renderer/src/features/settings/sections/accounts/AccountSettings.tsx) — DeepSeek section under "Show alternative AI providers"

## Related

- [deepseek-balance-forecast.md](deepseek-balance-forecast.md) — the run-out warning for this provider's account
- [model-vendors.md](model-vendors.md) — who pays for a DeepSeek session and which company serves it (the supply list)
- [kimi-provider.md](kimi-provider.md) — same shape (Anthropic-compat, no binary, spawn-env redirect), different vendor + key
- [gemini-provider.md](gemini-provider.md) — alt-CLI provider with per-turn spawn model
- [codex-provider.md](codex-provider.md) — alt-CLI provider with long-lived JSON-RPC child
- [ai-providers.md](ai-providers.md) — landing page for the full provider matrix
