@mars-sea/dsh-commandcode-provider 0.14.2 → 0.14.3
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 +22 -0
- package/lib/client.js +19 -12
- package/lib/index.d.ts +10 -4
- package/lib/index.js +75 -19
- package/package.json +2 -1
- package/lib/client.js.map +0 -1
- package/lib/index.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,28 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.14.3] - 2026-10-19
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **发布包不再携带 sourcemap,体积减少约 16%(tarball 2.9 MB → 2.5 MB,解包 5.1 MB → 3.5 MB;文件数 18 → 16)。** `tsdown.config.ts` 的 `sourcemap: true` 会产出 `lib/index.js.map` 与 `lib/client.js.map`,而 `files` 直接收整个 `lib`,两份 map(1.63 MiB)因此进了 tarball。它们没有任何读取方:`lib/client.js` 是 WebView 直接执行的 CJS 包,`//# sourceMappingURL` 只是尾部注释;`scripts/verify-engine-load.mjs` 的审计用正则匹配 `import`/`require` **语句**,不匹配注释。本地 `npm run build` 照旧产出 map,调试能力不受影响。**用户侧无需做任何事**,运行时行为与公开导出面零变化(`lib/index.d.ts` 的 `export { ... }` 一行未改)。
|
|
12
|
+
|
|
13
|
+
- **长会话的历史分析报告更快(约 −28%~−33%)。** `buildAnalytics` 原先有两处对「事实 × 模型」的重复扫描:每模型小计对整表过滤 N 次,场景矩阵对每个(事实 × 目录模型)都查一次候选价格行(96 个模型共 480,000 次查找,查的是同一批行)。现改为先按模型分桶一次,并把定价算式收进 `cost-facts.requestCost()`、让场景循环把查价提到内层循环之外;`requestRates` 增加可选的高峰时段 memo(由调用方持有,不会活得比它的价格表更久)。两套独立测量给出同一量级:PR 作者脚本 5,000 条事实 × 96 个目录模型 42.17 ms → 30.36 ms,维护者本机用另一套合成数据复测 14.87 ms → 9.90 ms。**输出逐位不变**:分桶顺序与原 `Set` 顺序一致,排序本来就是按唯一 id 的全序(维护者另用 3,000 条确定性事实 × 96 个模型对比两版 JSON 输出,147,944 字节完全一致)。
|
|
14
|
+
|
|
15
|
+
- **图片请求里同一张图只编码一次 base64。** `readImageRequest()` 对每个(附件,编码目标)返回同一个缓存对象,但一条请求里同一张图会出现在多条历史消息中;三个 wire 编解码器原先各自按「出现次数」执行 `Buffer.from(version.data).toString('base64')`(1 MiB 载荷 0.738 ms/次)。现改为以该缓存对象为键的 `WeakMap`,保存原始 base64 与 data URL,副本生命周期跟随宿主自己的版本缓存。命中约 21 ns。
|
|
16
|
+
|
|
17
|
+
- **「查看模型用量、成本与性能分析」入口移到「账户用量」分组标题行**,紧邻「刷新」。它原先裸放在页面说明段与第一个分组之间,既无外边距也不属于任何分组,视觉上像是游离在版式之外;移到「账户用量」标题行后与服务着同一批用量/成本数据的「刷新」并列,也复用了该行既有的 `cc-spacer` 布局,不新增样式类。分析入口仍只在 Host 暴露面板接缝时出现,行为不变(切到面板的「模型分析」页签并打开面板)。
|
|
18
|
+
|
|
19
|
+
- **多账户轮换说明精简 2 处冗余用词**(中文 47 → 43 字,英文同步)。`账户操作立即生效。当前账户达到用量限额或密钥失效时,请求会按列表顺序自动切换到下一个可用账户。` → 去掉「用量」与「自动」后为:`账户操作立即生效。当前账户达到限额或密钥失效时,请求会按列表顺序切换到下一个可用账户。` 「按列表顺序切换」本身已表达自动性,`达到限额` 在账户上下文里仍是额度含意;英文侧 `usage limit` → `limit`,`switch` 原本就没有 `automatically`。**已知取舍**:同页单账户文案 `accountsHint` 仍用「用量限额」,两条说明的术语因此不完全一致。
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **新增 `.gitattributes`:全部文本文件统一按 LF 检出与提交。** 仓库此前没有该文件,Windows 贡献者按 CRLF 检出后,sourcemap 的 `sourcesContent` 会内嵌带 CRLF 的源码,重建出的 `.map` 与提交里的不再逐字节相同,CI 的 `git diff --exit-code -- lib/` 守卫因此误报「产物过期」(2026-10-17 那次 CI 失败的根因)。实测对照:无该文件时 `core.autocrlf=true` 检出后 `src/adapter.ts` 有 3,482 行 CRLF、`lib/index.js` 有 11,817 行;加上后两者均为 0。图片与压缩包按 `binary` 排除在行尾转换之外。**本次加入时已跟踪文件 100% 是 LF,`git add --renormalize .` 未改写任何文件。**
|
|
24
|
+
|
|
25
|
+
### Removed
|
|
26
|
+
|
|
27
|
+
- 两份 sourcemap(`lib/index.js.map`、`lib/client.js.map`)不再纳入版本控制。它们是 tsdown 产物里唯一在 CRLF 工作树上无法逐字节重建的文件,跟踪它们只会让「产物过期」守卫依赖工作树的行尾;移出 tarball 与版本控制后,该守卫在任意平台都只反映源码与产物的真实一致性。
|
|
28
|
+
|
|
7
29
|
## [0.14.2] - 2026-10-18
|
|
8
30
|
|
|
9
31
|
### Changed
|
package/lib/client.js
CHANGED
|
@@ -3237,7 +3237,7 @@ window.__ModuleLoader__.load({
|
|
|
3237
3237
|
cardRouteActive: "已启用",
|
|
3238
3238
|
cardLoadingHint: "正在读取 Command Code 配置…",
|
|
3239
3239
|
cardRegistrationHint: "此卡片由 Command Code 插件提供,正在等待设置页装配,稍后即可显示完整内容。",
|
|
3240
|
-
accountsRotationHint: "
|
|
3240
|
+
accountsRotationHint: "账户操作立即生效。当前账户达到限额或密钥失效时,请求会按列表顺序切换到下一个可用账户。",
|
|
3241
3241
|
accountModeAuto: "使用方式:自动切换(按列表顺序)",
|
|
3242
3242
|
accountModePinned: "使用方式:固定使用「{name}」,不可用时仍会自动切换",
|
|
3243
3243
|
accountStatusPinned: "已固定",
|
|
@@ -3463,7 +3463,7 @@ window.__ModuleLoader__.load({
|
|
|
3463
3463
|
cardRouteActive: "Active",
|
|
3464
3464
|
cardLoadingHint: "Loading the Command Code configuration…",
|
|
3465
3465
|
cardRegistrationHint: "This card is contributed by the Command Code plugin and is waiting for the settings page to finish assembling.",
|
|
3466
|
-
accountsRotationHint: "Account actions apply immediately. When the current account hits its
|
|
3466
|
+
accountsRotationHint: "Account actions apply immediately. When the current account hits its limit or its key stops working, requests switch to the next usable account in list order.",
|
|
3467
3467
|
accountModeAuto: "Mode: switch automatically (list order)",
|
|
3468
3468
|
accountModePinned: "Mode: pinned to \"{name}\", still switching when it is unavailable",
|
|
3469
3469
|
accountStatusPinned: "Pinned",
|
|
@@ -3704,7 +3704,7 @@ window.__ModuleLoader__.load({
|
|
|
3704
3704
|
}
|
|
3705
3705
|
//#endregion
|
|
3706
3706
|
//#region package.json
|
|
3707
|
-
var version = "0.14.
|
|
3707
|
+
var version = "0.14.3";
|
|
3708
3708
|
var repository = {
|
|
3709
3709
|
"type": "git",
|
|
3710
3710
|
"url": "git+https://github.com/Mars-Sea/dsh-commandcode-provider.git"
|
|
@@ -5554,7 +5554,7 @@ window.__ModuleLoader__.load({
|
|
|
5554
5554
|
* each, with its status and quota inline — so one account's facts no longer
|
|
5555
5555
|
* have to be cross-read across separate surfaces.
|
|
5556
5556
|
*/
|
|
5557
|
-
function AccountsCard({ t, state, usage, login, disabled, actions, onRefresh, createEnrollment }) {
|
|
5557
|
+
function AccountsCard({ t, state, usage, login, disabled, actions, onRefresh, openAnalytics, createEnrollment }) {
|
|
5558
5558
|
const [adding, setAdding] = (0, react.useState)(false);
|
|
5559
5559
|
const [enrollment] = (0, react.useState)(createEnrollment);
|
|
5560
5560
|
const snapshot = (0, react.useSyncExternalStore)(enrollment.store.subscribe, enrollment.store.getSnapshot);
|
|
@@ -5582,6 +5582,12 @@ window.__ModuleLoader__.load({
|
|
|
5582
5582
|
children: t("accountsTitle")
|
|
5583
5583
|
}),
|
|
5584
5584
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "cc-spacer" }),
|
|
5585
|
+
openAnalytics ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
5586
|
+
variant: "ghost",
|
|
5587
|
+
size: "sm",
|
|
5588
|
+
onClick: openAnalytics,
|
|
5589
|
+
children: t("openAnalytics")
|
|
5590
|
+
}) : null,
|
|
5585
5591
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5586
5592
|
type: "button",
|
|
5587
5593
|
className: "cc-linkButton",
|
|
@@ -5929,12 +5935,6 @@ window.__ModuleLoader__.load({
|
|
|
5929
5935
|
className: "cc-intro",
|
|
5930
5936
|
children: t("intro")
|
|
5931
5937
|
}),
|
|
5932
|
-
props.openAnalytics ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
5933
|
-
variant: "ghost",
|
|
5934
|
-
size: "sm",
|
|
5935
|
-
onClick: props.openAnalytics,
|
|
5936
|
-
children: t("openAnalytics")
|
|
5937
|
-
}) : null,
|
|
5938
5938
|
!state.writable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5939
5939
|
className: "cc-readOnly",
|
|
5940
5940
|
role: "status",
|
|
@@ -5948,6 +5948,7 @@ window.__ModuleLoader__.load({
|
|
|
5948
5948
|
disabled,
|
|
5949
5949
|
actions,
|
|
5950
5950
|
onRefresh: props.refreshUsage,
|
|
5951
|
+
openAnalytics: props.openAnalytics,
|
|
5951
5952
|
createEnrollment: props.createEnrollment
|
|
5952
5953
|
}),
|
|
5953
5954
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelsCard, {
|
|
@@ -8376,10 +8377,16 @@ window.__ModuleLoader__.load({
|
|
|
8376
8377
|
* today, so the combination becoming real is visible before it reaches a user.
|
|
8377
8378
|
* This ordering is a latent choice, not a verified upstream rule.
|
|
8378
8379
|
*/
|
|
8379
|
-
function requestRates(price, at, contextTokens, table) {
|
|
8380
|
+
function requestRates(price, at, contextTokens, table, peakHourCache) {
|
|
8380
8381
|
const tier = price.contextTiers?.find((tier) => tier.maxContext === void 0 || contextTokens <= tier.maxContext);
|
|
8381
8382
|
if (tier !== void 0) return tier;
|
|
8382
|
-
|
|
8383
|
+
if (price.peak === void 0 || at === null) return price;
|
|
8384
|
+
let peak = peakHourCache?.get(at);
|
|
8385
|
+
if (peak === void 0) {
|
|
8386
|
+
peak = peakHour(at, table.peakHours);
|
|
8387
|
+
peakHourCache?.set(at, peak);
|
|
8388
|
+
}
|
|
8389
|
+
return peak ? price.peak : price;
|
|
8383
8390
|
}
|
|
8384
8391
|
/** Cache version and wire guard: changing bands/rates must refold historical groups. */
|
|
8385
8392
|
function pricingKey(table) {
|
package/lib/index.d.ts
CHANGED
|
@@ -207,7 +207,13 @@ interface CommandCodeConnectionOptions {
|
|
|
207
207
|
* text-only request never depends on the attachment seam.
|
|
208
208
|
*/
|
|
209
209
|
type ResolveAttachments = () => AttachmentStore | undefined;
|
|
210
|
-
/**
|
|
210
|
+
/**
|
|
211
|
+
* What the rotation hook knows about the request it is rotating within.
|
|
212
|
+
*
|
|
213
|
+
* Not exported: the only consumer is the `rotateApiKey` shape below, so the
|
|
214
|
+
* name never reaches the published `.d.ts` and the package's `exports` map
|
|
215
|
+
* leaves no deep-import path to it.
|
|
216
|
+
*/
|
|
211
217
|
interface AccountRotationContext {
|
|
212
218
|
/** Every API key this request has already used, just-rejected key included. */
|
|
213
219
|
tried: readonly string[];
|
|
@@ -265,13 +271,13 @@ interface CommandCodeAdapterDeps<C extends CommandCodeConnectionOptions = Comman
|
|
|
265
271
|
*/
|
|
266
272
|
imageOffload?: SurfaceImagePolicy;
|
|
267
273
|
}
|
|
268
|
-
/** Account identity from `/alpha/whoami`. */
|
|
274
|
+
/** Account identity from `/alpha/whoami`; reached only through `CommandCodeUsageReport`. */
|
|
269
275
|
interface CommandCodeAccount {
|
|
270
276
|
id: string;
|
|
271
277
|
name: string;
|
|
272
278
|
userName: string;
|
|
273
279
|
}
|
|
274
|
-
/** Usage summary from `/alpha/usage/summary`. */
|
|
280
|
+
/** Usage summary from `/alpha/usage/summary`; reached only through `CommandCodeUsageReport`. */
|
|
275
281
|
interface CommandCodeUsage {
|
|
276
282
|
totalCount: number;
|
|
277
283
|
totalCost: number;
|
|
@@ -326,7 +332,7 @@ interface CommandCodeCredits {
|
|
|
326
332
|
resetAt: number;
|
|
327
333
|
};
|
|
328
334
|
}
|
|
329
|
-
/** Subscription plan state from `/alpha/billing/subscriptions`. */
|
|
335
|
+
/** Subscription plan state from `/alpha/billing/subscriptions`; reached only through `CommandCodeUsageReport`. */
|
|
330
336
|
interface CommandCodePlan {
|
|
331
337
|
/** Raw subscription plan id (e.g. `individual-pro`); empty when unreported. */
|
|
332
338
|
planId: string;
|
package/lib/index.js
CHANGED
|
@@ -38,10 +38,30 @@ function peakHour(at, windows) {
|
|
|
38
38
|
* today, so the combination becoming real is visible before it reaches a user.
|
|
39
39
|
* This ordering is a latent choice, not a verified upstream rule.
|
|
40
40
|
*/
|
|
41
|
-
function requestRates(price, at, contextTokens, table) {
|
|
41
|
+
function requestRates(price, at, contextTokens, table, peakHourCache) {
|
|
42
42
|
const tier = price.contextTiers?.find((tier) => tier.maxContext === void 0 || contextTokens <= tier.maxContext);
|
|
43
43
|
if (tier !== void 0) return tier;
|
|
44
|
-
|
|
44
|
+
if (price.peak === void 0 || at === null) return price;
|
|
45
|
+
let peak = peakHourCache?.get(at);
|
|
46
|
+
if (peak === void 0) {
|
|
47
|
+
peak = peakHour(at, table.peakHours);
|
|
48
|
+
peakHourCache?.set(at, peak);
|
|
49
|
+
}
|
|
50
|
+
return peak ? price.peak : price;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Price one request's token buckets against an already-resolved price row.
|
|
54
|
+
*
|
|
55
|
+
* Split out of the report's per-model lookup so a caller that prices the same
|
|
56
|
+
* candidate model against every fact — the analytics scenario matrix — resolves
|
|
57
|
+
* the price row once per model instead of once per (fact, model) pair. The
|
|
58
|
+
* arithmetic lives here alone so the two callers cannot drift.
|
|
59
|
+
*/
|
|
60
|
+
function requestCost(tokens, price, at, table, peakHourCache) {
|
|
61
|
+
if (price.free === true) return 0;
|
|
62
|
+
const r = requestRates(price, at, tokens.uncachedInputTokens + tokens.cacheReadTokens + tokens.cacheWriteTokens, table, peakHourCache);
|
|
63
|
+
if (tokens.cacheWriteTokens > 0 && r.cacheWriteCost === void 0) return void 0;
|
|
64
|
+
return (tokens.uncachedInputTokens * r.inputCost + tokens.outputTokens * r.outputCost + tokens.cacheReadTokens * r.cacheReadCost + tokens.cacheWriteTokens * (r.cacheWriteCost ?? 0)) / 1e6;
|
|
45
65
|
}
|
|
46
66
|
/** Cache version and wire guard: changing bands/rates must refold historical groups. */
|
|
47
67
|
function pricingKey(table) {
|
|
@@ -3257,6 +3277,7 @@ function foldRequests(session, log) {
|
|
|
3257
3277
|
}
|
|
3258
3278
|
return facts;
|
|
3259
3279
|
}
|
|
3280
|
+
/** The zeroed accumulator `aggregate` adds into. Internal: nothing outside this module reads it. */
|
|
3260
3281
|
const emptyMetrics = () => ({
|
|
3261
3282
|
sessions: 0,
|
|
3262
3283
|
requests: 0,
|
|
@@ -3277,17 +3298,13 @@ const emptyMetrics = () => ({
|
|
|
3277
3298
|
decodeMs: 0,
|
|
3278
3299
|
decodeTokens: 0
|
|
3279
3300
|
});
|
|
3280
|
-
function priceRequest(f, id, table, prices) {
|
|
3301
|
+
function priceRequest(f, id, table, prices, peakHourCache) {
|
|
3281
3302
|
if (!f.tokens) return void 0;
|
|
3282
3303
|
const price = prices.get(id);
|
|
3283
3304
|
if (!price) return void 0;
|
|
3284
|
-
|
|
3285
|
-
const context = f.tokens.uncachedInputTokens + f.tokens.cacheReadTokens + f.tokens.cacheWriteTokens;
|
|
3286
|
-
const r = requestRates(price, f.at, context, table);
|
|
3287
|
-
if (f.tokens.cacheWriteTokens > 0 && r.cacheWriteCost === void 0) return void 0;
|
|
3288
|
-
return (f.tokens.uncachedInputTokens * r.inputCost + f.tokens.outputTokens * r.outputCost + f.tokens.cacheReadTokens * r.cacheReadCost + f.tokens.cacheWriteTokens * (r.cacheWriteCost ?? 0)) / 1e6;
|
|
3305
|
+
return requestCost(f.tokens, price, f.at, table, peakHourCache);
|
|
3289
3306
|
}
|
|
3290
|
-
function aggregate(facts, table, prices) {
|
|
3307
|
+
function aggregate(facts, table, prices, peakHourCache) {
|
|
3291
3308
|
const m = emptyMetrics();
|
|
3292
3309
|
m.sessions = new Set(facts.map((f) => f.session)).size;
|
|
3293
3310
|
for (const f of facts) {
|
|
@@ -3298,7 +3315,7 @@ function aggregate(facts, table, prices) {
|
|
|
3298
3315
|
m.usageSamples++;
|
|
3299
3316
|
for (const k of COST_TOKEN_KEYS) m.tokens[k] += f.tokens[k];
|
|
3300
3317
|
}
|
|
3301
|
-
const cost = priceRequest(f, f.model, table, prices);
|
|
3318
|
+
const cost = priceRequest(f, f.model, table, prices, peakHourCache);
|
|
3302
3319
|
if (cost !== void 0) {
|
|
3303
3320
|
m.pricedRequests++;
|
|
3304
3321
|
m.cost += cost;
|
|
@@ -3323,13 +3340,21 @@ function buildAnalytics(facts, query, table, catalog, now = Date.now()) {
|
|
|
3323
3340
|
const selected = query.mode === "range" ? facts.filter((f) => f.at >= query.from && f.at < query.to) : facts;
|
|
3324
3341
|
const prices = /* @__PURE__ */ new Map();
|
|
3325
3342
|
for (const p of table.models) for (const id of [p.id, p.slug]) if (!prices.has(id)) prices.set(id, p);
|
|
3326
|
-
const
|
|
3327
|
-
const
|
|
3343
|
+
const peakHourCache = /* @__PURE__ */ new Map();
|
|
3344
|
+
const totals = aggregate(selected, table, prices, peakHourCache);
|
|
3345
|
+
const byModel = /* @__PURE__ */ new Map();
|
|
3346
|
+
for (const f of selected) {
|
|
3347
|
+
const bucket = byModel.get(f.model);
|
|
3348
|
+
if (bucket === void 0) byModel.set(f.model, [f]);
|
|
3349
|
+
else bucket.push(f);
|
|
3350
|
+
}
|
|
3351
|
+
const models = [...byModel].map(([id, bucket]) => ({
|
|
3328
3352
|
id,
|
|
3329
|
-
...aggregate(
|
|
3353
|
+
...aggregate(bucket, table, prices, peakHourCache)
|
|
3330
3354
|
})).sort((a, b) => b.cost - a.cost || a.id.localeCompare(b.id));
|
|
3331
3355
|
const scenarios = catalog.map((model) => {
|
|
3332
3356
|
let cost = 0, pricedRequests = 0, excludedRequests = 0, unknownRequests = 0;
|
|
3357
|
+
const price = prices.get(model.id);
|
|
3333
3358
|
for (const f of selected) {
|
|
3334
3359
|
if (!f.tokens) {
|
|
3335
3360
|
unknownRequests++;
|
|
@@ -3340,7 +3365,7 @@ function buildAnalytics(facts, query, table, catalog, now = Date.now()) {
|
|
|
3340
3365
|
excludedRequests++;
|
|
3341
3366
|
continue;
|
|
3342
3367
|
}
|
|
3343
|
-
const priced =
|
|
3368
|
+
const priced = price === void 0 ? void 0 : requestCost(f.tokens, price, f.at, table, peakHourCache);
|
|
3344
3369
|
if (priced === void 0) unknownRequests++;
|
|
3345
3370
|
else {
|
|
3346
3371
|
cost += priced;
|
|
@@ -6307,9 +6332,16 @@ const DEFAULT_API_BASE = "https://api.commandcode.ai";
|
|
|
6307
6332
|
* under the historical name so existing importers are unaffected.
|
|
6308
6333
|
*/
|
|
6309
6334
|
const DEFAULT_GENERATE_MAX_TOKENS = MAX_OUTPUT_TOKEN_LIMIT;
|
|
6335
|
+
/** Catalog fetch budget. Internal: both call sites are in this module. */
|
|
6310
6336
|
const MODELS_TIMEOUT_MS = 1e4;
|
|
6311
6337
|
/** How long the picker's plan-filter billing facts stay cached before refetching. */
|
|
6312
6338
|
const BILLING_ACCESS_TTL_MS = 3e5;
|
|
6339
|
+
/**
|
|
6340
|
+
* How long a learned CLI-only protocol preference stays cached per account.
|
|
6341
|
+
* After this TTL a request may probe Provider API again, so an upgraded Go
|
|
6342
|
+
* account can recover without a restart.
|
|
6343
|
+
*/
|
|
6344
|
+
const PROTOCOL_CACHE_TTL_MS = 9e5;
|
|
6313
6345
|
/** The entry-plan tier weight (`individual-go` in KNOWN_SUBSCRIPTION_PLANS). */
|
|
6314
6346
|
const GO_TIER_WEIGHT = 0;
|
|
6315
6347
|
/** Hard cap on account rotations within one request (one attempt per distinct key). */
|
|
@@ -6960,6 +6992,31 @@ function priceRequestImage(block, model, imageCapable) {
|
|
|
6960
6992
|
};
|
|
6961
6993
|
}
|
|
6962
6994
|
/**
|
|
6995
|
+
* Base64 payloads keyed by the cached request version itself.
|
|
6996
|
+
*
|
|
6997
|
+
* `readImageRequest()` returns one codec object per (attachment, encoder
|
|
6998
|
+
* target) and `requestImages()` reuses that same object for every occurrence in
|
|
6999
|
+
* one generation, but a history that carries an image also replays it in every
|
|
7000
|
+
* later message. Encoding per occurrence therefore re-base64s the same
|
|
7001
|
+
* multi-megabyte buffer once per replay — the single most expensive
|
|
7002
|
+
* per-occurrence step of an image request. Keying on the object makes an
|
|
7003
|
+
* occurrence a map hit, and the WeakMap ties the copy's lifetime to the
|
|
7004
|
+
* harness's own version cache rather than to this plugin.
|
|
7005
|
+
*/
|
|
7006
|
+
const encodedRequestImages = /* @__PURE__ */ new WeakMap();
|
|
7007
|
+
function encodedRequestImage(version) {
|
|
7008
|
+
let encoded = encodedRequestImages.get(version);
|
|
7009
|
+
if (encoded === void 0) {
|
|
7010
|
+
const base64 = Buffer.from(version.data).toString("base64");
|
|
7011
|
+
encoded = {
|
|
7012
|
+
base64,
|
|
7013
|
+
dataUrl: `data:${version.mediaType};base64,${base64}`
|
|
7014
|
+
};
|
|
7015
|
+
encodedRequestImages.set(version, encoded);
|
|
7016
|
+
}
|
|
7017
|
+
return encoded;
|
|
7018
|
+
}
|
|
7019
|
+
/**
|
|
6963
7020
|
* Convert one image reference to the final `/alpha/generate` wire format.
|
|
6964
7021
|
* The official CLI accepts a base64 source internally, then toWireMessages()
|
|
6965
7022
|
* sends a data URL plus mimeType. Use the request version's media type because
|
|
@@ -6969,7 +7026,7 @@ async function imageToCommandCode(ref, readImage) {
|
|
|
6969
7026
|
const version = await readImage(ref);
|
|
6970
7027
|
return {
|
|
6971
7028
|
type: "image",
|
|
6972
|
-
image:
|
|
7029
|
+
image: encodedRequestImage(version).dataUrl,
|
|
6973
7030
|
mimeType: version.mediaType
|
|
6974
7031
|
};
|
|
6975
7032
|
}
|
|
@@ -7102,10 +7159,9 @@ async function messagesToCC(messages, readImage) {
|
|
|
7102
7159
|
* `{ type: 'image_url', image_url: { url: 'data:...;base64,...' } }`.
|
|
7103
7160
|
*/
|
|
7104
7161
|
async function imageToOpenAI(ref, readImage) {
|
|
7105
|
-
const version = await readImage(ref);
|
|
7106
7162
|
return {
|
|
7107
7163
|
type: "image_url",
|
|
7108
|
-
image_url: { url:
|
|
7164
|
+
image_url: { url: encodedRequestImage(await readImage(ref)).dataUrl }
|
|
7109
7165
|
};
|
|
7110
7166
|
}
|
|
7111
7167
|
/**
|
|
@@ -7172,7 +7228,7 @@ async function imageToMessages(ref, readImage) {
|
|
|
7172
7228
|
source: {
|
|
7173
7229
|
type: "base64",
|
|
7174
7230
|
media_type: version.mediaType,
|
|
7175
|
-
data:
|
|
7231
|
+
data: encodedRequestImage(version).base64
|
|
7176
7232
|
}
|
|
7177
7233
|
};
|
|
7178
7234
|
}
|
|
@@ -8174,7 +8230,7 @@ var CommandCodeAdapter = class CommandCodeAdapter extends LlmAdapter {
|
|
|
8174
8230
|
/** Cached protocol decision for a key, or undefined when expired/unknown. */
|
|
8175
8231
|
cachedProtocol(apiBase, apiKey) {
|
|
8176
8232
|
const hit = this.protocolCache.get(this.accountCacheKey(apiBase, apiKey));
|
|
8177
|
-
if (hit === void 0 || Date.now() - hit.at >=
|
|
8233
|
+
if (hit === void 0 || Date.now() - hit.at >= PROTOCOL_CACHE_TTL_MS) return void 0;
|
|
8178
8234
|
return hit.protocol;
|
|
8179
8235
|
}
|
|
8180
8236
|
rememberProtocol(apiBase, apiKey, protocol) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mars-sea/dsh-commandcode-provider",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.3",
|
|
4
4
|
"description": "Unofficial DeepSeek Harness LLM provider plugin for Command Code, ported from pi-commandcode-provider (MIT). Registers the 'commandcode' provider route with a Models-page card and live model catalog.",
|
|
5
5
|
"icon": "./icon.svg",
|
|
6
6
|
"type": "module",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"files": [
|
|
41
41
|
"lib",
|
|
42
|
+
"!lib/**/*.map",
|
|
42
43
|
"assets",
|
|
43
44
|
"icon.svg",
|
|
44
45
|
"locale",
|