@linxin666/dsh-client-ui-model-capabilities
v0.3.22
Published
Per-model capability declarations (image input and reasoning efforts) for custom pi-ai providers, edited in place on the Models settings cards; writes the official llm-pi-ai settings namespace, no DSH source changes.
Readme
dsh-model-capabilities
English | 中文
Per-model capability declarations for custom DSH providers: declare image input and reasoning efforts (which thinking levels a model offers, and the exact wire value each one sends) for every model in a custom provider's catalog, edited in place on the Models settings page. The official pi-ai settings namespace has carried these fields all along — this plugin adds the editor the settings page deliberately ships without.
What it does
- Seats the official extension area: registers the Models page's
settings.models.provider-cardslot for thellm-pi-aiadapter family, so every custom-provider card (hand-declared gateways, OpenAI-compatible endpoints, and named vendors alike) gains a collapsible "Model capabilities" area. - Provider disable/enable: one click archives a provider's profile in the plugin's own settings namespace and takes the route down through the official Remove-provider seam (
unsetonllm-pi-ai.providers.<route>); the provider leaves the model catalog that both the composer model picker and the subagent selection read — immediately, in every open surface, without a restart. Enabling restores the archived profile verbatim (API keys live in the credentials service and are never touched). Disabled providers are listed in a footer area on the Models page, where they come back. - Image input per model: one checkbox per model writes the profile's
inputmodality claim (["text", "image"]or["text"]). Declaring images is what makes DSH offer image attachments to a hand-declared vision model; declaring text alone corrects a catalog model whose gateway does not serve what the catalog records. The undeclared state (inherit) is shown and preserved, not hidden. - Reasoning efforts per model: a tri-state editor per model — undeclared (inherit), declared non-reasoning (
reasoningEfforts: false, which stops the model picker from offering thinking levels), or an explicit level dict. Levels run fromoffthroughmax; each enabled level carries a wire-spelling field (what the request actually sends, defaulting to the level name), plus a one-tap common low/medium/high preset.offmay keep an empty wire value, meaning "supported, send nothing". - Writes through the official wire: saves are a single path operation replacing the provider's whole
modelsarray in thellm-pi-aisettings namespace — the same whole-array override the official card performs. Fields this plugin does not edit (ids, display names, context windows, compat switches) survive every save, and the write applies live without a restart. - Validates before the host refuses: the editor enforces the adapter's own acceptance rules (a level dict needs at least one level beyond
off; every non-offlevel needs a non-empty wire value) and shows the reason a draft would be refused, instead of letting the host reject it after the fact. - Conflict-safe: every save carries the revision the panel read at; if the configuration changed in another surface, the panel reloads and asks for a retry instead of overwriting.
Install
From the family bundle
The dsh-web-all aggregate bundle includes this plugin; mounting that bundle is enough.
Standalone (development)
git clone https://github.com/zhu1090093659/dsh-web.git
cd dsh-web
pnpm install
pnpm -r build
dsh plugin --profile web add link:$(pwd)/packages/dsh-model-capabilitiesRestart dsh web. Open Web settings, Models; every custom provider card now carries the capability area below its catalog editor.
Configuration
The plugin registers one settings namespace of its own, dsh-model-capabilities, which holds nothing but the disabled-provider archive; there is nothing to configure by hand. Capability declarations and the enable/disable state live in the official llm-pi-ai namespace plus this archive, all editable on the Models page.
Semantics you should know
- Declarations are claims, not probes: nothing interrogates a gateway about what it accepts. A model claiming images its endpoint refuses is refused by the provider mid-turn, and a wire value the endpoint does not understand fails at request time — the fields exist precisely because nothing can infer them.
- The panel edits declared models only: a route serving the built-in pi-ai catalog without a
modelsarray shows guidance instead of an editor, because the browser cannot enumerate that catalog. Add the model rows in the card's catalog editor first (an entry whose id matches a catalog model overrides it field by field), then declare capabilities here. - Reasoning levels are selector vocabulary: the declared levels are what the composer's model picker offers for that model; the wire value is what rides the request.
offwith an empty wire value means the parameter is simply not sent when that level is chosen. - Disable is archive-and-unset, in that order: the profile is written to the archive before the route goes down, so a failed step can leave a harmless duplicate archive but never a lost profile. Enabling refuses when the route has grown a new profile in the meantime, so a restore can never clobber newer configuration. While a provider is disabled, delegation to it fails closed at the host (
NO_ADAPTER), not just in the UI.
Known limitations
- Modalities beyond text and image are not offered: the pi-ai adapter's modality vocabulary is
text | image, so video and PDF claims would not take effect end to end. - The DeepSeek direct adapter (
llm-deepseek) is not covered: its catalog is fixed and its reasoning-effort control already exists on the Models page. - A provider card whose route is still an unsaved draft dispatches no extension area; save the provider first.
- Disable works on profiles the user settings layer owns — exactly the hand-declared providers the Models page writes. A provider profile declared in the composition (base) layer cannot be taken down from the client: the settings merger guarantees user writes cannot remove it, so the toggle is not offered there.
