# DeepSeek — API Research (Phase 0) Researched 2026-07-30 against official docs (api-docs.deepseek.com) and a **live `/models` probe with a real key** (`/tmp/zyquo-probe/deepseek.json`). Major change vs older integrations: **`deepseek-chat` and `deepseek-reasoner` are RETIRED** — only `deepseek-v4-flash` and `deepseek-v4-pro` exist now. --- ## 1. Base URL & Endpoints Base: `https://api.deepseek.com` (OpenAI-compatible). An Anthropic-Messages-compatible surface also exists at `https://api.deepseek.com/anthropic` (not needed — Zyquo Cloud uses the OpenAI surface via `OpenAICompatibleClient`). | Endpoint | Method | Purpose | |---|---|---| | `/chat/completions` (also `/v1/chat/completions`) | POST | Chat (streaming + non-streaming) | | `/models` | GET | List models | | `/user/balance` | GET | Account balance (nice-to-have for the usage footer) | Docs: https://api-docs.deepseek.com/ and https://api-docs.deepseek.com/api/create-chat-completion ## 2. Authentication `Authorization: Bearer $DEEPSEEK_API_KEY`. Keys from platform.deepseek.com. ## 3. Chat Model Catalog Live probe (2026-07-30) returns exactly two models. Specs from https://api-docs.deepseek.com/quick_start/pricing. Both support **streaming, vision — NO (text-only; unverified whether V4 added image input — docs do not document vision input; treat as text-only), tools/function calling (up to 128 functions), JSON mode (`json_object`), and thinking mode** (default ON). | Model ID | Context | Max output | $/1M input (cache hit) | $/1M input (cache miss) | $/1M output | Thinking | Concurrency | |---|---|---|---|---|---|---|---| | `deepseek-v4-flash` | 1,000,000 | 384K | $0.0028 | $0.14 | $0.28 | ✅ default on (also non-thinking) | 2,500 | | `deepseek-v4-pro` | 1,000,000 | 384K | $0.003625 | $0.435 | $0.87 | ✅ default on (also non-thinking) | 500 | **Retired legacy IDs (do NOT ship in ModelCatalog):** `deepseek-chat` and `deepseek-reasoner` were routing aliases (chat = non-thinking mode, reasoner = thinking mode of the current generation, latterly resolving to `deepseek-v4-flash`). They stopped resolving on **2026-07-24 15:59 UTC** and now return errors (404-class). V4 launched in preview 2026-04-24, GA 2026-07-20. If migrating user configs: `deepseek-chat` → `deepseek-v4-flash` with `thinking.type: "disabled"`; `deepseek-reasoner` → `deepseek-v4-flash` with thinking enabled (note: reasoner mapped to **Flash**, not Pro). Sources: [DeepSeek V4 migration](https://ecorpit.com/deepseek-v4-migration-legacy-api-cutoff-july-2026/), [Developers Digest guide](https://www.developersdigest.tech/blog/deepseek-chat-to-v4-migration-guide), [TheRouter.ai](https://therouter.ai/news/deepseek-chat-reasoner-deprecation-v4-migration-routing/) (third-party corroboration of official release notes). Max-output default vs maximum split is not documented beyond "384K max" — default `max_tokens` when omitted: unverified. ## 4. Request / Response Format **OpenAI-compatible** with DeepSeek extensions/deviations (https://api-docs.deepseek.com/api/create-chat-completion): - `model`: `"deepseek-v4-flash" | "deepseek-v4-pro"` - `messages`: roles `system` / `user` / `assistant` / `tool`; optional `name` - `temperature`: 0–2, **default 1**; `top_p`: 0–1, default 1 - `max_tokens`: nullable int (input + output ≤ context) - **`thinking`**: `{ "type": "enabled" | "disabled" }` — default **enabled**; plus **`reasoning_effort`**: `"high" | "max"` (defaults vary by request type; exact default unverified) - `stream`, `stream_options: {"include_usage": true}` - `response_format`: `{"type": "text" | "json_object"}` (no `json_schema` documented) - `tools` (≤128 functions), `tool_choice`, `logprobs` + `top_logprobs` (0–20), `stop` (≤16 sequences) - **Deprecated/removed:** `frequency_penalty` and `presence_penalty` — "no longer supported". Do not surface these sliders for DeepSeek in the per-conversation parameters UI. ```json POST /chat/completions { "model": "deepseek-v4-flash", "messages": [ { "role": "system", "content": "You are a helpful assistant." }, { "role": "user", "content": "Reply with exactly: OK" } ], "thinking": { "type": "enabled" }, "reasoning_effort": "high", "max_tokens": 4096, "stream": false } ``` Response deviations from vanilla OpenAI: - `choices[0].message.reasoning_content` (nullable string): "For thinking mode only. The reasoning contents of the assistant message, before the final answer." → this feeds Zyquo Cloud's collapsible "Thinking…" section. - `finish_reason` values: `stop`, `length`, `content_filter`, `tool_calls`, **`insufficient_system_resource`** (DeepSeek-specific — surface as "DeepSeek servers overloaded"). - `usage`: `prompt_tokens` (= `prompt_cache_hit_tokens` + `prompt_cache_miss_tokens`), `completion_tokens`, `total_tokens`, `prompt_cache_hit_tokens`, `prompt_cache_miss_tokens`, `completion_tokens_details.reasoning_tokens`. Cost calc must use hit/miss split (cache-hit input is ~50× cheaper). **Vision:** not documented for V4 — treat DeepSeek as text-only (no `image_url` support; unverified whether it errors or ignores). **Legacy V3-era rule** ("do not pass `reasoning_content` back in the next request or the API errors") is **unverified for V4** — the V4 docs no longer state it. Safe client behavior: never send `reasoning_content` back in `messages` (matches OpenAI-compat semantics either way). Whether `temperature`/`top_p` are ignored in thinking mode (as with the old reasoner): unverified for V4 — docs list them without model restrictions. ## 5. Streaming Standard OpenAI SSE: `data: {chunk}` lines, terminated by `data: [DONE]`. DeepSeek specifics: - Thinking mode streams `choices[0].delta.reasoning_content` first (while reasoning), then `choices[0].delta.content` for the final answer. The parser must watch both fields and switch the UI from the "Thinking…" section to the answer body when `content` starts. - With `stream_options.include_usage: true`, one extra chunk with full `usage` arrives just before `[DONE]`. - **Keep-alive under load** (https://api-docs.deepseek.com/quick_start/rate_limit): non-streaming responses may pad with empty lines; streaming sends SSE comments `: keep-alive`. The SSE parser must ignore comment lines and empty lines. If inference hasn't started after **10 minutes**, the server closes the connection — use long read timeouts. ## 6. Special Parameters & Notes - **`thinking: {"type": "enabled"|"disabled"}`** — per-request toggle; default enabled on both models. Map Zyquo Cloud's "reasoning" toggle to this. - **`reasoning_effort: "high" | "max"`** — extra thinking depth control (thinking mode). - **Context caching is automatic** (no opt-in): repeated prefixes hit the cache and bill at the cache-hit input rate; observable via `prompt_cache_hit_tokens`/`prompt_cache_miss_tokens`. - **`user_id`** (optional): scheduling isolation; on expanded-capacity accounts each distinct `user_id` gets its own concurrency budget. - No `frequency_penalty`/`presence_penalty`; no `json_schema` response format; `n` not documented (unverified). ## 7. Rate Limits & Errors (https://api-docs.deepseek.com/quick_start/rate_limit, https://api-docs.deepseek.com/quick_start/error_codes) DeepSeek uses **concurrency limits, not RPM/TPM**: 2,500 concurrent requests for v4-flash, 500 for v4-pro (a slot is held from send until the response completes). Exceeding → HTTP 429. Free capacity-expansion requests available. Under load, expect keep-alive padding (§5) rather than fast failures. | HTTP | Meaning | Handling | |---|---|---| | 400 | Invalid request body format | fix request | | 401 | Wrong API key | "Invalid API key for DeepSeek" | | 402 | **Insufficient balance** (DeepSeek-specific) | tell user to top up | | 422 | Invalid parameters | fix params per message | | 429 | Concurrency limit | backoff + retry | | 500 | Server error | retry with backoff | | 503 | Server overloaded | retry after wait | Error body: OpenAI-style `{"error": {"message", "type", "code"}}` — exact JSON shape not specified in official docs (unverified; confirm in Phase 7). ## 8. `/models` Listing **Yes.** `GET /models` → minimal OpenAI shape (verified live): `{"object":"list","data":[{"id":"deepseek-v4-flash","object":"model","owned_by":"deepseek"},{"id":"deepseek-v4-pro","object":"model","owned_by":"deepseek"}]}`. IDs only — context/pricing/capabilities must come from the built-in catalog.