Repository navigation
design deepseek config
Fourth per-target panel, the #60/#62/#63 pattern applied to deepseek (dsh).
Durable companions: design-phase-9-harness-runtime.md (§4.3 the W3 writer
this extends), research-provider-model-params.md (§3.5 dsh ground truth +
§5 follow-up tiers), design-claude-code-config.md /
design-opencode-config.md / design-codex-config.md (the pattern's first
three instances).
The provider row keeps ONLY the connection (provider / credential /
base URL). The dsh panel owns everything model-shaped: the default model,
the switchable rows, and per-model detail. The generic default-model grid
and extra-models rows are hidden for target === 'deepseek'.
baseline; plugin typings re-verified 2026-10-17)
The llm-pi-ai settings namespace's PiAiModelProfile accepts per model
entry: id (required), name, contextWindow, maxTokens, input
(('text'|'image')[]), reasoningEfforts (false | Partial<Record<level, wire-spelling>>), compat. Our W3 writer emitted
BARE ids; research §3.5 called per-model detail "the largest cheap gap"
and §5 Tier 1 listed it as a pure win — this ships it.
Exposed by the panel (per model): name (display name), contextWindow
(max combined request+response context; drives dsh's auto-compaction),
maxTokens — a CONFIGURED value also becomes that model's per-request
default, unlike a catalog/route-inherited one — and vision →
input: ["text", "image"] (a CLAIM about the endpoint, not a check: dsh
refuses mid-turn if the gateway does not actually serve images).
Deliberately OUT of v1 (recorded as follow-ups, both need per-gateway
wire ground truth): reasoningEfforts (a level dict must name wire
spellings — e.g. what an openai-completions gateway expects per level —
which we cannot guess; false alone strips reasoning from a catalog model,
a niche case for our unknown-id routes) and the route-level reasoning
thinking dial (off|minimal|low|medium|high|xhigh|max). compat is
wire machinery dsh's own UI gates behind a drift-checked table — not user
preference surface. No behavior-switch section exists because dsh's
settings schema has NO sampling knobs at all (temperature/topP are
programmatic-only seams; the dsh-llm README: "the vocabulary grows when a
producer lands"). The panel is honestly thin.
spec.deepseek — additive optional field (deepseekConfigSchema: per-model
name / contextWindow / maxOutputTokens / vision, ≤17 entries),
zod-validated both ends; old daemons strip it. The four-spot wiring (#53
lesson): core DeepseekConfigData mirror, service row, toView passthrough,
sdk re-exports.
applyDshConfig's models: block gains per-entry fields with the opencode
precedence, per field: panel value (spec.deepseek.models) > #51
modelEntries seed > key OMITTED (the route's own defaults —
defaultContextWindow 262,144 / defaultMaxTokens 32,768 — apply; the
pi-writer stance of never writing a guessed value). vision: true emits
input: ["text", "image"] (JSON flow is valid YAML); absent stays the
route default (our route ids are unknown to pi-ai's catalog, so there is
nothing to inherit). A spec with no detail and no seed emits today's
bare - id: lines byte-identically — untouched rows re-apply unchanged
(pinned by test). The agent-default-model pin, the cordis.patch.yml
acp override and the .env key are untouched by #64.
Rig-verified end to end (survey-box, 2026-10-17): bailian route —
panel name (registry has no displayName) + panel contextWindow: 512000
BEATING the registry seed's 1,000,000 + empty output falling to the seed's
maxTokens: 384000 + vision claim → exact YAML on disk → reload prefill
round-trip exact. The heal from research §4.3 (dsh assuming 262k where the
registry knows 1M) rides the seed automatically.
deepseek-panel.tsx, i18n ds* keys (en/zh side by side):
- 模型 — default model (registry select when the provider has chat models, free-text otherwise) + the extra-models rows. Hint: the list IS the session-switchable set; the leading one is the default route.
- 模型详情 — collapsible per-model groups (the opencode pattern): display name / context window / output cap / vision checkbox, each with its own hint; the validation issue renders INLINE under the groups (the #63 lesson — the gate explains itself instead of only disabling Apply).
Numeric inputs keep STRING state while typing; dsIssue gates on positive
integers; serializeDsDraft yields undefined for an all-default draft,
so untouched rows keep their pre-#64 shape byte-identically.