@kenz1117/dsh-ui-usage-billing 0.9.6 → 0.9.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +2 -1
- package/README.md +2 -1
- package/lib/client.js +370 -295
- package/lib/index.js +562 -254
- package/lib/types/aggregate.d.ts +5 -0
- package/lib/types/balance.d.ts +5 -6
- package/lib/types/client/PerfPanel.d.ts +45 -0
- package/lib/types/client/PluginInfoCard.d.ts +12 -0
- package/lib/types/client/TokenPanel.d.ts +24 -0
- package/lib/types/client/UsageBilling.d.ts +107 -1
- package/lib/types/client/heatmap.d.ts +4 -2
- package/lib/types/client/locales.d.ts +1 -1
- package/lib/types/client/plan-knowledge.d.ts +24 -5
- package/lib/types/client/plugin-info.d.ts +20 -0
- package/lib/types/client/usage-billing-settings.d.ts +20 -0
- package/lib/types/index.d.ts +4 -1
- package/lib/types/pricing-shared.d.ts +4 -2
- package/lib/types/resilience.d.ts +49 -0
- package/package.json +1 -1
package/lib/types/aggregate.d.ts
CHANGED
|
@@ -33,7 +33,12 @@ export interface AggregateOptions {
|
|
|
33
33
|
subscriptionProviders?: readonly string[];
|
|
34
34
|
/** 官方渠道 provider id 列表;默认按 {@link isOfficialProvider} 判定(DeepSeek 官方直连)。 */
|
|
35
35
|
officialProviderIds?: readonly string[];
|
|
36
|
+
/** 每会话折叠缓存的上限(默认 {@link DEFAULT_MAX_CACHE_SESSIONS});
|
|
37
|
+
* 超限时按最近使用先后淘汰最久未用的会话,防长期运行内存膨胀。 */
|
|
38
|
+
maxCacheSessions?: number;
|
|
36
39
|
}
|
|
40
|
+
/** 每会话折叠缓存默认上限:超过则按 LRU 淘汰(P1-6 峰值内存治理)。 */
|
|
41
|
+
export declare const DEFAULT_MAX_CACHE_SESSIONS = 400;
|
|
37
42
|
/** One model's aggregated usage plus estimated cost in CNY. */
|
|
38
43
|
export interface ModelUsage {
|
|
39
44
|
calls: number;
|
package/lib/types/balance.d.ts
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
* Account-balance queries for the billing dashboard.
|
|
3
3
|
*
|
|
4
4
|
* Only providers with a public balance endpoint can report one. Today that is
|
|
5
|
-
* DeepSeek
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* for future providers.
|
|
5
|
+
* DeepSeek, Moonshot/Kimi, StepFun, SiliconFlow, and xAI (Grok) — all Bearer
|
|
6
|
+
* 鉴权 with a documented JSON shape; the other mainstream providers expose no
|
|
7
|
+
* standard balance API (or require a non-Bearer auth flow), so their rows in
|
|
8
|
+
* the model table show an unavailable state. The lookup map below is the
|
|
9
|
+
* extension point for future providers.
|
|
11
10
|
*
|
|
12
11
|
* API keys are read from the `llm-pi-ai` settings namespace (`providers.<id>.apiKeyEnv`),
|
|
13
12
|
* the same source the subscription adapter uses, so a deployment configures a
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PerfPanel: per-model latency/perf table + per-hour TTFT/generation-speed curve.
|
|
3
|
+
*
|
|
4
|
+
* Reads the optional `perf` field of the usage-stats document (aggregated by
|
|
5
|
+
* the host from session logs). Renders a per-model table of TTFT mean/P50/P90,
|
|
6
|
+
* generation speed, total latency and estimated-step count, plus a small
|
|
7
|
+
* dependency-free SVG twin-series hourly curve (TTFT in ms on the left axis,
|
|
8
|
+
* tokens/s on the right). Absent `perf` (older snapshot or stream-less logs)
|
|
9
|
+
* renders an empty state; the panel never fabricates samples.
|
|
10
|
+
*/
|
|
11
|
+
import type { TrendSeriesModel } from './TrendChart.tsx';
|
|
12
|
+
import type { UsageBillingKey } from './locales.ts';
|
|
13
|
+
/** 每模型性能统计(与服务端 `ModelPerf` 同形)。 */
|
|
14
|
+
export interface PerfModelData {
|
|
15
|
+
samples: number;
|
|
16
|
+
ttftAvg: number;
|
|
17
|
+
ttftP50: number;
|
|
18
|
+
ttftP90: number;
|
|
19
|
+
tpsAvg?: number;
|
|
20
|
+
latencyAvg: number;
|
|
21
|
+
estimatedSamples: number;
|
|
22
|
+
}
|
|
23
|
+
/** 每小时性能统计(与服务端 `HourPerf` 同形)。 */
|
|
24
|
+
export interface PerfHourData {
|
|
25
|
+
samples: number;
|
|
26
|
+
ttftAvg: number;
|
|
27
|
+
tpsAvg?: number;
|
|
28
|
+
}
|
|
29
|
+
/** 性能指标文档(服务端可选 `perf` 字段;旧快照缺失)。 */
|
|
30
|
+
export interface ClientPerf {
|
|
31
|
+
byModel: Record<string, PerfModelData>;
|
|
32
|
+
byHour: Record<string, PerfHourData>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Render the performance panel.
|
|
36
|
+
* @param props.perf - the optional perf doc; `undefined`/empty renders an empty state.
|
|
37
|
+
* @param props.models - model legend (key/name/color) for the table swatches and curve legend.
|
|
38
|
+
* @param props.t - locale function.
|
|
39
|
+
*/
|
|
40
|
+
export declare function PerfPanel({ perf, models, t, }: {
|
|
41
|
+
perf: ClientPerf | undefined;
|
|
42
|
+
models: readonly TrendSeriesModel[];
|
|
43
|
+
t: (key: UsageBillingKey) => string;
|
|
44
|
+
}): React.ReactNode;
|
|
45
|
+
//# sourceMappingURL=PerfPanel.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PluginInfoCard: 「设置 → 插件信息」卡——展示头像/作者、GitHub 仓库、版本号、
|
|
3
|
+
* 许可证等插件元信息。版本号来自服务端 usage-stats 的 `pluginVersion`(读自
|
|
4
|
+
* 包 package.json),其余元信息静态来自 `plugin-info.ts`。无版本号时显示 em dash。
|
|
5
|
+
*/
|
|
6
|
+
import type { UsageBillingKey } from './locales.ts';
|
|
7
|
+
/** 信息卡 props:locale 函数 + 版本号(服务端下发,可为空)。 */
|
|
8
|
+
export declare function PluginInfoCard({ t, version }: {
|
|
9
|
+
t: (key: UsageBillingKey) => string;
|
|
10
|
+
version: string | undefined;
|
|
11
|
+
}): React.ReactNode;
|
|
12
|
+
//# sourceMappingURL=PluginInfoCard.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TokenPanel: 「Token」分区——把 token 从费用里独立出来洞察。
|
|
3
|
+
* 三个板块 + 导出,全部由 `UsageStats` 的 byDay/byModel/total 派生,服务端零改动:
|
|
4
|
+
* 1. 每日 Token 堆叠趋势(未命中输入 / 缓存命中 / 输出[含 reasoning]),7/30 天切换;
|
|
5
|
+
* 2. 模型 Token 总量排行 + 占比;
|
|
6
|
+
* 3. Token 结构 KPI(缓存命中率 / reasoning 占比 / 输入:输出比 / 峰值日)。
|
|
7
|
+
*/
|
|
8
|
+
import type { UsageBillingKey } from './locales.ts';
|
|
9
|
+
import { type CostCurrency } from './pricing.ts';
|
|
10
|
+
import type { UsageStats } from './UsageBilling.tsx';
|
|
11
|
+
/**
|
|
12
|
+
* Token 洞察面板。
|
|
13
|
+
* @param props.stats - usage-stats 文档(byDay/byModel/total)。
|
|
14
|
+
* @param props.trendDays - 每日 token 窗口(7/30 天)。
|
|
15
|
+
* @param props.onTrendDays - 切换趋势窗口。
|
|
16
|
+
*/
|
|
17
|
+
export declare function TokenPanel(props: {
|
|
18
|
+
stats: UsageStats;
|
|
19
|
+
currency: CostCurrency;
|
|
20
|
+
trendDays: 7 | 30;
|
|
21
|
+
onTrendDays: (d: 7 | 30) => void;
|
|
22
|
+
t: (key: UsageBillingKey) => string;
|
|
23
|
+
}): React.ReactNode;
|
|
24
|
+
//# sourceMappingURL=TokenPanel.d.ts.map
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import type { InjectFace, PropsLocale, PropsRenderSlots, PropsRuntime, PropsStore } from '@deepseek-ai/dsh-client-ui-slots';
|
|
13
13
|
import type { SidebarFooterActionOwnerProps } from '@deepseek-ai/dsh-client-ui-sidebar/client';
|
|
14
|
+
import { type ClientPerf } from './PerfPanel.tsx';
|
|
14
15
|
import type { createBillingBudgetStore } from './budget-store.ts';
|
|
15
16
|
import { type CatalogModel } from './pricing.ts';
|
|
16
17
|
import { NS, type UsageBillingKey } from './locales.ts';
|
|
@@ -32,7 +33,7 @@ export interface ModelHealth {
|
|
|
32
33
|
catalog?: readonly CatalogModel[];
|
|
33
34
|
}
|
|
34
35
|
/** 仪表盘分区 Tab id。 */
|
|
35
|
-
export type DashboardTab = 'overview' | '
|
|
36
|
+
export type DashboardTab = 'overview' | 'token' | 'trends' | 'providers' | 'pricing' | 'settings';
|
|
36
37
|
/**
|
|
37
38
|
* Tab 定义(顺序即渲染顺序):概览=主数字/KPI/热力图,趋势=趋势图/每轮费用,
|
|
38
39
|
* 明细=厂商计费与订阅,统计=工作区/会话明细,费率=模型单价表,设置=预算与峰谷提醒。
|
|
@@ -83,6 +84,16 @@ export declare function peakOffpeakCost(turns: readonly {
|
|
|
83
84
|
peak: number;
|
|
84
85
|
offPeak: number;
|
|
85
86
|
};
|
|
87
|
+
/** 近 7 天费用序列(含今天,缺日补 0):触发卡 hover 速览的迷你柱数据源。
|
|
88
|
+
* 导出供测试:纯函数(日期取本地时区)。 */
|
|
89
|
+
export declare function activeDaysOf(byDay: Record<string, {
|
|
90
|
+
cost: number;
|
|
91
|
+
}>): number;
|
|
92
|
+
/** 连续使用天数:从今天往前连续「有调用记录」的天数;今天无记录则为 0。
|
|
93
|
+
* 导出供测试:纯函数(日期取本地时区)。 */
|
|
94
|
+
export declare function streakDaysOf(byDay: Record<string, {
|
|
95
|
+
cost: number;
|
|
96
|
+
}>, now?: number): number;
|
|
86
97
|
/**
|
|
87
98
|
* 近 7 天费用序列(含今天,缺日补 0):触发卡 hover 速览的迷你柱数据源。
|
|
88
99
|
* 导出供测试:纯函数(日期取本地时区)。
|
|
@@ -95,6 +106,101 @@ export declare function lastSevenDays(byDay: Record<string, {
|
|
|
95
106
|
date: string;
|
|
96
107
|
cost: number;
|
|
97
108
|
}[];
|
|
109
|
+
/** 会话明细行(与服务端 SessionUsageRow 同形;旧快照可能缺失整个 bySession)。 */
|
|
110
|
+
interface SessionBillingRow {
|
|
111
|
+
id: string;
|
|
112
|
+
title?: string;
|
|
113
|
+
cwd?: string;
|
|
114
|
+
calls: number;
|
|
115
|
+
cost: number;
|
|
116
|
+
lastActive: number;
|
|
117
|
+
}
|
|
118
|
+
/** Usage stats structure from `.dsh-usage-stats.json`. */
|
|
119
|
+
export interface UsageStats {
|
|
120
|
+
/** 服务端聚合时间戳(毫秒);旧快照可能缺失。 */
|
|
121
|
+
updatedAt?: number;
|
|
122
|
+
/** 月度预算(人民币元):宿主 Config 注入;未配置时不渲染预算条。 */
|
|
123
|
+
budget?: number;
|
|
124
|
+
/** 余额不足告警阈值(人民币元):宿主 Config 注入;未配置时客户端用默认值。 */
|
|
125
|
+
lowBalanceThreshold?: number;
|
|
126
|
+
/** 会话明细(按费用倒序,服务端已封顶);旧快照可能缺失。 */
|
|
127
|
+
bySession?: readonly SessionBillingRow[];
|
|
128
|
+
total: {
|
|
129
|
+
calls: number;
|
|
130
|
+
input: number;
|
|
131
|
+
output: number;
|
|
132
|
+
cacheHit: number;
|
|
133
|
+
cacheMiss: number;
|
|
134
|
+
cost: number;
|
|
135
|
+
/** 输出中的 reasoning(思考)token;已含在 output 内。 */
|
|
136
|
+
reasoning: number;
|
|
137
|
+
};
|
|
138
|
+
byModel: Record<string, {
|
|
139
|
+
calls: number;
|
|
140
|
+
input: number;
|
|
141
|
+
output: number;
|
|
142
|
+
cacheHit: number;
|
|
143
|
+
cacheMiss: number;
|
|
144
|
+
cost: number;
|
|
145
|
+
reasoning: number;
|
|
146
|
+
/** Billed through a subscription plan (no per-token cost). */
|
|
147
|
+
plan?: boolean;
|
|
148
|
+
/** 走官方 DeepSeek 直连的调用数(其余为第三方);旧快照可能缺失。 */
|
|
149
|
+
officialCalls?: number;
|
|
150
|
+
/** 走官方渠道的费用(CNY);旧快照可能缺失。 */
|
|
151
|
+
officialCost?: number;
|
|
152
|
+
}>;
|
|
153
|
+
byDay: Record<string, {
|
|
154
|
+
calls: number;
|
|
155
|
+
input: number;
|
|
156
|
+
output: number;
|
|
157
|
+
cacheHit: number;
|
|
158
|
+
cacheMiss: number;
|
|
159
|
+
cost: number;
|
|
160
|
+
reasoning: number;
|
|
161
|
+
}>;
|
|
162
|
+
/** 模型 × 日期 二维统计(趋势图堆叠柱的输入);旧快照可能缺失,渲染时降级为单色柱。 */
|
|
163
|
+
byDayModels?: Record<string, Record<string, {
|
|
164
|
+
calls: number;
|
|
165
|
+
input: number;
|
|
166
|
+
output: number;
|
|
167
|
+
cacheHit: number;
|
|
168
|
+
cacheMiss: number;
|
|
169
|
+
cost: number;
|
|
170
|
+
}>>;
|
|
171
|
+
/** 每轮费用明细(服务端聚合路径恒带);旧快照可能缺失。 */
|
|
172
|
+
byTurn?: readonly {
|
|
173
|
+
sessionId: string;
|
|
174
|
+
turn: number;
|
|
175
|
+
model: string;
|
|
176
|
+
input: number;
|
|
177
|
+
output: number;
|
|
178
|
+
cacheHit: number;
|
|
179
|
+
cacheMiss: number;
|
|
180
|
+
cost: number;
|
|
181
|
+
startedAt: number;
|
|
182
|
+
endedAt?: number;
|
|
183
|
+
}[];
|
|
184
|
+
/** 工作区聚合(按 cwd 末级目录);旧快照可能缺失。 */
|
|
185
|
+
byWorkspace?: readonly {
|
|
186
|
+
name: string;
|
|
187
|
+
calls: number;
|
|
188
|
+
cost: number;
|
|
189
|
+
input: number;
|
|
190
|
+
output: number;
|
|
191
|
+
lastActive: number;
|
|
192
|
+
}[];
|
|
193
|
+
/** 按角色费用归因(估算口径:输出实测,输入按消息长度摊分);旧快照可能缺失。 */
|
|
194
|
+
byRole?: {
|
|
195
|
+
user: number;
|
|
196
|
+
assistant: number;
|
|
197
|
+
tool: number;
|
|
198
|
+
};
|
|
199
|
+
/** 性能指标(TTFT/生成速度/总延迟)按模型与按小时;旧快照可能缺失。 */
|
|
200
|
+
perf?: ClientPerf;
|
|
201
|
+
/** 插件版本号(服务端读自包 package.json;旧快照缺失)。 */
|
|
202
|
+
pluginVersion?: string;
|
|
203
|
+
}
|
|
98
204
|
/** 组件注入面:探活 + 计费指标写入(billing 自身写入,主题插件经服务读取)。 */
|
|
99
205
|
export interface UsageBillingInjected {
|
|
100
206
|
checkModels: () => Promise<ModelHealth>;
|
|
@@ -20,16 +20,18 @@ export interface HeatmapDay {
|
|
|
20
20
|
value: number;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
* Render the month heatmap.
|
|
23
|
+
* Render the month or year heatmap.
|
|
24
24
|
* @param props.days - daily cost rows (keys are `YYYY-MM-DD`).
|
|
25
25
|
* @param props.currency - display currency for the hover amount.
|
|
26
26
|
* @param props.now - anchor date (defaults to today); injectable for tests.
|
|
27
27
|
* @param props.t - locale function (used for the legend labels).
|
|
28
|
+
* @param props.range - `month` (calendar month) or `year` (last 52 weeks, GitHub style).
|
|
28
29
|
*/
|
|
29
|
-
export declare function UsageHeatmap({ days, currency, now, t }: {
|
|
30
|
+
export declare function UsageHeatmap({ days, currency, now, t, range }: {
|
|
30
31
|
days: readonly HeatmapDay[];
|
|
31
32
|
currency: CostCurrency;
|
|
32
33
|
now?: Date;
|
|
34
|
+
range?: 'month' | 'year';
|
|
33
35
|
t: (key: 'billing.costAbbr' | 'billing.noData' | 'billing.heatmapLess' | 'billing.heatmapMore') => string;
|
|
34
36
|
}): React.ReactNode;
|
|
35
37
|
//# sourceMappingURL=heatmap.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Locale dictionaries for the usage billing surface. */
|
|
2
|
-
export type UsageBillingKey = 'billing.title' | 'billing.subtitle' | 'billing.cost' | 'billing.todayCost' | 'billing.monthCost' | 'billing.yearCost' | 'billing.monthProjected' | 'billing.liveTurn' | 'billing.liveSession' | 'billing.totalCost' | 'billing.calls' | 'billing.cacheHitRate' | 'billing.tokens' | 'billing.inputTokens' | 'billing.outputTokens' | 'billing.avgCost' | 'billing.trend' | 'billing.trend7d' | 'billing.trend30d' | 'billing.trendEmpty' | 'billing.budget' | 'billing.sessions' | 'billing.project' | 'billing.lastActive' | 'billing.sessionOverflow' | 'billing.budgetTierBody' | 'billing.models' | 'billing.providerBilling' | 'billing.estimated' | 'billing.actual' | 'billing.pricing' | 'billing.showPricing' | 'billing.hidePricing' | 'billing.pricePerM' | 'billing.input' | 'billing.output' | 'billing.cacheHit' | 'billing.peak' | 'billing.offPeak' | 'billing.flat' | 'billing.peakHours' | 'billing.band' | 'billing.openDashboard' | 'billing.close' | 'billing.lastUpdated' | 'billing.noData' | 'billing.todayRate' | 'billing.rateLive' | 'billing.rateBuiltin' | 'billing.pricingTip' | 'billing.balance' | 'billing.balanceUnconfigured' | 'billing.balanceUnauthorized' | 'billing.balanceUnreachable' | 'billing.uncatalogued' | 'billing.estimatedPricing' | 'billing.balanceDays' | 'billing.balanceLowBody' | 'billing.subscriptions' | 'billing.subscriptionNotConfigured' | 'billing.subscriptionUnauthorized' | 'billing.subscriptionUnavailable' | 'billing.subscriptionInvalid' | 'billing.subscriptionRateLimited' | 'billing.subscriptionSession' | 'billing.subscriptionWeekly' | 'billing.subscriptionMonthly' | 'billing.subscriptionBilling' | 'billing.subscriptionRemaining' | 'billing.subscriptionExhausted' | 'billing.subscriptionReset' | 'billing.subscriptionNoApi' | 'billing.heatmapLess' | 'billing.heatmapMore' | 'billing.currency' | 'billing.currencyCny' | 'billing.currencyUsd' | 'billing.heatmap' | 'billing.rounds' | 'billing.anomaly' | 'billing.workspaces' | 'billing.plan' | 'billing.remaining' | 'billing.unknownModel' | 'billing.model' | 'billing.currentRound' | 'billing.costAbbr' | 'billing.tabOverview' | 'billing.tabTrends' | 'billing.tabProviders' | 'billing.tabDetails' | 'billing.tabPricing' | 'billing.tabSettings' | 'billing.settingsHead' | 'billing.settingsHint' | 'billing.budgetHint' | 'billing.peakAlertHint' | 'billing.peakAlertDescPeak' | 'billing.peakAlertDescOff' | 'billing.export' | 'billing.exportCsvDay' | 'billing.exportCsvSession' | 'billing.exportJson' | 'billing.peakShare' | 'billing.peakShareHint' | 'billing.weekCost' | 'billing.roleCost' | 'billing.roleUser' | 'billing.roleAssistant' | 'billing.roleTool' | 'billing.roleHint' | 'billing.tierPeak' | 'billing.tierOff' | 'billing.tierToPeak' | 'billing.tierToOff' | 'billing.tierAlertEnterPeak' | 'billing.tierAlertEnterOff' | 'billing.peakAlertTitlePeak' | 'billing.peakAlertTitleOff' | 'billing.peakAlert' | 'billing.peakAlertLeadMin' | 'billing.peakAlertPosCorner' | 'billing.peakAlertPosCenter' | 'billing.peakAlertModePeak' | 'billing.peakAlertModeOff' | 'billing.peakAlertModeBoth' | 'billing.peakAlertWebNotify' | 'billing.peakAlertPreview' | 'billing.planTypeCode' | 'billing.planTypeToken' | 'billing.subscriptionFeePerMonth' | 'billing.triggerToday' | 'billing.triggerMonth' | 'billing.subscriptionIncluded' | 'billing.free' | 'billing.official' | 'billing.thirdParty' | 'billing.officialCost' | 'billing.thirdPartyCost';
|
|
2
|
+
export type UsageBillingKey = 'billing.title' | 'billing.subtitle' | 'billing.cost' | 'billing.todayCost' | 'billing.monthCost' | 'billing.yearCost' | 'billing.monthProjected' | 'billing.liveTurn' | 'billing.liveSession' | 'billing.totalCost' | 'billing.calls' | 'billing.cacheHitRate' | 'billing.tokens' | 'billing.inputTokens' | 'billing.outputTokens' | 'billing.avgCost' | 'billing.trend' | 'billing.trend7d' | 'billing.trend30d' | 'billing.trendEmpty' | 'billing.budget' | 'billing.sessions' | 'billing.project' | 'billing.lastActive' | 'billing.sessionOverflow' | 'billing.budgetTierBody' | 'billing.models' | 'billing.providerBilling' | 'billing.estimated' | 'billing.actual' | 'billing.pricing' | 'billing.showPricing' | 'billing.hidePricing' | 'billing.pricePerM' | 'billing.input' | 'billing.output' | 'billing.cacheHit' | 'billing.peak' | 'billing.offPeak' | 'billing.flat' | 'billing.peakHours' | 'billing.band' | 'billing.openDashboard' | 'billing.close' | 'billing.lastUpdated' | 'billing.noData' | 'billing.todayRate' | 'billing.rateLive' | 'billing.rateBuiltin' | 'billing.pricingTip' | 'billing.balance' | 'billing.balanceUnconfigured' | 'billing.balanceUnauthorized' | 'billing.balanceUnreachable' | 'billing.uncatalogued' | 'billing.estimatedPricing' | 'billing.balanceDays' | 'billing.balanceLowBody' | 'billing.subscriptions' | 'billing.subscriptionNotConfigured' | 'billing.subscriptionUnauthorized' | 'billing.subscriptionUnavailable' | 'billing.subscriptionInvalid' | 'billing.subscriptionRateLimited' | 'billing.subscriptionSession' | 'billing.subscriptionWeekly' | 'billing.subscriptionMonthly' | 'billing.subscriptionBilling' | 'billing.subscriptionRemaining' | 'billing.subscriptionExhausted' | 'billing.subscriptionReset' | 'billing.subscriptionNoApi' | 'billing.heatmapLess' | 'billing.heatmapMore' | 'billing.currency' | 'billing.currencyCny' | 'billing.currencyUsd' | 'billing.heatmap' | 'billing.rounds' | 'billing.anomaly' | 'billing.workspaces' | 'billing.plan' | 'billing.remaining' | 'billing.unknownModel' | 'billing.model' | 'billing.currentRound' | 'billing.costAbbr' | 'billing.tabOverview' | 'billing.tabTrends' | 'billing.tabProviders' | 'billing.tabDetails' | 'billing.tabPricing' | 'billing.tabSettings' | 'billing.settingsHead' | 'billing.settingsHint' | 'billing.budgetHint' | 'billing.peakAlertHint' | 'billing.peakAlertDescPeak' | 'billing.peakAlertDescOff' | 'billing.export' | 'billing.exportCsvDay' | 'billing.exportCsvSession' | 'billing.exportJson' | 'billing.peakShare' | 'billing.peakShareHint' | 'billing.weekCost' | 'billing.roleCost' | 'billing.roleUser' | 'billing.roleAssistant' | 'billing.roleTool' | 'billing.roleHint' | 'billing.tierPeak' | 'billing.tierOff' | 'billing.tierToPeak' | 'billing.tierToOff' | 'billing.tierAlertEnterPeak' | 'billing.tierAlertEnterOff' | 'billing.peakAlertTitlePeak' | 'billing.peakAlertTitleOff' | 'billing.peakAlert' | 'billing.peakAlertLeadMin' | 'billing.peakAlertPosCorner' | 'billing.peakAlertPosCenter' | 'billing.peakAlertModePeak' | 'billing.peakAlertModeOff' | 'billing.peakAlertModeBoth' | 'billing.peakAlertWebNotify' | 'billing.peakAlertPreview' | 'billing.planTypeCode' | 'billing.planTypeToken' | 'billing.subscriptionFeePerMonth' | 'billing.triggerToday' | 'billing.triggerMonth' | 'billing.subscriptionIncluded' | 'billing.free' | 'billing.official' | 'billing.thirdParty' | 'billing.officialCost' | 'billing.thirdPartyCost' | 'billing.perfSamples' | 'billing.perfTtft' | 'billing.perfP50' | 'billing.perfP90' | 'billing.perfTps' | 'billing.perfLatency' | 'billing.perfEstimated' | 'billing.perfEmpty' | 'billing.perfTpsUnit' | 'billing.perfTitle' | 'billing.perfHint' | 'billing.heatmapYear' | 'billing.heatmapMonth' | 'billing.activeDays' | 'billing.streakDays' | 'billing.subscriptionAutoDetect' | 'billing.pluginInfo' | 'billing.pluginName' | 'billing.pluginDescription' | 'billing.pluginVersion' | 'billing.pluginAuthor' | 'billing.pluginRepository' | 'billing.pluginNpm' | 'billing.pluginLicense' | 'billing.tabToken' | 'billing.tokenExport' | 'billing.tokenExportCsv' | 'billing.tokenCacheHitRate' | 'billing.tokenReasoningShare' | 'billing.tokenReasoningShort' | 'billing.tokenIo' | 'billing.tokenPeak' | 'billing.tokenDaily' | 'billing.tokenByModel' | 'billing.tokenMiss' | 'billing.tokenHit' | 'billing.tokenOutput' | 'billing.tokenTotal' | 'billing.tokenShare' | 'billing.usageStatsTool' | 'billing.usageStatsToolHint';
|
|
3
3
|
export declare const NS = "usageBilling";
|
|
4
4
|
export declare const zh: Record<UsageBillingKey, string>;
|
|
5
5
|
export declare const en: Record<UsageBillingKey, string>;
|
|
@@ -33,11 +33,17 @@ export interface PlanTier {
|
|
|
33
33
|
/** 额度口径的人话描述(官方未公布精确额度时)。 */
|
|
34
34
|
label?: string;
|
|
35
35
|
}
|
|
36
|
-
/**
|
|
36
|
+
/** 原生币订阅月费(金额 + 币种 + 计费周期)。 */
|
|
37
|
+
export interface SubscriptionMount {
|
|
38
|
+
amount: number;
|
|
39
|
+
currency: 'CNY' | 'USD';
|
|
40
|
+
period: 'month' | 'week' | 'day';
|
|
41
|
+
}
|
|
42
|
+
/** One plan row: provider id (after plan alias) → plan shape + optional subscription fee. */
|
|
37
43
|
export interface PlanKnowledgeEntry {
|
|
38
44
|
type: PlanType;
|
|
39
|
-
/**
|
|
40
|
-
|
|
45
|
+
/** 原生币订阅月费(如 $10/月);code 计划用,折算后计入「本月预计」。 */
|
|
46
|
+
subscription?: SubscriptionMount;
|
|
41
47
|
/** 自动识别的档位月费与周期额度口径(订阅卡片展示)。 */
|
|
42
48
|
tier?: PlanTier;
|
|
43
49
|
}
|
|
@@ -46,10 +52,23 @@ export interface PlanKnowledgeEntry {
|
|
|
46
52
|
* 覆盖我们实际会识别到的订阅通道;其余按量 API 不计入此表(默认 token)。
|
|
47
53
|
*/
|
|
48
54
|
export declare const PLAN_KNOWLEDGE: Readonly<Record<string, PlanKnowledgeEntry>>;
|
|
55
|
+
/**
|
|
56
|
+
* 订阅/plan provider id 变体 → PLAN_KNOWLEDGE 规范键(引用 dsh-spend 的别名归一化)。
|
|
57
|
+
* 部署配置的订阅 provider id 写法不一(glm/zhipu/bigmodel、ark/volcengine、
|
|
58
|
+
* kimi/moonshot、xiaomi…),先归一化再匹配,提升"自动识别"覆盖率。
|
|
59
|
+
* 注意:裸 qwen/dashscope/tongyi 等是按量 API(token 计费)而非订阅,不归一到
|
|
60
|
+
* 订阅键——只有显式 token-plan 后缀才由 SUBSCRIPTION_ID_RE 判定为订阅。
|
|
61
|
+
*/
|
|
62
|
+
export declare const PLAN_PROVIDER_ALIASES: Readonly<Record<string, string>>;
|
|
63
|
+
/** 归一化订阅 provider id:别名命中则映射到规范键,否则原样返回。 */
|
|
64
|
+
export declare function normalizePlanProvider(providerId: string): string;
|
|
49
65
|
/** provider id(llm-pi-ai 设置键)→ plan 知识;未命中默认 token。 */
|
|
50
66
|
export declare function planTypeOf(providerId: string): PlanType;
|
|
51
|
-
/**
|
|
52
|
-
|
|
67
|
+
/**
|
|
68
|
+
* 订阅月费折算为人民币:原生币 × 实时汇率(USD→CNY)。汇率缺失时返回 0,
|
|
69
|
+
* 避免用假设汇率造成失真(跨币种保护:金额统一折成 CNY 再相加)。
|
|
70
|
+
*/
|
|
71
|
+
export declare function subscriptionFeeCnyOf(providerId: string, rate: number | undefined): number;
|
|
53
72
|
/** 自动识别的档位月费与周期额度口径(订阅卡片展示);无档位知识返回 undefined。 */
|
|
54
73
|
export declare function tierInfoOf(providerId: string): PlanTier | undefined;
|
|
55
74
|
export interface FallbackRate {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 插件元信息(「设置 → 插件信息卡」展示):名称 / 描述 / 作者 / 仓库 / 许可证。
|
|
3
|
+
* 版本号不含在此——由服务端从自身 package.json 读取(pluginVersion),
|
|
4
|
+
* 这样发布版版本与源码单一来源,不会两处不同步。
|
|
5
|
+
*/
|
|
6
|
+
/** npm 包名。 */
|
|
7
|
+
export declare const PLUGIN_NAME = "@kenz1117/dsh-ui-usage-billing";
|
|
8
|
+
/** 一句话描述。 */
|
|
9
|
+
export declare const PLUGIN_DESCRIPTION = "Usage billing dashboard for DeepSeek Harness";
|
|
10
|
+
/** 作者显示名。 */
|
|
11
|
+
export declare const PLUGIN_AUTHOR_NAME = "KenZ";
|
|
12
|
+
/** 作者 GitHub 账号(仓库/作者页链接)。 */
|
|
13
|
+
export declare const PLUGIN_AUTHOR_HANDLE = "kenz1117";
|
|
14
|
+
/** 源码仓库(可点击)。 */
|
|
15
|
+
export declare const PLUGIN_REPOSITORY = "https://github.com/kenz1117/dsh-ui-usage-billing";
|
|
16
|
+
/** npm 包主页(可点击)。 */
|
|
17
|
+
export declare const PLUGIN_NPM_URL = "https://www.npmjs.com/package/@kenz1117/dsh-ui-usage-billing";
|
|
18
|
+
/** 许可证。 */
|
|
19
|
+
export declare const PLUGIN_LICENSE = "MIT";
|
|
20
|
+
//# sourceMappingURL=plugin-info.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* usage-stats 工具开关的共享设置契约(node 与 client 两端共用)。
|
|
3
|
+
*
|
|
4
|
+
* 宿主把已注册的设置命名空间服务给浏览器;node 半区在 apply 阶段读一次该值决定
|
|
5
|
+
* 是否向模型注入 `usage_stats` 工具(工具注入是启动期决策,改开关后重载应用生效),
|
|
6
|
+
* client 半区在「设置」Tab 渲染开关并写入同一命名空间。缺省的默认行为是关闭——
|
|
7
|
+
* 避免该工具默认占用模型每次请求的上下文(coding 场景通常在仪表盘看用量)。
|
|
8
|
+
*/
|
|
9
|
+
/** 设置命名空间 id(小写 kebab-case)。 */
|
|
10
|
+
export declare const BILLING_SETTINGS_NAMESPACE = "ui-usage-billing";
|
|
11
|
+
/** 该命名空间下用户可编辑的字段名。 */
|
|
12
|
+
export declare const ENABLE_USAGE_STATS_TOOL_FIELD = "enableUsageStatsTool";
|
|
13
|
+
/** 该命名空间下用户可编辑的子集。 */
|
|
14
|
+
export interface UsageBillingSettings {
|
|
15
|
+
/** 是否向模型注入 `usage_stats` 动态工具(默认 false:不注入)。 */
|
|
16
|
+
enableUsageStatsTool: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** 默认值:工具不注入(贴合 issue 诉求)。 */
|
|
19
|
+
export declare const DEFAULT_ENABLE_USAGE_STATS_TOOL = false;
|
|
20
|
+
//# sourceMappingURL=usage-billing-settings.d.ts.map
|
package/lib/types/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import type { Context } from '@deepseek-ai/cordis';
|
|
13
13
|
import type { CredentialProvider } from '@deepseek-ai/dsh-credentials';
|
|
14
|
-
import type
|
|
14
|
+
import { type SettingsProvider } from '@deepseek-ai/dsh-settings';
|
|
15
15
|
import type { CustomBalanceConfig, SubscriptionPlanConfig } from './pricing-shared.ts';
|
|
16
16
|
import { type IdentifiedSubscriptionPlan, type SubscriptionKeys } from './subscriptions.ts';
|
|
17
17
|
/** Plugin configuration. */
|
|
@@ -31,6 +31,9 @@ export interface UsageBillingConfig {
|
|
|
31
31
|
lowBalanceThreshold?: number;
|
|
32
32
|
/** 自定义 Provider 余额查询(任意 HTTP 端点 + extract 规则,适配 NewApi/LiteLLM 等)。 */
|
|
33
33
|
customBalances?: readonly CustomBalanceConfig[];
|
|
34
|
+
/** `usage_stats` 工具注入的组合 base(默认 false:不注入);与设置命名空间同字段,
|
|
35
|
+
* 作为用户设置(设置 Tab 开关)的组合兜底。该工具占用每次请求的上下文,coding 场景多在仪表盘查看。 */
|
|
36
|
+
enableUsageStatsTool?: boolean;
|
|
34
37
|
}
|
|
35
38
|
/** Required services: the web server, the persisted session log store, and user settings. */
|
|
36
39
|
export declare const inject: string[];
|
|
@@ -38,8 +38,10 @@ export interface ExtraModelPrice {
|
|
|
38
38
|
provider: string;
|
|
39
39
|
price: LivePrice;
|
|
40
40
|
}
|
|
41
|
-
/** 余额查询失败的原因,前端据此显示文案。
|
|
42
|
-
|
|
41
|
+
/** 余额查询失败的原因,前端据此显示文案。
|
|
42
|
+
* `invalid` 表示上游返回 2xx 但响应结构偏离预期(接口改版/漂移),
|
|
43
|
+
* 与"网络不可达"(unreachable)区分,便于定位是上游变更还是网络问题。 */
|
|
44
|
+
export type BalanceError = 'unconfigured' | 'unauthorized' | 'unreachable' | 'invalid';
|
|
43
45
|
/** 一个提供方的账户余额(`/api/billing/balance` 的一行)。 */
|
|
44
46
|
export interface ProviderBalance {
|
|
45
47
|
/** 提供方 id(小写,如 `deepseek`),与模型表 provider 匹配用。 */
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 上游网络请求的稳定性工具:有限重试(指数退避)与每平台熔断冷却门。
|
|
3
|
+
*
|
|
4
|
+
* 计费插件对三类上游做实时请求——pricing(汇率 / OpenRouter / models.dev)、
|
|
5
|
+
* balance(各厂商余额)、subscriptions(各订阅额度)。单次失败会被调用方降级,
|
|
6
|
+
* 但反复的瞬时失败(网络波动 / 5xx / 429)会让 30 秒轮询每次打满超时。这里提供
|
|
7
|
+
* 两个纯工具:`withRetry` 对可重试错误做指数退避,`createCooldownGate` 在单一
|
|
8
|
+
* 上游连续失败后短路一段时间,避免把请求打到已不可用的服务上。
|
|
9
|
+
*/
|
|
10
|
+
/** 是否是可重试的错误:网络性失败(TypeError / Abort / Timeout)或 5xx / 429。
|
|
11
|
+
* 401 / 403 鉴权失败与 404 不可重试——重试只放大错误、不会变好。 */
|
|
12
|
+
export declare function isRetryableError(error: unknown): boolean;
|
|
13
|
+
/** 重试配置。 */
|
|
14
|
+
export interface RetryOptions {
|
|
15
|
+
/** 除首次尝试外的额外重试次数(默认 1)。 */
|
|
16
|
+
retries?: number;
|
|
17
|
+
/** 首次退避基数(默认 250ms)。 */
|
|
18
|
+
baseDelayMs?: number;
|
|
19
|
+
/** 退避上限(默认 2000ms)。 */
|
|
20
|
+
maxDelayMs?: number;
|
|
21
|
+
/** 何时重试;默认 {@link isRetryableError}。 */
|
|
22
|
+
shouldRetry?: (error: unknown) => boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 对一次上游请求做有限重试:可重试错误时按指数退避(+同量级抖动)重试。
|
|
26
|
+
* @param fn - 发起请求的异步函数。
|
|
27
|
+
* @param options - 重试策略(见 {@link RetryOptions})。
|
|
28
|
+
* @returns fn 的结果;重试耗尽后抛出最后一次错误。
|
|
29
|
+
*/
|
|
30
|
+
export declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
31
|
+
/** 熔断冷却门配置。 */
|
|
32
|
+
export interface CooldownGateOptions {
|
|
33
|
+
/** 连续失败达到该次数进入冷却(默认 3)。 */
|
|
34
|
+
failures?: number;
|
|
35
|
+
/** 冷却时长(默认 30 秒)。 */
|
|
36
|
+
cooldownMs?: number;
|
|
37
|
+
}
|
|
38
|
+
/** 每平台熔断门:check 是否允许请求;fail / success 上报结果。 */
|
|
39
|
+
export interface CooldownGate {
|
|
40
|
+
/** 该平台是否允许发起请求。false 表示处于冷却中,调用方应短路为不可用。 */
|
|
41
|
+
check(key: string): boolean;
|
|
42
|
+
/** 上报一次失败(可能进入冷却)。 */
|
|
43
|
+
fail(key: string): void;
|
|
44
|
+
/** 上报一次成功(重置失败计数与冷却)。 */
|
|
45
|
+
success(key: string): void;
|
|
46
|
+
}
|
|
47
|
+
/** 每平台冷熔断:连续失败达阈值后短路一段真实时间,成功后复位。 */
|
|
48
|
+
export declare function createCooldownGate(options?: CooldownGateOptions): CooldownGate;
|
|
49
|
+
//# sourceMappingURL=resilience.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kenz1117/dsh-ui-usage-billing",
|
|
3
3
|
"description": "Usage billing dashboard for DeepSeek Harness: sidebar cost metrics plus a full dashboard modal, priced from a current multi-provider catalog with real usage aggregated from session logs.",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.7",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|