dsh-omniroute-models
Manifest validDSH plugin: searchable/filterable model manager for OmniRoute (or any OpenAI-compatible gateway) — provider directory, modality discovery, multi-select enable.
@dsh-external/dsh-omniroute-models
OmniRoute model manager: a DSH host+client plugin that pulls every OmniRoute model and its modalities, and lets you control which OmniRoute models DSH actually serves through a searchable / filterable / multi-select settings page.
Pain point: OmniRoute (an OpenAI-compatible gateway) exposes a lot of models (1000+ on this machine). DSH's built-in "Models" page has no search or filter, and its discovery contract does not return modalities (
DiscoveredModelViewonly has id/name/contextWindow/maxTokens). This plugin maps OmniRoute/v1/modelsrealinput_modalities/context_length/max_output_tokensintollm-pi-ai.providers.<route>.models; a single check applies immediately, no restart needed.
What it does
- Filter by vendor: the namespace prefix of a model id (the part before the first
/, e.g.opencode-go/deepseek-…→opencode-go) is parsed out; the UI has a "Vendor" dropdown and a vendor column to filter/view by vendor (opencode,oc,auto,github, no namespace…). - Switch by route (DSH provider): auto-enumerates every configured route under
llm-pi-ai.providers(route, displayName, api, baseURL, model count, OpenAI-compatible or not); the top "Route" dropdown switches which endpoint's models you manage. - One click pulls the provider's
/v1/models(defaulthttp://localhost:20128/v1), giving each model'sinput(text/image, derived frominput_modalities/capabilities.vision),contextWindow,maxTokens. - Adds an "OmniRoute model manager" page to the DSH settings panel: search box + modality filter + select-matching/clear-all + per-row checkbox.
- "Save selected" replaces
llm-pi-ai.providers.<route>.modelsin one go (DSH serves exactly the checked ones), written through the official settings seam intosettings.yamland effective on the next request; sibling fields likeapiKeyEnv/api/baseURLare preserved. - Enabled models are pre-checked, and on re-pull the stored value wins (it does not override
modalities/capacities you hand-edited in
settings.yaml). - Modality keeps only
text/image(what DSH understands);video/audioetc. are clipped so the plugin never writes modalities DSH cannot handle (and thus fails validation). - Web search: wires DSH's built-in
web_searchto one of two sources, selected in theWeb searchcard — the OmniRoute aggregate search (POST /v1/search, Tavily/Brave/Exa/Serper/Ollama/…) or the DeepSeek official native search. When the OmniRoute source is disabled, or the source is set to DeepSeek official,web_searchautomatically falls back to DeepSeek's official search instead of failing. For the OmniRoute source, the key is optional (OmniRoute uses its own per-provider stored keys) but if your endpoint requires one it resolves in this order: literalsearchApiKey→ DSH credentials ref named bysearchApiKeyEnv→ process env (same pattern as the officialdsh-web-search-deepseek).
API key requirement (model provider vs. search)
Every OmniRoute call now needs a valid key — since OmniRoute 3.8.50 even
GET /v1/models (the model catalog) rejects anonymous requests with 401
(REQUIRE_API_KEY does not change this).
- Pulling the catalog / saving the whitelist: the plugin resolves the route's
apiKeyEnvthrough the DSH credential store first (the exact seamllm-pi-aiuses for chat), then the process env, then the?apiKey=query parameter. Store the OmniRoute gateway token once as a DSH credential (or set the env var) and both the catalog and chat work. - Actually chatting: DSH's
llm-pi-aiadapter (via@earendil-works/pi-ai) requires a non-empty key and throwsNo API key for provider: <route>otherwise. Fill the provider's API key field (a DSH credential ref) in the "Models" settings.pi-aialso accepts a provider-levelheaders.authorization, but that is the non-standard path, not recommended.
For the web search provider the key is genuinely optional (OmniRoute serves
POST /v1/search anonymously and uses its own stored upstream keys) — see the
Web search bullet above.
Internals
- Host (
src/index.ts): registers two same-origin JSON routes (ctx.webServer.register):GET /omniroute-models/api/catalog?provider=<route>— enumerates thellm-pi-aiprovider directory (providers) → reads the route's current models → requestsGET {baseURL}/models→ returns{ configured, compatible, provider, displayName, api, baseURL, providers:[...], models:[{id,name,input,contextWindow,maxTokens,enabled}], enabledCount, totalCount }; returnscompatible:falseonly when the route protocol cannot be listed through an OpenAI-shaped/v1/models;anthropic-messages/openai-responsesare pulled just likeopenai-completions(the OmniRoute gateway's model catalog is protocol-agnostic and always OpenAI format).POST /omniroute-models/api/apply—{ provider, models:[{id,name,input,contextWindow,maxTokens}] }, validated then written viactx.settings.mutate('llm-pi-ai', [{op:'set', path:['providers',provider,'models'], value}], expectedRevision); conflicts returnSETTINGS_CONFLICT, schema rejection returnssettings-rejected.- The component does not register/own the
llm-pi-ainamespace (that is the adapter@deepseek-ai/dsh-llm-pi-ai's); it only reads/writes an existing namespace.
- Client (
src/client/index.tsx): subscribes thesettings.sectionslot (idomniroute-models, order 15), renders a React table; all data goes through same-originfetch, noctx.api/LLM remote. - Web search provider (
src/index.ts): owns theomniroute-modelssettings namespace for search config and, when enabled, registers actx.webWebSearchProvider(idomniroute) so DSH'sweb_searchuses OmniRoute; config/test routesGET|POST /omniroute-models/api/search-configandPOST /omniroute-models/api/search-test. The section is registered viainstallSettingsSection(which waits for thesettingsservice), so the plugin's activation order never races it;available()only requiresenabled+ an http(s) base URL, and the key is resolved lazily per request. - Only chat-capable models are listed: the gateway
/v1/modelscan mix inembedding/video/image-generation entries; the host'sfetchCatalogfilters bytype(embedding|video|image|audio|music|rerank) so they are never mis-listed/mis-saved as text chat models. OmniRoute ≥3.8.50 additionally lists its search engines as pseudo models (brave-search/web,tavily-search/news, …) with notype; those are filtered by their-searchvendor suffix.
i18n
- Uses DSH's official locale mechanism (
@deepseek-ai/dsh-client-locale), namespaceomniroute-models. - Dictionaries live in
src/client/locales.ts:zhis the key-set source of truth;en: Record<OmniKey,string>is compile-checked complete. - The client sets
inject = ['slots','locale'];applycallsctx.effect(() => ctx.locale.register(NS, { zh, en })), thenctx.locale.bind(NS)fort; thesettings.sectionregisters withinject: () => ({ t })andlabel: () => t('nav'); the section reads copy fromprops.tand refreshes when the language switches (DSH settings → Language). - Host message localization: the deterministic catalog/apply messages return a
code(e.g.catalog.notConfigured,apply.duplicateId) plusparams, keeping the Chinesemessagefor curl/development; the client'shostMessageonly translates knowncode(host.*keys), soSETTINGS_CONFLICT/settings-rejectedexception codes are not mis-translated. - Add a third language: add the dictionary in
locales.ts, add it todictionaries, and add the locale to the registration loop inapply.
Build
# Dev prerequisites: install build tooling, then point @deepseek-ai runtime types at the DSH harness
pnpm install && pnpm link:dev
npm run build # host → lib/index.js
npm run build:client # client → lib/client.js
Install / inject
- In this environment (super-injector):
dev_inject_plugin /path/to/dsh-omniroute-models, host+client applied immediately. - Production bundle (GitHub, pinned):
dsh plugin --profile web add github:publieople/dsh-omniroute-models#v0.2.5, then restart the target profile.
Usage
- Refresh the DSH page (runtime-injected client modules only bootstrap after a page reload).
- Open "Settings" → the "OmniRoute model manager" entry appears on the right.
- Search / filter by modality / check the models to use (vision models show a
text + imagebadge). - Click "Save selected" → writes
llm-pi-ai.providers.omniroute.modelsinsettings.yaml. - Send a message with a just-checked model to verify (vision models can attach an image).
Verify
- host:
curl "http://127.0.0.1:3080/omniroute-models/api/catalog"should return the model list + modalities + enabled. - write:
curl -X POST .../api/apply -d '{"provider":"omniroute","models":[{...}]}'. - check
~/.dsh/settings.yaml'sllm-pi-ai.providers.omniroute.models(withinput/contextWindow/maxTokens, siblings preserved).
Comments
Loading…
Similar plugins
by CARVIN94
An AI routing gateway that runs as a DSH plugin. Adds a Routing System sidebar panel for suppliers, account pool, fallback combos and API keys, and serves an OpenAI-compatible endpoint at http://local
★ 8
↓ 852/wk
MIT
TypeScript
Sep 26, 2026
dsh plugin --profile web add dsh-router-coreby andrepontesmelo
DSH plugin: virtual model ids backed by pluggable routing algorithms (priority, round-robin) over real provider candidates, with transparent failover.
★ 0
MIT
JavaScript
Sep 24, 2026
dsh plugin --profile web add @andrepontesmelo/dsh-model-routerDSH plugin: matches a model you declared on a custom gateway to the capability metadata it should have — context window, output cap, reasoning levels and image support — by looking the bare model name
★ 0
dsh plugin --profile web add dsh-model-metadataby lincong1987
dsh plugin: flexible model switch for sub‑agent & plan execution. 为子代理和计划执行选择更合适的模型。
★ 10
MIT
TypeScript
Sep 10, 2026
dsh plugin --profile web add dsh-model-switchby sharewiner
Manages the default DSH model, provider and model visibility, and optional OpenAI Responses web search.
★ 1
↓ 65/wk
MIT
JavaScript
Aug 26, 2026
dsh plugin --profile web add @sharewiner/dsh-model-managementby snowshadow
Community DSH plugin: OpenAI-compatible gateway adapter and dialect fixes (not an official DeepSeek package)
★ 0
MIT
TypeScript
Sep 10, 2026
dsh plugin --profile web add dsh-llm-gateway-compat