读取 OpenRouter 实时 /models 列表的模型提供商,新模型无需等待 harness 发版即可出现:模型按名称排序并显示输入/输出价格,按模型提供思考档位、图片输入、reasoning_details 回放、Anthropic 提示缓存,并按 OpenRouter usage.cost 统计本会话(含子代理)的实际花费,显示在 Web 输入框下方并可用 /cost 查看。
安装
# npm 包(预构建)
dsh plugin --profile web add dsh-openrouter-live
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:Boomerangz/dsh-openrouter-live
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
该插件的 README 只有英文版本。
An OpenRouter provider for DeepSeek Harness (dsh) that reads OpenRouter's live model list, so a model shows up in the picker as soon as OpenRouter serves it.
The harness's built-in openrouter route lists models from a catalog bundled with each release. A model released after that snapshot, such as deepseek/deepseek-v4.1-flash, does not appear in the picker until the next harness release. This plugin adds a second route, OpenRouter (live). It reads OpenRouter's /models endpoint and takes each model's metadata from there.
What it does
Live model list. It lists every OpenRouter model that accepts tools, sorted by name, so models from one vendor stay together. Each name ends with the input/output price per million tokens. The list is refreshed every 10 minutes. If a refresh fails, the previous list stays in use.

Per-model metadata. The context window and output cap come from OpenRouter. The reasoning levels come from the model's own
reasoning.supported_efforts, so the composer offers only levels the model accepts, including Off when reasoning is optional.Image input. It inlines images for models whose
/modelsentry listsimageinput. It follows the harness image budget: images are downscaled, and the oldest images are offloaded when a request grows too large.Reasoning continuity. It sends
reasoning_detailsback on later requests, including signed and encrypted entries. This lets models such as Claude and DeepSeek keep their reasoning across tool calls.Prompt caching.
- Anthropic models get cache breakpoints on the system prompt and the newest message. In a live check, a second request read 7209 of 7223 prompt tokens from cache.
- Other providers cache automatically. The
x-session-idheader keeps each conversation on one upstream provider, so its cache stays warm.
Classified failures. Errors map to the harness failure codes, so the harness retry plugin retries only what is worth retrying:
- Retried: rate limits, with OpenRouter's
Retry-Afterhonored; upstream 5xx errors; idle streams; truncated streams; empty responses. - Not retried: bad keys, exhausted credits, and context overflow.
- Retried: rate limits, with OpenRouter's
Actual spend, including subagents. The plugin records the charge OpenRouter reports for every response (
usage.cost), so these are real charges, not token estimates. Each charge is attributed to the session that made the request and to every session it was delegated from. Type/costin the CLI or Web UI:OpenRouter spend in this session: $0.0022 (5 requests) this agent: $0.0011 (3 requests) subagents: $0.0011 (2 requests in 1 session) All recorded sessions: $0.0022 (5 requests).In the Web UI the session total is always visible under the composer, next to the built-in statistics and context meter. It updates during a turn, including subagent charges, and its tooltip splits the total between the agent and its subagents. It is hidden in sessions with no OpenRouter charges.

Charges are appended to
~/.dsh/openrouter-live/costs.jsonl, one JSON line per response, so totals survive restarts. Each line carries the OpenRouter generation id, so any charge can be matched against your OpenRouter activity page.Shared credential. By default the route reads the same
OPENROUTER_API_KEYcredential as the built-inopenrouterroute, so a key you already stored works without extra setup.
Requirements
- DeepSeek Harness
0.1.6-alpha.2through0.1.7. It has been tested on0.1.6-alpha.2and0.1.7-alpha.2. The harness API is pre-stable, so later harness versions are added to the peer range after they are tested. - Node.js
^22.19 || >=24. - An OpenRouter API key.
Install
From npm:
dsh plugin --profile web add dsh-openrouter-live
From a local checkout:
git clone https://github.com/Boomerangz/dsh-openrouter-live.git
cd dsh-openrouter-live
npm install
npm pack --pack-destination dist # runs typecheck and tests first
dsh plugin --profile web add "$PWD/dist/dsh-openrouter-live-0.2.0.tgz"
[!IMPORTANT] Install the packed
.tgz, not the directory. When you add a directory, pnpm links it, Node resolves the link to its real path outside the profile, and the harness packages (@deepseek-ai/*) can't be found there. The whole profile then fails to boot.
Restart the profile after installing. OpenRouter (live) then appears in the model picker. If you haven't stored a key yet, choose one of these:
- Enter it on the built-in OpenRouter card under Settings → Models. It is stored as
OPENROUTER_API_KEY, which both routes read. - Export
OPENROUTER_API_KEYbefore launchingdsh.
To choose it as the default model, pick it in the composer's model picker. You can also set it in ~/.dsh/settings.yaml:
agent-default-model:
provider: openrouter-live
model: deepseek/deepseek-v4.1-flash
Configuration
Every field is optional. Set fields in the profile's patch layer, ~/.dsh/profiles/<profile>/cordis.patch.yml, under the plugin's entry id openrouter-live:
- id: openrouter-live
config:
models: ['deepseek/*', 'anthropic/claude-*', 'openai/gpt-5*']
extraBody:
provider:
sort: throughput
| Field | Default | Meaning |
|---|---|---|
models |
[] |
Glob patterns over model ids. An empty list lists every model. Ids outside the filter still work when typed. |
toolsOnly |
true |
List only models whose OpenRouter entry accepts tools. Agent turns need tools. |
priceInName |
true |
Append input/output prices per 1M tokens to model names, such as DeepSeek: DeepSeek V4.1 Flash ($0.15/$0.60), because the pickers show names but not descriptions. The price then also appears in the composer's model button. |
apiKeyEnv |
OPENROUTER_API_KEY |
Credential reference: a credential-store entry or environment variable. |
provider |
openrouter-live |
Route id. Give each instance its own id to run several side by side, for example one with a *:free filter. |
displayName |
OpenRouter (live) |
Provider name in the picker. |
baseURL |
https://openrouter.ai/api/v1 |
API root. |
modelListTtlMs |
600000 |
How long one fetched model list is reused. |
maxTokens |
32768 |
Output cap for requests that set none. A lower model limit wins. |
defaultContextWindow |
262144 |
Context size assumed for an id the list does not describe. |
streamIdleTimeoutMs |
300000 |
Longest silence inside a response stream before failing with TIMEOUT. |
maxRequestImageBytes |
20971520 |
Base64 image budget per request. Older images are offloaded beyond it. |
requestImagePixelBudget |
4194304 |
Pixel budget of one request image. |
requestImageMaxBytes |
1048576 |
Encoded-byte target of one request image. |
appTitle / appUrl |
DeepSeek Harness / unset |
OpenRouter app attribution headers (X-OpenRouter-Title, HTTP-Referer). |
extraBody |
{} |
Fields merged into every request body, such as provider routing. Fields the plugin sets take precedence. |
costLedgerPath |
$DSH_HOME/openrouter-live/costs.jsonl |
Spend ledger file. An empty string keeps spend in memory for the current process only. |
costCommand |
cost |
Slash command that reports spend. Leave it empty on a second instance that shares the ledger, so the command is registered once. |
costIndicator |
true |
Serve the Web UI spend indicator's data route (/openrouter-live/spend). Disable it on a second instance, which would otherwise claim the same route. |
retryPolicy |
harness default | The harness's provider retry policy for this route: {mode: normal, maxRetries, retryableCodes, backoff} or {mode: always}. |
How it maps onto OpenRouter
| Harness | OpenRouter chat completions |
|---|---|
| System prompt, user and assistant text | system, user and assistant messages |
| Tool definitions and tool calls | tools (function type) and tool_calls |
| Tool results | tool messages. Images returned by a tool follow in a user message, because tool messages carry text only. |
| Images | image_url data URLs, each preceded by the harness's image handle line |
| Reasoning effort | reasoning.effort |
| Reasoning output | The reasoning stream becomes reasoning blocks. reasoning_details is kept for replay. |
| Usage | prompt_tokens is split into uncached input, cache reads and cache writes. Reasoning tokens are reported separately. |
Development
npm install
npm run check # tsc --checkJs (strict) + node:test suite
OPENROUTER_API_KEY=... npm run smoke # live checks against OpenRouter; costs a few cents
The plugin is plain ESM JavaScript with JSDoc types, so no build step is needed to run it. npm pack generates the .d.ts files in types/. The test suite includes a composition test that boots the real LlmRuntime from @deepseek-ai/dsh-llm in a Cordis context and streams through it.
Known limitations
Spend covers only requests through this plugin's routes. The built-in
openrouteranddeepseek-officialroutes are not counted.A charge is recorded when OpenRouter reports it at the end of a response. A request that is cancelled or fails mid-stream may still be billed by OpenRouter, but it does not appear in
/cost.The Web UI indicator reads a route that answers only same-origin requests to a loopback address (
127.0.0.1,localhost), because the harness web server does not authenticate plugin routes. When the Web UI is opened over the network, the indicator stays hidden;/coststill works./costneeds the harness command service, which the CLI and Web profiles mount. Headless runs still write the ledger.Only OpenRouter's text output is used. Image generation and audio models are listed only when they also accept tools, and their non-text output is ignored.
Prices in the picker are OpenRouter's base prices. Time-of-day price overrides are not shown.
Explicit cache breakpoints are sent only for
anthropic/*models. Every other model relies on its provider's automatic caching.A model that reasons but publishes no
supported_effortsgets no reasoning selector, so OpenRouter's default applies.
License
MIT
链接
同类插件
V1ki/dsh-plugin-subscriptions★ 379
把 ChatGPT(Codex)、Claude、Grok 订阅当作 DeepSeek Harness 的 LLM 提供方:设置页登录、模型目录、用量展示,以及 image_generate、video_generate 与 x_search 工具。
Mars-Sea/dsh-commandcode-provider★ 318
非官方 Command Code 模型接入插件:注册 `commandcode` 路由,带实时模型目录与推理强度支持。
corrinehu/dsh-workbuddy-connect★ 186
将 WorkBuddy 桌面 App 包含的模型自动接入 DeepSeek Harness,在 DSH 对话窗口里零配置使用。
volcengine/ark-cli#ark-plan-api★ 137
在 DSH 原生模型选择器中注册方舟 Agent Plan、Coding Plan 与后付费模型路由。
cv-superding/dsh-deepseek-web-login★ 130
新增 deepseek-web provider,把 chat.deepseek.com 网页端模型接入 DSH:浏览器登录抓取、PoW 请求签名、SSE 流式传输与基于提示词的工具调用。
franksong2702/dsh-codex-connect★ 118
通过 ChatGPT OAuth 将 OpenAI Codex 模型接入 DeepSeek Harness,并提供可选的搜索与图片工具。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。