dsh-codearts 1.2.3 → 1.2.5
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/CHANGELOG.md +75 -0
- package/README.en.md +4 -0
- package/README.md +1 -0
- package/lib/bin.mjs +2 -2
- package/lib/client/index.d.cts +45 -6
- package/lib/client/index.js +645 -221
- package/lib/index.d.mts +35 -0
- package/lib/index.mjs +44 -11
- package/lib/{usage-CzJjkqOp.mjs → usage-DGIuT79_.mjs} +101 -8
- package/package.json +1 -1
package/lib/index.d.mts
CHANGED
|
@@ -1296,12 +1296,40 @@ interface UsageTotals {
|
|
|
1296
1296
|
promptTokens: number;
|
|
1297
1297
|
completionTokens: number;
|
|
1298
1298
|
totalTokens: number;
|
|
1299
|
+
/**
|
|
1300
|
+
* 命中上游 prompt 缓存的输入 token(OpenAI 兼容口径)。
|
|
1301
|
+
*
|
|
1302
|
+
* 上游若在 usage 帧里带 `prompt_tokens_details.cached_tokens`(也有平铺成
|
|
1303
|
+
* `cached_tokens` / `cache_tokens` / `prompt_cache_hit_tokens` 的),这里才可能
|
|
1304
|
+
* 是正数;不给就恒为 0。UI 据此决定显不显示「缓存」那一段 —— 不臆造。
|
|
1305
|
+
* 它是 `promptTokens` 的**子集**,不是额外的输入量。
|
|
1306
|
+
*/
|
|
1307
|
+
cachedTokens: number;
|
|
1308
|
+
/**
|
|
1309
|
+
* 其中属于「思考」的输出 token(OpenAI 兼容口径:`completion_tokens_details.reasoning_tokens`,
|
|
1310
|
+
* 平铺成顶层 `reasoning_tokens` 的也认)。
|
|
1311
|
+
*
|
|
1312
|
+
* 推理模型(deepseek-v4.1-flash 这类)会把它单列出来,通常照样计费;不单独记就
|
|
1313
|
+
* 只能看见一个偏大的「输出」。它是 `completionTokens` 的**子集**,不是额外的输出量。
|
|
1314
|
+
* 上游不给就恒为 0。
|
|
1315
|
+
*/
|
|
1316
|
+
reasoningTokens: number;
|
|
1299
1317
|
}
|
|
1300
1318
|
/** 上游 usage 帧里我们关心的字段。 */
|
|
1301
1319
|
interface RawUsage {
|
|
1302
1320
|
prompt_tokens?: unknown;
|
|
1303
1321
|
completion_tokens?: unknown;
|
|
1304
1322
|
total_tokens?: unknown;
|
|
1323
|
+
/** OpenAI 兼容的嵌套写法:`prompt_tokens_details: { cached_tokens }`。 */
|
|
1324
|
+
prompt_tokens_details?: unknown;
|
|
1325
|
+
/** 平铺写法,几家兼容层各用各的名字,都认。 */
|
|
1326
|
+
cached_tokens?: unknown;
|
|
1327
|
+
cache_tokens?: unknown;
|
|
1328
|
+
prompt_cache_hit_tokens?: unknown;
|
|
1329
|
+
/** 推理模型的嵌套写法:`completion_tokens_details: { reasoning_tokens }`。 */
|
|
1330
|
+
completion_tokens_details?: unknown;
|
|
1331
|
+
/** 平铺的思考 token 别名。 */
|
|
1332
|
+
reasoning_tokens?: unknown;
|
|
1305
1333
|
}
|
|
1306
1334
|
interface UsageSnapshot {
|
|
1307
1335
|
/** 今天的合计。 */
|
|
@@ -1587,6 +1615,13 @@ interface Config {
|
|
|
1587
1615
|
showCreditDock?: boolean;
|
|
1588
1616
|
/** 等上游开流时那行「排队第 N 位」是否显示。缺省 = 显示。 */
|
|
1589
1617
|
showQueueDock?: boolean;
|
|
1618
|
+
/**
|
|
1619
|
+
* 是否在 DSH 侧边栏的图标列里加一个 CodeArts 图标(点开在中间列显示整页版卡片)。
|
|
1620
|
+
*
|
|
1621
|
+
* 缺省 = **不显示**:图标列是全宿主共用的资源,每个插件都默认占一格很快就会挤满,
|
|
1622
|
+
* 而「设置 → 插件」里本来就能看到同一张卡片,所以这一格交给用户自己决定要不要。
|
|
1623
|
+
*/
|
|
1624
|
+
showSidebarPanel?: boolean;
|
|
1590
1625
|
}
|
|
1591
1626
|
declare const Config: z<Config>;
|
|
1592
1627
|
declare function apply(ctx: Context, rawConfig: Config): void;
|
package/lib/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as upstreamErrorMessage, B as modelUnavailableReason, C as isWelfareClaimedStatus, D as prepareChatBody, E as pickDailyWelfareCampaign, F as filterEnabledModels, G as codeartsAuthPath, H as CodeArtsCredentialStore, I as forgetModelUnavailable, K as startLogin, L as isBenefitBlocked, M as FALLBACK_CODEARTS_MODELS, N as clearBenefitBlocked, O as rateLimitFrame, P as creditRatioLabel, R as isBenefitModel, S as isTpmLimit, T as modelUnavailableReasonText, U as MANUAL_ACCOUNT_ID, V as CodeArtsAccountStore, W as codeartsAccountsPath, _ as isIamTokenError, a as SNAP_HOST, b as isParamInvalidFrame, c as claimDailyWelfare, d as fetchCallerIdentity, f as fetchModels, g as isConcurrencyCap, h as firstFrameError, i as refreshCatalog, j as CodeArtsCatalog, k as signedGet, l as clearQueueStatus, m as fetchWelfareCampaigns, n as codeartsUsagePath, o as canonicalModel, p as fetchQueueStatus, r as discoverModels, s as chatStream, t as CodeArtsUsageTracker, u as degradeTokenCeiling, v as isModelNotAccessible, w as maxTokensCeilingFor, x as isQueueableRate, y as isNotMultimodal, z as markModelUnavailable } from "./usage-
|
|
1
|
+
import { A as upstreamErrorMessage, B as modelUnavailableReason, C as isWelfareClaimedStatus, D as prepareChatBody, E as pickDailyWelfareCampaign, F as filterEnabledModels, G as codeartsAuthPath, H as CodeArtsCredentialStore, I as forgetModelUnavailable, K as startLogin, L as isBenefitBlocked, M as FALLBACK_CODEARTS_MODELS, N as clearBenefitBlocked, O as rateLimitFrame, P as creditRatioLabel, R as isBenefitModel, S as isTpmLimit, T as modelUnavailableReasonText, U as MANUAL_ACCOUNT_ID, V as CodeArtsAccountStore, W as codeartsAccountsPath, _ as isIamTokenError, a as SNAP_HOST, b as isParamInvalidFrame, c as claimDailyWelfare, d as fetchCallerIdentity, f as fetchModels, g as isConcurrencyCap, h as firstFrameError, i as refreshCatalog, j as CodeArtsCatalog, k as signedGet, l as clearQueueStatus, m as fetchWelfareCampaigns, n as codeartsUsagePath, o as canonicalModel, p as fetchQueueStatus, r as discoverModels, s as chatStream, t as CodeArtsUsageTracker, u as degradeTokenCeiling, v as isModelNotAccessible, w as maxTokensCeilingFor, x as isQueueableRate, y as isNotMultimodal, z as markModelUnavailable } from "./usage-DGIuT79_.mjs";
|
|
2
2
|
import { i as lazyApi, r as createProvider } from "./models-CgKCibpk.mjs";
|
|
3
3
|
import z from "@deepseek-ai/schemastery";
|
|
4
4
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
@@ -962,6 +962,13 @@ const recentShapes = [];
|
|
|
962
962
|
function recentRequestShapes() {
|
|
963
963
|
return [...recentShapes].reverse();
|
|
964
964
|
}
|
|
965
|
+
const recentUsages = [];
|
|
966
|
+
/** 探针只留最近 5 帧:够看形状,又不至于把内存堆成日志。 */
|
|
967
|
+
const USAGE_PROBE_LIMIT = 5;
|
|
968
|
+
/** 最近的 usage 原帧,最新在前。 */
|
|
969
|
+
function recentUsageShapes() {
|
|
970
|
+
return [...recentUsages].reverse();
|
|
971
|
+
}
|
|
965
972
|
function noteRequestShape(raw, model) {
|
|
966
973
|
let parsed;
|
|
967
974
|
try {
|
|
@@ -1406,7 +1413,16 @@ function createCodeArtsShim(options) {
|
|
|
1406
1413
|
if (payload === "" || payload === "[DONE]") continue;
|
|
1407
1414
|
try {
|
|
1408
1415
|
const parsed = JSON.parse(payload);
|
|
1409
|
-
if (parsed.usage !== void 0 && parsed.usage !== null)
|
|
1416
|
+
if (parsed.usage !== void 0 && parsed.usage !== null) {
|
|
1417
|
+
usage.noteUsage(attribution.accountId, attribution.model, parsed.usage);
|
|
1418
|
+
recentUsages.push({
|
|
1419
|
+
at: Date.now(),
|
|
1420
|
+
accountId: attribution.accountId,
|
|
1421
|
+
model: attribution.model,
|
|
1422
|
+
usage: parsed.usage
|
|
1423
|
+
});
|
|
1424
|
+
while (recentUsages.length > USAGE_PROBE_LIMIT) recentUsages.shift();
|
|
1425
|
+
}
|
|
1410
1426
|
} catch {}
|
|
1411
1427
|
}
|
|
1412
1428
|
}
|
|
@@ -1511,10 +1527,14 @@ function modelBadgesOf(models) {
|
|
|
1511
1527
|
};
|
|
1512
1528
|
});
|
|
1513
1529
|
}
|
|
1514
|
-
/**
|
|
1530
|
+
/**
|
|
1531
|
+
* 开关的默认值:没有 settings provider(或老配置没这两个键)时保持原有行为 ——
|
|
1532
|
+
* 底部两行都显示;侧边栏相反,缺省不开(那一格是所有插件共用的全局座位)。
|
|
1533
|
+
*/
|
|
1515
1534
|
const DEFAULT_DOCK_FLAGS = {
|
|
1516
1535
|
credits: true,
|
|
1517
|
-
queue: true
|
|
1536
|
+
queue: true,
|
|
1537
|
+
sidebar: false
|
|
1518
1538
|
};
|
|
1519
1539
|
/**
|
|
1520
1540
|
* 把逐账号的领取结果汇总成一条:HTTP 层只看 ok,卡片看 results 逐号展示。
|
|
@@ -1619,7 +1639,9 @@ function usageOf(deps) {
|
|
|
1619
1639
|
requests: 0,
|
|
1620
1640
|
promptTokens: 0,
|
|
1621
1641
|
completionTokens: 0,
|
|
1622
|
-
totalTokens: 0
|
|
1642
|
+
totalTokens: 0,
|
|
1643
|
+
cachedTokens: 0,
|
|
1644
|
+
reasoningTokens: 0
|
|
1623
1645
|
};
|
|
1624
1646
|
return {
|
|
1625
1647
|
today: snapshot?.today ?? noTotals,
|
|
@@ -1743,9 +1765,13 @@ function dockHandler(deps) {
|
|
|
1743
1765
|
}
|
|
1744
1766
|
try {
|
|
1745
1767
|
const body = JSON.parse(await readBody(req));
|
|
1746
|
-
const touched = [
|
|
1768
|
+
const touched = [
|
|
1769
|
+
"credits",
|
|
1770
|
+
"queue",
|
|
1771
|
+
"sidebar"
|
|
1772
|
+
].filter((key) => body[key] !== void 0);
|
|
1747
1773
|
if (touched.length === 0 || touched.some((key) => typeof body[key] !== "boolean")) {
|
|
1748
|
-
json(res, 400, { error: "expected {\"credits\"?: boolean, \"queue\"?: boolean}" });
|
|
1774
|
+
json(res, 400, { error: "expected {\"credits\"?: boolean, \"queue\"?: boolean, \"sidebar\"?: boolean}" });
|
|
1749
1775
|
return;
|
|
1750
1776
|
}
|
|
1751
1777
|
if (!await deps.setDock(Object.fromEntries(touched.map((key) => [key, body[key]])))) {
|
|
@@ -2129,7 +2155,10 @@ function debugHandler(deps) {
|
|
|
2129
2155
|
json(res, 403, { error: "request-not-trusted" });
|
|
2130
2156
|
return;
|
|
2131
2157
|
}
|
|
2132
|
-
json(res, 200, {
|
|
2158
|
+
json(res, 200, {
|
|
2159
|
+
requests: deps.recentRequests?.() ?? [],
|
|
2160
|
+
usages: deps.recentUsages?.() ?? []
|
|
2161
|
+
});
|
|
2133
2162
|
};
|
|
2134
2163
|
}
|
|
2135
2164
|
/** Mount the status / models / token routes. */
|
|
@@ -2383,7 +2412,8 @@ function unwrapConfig(value) {
|
|
|
2383
2412
|
const Config = z.object({
|
|
2384
2413
|
enabledModels: z.array(z.string()).description("Model ids offered in the model pickers (empty means every model)").volatile(),
|
|
2385
2414
|
showCreditDock: z.boolean().default(true).description("Show the remaining-credits line under the chat input box").volatile(),
|
|
2386
|
-
showQueueDock: z.boolean().default(true).description("Show the upstream queue position under the chat input box").volatile()
|
|
2415
|
+
showQueueDock: z.boolean().default(true).description("Show the upstream queue position under the chat input box").volatile(),
|
|
2416
|
+
showSidebarPanel: z.boolean().default(false).description("Show a CodeArts icon in the DSH sidebar icon column, opening this page in the middle column").volatile()
|
|
2387
2417
|
});
|
|
2388
2418
|
function settingsCompatNamespace(ctx) {
|
|
2389
2419
|
return resolveSettingsNamespaceCompat(ctx, ctx.get("settings"), CODEARTS_SETTINGS_NS);
|
|
@@ -2458,14 +2488,16 @@ function apply(ctx, rawConfig) {
|
|
|
2458
2488
|
};
|
|
2459
2489
|
const dock = () => ({
|
|
2460
2490
|
credits: current().showCreditDock !== false,
|
|
2461
|
-
queue: current().showQueueDock !== false
|
|
2491
|
+
queue: current().showQueueDock !== false,
|
|
2492
|
+
sidebar: current().showSidebarPanel === true
|
|
2462
2493
|
});
|
|
2463
2494
|
const setDock = async (patch) => {
|
|
2464
2495
|
const settings = ctx.get("settings");
|
|
2465
2496
|
if (settings === void 0) return false;
|
|
2466
2497
|
await settings.update(settingsCompatNamespace(ctx), {
|
|
2467
2498
|
...patch.credits === void 0 ? {} : { showCreditDock: patch.credits },
|
|
2468
|
-
...patch.queue === void 0 ? {} : { showQueueDock: patch.queue }
|
|
2499
|
+
...patch.queue === void 0 ? {} : { showQueueDock: patch.queue },
|
|
2500
|
+
...patch.sidebar === void 0 ? {} : { showSidebarPanel: patch.sidebar }
|
|
2469
2501
|
});
|
|
2470
2502
|
return true;
|
|
2471
2503
|
};
|
|
@@ -2481,6 +2513,7 @@ function apply(ctx, rawConfig) {
|
|
|
2481
2513
|
usage: () => usage.snapshot(),
|
|
2482
2514
|
queue: () => queue.snapshot(),
|
|
2483
2515
|
recentRequests: () => recentRequestShapes(),
|
|
2516
|
+
recentUsages: () => recentUsageShapes(),
|
|
2484
2517
|
credits: (signal) => loadCredits(signal),
|
|
2485
2518
|
refreshCredits: (signal) => {
|
|
2486
2519
|
credits.invalidate();
|
|
@@ -207,6 +207,41 @@ function parseToken(json, dpopJWK, clientId, prev) {
|
|
|
207
207
|
dpopPrivateKey: dpopJWK
|
|
208
208
|
};
|
|
209
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* 华为登录后浏览器落回本机回调的落地页。
|
|
212
|
+
*
|
|
213
|
+
* 这一页本身没有任何后续逻辑:`code` 在响应发出的同一时刻就已交给等待队列
|
|
214
|
+
* (见 startLogin 里的 finish),token 交换完全在服务端做,页面关不关都不影响
|
|
215
|
+
* 登录结果。它只是 redirect_uri 必然要渲染的一个落点 —— 华为侧没有「登录成功」
|
|
216
|
+
* 页可停留,成功标志就是这一次 302 到 127.0.0.1。
|
|
217
|
+
*
|
|
218
|
+
* 卡片用 `window.open` 打开授权页,所以这个标签页能自己关掉;用户从卡片的
|
|
219
|
+
* 手动链接打开、或浏览器拦脚本关窗时 close 会失败,1.2s 后把提示换成「可关闭」。
|
|
220
|
+
*/
|
|
221
|
+
const CALLBACK_HTML = `<!doctype html>
|
|
222
|
+
<html lang="zh-CN">
|
|
223
|
+
<head>
|
|
224
|
+
<meta charset="utf-8">
|
|
225
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
226
|
+
<title>CodeArts 登录</title>
|
|
227
|
+
<style>
|
|
228
|
+
html,body{height:100%}
|
|
229
|
+
body{margin:0;display:flex;align-items:center;justify-content:center;background:#fff;color:#1f2329;
|
|
230
|
+
font:15px/1.6 system-ui,-apple-system,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif}
|
|
231
|
+
p{margin:0;padding:24px;text-align:center}
|
|
232
|
+
</style>
|
|
233
|
+
</head>
|
|
234
|
+
<body>
|
|
235
|
+
<p id="msg">正在返回 DeepSeek Harness…</p>
|
|
236
|
+
<script>
|
|
237
|
+
setTimeout(function () { try { window.close() } catch (e) {} }, 300)
|
|
238
|
+
setTimeout(function () {
|
|
239
|
+
var el = document.getElementById('msg')
|
|
240
|
+
if (el) el.textContent = 'CodeArts 登录成功,本页可关闭,请回到 DeepSeek Harness。'
|
|
241
|
+
}, 1200)
|
|
242
|
+
<\/script>
|
|
243
|
+
</body>
|
|
244
|
+
</html>`;
|
|
210
245
|
async function startLogin(cfg = defaultLoginConfig()) {
|
|
211
246
|
const ticketId = randomHex(16);
|
|
212
247
|
const { verifier, challenge, method } = pkce();
|
|
@@ -236,8 +271,11 @@ async function startLogin(cfg = defaultLoginConfig()) {
|
|
|
236
271
|
}
|
|
237
272
|
finish(code);
|
|
238
273
|
function finish(c) {
|
|
239
|
-
res.writeHead(200, {
|
|
240
|
-
|
|
274
|
+
res.writeHead(200, {
|
|
275
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
276
|
+
"Cache-Control": "no-store"
|
|
277
|
+
});
|
|
278
|
+
res.end(CALLBACK_HTML);
|
|
241
279
|
if (c) for (const w of waiters.splice(0)) w(c);
|
|
242
280
|
}
|
|
243
281
|
});
|
|
@@ -2709,7 +2747,9 @@ function emptyTotals() {
|
|
|
2709
2747
|
requests: 0,
|
|
2710
2748
|
promptTokens: 0,
|
|
2711
2749
|
completionTokens: 0,
|
|
2712
|
-
totalTokens: 0
|
|
2750
|
+
totalTokens: 0,
|
|
2751
|
+
cachedTokens: 0,
|
|
2752
|
+
reasoningTokens: 0
|
|
2713
2753
|
};
|
|
2714
2754
|
}
|
|
2715
2755
|
function addTotals(into, add) {
|
|
@@ -2717,6 +2757,8 @@ function addTotals(into, add) {
|
|
|
2717
2757
|
into.promptTokens += add.promptTokens ?? 0;
|
|
2718
2758
|
into.completionTokens += add.completionTokens ?? 0;
|
|
2719
2759
|
into.totalTokens += add.totalTokens ?? 0;
|
|
2760
|
+
into.cachedTokens += add.cachedTokens ?? 0;
|
|
2761
|
+
into.reasoningTokens += add.reasoningTokens ?? 0;
|
|
2720
2762
|
}
|
|
2721
2763
|
function mergeTotals(into, from) {
|
|
2722
2764
|
addTotals(into, from);
|
|
@@ -2730,12 +2772,41 @@ function localDateKey(at = Date.now()) {
|
|
|
2730
2772
|
function positiveInt(value) {
|
|
2731
2773
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
|
|
2732
2774
|
}
|
|
2733
|
-
/**
|
|
2775
|
+
/**
|
|
2776
|
+
* 从上游 usage 帧里取缓存命中数。
|
|
2777
|
+
*
|
|
2778
|
+
* 位置见过两种:OpenAI 的 `prompt_tokens_details.cached_tokens`,以及兼容层直接
|
|
2779
|
+
* 平铺在顶层的几种别名。取第一个能读到的。缓存输入必然是输入的子集,所以比
|
|
2780
|
+
* `promptTokens` 还大的脏数据直接钳掉 —— 否则界面上会出现 >100% 的命中率。
|
|
2781
|
+
*/
|
|
2782
|
+
function cachedTokensOf(raw, promptTokens) {
|
|
2783
|
+
if (promptTokens <= 0) return 0;
|
|
2784
|
+
const cached = positiveInt(nestedField(raw.prompt_tokens_details, "cached_tokens") ?? raw.cached_tokens ?? raw.cache_tokens ?? raw.prompt_cache_hit_tokens);
|
|
2785
|
+
return Math.min(cached, promptTokens);
|
|
2786
|
+
}
|
|
2787
|
+
/**
|
|
2788
|
+
* 从上游 usage 帧里取思考 token。
|
|
2789
|
+
*
|
|
2790
|
+
* 口径与 {@link cachedTokensOf} 对称:嵌套 `completion_tokens_details.reasoning_tokens`
|
|
2791
|
+
* 优先,顶层 `reasoning_tokens` 兜底,超过输出总量就钳掉(它含在输出里)。
|
|
2792
|
+
*/
|
|
2793
|
+
function reasoningTokensOf(raw, completionTokens) {
|
|
2794
|
+
if (completionTokens <= 0) return 0;
|
|
2795
|
+
const reasoning = positiveInt(nestedField(raw.completion_tokens_details, "reasoning_tokens") ?? raw.reasoning_tokens);
|
|
2796
|
+
return Math.min(reasoning, completionTokens);
|
|
2797
|
+
}
|
|
2798
|
+
/** 读 `*_tokens_details` 这类嵌套对象里的一个字段;不是对象(或缺字段)给 undefined。 */
|
|
2799
|
+
function nestedField(details, key) {
|
|
2800
|
+
return typeof details === "object" && details !== null ? details[key] : void 0;
|
|
2801
|
+
}
|
|
2802
|
+
/** 从上游 usage 帧里取计数(缺哪个算 0,total 缺失时用 prompt+completion 兜底)。 */
|
|
2734
2803
|
function normalizeUsage(raw) {
|
|
2735
2804
|
if (raw === void 0) return {
|
|
2736
2805
|
promptTokens: 0,
|
|
2737
2806
|
completionTokens: 0,
|
|
2738
|
-
totalTokens: 0
|
|
2807
|
+
totalTokens: 0,
|
|
2808
|
+
cachedTokens: 0,
|
|
2809
|
+
reasoningTokens: 0
|
|
2739
2810
|
};
|
|
2740
2811
|
const promptTokens = positiveInt(raw.prompt_tokens);
|
|
2741
2812
|
const completionTokens = positiveInt(raw.completion_tokens);
|
|
@@ -2743,9 +2814,31 @@ function normalizeUsage(raw) {
|
|
|
2743
2814
|
return {
|
|
2744
2815
|
promptTokens,
|
|
2745
2816
|
completionTokens,
|
|
2746
|
-
totalTokens: total > 0 ? total : promptTokens + completionTokens
|
|
2817
|
+
totalTokens: total > 0 ? total : promptTokens + completionTokens,
|
|
2818
|
+
cachedTokens: cachedTokensOf(raw, promptTokens),
|
|
2819
|
+
reasoningTokens: reasoningTokensOf(raw, completionTokens)
|
|
2820
|
+
};
|
|
2821
|
+
}
|
|
2822
|
+
/** 读一项累计值,缺字段(旧账本没有 cachedTokens / reasoningTokens)就按 0 补齐。 */
|
|
2823
|
+
function normalizeTotals(raw) {
|
|
2824
|
+
return {
|
|
2825
|
+
requests: positiveInt(raw?.requests),
|
|
2826
|
+
promptTokens: positiveInt(raw?.promptTokens),
|
|
2827
|
+
completionTokens: positiveInt(raw?.completionTokens),
|
|
2828
|
+
totalTokens: positiveInt(raw?.totalTokens),
|
|
2829
|
+
cachedTokens: positiveInt(raw?.cachedTokens),
|
|
2830
|
+
reasoningTokens: positiveInt(raw?.reasoningTokens)
|
|
2747
2831
|
};
|
|
2748
2832
|
}
|
|
2833
|
+
/** 整张「模型/账号 -> 累计」表补齐字段。 */
|
|
2834
|
+
function normalizeStore(store) {
|
|
2835
|
+
const out = {};
|
|
2836
|
+
for (const [key, totals] of Object.entries(store ?? {})) {
|
|
2837
|
+
if (typeof totals !== "object" || totals === null) continue;
|
|
2838
|
+
out[key] = normalizeTotals(totals);
|
|
2839
|
+
}
|
|
2840
|
+
return out;
|
|
2841
|
+
}
|
|
2749
2842
|
/**
|
|
2750
2843
|
* 用量账本。
|
|
2751
2844
|
*
|
|
@@ -2784,8 +2877,8 @@ var CodeArtsUsageTracker = class {
|
|
|
2784
2877
|
if (parsed.version !== 1 || typeof parsed.days !== "object" || parsed.days === null) return;
|
|
2785
2878
|
for (const [date, day] of Object.entries(parsed.days)) {
|
|
2786
2879
|
if (typeof day !== "object" || day === null) continue;
|
|
2787
|
-
const models = day.models
|
|
2788
|
-
const accounts = day.accounts
|
|
2880
|
+
const models = normalizeStore(day.models);
|
|
2881
|
+
const accounts = normalizeStore(day.accounts);
|
|
2789
2882
|
this.days.set(date, {
|
|
2790
2883
|
models,
|
|
2791
2884
|
accounts
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "dsh-codearts",
|
|
3
3
|
"displayName": "DSH CodeArts Connect",
|
|
4
4
|
"description": "把华为云 CodeArts 接入 DeepSeek Harness —— 内置 OAuth2 登录(PKCE + DPoP),登录后即可在 DSH 对话窗口使用 CodeArts 的模型。",
|
|
5
|
-
"version": "1.2.
|
|
5
|
+
"version": "1.2.5",
|
|
6
6
|
"packageManager": "pnpm@11.24.0",
|
|
7
7
|
"author": "elegant01",
|
|
8
8
|
"keywords": [
|