@mars-sea/dsh-commandcode-provider 0.14.1 → 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 +26 -1
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/lib/client.js +205 -122
- 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/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",
|