@kenkaiiii/gg-core 5.89.0 → 5.91.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.
@@ -1374,6 +1374,91 @@ function isHiddenProvider(provider) {
1374
1374
  return HIDDEN_PROVIDERS.includes(provider);
1375
1375
  }
1376
1376
 
1377
+ // src/auth-storage.ts
1378
+ import { LOCAL_NO_API_KEY } from "@kenkaiiii/gg-ai";
1379
+
1380
+ // src/minimax-region.ts
1381
+ var MINIMAX_GLOBAL_BASE_URL = "https://api.minimax.io/anthropic";
1382
+ var MINIMAX_CN_BASE_URL = "https://api.minimax.cn/anthropic";
1383
+ var REGION_HOSTS = [
1384
+ { host: "https://api.minimax.io", baseUrl: MINIMAX_GLOBAL_BASE_URL },
1385
+ { host: "https://api.minimax.cn", baseUrl: MINIMAX_CN_BASE_URL }
1386
+ ];
1387
+ var KEY_KNOWN_CODES = /* @__PURE__ */ new Set([0, 2062]);
1388
+ var KEY_REJECTED_CODES = /* @__PURE__ */ new Set([1004, 2049]);
1389
+ async function probeRegion(host, apiKey, fetchImpl, timeoutMs) {
1390
+ const url = apiKey.startsWith("sk-api-") ? `${host}/account/query_balance` : `${host}/v1/token_plan/remains`;
1391
+ let sawRejection = false;
1392
+ const authHeaders = [
1393
+ { Authorization: `Bearer ${apiKey}` },
1394
+ { "x-api-key": apiKey }
1395
+ ];
1396
+ for (const auth of authHeaders) {
1397
+ let res;
1398
+ try {
1399
+ res = await fetchImpl(url, {
1400
+ headers: { ...auth, "Content-Type": "application/json" },
1401
+ signal: AbortSignal.timeout(timeoutMs)
1402
+ });
1403
+ } catch {
1404
+ return "inconclusive";
1405
+ }
1406
+ if (res.status === 401 || res.status === 403) {
1407
+ sawRejection = true;
1408
+ continue;
1409
+ }
1410
+ if (!res.ok) return "inconclusive";
1411
+ let code;
1412
+ try {
1413
+ code = (await res.json()).base_resp?.status_code;
1414
+ } catch {
1415
+ return "inconclusive";
1416
+ }
1417
+ if (typeof code === "number" && KEY_KNOWN_CODES.has(code)) return "authorized";
1418
+ if (typeof code === "number" && KEY_REJECTED_CODES.has(code)) {
1419
+ sawRejection = true;
1420
+ continue;
1421
+ }
1422
+ return "inconclusive";
1423
+ }
1424
+ return sawRejection ? "unauthorized" : "inconclusive";
1425
+ }
1426
+ async function detectMiniMaxBaseUrl(apiKey, options = {}) {
1427
+ const fetchImpl = options.fetch ?? fetch;
1428
+ const timeoutMs = options.timeoutMs ?? 5e3;
1429
+ const results = await Promise.all(
1430
+ REGION_HOSTS.map((r) => probeRegion(r.host, apiKey, fetchImpl, timeoutMs))
1431
+ );
1432
+ const index = results.indexOf("authorized");
1433
+ return index === -1 ? void 0 : REGION_HOSTS[index].baseUrl;
1434
+ }
1435
+
1436
+ // src/xiaomi-region.ts
1437
+ var XIAOMI_TOKEN_PLAN_BASE_URLS = [
1438
+ "https://token-plan-sgp.xiaomimimo.com/v1",
1439
+ "https://token-plan-ams.xiaomimimo.com/v1",
1440
+ "https://token-plan-cn.xiaomimimo.com/v1"
1441
+ ];
1442
+ async function detectXiaomiTokenPlanBaseUrl(apiKey, options = {}) {
1443
+ const fetchImpl = options.fetch ?? fetch;
1444
+ const timeoutMs = options.timeoutMs ?? 5e3;
1445
+ const accepted = await Promise.all(
1446
+ XIAOMI_TOKEN_PLAN_BASE_URLS.map(async (baseUrl) => {
1447
+ try {
1448
+ const res = await fetchImpl(`${baseUrl}/models`, {
1449
+ headers: { Authorization: `Bearer ${apiKey}` },
1450
+ signal: AbortSignal.timeout(timeoutMs)
1451
+ });
1452
+ return res.ok;
1453
+ } catch {
1454
+ return false;
1455
+ }
1456
+ })
1457
+ );
1458
+ const index = accepted.indexOf(true);
1459
+ return index === -1 ? void 0 : XIAOMI_TOKEN_PLAN_BASE_URLS[index];
1460
+ }
1461
+
1377
1462
  // src/auth-storage.ts
1378
1463
  var MOONSHOT_OAUTH_KEY = "moonshot-oauth";
1379
1464
  var XAI_OAUTH_KEY = "xai-oauth";
@@ -1424,6 +1509,15 @@ function activeBaseUrlEntry(data, provider) {
1424
1509
  }
1425
1510
  return data[provider];
1426
1511
  }
1512
+ var MINIMAX_REGION_RETRY_MS = 5 * 60 * 1e3;
1513
+ var miniMaxRegionProbes = /* @__PURE__ */ new Map();
1514
+ function cachedMiniMaxRegion(apiKey) {
1515
+ const cached = miniMaxRegionProbes.get(apiKey);
1516
+ if (cached && Date.now() - cached.at < MINIMAX_REGION_RETRY_MS) return cached.result;
1517
+ const result = detectMiniMaxBaseUrl(apiKey).catch(() => void 0);
1518
+ miniMaxRegionProbes.set(apiKey, { at: Date.now(), result });
1519
+ return result;
1520
+ }
1427
1521
  function readStoredBaseUrlSync(authFile, provider) {
1428
1522
  try {
1429
1523
  const data = JSON.parse(readFileSync2(authFile, "utf-8"));
@@ -1470,8 +1564,12 @@ var AuthStorage = class {
1470
1564
  snapshotIno = 0;
1471
1565
  /** Per-provider lock to serialize concurrent refresh calls. */
1472
1566
  refreshLocks = /* @__PURE__ */ new Map();
1473
- constructor(filePath) {
1567
+ detectMiniMaxRegion;
1568
+ detectXiaomiCluster;
1569
+ constructor(filePath, options) {
1474
1570
  this.filePath = filePath ?? getAppPaths().authFile;
1571
+ this.detectMiniMaxRegion = options?.detectMiniMaxBaseUrl ?? cachedMiniMaxRegion;
1572
+ this.detectXiaomiCluster = options?.detectXiaomiTokenPlanBaseUrl ?? detectXiaomiTokenPlanBaseUrl;
1475
1573
  }
1476
1574
  /** Path to the on-disk auth file. Useful for status output. */
1477
1575
  get path() {
@@ -1533,7 +1631,7 @@ var AuthStorage = class {
1533
1631
  */
1534
1632
  async setLocalEndpoint(endpointId, baseUrl, apiKey) {
1535
1633
  await this.setCredentials(`${LOCAL_AUTH_KEY_PREFIX}${endpointId}`, {
1536
- accessToken: apiKey && apiKey.length > 0 ? apiKey : "local",
1634
+ accessToken: apiKey && apiKey.length > 0 ? apiKey : LOCAL_NO_API_KEY,
1537
1635
  refreshToken: "",
1538
1636
  expiresAt: Date.now() + LOCAL_CREDENTIAL_LIFETIME_MS,
1539
1637
  baseUrl
@@ -1670,11 +1768,54 @@ var AuthStorage = class {
1670
1768
  await this.ensureFresh();
1671
1769
  return this.data[provider];
1672
1770
  }
1771
+ /**
1772
+ * A MiniMax key saved without an endpoint (every key, until its first use)
1773
+ * gets the endpoint of the region that issued it, saved so the check runs
1774
+ * once. Without this a Mainland China key went to the Global API, got a 401,
1775
+ * and was deleted as invalid.
1776
+ */
1777
+ async withMiniMaxRegion(creds) {
1778
+ const baseUrl = await this.detectMiniMaxRegion(creds.accessToken);
1779
+ if (!baseUrl) return creds;
1780
+ log("INFO", "auth", `MiniMax key belongs to ${baseUrl} \u2014 saved for future requests`);
1781
+ await this.mutateLatest((latest) => {
1782
+ const current = latest["minimax"];
1783
+ if (current?.accessToken === creds.accessToken && !current.baseUrl) {
1784
+ current.baseUrl = baseUrl;
1785
+ }
1786
+ });
1787
+ return { ...creds, baseUrl };
1788
+ }
1673
1789
  async setCredentials(provider, creds) {
1674
1790
  await this.mutateLatest((latest) => {
1675
1791
  latest[provider] = creds;
1676
1792
  });
1677
1793
  }
1794
+ /**
1795
+ * After a 401, move a regional key to the cluster that issued it instead of
1796
+ * treating it as invalid. Only the Xiaomi Token Plan is regional: every key
1797
+ * used to go to Singapore, so Europe and China keys were rejected and deleted.
1798
+ * Returns the new base URL, or undefined when no other cluster accepts the key.
1799
+ */
1800
+ async relocateRegionalApiKey(storageKeys) {
1801
+ const key = await this.pickStorageKey(storageKeys);
1802
+ const creds = key === "xiaomi" ? this.data[key] : void 0;
1803
+ if (!creds) return void 0;
1804
+ const baseUrl = await this.detectXiaomiCluster(creds.accessToken);
1805
+ if (!baseUrl || baseUrl === creds.baseUrl) return void 0;
1806
+ await this.mutateLatest((latest) => {
1807
+ const current = latest["xiaomi"];
1808
+ if (current?.accessToken === creds.accessToken) current.baseUrl = baseUrl;
1809
+ });
1810
+ log("INFO", "auth", `Xiaomi Token Plan key belongs to ${baseUrl} \u2014 saved for future requests`);
1811
+ return baseUrl;
1812
+ }
1813
+ // Keeps local-endpoint keys: they're the user's own config, and a 401 there is often a busy gateway.
1814
+ async clearRejectedApiKey(storageKey) {
1815
+ if (storageKey.startsWith(LOCAL_AUTH_KEY_PREFIX)) return false;
1816
+ await this.clearCredentials(storageKey);
1817
+ return true;
1818
+ }
1678
1819
  async clearCredentials(provider) {
1679
1820
  await this.mutateLatest((latest) => {
1680
1821
  delete latest[provider];
@@ -1788,6 +1929,7 @@ var AuthStorage = class {
1788
1929
  throw new NotLoggedInError(provider);
1789
1930
  }
1790
1931
  if (STATIC_API_KEY_PROVIDERS.has(provider)) {
1932
+ if (provider === "minimax" && !creds.baseUrl) return await this.withMiniMaxRegion(creds);
1791
1933
  return creds;
1792
1934
  }
1793
1935
  if (!opts?.forceRefresh && Date.now() < creds.expiresAt - refreshThresholdMs(creds)) {
@@ -2438,6 +2580,23 @@ var MODELS = [
2438
2580
  maxThinkingLevel: "max"
2439
2581
  },
2440
2582
  // ── MiniMax ────────────────────────────────────────────
2583
+ {
2584
+ // The only text model M Plan / Token Plan keys cover; MiniMax-M3 on those
2585
+ // keys fails with "insufficient balance (1008)". Pay-as-you-go serves both.
2586
+ // Always thinks (`thinking: disabled` 400s; omitted = on) with a real
2587
+ // low→max effort ladder on output_config.effort, API default max.
2588
+ id: "MiniMax-M3.1-Flash",
2589
+ name: "MiniMax M3.1 Flash",
2590
+ provider: "minimax",
2591
+ contextWindow: 1e6,
2592
+ maxOutputTokens: 131072,
2593
+ supportsThinking: true,
2594
+ supportsImages: true,
2595
+ supportsVideo: true,
2596
+ maxVideoBytes: 50 * 1024 * 1024,
2597
+ costTier: "low",
2598
+ maxThinkingLevel: "max"
2599
+ },
2441
2600
  {
2442
2601
  id: "MiniMax-M3",
2443
2602
  name: "MiniMax M3",
@@ -2688,7 +2847,7 @@ var DEFAULT_MODEL_IDS = {
2688
2847
  gemini: "gemini-3.1-flash-lite",
2689
2848
  glm: "glm-5.3",
2690
2849
  moonshot: "kimi-k3",
2691
- minimax: "MiniMax-M3",
2850
+ minimax: "MiniMax-M3.1-Flash",
2692
2851
  deepseek: "deepseek-v4-pro",
2693
2852
  huggingface: "moonshotai/Kimi-K2.7-Code",
2694
2853
  openrouter: "qwen/qwen3.8-max",
@@ -2784,6 +2943,11 @@ export {
2784
2943
  closeLogger,
2785
2944
  HIDDEN_PROVIDERS,
2786
2945
  isHiddenProvider,
2946
+ MINIMAX_GLOBAL_BASE_URL,
2947
+ MINIMAX_CN_BASE_URL,
2948
+ detectMiniMaxBaseUrl,
2949
+ XIAOMI_TOKEN_PLAN_BASE_URLS,
2950
+ detectXiaomiTokenPlanBaseUrl,
2787
2951
  MOONSHOT_OAUTH_KEY,
2788
2952
  XAI_OAUTH_KEY,
2789
2953
  dualAuthProvider,
@@ -2818,4 +2982,4 @@ export {
2818
2982
  getDefaultThinkingLevel,
2819
2983
  getSummaryModel
2820
2984
  };
2821
- //# sourceMappingURL=chunk-5ZYOOESD.js.map
2985
+ //# sourceMappingURL=chunk-M53JVW2V.js.map