dsh-key-usage 0.1.2 → 0.1.4

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.
@@ -0,0 +1,349 @@
1
+ /** 抓取日期:更新价目时统一改这里,避免每条手写导致漂移。 */
2
+ const FETCHED_AT = '2026-10-13';
3
+ /* ------------------------------------------------------------------ *
4
+ * DeepSeek 官方(CNY / 百万 tokens)
5
+ * 来源:https://api-docs.deepseek.com/zh-cn/quick_start/pricing (英文页同价、不同币种)
6
+ * 取**中文文档的 CNY 价**,不做汇率换算。
7
+ *
8
+ * 错峰换算依据:官方原文「空闲时段价格为高峰时段价格的一半。北京时间周一至周五
9
+ * (不含中国法定节假日)9:00–12:00、14:00–18:00 为高峰时段;其余时段,包括周末及
10
+ * 中国法定节假日全天均为空闲时段」。窗口按**本地时间**判定,且高峰只在周一至周五,
11
+ * 因此每个窗口都带 `days`(1=周一 … 7=周日):工作日三段 + 周末全天一段。
12
+ * 注意:规则模型表达不了「中国法定节假日」,节假日会被算成高峰价,这是已知近似,
13
+ * 与换算依据一并写进 offPeak 的 note。
14
+ * ------------------------------------------------------------------ */
15
+ const DEEPSEEK_SOURCE = 'https://api-docs.deepseek.com/zh-cn/quick_start/pricing';
16
+ const DEEPSEEK_OFFPEAK_NOTE = '错峰 = 高峰半价。高峰为北京时间周一至周五(不含中国法定节假日)9:00–12:00 与 14:00–18:00,'
17
+ + '其余时段(含周末全天)均为空闲时段;窗口按本地时间判定,工作日三段与周末全天各用一条窗口表达。'
18
+ + '限制:插件没有中国法定节假日日历,节假日会按高峰价算 —— 这是已知近似(方向:把空闲当高峰,金额偏高)。';
19
+ const deepseekOffPeakWindows = [
20
+ { from: '00:00', to: '09:00', days: [1, 2, 3, 4, 5] },
21
+ { from: '12:00', to: '14:00', days: [1, 2, 3, 4, 5] },
22
+ { from: '18:00', to: '00:00', days: [1, 2, 3, 4, 5] },
23
+ { from: '00:00', to: '00:00', days: [6, 7] },
24
+ ];
25
+ const DEEPSEEK_ENTRIES = [
26
+ {
27
+ provider: 'deepseek-official',
28
+ model: 'deepseek-flash',
29
+ unit: 'perMillionTokens',
30
+ currency: 'CNY',
31
+ // 官方表未单列「缓存写入」:DeepSeek 缓存写按未命中价计(命中价另有专档),此处沿用未命中价
32
+ input: 2, cacheRead: 0.04, cacheWrite: 2, output: 8,
33
+ offPeak: { windows: deepseekOffPeakWindows, input: 1, cacheRead: 0.02, cacheWrite: 1, output: 4 },
34
+ source: DEEPSEEK_SOURCE,
35
+ fetchedAt: FETCHED_AT,
36
+ note: 'deepseek-flash(模型版本 DeepSeek-V4.1-Flash)高峰价:未命中 ¥2.00 / 命中 ¥0.04 / 输出 ¥8.00;'
37
+ + '缓存写入档文档未单列,沿用未命中价(口径推断,见 docs/05 附录 A.5)。' + DEEPSEEK_OFFPEAK_NOTE,
38
+ },
39
+ {
40
+ // 官方标注:deepseek-v4-flash 与 deepseek-v4-flash-vision-exp 为旧名,请求按 Flash 价计费
41
+ provider: 'deepseek-official',
42
+ model: 'deepseek-v4-flash',
43
+ unit: 'perMillionTokens',
44
+ currency: 'CNY',
45
+ input: 2, cacheRead: 0.04, cacheWrite: 2, output: 8,
46
+ offPeak: { windows: deepseekOffPeakWindows, input: 1, cacheRead: 0.02, cacheWrite: 1, output: 4 },
47
+ source: DEEPSEEK_SOURCE,
48
+ fetchedAt: FETCHED_AT,
49
+ note: '旧模型名:官方注明请求由 DeepSeek-V4.1-Flash 提供服务并按 Flash 价计费,故与 deepseek-flash 同价。'
50
+ + DEEPSEEK_OFFPEAK_NOTE,
51
+ },
52
+ {
53
+ provider: 'deepseek-official',
54
+ model: 'deepseek-v4-flash-vision-exp',
55
+ unit: 'perMillionTokens',
56
+ currency: 'CNY',
57
+ input: 2, cacheRead: 0.04, cacheWrite: 2, output: 8,
58
+ offPeak: { windows: deepseekOffPeakWindows, input: 1, cacheRead: 0.02, cacheWrite: 1, output: 4 },
59
+ source: DEEPSEEK_SOURCE,
60
+ fetchedAt: FETCHED_AT,
61
+ note: '旧模型名(同 deepseek-v4-flash 的计费说明):按 Flash 价计费。' + DEEPSEEK_OFFPEAK_NOTE,
62
+ },
63
+ {
64
+ provider: 'deepseek-official',
65
+ model: 'deepseek-v4-pro',
66
+ unit: 'perMillionTokens',
67
+ currency: 'CNY',
68
+ input: 9, cacheRead: 0.3, cacheWrite: 9, output: 27,
69
+ offPeak: { windows: deepseekOffPeakWindows, input: 4.5, cacheRead: 0.15, cacheWrite: 4.5, output: 13.5 },
70
+ source: DEEPSEEK_SOURCE,
71
+ fetchedAt: FETCHED_AT,
72
+ note: 'deepseek-v4-pro(DeepSeek-V4-Pro-0813)高峰价:未命中 ¥9.00 / 命中 ¥0.30 / 输出 ¥27.00;'
73
+ + '缓存写入档文档未单列,沿用未命中价。' + DEEPSEEK_OFFPEAK_NOTE,
74
+ },
75
+ ];
76
+ /* ------------------------------------------------------------------ *
77
+ * Moonshot / Kimi(CNY / 百万 tokens)
78
+ * 来源:https://platform.kimi.com/docs/pricing/chat
79
+ * 官方口径:K3 缓存写入按 TTL 分 5min / 1h 两档单独计费,未指定 TTL 默认 5min;
80
+ * 本插件只有一个「缓存写入」档,因此取**默认 5min 档**,1h 档价差写进 note。
81
+ * K2 系列官方表**没有**缓存写入列,故 cacheWrite 留空。
82
+ * ------------------------------------------------------------------ */
83
+ const KIMI_SOURCE = 'https://platform.kimi.com/docs/pricing/chat';
84
+ const KIMI_TTL_NOTE = '官方缓存写入分 TTL 5min(本插件取此档,为默认档)/ 1h(¥40.00)两档。';
85
+ const KIMI_ENTRIES = [
86
+ {
87
+ provider: 'moonshotai',
88
+ model: 'kimi-k3',
89
+ unit: 'perMillionTokens',
90
+ currency: 'CNY',
91
+ input: 20, cacheRead: 2, cacheWrite: 20, output: 100,
92
+ source: KIMI_SOURCE,
93
+ fetchedAt: FETCHED_AT,
94
+ note: 'K3 系列(1M tokens 计价,上下文窗口 1,048,576):未命中 ¥20.00 / 命中 ¥2.00 / 输出 ¥100.00。' + KIMI_TTL_NOTE,
95
+ },
96
+ {
97
+ provider: 'moonshotai',
98
+ model: 'kimi-k2.7-code',
99
+ unit: 'perMillionTokens',
100
+ currency: 'CNY',
101
+ input: 6.5, cacheRead: 1.3, output: 27,
102
+ source: KIMI_SOURCE,
103
+ fetchedAt: FETCHED_AT,
104
+ note: 'K2.7 Code(上下文窗口 262,144):未命中 ¥6.50 / 命中 ¥1.30 / 输出 ¥27.00。'
105
+ + '官方 K2 系列价格表没有「缓存写入」列,该档留空(不按输入价顶替)。',
106
+ },
107
+ {
108
+ provider: 'moonshotai',
109
+ model: 'kimi-k2.7-code-highspeed',
110
+ unit: 'perMillionTokens',
111
+ currency: 'CNY',
112
+ input: 13, cacheRead: 2.6, output: 54,
113
+ source: KIMI_SOURCE,
114
+ fetchedAt: FETCHED_AT,
115
+ note: 'K2.7 Code Highspeed:未命中 ¥13.00 / 命中 ¥2.60 / 输出 ¥54.00。'
116
+ + '官方 K2 系列价格表没有「缓存写入」列,该档留空。',
117
+ },
118
+ {
119
+ provider: 'moonshotai',
120
+ model: 'kimi-k2.6',
121
+ unit: 'perMillionTokens',
122
+ currency: 'CNY',
123
+ input: 6.5, cacheRead: 1.1, output: 27,
124
+ source: KIMI_SOURCE,
125
+ fetchedAt: FETCHED_AT,
126
+ note: 'K2.6(上下文窗口 262,144):未命中 ¥6.50 / 命中 ¥1.10 / 输出 ¥27.00。'
127
+ + '官方 K2 系列价格表没有「缓存写入」列,该档留空。',
128
+ },
129
+ ];
130
+ /* ------------------------------------------------------------------ *
131
+ * Z.ai / GLM(USD / 百万 tokens)
132
+ * 来源:https://docs.z.ai/guides/overview/pricing
133
+ * 官方列:Input / Cached Input / Cached Input Storage / Output。
134
+ * 「Cached Input Storage」文档标为 Limited-time Free(限时免费)→ 本插件 cacheWrite 记 0,
135
+ * 属于「文档明确给出的 0」而不是缺档。
136
+ * ------------------------------------------------------------------ */
137
+ const ZAI_SOURCE = 'https://docs.z.ai/guides/overview/pricing';
138
+ const ZAI_NOTE = '缓存写入档对应官方「Cached Input Storage」,文档标注 Limited-time Free(限时免费),故记 0。';
139
+ const ZAI_ENTRIES = [
140
+ {
141
+ provider: 'zai',
142
+ model: 'glm-5.3',
143
+ unit: 'perMillionTokens',
144
+ currency: 'USD',
145
+ input: 1.4, cacheRead: 0.26, cacheWrite: 0, output: 4.4,
146
+ source: ZAI_SOURCE,
147
+ fetchedAt: FETCHED_AT,
148
+ note: 'GLM-5.3:输入 $1.4 / 缓存命中 $0.26 / 输出 $4.4。' + ZAI_NOTE,
149
+ },
150
+ {
151
+ provider: 'zai',
152
+ model: 'glm-5.3-flash',
153
+ unit: 'perMillionTokens',
154
+ currency: 'USD',
155
+ input: 0.15, cacheRead: 0.03, cacheWrite: 0, output: 0.5,
156
+ source: ZAI_SOURCE,
157
+ fetchedAt: FETCHED_AT,
158
+ note: 'GLM-5.3-Flash:输入 $0.15 / 缓存命中 $0.03 / 输出 $0.50。' + ZAI_NOTE,
159
+ },
160
+ {
161
+ provider: 'zai',
162
+ model: 'glm-5.3-flashx',
163
+ unit: 'perMillionTokens',
164
+ currency: 'USD',
165
+ input: 0.37, cacheRead: 0.075, cacheWrite: 0, output: 1.25,
166
+ source: ZAI_SOURCE,
167
+ fetchedAt: FETCHED_AT,
168
+ note: 'GLM-5.3-FlashX:输入 $0.37 / 缓存命中 $0.075 / 输出 $1.25。' + ZAI_NOTE,
169
+ },
170
+ {
171
+ provider: 'zai',
172
+ model: 'glm-5.2',
173
+ unit: 'perMillionTokens',
174
+ currency: 'USD',
175
+ input: 1.4, cacheRead: 0.26, cacheWrite: 0, output: 4.4,
176
+ source: ZAI_SOURCE,
177
+ fetchedAt: FETCHED_AT,
178
+ note: 'GLM-5.2:输入 $1.4 / 缓存命中 $0.26 / 输出 $4.4。' + ZAI_NOTE,
179
+ },
180
+ {
181
+ provider: 'zai',
182
+ model: 'glm-5',
183
+ unit: 'perMillionTokens',
184
+ currency: 'USD',
185
+ input: 1, cacheRead: 0.2, cacheWrite: 0, output: 3.2,
186
+ source: ZAI_SOURCE,
187
+ fetchedAt: FETCHED_AT,
188
+ note: 'GLM-5(Text Models 表):输入 $1 / 缓存命中 $0.2 / 输出 $3.2。' + ZAI_NOTE,
189
+ },
190
+ ];
191
+ /* ------------------------------------------------------------------ *
192
+ * OpenRouter(USD / token → 本插件按 perMillionTokens 记录)
193
+ * 来源:https://openrouter.ai/api/v1/models 的 `pricing` 字段(**per token** 的 USD 字符串)。
194
+ * 换算:per token × 1e6 = 每百万 tokens,即 0.0000000441 → $0.0441 / MTok。
195
+ * 只收录用户实际会用到的四个家族各 1–2 个主流型号;`:batch` 变体价更低,未收录。
196
+ * 注意:这里是 OpenRouter 的中转价,与厂商直连价不同(如 deepseek/deepseek-v4.1-flash
197
+ * 的 $0.0441 是 OpenRouter 侧报价,DeepSeek 官方 flash 未命中价是 $0.30 —— 两者不是一回事)。
198
+ * `overrides`(超长上下文的阶梯价)本插件模型表达不了,未收录,见 note。
199
+ * ------------------------------------------------------------------ */
200
+ const OPENROUTER_SOURCE = 'https://openrouter.ai/api/v1/models';
201
+ const OPENROUTER_UNIT_NOTE = '官方 pricing 为 USD per token,此处 ×1e6 换算为每百万 tokens。';
202
+ const OPENROUTER_OVERRIDE_NOTE = '官方另有 overrides 阶梯价(超长提示按更高单价计),本插件价格模型表达不了,未收录。';
203
+ const OPENROUTER_ENTRIES = [
204
+ {
205
+ provider: 'openrouter',
206
+ model: 'deepseek/deepseek-v4.1-flash',
207
+ unit: 'perMillionTokens',
208
+ currency: 'USD',
209
+ input: 0.0441, cacheRead: 0.0054, output: 0.63,
210
+ source: OPENROUTER_SOURCE,
211
+ fetchedAt: FETCHED_AT,
212
+ note: 'OpenRouter 中转价(非 DeepSeek 官方直连价):prompt 0.0000000441 / completion 0.00000063 / '
213
+ + 'input_cache_read 0.0000000054。无 input_cache_write 字段,缓存写入档留空。' + OPENROUTER_UNIT_NOTE,
214
+ },
215
+ {
216
+ provider: 'openrouter',
217
+ model: 'anthropic/claude-sonnet-5.5',
218
+ unit: 'perMillionTokens',
219
+ currency: 'USD',
220
+ input: 2, cacheRead: 0.1, cacheWrite: 2.5, output: 10,
221
+ source: OPENROUTER_SOURCE,
222
+ fetchedAt: FETCHED_AT,
223
+ note: 'Claude Sonnet 5.5:prompt 0.000002 / completion 0.00001 / cache_read 0.0000001 / cache_write 0.0000025。'
224
+ + '另有 input_cache_write_1h 0.000004(1 小时 TTL),本插件只有一个缓存写入档,取默认档。'
225
+ + OPENROUTER_UNIT_NOTE + OPENROUTER_OVERRIDE_NOTE,
226
+ },
227
+ {
228
+ provider: 'openrouter',
229
+ model: 'anthropic/claude-opus-5.5',
230
+ unit: 'perMillionTokens',
231
+ currency: 'USD',
232
+ input: 4, cacheRead: 0.2, cacheWrite: 5, output: 20,
233
+ source: OPENROUTER_SOURCE,
234
+ fetchedAt: FETCHED_AT,
235
+ note: 'Claude Opus 5.5:prompt 0.000004 / completion 0.00002 / cache_read 0.0000002 / cache_write 0.000005。'
236
+ + OPENROUTER_UNIT_NOTE,
237
+ },
238
+ {
239
+ provider: 'openrouter',
240
+ model: 'openai/gpt-6.1-sol',
241
+ unit: 'perMillionTokens',
242
+ currency: 'USD',
243
+ input: 2, cacheRead: 0.1, cacheWrite: 2.5, output: 10,
244
+ source: OPENROUTER_SOURCE,
245
+ fetchedAt: FETCHED_AT,
246
+ note: 'GPT-6.1 Sol:prompt 0.000002 / completion 0.00001 / cache_read 0.0000001 / cache_write 0.0000025。'
247
+ + OPENROUTER_UNIT_NOTE + OPENROUTER_OVERRIDE_NOTE,
248
+ },
249
+ {
250
+ provider: 'openrouter',
251
+ model: 'openai/gpt-6-astra',
252
+ unit: 'perMillionTokens',
253
+ currency: 'USD',
254
+ input: 10, cacheRead: 1, cacheWrite: 12.5, output: 50,
255
+ source: OPENROUTER_SOURCE,
256
+ fetchedAt: FETCHED_AT,
257
+ note: 'GPT-6 Astra:prompt 0.00001 / completion 0.00005 / cache_read 0.000001 / cache_write 0.0000125。'
258
+ + OPENROUTER_UNIT_NOTE + OPENROUTER_OVERRIDE_NOTE,
259
+ },
260
+ ];
261
+ /* ------------------------------------------------------------------ *
262
+ * 汇总:按厂商分组,便于以后整体替换某一家。
263
+ * ------------------------------------------------------------------ */
264
+ export const PRICING_CATALOG = [
265
+ ...DEEPSEEK_ENTRIES,
266
+ ...KIMI_ENTRIES,
267
+ ...ZAI_ENTRIES,
268
+ ...OPENROUTER_ENTRIES,
269
+ ];
270
+ export function catalogSources() {
271
+ const bySource = new Map();
272
+ for (const entry of PRICING_CATALOG) {
273
+ const existing = bySource.get(entry.source);
274
+ if (existing === undefined) {
275
+ bySource.set(entry.source, { source: entry.source, fetchedAt: entry.fetchedAt, providers: [entry.provider], count: 1 });
276
+ continue;
277
+ }
278
+ existing.count += 1;
279
+ if (!existing.providers.includes(entry.provider))
280
+ existing.providers.push(entry.provider);
281
+ }
282
+ return [...bySource.values()];
283
+ }
284
+ /** 价目条数(界面文案用)。 */
285
+ export function catalogEntryCount() {
286
+ return PRICING_CATALOG.length;
287
+ }
288
+ /**
289
+ * 模型 id 归一:去掉路由前缀(`vendor/model` → `model`)并转小写。
290
+ * 只做保守的两步(原样 → 忽略大小写 → 去 `vendor/` 前缀),**不做**模糊 / 近似匹配 ——
291
+ * 宁可继续显示「估算」,也不要给出错误金额。
292
+ */
293
+ export function normalizeModelId(model) {
294
+ const trimmed = model.trim();
295
+ const slash = trimmed.lastIndexOf('/');
296
+ const tail = slash >= 0 ? trimmed.slice(slash + 1) : trimmed;
297
+ return tail.toLowerCase();
298
+ }
299
+ /** 通道 id 归一:同样取末段(事件里的 provider 可能是路由名)。 */
300
+ export function normalizeProviderId(provider) {
301
+ return normalizeModelId(provider);
302
+ }
303
+ /**
304
+ * 按「通道 + 模型」查内置价目:
305
+ * 1. 通道与模型都精确匹配;
306
+ * 2. 忽略大小写匹配;
307
+ * 3. 去掉 `vendor/` 前缀后再匹配(`deepseek/deepseek-v4.1-flash` → `deepseek-v4.1-flash`);
308
+ * 4. 该通道的通配兜底(`provider + '*'`),**只在文档给出通道统一价时才会存在**。
309
+ * 找不到返回 null,由调用方继续回落台账均价。
310
+ */
311
+ export function catalogRuleFor(provider, model) {
312
+ const wantedProvider = normalizeProviderId(provider);
313
+ const wantedModel = normalizeModelId(model);
314
+ const candidates = [
315
+ (entry) => entry.provider === provider && entry.model === model,
316
+ (entry) => normalizeProviderId(entry.provider) === wantedProvider && normalizeModelId(entry.model) === wantedModel,
317
+ (entry) => normalizeProviderId(entry.provider) === wantedProvider && entry.model === '*',
318
+ ];
319
+ for (const matches of candidates) {
320
+ const hit = PRICING_CATALOG.find(matches);
321
+ if (hit !== undefined)
322
+ return toPricingRule(hit);
323
+ }
324
+ return null;
325
+ }
326
+ /** 内置价目 → 计费规则:缺档一律按 0(相当于该档不产生费用,而不是用别的档顶替)。 */
327
+ function toPricingRule(entry) {
328
+ const rates = {
329
+ input: entry.input ?? 0,
330
+ cacheRead: entry.cacheRead ?? 0,
331
+ cacheWrite: entry.cacheWrite ?? 0,
332
+ output: entry.output ?? 0,
333
+ };
334
+ return {
335
+ provider: entry.provider,
336
+ model: entry.model,
337
+ unit: entry.unit,
338
+ currency: entry.currency,
339
+ ...rates,
340
+ offPeak: entry.offPeak === undefined ? null : {
341
+ input: entry.offPeak.input ?? rates.input,
342
+ cacheRead: entry.offPeak.cacheRead ?? rates.cacheRead,
343
+ cacheWrite: entry.offPeak.cacheWrite ?? rates.cacheWrite,
344
+ output: entry.offPeak.output ?? rates.output,
345
+ windows: entry.offPeak.windows,
346
+ },
347
+ note: entry.note + '(来源:' + entry.source + ',抓取 ' + entry.fetchedAt + ')',
348
+ };
349
+ }