The catalog's context window is now a text field that reads a decimal K or M suffix — 1M is 1000K, matching how model capacities are quoted — and stores the plain token count, so settings.yaml and the adapter are unchanged. A stored count reads back in the shortest form that round-trips: 1000000 as 1M, 256000 as 256K, and 131072 written out, because it is not a whole number of thousands. The field holds the typed text while its row has focus, since re-deriving it from the parsed count on every keystroke would rewrite 1000 to 1K mid-word; text that does not parse stays on screen so the save-time rejection names a row the user can still see and correct.
5.6 KiB
@deepseek-ai/dsh-client-ui-models
English | 中文
Models settings plugin: the provider configuration page and official-DeepSeek first-run routing overlay. It joins three wire domains into one shared snapshot — llm.providers (the configurable-provider directory with each route's live/dormant state), settings.describe (serialized schemas, layered redacted values, secret slots), and credentials.describe (value-free configured/source/writable badges) — and renders provider rows with one editor card at a time, without presenting route liveness as provider status.
Rows are the configured providers (their profile resolves in the owning namespace); a whole-section provider whose key is not configured anywhere (the first-run DeepSeek posture) renders as its open setup card instead of a row, and the add flow is a card carrying the dormant-directory provider select — a bare-mounted llm-pi-ai offers its whole installed catalog before any route exists. The editor is a hand-written card per adapter family: the primary field is a single API key input — the page never asks for an environment-variable name; a typed key stores write-only through credentials.set under the profile's reference, deriving <ROUTE>_API_KEY when the profile has none, and the pi-ai profile records that derivation as apiKeyEnv, so settings.yaml never carries a key value. The collapsed 自定义设置 fold carries the curated extras — baseURL for both families (the deepseek placeholder shows the public endpoint), reasoningEffort (deepseek) or reasoning (pi-ai), and the direct DeepSeek adapter's advisory model catalog. Each DeepSeek row edits id, optional display name, and optional contextWindow; existing fields outside that curated set survive edits, while every other profile field stays owned by settings.yaml. A row is deletable only when the user layer alone carries it (removal restores the composition base), and a localized confirmation dialog must complete before the page submits that destructive unset.
The first-run overlay projects deepseek-official readiness from that same joined snapshot. It recognizes the official adapter through its llm-deepseek configurable-provider declaration, so an undeclared live route with the same provider id is not treated as repairable configuration. A configured literal apiKey secret sidecar or configured credential reference suppresses the prompt, including a read-only launch-environment credential. Only a mounted adapter with a missing writable reference shows the action that opens Settings on the Models section, whose existing setup card exclusively owns key input and credentials.set; the overlay never holds a secret. An absent adapter, inactive route, failed join, read-only deployment, or unusable settings or credential capability is skipped so onboarding cannot block the rest of the product; the Models page remains the diagnostic surface.
Every edit lands as settings.mutate path ops against the stored section — a set per changed field, an unset per cleared one, and a single unset for a deleted provider row. The page only ever holds the REDACTED descriptor, so it names the fields it can see rather than rebuilding a section: a stored literal secret it never received is mentioned by no op and survives. DeepSeek's models is one replace-by-value array: the editor shows inherited effective rows until the first model edit materializes the complete array in the user layer, while reset unsets that override. A context window is typed as a count with an optional decimal K or M suffix (256K, 1M; 1M is 1000K) and stored as the plain count, spelled back in the shortest form that round-trips. Empty ids, duplicate ids, empty explicit names, and unreadable, non-positive, or fractional context windows fail before any write. Each write carries the revision the card opened at, so a concurrent write from another tab or an external settings.yaml edit is refused as settings-conflict and the card asks the user to reopen instead of replaying its stale snapshot. The page refetches on the pushed invalidations (settings/changed, credentials/changed, models/changed, and connection/reset) once it has loaded, so an external settings.yaml edit, a second tab, or a settings-born route converges without polling.
Model Experience
None, as the section renders a browser configuration UI; nothing here reaches a model request.
KV Cache effect
None; this package neither assembles nor sends a provider request.
Known Limitations and Deferred Work
- Only the API key and curated fold fields are editable on the card — the hand-written editor traded schema-generic field coverage for the mockup layout (Agent Note). DeepSeek exposes
baseURL,reasoningEffort, and modelid/name/contextWindow; pi-ai exposesbaseURLandreasoning. Retry policy, timeouts, DeepSeek model descriptions, and other advanced fields remain insettings.yaml; existing model fields the editor does not show are preserved. A profile schema without the conventional fields renders the hint alone, and the two curated layouts key on thellm-deepseek/llm-pi-ainamespaces by name. - Deleting a row leaves its stored key in
.env— removal unsets the settings profile but deliberately does not unset the derived credential; re-adding the provider finds the key already configured. An explicit key-removal control is deferred. - Undeclared live routes render nowhere — a route registered without a configurable-provider declaration has no settings address; it stays visible in pickers but not on this page's rows.