zhm20001/dsh-usage-board

dsh-usage-board

dsh-usage-board 是专为 DSH (DeepSeek Harness) 设计的用量与成本可视化看板插件。 插件能实时捕获会话内的 Token 消耗、Step 耗时和异常指标,支持冷启动增量回溯历史全量会话,并按 Sub-agent DAG 调用关系进行树状归集与反向明细穿透。

Uncategorizeddeepseek-harnessdsh

dsh-usage-board

A full-featured usage monitoring, cost accounting, and diagnostics dashboard plugin for DeepSeek Harness (DSH / Cordis).

简体中文 | English


📖 Introduction

dsh-usage-board is a usage and cost visualization dashboard plugin designed for DSH (DeepSeek Harness).

It captures in-session token consumption, step latency, and anomaly metrics in real time, supports cold-start incremental backfill of all historical sessions, and aggregates usage along the Sub-agent DAG call tree with drill-down into per-step details.


📸 UI Preview

The plugin mounts its UI in three places via the host's slot system (the frontend is a lightweight stateless design, lib/client.js): the Usage Board button at the bottom of the sidebar opens the fullscreen dashboard, and the conversation page ships a built-in Usage tab for per-session accounting.

Conversation "Usage" tab — per-session accounting & diagnostics

Session Usage Tab

Tree-level KPIs (input / output = thinking + content / cache hit / cost), five-bucket token composition × peak/off-peak cost (zero buckets hidden automatically), model breakdown, request efficiency, and per-step detail. Hover the inline ? to see that bucket's peak / off-peak unit price and amount side by side (off-peak = peak × ½):

Peak/off-peak rate tooltip

Fullscreen dashboard (Overlay) — overview

Dashboard overview

Volume / cost / cache-hit KPIs, official DeepSeek balance with burn-rate forecast (incl. off-peak/counterfactual savings), an 84-day usage heatmap, and a 24-hour peak/off-peak profile.

Fullscreen dashboard (Overlay) — sessions & turns detail

Dashboard turns table

Recent sessions aggregated by call tree, Turn × Step detail (TTFT / duration / five token buckets / peak-off-peak cost), one-click CSV export.

Mount points

SlotLocationContent
conversation.viewConversation page "Usage" tabTree-level aggregate metrics, five-bucket token composition × peak/off-peak cost, model breakdown, step-level duration waterfall
sidebar.footer.actionSidebar footerAlways-on toggle button for the dashboard
shell.overlayFullscreen dashboard (Overlay)Balance & remaining days, anomaly & counterfactual-savings KPIs, 84-day heatmap, 24h peak/off-peak profile, recent sessions, turns detail table with CSV export

✨ Key Features

  • ⚡ Zero runtime dependencies: built on Node.js 22.5+ native node:sqlite — no native C++ compilation, no worker processes.
  • 🏛️ CQRS architecture: DSH session files are the read-only source of truth (Write Model); the plugin's SQLite database is a rebuildable read-only projection (Read Model), keeping session data safe.
  • 🚀 Warm/hot two-layer read model:
    • Warm layer (SQLite): incremental daily_rollups / session_rollups per dirty partition; costs recomputed on the fly against the latest price schedule.
    • Hot layer (in-memory snapshot): an immutable in-process snapshot served render-ready in one request; rev version negotiation answers unchanged instantly when nothing changed.
  • 🌲 Sub-agent DAG aggregation: multi-level sub-agent call-chain aggregation, step-duration waterfalls, five-bucket token composition analysis.
  • 💰 Cost & balance insights: official DeepSeek balance passthrough, live burn-down forecast, off-peak/counterfactual savings computation.
  • 🖥️ Three seamless UI mounts: natively embedded in the DSH web console (conversation tab, sidebar entry, fullscreen dashboard).

🚀 Quick Start

1. Prerequisites

  • Node.js >= 22.5.0
  • DSH (DeepSeek Harness)

2. Enable as a DSH plugin

# 1. Clone and build (the repo ships no lib/ output — build first)
git clone https://github.com/zhm20001/dsh-usage-board.git
cd dsh-usage-board
npm install
npm run build

# 2. Register the plugin with a DSH web profile
dsh plugin --profile web add "$(pwd)"

# 3. Start the DSH web host
dsh --profile web --port 3099

Then open http://127.0.0.1:3099 — the usage board is right in the console. The first launch backfills all historical sessions via a cold-start scan; afterwards it follows incrementally.


⚙️ Configuration

Balance query

The dashboard's Balance card reads the official DeepSeek GET /user/balance endpoint:

  1. Option 1: fill in DEEPSEEK_API_KEY under DSH "Settings → Models".
  2. Option 2: write it to ~/.dsh/.credentials.yaml (permissions must be 0600):
    DEEPSEEK_API_KEY: sk-xxxxxxxxxxxxxxxxxxxxxxxx
    

Note: without a key the balance card shows a placeholder; all other local statistics are unaffected. The balance query is the plugin's only outbound request — everything else runs purely locally.

Data & storage paths

KindLocationNotes
Source of truth (Write Model)~/.dsh/sessions/<projectKey>/<sessionId>/session.jsonl.zstdOriginal DSH sessions, read-only
Projection (Read Model)~/.dsh/data/usage.sqliteSQLite index & aggregation DB maintained by the plugin

💡 Safe to rebuild: the projection DB can be deleted and rebuilt at any time (stop the plugin first, then rm ~/.dsh/data/usage.sqlite*). The next launch re-scans all historical sessions via backfill; never delete the Write Model.


🔌 API & Embedded Development (SDK)

HTTP API endpoints

EndpointMethodDescription
/api/usage-dashboard/snapshot?rev=NGETFull dashboard main frame. If rev matches the current version, returns {unchanged: true, revision}
/api/usage-dashboard/snapshot?refresh=1GETForce one outbound refresh of the live DeepSeek balance
/api/usage-dashboard/turnsGETTurns detail list. Params: limit (default 500, max 500), session_id, root_session_id (both may be combined for intersection), format=csv

Endpoints are registered only when ctx.webServer is injected (loopback same-origin only); without it the engine still works fully as a library.

Use as a standalone library

Run npm run build to produce lib/, then depend on this package (or point straight at lib/index.js):

import { createEngine } from 'dsh-usage-board'

// ctx is a structured HostContext — no real Cordis runtime needed
const engine = createEngine(ctx, { dbPath, sessionsRoot })

// Wait for cold-start / incremental backfill to become ready
await engine.ready

// Example query calls
const rollup = engine.query.getRollupBySession(rootSessionId)
const heat = engine.query.getHeatmapData(12)
const fails = engine.query.getTimelineAnomalies(100)
const text = engine.query.loadTurnDetails({ sessionFilePath, turnIndex })

// Dispose in reverse order
await engine.dispose()

🛠️ Local Development

# Build both the Node and client bundles
npm run build

# Watch mode (pairs with the DSH host's client HMR hot swap)
npm run dev

# Run the full test suite (node --test, no external dependencies)
npm test

# Type-check
npm run typecheck

📄 License

This project is open-sourced under the MIT License.