Files
deepseek-harness/packages/llm/openrouter-usage/README.md
Coder ed152416d5
Some checks failed
CI / node 22.19 (push) Has been skipped
CI / node 26 (push) Has been skipped
CI / python 3.10 / keyless SDK (push) Has been skipped
CI / python runtime / release-shaped Linux x64 (push) Has been skipped
CI / windows node 24 / wine blocking (push) Has been skipped
CI / wine apt cache (push) Successful in 58s
CI / serial / linux (push) Has been skipped
Deploy documentation / build (push) Failing after 2m46s
Deploy documentation / deploy (push) Has been skipped
E2E (real DeepSeek API) / e2e (push) Failing after 1m18s
Sandbox / sandbox e2e (bwrap, ubuntu-latest) (push) Failing after 1m18s
Landlock Run / Matrix (push) Successful in 13s
Release (vendor) / Pack npm tarballs (push) Failing after 3m43s
Release (dsh) / Pack npm tarballs (push) Failing after 1m53s
Sandbox / sandbox e2e (landlock, ubuntu-24.04) (push) Failing after 1m51s
Release (vendor) / Publish to npm (push) Has been skipped
Release (dsh) / Publish to npm (push) Has been skipped
CI / node 24 / static (push) Has been cancelled
CI / node 24 / coverage (push) Has been cancelled
CI / node 24 / snapshots and artifacts (push) Has been cancelled
CI / windows node 24 / native complete (push) Has been cancelled
CI / serial / linux (self-hosted standby) (push) Has been cancelled
CI / serial / macos (push) Has been cancelled
CI / serial / windows (self-hosted standby) (push) Has been cancelled
CI / larger-runner-benchmark (16, linux, dsh-ubuntu-24-04-16core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (16, windows, dsh-windows-2025-16core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (32, linux, dsh-ubuntu-24-04-32core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (32, windows, dsh-windows-2025-32core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (4, linux, dsh-ubuntu-24-04-4core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (4, windows, dsh-windows-2025-4core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (64, linux, dsh-ubuntu-24-04-64core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (64, windows, dsh-windows-2025-64core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (8, linux, dsh-ubuntu-24-04-8core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (8, windows, dsh-windows-2025-8core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (96, linux, dsh-ubuntu-24-04-96core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (96, windows, dsh-windows-2025-96core, production-site) (push) Has been cancelled
CI / consolidated-runner-benchmark (16, linux, dsh-ubuntu-24-04-16core, 16) (push) Has been cancelled
CI / consolidated-runner-benchmark (16, windows, dsh-windows-2025-16core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (32, linux, dsh-ubuntu-24-04-32core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (32, windows, dsh-windows-2025-32core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (4, linux, dsh-ubuntu-24-04-4core, 4) (push) Has been cancelled
CI / consolidated-runner-benchmark (4, windows, dsh-windows-2025-4core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (64, linux, dsh-ubuntu-24-04-64core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (64, windows, dsh-windows-2025-64core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (8, linux, dsh-ubuntu-24-04-8core, 8) (push) Has been cancelled
CI / consolidated-runner-benchmark (8, windows, dsh-windows-2025-8core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (96, linux, dsh-ubuntu-24-04-96core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (96, windows, dsh-windows-2025-96core, 2) (push) Has been cancelled
CI / all checks passed (push) Has been cancelled
Sandbox / sandbox e2e (seatbelt, macos-latest) (push) Has been cancelled
Sandbox / sandbox e2e (landlock, ubuntu-24.04-arm) (push) Has been cancelled
Landlock Run / ${{ matrix.platform }} (push) Has been cancelled
Landlock Run / darwin (no platform package — degradation proof) (push) Has been cancelled
feat: add searxng web-search provider, openrouter cost balance UI, offline scripts; update source-launch and docs
2026-08-20 13:01:40 +07:00

102 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# @deepseek-ai/dsh-openrouter-usage
English | [中文](README.zh.md)
OpenRouter spend tracking: a Typert Remote gateway exposing the account
balance plus the `openRouterCost` session projection, which prices logged
token usage against OpenRouter's model pricing table.
The package is inert without a resolvable `OPENROUTER_API_KEY` (the same
credential OpenRouter LLM routing already uses): no key means no fetch, an
empty pricing table (so every step stays unpriced), and an empty balance.
## Config
```yaml
- id: openrouter-usage
name: '@deepseek-ai/dsh-openrouter-usage'
config:
apiKeyEnv: OPENROUTER_API_KEY
baseURL: https://openrouter.ai/api/v1
syncEnabled: true
pricingRefreshMs: 21600000
balanceRefreshMs: 60000
```
| Key | Default | Meaning |
| --- | --- | --- |
| `apiKeyEnv` | `OPENROUTER_API_KEY` | Credential reference resolved per refresh. |
| `baseURL` | `https://openrouter.ai/api/v1` | OpenRouter API root; `/credits`, `/models`, and `/auth/key` are appended. |
| `syncEnabled` | `true` | Whether periodic pricing/balance refresh runs. |
| `pricingRefreshMs` | `21600000` (6h) | Pricing-table refresh interval in ms. |
| `balanceRefreshMs` | `60000` (60s) | Balance refresh interval in ms. |
The key resolves through the credentials seam (`ctx.credentials`), with the
launch environment as fallback, exactly like `dsh-web-search-deepseek`.
## Service contract
`ctx.openRouterUsage` is a Typert Remote gateway. The `snapshot()` method
returns a detached copy of the last successful balance snapshot: `balanceUsd`
is the available balance from `GET /credits` (`total_credits` minus the spent
`total_usage`, the figure OpenRouter's dashboard surfaces), plus `label` and
the monthly `usageTokens`/`limitTokens` budget from `GET /auth/key`,
`isFreeTier`, and an `updatedAt` epoch. Before any successful fetch it serves
an all-`null`
record; a failed refresh keeps the last-known snapshot and logs. The same key
also refreshes the model pricing table from `GET /models`
(`pricing.prompt`/`completion` USD per token, plus a flat `request` fee and
optional `input_cache_read`/`input_cache_write` when disclosed).
The `openRouterCost` projection folds each session's logged token usage
(`assistant/chunk` usage and `assistant/message` usage, deduplicated per
step) against the pricing table. Attribution prefers the assembled message's
own `provider`/`model`; a chunk-only (failed) step prices from the newest
`request/context` route. A step on a non-`openrouter` provider is outside the
domain and changes nothing; an OpenRouter step whose model has no pricing
entry counts as an unknown (unpriced) step.
## Extension points
Web surfaces read the `openRouterCost` projection and call the balance Remote
through the client assembly (`ctx.remote.openRouterUsage.snapshot()`); the
component stack ships in `dsh-client-ui-openrouter-usage`. The gateway
requires no session or agent wiring — everything rides the durable whole-log
projection and one cached fetch.
## Model Experience
### OpenRouter cost and balance readouts
#### What the model sees
Nothing. Cost and balance are client-facing read models only: neither enters
a model request, a tool schema, or any prompt. The agent loop is unchanged.
#### Token effect
No model tokens. Priced figures derive from usage already logged by the
existing `assistant/message` and `assistant/chunk` events.
#### KV Cache effect
None; the KV cache is unaffected because cost is a projection of existing
usage events, never a new model-visible input.
## Known Limitations and Deferred Work
- **Estimate, not itemized billing** — cost is `tokens × model pricing`,
not OpenRouter's itemized per-generation billing. Generation ids are not
durably logged, and the pi-ai adapter discards `usage.cost`, so the
projection reconstructs spend from token counts. Free-tier and
promotional pricing may differ from the model table.
- **Pricing as of the fold** — the projection prices a cell with the model
table current when that cell folds. Refreshing pricing only affects cells
folded afterward; already-folded history keeps its prior figures.
- **Per-token approximation** — cache-read/cache-write fall back to the
prompt rate when the API does not disclose separate cache rates, and the
flat request fee is charged once per step. Bills may differ by fractions
of a cent.
- **No settings card** — the plugin exposes config only through cordis.yml;
a settings-section UI is deferred.