Sessions & Messages

dsh-gateway-billing

LeslieWylie/dsh-gateway-billing · ★ 0

LeslieWylie

Per-conversation LLM billing display for the DSH web composer, for anyone self-hosting a New API / One API-compatible gateway.

License
MIT
Added
2026-08-17
Maintenance
active
Install kind
github
Manifest details
Manifest status
Declared
Manifest path
package.json#dsh
Manifest checked
2026-08-19
Lifecycle scripts
None found

Static manifest checks report declarations only; they are not compatibility or security review.

安装

dsh plugin --profile web add github:LeslieWylie/dsh-gateway-billing

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

For install and environment setup, plus plugin development tutorials, see DSH community docs ↗

README

Source README · body: en · Read Chinese README

Table of contents
  1. What is this
  2. Core Capabilities
  3. Install
  4. Via profile (recommended)
  5. Via dsh plugin add (once published to npm)
  6. Required Configuration
  7. Design Principles
  8. Sanitization Notice
  9. Changelog
  10. License

简体中文

What is this

A per-conversation model billing display skill. Generalized from an internal gateway-billing dashboard, it shows the running cost of the current conversation's model calls right below the DSH Web composer — for anyone self-hosting an LLM gateway that exposes a New API / One API-compatible /pricing endpoint.

Core Capabilities

Module Content
Pricing fetch Fetches a New API / One API-format price table from your configured gateway URL, auto-refreshing every 10 minutes
Dual billing modes Supports both token-based pricing (quota_type=0) and fixed per-call pricing (quota_type=1)
Per-conversation folding Walks every model-call node in the current conversation and folds usage (input/output/cache tokens) against the price table
Composer dock display One-line entry: 💰 total cost · most recent model×calls · input/output/cache tokens; multi-model conversations expand to per-model rows
Distinct not-configured / failed states An unconfigured pricing URL and a failed fetch (network error, etc.) render different messages; the former has no "click to retry" — retrying can't fix a missing config
Unpriced-model surfacing A model call with no matching price-table entry is counted and highlighted separately, never silently treated as $0

Install

# 1. Clone the repo
git clone https://github.com/LeslieWylie/dsh-gateway-billing.git ~/Desktop/01-Projects/dsh-gateway-billing

# 2. Add to your profile
cd ~/.dsh/profiles/<your-profile>

# Edit package.json: add to dependencies:
# "dsh-gateway-billing": "link:~/Desktop/01-Projects/dsh-gateway-billing"

# 3. Edit cordis.patch.yml, add an entry pointing at your own gateway's pricing endpoint:
# - id: gateway-billing
#   name: 'dsh-gateway-billing'
#   config:
#     pricingUrl: 'https://your-gateway.example.com/api/pricing'

# 4. Install
pnpm install

# 5. Restart dsh

Via dsh plugin add (once published to npm)

dsh plugin add dsh-gateway-billing

Required Configuration

This skill requires a config block on its own gateway-billing entry in your profile's cordis.patch.yml:

Config Description Example
pricingUrl Your gateway's pricing endpoint. Must return New API / One API-format {data: [{model_name, quota_type, model_ratio, completion_ratio, model_price}, ...]} https://your-gateway.example.com/api/pricing

Without pricingUrl set, the composer dock clearly shows "not configured" — it never errors out or displays a misleading cost figure.

Design Principles

  • Gateway-agnostic: no gateway URL is baked in; the price table source is entirely user-configured
  • Failure is visible: a failed fetch and a missing config are distinct states with distinct messages — neither is swallowed silently
  • Fetch once, read many: the price table refreshes and caches server-side every 10 minutes; the composer dock reads a snapshot over RPC rather than re-fetching per conversation

Sanitization Notice

This plugin was generalized from an internal gateway-billing dashboard. The original implementation hardcoded its pricing endpoint in source and had no "not configured" state — sanitization turned the endpoint into a required config.pricingUrl and added the distinct not-configured/failed rendering. All internal institution names and internal gateway domains have been removed.

Changelog

See CHANGELOG.md.

License

MIT