@mars-sea/dsh-commandcode-provider 0.13.1 → 0.13.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 +29 -0
- package/README.md +13 -7
- package/README.zh-CN.md +11 -5
- package/lib/client.js +55 -18
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +25 -2
- package/lib/index.js +219 -72
- package/lib/index.js.map +1 -1
- package/package.json +39 -38
package/lib/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { CredentialRef } from "@deepseek-ai/dsh-credentials";
|
|
|
4
4
|
import { TypertRemoteService, TypertSchema } from "@deepseek-ai/dsh-typert-protocol";
|
|
5
5
|
import { WebRuntime, WebSearchProvider, WebSearchRequest, WebSearchResult } from "@deepseek-ai/dsh-web";
|
|
6
6
|
import { Context } from "@deepseek-ai/cordis";
|
|
7
|
-
import { AttachmentStore } from "@deepseek-ai/dsh-attachment";
|
|
7
|
+
import { AttachmentStore, ImageAttachmentRef, ImageRequestTarget } from "@deepseek-ai/dsh-attachment";
|
|
8
8
|
import { CommandDefinition } from "@deepseek-ai/dsh-commands";
|
|
9
9
|
//#region src/provider-errors.d.ts
|
|
10
10
|
/**
|
|
@@ -61,7 +61,7 @@ type CommandCodeProtocol = 'cli' | 'openai' | 'messages';
|
|
|
61
61
|
declare const DEFAULT_MAX_OUTPUT_TOKENS = 131072;
|
|
62
62
|
//#endregion
|
|
63
63
|
//#region src/adapter.d.ts
|
|
64
|
-
declare const COMMAND_CODE_CLI_VERSION = "1.82.
|
|
64
|
+
declare const COMMAND_CODE_CLI_VERSION = "1.82.2";
|
|
65
65
|
declare const DEFAULT_API_BASE = "https://api.commandcode.ai";
|
|
66
66
|
/**
|
|
67
67
|
* The output budget this bundle asks for, and the ceiling it will never exceed.
|
|
@@ -284,6 +284,8 @@ interface CommandCodeUsage {
|
|
|
284
284
|
totalTokensOut: number;
|
|
285
285
|
totalCredits: number;
|
|
286
286
|
periodBasis: string;
|
|
287
|
+
/** 官方汇总返回的统计起点;缺失时不把查询参数当作已确认的统计范围。 */
|
|
288
|
+
periodStart?: number;
|
|
287
289
|
}
|
|
288
290
|
/** Credit/limit state from `/alpha/billing/credits`. */
|
|
289
291
|
interface CommandCodeCredits {
|
|
@@ -338,6 +340,8 @@ interface CommandCodePlan {
|
|
|
338
340
|
monthlyCredits: number | null;
|
|
339
341
|
/** Billing period end in millis; 0 when the endpoint did not report one. */
|
|
340
342
|
currentPeriodEnd: number;
|
|
343
|
+
/** 官方订阅账期起点,毫秒;旧宿主或未报告该字段时缺省。 */
|
|
344
|
+
currentPeriodStart?: number;
|
|
341
345
|
}
|
|
342
346
|
/**
|
|
343
347
|
* Why every account endpoint failed at once (the report then carries no data
|
|
@@ -443,6 +447,25 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
|
|
|
443
447
|
* requirement — the meter throws when the counts differ.
|
|
444
448
|
*/
|
|
445
449
|
imageRequestPricing(_provider: string, model: string): LlmImageRequestPricing | undefined;
|
|
450
|
+
/**
|
|
451
|
+
* The dimensions and byte target this route actually puts on the wire.
|
|
452
|
+
*
|
|
453
|
+
* The base default answers with the NORMALIZED original (`image.width`,
|
|
454
|
+
* `image.height`, `image.bytes`), which is right only for an adapter that
|
|
455
|
+
* does not resize. This route always re-encodes through
|
|
456
|
+
* `readImageRequest(ref, requestImageTarget(ref))` — long edge 1568, encoded
|
|
457
|
+
* bytes capped at 1 MiB — so the default would over-report both dimensions
|
|
458
|
+
* and bytes for every image, most visibly for Retina screenshots.
|
|
459
|
+
*
|
|
460
|
+
* `imageRequestPricing` above already prices at this same target; exposing it
|
|
461
|
+
* here keeps the harness's own readers (the CUA screenshot path calls
|
|
462
|
+
* `ctx.llm.imageRequestTarget`) consistent with what the gateway receives.
|
|
463
|
+
* @param _provider - registered provider route; one route per adapter here.
|
|
464
|
+
* @param _model - exact model id; the target is model-independent on this route.
|
|
465
|
+
* @param image - normalized attachment whose request projection is resolved.
|
|
466
|
+
* @returns the same target `readImageRequest` encodes to, before base64 expansion.
|
|
467
|
+
*/
|
|
468
|
+
imageRequestTarget(_provider: string, _model: string, image: ImageAttachmentRef): ImageRequestTarget;
|
|
446
469
|
listModels(provider: string, opts?: {
|
|
447
470
|
unfiltered?: boolean;
|
|
448
471
|
}): Promise<readonly LlmModelInfo[]>;
|
package/lib/index.js
CHANGED
|
@@ -431,7 +431,7 @@ const KNOWN_EFFORTS = {
|
|
|
431
431
|
"xhigh",
|
|
432
432
|
"max"
|
|
433
433
|
],
|
|
434
|
-
"inclusionai/ling-3.1-flash
|
|
434
|
+
"inclusionai/ling-3.1-flash": [
|
|
435
435
|
"low",
|
|
436
436
|
"medium",
|
|
437
437
|
"high"
|
|
@@ -711,22 +711,20 @@ function requiresMessagesEndpoint(modelId) {
|
|
|
711
711
|
* **Generated — do not hand-edit.** `scripts/sync-output-limits.mjs` rewrites
|
|
712
712
|
* this literal from models.dev; run it after a catalog sync, and use its
|
|
713
713
|
* `--check` in CI. Command Code resells these models through their VENDOR's own
|
|
714
|
-
* API, so the vendor's published ceiling is the value recorded:
|
|
715
|
-
* catalog ids as of 2026-10-
|
|
714
|
+
* API, so the vendor's published ceiling is the value recorded: 76 of the 89
|
|
715
|
+
* catalog ids as of 2026-10-15. Each row carries a comment naming the entry it
|
|
716
716
|
* came from.
|
|
717
717
|
*
|
|
718
|
-
*
|
|
719
|
-
* script's `MANUAL_CEILINGS
|
|
720
|
-
*
|
|
721
|
-
*
|
|
722
|
-
*
|
|
723
|
-
*
|
|
724
|
-
*
|
|
725
|
-
*
|
|
726
|
-
*
|
|
727
|
-
*
|
|
728
|
-
*
|
|
729
|
-
* The 12 unlisted models are ones no vendor publishes and the aggregators
|
|
718
|
+
* One of those 76 rests on more than a vendor lookup, hand-recorded in the
|
|
719
|
+
* script's `MANUAL_CEILINGS`: `inclusionai/ling-3.0-flash-sante:free` (32768)
|
|
720
|
+
* lost both its vendor row and its unanimous third-party vote (vercel files
|
|
721
|
+
* 32000), and is pinned so a regeneration cannot drop a live model's ceiling
|
|
722
|
+
* back to the default. (`gpt-6.1-sol` (128000) needs no pin — OpenAI's own row
|
|
723
|
+
* carries it and every other provider carrying the id agrees.) All are still
|
|
724
|
+
* correctable — a stricter gateway costs one refused request, and
|
|
725
|
+
* `streamRequest()` remembers what the endpoint said.
|
|
726
|
+
*
|
|
727
|
+
* The 13 unlisted models are ones no vendor publishes and the aggregators
|
|
730
728
|
* disagree about. They are NOT a gap: a refusal states the ceiling in full, and
|
|
731
729
|
* `streamRequest()` reads it off, retries once and remembers it for the model
|
|
732
730
|
* (issue #71). A vendor figure the gateway turns out to be stricter than costs
|
|
@@ -772,7 +770,6 @@ const MODEL_OUTPUT_TOKEN_LIMITS = /* @__PURE__ */ new Map([
|
|
|
772
770
|
["gpt-6-sol", 128e3],
|
|
773
771
|
["gpt-6.1-sol", 128e3],
|
|
774
772
|
["inclusionai/ling-3.0-flash-sante:free", 32768],
|
|
775
|
-
["inclusionai/ling-3.1-flash:free", 32768],
|
|
776
773
|
["meituan/LongCat-2.0", 131072],
|
|
777
774
|
["meta/muse-spark-1.1", 131072],
|
|
778
775
|
["meta/muse-spark-1.2", 131072],
|
|
@@ -866,7 +863,7 @@ const KNOWN_PLANS = {
|
|
|
866
863
|
"gpt-6-luna": "go",
|
|
867
864
|
"meituan/LongCat-2.0": "go",
|
|
868
865
|
"inclusionai/ling-3.0-flash-sante:free": "go",
|
|
869
|
-
"inclusionai/ling-3.1-flash
|
|
866
|
+
"inclusionai/ling-3.1-flash": "go",
|
|
870
867
|
"meta/muse-spark-1.2-contributor": "go",
|
|
871
868
|
"meta/muse-spark-1.3-contributor": "go",
|
|
872
869
|
"mistral/mistral-large-4": "go",
|
|
@@ -1076,10 +1073,6 @@ const KNOWN_DEALS = {
|
|
|
1076
1073
|
label: "FREE",
|
|
1077
1074
|
free: true
|
|
1078
1075
|
},
|
|
1079
|
-
"inclusionai/ling-3.1-flash:free": {
|
|
1080
|
-
label: "FREE",
|
|
1081
|
-
free: true
|
|
1082
|
-
},
|
|
1083
1076
|
"stealth/glyph-cluster:free": {
|
|
1084
1077
|
label: "FREE",
|
|
1085
1078
|
free: true
|
|
@@ -1721,8 +1714,8 @@ const MODEL_PRICE_ROWS = [
|
|
|
1721
1714
|
],
|
|
1722
1715
|
allowance: {
|
|
1723
1716
|
go: 10,
|
|
1724
|
-
goat:
|
|
1725
|
-
pro:
|
|
1717
|
+
goat: 100,
|
|
1718
|
+
pro: 100
|
|
1726
1719
|
}
|
|
1727
1720
|
},
|
|
1728
1721
|
{
|
|
@@ -2144,6 +2137,19 @@ const MODEL_PRICE_ROWS = [
|
|
|
2144
2137
|
pro: 30
|
|
2145
2138
|
}
|
|
2146
2139
|
},
|
|
2140
|
+
{
|
|
2141
|
+
id: "ling-3.1-flash",
|
|
2142
|
+
rates: [
|
|
2143
|
+
.3,
|
|
2144
|
+
.9,
|
|
2145
|
+
.06
|
|
2146
|
+
],
|
|
2147
|
+
allowance: {
|
|
2148
|
+
go: 6,
|
|
2149
|
+
goat: 20,
|
|
2150
|
+
pro: 30
|
|
2151
|
+
}
|
|
2152
|
+
},
|
|
2147
2153
|
{
|
|
2148
2154
|
id: "longcat-2.0",
|
|
2149
2155
|
rates: [
|
|
@@ -2554,6 +2560,20 @@ const MODEL_PRICE_ROWS = [
|
|
|
2554
2560
|
pro: 30
|
|
2555
2561
|
}
|
|
2556
2562
|
},
|
|
2563
|
+
{
|
|
2564
|
+
id: "qwen-3.8-max-prime",
|
|
2565
|
+
rates: [
|
|
2566
|
+
4,
|
|
2567
|
+
12,
|
|
2568
|
+
.5,
|
|
2569
|
+
5
|
|
2570
|
+
],
|
|
2571
|
+
allowance: {
|
|
2572
|
+
go: 6,
|
|
2573
|
+
goat: 20,
|
|
2574
|
+
pro: 30
|
|
2575
|
+
}
|
|
2576
|
+
},
|
|
2557
2577
|
{
|
|
2558
2578
|
id: "qwen-3.8-omni-flash",
|
|
2559
2579
|
rates: [
|
|
@@ -2826,6 +2846,12 @@ function tokensOf$1(value) {
|
|
|
2826
2846
|
cacheWriteTokens: u.cacheWriteTokens ?? 0
|
|
2827
2847
|
};
|
|
2828
2848
|
}
|
|
2849
|
+
/** The four buckets of an already-parsed record, or undefined when one is missing. */
|
|
2850
|
+
function costTokensOf(value) {
|
|
2851
|
+
const t = record$3(value);
|
|
2852
|
+
if (!t || !COST_TOKEN_KEYS.every((k) => finite(t[k]))) return void 0;
|
|
2853
|
+
return t;
|
|
2854
|
+
}
|
|
2829
2855
|
/** Current v2 settlements store the last usage in their stream; v1 stores chunk events. */
|
|
2830
2856
|
function usageOf(type, data) {
|
|
2831
2857
|
if (type === "assistant/chunk") {
|
|
@@ -2846,16 +2872,51 @@ function parseState(value) {
|
|
|
2846
2872
|
const s = record$3(value), facts = record$3(s?.facts);
|
|
2847
2873
|
if (!s || !facts || !finite(facts.pricingKey) || !Array.isArray(facts.groups)) throw new TypeError("invalid commandCodeCost state");
|
|
2848
2874
|
const group = (v) => {
|
|
2849
|
-
const g = record$3(v)
|
|
2850
|
-
return !!g && typeof g.provider === "string" && typeof g.model === "string" && (g.at === null || finite(g.at)) && finite(g.contextTokens) &&
|
|
2875
|
+
const g = record$3(v);
|
|
2876
|
+
return !!g && typeof g.provider === "string" && typeof g.model === "string" && (g.at === null || finite(g.at)) && finite(g.contextTokens) && costTokensOf(g.tokens) !== void 0;
|
|
2851
2877
|
};
|
|
2852
2878
|
const sel = record$3(s.selection), last = record$3(s.last);
|
|
2853
|
-
|
|
2854
|
-
|
|
2879
|
+
const summaryTokens = facts.summaryTokens === void 0 ? zeroCostTokens() : costTokensOf(facts.summaryTokens);
|
|
2880
|
+
if (summaryTokens === void 0 || !(s.selection === null || sel && typeof sel.provider === "string" && typeof sel.model === "string") || !(s.at === null || finite(s.at)) || !facts.groups.every(group) || !(s.last === null || last && finite(last.turn) && finite(last.step) && group(last.group))) throw new TypeError("invalid commandCodeCost state");
|
|
2881
|
+
return {
|
|
2882
|
+
...value,
|
|
2883
|
+
facts: {
|
|
2884
|
+
...facts,
|
|
2885
|
+
summaryTokens
|
|
2886
|
+
}
|
|
2887
|
+
};
|
|
2855
2888
|
}
|
|
2856
2889
|
/** Optional registry uses only synchronous parse/view; no new runtime module is required. */
|
|
2857
2890
|
function createCostProjection(table = modelPriceTable()) {
|
|
2858
2891
|
const version = pricingKey(table);
|
|
2892
|
+
/** Groups that still carry tokens; a retry that replaced a group can drive one to zero. */
|
|
2893
|
+
const liveGroups = (groups) => groups.filter((g) => COST_TOKEN_KEYS.some((k) => g.tokens[k] > 0));
|
|
2894
|
+
/**
|
|
2895
|
+
* Fold one settled usage group into `groups`, first undoing the group a retry
|
|
2896
|
+
* supersedes. Shared by turn/step settlements and summary calls, which have
|
|
2897
|
+
* no turn/step of their own.
|
|
2898
|
+
*/
|
|
2899
|
+
const foldGroup = (groups, previous, group, tokens) => {
|
|
2900
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2901
|
+
groups.forEach((g, i) => {
|
|
2902
|
+
const key = costGroupKey(g, table);
|
|
2903
|
+
if (!byKey.has(key)) byKey.set(key, i);
|
|
2904
|
+
});
|
|
2905
|
+
if (previous) {
|
|
2906
|
+
const old = byKey.get(costGroupKey(previous, table));
|
|
2907
|
+
if (old !== void 0) for (const k of COST_TOKEN_KEYS) groups[old].tokens[k] -= previous.tokens[k];
|
|
2908
|
+
}
|
|
2909
|
+
const targetIdx = byKey.get(costGroupKey(group, table));
|
|
2910
|
+
let target = targetIdx === void 0 ? void 0 : groups[targetIdx];
|
|
2911
|
+
if (!target) {
|
|
2912
|
+
target = {
|
|
2913
|
+
...group,
|
|
2914
|
+
tokens: zeroCostTokens()
|
|
2915
|
+
};
|
|
2916
|
+
groups.push(target);
|
|
2917
|
+
}
|
|
2918
|
+
for (const k of COST_TOKEN_KEYS) target.tokens[k] += tokens[k];
|
|
2919
|
+
};
|
|
2859
2920
|
return {
|
|
2860
2921
|
key: "commandCodeCost",
|
|
2861
2922
|
stateVersion: version,
|
|
@@ -2866,7 +2927,8 @@ function createCostProjection(table = modelPriceTable()) {
|
|
|
2866
2927
|
last: null,
|
|
2867
2928
|
facts: {
|
|
2868
2929
|
pricingKey: version,
|
|
2869
|
-
groups: []
|
|
2930
|
+
groups: [],
|
|
2931
|
+
summaryTokens: zeroCostTokens()
|
|
2870
2932
|
}
|
|
2871
2933
|
}),
|
|
2872
2934
|
apply(state, event) {
|
|
@@ -2887,6 +2949,32 @@ function createCostProjection(table = modelPriceTable()) {
|
|
|
2887
2949
|
at: finite(event.time) ? event.time : null,
|
|
2888
2950
|
last: null
|
|
2889
2951
|
};
|
|
2952
|
+
if (event.type === "compaction/summary") {
|
|
2953
|
+
const summary = tokensOf$1(data.usage);
|
|
2954
|
+
if (summary === void 0) return state;
|
|
2955
|
+
const group = {
|
|
2956
|
+
provider: typeof data.provider === "string" ? data.provider : "",
|
|
2957
|
+
model: typeof data.model === "string" ? data.model : "",
|
|
2958
|
+
at: finite(event.time) ? event.time : null,
|
|
2959
|
+
contextTokens: summary.uncachedInputTokens + summary.cacheReadTokens + summary.cacheWriteTokens,
|
|
2960
|
+
tokens: summary
|
|
2961
|
+
};
|
|
2962
|
+
const groups = state.facts.groups.map((g) => ({
|
|
2963
|
+
...g,
|
|
2964
|
+
tokens: { ...g.tokens }
|
|
2965
|
+
}));
|
|
2966
|
+
foldGroup(groups, void 0, group, summary);
|
|
2967
|
+
const summaryTokens = { ...state.facts.summaryTokens };
|
|
2968
|
+
for (const k of COST_TOKEN_KEYS) summaryTokens[k] += summary[k];
|
|
2969
|
+
return {
|
|
2970
|
+
...state,
|
|
2971
|
+
facts: {
|
|
2972
|
+
pricingKey: version,
|
|
2973
|
+
groups: liveGroups(groups),
|
|
2974
|
+
summaryTokens
|
|
2975
|
+
}
|
|
2976
|
+
};
|
|
2977
|
+
}
|
|
2890
2978
|
const tokens = usageOf(event.type, data);
|
|
2891
2979
|
if (tokens === void 0 || !finite(data.turn) || !finite(data.step)) return state;
|
|
2892
2980
|
const previous = state.last?.turn === data.turn && state.last.step === data.step ? state.last.group : void 0;
|
|
@@ -2902,26 +2990,7 @@ function createCostProjection(table = modelPriceTable()) {
|
|
|
2902
2990
|
...g,
|
|
2903
2991
|
tokens: { ...g.tokens }
|
|
2904
2992
|
}));
|
|
2905
|
-
|
|
2906
|
-
groups.forEach((g, i) => {
|
|
2907
|
-
const key = costGroupKey(g, table);
|
|
2908
|
-
if (!byKey.has(key)) byKey.set(key, i);
|
|
2909
|
-
});
|
|
2910
|
-
const groupKey = costGroupKey(group, table);
|
|
2911
|
-
if (previous) {
|
|
2912
|
-
const old = byKey.get(costGroupKey(previous, table));
|
|
2913
|
-
if (old !== void 0) for (const k of COST_TOKEN_KEYS) groups[old].tokens[k] -= previous.tokens[k];
|
|
2914
|
-
}
|
|
2915
|
-
const targetIdx = byKey.get(groupKey);
|
|
2916
|
-
let target = targetIdx === void 0 ? void 0 : groups[targetIdx];
|
|
2917
|
-
if (!target) {
|
|
2918
|
-
target = {
|
|
2919
|
-
...group,
|
|
2920
|
-
tokens: zeroCostTokens()
|
|
2921
|
-
};
|
|
2922
|
-
groups.push(target);
|
|
2923
|
-
}
|
|
2924
|
-
for (const k of COST_TOKEN_KEYS) target.tokens[k] += tokens[k];
|
|
2993
|
+
foldGroup(groups, previous, group, tokens);
|
|
2925
2994
|
return {
|
|
2926
2995
|
...state,
|
|
2927
2996
|
last: {
|
|
@@ -2931,7 +3000,8 @@ function createCostProjection(table = modelPriceTable()) {
|
|
|
2931
3000
|
},
|
|
2932
3001
|
facts: {
|
|
2933
3002
|
pricingKey: version,
|
|
2934
|
-
groups: groups
|
|
3003
|
+
groups: liveGroups(groups),
|
|
3004
|
+
summaryTokens: state.facts.summaryTokens
|
|
2935
3005
|
}
|
|
2936
3006
|
};
|
|
2937
3007
|
},
|
|
@@ -3009,6 +3079,20 @@ function foldRequests(session, log) {
|
|
|
3009
3079
|
}
|
|
3010
3080
|
continue;
|
|
3011
3081
|
}
|
|
3082
|
+
if (event.type === "compaction/summary") {
|
|
3083
|
+
if (event.seq >= log.inheritedEventCount && d.provider === "commandcode") {
|
|
3084
|
+
const tokens = tokensOf(d.usage);
|
|
3085
|
+
facts.push({
|
|
3086
|
+
session,
|
|
3087
|
+
model: typeof d.model === "string" ? d.model : "",
|
|
3088
|
+
at: event.time,
|
|
3089
|
+
retry: false,
|
|
3090
|
+
outcome: "completed",
|
|
3091
|
+
...tokens === void 0 ? {} : { tokens }
|
|
3092
|
+
});
|
|
3093
|
+
}
|
|
3094
|
+
continue;
|
|
3095
|
+
}
|
|
3012
3096
|
if (event.type === "step/start" || event.type === "llm/retry-started") {
|
|
3013
3097
|
begin(event, d, event.type === "llm/retry-started");
|
|
3014
3098
|
continue;
|
|
@@ -4157,8 +4241,14 @@ function parseProviderError(errText) {
|
|
|
4157
4241
|
* `CONTEXT_WINDOW_EXCEEDED`, because that failure has a recovery the harness
|
|
4158
4242
|
* performs and a generic provider error does not. Every message built here is
|
|
4159
4243
|
* bilingual — the harness renders it verbatim in its retry chrome.
|
|
4244
|
+
*
|
|
4245
|
+
* The optional `priorRejection` records a refusal from an earlier transport
|
|
4246
|
+
* attempt in this same call (see {@link isMessagesPermissionRejection}), so a
|
|
4247
|
+
* failed CLI fallback still shows what the Messages surface said first. It is
|
|
4248
|
+
* presentation only: classification, retry budget and failure code all keep
|
|
4249
|
+
* reading the current attempt.
|
|
4160
4250
|
*/
|
|
4161
|
-
function generateHttpError(status, errText, retryAfterMs, parsed = parseProviderError(errText)) {
|
|
4251
|
+
function generateHttpError(status, errText, retryAfterMs, parsed = parseProviderError(errText), priorRejection) {
|
|
4162
4252
|
const providerCode = parsed.nested === void 0 ? void 0 : parsed.code;
|
|
4163
4253
|
const providerDetail = parsed.nested === void 0 ? "" : [
|
|
4164
4254
|
parsed.code,
|
|
@@ -4175,9 +4265,14 @@ function generateHttpError(status, errText, retryAfterMs, parsed = parseProvider
|
|
|
4175
4265
|
if (status === 422 && isZdrNoProviders(providerCode, providerDetail, errText)) return bilingual("PROVIDER_HTTP_ERROR", `Command Code API error 422 (${detail}): zero data retention is enforced but no ZDR-capable upstream is available for this model — turn the ZDR setting off (or use another model)`, "Command Code API 返回 422:已开启零数据保留(ZDR),但该模型当前没有可用的 ZDR 上游——请关闭 ZDR 开关,或改用其他模型", { status: 422 });
|
|
4176
4266
|
if (status === 401) return bilingual("INVALID_CREDENTIAL", `Command Code API error 401 (${detail}): the API key is missing or invalid — check the key stored for COMMANDCODE_API_KEY (Models page) or the auth file`, "Command Code API 返回 401:API 密钥缺失或无效——请在设置页检查 COMMANDCODE_API_KEY 存储的密钥,或检查 auth 文件", { status: 401 });
|
|
4177
4267
|
if (status === 413) return bilingual("PROVIDER_HTTP_ERROR", "Command Code API error 413: the request body exceeds the provider's size limit (the cap is undocumented, measured at about 50 MB) — the session history is too large to send, usually because of accumulated image attachments. Start a new session, or drop the image-heavy part of this one, and retry", "Command Code API 返回 413:请求体超过服务端的体积上限(官方未公开,实测约 50 MB)——会话历史过大,通常是历史图片累积所致。请新建会话,或移除本会话中图片较多的部分后重试", { status: 413 });
|
|
4178
|
-
const
|
|
4179
|
-
const
|
|
4180
|
-
|
|
4268
|
+
const safeIdentifier = (value) => value !== void 0 && /^[A-Za-z0-9_.:-]{1,80}$/.test(value) ? value : void 0;
|
|
4269
|
+
const diagnosticCode = safeIdentifier(parsed.code) ?? /^\s*(MODEL_NOT_IN_PLAN|INSUFFICIENT_CREDITS|USAGE_EXCEEDED|PREMIUM_CREDITS_EXHAUSTED)\b/i.exec(parsed.message ?? "")?.[1];
|
|
4270
|
+
const diagnosticType = safeIdentifier(parsed.type);
|
|
4271
|
+
const identifiers = [diagnosticCode === void 0 ? void 0 : `错误码:${diagnosticCode}`, diagnosticType === void 0 ? void 0 : `错误类型:${diagnosticType}`].filter((value) => value !== void 0);
|
|
4272
|
+
const diagnostic = identifiers.length === 0 ? "" : `(${identifiers.join(";")})`;
|
|
4273
|
+
const priorIdentifier = priorRejection === void 0 ? void 0 : safeIdentifier(priorRejection);
|
|
4274
|
+
const priorNote = priorIdentifier === void 0 ? "" : `此前 Messages 接口以 ${priorIdentifier} 拒绝,已回退 CLI 直连,仍未成功。`;
|
|
4275
|
+
return new LlmError(`Command Code 请求失败(HTTP ${status})${diagnostic}:` + (status === 429 ? "请求受到用量或速率限制,请稍后重试并检查账户额度。" : status === 408 ? "服务端处理超时,请稍后重试。" : status >= 500 ? "上游服务暂时无法完成请求,请稍后重试。" : "服务端拒绝了本次请求,请检查模型、套餐和请求设置。") + priorNote, httpErrorCode(status), {
|
|
4181
4276
|
status,
|
|
4182
4277
|
...retryAfterMs !== void 0 && retryAfterMs > 0 && retryAfterMs <= 9e5 ? { providerRetryAfterMs: retryAfterMs } : {}
|
|
4183
4278
|
});
|
|
@@ -4327,6 +4422,22 @@ function isUpgradeRequiredError(status, errText, parsed = parseProviderError(err
|
|
|
4327
4422
|
if (parsed.message?.toLowerCase().includes("go plan") && parsed.message.toLowerCase().includes("api access")) return true;
|
|
4328
4423
|
return false;
|
|
4329
4424
|
}
|
|
4425
|
+
/**
|
|
4426
|
+
* True when the Messages surface (`/provider/v1/messages`) refused one request
|
|
4427
|
+
* with Anthropic's `permission_error` (issue #84).
|
|
4428
|
+
*
|
|
4429
|
+
* 职责:把「反代 Claude 链路对该账号不放行」这一种拒绝,从普通权限失败里
|
|
4430
|
+
* 单独认出来,交给适配器决定是否改用 CLI 直连(`/alpha/generate`)。
|
|
4431
|
+
*
|
|
4432
|
+
* 为什么边界如此窄:只认 HTTP 403 加上结构化的 `code`/`type` 等于
|
|
4433
|
+
* `permission_error`,不扫原始正文。正文可能回显输入或返回整页英文错误,
|
|
4434
|
+
* 扫文本会把无关失败也变成一次传输切换;而真正「模型不在套餐内」的拒绝
|
|
4435
|
+
* (`MODEL_NOT_IN_PLAN` 等其它标识)继续按原样上报,不被这条规则吞掉。
|
|
4436
|
+
*/
|
|
4437
|
+
function isMessagesPermissionRejection(status, parsed) {
|
|
4438
|
+
if (status !== 403) return false;
|
|
4439
|
+
return (parsed.code ?? parsed.type)?.toLowerCase() === "permission_error";
|
|
4440
|
+
}
|
|
4330
4441
|
//#endregion
|
|
4331
4442
|
//#region src/stream-trace.ts
|
|
4332
4443
|
/**
|
|
@@ -5902,7 +6013,7 @@ var GatewayFacts = class {
|
|
|
5902
6013
|
* per-request options thunk and an API-key resolver from the plugin entry
|
|
5903
6014
|
* (src/index.ts), so a settings change reaches the very next request.
|
|
5904
6015
|
*/
|
|
5905
|
-
const COMMAND_CODE_CLI_VERSION = "1.82.
|
|
6016
|
+
const COMMAND_CODE_CLI_VERSION = "1.82.2";
|
|
5906
6017
|
const DEFAULT_API_BASE = "https://api.commandcode.ai";
|
|
5907
6018
|
/**
|
|
5908
6019
|
* The output budget this bundle asks for, and the ceiling it will never exceed.
|
|
@@ -6057,7 +6168,7 @@ function requestFingerprint(protocol, body) {
|
|
|
6057
6168
|
};
|
|
6058
6169
|
}
|
|
6059
6170
|
/** Parse a billing-period timestamp (ISO string or millis) into millis; 0 when absent/invalid. */
|
|
6060
|
-
function
|
|
6171
|
+
function periodTimestampValue(value) {
|
|
6061
6172
|
const asNumber = numberValue(value);
|
|
6062
6173
|
if (asNumber !== void 0) return asNumber;
|
|
6063
6174
|
const asString = stringValue(value);
|
|
@@ -6906,7 +7017,7 @@ const USAGE_ENDPOINT_COUNT = 4;
|
|
|
6906
7017
|
*/
|
|
6907
7018
|
function parseUsageTotals(usage) {
|
|
6908
7019
|
if (usage === void 0) return void 0;
|
|
6909
|
-
|
|
7020
|
+
const result = {
|
|
6910
7021
|
totalCount: numberValue(usage.totalCount) ?? 0,
|
|
6911
7022
|
totalCost: numberValue(usage.totalCost) ?? 0,
|
|
6912
7023
|
successRate: numberValue(usage.successRate) ?? 0,
|
|
@@ -6915,8 +7026,11 @@ function parseUsageTotals(usage) {
|
|
|
6915
7026
|
totalTokensIn: numberValue(usage.totalTokensIn) ?? 0,
|
|
6916
7027
|
totalTokensOut: numberValue(usage.totalTokensOut) ?? 0,
|
|
6917
7028
|
totalCredits: numberValue(usage.totalCredits) ?? 0,
|
|
6918
|
-
periodBasis: stringValue(usage.periodBasis) ?? "
|
|
7029
|
+
periodBasis: stringValue(usage.periodBasis) ?? "unreported"
|
|
6919
7030
|
};
|
|
7031
|
+
const start = periodTimestampValue(usage.periodStart);
|
|
7032
|
+
if (start > 0 && Number.isFinite(new Date(start).getTime())) result.periodStart = start;
|
|
7033
|
+
return result;
|
|
6920
7034
|
}
|
|
6921
7035
|
/**
|
|
6922
7036
|
* Parse one window block into a window limit, or undefined when the endpoint
|
|
@@ -6962,9 +7076,8 @@ function parseCreditLimits(credits) {
|
|
|
6962
7076
|
return parsed;
|
|
6963
7077
|
}
|
|
6964
7078
|
/**
|
|
6965
|
-
*
|
|
6966
|
-
*
|
|
6967
|
-
* query alongside, so getUsage fetches whoami first and the rest in parallel.
|
|
7079
|
+
* Read the account identity and organization scope from whoami. Every billing
|
|
7080
|
+
* and usage request must use this same organization, so getUsage reads it first.
|
|
6968
7081
|
*/
|
|
6969
7082
|
function parseAccountIdentity(whoami) {
|
|
6970
7083
|
const whoamiData = whoami !== void 0 && isRecord(whoami.user) ? whoami.user : void 0;
|
|
@@ -7533,6 +7646,27 @@ var CommandCodeAdapter = class CommandCodeAdapter extends LlmAdapter {
|
|
|
7533
7646
|
const imageCapable = KNOWN_IMAGE_MODELS.has(model);
|
|
7534
7647
|
return { priceImages: (images) => images.map((image) => priceRequestImage(image, model, imageCapable)) };
|
|
7535
7648
|
}
|
|
7649
|
+
/**
|
|
7650
|
+
* The dimensions and byte target this route actually puts on the wire.
|
|
7651
|
+
*
|
|
7652
|
+
* The base default answers with the NORMALIZED original (`image.width`,
|
|
7653
|
+
* `image.height`, `image.bytes`), which is right only for an adapter that
|
|
7654
|
+
* does not resize. This route always re-encodes through
|
|
7655
|
+
* `readImageRequest(ref, requestImageTarget(ref))` — long edge 1568, encoded
|
|
7656
|
+
* bytes capped at 1 MiB — so the default would over-report both dimensions
|
|
7657
|
+
* and bytes for every image, most visibly for Retina screenshots.
|
|
7658
|
+
*
|
|
7659
|
+
* `imageRequestPricing` above already prices at this same target; exposing it
|
|
7660
|
+
* here keeps the harness's own readers (the CUA screenshot path calls
|
|
7661
|
+
* `ctx.llm.imageRequestTarget`) consistent with what the gateway receives.
|
|
7662
|
+
* @param _provider - registered provider route; one route per adapter here.
|
|
7663
|
+
* @param _model - exact model id; the target is model-independent on this route.
|
|
7664
|
+
* @param image - normalized attachment whose request projection is resolved.
|
|
7665
|
+
* @returns the same target `readImageRequest` encodes to, before base64 expansion.
|
|
7666
|
+
*/
|
|
7667
|
+
imageRequestTarget(_provider, _model, image) {
|
|
7668
|
+
return requestImageTarget(image);
|
|
7669
|
+
}
|
|
7536
7670
|
async listModels(provider, opts) {
|
|
7537
7671
|
const connection = { ...this.deps.options() };
|
|
7538
7672
|
const catalog = await this.gatewayFacts.refresh(connection);
|
|
@@ -7879,16 +8013,22 @@ var CommandCodeAdapter = class CommandCodeAdapter extends LlmAdapter {
|
|
|
7879
8013
|
const report = { failures };
|
|
7880
8014
|
const { account, orgId } = parseAccountIdentity(await getJson("/alpha/whoami"));
|
|
7881
8015
|
if (account !== void 0) report.account = account;
|
|
7882
|
-
const
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
|
|
8016
|
+
const scopedPath = (path, since) => {
|
|
8017
|
+
const params = new URLSearchParams();
|
|
8018
|
+
if (orgId !== void 0) params.set("orgId", orgId);
|
|
8019
|
+
if (since !== void 0) params.set("since", since);
|
|
8020
|
+
const query = params.toString();
|
|
8021
|
+
return query ? `${path}?${query}` : path;
|
|
8022
|
+
};
|
|
8023
|
+
const [credits, subscription] = await Promise.all([getJson(scopedPath("/alpha/billing/credits")), getJson(scopedPath("/alpha/billing/subscriptions"))]);
|
|
8024
|
+
const subData = subscription !== void 0 && isRecord(subscription.data) ? subscription.data : void 0;
|
|
8025
|
+
const rawStart = subData?.currentPeriodStart;
|
|
8026
|
+
const periodStart = periodTimestampValue(rawStart);
|
|
8027
|
+
const validStart = periodStart > 0 && Number.isFinite(new Date(periodStart).getTime());
|
|
8028
|
+
const totals = parseUsageTotals(await getJson(scopedPath("/alpha/usage/summary", validStart ? String(rawStart) : void 0)));
|
|
7888
8029
|
if (totals !== void 0) report.usage = totals;
|
|
7889
8030
|
const limits = parseCreditLimits(credits);
|
|
7890
8031
|
if (limits !== void 0) report.credits = limits;
|
|
7891
|
-
const subData = subscription !== void 0 && isRecord(subscription.data) ? subscription.data : void 0;
|
|
7892
8032
|
const creditsData = credits !== void 0 && isRecord(credits.credits) ? credits.credits : void 0;
|
|
7893
8033
|
const planId = stringValue(subData?.planId) ?? stringValue(creditsData?.planId);
|
|
7894
8034
|
if (subData !== void 0 || planId !== void 0) {
|
|
@@ -7898,8 +8038,9 @@ var CommandCodeAdapter = class CommandCodeAdapter extends LlmAdapter {
|
|
|
7898
8038
|
name: info?.name ?? planId ?? "",
|
|
7899
8039
|
status: stringValue(subData?.status) ?? "",
|
|
7900
8040
|
monthlyCredits: info?.monthlyCredits ?? null,
|
|
7901
|
-
currentPeriodEnd:
|
|
8041
|
+
currentPeriodEnd: periodTimestampValue(subData?.currentPeriodEnd)
|
|
7902
8042
|
};
|
|
8043
|
+
if (validStart) report.plan.currentPeriodStart = periodStart;
|
|
7903
8044
|
}
|
|
7904
8045
|
const blocked = classifyTotalFailure(failures, failed);
|
|
7905
8046
|
if (blocked !== void 0) report.blocked = blocked;
|
|
@@ -8053,6 +8194,7 @@ var CommandCodeAdapter = class CommandCodeAdapter extends LlmAdapter {
|
|
|
8053
8194
|
const reasoningEffort = effort === "off" && declared === void 0 ? void 0 : declared;
|
|
8054
8195
|
const systemText = [options.system ?? "", ...options.messages.filter((m) => m.role === "system").map((m) => m.content.map(blockText).filter(Boolean).join("\n"))].filter(Boolean).join("\n\n");
|
|
8055
8196
|
let protocol = this.resolveProtocol(connection, apiKey, options.model, modelEntry);
|
|
8197
|
+
let messagesPermissionRejection;
|
|
8056
8198
|
let requestOptions = withSurfaceOffload(options, this.surfaceOffload, REQUEST_IMAGE_BUDGETS[0], connection.offloadSeenImagesForCache === true && protocol === "cli" ? options.model : void 0);
|
|
8057
8199
|
const buildBody = async (target) => {
|
|
8058
8200
|
const finishBody = timing.phase("body");
|
|
@@ -8143,8 +8285,10 @@ var CommandCodeAdapter = class CommandCodeAdapter extends LlmAdapter {
|
|
|
8143
8285
|
break;
|
|
8144
8286
|
}
|
|
8145
8287
|
const providerError = parseProviderError(attempt.errText);
|
|
8146
|
-
|
|
8288
|
+
const messagesPermissionDenied = protocol === "messages" && isMessagesPermissionRejection(attempt.status, providerError);
|
|
8289
|
+
if (protocol !== "cli" && (messagesPermissionDenied || isUpgradeRequiredError(attempt.status, attempt.errText, providerError))) {
|
|
8147
8290
|
const wasMessages = protocol === "messages";
|
|
8291
|
+
if (messagesPermissionDenied) messagesPermissionRejection = providerError.code ?? providerError.type;
|
|
8148
8292
|
protocol = "cli";
|
|
8149
8293
|
if (!wasMessages) this.rememberProtocol(connection.apiBase, apiKey, "cli");
|
|
8150
8294
|
requestOptions = withSurfaceOffload(options, this.surfaceOffload, REQUEST_IMAGE_BUDGETS[0], connection.offloadSeenImagesForCache === true ? options.model : void 0);
|
|
@@ -8164,6 +8308,7 @@ var CommandCodeAdapter = class CommandCodeAdapter extends LlmAdapter {
|
|
|
8164
8308
|
});
|
|
8165
8309
|
if (next !== void 0 && !tried.has(next)) {
|
|
8166
8310
|
apiKey = next;
|
|
8311
|
+
messagesPermissionRejection = void 0;
|
|
8167
8312
|
const nextProtocol = this.resolveProtocol(connection, apiKey, options.model, modelEntry);
|
|
8168
8313
|
if (nextProtocol !== protocol) {
|
|
8169
8314
|
protocol = nextProtocol;
|
|
@@ -8183,7 +8328,7 @@ var CommandCodeAdapter = class CommandCodeAdapter extends LlmAdapter {
|
|
|
8183
8328
|
...wait > 0 && wait <= 9e5 ? { providerRetryAfterMs: wait } : {}
|
|
8184
8329
|
});
|
|
8185
8330
|
}
|
|
8186
|
-
throw generateHttpError(attempt.status, attempt.errText, attempt.retryAfterMs, providerError);
|
|
8331
|
+
throw generateHttpError(attempt.status, attempt.errText, attempt.retryAfterMs, providerError, messagesPermissionRejection);
|
|
8187
8332
|
}
|
|
8188
8333
|
} catch (error) {
|
|
8189
8334
|
trace.record("connect-error", {
|
|
@@ -8365,7 +8510,7 @@ function renderReport(report, locale, title) {
|
|
|
8365
8510
|
}
|
|
8366
8511
|
if (report.usage) {
|
|
8367
8512
|
const u = report.usage;
|
|
8368
|
-
lines.push(commandCopy(locale, "usageHeader"), commandCopy(locale, "requestsLine").replace("{n}", String(u.
|
|
8513
|
+
lines.push(commandCopy(locale, "usageHeader"), commandCopy(locale, "requestsLine").replace("{n}", String(u.totalCount)).replace("{f}", String(u.failedCount)).replace("{r}", successRateText(u.successRate)), commandCopy(locale, "costLine").replace("{money}", money(u.totalCost)).replace("{credits}", moneyShort(u.totalCredits)), commandCopy(locale, "tokensLine").replace("{in}", tokensCompact(u.totalTokensIn)).replace("{out}", tokensCompact(u.totalTokensOut)), "");
|
|
8369
8514
|
}
|
|
8370
8515
|
if (report.credits) {
|
|
8371
8516
|
const c = report.credits;
|
|
@@ -8486,6 +8631,7 @@ function parseUsageReport(value) {
|
|
|
8486
8631
|
totalCredits: numberField(usage, "totalCredits", "usage.totalCredits"),
|
|
8487
8632
|
periodBasis: stringField$1(usage, "periodBasis", "usage.periodBasis")
|
|
8488
8633
|
};
|
|
8634
|
+
if (usage.periodStart !== void 0) report.usage.periodStart = numberField(usage, "periodStart", "usage.periodStart");
|
|
8489
8635
|
}
|
|
8490
8636
|
if (source.credits !== void 0) {
|
|
8491
8637
|
const credits = record$1(source.credits, "credits");
|
|
@@ -8513,6 +8659,7 @@ function parseUsageReport(value) {
|
|
|
8513
8659
|
monthlyCredits: monthly,
|
|
8514
8660
|
currentPeriodEnd: numberField(plan, "currentPeriodEnd", "plan.currentPeriodEnd")
|
|
8515
8661
|
};
|
|
8662
|
+
if (plan.currentPeriodStart !== void 0) report.plan.currentPeriodStart = numberField(plan, "currentPeriodStart", "plan.currentPeriodStart");
|
|
8516
8663
|
}
|
|
8517
8664
|
return report;
|
|
8518
8665
|
}
|
|
@@ -10756,7 +10903,7 @@ function apply(ctx, config) {
|
|
|
10756
10903
|
const resolved = await scopedPool(connection).resolveKey(model === void 0 ? {} : { model });
|
|
10757
10904
|
if (resolved !== void 0) return assertUsableApiKey(resolved.key, "llm-commandcode", resolved.slot.ref ?? `${resolved.slot.label} (config.apiKey)`);
|
|
10758
10905
|
const ref = connection.apiKeyEnv;
|
|
10759
|
-
throw new LlmError(`llm-commandcode: no API key for provider route "${PROVIDER}"; store ${ref} through the credentials service (the web Models page writes it), export it in the launching environment, set config.apiKey, or run \`command-code login\` to write ~/.commandcode/auth.json
|
|
10906
|
+
throw new LlmError(`llm-commandcode: no API key for provider route "${PROVIDER}"; store ${ref} through the credentials service (the web Models page writes it), export it in the launching environment, set config.apiKey, or run \`command-code login\` to write ~/.commandcode/auth.json. The headless profile mounts no credentials service, so a key saved only in the store never reaches it: export the variable or put it in a .env file for those runs.`, "MISSING_CREDENTIAL");
|
|
10760
10907
|
};
|
|
10761
10908
|
const adapter = new CommandCodeAdapter({
|
|
10762
10909
|
options,
|