feat: add the DeepSeek platform provider and deepseek-flash

Refs #83

The first vendor-cloud chat row in agent/models.yml. The provider label is the
bare word `deepseek` because pi-catalog/src/hosts.ts keys the direct-DeepSeek
behaviour set (max_tokens field, thinking extraBody, thinking-disable mode) off
that exact name and off api.deepseek.com; the house `<api> (<host>)` pattern
would not match and the row would lose the quirks the endpoint answers to.

The key is command-backed (`!cat ~/.config/secrets/deepseek_api_key`, 600), so
no sk-… value enters the tracked tree, and the row declares the model card's own
pair: contextWindow 1048576 / maxTokens 262144, input [text, image], with the
October 2026 peak rate card in cost. Docs move to the new
omp-docs/core/deepseek-provider.md, indexed and logged in the same commit.
This commit is contained in:
Frank committed 2026-10-29 14:47:34 -07:00
1 parent 53025a6be5
commit 206c9acb46
4 files changed
+228 -3

No files matched your search

+83 -3
View File
@@ -319,10 +319,90 @@ providers:
api: openai-speech
input: [text]
# Vendor cloud, not a fleet host: DeepSeek's own API. The label is the bare
# `deepseek` — NOT the house `<api> (<host>)` pattern — because the harness
# matches provider names against a built-in service table
# (`src/config/model-registry.ts` profiles, `dist/cli.js` `VIn` map), and
# `deepseekDirect` lists `providers: ["deepseek"]` with urlMarkers
# `["api.deepseek.com"]`. A name like `deepseek (platform)` matches neither
# form, and the row loses the direct-DeepSeek behaviour set the catalog ships
# for its own built-in provider (see the compat block below). The baseUrl
# carries the host the label can't name.
"deepseek":
baseUrl: https://api.deepseek.com/v1
api: openai-completions
# Command-backed, like every other credential in this file: the key lives in
# ~/.config/secrets/deepseek_api_key (600) and never enters the tracked
# tree, where the pre-commit shape gate would read it. Quoted because an
# unquoted leading `!` is a YAML tag. The resolved value is cached for the
# process lifetime — rotation is: rewrite the file, then restart omp.
# Written 2026-10-29 from the key Frank issued; every other workstation that
# pulls this repo needs its own copy of the file (nothing here carries it).
apiKey: "!cat ~/.config/secrets/deepseek_api_key"
models:
- id: deepseek-flash
name: "deepseek-flash"
# Official name (api-docs.deepseek.com): `deepseek-flash` is served by
# DeepSeek-V4.1-Flash-1017. The legacy names deepseek-v4-flash and
# deepseek-v4-flash-vision-exp are still accepted but retired — the
# model card says to use `deepseek-flash`; so does Frank.
# The model card states context_window 1M; 262,144 is its `max_tokens ≥
# 256K` recommendation. The two are the engine's own pair: any prompt +
# budget over 1,048,574 is a refusal, and this row states them together
# so the harness clamps before the API has to.
contextWindow: 1048576
maxTokens: 262144
# Natively multimodal (V4.1 = image-text-to-text on the hub), despite
# the retired `-vision-exp` alias suggesting otherwise.
input: [text, image]
# Rate card, per 1M tokens, peak tier ($0.15/$0.60 off-peak is not
# modelled — the harness has one field per direction and a session
# cannot know which window it is billing into). Overriding these here is
# the only way a non-catalog row reports cost at all.
cost:
input: 0.3
output: 1.2
cacheRead: 0.006
cacheWrite: 0
compat:
# Copied from the harness's own built-in descriptor for this provider
# (`pi-catalog/src/provider-models/openai-compat.ts:7422`), never
# simplified — the same law as the WAN rows:
# V4 thinking mode rejects the `tool_choice` parameter outright; tool
# calls still work and default to auto when tools are present.
supportsToolChoice: false
# V4 has no `developer` role.
supportsDeveloperRole: false
# Reasoning arrives in `reasoning_content`; the harness's default for a
# direct DeepSeek provider is `zai-thinking-disabled` (an explicit
# `thinking: {"type":"disabled"}`), which is what this endpoint
# honours — `reasoning_effort: "none"` is not accepted here. Left unset
# so the built-in default stays in charge rather than a guess.
reasoningContentField: "reasoning_content"
# The documented request enables thinking with the `thinking` toggle
# AND `reasoning_effort`; when thinking is on, the harness strips the
# toggle from extraBody and keeps the effort value, so the request
# carries what the endpoint expects.
# Card-recommended sampler: temperature 1.0, top_p 1.0 (in thinking
# mode the API floors top_p at 0.95 — 1.0 is inside the allowed set).
# top_k is not accepted through the OpenAI surface, so it is not sent.
# extraBody is merged last and wins, so pinning the trio survives a
# server-side sampler edit — same law as the LAN rows.
extraBody:
thinking:
type: enabled
temperature: 1.0
top_p: 1.0
# `max_tokens` is the field this API speaks (not
# max_completion_tokens) — set by the built-in default, and this row
# cannot mis-name it because it names no override of its own.
# ─── WAN door ───────────────────────────────────────────────────────────
# The only block in this file that answers OFF the home network. Every
# provider above is a LAN IP, and `modelRoles` (config.yml) still points at
# those, so away from home you must NAME one of the rows below:
# The fleet's own off-network door. Since 2026-10-29 the `deepseek` block
# above is also reachable from anywhere (a vendor URL, not a LAN IP), but it
# is not this door: this block is the route back to FRANK'S engines. Every
# fleet provider here is a LAN address, and `modelRoles` (config.yml) still
# points at those, so away from home you must NAME one of the rows below:
# omp --model 'openwebui (franksdank.cloud)/frank-dragoon:medium'
# The door is the OpenWebUI vhost `ai.franksdank.cloud` — Caddy → OWU on
# Dankclaw:3005, Anubis-exempt because OWU enforces its own auth, public A