@eddyskywalker/dsh-chatgpt-subscription 0.29.0 → 0.30.0
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 +27 -0
- package/README.md +11 -2
- package/lib/client.js +18 -16
- package/lib/client.js.map +1 -1
- package/lib/index.js +569 -136
- package/lib/types/client/minimax-code/MinimaxCodeSection.d.ts +8 -5
- package/lib/types/client/minimax-code/MinimaxCodeSection.d.ts.map +1 -1
- package/lib/types/client/minimax-code/locales.d.ts +6 -6
- package/lib/types/host/common/context-overflow.d.ts.map +1 -1
- package/lib/types/host/minimax-code/adapter.d.ts +14 -0
- package/lib/types/host/minimax-code/adapter.d.ts.map +1 -1
- package/lib/types/host/minimax-code/checkin-gateway.d.ts +36 -0
- package/lib/types/host/minimax-code/checkin-gateway.d.ts.map +1 -1
- package/lib/types/host/minimax-code/checkin.d.ts +60 -2
- package/lib/types/host/minimax-code/checkin.d.ts.map +1 -1
- package/lib/types/host/minimax-code/mapper.d.ts +51 -19
- package/lib/types/host/minimax-code/mapper.d.ts.map +1 -1
- package/lib/types/host/minimax-code/model-catalog.d.ts +40 -15
- package/lib/types/host/minimax-code/model-catalog.d.ts.map +1 -1
- package/lib/types/host/minimax-code/token-store.d.ts.map +1 -1
- package/lib/types/host/minimax-code/types.d.ts.map +1 -1
- package/lib/types/host/proxy-manager.d.ts.map +1 -1
- package/lib/types/shared/minimax-code-contracts.d.ts +17 -3
- package/lib/types/shared/minimax-code-contracts.d.ts.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -50,10 +50,9 @@ const MINIMAX_CODE_PROVIDER_NAME = "MiniMax Code(编程订阅)";
|
|
|
50
50
|
* 设置卡片只渲染这一份列表:档位是线路级的词汇表(`isMinimaxCodeReasoningEffort`
|
|
51
51
|
* 就是按它校验的),而不是单个模型的能力表。某个模型实际接受哪些档位由
|
|
52
52
|
* `MinimaxCodeModelOption.reasoningEfforts` 单独给出——把两者合成一份会让卡片
|
|
53
|
-
* 在给一个只认
|
|
53
|
+
* 在给一个只认 high 的模型显示 max 时无从判断是模型不支持还是文案没写。
|
|
54
54
|
*/
|
|
55
55
|
const MINIMAX_CODE_REASONING_EFFORTS = [
|
|
56
|
-
"default",
|
|
57
56
|
"low",
|
|
58
57
|
"medium",
|
|
59
58
|
"high",
|
|
@@ -802,7 +801,7 @@ async function rehydrateSnapshot(key) {
|
|
|
802
801
|
* so a backend that flattens the envelope does not read as an empty catalog.
|
|
803
802
|
*/
|
|
804
803
|
function parseListing(payload) {
|
|
805
|
-
const record = asRecord$
|
|
804
|
+
const record = asRecord$16(payload);
|
|
806
805
|
const models = Array.isArray(payload) ? payload : record?.models;
|
|
807
806
|
if (!Array.isArray(models)) return [];
|
|
808
807
|
return models.flatMap((item) => parseListingEntry$1(item));
|
|
@@ -816,7 +815,7 @@ function parseListing(payload) {
|
|
|
816
815
|
* back to a conservative answer rather than to a guess.
|
|
817
816
|
*/
|
|
818
817
|
function parseListingEntry$1(value) {
|
|
819
|
-
const record = asRecord$
|
|
818
|
+
const record = asRecord$16(value);
|
|
820
819
|
if (record === void 0) return [];
|
|
821
820
|
const id = asString$25(record.slug) ?? asString$25(record.id);
|
|
822
821
|
if (id === void 0) return [];
|
|
@@ -852,7 +851,7 @@ function parseEfforts(value) {
|
|
|
852
851
|
if (!Array.isArray(value)) return null;
|
|
853
852
|
const out = [];
|
|
854
853
|
for (const item of value) {
|
|
855
|
-
const effort = asString$25(item) ?? asString$25(asRecord$
|
|
854
|
+
const effort = asString$25(item) ?? asString$25(asRecord$16(item)?.effort);
|
|
856
855
|
if (effort !== void 0 && !out.includes(effort)) out.push(effort);
|
|
857
856
|
}
|
|
858
857
|
return out.length > 0 ? out : null;
|
|
@@ -867,7 +866,7 @@ function parseEfforts(value) {
|
|
|
867
866
|
function accountKeyFor$1(credentials) {
|
|
868
867
|
return credentials.accountId || "default";
|
|
869
868
|
}
|
|
870
|
-
function asRecord$
|
|
869
|
+
function asRecord$16(value) {
|
|
871
870
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
872
871
|
}
|
|
873
872
|
function asString$25(value) {
|
|
@@ -4423,7 +4422,7 @@ function isContextOverflow(error) {
|
|
|
4423
4422
|
const parsed = JSON.parse(error);
|
|
4424
4423
|
if (typeof parsed === "object" && parsed !== null) return isContextOverflow(parsed);
|
|
4425
4424
|
} catch {}
|
|
4426
|
-
return /\bcontext[_ -](?:length|window)[_ -](?:exceeded|overflow|limit[_ -]exceeded)\b/i.test(error) || /\b(?:maximum|max)(?: allowed| supported)? context (?:length|window)\b/i.test(error) && /\b(?:exceed(?:s|ed)?|requested|resulted in|reduce|too (?:long|large))\b/i.test(error) || /\b(?:prompt|input|request) (?:is )?too (?:long|large) for (?:the |this )?(?:model(?:'s)? )?context\b/i.test(error) || /\b(?:prompt|input) (?:is )?too long:\s*[\d,]+ tokens?\s*>\s*[\d,]+\s*(?:tokens?\s*)?maximum\b/i.test(error) || /\brequest exceeded model token limit\b/i.test(error) || /\b(?:input|prompt|request|messages?)\b.{0,40}\bexceed(?:s|ed)?\b.{0,40}\b(?:model(?:'s)? )?context (?:length|window)\b/i.test(error);
|
|
4425
|
+
return /\bcontext[_ -](?:length|window)[_ -](?:exceeded|overflow|limit[_ -]exceeded)\b/i.test(error) || /\bcontext window exceeds limit\b/i.test(error) || /\b(?:maximum|max)(?: allowed| supported)? context (?:length|window)\b/i.test(error) && /\b(?:exceed(?:s|ed)?|requested|resulted in|reduce|too (?:long|large))\b/i.test(error) || /\b(?:prompt|input|request) (?:is )?too (?:long|large) for (?:the |this )?(?:model(?:'s)? )?context\b/i.test(error) || /\b(?:prompt|input) (?:is )?too long:\s*[\d,]+ tokens?\s*>\s*[\d,]+\s*(?:tokens?\s*)?maximum\b/i.test(error) || /\bprompt is too long\b(?!\s+in\s+bytes)/i.test(error) || /\binput is too long\b(?!\s+in\s+bytes)/i.test(error) || /\brequest exceeded model token limit\b/i.test(error) || /\b(?:input|prompt|request|messages?)\b.{0,40}\bexceed(?:s|ed)?\b.{0,40}\b(?:model(?:'s)? )?context (?:length|window)\b/i.test(error);
|
|
4427
4426
|
}
|
|
4428
4427
|
if (typeof error !== "object" || error === null || Array.isArray(error)) return false;
|
|
4429
4428
|
const fields = error;
|
|
@@ -4431,7 +4430,10 @@ function isContextOverflow(error) {
|
|
|
4431
4430
|
fields.code,
|
|
4432
4431
|
fields.type,
|
|
4433
4432
|
fields.message,
|
|
4434
|
-
fields.error
|
|
4433
|
+
fields.error,
|
|
4434
|
+
fields.errorReason,
|
|
4435
|
+
fields.status_msg,
|
|
4436
|
+
fields.base_resp
|
|
4435
4437
|
].some((value) => typeof value === "string" ? isContextOverflow(value) : value !== error && value !== void 0 && isContextOverflow(value));
|
|
4436
4438
|
}
|
|
4437
4439
|
/** Only request-rejection statuses can be reclassified as context overflow. */
|
|
@@ -8537,10 +8539,24 @@ function readSource(value) {
|
|
|
8537
8539
|
...publishedAt !== null ? { publishedAt } : {}
|
|
8538
8540
|
};
|
|
8539
8541
|
}
|
|
8542
|
+
/**
|
|
8543
|
+
* The answer text, as the endpoint actually returns it.
|
|
8544
|
+
*
|
|
8545
|
+
* The live `/alpha/search` response carries three top-level fields:
|
|
8546
|
+
* `encrypted_output` (an opaque blob), `output` (the answer, with inline
|
|
8547
|
+
* citation markers) and `results` (the source list). The names above are the
|
|
8548
|
+
* older shapes the endpoint has used; `output` is the one it uses now, and
|
|
8549
|
+
* leaving it out meant every real search came back with NO answer text - the
|
|
8550
|
+
* harness tool then reported a bare source list, which reads as a working
|
|
8551
|
+
* search that simply found nothing to say.
|
|
8552
|
+
*
|
|
8553
|
+
* `encrypted_output` is deliberately not consulted: it is the encrypted
|
|
8554
|
+
* counterpart of `output`, not a fallback for it.
|
|
8555
|
+
*/
|
|
8540
8556
|
function readContent(data) {
|
|
8541
8557
|
const root = record$4(data);
|
|
8542
8558
|
if (root === null) return void 0;
|
|
8543
|
-
return string$1(root.content) ?? string$1(root.output_text) ?? string$1(root.summary) ?? void 0;
|
|
8559
|
+
return string$1(root.content) ?? string$1(root.output_text) ?? string$1(root.summary) ?? string$1(root.output) ?? void 0;
|
|
8544
8560
|
}
|
|
8545
8561
|
function dedupeSources(sources) {
|
|
8546
8562
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -8573,6 +8589,22 @@ function isSource(value) {
|
|
|
8573
8589
|
//#endregion
|
|
8574
8590
|
//#region src/host/proxy-manager.ts
|
|
8575
8591
|
const SYSTEM_PROXY_CACHE_TTL_MS = 5e3;
|
|
8592
|
+
/**
|
|
8593
|
+
* How long a proxied connection may take to establish.
|
|
8594
|
+
*
|
|
8595
|
+
* undici's default is 10 seconds, and it covers the TLS handshake with the
|
|
8596
|
+
* ORIGIN, not merely the hop to the proxy: a proxy whose route to
|
|
8597
|
+
* chatgpt.com goes through a slow node measured 1.2s to 18s for that
|
|
8598
|
+
* handshake alone, and the request after it took 31s end to end. The default
|
|
8599
|
+
* therefore killed requests that would have succeeded seconds later, and it
|
|
8600
|
+
* killed them as an opaque `fetch failed` - the underlying
|
|
8601
|
+
* `UND_ERR_CONNECT_TIMEOUT` never named the proxy, so the failure read as
|
|
8602
|
+
* "the search is broken" rather than "the line was slow".
|
|
8603
|
+
*
|
|
8604
|
+
* 60 seconds covers the measured worst case with room to spare. It bounds the
|
|
8605
|
+
* CONNECT phase only; the request itself keeps undici's own timeouts.
|
|
8606
|
+
*/
|
|
8607
|
+
const PROXY_CONNECT_TIMEOUT_MS = 6e4;
|
|
8576
8608
|
function normalizeProxyUrl(rawUrl) {
|
|
8577
8609
|
const trimmed = rawUrl.trim();
|
|
8578
8610
|
if (!trimmed) return "";
|
|
@@ -8726,7 +8758,10 @@ var ProxyManager = class {
|
|
|
8726
8758
|
getOrCreateAgent(proxyUrl) {
|
|
8727
8759
|
let agent = this.agents.get(proxyUrl);
|
|
8728
8760
|
if (!agent) {
|
|
8729
|
-
agent = new ProxyAgent(
|
|
8761
|
+
agent = new ProxyAgent({
|
|
8762
|
+
uri: proxyUrl,
|
|
8763
|
+
connectTimeout: PROXY_CONNECT_TIMEOUT_MS
|
|
8764
|
+
});
|
|
8730
8765
|
this.agents.set(proxyUrl, agent);
|
|
8731
8766
|
}
|
|
8732
8767
|
return agent;
|
|
@@ -14289,7 +14324,7 @@ function timeoutSignal$4(signal, ms) {
|
|
|
14289
14324
|
function isRecord$38(value) {
|
|
14290
14325
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14291
14326
|
}
|
|
14292
|
-
function asRecord$
|
|
14327
|
+
function asRecord$15(value) {
|
|
14293
14328
|
return isRecord$38(value) ? value : void 0;
|
|
14294
14329
|
}
|
|
14295
14330
|
function asString$23(value) {
|
|
@@ -14368,16 +14403,16 @@ const ORG_KEYS = [
|
|
|
14368
14403
|
];
|
|
14369
14404
|
/** Map `/alpha/whoami` (or a stored key's own facts) onto the public account DTO. */
|
|
14370
14405
|
function parseWhoami(payload, fallback = {}) {
|
|
14371
|
-
const root = asRecord$
|
|
14372
|
-
const data = asRecord$
|
|
14373
|
-
const user = asRecord$
|
|
14374
|
-
const org = asRecord$
|
|
14375
|
-
const key = asRecord$
|
|
14406
|
+
const root = asRecord$15(payload) ?? {};
|
|
14407
|
+
const data = asRecord$15(root.data) ?? root;
|
|
14408
|
+
const user = asRecord$15(deepValue(data, USER_KEYS)) ?? {};
|
|
14409
|
+
const org = asRecord$15(deepValue(data, ORG_KEYS)) ?? {};
|
|
14410
|
+
const key = asRecord$15(deepValue(data, [
|
|
14376
14411
|
"apiKey",
|
|
14377
14412
|
"key",
|
|
14378
14413
|
"credential"
|
|
14379
14414
|
])) ?? {};
|
|
14380
|
-
const subscription = asRecord$
|
|
14415
|
+
const subscription = asRecord$15(deepValue(data, [
|
|
14381
14416
|
"subscription",
|
|
14382
14417
|
"plan",
|
|
14383
14418
|
"tier"
|
|
@@ -14481,14 +14516,14 @@ function humanizeWindowKey$1(key) {
|
|
|
14481
14516
|
* — so they are read here first, by name.
|
|
14482
14517
|
*/
|
|
14483
14518
|
function parseWindowLimits(payload, consumed = []) {
|
|
14484
|
-
const root = asRecord$
|
|
14485
|
-
const limits = asRecord$
|
|
14519
|
+
const root = asRecord$15(payload) ?? {};
|
|
14520
|
+
const limits = asRecord$15(deepValue(asRecord$15(root.data) ?? root, ["windowLimits", "window_limits"]));
|
|
14486
14521
|
if (limits === void 0) return [];
|
|
14487
14522
|
const keys = [...WINDOW_ORDER$1.filter((key) => limits[key] !== void 0), ...Object.keys(limits).filter((key) => !WINDOW_ORDER$1.includes(key))];
|
|
14488
14523
|
const meters = [];
|
|
14489
14524
|
for (const key of keys) {
|
|
14490
14525
|
if (key === "limited" || key === "exceeded") continue;
|
|
14491
|
-
const record = asRecord$
|
|
14526
|
+
const record = asRecord$15(limits[key]);
|
|
14492
14527
|
if (record === void 0) continue;
|
|
14493
14528
|
const cap = firstNumber$2(record, [
|
|
14494
14529
|
"cap",
|
|
@@ -14522,8 +14557,8 @@ function parseWindowLimits(payload, consumed = []) {
|
|
|
14522
14557
|
* source for a remaining balance.
|
|
14523
14558
|
*/
|
|
14524
14559
|
function parseCreditBalances(payload, consumed = []) {
|
|
14525
|
-
const root = asRecord$
|
|
14526
|
-
const credits = asRecord$
|
|
14560
|
+
const root = asRecord$15(payload) ?? {};
|
|
14561
|
+
const credits = asRecord$15(deepValue(asRecord$15(root.data) ?? root, ["credits"]));
|
|
14527
14562
|
if (credits === void 0) return [];
|
|
14528
14563
|
const monthly = firstNumber$2(credits, ["monthlyCredits", "monthly_credits"]);
|
|
14529
14564
|
const purchased = firstNumber$2(credits, ["purchasedCredits", "purchased_credits"]);
|
|
@@ -14570,13 +14605,13 @@ function parsePlanId(payloads) {
|
|
|
14570
14605
|
* subscription's remaining credits as usable would be worse than showing none.
|
|
14571
14606
|
*/
|
|
14572
14607
|
function parseSubscriptionStatus(payload) {
|
|
14573
|
-
const root = asRecord$
|
|
14574
|
-
return asString$23(deepValue(asRecord$
|
|
14608
|
+
const root = asRecord$15(payload) ?? {};
|
|
14609
|
+
return asString$23(deepValue(asRecord$15(root.data) ?? root, ["status"])) ?? null;
|
|
14575
14610
|
}
|
|
14576
14611
|
/** End of the current billing period, in Unix milliseconds. */
|
|
14577
14612
|
function parseSubscriptionPeriodEnd(payload) {
|
|
14578
|
-
const root = asRecord$
|
|
14579
|
-
return parseTimestamp$1(deepValue(asRecord$
|
|
14613
|
+
const root = asRecord$15(payload) ?? {};
|
|
14614
|
+
return parseTimestamp$1(deepValue(asRecord$15(root.data) ?? root, ["currentPeriodEnd", "current_period_end"]));
|
|
14580
14615
|
}
|
|
14581
14616
|
/**
|
|
14582
14617
|
* Turn one billing/usage payload into meters.
|
|
@@ -14793,9 +14828,9 @@ function parseUsageWindows$1(payload) {
|
|
|
14793
14828
|
return windows;
|
|
14794
14829
|
}
|
|
14795
14830
|
function extractCreditsBalance(payload) {
|
|
14796
|
-
const root = asRecord$
|
|
14797
|
-
const data = asRecord$
|
|
14798
|
-
const credits = asRecord$
|
|
14831
|
+
const root = asRecord$15(payload) ?? {};
|
|
14832
|
+
const data = asRecord$15(root.data) ?? root;
|
|
14833
|
+
const credits = asRecord$15(data.credits);
|
|
14799
14834
|
if (credits !== void 0) {
|
|
14800
14835
|
const pools = [
|
|
14801
14836
|
"monthlyCredits",
|
|
@@ -14839,11 +14874,11 @@ let catalogInFlight$4 = null;
|
|
|
14839
14874
|
const catalogSnapshotScopesLoaded$3 = /* @__PURE__ */ new Set();
|
|
14840
14875
|
/** Parse the public `/provider/v1/models` payload. */
|
|
14841
14876
|
function parseProviderModels(payload) {
|
|
14842
|
-
const root = asRecord$
|
|
14877
|
+
const root = asRecord$15(payload) ?? {};
|
|
14843
14878
|
const list = Array.isArray(root.data) ? root.data : Array.isArray(payload) ? payload : [];
|
|
14844
14879
|
const models = [];
|
|
14845
14880
|
for (const entry of list) {
|
|
14846
|
-
const record = asRecord$
|
|
14881
|
+
const record = asRecord$15(entry);
|
|
14847
14882
|
if (!record) continue;
|
|
14848
14883
|
const id = firstString$1(record, [
|
|
14849
14884
|
"id",
|
|
@@ -21788,7 +21823,7 @@ function withTimeout$7(signal, ms) {
|
|
|
21788
21823
|
function oauthEndpoint(host, endpoint) {
|
|
21789
21824
|
return `${host.replace(/\/+$/, "")}${endpoint}`;
|
|
21790
21825
|
}
|
|
21791
|
-
function asRecord$
|
|
21826
|
+
function asRecord$14(value) {
|
|
21792
21827
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
21793
21828
|
}
|
|
21794
21829
|
/**
|
|
@@ -21799,8 +21834,8 @@ function asRecord$13(value) {
|
|
|
21799
21834
|
* caller decides whether the flow continues.
|
|
21800
21835
|
*/
|
|
21801
21836
|
function oauthErrorFields$2(payload) {
|
|
21802
|
-
const root = asRecord$
|
|
21803
|
-
const nested = asRecord$
|
|
21837
|
+
const root = asRecord$14(payload) ?? {};
|
|
21838
|
+
const nested = asRecord$14(root.error);
|
|
21804
21839
|
if (nested !== void 0) return {
|
|
21805
21840
|
code: typeof nested.code === "string" ? nested.code : "",
|
|
21806
21841
|
description: String(nested.message ?? nested.error_description ?? nested.detail ?? nested.type ?? "")
|
|
@@ -21832,7 +21867,7 @@ async function requestDeviceAuthorization(options = {}) {
|
|
|
21832
21867
|
const { description } = oauthErrorFields$2(payload);
|
|
21833
21868
|
throw new Error(`Device authorization failed (${response.status})${description ? `: ${description}` : ""}`);
|
|
21834
21869
|
}
|
|
21835
|
-
const record = asRecord$
|
|
21870
|
+
const record = asRecord$14(payload) ?? {};
|
|
21836
21871
|
const userCode = typeof record.user_code === "string" ? record.user_code : "";
|
|
21837
21872
|
const deviceCode = typeof record.device_code === "string" ? record.device_code : "";
|
|
21838
21873
|
const complete = typeof record.verification_uri_complete === "string" ? record.verification_uri_complete : "";
|
|
@@ -21874,7 +21909,7 @@ async function pollDeviceToken$1(host, deviceCode, options) {
|
|
|
21874
21909
|
signal: withTimeout$7(options.signal, OAUTH_TIMEOUT_MS$2)
|
|
21875
21910
|
});
|
|
21876
21911
|
const payload = await response.json().catch(() => void 0);
|
|
21877
|
-
const record = asRecord$
|
|
21912
|
+
const record = asRecord$14(payload) ?? {};
|
|
21878
21913
|
if (response.status === 200 && typeof record.access_token === "string" && record.access_token !== "") return {
|
|
21879
21914
|
kind: "success",
|
|
21880
21915
|
token: parseTokenResponse$2(record)
|
|
@@ -22000,7 +22035,7 @@ async function refreshAccessToken$1(refreshToken, options = {}) {
|
|
|
22000
22035
|
const payload = await response.json().catch(() => void 0);
|
|
22001
22036
|
const { code, description } = oauthErrorFields$2(payload);
|
|
22002
22037
|
if (response.status === 401 || response.status === 403 || code === "invalid_grant") throw new KimiCodeUnauthorizedError(description || "Token refresh was rejected; sign in again.");
|
|
22003
|
-
if (response.ok) return parseTokenResponse$2(asRecord$
|
|
22038
|
+
if (response.ok) return parseTokenResponse$2(asRecord$14(payload) ?? {});
|
|
22004
22039
|
if (!RETRYABLE_REFRESH_STATUSES$1.has(response.status)) throw new Error(description || `Token refresh failed (HTTP ${response.status}).`);
|
|
22005
22040
|
lastError = new KimiCodeRetryableError(description || `Token refresh failed (HTTP ${response.status}).`);
|
|
22006
22041
|
} catch (error) {
|
|
@@ -22227,7 +22262,7 @@ const FIXED_POINT_CENTS = 1e6;
|
|
|
22227
22262
|
function isRecord$33(value) {
|
|
22228
22263
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22229
22264
|
}
|
|
22230
|
-
function asRecord$
|
|
22265
|
+
function asRecord$13(value) {
|
|
22231
22266
|
return isRecord$33(value) ? value : void 0;
|
|
22232
22267
|
}
|
|
22233
22268
|
function asString$18(value) {
|
|
@@ -22370,7 +22405,7 @@ function parseThinkingType(record) {
|
|
|
22370
22405
|
return raw === "only" || raw === "no" || raw === "both" ? raw : void 0;
|
|
22371
22406
|
}
|
|
22372
22407
|
function parseCatalogModel(value) {
|
|
22373
|
-
const record = asRecord$
|
|
22408
|
+
const record = asRecord$13(value);
|
|
22374
22409
|
if (record === void 0) return void 0;
|
|
22375
22410
|
const id = asString$18(record.id);
|
|
22376
22411
|
if (id === void 0) return void 0;
|
|
@@ -22378,10 +22413,10 @@ function parseCatalogModel(value) {
|
|
|
22378
22413
|
if (status !== void 0 && RETIRED_MODEL_STATUSES.has(status)) return void 0;
|
|
22379
22414
|
const contextWindow = firstNumber(record, ["context_length", "contextLength"]);
|
|
22380
22415
|
if (contextWindow === void 0 || contextWindow <= 0) return void 0;
|
|
22381
|
-
const declaredInput = firstNumber(asRecord$
|
|
22416
|
+
const declaredInput = firstNumber(asRecord$13(record.limit) ?? asRecord$13(record.limits) ?? {}, ["input"]) ?? firstNumber(record, ["max_input_tokens", "maxInputTokens"]);
|
|
22382
22417
|
const maxInputTokens = declaredInput !== void 0 && declaredInput > 0 && declaredInput < contextWindow ? declaredInput : void 0;
|
|
22383
22418
|
const thinkingType = parseThinkingType(record);
|
|
22384
|
-
const efforts = asRecord$
|
|
22419
|
+
const efforts = asRecord$13(record.think_efforts) ?? asRecord$13(record.thinkEfforts);
|
|
22385
22420
|
const validEfforts = Array.isArray(efforts?.valid_efforts) ? efforts.valid_efforts.filter((entry) => typeof entry === "string") : Array.isArray(efforts?.validEfforts) ? efforts.validEfforts.filter((entry) => typeof entry === "string") : void 0;
|
|
22386
22421
|
const modalities = ["text"];
|
|
22387
22422
|
if (record.supports_image_in === true || record.supportsImageIn === true) modalities.push("image");
|
|
@@ -22496,7 +22531,7 @@ async function performListing(options) {
|
|
|
22496
22531
|
});
|
|
22497
22532
|
if (!response.ok) throw new Error(`Kimi Code model listing failed (${response.status}).`);
|
|
22498
22533
|
const payload = await response.json().catch(() => void 0);
|
|
22499
|
-
const data = Array.isArray(payload) ? payload : asRecord$
|
|
22534
|
+
const data = Array.isArray(payload) ? payload : asRecord$13(payload)?.data;
|
|
22500
22535
|
if (!Array.isArray(data)) throw new Error("Kimi Code model listing was not in the documented shape.");
|
|
22501
22536
|
const models = data.map(parseCatalogModel).filter((model) => model !== void 0);
|
|
22502
22537
|
if (epoch !== catalogCacheEpoch$2) return models;
|
|
@@ -22831,7 +22866,7 @@ function usageWindow(id, record, descriptor) {
|
|
|
22831
22866
|
* than a fabricated 0%.
|
|
22832
22867
|
*/
|
|
22833
22868
|
function parseUsageWindows(payload) {
|
|
22834
|
-
const root = asRecord$
|
|
22869
|
+
const root = asRecord$13(payload) ?? {};
|
|
22835
22870
|
const windows = [];
|
|
22836
22871
|
const seen = /* @__PURE__ */ new Set();
|
|
22837
22872
|
const push = (id, record, descriptor) => {
|
|
@@ -22841,23 +22876,23 @@ function parseUsageWindows(payload) {
|
|
|
22841
22876
|
seen.add(id);
|
|
22842
22877
|
windows.push(parsed);
|
|
22843
22878
|
};
|
|
22844
|
-
const usages = asRecord$
|
|
22879
|
+
const usages = asRecord$13(root.usages) ?? asRecord$13(root.usageWindows);
|
|
22845
22880
|
if (usages !== void 0) {
|
|
22846
22881
|
const keys = [...WINDOW_ORDER.filter((key) => usages[key] !== void 0), ...Object.keys(usages).filter((key) => !WINDOW_ORDER.includes(key))];
|
|
22847
22882
|
for (const key of keys) {
|
|
22848
|
-
const record = asRecord$
|
|
22883
|
+
const record = asRecord$13(usages[key]);
|
|
22849
22884
|
if (record === void 0) continue;
|
|
22850
22885
|
push(key, record, WINDOW_DESCRIPTORS[key]);
|
|
22851
22886
|
}
|
|
22852
22887
|
}
|
|
22853
|
-
const topLevel = asRecord$
|
|
22888
|
+
const topLevel = asRecord$13(root.usage);
|
|
22854
22889
|
if (topLevel !== void 0 && seen.size === 0) push("limit_7d", topLevel, WINDOW_DESCRIPTORS.limit_7d);
|
|
22855
22890
|
const limits = Array.isArray(root.limits) ? root.limits : [];
|
|
22856
22891
|
for (const entry of limits) {
|
|
22857
|
-
const record = asRecord$
|
|
22892
|
+
const record = asRecord$13(entry);
|
|
22858
22893
|
if (record === void 0) continue;
|
|
22859
|
-
const detail = asRecord$
|
|
22860
|
-
const window = asRecord$
|
|
22894
|
+
const detail = asRecord$13(record.detail) ?? record;
|
|
22895
|
+
const window = asRecord$13(record.window);
|
|
22861
22896
|
const duration = firstNumber(window ?? {}, ["duration"]);
|
|
22862
22897
|
const unit = asString$18(window?.timeUnit ?? window?.time_unit);
|
|
22863
22898
|
const minutes = duration === void 0 ? null : unit === "TIME_UNIT_HOUR" ? duration * 60 : duration;
|
|
@@ -22890,13 +22925,13 @@ function fixedPointToCents(value) {
|
|
|
22890
22925
|
* under-report a charge limit by six orders of magnitude.
|
|
22891
22926
|
*/
|
|
22892
22927
|
function moneyCents(value) {
|
|
22893
|
-
const record = asRecord$
|
|
22928
|
+
const record = asRecord$13(value);
|
|
22894
22929
|
if (record === void 0) return null;
|
|
22895
22930
|
const cents = asNumber$5(record.priceInCents ?? record.price_in_cents);
|
|
22896
22931
|
return cents === void 0 || !Number.isFinite(cents) ? null : Math.round(cents);
|
|
22897
22932
|
}
|
|
22898
22933
|
function moneyCurrency(value) {
|
|
22899
|
-
const record = asRecord$
|
|
22934
|
+
const record = asRecord$13(value);
|
|
22900
22935
|
return record === void 0 ? void 0 : asString$18(record.currency);
|
|
22901
22936
|
}
|
|
22902
22937
|
/**
|
|
@@ -22907,10 +22942,10 @@ function moneyCurrency(value) {
|
|
|
22907
22942
|
* cannot spend.
|
|
22908
22943
|
*/
|
|
22909
22944
|
function parseExtraUsage(payload) {
|
|
22910
|
-
const root = asRecord$
|
|
22911
|
-
const wallet = asRecord$
|
|
22945
|
+
const root = asRecord$13(payload) ?? {};
|
|
22946
|
+
const wallet = asRecord$13(root.boosterWallet) ?? asRecord$13(root.booster_wallet) ?? asRecord$13(root.extraUsage);
|
|
22912
22947
|
if (wallet === void 0) return null;
|
|
22913
|
-
const balance = asRecord$
|
|
22948
|
+
const balance = asRecord$13(wallet.balance);
|
|
22914
22949
|
const balanceType = asString$18(balance?.type);
|
|
22915
22950
|
const amount = asNumber$5(balance?.amount);
|
|
22916
22951
|
if (balance === void 0 || balanceType !== "BOOSTER" || amount === void 0 || amount <= 0) return null;
|
|
@@ -22959,7 +22994,7 @@ function membershipLevelName(level) {
|
|
|
22959
22994
|
* `user_level_name` still yields a readable tier instead of a raw enum.
|
|
22960
22995
|
*/
|
|
22961
22996
|
function parsePlanName(payload) {
|
|
22962
|
-
const root = asRecord$
|
|
22997
|
+
const root = asRecord$13(payload) ?? {};
|
|
22963
22998
|
const direct = firstString(root, [
|
|
22964
22999
|
"user_level_name",
|
|
22965
23000
|
"userLevelName",
|
|
@@ -22967,17 +23002,17 @@ function parsePlanName(payload) {
|
|
|
22967
23002
|
"plan_name"
|
|
22968
23003
|
]);
|
|
22969
23004
|
if (direct !== void 0) return direct;
|
|
22970
|
-
const membership = asRecord$
|
|
23005
|
+
const membership = asRecord$13(asRecord$13(root.user)?.membership);
|
|
22971
23006
|
const named = asString$18(membership?.level_name ?? membership?.levelName);
|
|
22972
23007
|
if (named !== void 0) return named;
|
|
22973
23008
|
return membershipLevelName(asString$18(membership?.level) ?? null);
|
|
22974
23009
|
}
|
|
22975
23010
|
/** Machine tier level when the service reports one. */
|
|
22976
23011
|
function parsePlanLevel(payload) {
|
|
22977
|
-
const root = asRecord$
|
|
23012
|
+
const root = asRecord$13(payload) ?? {};
|
|
22978
23013
|
const direct = firstNumber(root, ["user_level", "userLevel"]);
|
|
22979
23014
|
if (direct !== void 0) return String(direct);
|
|
22980
|
-
const membership = asRecord$
|
|
23015
|
+
const membership = asRecord$13(asRecord$13(root.user)?.membership);
|
|
22981
23016
|
return asString$18(membership?.level ?? membership?.levelId ?? membership?.level_id) ?? null;
|
|
22982
23017
|
}
|
|
22983
23018
|
/**
|
|
@@ -23084,7 +23119,7 @@ function accountFromCredentials$2(credentials, payload, profile) {
|
|
|
23084
23119
|
const planLevel = (profile === void 0 ? null : parsePlanLevel(profile)) ?? (payload === void 0 ? null : parsePlanLevel(payload));
|
|
23085
23120
|
return {
|
|
23086
23121
|
userId: credentials.userId ?? identity.userId ?? null,
|
|
23087
|
-
nickname: (profile === void 0 ? null : firstString(asRecord$
|
|
23122
|
+
nickname: (profile === void 0 ? null : firstString(asRecord$13(profile) ?? {}, [
|
|
23088
23123
|
"nickname",
|
|
23089
23124
|
"username",
|
|
23090
23125
|
"name"
|
|
@@ -27219,7 +27254,7 @@ function isRegion$3(value) {
|
|
|
27219
27254
|
}
|
|
27220
27255
|
/** Reasoning levels the whole route understands, for route-level validation. */
|
|
27221
27256
|
function isMinimaxCodeReasoningEffort(value) {
|
|
27222
|
-
return value === "
|
|
27257
|
+
return value === "low" || value === "medium" || value === "high" || value === "xhigh" || value === "max";
|
|
27223
27258
|
}
|
|
27224
27259
|
/**
|
|
27225
27260
|
* Render a token for a log line or an error message without disclosing it.
|
|
@@ -27752,31 +27787,54 @@ function catalogEntry(modelId) {
|
|
|
27752
27787
|
return minimaxCodeModelDef(modelId);
|
|
27753
27788
|
}
|
|
27754
27789
|
/**
|
|
27755
|
-
* The thinking
|
|
27790
|
+
* The `thinking` object one request carries, and the only thing that decides
|
|
27791
|
+
* WHICH CHANNEL the reasoning comes back in.
|
|
27756
27792
|
*
|
|
27757
|
-
* The official "Model Invocation" page
|
|
27758
|
-
*
|
|
27793
|
+
* The official "Model Invocation" page says thinking is on by default and needs
|
|
27794
|
+
* no configuration, and that the depth field is a top-level
|
|
27795
|
+
* `output_config.effort`. Both are true - and they were read as "the request
|
|
27796
|
+
* never carries a `thinking` key". Measured on this subscription endpoint on
|
|
27797
|
+
* 2026-10-20 (`scripts/probe-minimax-thinking-channels.probe.ts`):
|
|
27759
27798
|
*
|
|
27760
|
-
*
|
|
27799
|
+
* | request | response block | where the reasoning lands |
|
|
27800
|
+
* | --- | --- | --- |
|
|
27801
|
+
* | no `thinking` field | `content_block.type = "text"` | **in the answer text** |
|
|
27802
|
+
* | `thinking: { type: 'adaptive' }` | `content_block.type = "thinking"` | **in a thinking block** |
|
|
27761
27803
|
*
|
|
27762
|
-
*
|
|
27763
|
-
*
|
|
27764
|
-
*
|
|
27804
|
+
* The same model, the same prompt, the same reasoning - but without the object
|
|
27805
|
+
* the service streams it as ordinary assistant text, so the model visibly
|
|
27806
|
+
* thinks out loud inside the answer. That also means the harness never sees a
|
|
27807
|
+
* reasoning block, and the interleaved-thinking replay has nothing to replay.
|
|
27765
27808
|
*
|
|
27766
|
-
*
|
|
27809
|
+
* M3.1 needs no object: measured, a forced-on model answers in the thinking
|
|
27810
|
+
* channel either way, which is why the upstream managed path deletes the
|
|
27811
|
+
* `thinking` key for forced-on models and keeps it for switchable ones.
|
|
27767
27812
|
*
|
|
27768
|
-
*
|
|
27769
|
-
*
|
|
27770
|
-
*
|
|
27771
|
-
* 2. The depth level belongs at the TOP level, in `output_config.effort`, not
|
|
27772
|
-
* inside a thinking object. Anywhere else is a field the service does not read.
|
|
27773
|
-
* 3. `effort` accepts low, medium, high, xhigh and max. There is no `default`
|
|
27774
|
-
* member: the page says omitting the field means max, so `default` must not
|
|
27775
|
-
* reach the wire, and neither must an explicit `max` for the same reason.
|
|
27813
|
+
* The off state is the same object with `disabled`, which is what the upstream
|
|
27814
|
+
* managed path sends and what this endpoint measured as thinking off (10 output
|
|
27815
|
+
* tokens, no thinking block).
|
|
27776
27816
|
*
|
|
27777
|
-
*
|
|
27778
|
-
* thinking
|
|
27779
|
-
|
|
27817
|
+
* @returns the value for `thinking`, or undefined when the request should
|
|
27818
|
+
* carry no thinking object at all.
|
|
27819
|
+
*/
|
|
27820
|
+
function thinkingFieldFor(modelId, requestedEffort) {
|
|
27821
|
+
const model = catalogEntry(modelId);
|
|
27822
|
+
if (model === void 0) return void 0;
|
|
27823
|
+
if (model.thinking !== "toggle") return void 0;
|
|
27824
|
+
return { type: isThinkingDisabledEffort(requestedEffort) ? "disabled" : "adaptive" };
|
|
27825
|
+
}
|
|
27826
|
+
/**
|
|
27827
|
+
* The depth level one request carries, as `output_config`.
|
|
27828
|
+
*
|
|
27829
|
+
* The level belongs at the TOP level - `output_config.effort` - and accepts
|
|
27830
|
+
* low, medium, high, xhigh and max. There is no `default` member: the page
|
|
27831
|
+
* says omitting the field means max, so the old local `default` spelling never
|
|
27832
|
+
* reached the wire. This line no longer leans on that: every model that has
|
|
27833
|
+
* levels states its default out loud, and a request that asks for nothing
|
|
27834
|
+
* resolves to that default instead of to an omission.
|
|
27835
|
+
*
|
|
27836
|
+
* The level is the DEPTH, not the channel: measured, low and max differ by
|
|
27837
|
+
* about 3x thinking and 4x latency, and it composes with the `thinking` object.
|
|
27780
27838
|
*
|
|
27781
27839
|
* @returns the value for `output_config`, or undefined when the request should
|
|
27782
27840
|
* carry no thinking control at all.
|
|
@@ -27785,9 +27843,9 @@ function outputConfigFor(modelId, requestedEffort) {
|
|
|
27785
27843
|
const model = catalogEntry(modelId);
|
|
27786
27844
|
if (model === void 0) return void 0;
|
|
27787
27845
|
if (model.thinking === "always-on") return void 0;
|
|
27788
|
-
if (
|
|
27789
|
-
const effort = effortForModel(modelId, requestedEffort
|
|
27790
|
-
return effort ===
|
|
27846
|
+
if (isThinkingDisabledEffort(requestedEffort)) return void 0;
|
|
27847
|
+
const effort = effortForModel(modelId, requestedEffort);
|
|
27848
|
+
return effort === null ? void 0 : { effort };
|
|
27791
27849
|
}
|
|
27792
27850
|
/**
|
|
27793
27851
|
* Raise a cap that is too small for this line's forced thinking.
|
|
@@ -27918,7 +27976,10 @@ function buildMinimaxRequest(options, images = NO_RESOLVED_IMAGES$3, request = {
|
|
|
27918
27976
|
}
|
|
27919
27977
|
const system = leadingSystemText$5(options);
|
|
27920
27978
|
const maxTokens = options.maxTokens ?? maxOutputTokensFor$1(options.model);
|
|
27921
|
-
const
|
|
27979
|
+
const requestedEffort = options.reasoningEffort === void 0 ? null : String(options.reasoningEffort);
|
|
27980
|
+
const outputConfig = outputConfigFor(options.model, requestedEffort);
|
|
27981
|
+
const thinking = thinkingFieldFor(options.model, requestedEffort);
|
|
27982
|
+
const thinkingEngaged = outputConfig !== void 0 || thinking?.type === "adaptive";
|
|
27922
27983
|
const caching = request.cacheControl !== false;
|
|
27923
27984
|
const body = {
|
|
27924
27985
|
model: options.model,
|
|
@@ -27929,13 +27990,14 @@ function buildMinimaxRequest(options, images = NO_RESOLVED_IMAGES$3, request = {
|
|
|
27929
27990
|
type: "text",
|
|
27930
27991
|
text: system
|
|
27931
27992
|
}] : system },
|
|
27932
|
-
...options.temperature === void 0 ||
|
|
27993
|
+
...options.temperature === void 0 || thinkingEngaged ? {} : { temperature: options.temperature },
|
|
27933
27994
|
...options.stop && options.stop.length > 0 ? { stop_sequences: options.stop } : {},
|
|
27934
27995
|
...options.tools && options.tools.length > 0 ? { tools: options.tools.map((tool) => ({
|
|
27935
27996
|
name: tool.name,
|
|
27936
27997
|
description: tool.description,
|
|
27937
27998
|
input_schema: stripMetaSchema$2(tool.parameters)
|
|
27938
27999
|
})) } : {},
|
|
28000
|
+
...thinking === void 0 ? {} : { thinking },
|
|
27939
28001
|
...outputConfig === void 0 ? {} : { output_config: outputConfig }
|
|
27940
28002
|
};
|
|
27941
28003
|
if (caching) markMinimaxCacheBreakpoints(body);
|
|
@@ -28157,6 +28219,8 @@ function processMinimaxStreamLine(line, state) {
|
|
|
28157
28219
|
}
|
|
28158
28220
|
const stop = message === void 0 ? void 0 : asString$15(message.stop_reason);
|
|
28159
28221
|
if (stop !== void 0) state.finishReason = stop;
|
|
28222
|
+
const answered = message === void 0 ? void 0 : asString$15(message.model);
|
|
28223
|
+
if (answered !== void 0) state.answeredModel = answered;
|
|
28160
28224
|
return out;
|
|
28161
28225
|
}
|
|
28162
28226
|
if (type === "content_block_start") {
|
|
@@ -28391,8 +28455,8 @@ const MINIMAX_CODE_MODELS = [
|
|
|
28391
28455
|
maxTokens: 128e3,
|
|
28392
28456
|
inputModalities: ["text"],
|
|
28393
28457
|
thinking: "always-on",
|
|
28394
|
-
reasoningEfforts: [
|
|
28395
|
-
defaultReasoningEffort:
|
|
28458
|
+
reasoningEfforts: [],
|
|
28459
|
+
defaultReasoningEffort: null,
|
|
28396
28460
|
maxAttachments: null,
|
|
28397
28461
|
maxImageBytes: null,
|
|
28398
28462
|
maxVideoBytes: null,
|
|
@@ -28407,8 +28471,8 @@ const MINIMAX_CODE_MODELS = [
|
|
|
28407
28471
|
maxTokens: 128e3,
|
|
28408
28472
|
inputModalities: ["text"],
|
|
28409
28473
|
thinking: "always-on",
|
|
28410
|
-
reasoningEfforts: [
|
|
28411
|
-
defaultReasoningEffort:
|
|
28474
|
+
reasoningEfforts: [],
|
|
28475
|
+
defaultReasoningEffort: null,
|
|
28412
28476
|
maxAttachments: null,
|
|
28413
28477
|
maxImageBytes: null,
|
|
28414
28478
|
maxVideoBytes: null,
|
|
@@ -28427,8 +28491,14 @@ const MINIMAX_CODE_MODELS = [
|
|
|
28427
28491
|
"video"
|
|
28428
28492
|
],
|
|
28429
28493
|
thinking: "toggle",
|
|
28430
|
-
reasoningEfforts: [
|
|
28431
|
-
|
|
28494
|
+
reasoningEfforts: [
|
|
28495
|
+
"low",
|
|
28496
|
+
"medium",
|
|
28497
|
+
"high",
|
|
28498
|
+
"xhigh",
|
|
28499
|
+
"max"
|
|
28500
|
+
],
|
|
28501
|
+
defaultReasoningEffort: "max",
|
|
28432
28502
|
maxAttachments: 9,
|
|
28433
28503
|
maxImageBytes: 10 * 1024 * 1024,
|
|
28434
28504
|
maxVideoBytes: 50 * 1024 * 1024,
|
|
@@ -28438,8 +28508,8 @@ const MINIMAX_CODE_MODELS = [
|
|
|
28438
28508
|
{
|
|
28439
28509
|
id: "MiniMax-M3.1-Flash",
|
|
28440
28510
|
name: "MiniMax M3.1 Flash",
|
|
28441
|
-
contextWindow:
|
|
28442
|
-
optionalContextWindow:
|
|
28511
|
+
contextWindow: 512e3,
|
|
28512
|
+
optionalContextWindow: 1e6,
|
|
28443
28513
|
maxTokens: 128e3,
|
|
28444
28514
|
inputModalities: [
|
|
28445
28515
|
"text",
|
|
@@ -28448,14 +28518,13 @@ const MINIMAX_CODE_MODELS = [
|
|
|
28448
28518
|
],
|
|
28449
28519
|
thinking: "forced-effort",
|
|
28450
28520
|
reasoningEfforts: [
|
|
28451
|
-
"default",
|
|
28452
28521
|
"low",
|
|
28453
28522
|
"medium",
|
|
28454
28523
|
"high",
|
|
28455
28524
|
"xhigh",
|
|
28456
28525
|
"max"
|
|
28457
28526
|
],
|
|
28458
|
-
defaultReasoningEffort: "
|
|
28527
|
+
defaultReasoningEffort: "max",
|
|
28459
28528
|
maxAttachments: 4,
|
|
28460
28529
|
maxImageBytes: 10 * 1024 * 1024,
|
|
28461
28530
|
maxVideoBytes: 50 * 1024 * 1024,
|
|
@@ -28527,7 +28596,8 @@ function isThinkingDisabledEffort(value) {
|
|
|
28527
28596
|
*/
|
|
28528
28597
|
function effortForModel(modelId, requested) {
|
|
28529
28598
|
const model = minimaxCodeModelDef(modelId);
|
|
28530
|
-
if (model === void 0) return
|
|
28599
|
+
if (model === void 0) return null;
|
|
28600
|
+
if (model.reasoningEfforts.length === 0) return null;
|
|
28531
28601
|
if (requested === void 0 || requested === null) return model.defaultReasoningEffort;
|
|
28532
28602
|
const normalized = requested.trim().toLowerCase();
|
|
28533
28603
|
return model.reasoningEfforts.find((effort) => effort === normalized) ?? model.defaultReasoningEffort;
|
|
@@ -28597,7 +28667,7 @@ function buildMinimaxCodeModelOptions(storedEnabledModelIds, contextWindowOverri
|
|
|
28597
28667
|
contextWindow,
|
|
28598
28668
|
defaultMaxTokens: maxOutputTokensFor$1(model.id, contextWindow),
|
|
28599
28669
|
reasoningEfforts: [...model.reasoningEfforts],
|
|
28600
|
-
defaultReasoningEffort: model.defaultReasoningEffort,
|
|
28670
|
+
defaultReasoningEffort: model.defaultReasoningEffort ?? void 0,
|
|
28601
28671
|
thinking: model.thinking,
|
|
28602
28672
|
description: model.description
|
|
28603
28673
|
};
|
|
@@ -29345,7 +29415,7 @@ function registerMinimaxCodePreferenceStore(settings, fallbackStore = new Minima
|
|
|
29345
29415
|
enabled: value.enabled !== false,
|
|
29346
29416
|
enabledModelIds: value.enabledModelIds,
|
|
29347
29417
|
contextWindowOverrides: value.contextWindowOverrides,
|
|
29348
|
-
defaultReasoningEffort: value.defaultReasoningEffort,
|
|
29418
|
+
defaultReasoningEffort: isReasoningEffort$1(value.defaultReasoningEffort) ? value.defaultReasoningEffort : null,
|
|
29349
29419
|
checkin: { enabled: value.checkin?.enabled !== false }
|
|
29350
29420
|
};
|
|
29351
29421
|
},
|
|
@@ -29418,7 +29488,7 @@ function withTimeout$6(signal, ms) {
|
|
|
29418
29488
|
const timeout = AbortSignal.timeout(ms);
|
|
29419
29489
|
return signal === void 0 ? timeout : AbortSignal.any([signal, timeout]);
|
|
29420
29490
|
}
|
|
29421
|
-
function asRecord$
|
|
29491
|
+
function asRecord$12(value) {
|
|
29422
29492
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
29423
29493
|
}
|
|
29424
29494
|
function asString$13(value) {
|
|
@@ -29432,8 +29502,8 @@ function asString$13(value) {
|
|
|
29432
29502
|
* both are unwrapped before the caller decides what the failure means.
|
|
29433
29503
|
*/
|
|
29434
29504
|
function oauthErrorFields$1(payload) {
|
|
29435
|
-
const root = asRecord$
|
|
29436
|
-
const nested = asRecord$
|
|
29505
|
+
const root = asRecord$12(payload) ?? {};
|
|
29506
|
+
const nested = asRecord$12(root.error);
|
|
29437
29507
|
if (nested !== void 0) return {
|
|
29438
29508
|
code: asString$13(nested.code) ?? "",
|
|
29439
29509
|
description: String(nested.message ?? nested.error_description ?? nested.detail ?? nested.type ?? "")
|
|
@@ -29489,7 +29559,7 @@ async function requestDeviceAuthorization$1(options = {}) {
|
|
|
29489
29559
|
const { description } = oauthErrorFields$1(payload);
|
|
29490
29560
|
throw new Error("MiniMax Code device authorization failed (" + response.status + ")" + (description === "" ? "" : ": " + description));
|
|
29491
29561
|
}
|
|
29492
|
-
const record = asRecord$
|
|
29562
|
+
const record = asRecord$12(payload) ?? {};
|
|
29493
29563
|
const userCode = asString$13(record.user_code);
|
|
29494
29564
|
const deviceCode = asString$13(record.device_code);
|
|
29495
29565
|
if (userCode === void 0 || deviceCode === void 0) throw new Error("MiniMax Code device authorization response carried no device code or user code");
|
|
@@ -29543,7 +29613,7 @@ async function pollDeviceToken(authorization, options = {}) {
|
|
|
29543
29613
|
signal: withTimeout$6(options.signal, OAUTH_TIMEOUT_MS$1)
|
|
29544
29614
|
});
|
|
29545
29615
|
const payload = await response.json().catch(() => void 0);
|
|
29546
|
-
const record = asRecord$
|
|
29616
|
+
const record = asRecord$12(payload) ?? {};
|
|
29547
29617
|
if (response.ok && asString$13(record.access_token) !== void 0) return {
|
|
29548
29618
|
kind: "success",
|
|
29549
29619
|
token: parseTokenResponse$1(record)
|
|
@@ -29607,7 +29677,7 @@ async function refreshAccessToken$2(refreshToken, options) {
|
|
|
29607
29677
|
const payload = await response.json().catch(() => void 0);
|
|
29608
29678
|
const { code, description } = oauthErrorFields$1(payload);
|
|
29609
29679
|
if (response.status === 400 || response.status === 401 || response.status === 403 || code === "invalid_grant" || code === "invalid_client") throw new MinimaxCodeUnauthorizedError("MiniMax Code rejected the stored refresh token " + redactToken(refreshToken) + ". Sign in again in MiniMax Code, then reopen this card.");
|
|
29610
|
-
if (response.ok) return parseTokenResponse$1(asRecord$
|
|
29680
|
+
if (response.ok) return parseTokenResponse$1(asRecord$12(payload) ?? {});
|
|
29611
29681
|
if (!RETRYABLE_REFRESH_STATUSES.has(response.status)) throw new MinimaxCodeRetryableError(description || "MiniMax Code token refresh failed (HTTP " + response.status + ").");
|
|
29612
29682
|
lastError = new MinimaxCodeRetryableError(description || "MiniMax Code token refresh failed (HTTP " + response.status + ").");
|
|
29613
29683
|
} catch (error) {
|
|
@@ -29937,7 +30007,7 @@ function probeRequestHeaders(accessToken) {
|
|
|
29937
30007
|
accept: "application/json"
|
|
29938
30008
|
};
|
|
29939
30009
|
}
|
|
29940
|
-
function asRecord$
|
|
30010
|
+
function asRecord$11(value) {
|
|
29941
30011
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
29942
30012
|
}
|
|
29943
30013
|
function numberOr$5(value, fallback) {
|
|
@@ -29945,7 +30015,7 @@ function numberOr$5(value, fallback) {
|
|
|
29945
30015
|
}
|
|
29946
30016
|
/** Read the four token counters the Messages response reports. */
|
|
29947
30017
|
function parseAnthropicUsage(payload) {
|
|
29948
|
-
const usage = asRecord$
|
|
30018
|
+
const usage = asRecord$11(asRecord$11(payload)?.usage);
|
|
29949
30019
|
if (usage === void 0) return null;
|
|
29950
30020
|
return {
|
|
29951
30021
|
inputTokens: numberOr$5(usage.input_tokens, 0),
|
|
@@ -29959,13 +30029,13 @@ function summarizeFailureBody(raw) {
|
|
|
29959
30029
|
const text = raw.replace(/[\r\n\t]+/g, " ").trim();
|
|
29960
30030
|
if (text === "") return "";
|
|
29961
30031
|
try {
|
|
29962
|
-
const record = asRecord$
|
|
30032
|
+
const record = asRecord$11(JSON.parse(text));
|
|
29963
30033
|
if (record !== void 0) {
|
|
29964
30034
|
const message = record.message ?? record.error_description ?? record.errorReason ?? record.error;
|
|
29965
30035
|
if (typeof message === "string") return message.slice(0, 400);
|
|
29966
|
-
const nestedMessage = asRecord$
|
|
30036
|
+
const nestedMessage = asRecord$11(record.error)?.message;
|
|
29967
30037
|
if (typeof nestedMessage === "string") return nestedMessage.slice(0, 400);
|
|
29968
|
-
const baseResp = asRecord$
|
|
30038
|
+
const baseResp = asRecord$11(record.base_resp)?.status_msg;
|
|
29969
30039
|
if (typeof baseResp === "string") return baseResp.slice(0, 400);
|
|
29970
30040
|
}
|
|
29971
30041
|
} catch {}
|
|
@@ -30284,11 +30354,11 @@ function quotaWindow(input) {
|
|
|
30284
30354
|
* card's graceful degradation.
|
|
30285
30355
|
*/
|
|
30286
30356
|
function parseTokenPlanQuota(payload, now = Date.now()) {
|
|
30287
|
-
const rows = asRecord$
|
|
30357
|
+
const rows = asRecord$11(payload)?.model_remains;
|
|
30288
30358
|
if (!Array.isArray(rows)) return null;
|
|
30289
30359
|
const entries = [];
|
|
30290
30360
|
for (const raw of rows) {
|
|
30291
|
-
const row = asRecord$
|
|
30361
|
+
const row = asRecord$11(raw);
|
|
30292
30362
|
if (row === void 0) continue;
|
|
30293
30363
|
const name = typeof row.model_name === "string" && row.model_name !== "" ? row.model_name : "quota";
|
|
30294
30364
|
const intervalTotal = numberOr$5(row.current_interval_total_count, 0);
|
|
@@ -30364,7 +30434,7 @@ async function fetchTokenPlanQuota(credentials, options = {}) {
|
|
|
30364
30434
|
}
|
|
30365
30435
|
if (!response.ok) continue;
|
|
30366
30436
|
const payload = await response.json().catch(() => void 0);
|
|
30367
|
-
if (numberOr$5(asRecord$
|
|
30437
|
+
if (numberOr$5(asRecord$11(asRecord$11(payload)?.base_resp)?.status_code, 0) !== 0) {
|
|
30368
30438
|
reason = "credential-not-accepted";
|
|
30369
30439
|
break;
|
|
30370
30440
|
}
|
|
@@ -30770,6 +30840,11 @@ function quotaCooldownMs(bodyText) {
|
|
|
30770
30840
|
* the other — so a body whose chosen field says "rate limit" while its sibling says
|
|
30771
30841
|
* 额度不足 must still be read as the quota verdict it is. Same reasoning, same raw-text
|
|
30772
30842
|
* match, as the sibling line's plan-scope test (kimi-code/adapter.ts:838).
|
|
30843
|
+
*
|
|
30844
|
+
* This table is the FALLBACK, not the only verdict: the service states the same
|
|
30845
|
+
* condition as a number too, and {@link namesSpentWindow} asks that first. The entries
|
|
30846
|
+
* stay because a Chinese sentence arrives with no code at all, and because a body that
|
|
30847
|
+
* is not JSON has nothing but its wording to read.
|
|
30773
30848
|
*/
|
|
30774
30849
|
const QUOTA_EXHAUSTED_PATTERNS = [
|
|
30775
30850
|
/insufficient\s+(?:balance|quota|credit|funds)/i,
|
|
@@ -30789,13 +30864,111 @@ function matchesAny(text, patterns) {
|
|
|
30789
30864
|
return patterns.some((pattern) => pattern.test(text));
|
|
30790
30865
|
}
|
|
30791
30866
|
/**
|
|
30867
|
+
* The upstream status codes that mean this account's usage window is spent.
|
|
30868
|
+
*
|
|
30869
|
+
* The official MiniMax Code client settles this verdict on a NUMBER and not on
|
|
30870
|
+
* wording — `LLM_USAGE_LIMIT_UPSTREAM_STATUS_CODES = [2056, 2067]` in
|
|
30871
|
+
* packages/shared/src/llm-error-classifier.ts — and until this table existed this
|
|
30872
|
+
* line had only the phrase regexes above. A phrase table is the brittle half of the
|
|
30873
|
+
* same rule: every phrasing the service invents needs a new entry, and every entry
|
|
30874
|
+
* added is another chance to file ordinary back-pressure as a terminal verdict (the
|
|
30875
|
+
* `/quota/i` → `rate_limit_exceeded` regression the table itself records). The code
|
|
30876
|
+
* is what the service already decided; reading it is reading the verdict rather
|
|
30877
|
+
* than guessing at it.
|
|
30878
|
+
*
|
|
30879
|
+
* Both codes are the same verdict as the wording path: the account's window is
|
|
30880
|
+
* gone until it resets, so the failure is terminal (no retry can refill a window)
|
|
30881
|
+
* and it belongs to ONE account (the pool cools it for the window the body names —
|
|
30882
|
+
* five hours or a week — and lets the next account answer).
|
|
30883
|
+
*
|
|
30884
|
+
* 2013 is deliberately absent. Upstream calls it a generic invalid-params code and
|
|
30885
|
+
* this repo already reads it that way on the reset-card and Files API paths, so a
|
|
30886
|
+
* 2013 must never become a quota verdict no matter which envelope carries it.
|
|
30887
|
+
*/
|
|
30888
|
+
const USAGE_LIMIT_UPSTREAM_STATUS_CODES = /* @__PURE__ */ new Set([2056, 2067]);
|
|
30889
|
+
function isUsageLimitStatusCode(code) {
|
|
30890
|
+
return code !== void 0 && USAGE_LIMIT_UPSTREAM_STATUS_CODES.has(code);
|
|
30891
|
+
}
|
|
30892
|
+
/** A JSON object, or undefined for anything else (including a failed parse). */
|
|
30893
|
+
function asRecord$10(value) {
|
|
30894
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
30895
|
+
}
|
|
30896
|
+
/** The whole number one field holds, or undefined when it holds anything else. */
|
|
30897
|
+
function integerOrUndefined(value) {
|
|
30898
|
+
return typeof value === "number" && Number.isSafeInteger(value) ? value : void 0;
|
|
30899
|
+
}
|
|
30900
|
+
/**
|
|
30901
|
+
* The numeric status code one envelope carries, read from the field that envelope
|
|
30902
|
+
* documents.
|
|
30903
|
+
*
|
|
30904
|
+
* The two envelopes this line already parses put the code in different places, and
|
|
30905
|
+
* both are read here for the same reason `QUOTA_EXHAUSTED_PATTERNS` matches the raw
|
|
30906
|
+
* body: a body that carries only `base_resp.status_code` carries no sentence at all,
|
|
30907
|
+
* so an extractor keyed on one field would judge an envelope it never saw.
|
|
30908
|
+
*
|
|
30909
|
+
* · the platform envelope — `{"base_resp":{"status_code":…,"status_msg":…}}` — as
|
|
30910
|
+
* every platform route in this line already reads it (client.ts:131,
|
|
30911
|
+
* reset-card.ts:182-188, files-api.ts:373-375, checkin-gateway.ts:402-406);
|
|
30912
|
+
* · the client envelope — `{"errorCode":…,"errorReason":…}` — as types.ts:22 and
|
|
30913
|
+
* model-catalog.ts:6 document it;
|
|
30914
|
+
* · the Messages envelope — `{"code":…,"message":…}` — which is the ONLY numeric
|
|
30915
|
+
* field this route's own error bodies carry. Measured on 2026-10-20 (see
|
|
30916
|
+
* docs/minimax-code-probe-capabilities.md): a 400 on /messages carries no
|
|
30917
|
+
* base_resp and no errorCode at all, and its 2013 sits in the message TEXT
|
|
30918
|
+
* alone; the 401 that shares that text says `{"code":401,"message":"auth
|
|
30919
|
+
* failed"}`. Without this arm the numeric branch below could never fire on
|
|
30920
|
+
* this route, which is what left every /messages refusal to the phrase table.
|
|
30921
|
+
*/
|
|
30922
|
+
function statusCodeIn(record) {
|
|
30923
|
+
if (record === void 0) return void 0;
|
|
30924
|
+
return integerOrUndefined(asRecord$10(record.base_resp)?.status_code) ?? integerOrUndefined(record.errorCode) ?? integerOrUndefined(record.code);
|
|
30925
|
+
}
|
|
30926
|
+
/**
|
|
30927
|
+
* Whether this body NAMES a spent usage window by its status code.
|
|
30928
|
+
*
|
|
30929
|
+
* Read from the raw body, in both envelopes, exactly as the phrase table is — with
|
|
30930
|
+
* one arm more: the in-band body this adapter itself builds (`{ error: <the stream's
|
|
30931
|
+
* own error object> }`, see the reclassification in `generate`) is one level down,
|
|
30932
|
+
* so the same two fields are read inside it as well. That is what lets an in-band
|
|
30933
|
+
* failure inherit this verdict instead of needing a second copy of the rule.
|
|
30934
|
+
*
|
|
30935
|
+
* A body that is not JSON answers false and falls through to the phrase table: a
|
|
30936
|
+
* truncated or plain-text body has no field to read, and the wording is the only
|
|
30937
|
+
* evidence it carries.
|
|
30938
|
+
*/
|
|
30939
|
+
function namesUsageLimitStatusCode(bodyText) {
|
|
30940
|
+
const text = bodyText.trim();
|
|
30941
|
+
if (text === "") return false;
|
|
30942
|
+
let parsed;
|
|
30943
|
+
try {
|
|
30944
|
+
parsed = JSON.parse(text);
|
|
30945
|
+
} catch {
|
|
30946
|
+
return false;
|
|
30947
|
+
}
|
|
30948
|
+
const record = asRecord$10(parsed);
|
|
30949
|
+
if (record === void 0) return false;
|
|
30950
|
+
return isUsageLimitStatusCode(statusCodeIn(record)) || isUsageLimitStatusCode(statusCodeIn(asRecord$10(record.error)));
|
|
30951
|
+
}
|
|
30952
|
+
/**
|
|
30953
|
+
* Whether this body names a spent usage window at all — by number or by wording.
|
|
30954
|
+
*
|
|
30955
|
+
* The number is the service's own verdict and the wording is the fallback, which is
|
|
30956
|
+
* the order the two are asked in rather than two copies of the same question: a
|
|
30957
|
+
* Chinese sentence has no code, and a bare code has no sentence, so both arms exist
|
|
30958
|
+
* and both answer into the ONE verdict {@link quotaExhaustedFailure} builds.
|
|
30959
|
+
*/
|
|
30960
|
+
function namesSpentWindow(bodyText) {
|
|
30961
|
+
return namesUsageLimitStatusCode(bodyText) || matchesAny(bodyText, QUOTA_EXHAUSTED_PATTERNS);
|
|
30962
|
+
}
|
|
30963
|
+
/**
|
|
30792
30964
|
* Whether this refusal is a spent window rather than a refused credential.
|
|
30793
30965
|
*
|
|
30794
|
-
* The same raw-body
|
|
30966
|
+
* The same raw-body test classifyMinimaxFailure performs, hoisted into its own name
|
|
30795
30967
|
* because it now answers a second question too, and one the status alone cannot: is
|
|
30796
30968
|
* renewing this credential worth attempting at all (see the recovery loop in this
|
|
30797
30969
|
* adapter). A verdict the pool acts on and a verdict the user is shown have to be the
|
|
30798
|
-
* SAME verdict, so both read this one predicate
|
|
30970
|
+
* SAME verdict, so both read this one predicate — {@link namesSpentWindow}, which asks
|
|
30971
|
+
* the upstream usage-limit code first and the wording table second — rather than
|
|
30799
30972
|
* keeping two copies of the condition that could drift apart.
|
|
30800
30973
|
*
|
|
30801
30974
|
* The status is inside on purpose. 403 is the only status a spent window arrives as,
|
|
@@ -30805,7 +30978,7 @@ function matchesAny(text, patterns) {
|
|
|
30805
30978
|
* into it would send a working token off to be renewed.
|
|
30806
30979
|
*/
|
|
30807
30980
|
function isSpentWindow403(status, bodyText) {
|
|
30808
|
-
return status === 403 &&
|
|
30981
|
+
return status === 403 && namesSpentWindow(bodyText);
|
|
30809
30982
|
}
|
|
30810
30983
|
/**
|
|
30811
30984
|
* The verdict a spent Token Plan window gets, whichever status carries it.
|
|
@@ -30849,7 +31022,7 @@ function classifyMinimaxFailure(status, bodyText) {
|
|
|
30849
31022
|
message: "MiniMax Code(编程订阅) rejected the stored credential (" + status + "). Sign in again in the MiniMax Code app, then reopen this card." + (detail === "" ? "" : " " + detail)
|
|
30850
31023
|
};
|
|
30851
31024
|
if (status === 429) {
|
|
30852
|
-
if (
|
|
31025
|
+
if (namesSpentWindow(bodyText)) return quotaExhaustedFailure(detail);
|
|
30853
31026
|
return {
|
|
30854
31027
|
code: "RATE_LIMIT",
|
|
30855
31028
|
retryable: true,
|
|
@@ -31015,6 +31188,48 @@ async function uploadOversizedMedia(options, images, videos, credentials, accoun
|
|
|
31015
31188
|
})
|
|
31016
31189
|
};
|
|
31017
31190
|
}
|
|
31191
|
+
/**
|
|
31192
|
+
* The error code for "the model this request named is not the model that answered".
|
|
31193
|
+
*
|
|
31194
|
+
* Deliberately NOT in `MINIMAX_CODE_RETRY_POLICY_CONFIG.retryableCodes` (which is
|
|
31195
|
+
* RATE_LIMIT / SERVER / TIMEOUT / TRANSPORT), so the harness never retries it:
|
|
31196
|
+
* re-issuing the SAME body against the SAME substitution answers the SAME wrong
|
|
31197
|
+
* model, and each attempt is billed at the substituted model's price. The failure
|
|
31198
|
+
* is terminal until a human changes the model, which is exactly what the retry
|
|
31199
|
+
* policy is keyed on.
|
|
31200
|
+
*
|
|
31201
|
+
* Exported so a test (and any later caller) can name it instead of copying the
|
|
31202
|
+
* literal, the same way NO_ANSWER_PHRASE is.
|
|
31203
|
+
*/
|
|
31204
|
+
const MODEL_SUBSTITUTED_CODE = "MODEL_SUBSTITUTED";
|
|
31205
|
+
/**
|
|
31206
|
+
* Whether the id the service ANSWERED with is the id the request asked for.
|
|
31207
|
+
*
|
|
31208
|
+
* Case-insensitive equality is the whole rule: this line already accepts a case
|
|
31209
|
+
* variant of an id as the same model (the catalog and the stored settings compare
|
|
31210
|
+
* ids the same way), and nothing else is normalized. A REQUESTED id is whatever
|
|
31211
|
+
* the catalog spells; an ANSWERED id is whatever the service spells; the two
|
|
31212
|
+
* differing only in letter case is not a substitution, and refusing to answer over
|
|
31213
|
+
* one would fail a turn that is being served the model it asked for.
|
|
31214
|
+
*
|
|
31215
|
+
* Everything else is a mismatch: a different id, a retired spelling, an id the
|
|
31216
|
+
* service does not route at all. That is the substitution this check exists for.
|
|
31217
|
+
*/
|
|
31218
|
+
function sameModelId(requested, answered) {
|
|
31219
|
+
return requested.trim().toLowerCase() === answered.trim().toLowerCase();
|
|
31220
|
+
}
|
|
31221
|
+
/**
|
|
31222
|
+
* The failure a substituted model gets, worded so the reader can act on it.
|
|
31223
|
+
*
|
|
31224
|
+
* Both ids are named because both are the facts: the catalogue-facing id the user
|
|
31225
|
+
* selected, and the one the service actually ran. Neither is a secret — they are
|
|
31226
|
+
* model names — and nothing else from the request (token, account, body) goes in.
|
|
31227
|
+
* The remedy is spelled out because the check cannot pick one for the user: the
|
|
31228
|
+
* substitution means this id no longer routes, so the selection has to change.
|
|
31229
|
+
*/
|
|
31230
|
+
function modelSubstitutedFailure(requested, answered) {
|
|
31231
|
+
return new LlmError("MiniMax Code(编程订阅) answered with a different model than the one requested: the request asked for \"" + requested + "\", and the service answered as \"" + answered + "\". This endpoint does not reject a model id it cannot route — it silently runs another one — so the id \"" + requested + "\" is not being served and the request was billed at the answering model's rate instead. Nothing was retried, because the same request would be answered the same way. Pick a different model for this line, or check whether \"" + requested + "\" is still offered, then send the request again.", MODEL_SUBSTITUTED_CODE, { status: 200 });
|
|
31232
|
+
}
|
|
31018
31233
|
var MinimaxCodeAdapter = class extends LlmAdapter {
|
|
31019
31234
|
store;
|
|
31020
31235
|
/**
|
|
@@ -31152,8 +31367,7 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
|
|
|
31152
31367
|
"medium",
|
|
31153
31368
|
"high",
|
|
31154
31369
|
"xhigh",
|
|
31155
|
-
"max"
|
|
31156
|
-
"default"
|
|
31370
|
+
"max"
|
|
31157
31371
|
]);
|
|
31158
31372
|
const contextWindow = contextWindowForModel(modelId, settings.contextWindowOverrides);
|
|
31159
31373
|
const defaultEffort = entry === void 0 ? void 0 : resolveDefaultEffort(entry, settings.defaultReasoningEffort);
|
|
@@ -31210,6 +31424,24 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
|
|
|
31210
31424
|
let authOwner;
|
|
31211
31425
|
let accountId;
|
|
31212
31426
|
let response;
|
|
31427
|
+
/**
|
|
31428
|
+
* The model id this request actually PUT ON THE WIRE — the comparison basis for
|
|
31429
|
+
* the served-model check further down.
|
|
31430
|
+
*
|
|
31431
|
+
* Read back out of the serialized body rather than taken from `options.model`
|
|
31432
|
+
* directly: `buildMinimaxRequest` writes `model: options.model` today, so the two
|
|
31433
|
+
* agree, but the thing that must be compared is by definition what left the
|
|
31434
|
+
* socket. The catalogue's renames (model-catalog.ts:269-282) never touch it —
|
|
31435
|
+
* "The WIRE still carries whatever id the caller asked for ... Only the LOOKUP is
|
|
31436
|
+
* renamed" — so a retired spelling is compared AS the retired spelling, which is
|
|
31437
|
+
* exactly the id the service substitutes a different model for.
|
|
31438
|
+
*
|
|
31439
|
+
* Hoisted here because the body is built (and rebuilt, by the 401 recovery)
|
|
31440
|
+
* inside the rotation loop while the stream is read after it. A body carrying no
|
|
31441
|
+
* model string leaves it undefined and turns the check off for the round — the
|
|
31442
|
+
* same "nothing to verify" outcome as a header with no model in it.
|
|
31443
|
+
*/
|
|
31444
|
+
let wireModel;
|
|
31213
31445
|
const pool = this.options.accountPool;
|
|
31214
31446
|
while (true) {
|
|
31215
31447
|
try {
|
|
@@ -31223,8 +31455,17 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
|
|
|
31223
31455
|
if (accountId !== void 0) tried.add(accountId);
|
|
31224
31456
|
authOwner = computeMinimaxAuthOwner(credentials, accountId);
|
|
31225
31457
|
const withUploads = await uploadOversizedMedia(requestOptions, images, videos, credentials, accountId, this.options.fetchFn ?? fetch, signal);
|
|
31458
|
+
/**
|
|
31459
|
+
* Build one body, and record the model id it carries as this round's
|
|
31460
|
+
* comparison basis.
|
|
31461
|
+
*
|
|
31462
|
+
* The two are set together because they cannot disagree: `wireModel` is read
|
|
31463
|
+
* back out of the body that is about to be sent, so the id the answered-model
|
|
31464
|
+
* check compares against is by construction the id on the wire — not the
|
|
31465
|
+
* catalogue name, not a renamed lookup.
|
|
31466
|
+
*/
|
|
31226
31467
|
const buildBodyForOwner = (owner) => {
|
|
31227
|
-
|
|
31468
|
+
const built = buildMinimaxRequest({
|
|
31228
31469
|
...withUploads,
|
|
31229
31470
|
maxTokens: effectiveMax
|
|
31230
31471
|
}, images, {
|
|
@@ -31233,7 +31474,10 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
|
|
|
31233
31474
|
videoAccepted: minimaxCodeModelDef(options.model)?.inputModalities.includes("video") === true,
|
|
31234
31475
|
authOwner: owner,
|
|
31235
31476
|
route: PROVIDER_ID$4
|
|
31236
|
-
})
|
|
31477
|
+
});
|
|
31478
|
+
const serialized = assertRequestBodyFits(built);
|
|
31479
|
+
wireModel = typeof built.model === "string" ? built.model : void 0;
|
|
31480
|
+
return serialized;
|
|
31237
31481
|
};
|
|
31238
31482
|
let body = buildBodyForOwner(authOwner);
|
|
31239
31483
|
let refusedBody;
|
|
@@ -31300,6 +31544,41 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
|
|
|
31300
31544
|
* in-band reclassification below pre-output only.
|
|
31301
31545
|
*/
|
|
31302
31546
|
let outputStarted = false;
|
|
31547
|
+
/**
|
|
31548
|
+
* Whether the served-model check has already been decided for this stream.
|
|
31549
|
+
*
|
|
31550
|
+
* One decision per stream, made on the round `message_start` arrives: the field
|
|
31551
|
+
* cannot change afterwards, and re-deciding on every later frame would re-run two
|
|
31552
|
+
* string comparisons per SSE line for an answer that is already known.
|
|
31553
|
+
*/
|
|
31554
|
+
let answeredVerified = false;
|
|
31555
|
+
/**
|
|
31556
|
+
* Compare the model the service ANSWERED with against the one this request put on
|
|
31557
|
+
* the wire, and refuse the turn when they differ.
|
|
31558
|
+
*
|
|
31559
|
+
* Measured fact this exists for (docs/minimax-code-probe-capabilities.md): the
|
|
31560
|
+
* /messages endpoint answers 200 with a normal stream for a model id it cannot
|
|
31561
|
+
* route, substituting a default model — `modelless-probe-id-zzz` and the empty
|
|
31562
|
+
* string both came back as MiniMax-M3, and an unlisted but real id came back as
|
|
31563
|
+
* itself. There is no "unknown model" error payload to react to, so this header is
|
|
31564
|
+
* the ONLY evidence that the id the user selected is not the id that ran, which on
|
|
31565
|
+
* this line is a wallet problem (M3 at max effort costs about 3x the thinking and
|
|
31566
|
+
* 4x the latency of the cheaper tiers).
|
|
31567
|
+
*
|
|
31568
|
+
* Two "no verdict" cases, both deliberate: a stream whose header carries no model
|
|
31569
|
+
* (undefined) and a request whose body carried none (also undefined). Neither is
|
|
31570
|
+
* evidence of substitution, and failing a turn over an unverifiable one would turn
|
|
31571
|
+
* a protocol variation into an outage.
|
|
31572
|
+
*/
|
|
31573
|
+
const verifyAnsweredModel = () => {
|
|
31574
|
+
if (answeredVerified) return;
|
|
31575
|
+
const answered = state.answeredModel;
|
|
31576
|
+
if (answered === void 0) return;
|
|
31577
|
+
answeredVerified = true;
|
|
31578
|
+
if (wireModel === void 0) return;
|
|
31579
|
+
if (sameModelId(wireModel, answered)) return;
|
|
31580
|
+
throw modelSubstitutedFailure(wireModel, answered);
|
|
31581
|
+
};
|
|
31303
31582
|
try {
|
|
31304
31583
|
try {
|
|
31305
31584
|
while (true) {
|
|
@@ -31311,7 +31590,9 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
|
|
|
31311
31590
|
buffer = lines.pop() ?? "";
|
|
31312
31591
|
for (const line of lines) {
|
|
31313
31592
|
activity?.pulse();
|
|
31314
|
-
|
|
31593
|
+
const chunks = processMinimaxStreamLine(line, state);
|
|
31594
|
+
verifyAnsweredModel();
|
|
31595
|
+
for (const chunk of chunks) {
|
|
31315
31596
|
outputStarted = true;
|
|
31316
31597
|
yield chunk;
|
|
31317
31598
|
}
|
|
@@ -31319,9 +31600,13 @@ var MinimaxCodeAdapter = class extends LlmAdapter {
|
|
|
31319
31600
|
}
|
|
31320
31601
|
}
|
|
31321
31602
|
buffer += decoder.decode();
|
|
31322
|
-
if (buffer.trim() !== "") for (const line of buffer.split("\n"))
|
|
31323
|
-
|
|
31324
|
-
|
|
31603
|
+
if (buffer.trim() !== "") for (const line of buffer.split("\n")) {
|
|
31604
|
+
const tailChunks = processMinimaxStreamLine(line, state);
|
|
31605
|
+
verifyAnsweredModel();
|
|
31606
|
+
for (const chunk of tailChunks) {
|
|
31607
|
+
outputStarted = true;
|
|
31608
|
+
yield chunk;
|
|
31609
|
+
}
|
|
31325
31610
|
}
|
|
31326
31611
|
if (state.finished) return;
|
|
31327
31612
|
assertStreamComplete(state);
|
|
@@ -58770,6 +59055,45 @@ function md5(value) {
|
|
|
58770
59055
|
function checkinGatewayOrigin(region) {
|
|
58771
59056
|
return region === "cn" ? "https://agent.minimaxi.com" : "https://agent.minimax.io";
|
|
58772
59057
|
}
|
|
59058
|
+
/**
|
|
59059
|
+
* Non-secret identity of the SIGN-IN a check-in credential came from.
|
|
59060
|
+
*
|
|
59061
|
+
* Spelled the way `minimaxCodePoolIdentity` (account-pool.ts) and
|
|
59062
|
+
* `rotationKey` (token-store.ts) spell it — a native record slot, or the
|
|
59063
|
+
* sign-in that produced a plugin-owned credential — because it names the same
|
|
59064
|
+
* thing those do: one session, stable across every token rotation. It is
|
|
59065
|
+
* repeated here rather than imported so this wire half stays free of the pool's
|
|
59066
|
+
* imports.
|
|
59067
|
+
*
|
|
59068
|
+
* **Read this before trusting it as an account id.** It is a rotation key — a
|
|
59069
|
+
* guard rail that tells "the same session, rotated" from "a different session" —
|
|
59070
|
+
* and NOT the authoritative identity of the person behind it:
|
|
59071
|
+
*
|
|
59072
|
+
* - `native:<region>:<recordKey>` names a RECORD SLOT in the desktop app's
|
|
59073
|
+
* `auth.json`, not a user. `recordKey` is a digest of the app's auth-home
|
|
59074
|
+
* path, and the app keeps one record per slot, so signing a DIFFERENT account
|
|
59075
|
+
* in on the desktop replaces that slot's session while the key stays the same.
|
|
59076
|
+
* - `signin:<region>:<loginEpoch>` has the same shape of gap: it names the
|
|
59077
|
+
* sign-in event, not the account it produced.
|
|
59078
|
+
*
|
|
59079
|
+
* The authoritative account fact on this line is therefore the `realUserID`
|
|
59080
|
+
* resolved from the identity surface, and that is what the check-in state pins
|
|
59081
|
+
* and what an attempt is compared against. This key is supporting evidence: it
|
|
59082
|
+
* distinguishes a rotation from a swap, which `realUserID` cannot do without
|
|
59083
|
+
* a request.
|
|
59084
|
+
*
|
|
59085
|
+
* Both fields are deliberately non-secret: a record slot name and a sign-in
|
|
59086
|
+
* epoch, never a token and never a digest of one. That is what makes this the
|
|
59087
|
+
* only account identity allowed to appear in a check-in error message.
|
|
59088
|
+
*/
|
|
59089
|
+
function checkinAccountIdentity(credentials) {
|
|
59090
|
+
const region = credentials.region;
|
|
59091
|
+
if (typeof region !== "string" || region === "") return void 0;
|
|
59092
|
+
const recordKey = credentials.recordKey;
|
|
59093
|
+
if (typeof recordKey === "string" && recordKey !== "") return `native:${region}:${recordKey}`;
|
|
59094
|
+
const loginEpoch = credentials.loginEpoch;
|
|
59095
|
+
if (typeof loginEpoch === "string" && loginEpoch !== "") return `signin:${region}:${loginEpoch}`;
|
|
59096
|
+
}
|
|
58773
59097
|
const DAY_STATUSES = /* @__PURE__ */ new Set([
|
|
58774
59098
|
1,
|
|
58775
59099
|
2,
|
|
@@ -59076,6 +59400,34 @@ function localDateString(nowMs) {
|
|
|
59076
59400
|
const day = `${date.getDate()}`.padStart(2, "0");
|
|
59077
59401
|
return `${date.getFullYear()}-${month}-${day}`;
|
|
59078
59402
|
}
|
|
59403
|
+
/**
|
|
59404
|
+
* The check-in refused to act because the account changed **halfway through one
|
|
59405
|
+
* attempt**.
|
|
59406
|
+
*
|
|
59407
|
+
* This is deliberately NOT the "the pool row was re-pointed at another account"
|
|
59408
|
+
* case: that one is a legitimate state change and the entry re-synchronises to
|
|
59409
|
+
* it (see {@link MinimaxCodeCheckinService['identityFor']}). What this class
|
|
59410
|
+
* reports is the one case that must never self-heal — a forced 401 renewal that
|
|
59411
|
+
* answers with a different account — because the panel was already read for one
|
|
59412
|
+
* account and the claim would post as another.
|
|
59413
|
+
*
|
|
59414
|
+
* Its own class so the caller can tell it apart from a transport failure: it is
|
|
59415
|
+
* never retried, and never recorded as "nothing to do today". The message
|
|
59416
|
+
* carries only non-secret facts — the account keys each side resolved to — and
|
|
59417
|
+
* never a token.
|
|
59418
|
+
*/
|
|
59419
|
+
var MinimaxCodeCheckinAccountMismatchError = class extends Error {
|
|
59420
|
+
accountId;
|
|
59421
|
+
expectedIdentity;
|
|
59422
|
+
actualIdentity;
|
|
59423
|
+
constructor(accountId, expectedIdentity, actualIdentity) {
|
|
59424
|
+
super(`账号不一致:签到条目 pinned 到 ${expectedIdentity ?? "未知账号"},当前凭据属于 ${actualIdentity ?? "未知账号"};已中止本次签到(account ${accountId}),未领取。`);
|
|
59425
|
+
this.accountId = accountId;
|
|
59426
|
+
this.expectedIdentity = expectedIdentity;
|
|
59427
|
+
this.actualIdentity = actualIdentity;
|
|
59428
|
+
this.name = "MinimaxCodeCheckinAccountMismatchError";
|
|
59429
|
+
}
|
|
59430
|
+
};
|
|
59079
59431
|
function isRecord(value) {
|
|
59080
59432
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
59081
59433
|
}
|
|
@@ -59103,6 +59455,33 @@ function parseStateEntry(value) {
|
|
|
59103
59455
|
return entry;
|
|
59104
59456
|
}
|
|
59105
59457
|
/**
|
|
59458
|
+
* Refuse to act when the credential drifted away from the account this attempt
|
|
59459
|
+
* started on.
|
|
59460
|
+
*
|
|
59461
|
+
* This is the narrow, intra-attempt half of the account guard. The wide half —
|
|
59462
|
+
* "the pool row was re-pointed at another account" — is a legitimate state
|
|
59463
|
+
* change that `identityFor` re-synchronises to; this one is the case that must
|
|
59464
|
+
* never self-heal, because by the time it fires the panel and the claim would
|
|
59465
|
+
* belong to two different accounts.
|
|
59466
|
+
*
|
|
59467
|
+
* The comparison is on {@link checkinAccountIdentity}, which is deliberately
|
|
59468
|
+
* the ROTATION key rather than an account id: a rotated token of the same
|
|
59469
|
+
* sign-in passes by construction, and only a different sign-in fails. What it
|
|
59470
|
+
* cannot promise is that the sign-in behind a key is still the same person —
|
|
59471
|
+
* see the note on `native:<region>:<recordKey>` in {@link checkinAccountIdentity}
|
|
59472
|
+
* — which is exactly why the authoritative account fact in this file stays the
|
|
59473
|
+
* resolved `realUserID`, and why this check is a guard rail rather than the
|
|
59474
|
+
* identity system.
|
|
59475
|
+
*
|
|
59476
|
+
* With no key on either side there is nothing to compare, and comparing keys
|
|
59477
|
+
* that were absent when the attempt began would refuse a legitimate re-sync.
|
|
59478
|
+
*/
|
|
59479
|
+
function assertSameAccount(accountId, credentials, pinned) {
|
|
59480
|
+
const actual = checkinAccountIdentity(credentials);
|
|
59481
|
+
if (pinned === void 0 || actual === void 0 || pinned === actual) return;
|
|
59482
|
+
throw new MinimaxCodeCheckinAccountMismatchError(accountId, pinned, actual);
|
|
59483
|
+
}
|
|
59484
|
+
/**
|
|
59106
59485
|
* The check-in scheduler. One instance per plugin load; the host owns the
|
|
59107
59486
|
* interval and clears it from the same `ctx.effect` that created it.
|
|
59108
59487
|
*/
|
|
@@ -59205,19 +59584,51 @@ var MinimaxCodeCheckinService = class {
|
|
|
59205
59584
|
* it, so it is fetched from the identity surface once and kept in the state
|
|
59206
59585
|
* document. The region is cached alongside because the identity call's
|
|
59207
59586
|
* origin depends on it.
|
|
59587
|
+
*
|
|
59588
|
+
* The account identity of the resolving credential is pinned to the entry as
|
|
59589
|
+
* well: the pin records which sign-in this realUserID was learned FOR, and it
|
|
59590
|
+
* outlives the token that resolved it.
|
|
59591
|
+
*
|
|
59592
|
+
* **A re-pointed row is a state change, not a fault.** When the pin no longer
|
|
59593
|
+
* matches the credential in hand, the pool row now holds a different account
|
|
59594
|
+
* (the user signed a second account into the desktop app's sheet, or adopted
|
|
59595
|
+
* another session into this row). Following it is the correct outcome: a pool
|
|
59596
|
+
* row IS one account this plugin manages, and the check-in exists to sign in
|
|
59597
|
+
* whatever account that row now holds. Holding the stale pin instead would
|
|
59598
|
+
* mean asking the panel with A's realUserID while presenting B's token —
|
|
59599
|
+
* precisely "B's credential used to check in A" — and would have no exit,
|
|
59600
|
+
* because nothing clears a state document the card cannot reach.
|
|
59601
|
+
*
|
|
59602
|
+
* So a diverging pin re-resolves the identity WITH the credential in hand and
|
|
59603
|
+
* re-pins the entry to it. An entry written before the pin existed carries
|
|
59604
|
+
* `undefined` and re-resolves once too, which is how an old state document
|
|
59605
|
+
* heals itself into a pinned one.
|
|
59606
|
+
*
|
|
59607
|
+
* The one thing that must still never happen — an account changing halfway
|
|
59608
|
+
* through a single attempt — is caught elsewhere, because it cannot be caught
|
|
59609
|
+
* here: {@link attemptOnce}'s panel/claim pair and the forced-renewal guard in
|
|
59610
|
+
* {@link checkinOne}.
|
|
59208
59611
|
*/
|
|
59209
|
-
async identityFor(account,
|
|
59612
|
+
async identityFor(account, credentials, region) {
|
|
59613
|
+
const credentialIdentity = checkinAccountIdentity(credentials);
|
|
59210
59614
|
const cached = this.identities[account.id];
|
|
59211
|
-
if (cached !== void 0 && cached.region === region) return
|
|
59615
|
+
if (cached !== void 0 && cached.region === region && cached.accountIdentity === credentialIdentity) return {
|
|
59616
|
+
identity: cached,
|
|
59617
|
+
changedFrom: void 0
|
|
59618
|
+
};
|
|
59212
59619
|
const next = {
|
|
59213
|
-
realUserID: (await fetchAccountIdentity(accessToken, region, {
|
|
59620
|
+
realUserID: (await fetchAccountIdentity(credentials.accessToken, region, {
|
|
59214
59621
|
fetchFn: this.fetchFn,
|
|
59215
59622
|
...this.appVersion === void 0 ? {} : { appVersion: this.appVersion }
|
|
59216
59623
|
})).realUserID,
|
|
59217
|
-
region
|
|
59624
|
+
region,
|
|
59625
|
+
...credentialIdentity === void 0 ? {} : { accountIdentity: credentialIdentity }
|
|
59218
59626
|
};
|
|
59219
59627
|
this.identities[account.id] = next;
|
|
59220
|
-
return
|
|
59628
|
+
return {
|
|
59629
|
+
identity: next,
|
|
59630
|
+
changedFrom: cached?.accountIdentity !== void 0 && cached.accountIdentity !== credentialIdentity ? cached.accountIdentity : void 0
|
|
59631
|
+
};
|
|
59221
59632
|
}
|
|
59222
59633
|
/** Check one account in, recording the outcome in its today's entry. */
|
|
59223
59634
|
async checkinOne(account, today, nowMs) {
|
|
@@ -59237,11 +59648,16 @@ var MinimaxCodeCheckinService = class {
|
|
|
59237
59648
|
if (!(error instanceof MinimaxCodeCheckinHttpError) || error.status !== 401 && error.status !== 403) throw error;
|
|
59238
59649
|
delete this.identities[account.id];
|
|
59239
59650
|
const renewed = await this.pool.renewCredential(account.id, this.fetchFn);
|
|
59651
|
+
const beforeRenewal = checkinAccountIdentity(credentials);
|
|
59652
|
+
const afterRenewal = checkinAccountIdentity(renewed);
|
|
59653
|
+
if (beforeRenewal !== void 0 && afterRenewal !== void 0 && beforeRenewal !== afterRenewal) throw new MinimaxCodeCheckinAccountMismatchError(account.id, beforeRenewal, afterRenewal);
|
|
59240
59654
|
await this.attemptOnce(account, entry, renewed, region, nowMs);
|
|
59241
59655
|
}
|
|
59242
59656
|
} catch (error) {
|
|
59243
59657
|
entry.attempts += 1;
|
|
59244
59658
|
entry.lastError = error instanceof Error ? error.message : String(error);
|
|
59659
|
+
entry.inactive = false;
|
|
59660
|
+
delete entry.inactiveAt;
|
|
59245
59661
|
this.logger?.warn(`[minimax-code-checkin] ${account.id} attempt ${entry.attempts}/3 failed: ${entry.lastError}`);
|
|
59246
59662
|
}
|
|
59247
59663
|
}
|
|
@@ -59251,23 +59667,39 @@ var MinimaxCodeCheckinService = class {
|
|
|
59251
59667
|
* caller's renew-and-retry or attempt bookkeeping.
|
|
59252
59668
|
*/
|
|
59253
59669
|
async attemptOnce(account, entry, credentials, region, nowMs) {
|
|
59254
|
-
const identity = await this.identityFor(account, credentials
|
|
59255
|
-
|
|
59670
|
+
const { identity, changedFrom } = await this.identityFor(account, credentials, region);
|
|
59671
|
+
if (changedFrom !== void 0) this.logger?.warn(`[minimax-code-checkin] ${account.id} account changed since the last pass (${changedFrom} -> ${checkinAccountIdentity(credentials) ?? "unknown"}); entry re-synced to the credential now held`);
|
|
59672
|
+
const pinned = checkinAccountIdentity(credentials);
|
|
59673
|
+
const panel = await this.panel(account, credentials, identity, region, pinned);
|
|
59256
59674
|
if (this.recordPanelOutcome(entry, panel, account.id, nowMs)) return;
|
|
59257
|
-
const claim = await this.claim(credentials, identity, region);
|
|
59675
|
+
const claim = await this.claim(account, credentials, identity, region, pinned);
|
|
59258
59676
|
this.markSignedIn(entry, claim.panel);
|
|
59259
59677
|
if (claim.claim_result === 1) entry.claimedPoints = claim.points;
|
|
59260
59678
|
this.logger?.info(`[minimax-code-checkin] ${account.id} signed in; +${claim.points} credits${claim.claim_result === 2 ? " (already claimed upstream)" : ""}`);
|
|
59261
59679
|
}
|
|
59262
|
-
/**
|
|
59263
|
-
|
|
59680
|
+
/**
|
|
59681
|
+
* The status call, against the current credential.
|
|
59682
|
+
*
|
|
59683
|
+
* The guard runs BEFORE the panel is read: the credential making this request
|
|
59684
|
+
* must still be the one the identity was resolved with a moment ago.
|
|
59685
|
+
*/
|
|
59686
|
+
async panel(account, credentials, identity, region, pinned) {
|
|
59687
|
+
assertSameAccount(account.id, credentials, pinned);
|
|
59264
59688
|
return fetchSigninPanel(credentials.accessToken, identity.realUserID, region, {
|
|
59265
59689
|
fetchFn: this.fetchFn,
|
|
59266
59690
|
...this.appVersion === void 0 ? {} : { appVersion: this.appVersion }
|
|
59267
59691
|
});
|
|
59268
59692
|
}
|
|
59269
|
-
/**
|
|
59270
|
-
|
|
59693
|
+
/**
|
|
59694
|
+
* The claim call, against the current credential.
|
|
59695
|
+
*
|
|
59696
|
+
* The guard runs again here — the pair the official client protects
|
|
59697
|
+
* (`getSigninPanel` then `claimSignin`) — so a panel read for one account can
|
|
59698
|
+
* never be followed by a claim posted as another, and both calls carry the
|
|
59699
|
+
* same identity value by construction.
|
|
59700
|
+
*/
|
|
59701
|
+
async claim(account, credentials, identity, region, pinned) {
|
|
59702
|
+
assertSameAccount(account.id, credentials, pinned);
|
|
59271
59703
|
return claimSignin(credentials.accessToken, identity.realUserID, region, {
|
|
59272
59704
|
fetchFn: this.fetchFn,
|
|
59273
59705
|
...this.appVersion === void 0 ? {} : { appVersion: this.appVersion }
|
|
@@ -59357,7 +59789,8 @@ var MinimaxCodeCheckinService = class {
|
|
|
59357
59789
|
if (isRecord(parsed.identities)) {
|
|
59358
59790
|
for (const [id, value] of Object.entries(parsed.identities)) if (isRecord(value) && typeof value.realUserID === "string" && isRegion(value.region)) this.identities[id] = {
|
|
59359
59791
|
realUserID: value.realUserID,
|
|
59360
|
-
region: value.region
|
|
59792
|
+
region: value.region,
|
|
59793
|
+
...typeof value.accountIdentity === "string" && value.accountIdentity !== "" ? { accountIdentity: value.accountIdentity } : {}
|
|
59361
59794
|
};
|
|
59362
59795
|
}
|
|
59363
59796
|
}
|