dsh-bailian-catalog
kennethfan/dsh-bailian-catalog
DSH 设置页里的百炼(DashScope / Model Studio)模型目录:列出当前 API Key 可用的全部模型、按模型家族分组,可探测某模型是否真的可调用(未开通会返回 403,而 DSH 会把它显示成密钥无效),探测不通过的模型拒绝加入配置,并显示当前会话的上下文窗口与剩余额度。百炼 sk- Key 没有余额接口,因此这里的额度指上下文额度。
安装
dsh plugin --profile web add github:kennethfan/dsh-bailian-catalogREADME
dsh-bailian-catalog
English | 中文
Lists every Alibaba Bailian (DashScope / Model Studio) model the configured credential can reach, inside the DSH Web GUI under Settings → 百炼模型, and adds or removes any of them from the Bailian provider route. It also shows the current session's context quota.
What it does
- Settings panel: total model count, probed endpoint, refresh time, search, per-family collapsing, and one-click copy of a model id.
- Add to config: every row has an Add button that writes the model into
llm-pi-ai'sproviders.bailian.models, after which the model appears in the model picker. Clicking it again removes the model. The add is probed first — see Availability probing. - Availability probe: a per-row Probe button that sends one minimal chat request and reports whether the model is actually callable, so an unopened model is not mistaken for a bad key.
- Current session quota: the context window, tokens used, remaining budget and a usage bar for the model the active session is running on.
- Agent tool:
bailian_list_models, callable from any session, with aquerysubstring filter, an exactfamilyfilter and an exactvendor(namespace) filter.
Availability probing
A model listed by /models is not necessarily a model you may call. A Bailian workspace that has not opened a model answers 403 AccessDenied.Unpurchased, and DSH surfaces every upstream 401/403 as "invalid API key" — which points at the key instead of at the entitlement. Probing settles it.
POST /api/bailian-catalog/probe sends one max_tokens: 1 chat request and classifies the answer:
| State | Meaning |
|---|---|
ok | Callable |
unpurchased | The workspace has not opened this model, or its quota is exhausted (AccessDenied.Unpurchased) |
unauthorized | The key is invalid or expired |
not-found | The model does not exist, or the OpenAI-compatible interface does not support it (embedding, rerank) |
not-chat | A non-chat model (embedding, image, speech) rejected the messages payload — the route is reachable, but a chat request cannot verify it |
rate-limited | Throttled; retry later |
timeout / error | No usable answer |
not-chat is deliberately a neutral result rather than a failure: probing an image or embedding model with a chat request always returns 400, which says nothing about whether the model is available.
Adding is guarded by the probe. A model in a blocking state (unpurchased, unauthorized, not-found, error, timeout) is not written to the route, and the panel shows why. Writing an unusable model into the route is what turns one bad selection into a session that fails on every turn. not-chat models are allowed through, since a chat request cannot judge them, and the probe result is returned alongside the write.
Grouping
Many endpoints advertise ids without an owner/ prefix — roughly six in ten on the author's endpoint — so grouping by that prefix alone would leave most models in a single bucket. Models are grouped by family instead, derived from id patterns (qwen* → 通义千问, glm* → 智谱, kimi* → Kimi, deepseek* → DeepSeek, minimax* → MiniMax, wan* → 通义万相, and so on), with the owner/ prefix kept as a secondary namespace value. On the author's endpoint nearly every model resolves to a real family; only gui-plus and two ops entries fall through to 其他.
How it works
- Host half (
index.js)- Reads
BAILIAN_API_KEYthrough thecredentialsservice (credential store first, environment fallback). The key stays in host memory: it is never sent to the browser and never written to disk. - Enumerates models through the official
llm.discoverModels()path, which requestsGET {baseURL}/modelswithAuthorization: Bearer. - Quota: reads the most recently active live session, measures used tokens with
tokenMeter.measure(), and takes the model and window fromsession.requestContext(), falling back tollm.resolveModelInfo()when the window is unknown. - Add/remove writes through
settings.mutate(), the structured profile-patch write path, rather than editing YAML text. - Probing posts one
max_tokens: 1chat request with a hard timeout and classifies the answer; error code and message are read from both theerrorobject and the payload top level, since this endpoint uses both shapes. - Every route calls
connection.requestRejectionbefore doing any work.
- Reads
- Browser half (
client.js)- A hand-written
ModuleLoaderbundle with no build step, depending only on the shell-providedreact. - Registers a
settings.section(idbailian-catalog, order 12) and renders from the same-origin endpoints.
- A hand-written
Endpoints
| Method | Path | Purpose |
|---|---|---|
GET | /api/bailian-catalog/list | Model list, plus configured (ids already in the route) and families |
GET | /api/bailian-catalog/usage | Active session's model, tokens used and context window |
POST | /api/bailian-catalog/probe | { id }, one minimal chat request, classified into the states above |
POST | /api/bailian-catalog/add | { id }, probed first; returns already, blocked, or added |
POST | /api/bailian-catalog/remove | { id }, removes it from the route |
Every route asks connection.requestRejection first, so the Host/Origin fence and browser authentication gate callers before any model list or config write is reachable. A no-cookie request gets 401; a cross-site Origin gets 403.
The first
settings.mutatewrite materializes schema defaults (input: [],compat: { chatTemplateKwargs: {}, chatTemplateArgs: {} }) into the patch. They are semantically inert, but they add a few lines to the file.
What "quota" means here
A Bailian sk- key has no balance or quota endpoint (the usual paths — /dashboard/billing/*, /user/balance, /usage — all return 404), and account balance is only reachable through the Alibaba Cloud BSS OpenAPI with an AccessKey. So this plugin reports context quota instead:
- the context window, tokens used, remaining budget and a usage bar for the active session's model;
- states: enough budget, near the ceiling, or exhausted;
- it is measured the same way the in-session compaction decision is, so "exhausted" means that session can no longer continue and a new session restores the budget.
Install
From GitHub:
dsh plugin --profile <profile> add github:kennethfan/dsh-bailian-catalog
From a local checkout:
dsh plugin --profile <profile> add link:/path/to/dsh-bailian-catalog
The host half needs a dsh process restart before its routes exist; the browser half appears after a page refresh.
Prerequisites
You need your own Bailian (DashScope / Model Studio) API key, and — if you use a dedicated Model Studio workspace — that workspace's MaaS gateway URL. This plugin ships no credential and points at no private workspace: the default endpoint is the public DashScope compatible endpoint.
Configuration
| Key | Default | Meaning |
|---|---|---|
baseURL | https://dashscope.aliyuncs.com/compatible-mode/v1 | Endpoint to enumerate. Point it at your workspace's MaaS gateway when you use a dedicated Bailian space. |
provider | bailian | The llm-pi-ai provider key that add/remove writes to. |
apiKeyEnv | BAILIAN_API_KEY | Credential reference resolved through the credentials service. |
families | [] | Extra family rules (see below). |
- insert:
- id: bailian-catalog
name: 'dsh-bailian-catalog'
config:
baseURL: https://llm-<your-workspace>.cn-beijing.maas.aliyuncs.com/compatible-mode/v1
provider: bailian
apiKeyEnv: BAILIAN_API_KEY
A workspace gateway returns the same body shape as the public endpoint; it simply sees whatever models your key is entitled to.
Custom family rules
families adds your own rules to the family table. They are matched before the built-in rules, so a rule can also reclassify something a built-in rule would otherwise claim:
- id: bailian-catalog
name: 'dsh-bailian-catalog'
config:
families:
- pattern: '^gui-plus$' # case-insensitive regular expression
family: GUI
- pattern: '^sre-gpu'
family: 运维
A rule is tested against the full model id first and against the leaf name (the part after /) second, exactly like the built-in table.
Invalid input is skipped rather than fatal — a bad regular expression, a missing pattern or family, or a families value that is not an array each produce a warning that the settings panel shows, and the built-in rules keep working.
Known limits
- The endpoint returns the models the current API key can use, not Bailian's full public catalog (180 on the author's endpoint). Listing a model does not imply entitlement — probe it.
- Probing costs one request per click. It is not run automatically for the whole list, since that would be hundreds of calls.
- A chat request cannot judge embedding, image, speech or rerank models; they report
not-chatand stay unverified. - Reads are safe; only add/remove write, and only to the configured provider's
modelslist. - Reachable from localhost only (the web server binds 127.0.0.1); the route fence assumes that origin model.
License
MIT