@deepwhale/llm 1.0.10 → 1.0.12
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/LICENSE +21 -21
- package/package.json +1 -1
- package/dist/anthropic-client.d.ts +0 -147
- package/dist/anthropic-client.d.ts.map +0 -1
- package/dist/anthropic-client.js +0 -443
- package/dist/anthropic-client.js.map +0 -1
- package/dist/canonicalize-schema.d.ts +0 -40
- package/dist/canonicalize-schema.d.ts.map +0 -1
- package/dist/canonicalize-schema.js +0 -93
- package/dist/canonicalize-schema.js.map +0 -1
- package/dist/deepseek-client.d.ts +0 -106
- package/dist/deepseek-client.d.ts.map +0 -1
- package/dist/deepseek-client.js +0 -457
- package/dist/deepseek-client.js.map +0 -1
- package/dist/index.d.ts +0 -26
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -27
- package/dist/index.js.map +0 -1
- package/dist/parse.d.ts +0 -53
- package/dist/parse.d.ts.map +0 -1
- package/dist/parse.js +0 -299
- package/dist/parse.js.map +0 -1
- package/dist/pricing-config.d.ts +0 -104
- package/dist/pricing-config.d.ts.map +0 -1
- package/dist/pricing-config.js +0 -186
- package/dist/pricing-config.js.map +0 -1
- package/dist/pricing.default.toml +0 -46
- package/dist/types.d.ts +0 -288
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -70
- package/dist/types.js.map +0 -1
package/dist/parse.js
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @deepwhale/llm — OpenAI-shape 协议解析层
|
|
3
|
-
*
|
|
4
|
-
* Sprint 1b.5 Step 2 抽出来: 之前这些 module-level fn 在 deepseek-client.ts 里,
|
|
5
|
-
* Step 2 起 AnthropicClient (走 /anthropic endpoint, DeepSeek shim 返 OpenAI-shape)
|
|
6
|
-
* 也需要复用, 抽到 parse.ts 当共享解析层.
|
|
7
|
-
*
|
|
8
|
-
* 设计原则:
|
|
9
|
-
* - 纯函数, 零副作用 (无 console / 无 I/O)
|
|
10
|
-
* - pricing/model 都是 optional, 缺时走 R7 中间路径 (base 2 字段, cost 字段 absent)
|
|
11
|
-
* - 不假设 caller 是 deepseek / anthropic, 任何返 OpenAI-shape JSON 的协议都走这层
|
|
12
|
-
*
|
|
13
|
-
* 不在这层的:
|
|
14
|
-
* - SSE 协议层 (data:/event:/id:/retry: 协议) — 留在 deepseek-client.ts:isSseDoneSentinel
|
|
15
|
-
* - HTTP / fetch / retry — caller 负责
|
|
16
|
-
* - request 编组 (ChatMessage → wire JSON) — 留 caller (toWireMessage 是 deepseek 私货)
|
|
17
|
-
*/
|
|
18
|
-
import { computeCost } from './pricing-config.js';
|
|
19
|
-
/**
|
|
20
|
-
* 解析 OAI chat completion 完整响应 JSON 为 ChatResult.
|
|
21
|
-
* 返 null 表示响应结构无效 (缺 choices[0].message), caller 决定抛什么错.
|
|
22
|
-
*
|
|
23
|
-
* @param fallbackModel - 响应里没 model 字段时用的 fallback (避免 "unknown model" 传播)
|
|
24
|
-
* @param pricing - 可选, 用于算 cost_turn + cost_currency. undefined 走 R7 中间路径.
|
|
25
|
-
*/
|
|
26
|
-
export function parseOaiChatCompletion(json, fallbackModel, pricing) {
|
|
27
|
-
if (typeof json !== 'object' || json === null)
|
|
28
|
-
return null;
|
|
29
|
-
const obj = json;
|
|
30
|
-
const choices = obj['choices'];
|
|
31
|
-
if (!Array.isArray(choices) || choices.length === 0)
|
|
32
|
-
return null;
|
|
33
|
-
const first = choices[0];
|
|
34
|
-
if (typeof first !== 'object' || first === null)
|
|
35
|
-
return null;
|
|
36
|
-
const firstObj = first;
|
|
37
|
-
const message = firstObj['message'];
|
|
38
|
-
if (typeof message !== 'object' || message === null)
|
|
39
|
-
return null;
|
|
40
|
-
const msg = message;
|
|
41
|
-
// Sprint 1c-revive-2-D-21.1 (2026-06-06, 修 DeepSeek V4 thinking 400 bug):
|
|
42
|
-
// 取消 Sprint 1a "机制 3 简化" 拍板 (当时 L117-119 注释 "sprint 1b 再加" 一直没补),
|
|
43
|
-
// 改为从 choices[0].message.reasoning_content 提取. DeepSeek V4 默认开 thinking
|
|
44
|
-
// mode, 多轮必须回传, 否则 400.
|
|
45
|
-
// 兼容: V3 旧 model / 非 thinking 模式不返 reasoning_content 字段, 走 typeof string
|
|
46
|
-
// 守卫, undefined 时 result 不带该字段, 不破坏旧 caller.
|
|
47
|
-
const content = typeof msg['content'] === 'string' ? msg['content'] : '';
|
|
48
|
-
const reasoningContent = typeof msg['reasoning_content'] === 'string' ? msg['reasoning_content'] : undefined;
|
|
49
|
-
// 解析 tool_calls
|
|
50
|
-
let toolCalls;
|
|
51
|
-
const rawTc = msg['tool_calls'];
|
|
52
|
-
if (Array.isArray(rawTc) && rawTc.length > 0) {
|
|
53
|
-
toolCalls = [];
|
|
54
|
-
for (const tc of rawTc) {
|
|
55
|
-
if (typeof tc !== 'object' || tc === null)
|
|
56
|
-
continue;
|
|
57
|
-
const tcObj = tc;
|
|
58
|
-
const fn = tcObj['function'];
|
|
59
|
-
if (typeof fn !== 'object' || fn === null)
|
|
60
|
-
continue;
|
|
61
|
-
const fnObj = fn;
|
|
62
|
-
const name = typeof fnObj['name'] === 'string' ? fnObj['name'] : '';
|
|
63
|
-
const argsStr = typeof fnObj['arguments'] === 'string' ? fnObj['arguments'] : '{}';
|
|
64
|
-
let args = {};
|
|
65
|
-
try {
|
|
66
|
-
const parsed = JSON.parse(argsStr);
|
|
67
|
-
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
|
68
|
-
args = parsed;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
catch {
|
|
72
|
-
// args 解析失败,留空对象。caller 看到 args={} 通常意味着 LLM 输出格式错误。
|
|
73
|
-
}
|
|
74
|
-
const id = typeof tcObj['id'] === 'string' ? tcObj['id'] : '';
|
|
75
|
-
toolCalls.push({ id, name, args });
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
// usage
|
|
79
|
-
let usage;
|
|
80
|
-
const rawUsage = obj['usage'];
|
|
81
|
-
if (typeof rawUsage === 'object' && rawUsage !== null) {
|
|
82
|
-
const u = rawUsage;
|
|
83
|
-
const prompt = typeof u['prompt_tokens'] === 'number' ? u['prompt_tokens'] : 0;
|
|
84
|
-
const completion = typeof u['completion_tokens'] === 'number' ? u['completion_tokens'] : 0;
|
|
85
|
-
const total = typeof u['total_tokens'] === 'number' ? u['total_tokens'] : prompt + completion;
|
|
86
|
-
const cached = typeof u['prompt_cache_hit_tokens'] === 'number' ? u['prompt_cache_hit_tokens'] : undefined;
|
|
87
|
-
usage = { prompt_tokens: prompt, completion_tokens: completion, total_tokens: total };
|
|
88
|
-
if (cached !== undefined)
|
|
89
|
-
usage.cached_tokens = cached;
|
|
90
|
-
// Sprint 1b.5: 改用 pricing-config.computeCost, 接 PricingConfig + ModelId,
|
|
91
|
-
// 返 CostBreakdownResult (undefined / base 2 字段 / 完整 4 字段 3 种).
|
|
92
|
-
// 公式不变 (V4-Flash pricing 在 default.toml 跟旧 hardcode 一致).
|
|
93
|
-
// parseOaiChatCompletion 是 module-level, 从参数接 pricing + fallbackModel.
|
|
94
|
-
const breakdown = computeCost(pricing, fallbackModel, prompt, completion, cached);
|
|
95
|
-
if (breakdown !== undefined) {
|
|
96
|
-
usage.cache_hit_rate = breakdown.cache_hit_rate;
|
|
97
|
-
if (breakdown.cost_turn !== undefined)
|
|
98
|
-
usage.cost_turn = breakdown.cost_turn;
|
|
99
|
-
if (breakdown.cost_currency !== undefined)
|
|
100
|
-
usage.cost_currency = breakdown.cost_currency;
|
|
101
|
-
usage.tokens_uncached = breakdown.tokens_uncached;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
// finish_reason
|
|
105
|
-
const rawFr = firstObj['finish_reason'];
|
|
106
|
-
const finishReason = rawFr === 'stop' || rawFr === 'tool_calls' || rawFr === 'length' || rawFr === 'content_filter'
|
|
107
|
-
? rawFr
|
|
108
|
-
: undefined;
|
|
109
|
-
const modelRaw = obj['model'];
|
|
110
|
-
const model = typeof modelRaw === 'string' ? modelRaw : fallbackModel;
|
|
111
|
-
const result = { model, content };
|
|
112
|
-
if (toolCalls)
|
|
113
|
-
result.tool_calls = toolCalls;
|
|
114
|
-
if (reasoningContent !== undefined)
|
|
115
|
-
result.reasoning_content = reasoningContent;
|
|
116
|
-
if (usage)
|
|
117
|
-
result.usage = usage;
|
|
118
|
-
if (finishReason)
|
|
119
|
-
result.finish_reason = finishReason;
|
|
120
|
-
return result;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* 判断 SSE event raw text 是否是 OAI 协议的 [DONE] 终止 marker.
|
|
124
|
-
* 在 parseSseEvent 之前调用, 确保 [DONE] sentinel 不被算作 parse failure
|
|
125
|
-
* (P2-D follow-up: 之前会被静默归入 sseParseFailures++, 正常流也刷 warn).
|
|
126
|
-
*
|
|
127
|
-
* 容忍: data: [DONE] / data:[DONE] / 多个 data: 行 / 前后空白 / CRLF.
|
|
128
|
-
*/
|
|
129
|
-
export function isSseDoneSentinel(eventRaw) {
|
|
130
|
-
// 扫所有 data: 行,看是否有且只有 [DONE]
|
|
131
|
-
let sawDataLine = false;
|
|
132
|
-
for (const ln of eventRaw.split('\n')) {
|
|
133
|
-
if (!ln.startsWith('data:'))
|
|
134
|
-
continue;
|
|
135
|
-
const payload = ln.slice(5).trimStart();
|
|
136
|
-
if (payload === '[DONE]') {
|
|
137
|
-
sawDataLine = true;
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
// [DONE] event 不应混入别的 data
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
return sawDataLine;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* 解析单个 SSE event (`data: {...}\n`).
|
|
148
|
-
* 返回 null 表示跳过该 event (heartbeat / comment / 解析失败).
|
|
149
|
-
*
|
|
150
|
-
* 注意:[DONE] sentinel 由 isSseDoneSentinel 在调用方提前拦截,
|
|
151
|
-
* 本函数不再处理,避免重复路径让 caller 误算 parse failure.
|
|
152
|
-
*/
|
|
153
|
-
export function parseSseEvent(eventRaw, pricing, model) {
|
|
154
|
-
const lines = eventRaw.split('\n');
|
|
155
|
-
const dataLines = [];
|
|
156
|
-
for (const ln of lines) {
|
|
157
|
-
if (ln.startsWith('data:')) {
|
|
158
|
-
dataLines.push(ln.slice(5).trimStart());
|
|
159
|
-
}
|
|
160
|
-
// event:/id:/retry: 忽略
|
|
161
|
-
}
|
|
162
|
-
if (dataLines.length === 0)
|
|
163
|
-
return null;
|
|
164
|
-
const data = dataLines.join('\n');
|
|
165
|
-
// [DONE] sentinel 已被 isSseDoneSentinel 提前拦截,这里不再判断。
|
|
166
|
-
let json;
|
|
167
|
-
try {
|
|
168
|
-
json = JSON.parse(data);
|
|
169
|
-
}
|
|
170
|
-
catch {
|
|
171
|
-
return null; // 解析失败静默跳过(Sprint 1a 简化,Sprint 1b 加重试日志)
|
|
172
|
-
}
|
|
173
|
-
if (typeof json !== 'object' || json === null)
|
|
174
|
-
return null;
|
|
175
|
-
const obj = json;
|
|
176
|
-
// P1 fix (2026-06-03): 之前 usage 解析只在 choices=[] 分支走, 但 OAI/DeepSeek
|
|
177
|
-
// stream 协议允许最后一个 chunk 同时带 choices (e.g. {delta:{}, finish_reason:"stop"})
|
|
178
|
-
// 和顶层 usage, 此时 usage 会被丢弃 → 状态栏拿不到 cache/cost 数据。
|
|
179
|
-
// 改成先解析顶层 usage, 任何 chunk 类型都挂上。
|
|
180
|
-
// usage-only chunk (choices=[]) 路径保留作为 fallback, 服务端历史兼容。
|
|
181
|
-
// Sprint 1b.5: 把 pricing + model 透传给 parseSseUsageField.
|
|
182
|
-
const topLevelUsage = parseSseUsageField(obj, pricing, model);
|
|
183
|
-
const choices = obj['choices'];
|
|
184
|
-
if (!Array.isArray(choices) || choices.length === 0) {
|
|
185
|
-
if (topLevelUsage !== undefined) {
|
|
186
|
-
return { delta: {}, usage: topLevelUsage };
|
|
187
|
-
}
|
|
188
|
-
return null;
|
|
189
|
-
}
|
|
190
|
-
const first = choices[0];
|
|
191
|
-
if (typeof first !== 'object' || first === null)
|
|
192
|
-
return null;
|
|
193
|
-
const firstObj = first;
|
|
194
|
-
const rawDelta = firstObj['delta'];
|
|
195
|
-
if (typeof rawDelta !== 'object' || rawDelta === null)
|
|
196
|
-
return null;
|
|
197
|
-
const deltaObj = rawDelta;
|
|
198
|
-
// Sprint 1c-revive-2-D-21.1 (2026-06-06, 修 DeepSeek V4 thinking 400 bug):
|
|
199
|
-
// delta.reasoning_content 提取. stream 期间逐 chunk 累加到 working, final
|
|
200
|
-
// ChatResult 拿到完整 reasoning_content. 跟 content 一样, 可能为空字符串
|
|
201
|
-
// (纯 tool_call 增量 + thinking 关闭). 不开 thinking 的 model 不带这字段.
|
|
202
|
-
const content = typeof deltaObj['content'] === 'string' ? deltaObj['content'] : undefined;
|
|
203
|
-
const reasoningContentDelta = typeof deltaObj['reasoning_content'] === 'string' ? deltaObj['reasoning_content'] : undefined;
|
|
204
|
-
// tool_calls 增量(DeepSeek V4 stream 一次性给完整,这里当 full 处理)
|
|
205
|
-
let toolCalls;
|
|
206
|
-
const rawTc = deltaObj['tool_calls'];
|
|
207
|
-
if (Array.isArray(rawTc) && rawTc.length > 0) {
|
|
208
|
-
toolCalls = [];
|
|
209
|
-
for (const tc of rawTc) {
|
|
210
|
-
if (typeof tc !== 'object' || tc === null)
|
|
211
|
-
continue;
|
|
212
|
-
const tcObj = tc;
|
|
213
|
-
const fn = tcObj['function'];
|
|
214
|
-
if (typeof fn !== 'object' || fn === null)
|
|
215
|
-
continue;
|
|
216
|
-
const fnObj = fn;
|
|
217
|
-
const name = typeof fnObj['name'] === 'string' ? fnObj['name'] : '';
|
|
218
|
-
const argsStr = typeof fnObj['arguments'] === 'string' ? fnObj['arguments'] : '{}';
|
|
219
|
-
let args = {};
|
|
220
|
-
try {
|
|
221
|
-
const parsed = JSON.parse(argsStr);
|
|
222
|
-
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
|
223
|
-
args = parsed;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
catch {
|
|
227
|
-
/* leave {} */
|
|
228
|
-
}
|
|
229
|
-
const id = typeof tcObj['id'] === 'string' ? tcObj['id'] : '';
|
|
230
|
-
const idx = typeof tcObj['index'] === 'number' ? tcObj['index'] : 0;
|
|
231
|
-
// Sprint 1a 简化:按 index 收集,最终输出合并
|
|
232
|
-
toolCalls.push({ id: id || `${idx}`, name, args });
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
// finish_reason
|
|
236
|
-
const rawFr = firstObj['finish_reason'];
|
|
237
|
-
const finishReason = rawFr === 'stop' || rawFr === 'tool_calls' || rawFr === 'length' || rawFr === 'content_filter'
|
|
238
|
-
? rawFr
|
|
239
|
-
: undefined;
|
|
240
|
-
// Sprint 1c-revive-2-D-21.1 (2026-06-06): delta shape 扩到带 reasoning_content.
|
|
241
|
-
const delta = {};
|
|
242
|
-
if (content !== undefined)
|
|
243
|
-
delta.content = content;
|
|
244
|
-
if (toolCalls !== undefined)
|
|
245
|
-
delta.tool_calls = toolCalls;
|
|
246
|
-
if (reasoningContentDelta !== undefined)
|
|
247
|
-
delta.reasoning_content = reasoningContentDelta;
|
|
248
|
-
const chunk = { delta };
|
|
249
|
-
if (finishReason)
|
|
250
|
-
chunk.finish_reason = finishReason;
|
|
251
|
-
// P1 fix (2026-06-03): 顶层 usage 在 choices 路径同样挂上,
|
|
252
|
-
// 让 final chunk (带 finish_reason="stop" + 顶层 usage) 能把 usage 透出。
|
|
253
|
-
if (topLevelUsage !== undefined)
|
|
254
|
-
chunk.usage = topLevelUsage;
|
|
255
|
-
return chunk;
|
|
256
|
-
}
|
|
257
|
-
/**
|
|
258
|
-
* 从 SSE event JSON 顶层 usage 字段解析出标准化的 Usage 结构,
|
|
259
|
-
* 顺手算 Sprint 1b 的 cache_hit_rate / cost_turn / tokens_uncached.
|
|
260
|
-
*
|
|
261
|
-
* 返回 undefined 表示该 event 不带 usage (OAI 标准: 只在 stream 末尾出现).
|
|
262
|
-
*
|
|
263
|
-
* P1 fix (2026-06-03): 抽出避免在 choices=[] 和 choices=[...] 两条路径上重复解析。
|
|
264
|
-
*/
|
|
265
|
-
export function parseSseUsageField(obj, pricing, model) {
|
|
266
|
-
const rawUsage = obj['usage'];
|
|
267
|
-
if (typeof rawUsage !== 'object' || rawUsage === null)
|
|
268
|
-
return undefined;
|
|
269
|
-
const u = rawUsage;
|
|
270
|
-
const prompt = typeof u['prompt_tokens'] === 'number' ? u['prompt_tokens'] : 0;
|
|
271
|
-
const completion = typeof u['completion_tokens'] === 'number' ? u['completion_tokens'] : 0;
|
|
272
|
-
const total = typeof u['total_tokens'] === 'number' ? u['total_tokens'] : prompt + completion;
|
|
273
|
-
const cached = typeof u['prompt_cache_hit_tokens'] === 'number'
|
|
274
|
-
? u['prompt_cache_hit_tokens']
|
|
275
|
-
: undefined;
|
|
276
|
-
const usage = {
|
|
277
|
-
prompt_tokens: prompt,
|
|
278
|
-
completion_tokens: completion,
|
|
279
|
-
total_tokens: total,
|
|
280
|
-
};
|
|
281
|
-
if (cached !== undefined)
|
|
282
|
-
usage.cached_tokens = cached;
|
|
283
|
-
// Sprint 1b.5: 改用 pricing-config.computeCost, 公式不变 (default.toml V4-Flash).
|
|
284
|
-
// parseSseUsageField 是 module-level fn, 不持有 this.pricing. pricing/model 可选
|
|
285
|
-
// — undefined 时走 R7 中间路径 (base 2 字段, cost 字段 absent, 不静默 fallback).
|
|
286
|
-
// model undefined 时也安全: computeCost 内部 pricing.models[model] 返 undefined
|
|
287
|
-
// → 走 base 2 字段分支, cost 字段 absent. 不需要 throw.
|
|
288
|
-
const breakdown = computeCost(pricing, model, prompt, completion, cached);
|
|
289
|
-
if (breakdown !== undefined) {
|
|
290
|
-
usage.cache_hit_rate = breakdown.cache_hit_rate;
|
|
291
|
-
if (breakdown.cost_turn !== undefined)
|
|
292
|
-
usage.cost_turn = breakdown.cost_turn;
|
|
293
|
-
if (breakdown.cost_currency !== undefined)
|
|
294
|
-
usage.cost_currency = breakdown.cost_currency;
|
|
295
|
-
usage.tokens_uncached = breakdown.tokens_uncached;
|
|
296
|
-
}
|
|
297
|
-
return usage;
|
|
298
|
-
}
|
|
299
|
-
//# sourceMappingURL=parse.js.map
|
package/dist/parse.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}
|
package/dist/pricing-config.d.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @deepwhale/llm — Pricing 配置 (Sprint 1b.5 Step 1)
|
|
3
|
-
*
|
|
4
|
-
* 把原本 hardcode 在 `types.ts:computeCostBreakdown` 的 V4-Flash pricing 抽到
|
|
5
|
-
* ship-in + 用户可覆盖的 TOML 配置。Per-model currency (DeepSeek CNY, Anthropic USD),
|
|
6
|
-
* 不在 UI 层做汇率换算 — UI 从 `cost_currency` 字段读 symbol (¥ / $)。
|
|
7
|
-
*
|
|
8
|
-
* ## 设计原则 (R7 / Step 0 拍板, 2026-06-03)
|
|
9
|
-
*
|
|
10
|
-
* 1. `loadPricingConfig(userPath)`:
|
|
11
|
-
* - 显式传 `userPath` 但文件不存在或非法 → **抛 PricingConfigParseError** (不静默)
|
|
12
|
-
* - 不传 → 加载 ship-in `pricing.default.toml`
|
|
13
|
-
*
|
|
14
|
-
* 2. `computeCost(pricing, model, ...)` 是**纯函数**: 无 console / 无 logger / 无 IO。
|
|
15
|
-
* 3 种返回路径 (`CostBreakdownResult` 联合类型):
|
|
16
|
-
* - 整体 `undefined`: 没 `cached_tokens` → 4 字段全 absent
|
|
17
|
-
* - `{ base, no cost }`: 有 cache 但 pricing 找不到 model → 有 cache_hit_rate / tokens_uncached, 缺 cost
|
|
18
|
-
* - 完整 4 字段: 找到
|
|
19
|
-
*
|
|
20
|
-
* 3. Warning 责任在 caller (client/mode 边界), 纯函数零副作用。
|
|
21
|
-
*
|
|
22
|
-
* 4. UI/RPC: `cost_turn` absent 时字段不显示 (absent 不是 null), 读 `cost_currency` 决 symbol。
|
|
23
|
-
*/
|
|
24
|
-
import type { ModelId } from './types.js';
|
|
25
|
-
/**
|
|
26
|
-
* 单个模型的定价。Currency 跟价格数字绑定, UI 层不做汇率换算。
|
|
27
|
-
*/
|
|
28
|
-
export interface ModelPricing {
|
|
29
|
-
/** 缓存未命中 input 价格, /M tokens. */
|
|
30
|
-
cache_miss_per_m: number;
|
|
31
|
-
/** 缓存命中 input 价格, /M tokens. */
|
|
32
|
-
cache_hit_per_m: number;
|
|
33
|
-
/** 输出价格, /M tokens. */
|
|
34
|
-
completion_per_m: number;
|
|
35
|
-
/** Currency 跟价格数字绑定, 不在 UI 层做汇率换算. */
|
|
36
|
-
currency: 'CNY' | 'USD';
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* 完整的 pricing 配置 (TOML 解析后).
|
|
40
|
-
*
|
|
41
|
-
* `models` 必须非空. 找不到 model 时**不静默 fallback** (见 R7).
|
|
42
|
-
*/
|
|
43
|
-
export interface PricingConfig {
|
|
44
|
-
models: Record<string, ModelPricing>;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* `computeCost` 的 3 种返回结果 (联合类型).
|
|
48
|
-
*
|
|
49
|
-
* - `undefined`: 没 `cached_tokens` (Provider 也不支持 cache) → 4 字段全 absent
|
|
50
|
-
* - `{ base, no cost }`: 有 cache 但 pricing 找不到 model 或 pricing 本身 undefined
|
|
51
|
-
* → 有 cache_hit_rate + tokens_uncached, 缺 cost_turn + cost_currency
|
|
52
|
-
* - 完整 4 字段: 找到 model → cost_turn 和 cost_currency 同步存在 (不变量)
|
|
53
|
-
*/
|
|
54
|
-
export type CostBreakdownResult = undefined | {
|
|
55
|
-
cache_hit_rate: number;
|
|
56
|
-
tokens_uncached: number;
|
|
57
|
-
/** cost_turn 存在时 cost_currency 必须也存在 (类型不变量). */
|
|
58
|
-
cost_turn?: number;
|
|
59
|
-
cost_currency?: 'CNY' | 'USD';
|
|
60
|
-
};
|
|
61
|
-
/**
|
|
62
|
-
* pricing TOML 解析/加载错误. `userPath` 显式传但文件不存在/非法时抛.
|
|
63
|
-
*/
|
|
64
|
-
export declare class PricingConfigParseError extends Error {
|
|
65
|
-
readonly userPath: string;
|
|
66
|
-
readonly name: "PricingConfigParseError";
|
|
67
|
-
constructor(message: string, userPath: string, options?: {
|
|
68
|
-
cause?: unknown;
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* 解析 TOML string → PricingConfig. 纯函数, 无 IO.
|
|
73
|
-
*
|
|
74
|
-
* 校验:
|
|
75
|
-
* - 必须有 `[models.xxx]` 块 (至少 1 个)
|
|
76
|
-
* - 每个 model 4 字段全必填 (cache_miss_per_m / cache_hit_per_m / completion_per_m / currency)
|
|
77
|
-
* - currency 必须在 'CNY' | 'USD' enum
|
|
78
|
-
* - 价格数字必须非负有限
|
|
79
|
-
*
|
|
80
|
-
* @throws PricingConfigParseError — malformed / 缺字段 / currency 错 / 数字非有限
|
|
81
|
-
*/
|
|
82
|
-
export declare function parsePricingConfig(toml: string): PricingConfig;
|
|
83
|
-
/**
|
|
84
|
-
* 纯函数, 无 console / 无 logger / 无 IO. 3 种返回路径见 `CostBreakdownResult`.
|
|
85
|
-
*
|
|
86
|
-
* 公式: tokens_uncached = max(0, prompt - cached)
|
|
87
|
-
* cache_hit_rate = cached / prompt (prompt=0 时 0, 避免除零)
|
|
88
|
-
* cost_turn = tokens_uncached * cache_miss_per_m/1e6
|
|
89
|
-
* + cached * cache_hit_per_m/1e6
|
|
90
|
-
* + completion * completion_per_m/1e6
|
|
91
|
-
*
|
|
92
|
-
* 把 /M 转 /token 必须除 1e6, 不要直接当 /token 用 (会大 1000×).
|
|
93
|
-
*/
|
|
94
|
-
export declare function computeCost(pricing: PricingConfig | undefined, model: ModelId | undefined, promptTokens: number, completionTokens: number, cachedTokens: number | undefined): CostBreakdownResult;
|
|
95
|
-
/**
|
|
96
|
-
* 加载 pricing config. 三种来源优先级 (高→低):
|
|
97
|
-
* 1. `userPath` 显式指定且存在 → 解析用户文件
|
|
98
|
-
* 2. `userPath` 显式指定但不存在或非法 → **抛 PricingConfigParseError** (不静默 fallback)
|
|
99
|
-
* 3. `userPath` 未传 → 加载 ship-in `pricing.default.toml`
|
|
100
|
-
*
|
|
101
|
-
* hot path 不应调 (走 client.pricing 字段). Step 2 的 AnthropicClient 启动时调一次.
|
|
102
|
-
*/
|
|
103
|
-
export declare function loadPricingConfig(userPath?: string): Promise<PricingConfig>;
|
|
104
|
-
//# sourceMappingURL=pricing-config.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pricing-config.d.ts","sourceRoot":"","sources":["../src/pricing-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAI1C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,iCAAiC;IACjC,gBAAgB,EAAE,MAAM,CAAC;IACzB,gCAAgC;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,uBAAuB;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,QAAQ,EAAE,KAAK,GAAG,KAAK,CAAC;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACtC;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAC3B,SAAS,GACT;IACE,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;CAC/B,CAAC;AAEN;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAI9C,QAAQ,CAAC,QAAQ,EAAE,MAAM;IAH3B,SAAkB,IAAI,EAAG,yBAAyB,CAAU;gBAE1D,OAAO,EAAE,MAAM,EACN,QAAQ,EAAE,MAAM,EACzB,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAOhC;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAmE9D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,aAAa,GAAG,SAAS,EAClC,KAAK,EAAE,OAAO,GAAG,SAAS,EAC1B,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,mBAAmB,CA6BrB;AAID;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CASjF"}
|
package/dist/pricing-config.js
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @deepwhale/llm — Pricing 配置 (Sprint 1b.5 Step 1)
|
|
3
|
-
*
|
|
4
|
-
* 把原本 hardcode 在 `types.ts:computeCostBreakdown` 的 V4-Flash pricing 抽到
|
|
5
|
-
* ship-in + 用户可覆盖的 TOML 配置。Per-model currency (DeepSeek CNY, Anthropic USD),
|
|
6
|
-
* 不在 UI 层做汇率换算 — UI 从 `cost_currency` 字段读 symbol (¥ / $)。
|
|
7
|
-
*
|
|
8
|
-
* ## 设计原则 (R7 / Step 0 拍板, 2026-06-03)
|
|
9
|
-
*
|
|
10
|
-
* 1. `loadPricingConfig(userPath)`:
|
|
11
|
-
* - 显式传 `userPath` 但文件不存在或非法 → **抛 PricingConfigParseError** (不静默)
|
|
12
|
-
* - 不传 → 加载 ship-in `pricing.default.toml`
|
|
13
|
-
*
|
|
14
|
-
* 2. `computeCost(pricing, model, ...)` 是**纯函数**: 无 console / 无 logger / 无 IO。
|
|
15
|
-
* 3 种返回路径 (`CostBreakdownResult` 联合类型):
|
|
16
|
-
* - 整体 `undefined`: 没 `cached_tokens` → 4 字段全 absent
|
|
17
|
-
* - `{ base, no cost }`: 有 cache 但 pricing 找不到 model → 有 cache_hit_rate / tokens_uncached, 缺 cost
|
|
18
|
-
* - 完整 4 字段: 找到
|
|
19
|
-
*
|
|
20
|
-
* 3. Warning 责任在 caller (client/mode 边界), 纯函数零副作用。
|
|
21
|
-
*
|
|
22
|
-
* 4. UI/RPC: `cost_turn` absent 时字段不显示 (absent 不是 null), 读 `cost_currency` 决 symbol。
|
|
23
|
-
*/
|
|
24
|
-
import { readFile } from 'node:fs/promises';
|
|
25
|
-
import { fileURLToPath } from 'node:url';
|
|
26
|
-
import { dirname, resolve } from 'node:path';
|
|
27
|
-
import { parse as parseToml } from 'smol-toml';
|
|
28
|
-
/**
|
|
29
|
-
* pricing TOML 解析/加载错误. `userPath` 显式传但文件不存在/非法时抛.
|
|
30
|
-
*/
|
|
31
|
-
export class PricingConfigParseError extends Error {
|
|
32
|
-
userPath;
|
|
33
|
-
name = 'PricingConfigParseError';
|
|
34
|
-
constructor(message, userPath, options) {
|
|
35
|
-
super(message);
|
|
36
|
-
this.userPath = userPath;
|
|
37
|
-
if (options?.cause !== undefined) {
|
|
38
|
-
this.cause = options.cause;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
// ---- 纯函数 (无 console, 无 IO) ----
|
|
43
|
-
/**
|
|
44
|
-
* 解析 TOML string → PricingConfig. 纯函数, 无 IO.
|
|
45
|
-
*
|
|
46
|
-
* 校验:
|
|
47
|
-
* - 必须有 `[models.xxx]` 块 (至少 1 个)
|
|
48
|
-
* - 每个 model 4 字段全必填 (cache_miss_per_m / cache_hit_per_m / completion_per_m / currency)
|
|
49
|
-
* - currency 必须在 'CNY' | 'USD' enum
|
|
50
|
-
* - 价格数字必须非负有限
|
|
51
|
-
*
|
|
52
|
-
* @throws PricingConfigParseError — malformed / 缺字段 / currency 错 / 数字非有限
|
|
53
|
-
*/
|
|
54
|
-
export function parsePricingConfig(toml) {
|
|
55
|
-
let raw;
|
|
56
|
-
try {
|
|
57
|
-
raw = parseToml(toml);
|
|
58
|
-
}
|
|
59
|
-
catch (cause) {
|
|
60
|
-
throw new PricingConfigParseError(`TOML parse failed: ${cause.message}`, '<inline>', { cause });
|
|
61
|
-
}
|
|
62
|
-
if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
63
|
-
throw new PricingConfigParseError('TOML root must be a table', '<inline>');
|
|
64
|
-
}
|
|
65
|
-
const root = raw;
|
|
66
|
-
const modelsRaw = root['models'];
|
|
67
|
-
if (modelsRaw === undefined || modelsRaw === null) {
|
|
68
|
-
throw new PricingConfigParseError('Missing required section: [models.*]', '<inline>');
|
|
69
|
-
}
|
|
70
|
-
if (typeof modelsRaw !== 'object' || Array.isArray(modelsRaw)) {
|
|
71
|
-
throw new PricingConfigParseError('Section [models.*] must be a table', '<inline>');
|
|
72
|
-
}
|
|
73
|
-
const models = {};
|
|
74
|
-
for (const [modelId, value] of Object.entries(modelsRaw)) {
|
|
75
|
-
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
76
|
-
throw new PricingConfigParseError(`[models.${modelId}] must be a table`, '<inline>');
|
|
77
|
-
}
|
|
78
|
-
const block = value;
|
|
79
|
-
const cacheMiss = block['cache_miss_per_m'];
|
|
80
|
-
const cacheHit = block['cache_hit_per_m'];
|
|
81
|
-
const completion = block['completion_per_m'];
|
|
82
|
-
const currency = block['currency'];
|
|
83
|
-
for (const [field, val] of [
|
|
84
|
-
['cache_miss_per_m', cacheMiss],
|
|
85
|
-
['cache_hit_per_m', cacheHit],
|
|
86
|
-
['completion_per_m', completion],
|
|
87
|
-
]) {
|
|
88
|
-
if (typeof val !== 'number' || !Number.isFinite(val) || val < 0) {
|
|
89
|
-
throw new PricingConfigParseError(`[models.${modelId}].${field} must be a non-negative finite number, got: ${JSON.stringify(val)}`, '<inline>');
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if (currency !== 'CNY' && currency !== 'USD') {
|
|
93
|
-
throw new PricingConfigParseError(`[models.${modelId}].currency must be 'CNY' or 'USD', got: ${JSON.stringify(currency)}`, '<inline>');
|
|
94
|
-
}
|
|
95
|
-
models[modelId] = {
|
|
96
|
-
cache_miss_per_m: cacheMiss,
|
|
97
|
-
cache_hit_per_m: cacheHit,
|
|
98
|
-
completion_per_m: completion,
|
|
99
|
-
currency,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
if (Object.keys(models).length === 0) {
|
|
103
|
-
throw new PricingConfigParseError('At least one model required in [models.*]', '<inline>');
|
|
104
|
-
}
|
|
105
|
-
return { models };
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* 纯函数, 无 console / 无 logger / 无 IO. 3 种返回路径见 `CostBreakdownResult`.
|
|
109
|
-
*
|
|
110
|
-
* 公式: tokens_uncached = max(0, prompt - cached)
|
|
111
|
-
* cache_hit_rate = cached / prompt (prompt=0 时 0, 避免除零)
|
|
112
|
-
* cost_turn = tokens_uncached * cache_miss_per_m/1e6
|
|
113
|
-
* + cached * cache_hit_per_m/1e6
|
|
114
|
-
* + completion * completion_per_m/1e6
|
|
115
|
-
*
|
|
116
|
-
* 把 /M 转 /token 必须除 1e6, 不要直接当 /token 用 (会大 1000×).
|
|
117
|
-
*/
|
|
118
|
-
export function computeCost(pricing, model, promptTokens, completionTokens, cachedTokens) {
|
|
119
|
-
if (cachedTokens === undefined) {
|
|
120
|
-
return undefined;
|
|
121
|
-
}
|
|
122
|
-
const tokensUncached = Math.max(0, promptTokens - cachedTokens);
|
|
123
|
-
const hitRate = promptTokens > 0 ? cachedTokens / promptTokens : 0;
|
|
124
|
-
// model undefined 或 pricing 找不到 model → 走 R7 中间路径
|
|
125
|
-
// (有 cached 但 cost 字段 absent). 不静默 fallback, 不抛错, 不写 0.
|
|
126
|
-
const modelPricing = model !== undefined ? pricing?.models[model] : undefined;
|
|
127
|
-
if (modelPricing === undefined) {
|
|
128
|
-
return {
|
|
129
|
-
cache_hit_rate: hitRate,
|
|
130
|
-
tokens_uncached: tokensUncached,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
const costTurn = tokensUncached * (modelPricing.cache_miss_per_m / 1_000_000) +
|
|
134
|
-
cachedTokens * (modelPricing.cache_hit_per_m / 1_000_000) +
|
|
135
|
-
completionTokens * (modelPricing.completion_per_m / 1_000_000);
|
|
136
|
-
return {
|
|
137
|
-
cache_hit_rate: hitRate,
|
|
138
|
-
tokens_uncached: tokensUncached,
|
|
139
|
-
cost_turn: costTurn,
|
|
140
|
-
cost_currency: modelPricing.currency,
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
// ---- IO 函数 (一次启动加载, 注入到 client) ----
|
|
144
|
-
/**
|
|
145
|
-
* 加载 pricing config. 三种来源优先级 (高→低):
|
|
146
|
-
* 1. `userPath` 显式指定且存在 → 解析用户文件
|
|
147
|
-
* 2. `userPath` 显式指定但不存在或非法 → **抛 PricingConfigParseError** (不静默 fallback)
|
|
148
|
-
* 3. `userPath` 未传 → 加载 ship-in `pricing.default.toml`
|
|
149
|
-
*
|
|
150
|
-
* hot path 不应调 (走 client.pricing 字段). Step 2 的 AnthropicClient 启动时调一次.
|
|
151
|
-
*/
|
|
152
|
-
export async function loadPricingConfig(userPath) {
|
|
153
|
-
if (userPath === undefined) {
|
|
154
|
-
// 走 ship-in default: 跟 pricing-config.ts 同目录, build 后复制到 dist/.
|
|
155
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
156
|
-
// dist/pricing-config.js → dist/pricing.default.toml
|
|
157
|
-
const defaultPath = resolve(here, 'pricing.default.toml');
|
|
158
|
-
return await loadFromPath(defaultPath);
|
|
159
|
-
}
|
|
160
|
-
return await loadFromPath(userPath);
|
|
161
|
-
}
|
|
162
|
-
async function loadFromPath(path) {
|
|
163
|
-
let tomlText;
|
|
164
|
-
try {
|
|
165
|
-
tomlText = await readFile(path, 'utf-8');
|
|
166
|
-
}
|
|
167
|
-
catch (cause) {
|
|
168
|
-
const err = cause;
|
|
169
|
-
if (err.code === 'ENOENT') {
|
|
170
|
-
throw new PricingConfigParseError(`Pricing config not found at: ${path}`, path, { cause });
|
|
171
|
-
}
|
|
172
|
-
throw new PricingConfigParseError(`Failed to read pricing config at ${path}: ${err.message}`, path, { cause });
|
|
173
|
-
}
|
|
174
|
-
try {
|
|
175
|
-
return parsePricingConfig(tomlText);
|
|
176
|
-
}
|
|
177
|
-
catch (cause) {
|
|
178
|
-
if (cause instanceof PricingConfigParseError) {
|
|
179
|
-
// 重新抛, 用真实 path 替换 inner 错误的 '<inline>' 占位符.
|
|
180
|
-
// 保留原始 userPath (readonly 字段, 不用 spread 因为 class 自带字段).
|
|
181
|
-
throw new PricingConfigParseError(cause.message.replace('<inline>', path), path, { cause });
|
|
182
|
-
}
|
|
183
|
-
throw cause;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
//# sourceMappingURL=pricing-config.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pricing-config.js","sourceRoot":"","sources":["../src/pricing-config.ts"],"names":[],"mappings":"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"}
|