@kenkaiiii/gg-core 5.90.0 → 5.91.1
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/LICENSE +661 -21
- package/NOTICE +52 -0
- package/README.md +11 -11
- package/dist/{chunk-QL5357JB.js → chunk-YXPGQIOD.js} +204 -8
- package/dist/chunk-YXPGQIOD.js.map +1 -0
- package/dist/index.cjs +287 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -3
- package/dist/index.d.ts +74 -3
- package/dist/index.js +90 -6
- package/dist/index.js.map +1 -1
- package/dist/model-registry.cjs +58 -3
- package/dist/model-registry.cjs.map +1 -1
- package/dist/model-registry.d.cts +15 -1
- package/dist/model-registry.d.ts +15 -1
- package/dist/model-registry.js +5 -1
- package/package.json +5 -4
- package/dist/chunk-QL5357JB.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -40,14 +40,18 @@ __export(index_exports, {
|
|
|
40
40
|
HIDDEN_PROVIDERS: () => HIDDEN_PROVIDERS,
|
|
41
41
|
LOCAL_API_KEY_PLACEHOLDER: () => LOCAL_API_KEY_PLACEHOLDER,
|
|
42
42
|
LOCAL_AUTH_KEY_PREFIX: () => LOCAL_AUTH_KEY_PREFIX,
|
|
43
|
+
MINIMAX_CN_BASE_URL: () => MINIMAX_CN_BASE_URL,
|
|
44
|
+
MINIMAX_GLOBAL_BASE_URL: () => MINIMAX_GLOBAL_BASE_URL,
|
|
43
45
|
MODELS: () => MODELS,
|
|
44
46
|
MOONSHOT_OAUTH_KEY: () => MOONSHOT_OAUTH_KEY,
|
|
45
47
|
NotLoggedInError: () => NotLoggedInError,
|
|
48
|
+
OPENROUTER_DEFAULT_BASE_URL: () => OPENROUTER_DEFAULT_BASE_URL,
|
|
46
49
|
PLAN_MODE_THINKING_CAP: () => PLAN_MODE_THINKING_CAP,
|
|
47
50
|
SubscriptionUsageError: () => SubscriptionUsageError,
|
|
48
51
|
TelegramBot: () => TelegramBot,
|
|
49
52
|
XAI_OAUTH_KEY: () => XAI_OAUTH_KEY,
|
|
50
53
|
XIAOMI_CREDITS_KEY: () => XIAOMI_CREDITS_KEY,
|
|
54
|
+
XIAOMI_TOKEN_PLAN_BASE_URLS: () => XIAOMI_TOKEN_PLAN_BASE_URLS,
|
|
51
55
|
authPriorityNote: () => authPriorityNote,
|
|
52
56
|
clampThinkingForPlanMode: () => clampThinkingForPlanMode,
|
|
53
57
|
clearLocalDiscoveryCache: () => clearLocalDiscoveryCache,
|
|
@@ -56,6 +60,8 @@ __export(index_exports, {
|
|
|
56
60
|
createAutoUpdater: () => createAutoUpdater,
|
|
57
61
|
decodeOggOpus: () => decodeOggOpus,
|
|
58
62
|
describeAuthMethods: () => describeAuthMethods,
|
|
63
|
+
detectMiniMaxBaseUrl: () => detectMiniMaxBaseUrl,
|
|
64
|
+
detectXiaomiTokenPlanBaseUrl: () => detectXiaomiTokenPlanBaseUrl,
|
|
59
65
|
discoverLocalModels: () => discoverLocalModels,
|
|
60
66
|
downmixToMono: () => downmixToMono,
|
|
61
67
|
dualAuthProvider: () => dualAuthProvider,
|
|
@@ -81,6 +87,7 @@ __export(index_exports, {
|
|
|
81
87
|
getModel: () => getModel,
|
|
82
88
|
getModelsForProvider: () => getModelsForProvider,
|
|
83
89
|
getNextThinkingLevel: () => getNextThinkingLevel,
|
|
90
|
+
getProviderCatalog: () => getProviderCatalog,
|
|
84
91
|
getSessionId: () => getSessionId,
|
|
85
92
|
getSummaryModel: () => getSummaryModel,
|
|
86
93
|
getSupportedThinkingLevels: () => getSupportedThinkingLevels,
|
|
@@ -110,6 +117,7 @@ __export(index_exports, {
|
|
|
110
117
|
ollamaServedContext: () => ollamaServedContext,
|
|
111
118
|
openLog: () => openLog,
|
|
112
119
|
parseLocalModelId: () => parseLocalModelId,
|
|
120
|
+
parseOpenRouterCatalog: () => parseOpenRouterCatalog,
|
|
113
121
|
pendingClaudeCodeVersionRefresh: () => import_gg_ai.pendingClaudeCodeVersionRefresh,
|
|
114
122
|
probeEndpoint: () => probeEndpoint,
|
|
115
123
|
providerStorageKeys: () => providerStorageKeys,
|
|
@@ -123,6 +131,7 @@ __export(index_exports, {
|
|
|
123
131
|
registerRuntimeModels: () => registerRuntimeModels,
|
|
124
132
|
resample: () => resample,
|
|
125
133
|
setProgressCallback: () => setProgressCallback,
|
|
134
|
+
setProviderCatalog: () => setProviderCatalog,
|
|
126
135
|
toModelInfo: () => toModelInfo,
|
|
127
136
|
transcribeVoice: () => transcribeVoice,
|
|
128
137
|
usesOpenAICodexTransport: () => usesOpenAICodexTransport,
|
|
@@ -1329,9 +1338,13 @@ async function acquireLock(lockPath) {
|
|
|
1329
1338
|
continue;
|
|
1330
1339
|
}
|
|
1331
1340
|
} catch {
|
|
1332
|
-
await import_promises.default.
|
|
1333
|
-
|
|
1334
|
-
|
|
1341
|
+
const stat = await import_promises.default.stat(lockPath).catch(() => null);
|
|
1342
|
+
if (!stat) continue;
|
|
1343
|
+
if (Date.now() - stat.mtimeMs > STALE_TIMEOUT_MS) {
|
|
1344
|
+
await import_promises.default.unlink(lockPath).catch(() => {
|
|
1345
|
+
});
|
|
1346
|
+
continue;
|
|
1347
|
+
}
|
|
1335
1348
|
}
|
|
1336
1349
|
if (Date.now() - startTime > MAX_WAIT_MS) {
|
|
1337
1350
|
await import_promises.default.unlink(lockPath).catch(() => {
|
|
@@ -1528,6 +1541,90 @@ function isHiddenProvider(provider) {
|
|
|
1528
1541
|
|
|
1529
1542
|
// src/auth-storage.ts
|
|
1530
1543
|
var import_gg_ai3 = require("@kenkaiiii/gg-ai");
|
|
1544
|
+
|
|
1545
|
+
// src/minimax-region.ts
|
|
1546
|
+
var MINIMAX_GLOBAL_BASE_URL = "https://api.minimax.io/anthropic";
|
|
1547
|
+
var MINIMAX_CN_BASE_URL = "https://api.minimax.cn/anthropic";
|
|
1548
|
+
var REGION_HOSTS = [
|
|
1549
|
+
{ host: "https://api.minimax.io", baseUrl: MINIMAX_GLOBAL_BASE_URL },
|
|
1550
|
+
{ host: "https://api.minimax.cn", baseUrl: MINIMAX_CN_BASE_URL }
|
|
1551
|
+
];
|
|
1552
|
+
var KEY_KNOWN_CODES = /* @__PURE__ */ new Set([0, 2062]);
|
|
1553
|
+
var KEY_REJECTED_CODES = /* @__PURE__ */ new Set([1004, 2049]);
|
|
1554
|
+
async function probeRegion(host, apiKey, fetchImpl, timeoutMs) {
|
|
1555
|
+
const url = apiKey.startsWith("sk-api-") ? `${host}/account/query_balance` : `${host}/v1/token_plan/remains`;
|
|
1556
|
+
let sawRejection = false;
|
|
1557
|
+
const authHeaders2 = [
|
|
1558
|
+
{ Authorization: `Bearer ${apiKey}` },
|
|
1559
|
+
{ "x-api-key": apiKey }
|
|
1560
|
+
];
|
|
1561
|
+
for (const auth of authHeaders2) {
|
|
1562
|
+
let res;
|
|
1563
|
+
try {
|
|
1564
|
+
res = await fetchImpl(url, {
|
|
1565
|
+
headers: { ...auth, "Content-Type": "application/json" },
|
|
1566
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
1567
|
+
});
|
|
1568
|
+
} catch {
|
|
1569
|
+
return "inconclusive";
|
|
1570
|
+
}
|
|
1571
|
+
if (res.status === 401 || res.status === 403) {
|
|
1572
|
+
sawRejection = true;
|
|
1573
|
+
continue;
|
|
1574
|
+
}
|
|
1575
|
+
if (!res.ok) return "inconclusive";
|
|
1576
|
+
let code;
|
|
1577
|
+
try {
|
|
1578
|
+
code = (await res.json()).base_resp?.status_code;
|
|
1579
|
+
} catch {
|
|
1580
|
+
return "inconclusive";
|
|
1581
|
+
}
|
|
1582
|
+
if (typeof code === "number" && KEY_KNOWN_CODES.has(code)) return "authorized";
|
|
1583
|
+
if (typeof code === "number" && KEY_REJECTED_CODES.has(code)) {
|
|
1584
|
+
sawRejection = true;
|
|
1585
|
+
continue;
|
|
1586
|
+
}
|
|
1587
|
+
return "inconclusive";
|
|
1588
|
+
}
|
|
1589
|
+
return sawRejection ? "unauthorized" : "inconclusive";
|
|
1590
|
+
}
|
|
1591
|
+
async function detectMiniMaxBaseUrl(apiKey, options = {}) {
|
|
1592
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
1593
|
+
const timeoutMs = options.timeoutMs ?? 5e3;
|
|
1594
|
+
const results = await Promise.all(
|
|
1595
|
+
REGION_HOSTS.map((r) => probeRegion(r.host, apiKey, fetchImpl, timeoutMs))
|
|
1596
|
+
);
|
|
1597
|
+
const index = results.indexOf("authorized");
|
|
1598
|
+
return index === -1 ? void 0 : REGION_HOSTS[index].baseUrl;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
// src/xiaomi-region.ts
|
|
1602
|
+
var XIAOMI_TOKEN_PLAN_BASE_URLS = [
|
|
1603
|
+
"https://token-plan-sgp.xiaomimimo.com/v1",
|
|
1604
|
+
"https://token-plan-ams.xiaomimimo.com/v1",
|
|
1605
|
+
"https://token-plan-cn.xiaomimimo.com/v1"
|
|
1606
|
+
];
|
|
1607
|
+
async function detectXiaomiTokenPlanBaseUrl(apiKey, options = {}) {
|
|
1608
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
1609
|
+
const timeoutMs = options.timeoutMs ?? 5e3;
|
|
1610
|
+
const accepted = await Promise.all(
|
|
1611
|
+
XIAOMI_TOKEN_PLAN_BASE_URLS.map(async (baseUrl) => {
|
|
1612
|
+
try {
|
|
1613
|
+
const res = await fetchImpl(`${baseUrl}/models`, {
|
|
1614
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
1615
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
1616
|
+
});
|
|
1617
|
+
return res.ok;
|
|
1618
|
+
} catch {
|
|
1619
|
+
return false;
|
|
1620
|
+
}
|
|
1621
|
+
})
|
|
1622
|
+
);
|
|
1623
|
+
const index = accepted.indexOf(true);
|
|
1624
|
+
return index === -1 ? void 0 : XIAOMI_TOKEN_PLAN_BASE_URLS[index];
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
// src/auth-storage.ts
|
|
1531
1628
|
var MOONSHOT_OAUTH_KEY = "moonshot-oauth";
|
|
1532
1629
|
var XAI_OAUTH_KEY = "xai-oauth";
|
|
1533
1630
|
var DUAL_AUTH_PROVIDERS = [
|
|
@@ -1577,6 +1674,15 @@ function activeBaseUrlEntry(data, provider) {
|
|
|
1577
1674
|
}
|
|
1578
1675
|
return data[provider];
|
|
1579
1676
|
}
|
|
1677
|
+
var MINIMAX_REGION_RETRY_MS = 5 * 60 * 1e3;
|
|
1678
|
+
var miniMaxRegionProbes = /* @__PURE__ */ new Map();
|
|
1679
|
+
function cachedMiniMaxRegion(apiKey) {
|
|
1680
|
+
const cached = miniMaxRegionProbes.get(apiKey);
|
|
1681
|
+
if (cached && Date.now() - cached.at < MINIMAX_REGION_RETRY_MS) return cached.result;
|
|
1682
|
+
const result = detectMiniMaxBaseUrl(apiKey).catch(() => void 0);
|
|
1683
|
+
miniMaxRegionProbes.set(apiKey, { at: Date.now(), result });
|
|
1684
|
+
return result;
|
|
1685
|
+
}
|
|
1580
1686
|
function readStoredBaseUrlSync(authFile, provider) {
|
|
1581
1687
|
try {
|
|
1582
1688
|
const data = JSON.parse((0, import_node_fs3.readFileSync)(authFile, "utf-8"));
|
|
@@ -1623,8 +1729,12 @@ var AuthStorage = class {
|
|
|
1623
1729
|
snapshotIno = 0;
|
|
1624
1730
|
/** Per-provider lock to serialize concurrent refresh calls. */
|
|
1625
1731
|
refreshLocks = /* @__PURE__ */ new Map();
|
|
1626
|
-
|
|
1732
|
+
detectMiniMaxRegion;
|
|
1733
|
+
detectXiaomiCluster;
|
|
1734
|
+
constructor(filePath, options) {
|
|
1627
1735
|
this.filePath = filePath ?? getAppPaths().authFile;
|
|
1736
|
+
this.detectMiniMaxRegion = options?.detectMiniMaxBaseUrl ?? cachedMiniMaxRegion;
|
|
1737
|
+
this.detectXiaomiCluster = options?.detectXiaomiTokenPlanBaseUrl ?? detectXiaomiTokenPlanBaseUrl;
|
|
1628
1738
|
}
|
|
1629
1739
|
/** Path to the on-disk auth file. Useful for status output. */
|
|
1630
1740
|
get path() {
|
|
@@ -1823,11 +1933,48 @@ var AuthStorage = class {
|
|
|
1823
1933
|
await this.ensureFresh();
|
|
1824
1934
|
return this.data[provider];
|
|
1825
1935
|
}
|
|
1936
|
+
/**
|
|
1937
|
+
* A MiniMax key saved without an endpoint (every key, until its first use)
|
|
1938
|
+
* gets the endpoint of the region that issued it, saved so the check runs
|
|
1939
|
+
* once. Without this a Mainland China key went to the Global API, got a 401,
|
|
1940
|
+
* and was deleted as invalid.
|
|
1941
|
+
*/
|
|
1942
|
+
async withMiniMaxRegion(creds) {
|
|
1943
|
+
const baseUrl = await this.detectMiniMaxRegion(creds.accessToken);
|
|
1944
|
+
if (!baseUrl) return creds;
|
|
1945
|
+
log("INFO", "auth", `MiniMax key belongs to ${baseUrl} \u2014 saved for future requests`);
|
|
1946
|
+
await this.mutateLatest((latest) => {
|
|
1947
|
+
const current = latest["minimax"];
|
|
1948
|
+
if (current?.accessToken === creds.accessToken && !current.baseUrl) {
|
|
1949
|
+
current.baseUrl = baseUrl;
|
|
1950
|
+
}
|
|
1951
|
+
});
|
|
1952
|
+
return { ...creds, baseUrl };
|
|
1953
|
+
}
|
|
1826
1954
|
async setCredentials(provider, creds) {
|
|
1827
1955
|
await this.mutateLatest((latest) => {
|
|
1828
1956
|
latest[provider] = creds;
|
|
1829
1957
|
});
|
|
1830
1958
|
}
|
|
1959
|
+
/**
|
|
1960
|
+
* After a 401, move a regional key to the cluster that issued it instead of
|
|
1961
|
+
* treating it as invalid. Only the Xiaomi Token Plan is regional: every key
|
|
1962
|
+
* used to go to Singapore, so Europe and China keys were rejected and deleted.
|
|
1963
|
+
* Returns the new base URL, or undefined when no other cluster accepts the key.
|
|
1964
|
+
*/
|
|
1965
|
+
async relocateRegionalApiKey(storageKeys) {
|
|
1966
|
+
const key = await this.pickStorageKey(storageKeys);
|
|
1967
|
+
const creds = key === "xiaomi" ? this.data[key] : void 0;
|
|
1968
|
+
if (!creds) return void 0;
|
|
1969
|
+
const baseUrl = await this.detectXiaomiCluster(creds.accessToken);
|
|
1970
|
+
if (!baseUrl || baseUrl === creds.baseUrl) return void 0;
|
|
1971
|
+
await this.mutateLatest((latest) => {
|
|
1972
|
+
const current = latest["xiaomi"];
|
|
1973
|
+
if (current?.accessToken === creds.accessToken) current.baseUrl = baseUrl;
|
|
1974
|
+
});
|
|
1975
|
+
log("INFO", "auth", `Xiaomi Token Plan key belongs to ${baseUrl} \u2014 saved for future requests`);
|
|
1976
|
+
return baseUrl;
|
|
1977
|
+
}
|
|
1831
1978
|
// Keeps local-endpoint keys: they're the user's own config, and a 401 there is often a busy gateway.
|
|
1832
1979
|
async clearRejectedApiKey(storageKey) {
|
|
1833
1980
|
if (storageKey.startsWith(LOCAL_AUTH_KEY_PREFIX)) return false;
|
|
@@ -1947,6 +2094,7 @@ var AuthStorage = class {
|
|
|
1947
2094
|
throw new NotLoggedInError(provider);
|
|
1948
2095
|
}
|
|
1949
2096
|
if (STATIC_API_KEY_PROVIDERS.has(provider)) {
|
|
2097
|
+
if (provider === "minimax" && !creds.baseUrl) return await this.withMiniMaxRegion(creds);
|
|
1950
2098
|
return creds;
|
|
1951
2099
|
}
|
|
1952
2100
|
if (!opts?.forceRefresh && Date.now() < creds.expiresAt - refreshThresholdMs(creds)) {
|
|
@@ -2597,6 +2745,23 @@ var MODELS = [
|
|
|
2597
2745
|
maxThinkingLevel: "max"
|
|
2598
2746
|
},
|
|
2599
2747
|
// ── MiniMax ────────────────────────────────────────────
|
|
2748
|
+
{
|
|
2749
|
+
// The only text model M Plan / Token Plan keys cover; MiniMax-M3 on those
|
|
2750
|
+
// keys fails with "insufficient balance (1008)". Pay-as-you-go serves both.
|
|
2751
|
+
// Always thinks (`thinking: disabled` 400s; omitted = on) with a real
|
|
2752
|
+
// low→max effort ladder on output_config.effort, API default max.
|
|
2753
|
+
id: "MiniMax-M3.1-Flash",
|
|
2754
|
+
name: "MiniMax M3.1 Flash",
|
|
2755
|
+
provider: "minimax",
|
|
2756
|
+
contextWindow: 1e6,
|
|
2757
|
+
maxOutputTokens: 131072,
|
|
2758
|
+
supportsThinking: true,
|
|
2759
|
+
supportsImages: true,
|
|
2760
|
+
supportsVideo: true,
|
|
2761
|
+
maxVideoBytes: 50 * 1024 * 1024,
|
|
2762
|
+
costTier: "low",
|
|
2763
|
+
maxThinkingLevel: "max"
|
|
2764
|
+
},
|
|
2600
2765
|
{
|
|
2601
2766
|
id: "MiniMax-M3",
|
|
2602
2767
|
name: "MiniMax M3",
|
|
@@ -2803,11 +2968,44 @@ function clearRuntimeModels(predicate) {
|
|
|
2803
2968
|
if (predicate(model)) runtimeModels.delete(id);
|
|
2804
2969
|
}
|
|
2805
2970
|
}
|
|
2971
|
+
var providerCatalogs = /* @__PURE__ */ new Map();
|
|
2972
|
+
function setProviderCatalog(provider, models) {
|
|
2973
|
+
if (!models) {
|
|
2974
|
+
providerCatalogs.delete(provider);
|
|
2975
|
+
return [];
|
|
2976
|
+
}
|
|
2977
|
+
const installed = /* @__PURE__ */ new Map();
|
|
2978
|
+
for (const model of models) {
|
|
2979
|
+
if (model.provider !== provider) continue;
|
|
2980
|
+
if (MODELS.some((m) => m.id === model.id && m.provider !== provider)) continue;
|
|
2981
|
+
installed.set(model.id, model);
|
|
2982
|
+
}
|
|
2983
|
+
providerCatalogs.set(provider, installed);
|
|
2984
|
+
return [...installed.values()];
|
|
2985
|
+
}
|
|
2986
|
+
function getProviderCatalog(provider) {
|
|
2987
|
+
const catalog = providerCatalogs.get(provider);
|
|
2988
|
+
return catalog ? [...catalog.values()] : void 0;
|
|
2989
|
+
}
|
|
2806
2990
|
function getAllModels() {
|
|
2807
|
-
|
|
2991
|
+
const synced = [...providerCatalogs.values()].flatMap((c) => [...c.values()]);
|
|
2992
|
+
return [
|
|
2993
|
+
...MODELS.filter((m) => !providerCatalogs.has(m.provider)),
|
|
2994
|
+
...synced,
|
|
2995
|
+
...runtimeModels.values()
|
|
2996
|
+
];
|
|
2808
2997
|
}
|
|
2809
2998
|
function getModel(id) {
|
|
2810
|
-
|
|
2999
|
+
const fixed = MODELS.find((m) => m.id === id);
|
|
3000
|
+
if (fixed && !providerCatalogs.has(fixed.provider)) return fixed;
|
|
3001
|
+
return findSynced(id) ?? fixed ?? runtimeModels.get(id);
|
|
3002
|
+
}
|
|
3003
|
+
function findSynced(id) {
|
|
3004
|
+
for (const catalog of providerCatalogs.values()) {
|
|
3005
|
+
const hit = catalog.get(id);
|
|
3006
|
+
if (hit) return hit;
|
|
3007
|
+
}
|
|
3008
|
+
return void 0;
|
|
2811
3009
|
}
|
|
2812
3010
|
function getModelsForProvider(provider) {
|
|
2813
3011
|
return getAllModels().filter((m) => m.provider === provider);
|
|
@@ -2847,7 +3045,7 @@ var DEFAULT_MODEL_IDS = {
|
|
|
2847
3045
|
gemini: "gemini-3.1-flash-lite",
|
|
2848
3046
|
glm: "glm-5.3",
|
|
2849
3047
|
moonshot: "kimi-k3",
|
|
2850
|
-
minimax: "MiniMax-M3",
|
|
3048
|
+
minimax: "MiniMax-M3.1-Flash",
|
|
2851
3049
|
deepseek: "deepseek-v4-pro",
|
|
2852
3050
|
huggingface: "moonshotai/Kimi-K2.7-Code",
|
|
2853
3051
|
openrouter: "qwen/qwen3.8-max",
|
|
@@ -2913,6 +3111,59 @@ function getSummaryModel(provider, currentModelId) {
|
|
|
2913
3111
|
return tagged ?? getModel(currentModelId) ?? getDefaultModel(provider);
|
|
2914
3112
|
}
|
|
2915
3113
|
|
|
3114
|
+
// src/openrouter-catalog.ts
|
|
3115
|
+
var OPENROUTER_DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
|
|
3116
|
+
var EFFORT_LADDER = ["low", "medium", "high", "xhigh", "max"];
|
|
3117
|
+
function positiveInt(value) {
|
|
3118
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : void 0;
|
|
3119
|
+
}
|
|
3120
|
+
function strings(value) {
|
|
3121
|
+
return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
3122
|
+
}
|
|
3123
|
+
function costTier(prompt) {
|
|
3124
|
+
const perToken = typeof prompt === "string" ? Number(prompt) : NaN;
|
|
3125
|
+
if (!Number.isFinite(perToken) || perToken < 5e-7) return "low";
|
|
3126
|
+
return perToken < 3e-6 ? "medium" : "high";
|
|
3127
|
+
}
|
|
3128
|
+
function parseOpenRouterCatalog(body) {
|
|
3129
|
+
const data = body?.data;
|
|
3130
|
+
if (!Array.isArray(data)) return { models: [], skipped: 0 };
|
|
3131
|
+
const models = [];
|
|
3132
|
+
let skipped = 0;
|
|
3133
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3134
|
+
for (const raw of data) {
|
|
3135
|
+
const id = typeof raw?.id === "string" ? raw.id.trim() : "";
|
|
3136
|
+
const params = strings(raw?.supported_parameters);
|
|
3137
|
+
const contextWindow = positiveInt(raw?.top_provider?.context_length) ?? positiveInt(raw?.context_length);
|
|
3138
|
+
if (!id || seen.has(id) || !params.includes("tools") || !contextWindow) {
|
|
3139
|
+
skipped++;
|
|
3140
|
+
continue;
|
|
3141
|
+
}
|
|
3142
|
+
seen.add(id);
|
|
3143
|
+
const efforts = strings(raw.reasoning?.supported_efforts);
|
|
3144
|
+
const ladder = EFFORT_LADDER.filter((rung) => efforts.includes(rung));
|
|
3145
|
+
const supportsThinking = ladder.length > 0 || params.includes("reasoning") || params.includes("reasoning_effort");
|
|
3146
|
+
const defaultEffort = raw.reasoning?.default_effort;
|
|
3147
|
+
const maxOutput = positiveInt(raw.top_provider?.max_completion_tokens) ?? Math.min(contextWindow, 16384);
|
|
3148
|
+
models.push({
|
|
3149
|
+
id,
|
|
3150
|
+
name: typeof raw.name === "string" && raw.name.trim() ? raw.name.trim() : id,
|
|
3151
|
+
provider: "openrouter",
|
|
3152
|
+
contextWindow,
|
|
3153
|
+
maxOutputTokens: Math.min(maxOutput, contextWindow),
|
|
3154
|
+
supportsThinking,
|
|
3155
|
+
supportsImages: strings(raw.architecture?.input_modalities).includes("image"),
|
|
3156
|
+
// Video needs a per-transport payload cap the catalog doesn't publish.
|
|
3157
|
+
supportsVideo: false,
|
|
3158
|
+
costTier: costTier(raw.pricing?.prompt),
|
|
3159
|
+
maxThinkingLevel: ladder[ladder.length - 1] ?? "high",
|
|
3160
|
+
...ladder.length > 0 ? { thinkingLevels: ladder } : {},
|
|
3161
|
+
...typeof defaultEffort === "string" && ladder.includes(defaultEffort) ? { defaultThinkingLevel: defaultEffort } : {}
|
|
3162
|
+
});
|
|
3163
|
+
}
|
|
3164
|
+
return { models, skipped };
|
|
3165
|
+
}
|
|
3166
|
+
|
|
2916
3167
|
// src/thinking-level.ts
|
|
2917
3168
|
var OPENAI_GPT_THINKING_LEVELS = ["medium", "high", "xhigh"];
|
|
2918
3169
|
var OPENAI_GPT_56_THINKING_LEVELS = [
|
|
@@ -2941,6 +3192,13 @@ var ANTHROPIC_ADAPTIVE_THINKING_LEVELS = [
|
|
|
2941
3192
|
];
|
|
2942
3193
|
var MOONSHOT_K3_THINKING_LEVELS = ["low", "high", "max"];
|
|
2943
3194
|
var GLM_THINKING_LEVELS = ["low", "medium", "high", "xhigh", "max"];
|
|
3195
|
+
var MINIMAX_EFFORT_THINKING_LEVELS = [
|
|
3196
|
+
"low",
|
|
3197
|
+
"medium",
|
|
3198
|
+
"high",
|
|
3199
|
+
"xhigh",
|
|
3200
|
+
"max"
|
|
3201
|
+
];
|
|
2944
3202
|
var LOCAL_THINKING_LEVELS = ["low", "medium", "high", "max"];
|
|
2945
3203
|
function isOpenAIGptModel(provider, model) {
|
|
2946
3204
|
return provider === "openai" && model.startsWith("gpt-");
|
|
@@ -2957,6 +3215,9 @@ function isMoonshotK3Model(provider, model) {
|
|
|
2957
3215
|
function isGlmModel(provider) {
|
|
2958
3216
|
return provider === "glm";
|
|
2959
3217
|
}
|
|
3218
|
+
function isMiniMaxEffortModel(provider, model) {
|
|
3219
|
+
return provider === "minimax" && model.startsWith("MiniMax-M3.1");
|
|
3220
|
+
}
|
|
2960
3221
|
function isAnthropicXhighModel(provider, model) {
|
|
2961
3222
|
return provider === "anthropic" && /opus-5|opus-4-8|opus-4-7|sonnet-5[-.]5|haiku-5[-.]5/.test(model);
|
|
2962
3223
|
}
|
|
@@ -2970,6 +3231,8 @@ function getSupportedThinkingLevels(provider, model) {
|
|
|
2970
3231
|
const maxIndex2 = LOCAL_THINKING_LEVELS.indexOf(info.maxThinkingLevel);
|
|
2971
3232
|
return maxIndex2 === -1 ? LOCAL_THINKING_LEVELS.slice(0, 3) : LOCAL_THINKING_LEVELS.slice(0, maxIndex2 + 1);
|
|
2972
3233
|
}
|
|
3234
|
+
const declared = getModel(model)?.thinkingLevels;
|
|
3235
|
+
if (declared && declared.length > 0) return declared;
|
|
2973
3236
|
const maxLevel = getMaxThinkingLevel(model);
|
|
2974
3237
|
if (isAnthropicAdaptiveModel(provider, model)) {
|
|
2975
3238
|
const levels2 = isAnthropicXhighModel(provider, model) ? ANTHROPIC_XHIGH_THINKING_LEVELS : ANTHROPIC_ADAPTIVE_THINKING_LEVELS;
|
|
@@ -2989,6 +3252,7 @@ function getSupportedThinkingLevels(provider, model) {
|
|
|
2989
3252
|
}
|
|
2990
3253
|
if (isMoonshotK3Model(provider, model)) return MOONSHOT_K3_THINKING_LEVELS;
|
|
2991
3254
|
if (provider === "deepseek") return DEEPSEEK_THINKING_LEVELS;
|
|
3255
|
+
if (isMiniMaxEffortModel(provider, model)) return MINIMAX_EFFORT_THINKING_LEVELS;
|
|
2992
3256
|
if (isGlmModel(provider)) {
|
|
2993
3257
|
const maxIndex2 = GLM_THINKING_LEVELS.indexOf(maxLevel);
|
|
2994
3258
|
if (maxIndex2 === -1) return GLM_THINKING_LEVELS;
|
|
@@ -3009,7 +3273,7 @@ function isThinkingLevelSupported(provider, model, level) {
|
|
|
3009
3273
|
}
|
|
3010
3274
|
function getNextThinkingLevel(provider, model, current) {
|
|
3011
3275
|
const supportedLevels = getSupportedThinkingLevels(provider, model);
|
|
3012
|
-
const shouldCycleLevels = isOpenAIGptModel(provider, model) || isAnthropicAdaptiveModel(provider, model) || isSakanaModel(provider) || isXaiModel(provider) || isMoonshotK3Model(provider, model) || isGlmModel(provider) || provider === "deepseek" || // Local servers take a real effort level, not just on/off: Ollama accepts
|
|
3276
|
+
const shouldCycleLevels = isOpenAIGptModel(provider, model) || isAnthropicAdaptiveModel(provider, model) || isSakanaModel(provider) || isXaiModel(provider) || isMoonshotK3Model(provider, model) || isGlmModel(provider) || isMiniMaxEffortModel(provider, model) || provider === "deepseek" || // Local servers take a real effort level, not just on/off: Ollama accepts
|
|
3013
3277
|
// low/medium/high on `reasoning_effort` (verified against 0.32) and the
|
|
3014
3278
|
// other OpenAI-compatible servers use the same three. A model that can't
|
|
3015
3279
|
// reason at all already has no supported levels, so it never gets here.
|
|
@@ -3124,7 +3388,9 @@ async function probeEndpoint(endpoint, { timeoutMs = DEFAULT_PROBE_TIMEOUT_MS, s
|
|
|
3124
3388
|
const entries = (list.data ?? []).filter(
|
|
3125
3389
|
(entry) => typeof entry.id === "string" && entry.id.length > 0 && !NON_CHAT_ID_PATTERN.test(entry.id)
|
|
3126
3390
|
);
|
|
3127
|
-
const
|
|
3391
|
+
const enriched = await enrich(endpoint, entries, { timeoutMs, signal });
|
|
3392
|
+
const pinned = contextLength(endpoint.contextLength);
|
|
3393
|
+
const models = pinned === void 0 ? enriched : enriched.map((m) => ({ ...m, contextWindow: pinned, contextWindowKnown: true }));
|
|
3128
3394
|
log("INFO", "local-models", `Probed ${endpoint.label}`, {
|
|
3129
3395
|
baseUrl: endpoint.baseUrl,
|
|
3130
3396
|
models: String(models.length)
|
|
@@ -3150,7 +3416,7 @@ async function enrichCustom(endpoint, entries, options) {
|
|
|
3150
3416
|
return generic;
|
|
3151
3417
|
}
|
|
3152
3418
|
function genericModel(endpoint, entry) {
|
|
3153
|
-
const declared = contextLength(entry.max_model_len) ?? contextLength(entry.context_length);
|
|
3419
|
+
const declared = contextLength(entry.max_model_len) ?? contextLength(entry.context_length) ?? contextLength(entry.meta?.n_ctx);
|
|
3154
3420
|
return {
|
|
3155
3421
|
rawId: entry.id,
|
|
3156
3422
|
endpointId: endpoint.id,
|
|
@@ -3330,7 +3596,7 @@ function toModelInfo(model, endpoint) {
|
|
|
3330
3596
|
}
|
|
3331
3597
|
var cache;
|
|
3332
3598
|
function cacheKey(endpoints) {
|
|
3333
|
-
return endpoints.map((e) => `${e.id}@${e.baseUrl}`).join("|");
|
|
3599
|
+
return endpoints.map((e) => `${e.id}@${e.baseUrl}#${e.contextLength ?? ""}`).join("|");
|
|
3334
3600
|
}
|
|
3335
3601
|
async function discoverLocalModels(endpoints = DEFAULT_LOCAL_ENDPOINTS, options = {}) {
|
|
3336
3602
|
const key = cacheKey(endpoints);
|
|
@@ -3451,7 +3717,7 @@ var ALL_AUTH_PROVIDERS = [
|
|
|
3451
3717
|
{
|
|
3452
3718
|
value: "minimax",
|
|
3453
3719
|
label: "MiniMax",
|
|
3454
|
-
description: "MiniMax M3",
|
|
3720
|
+
description: "MiniMax M3.1 Flash, M3",
|
|
3455
3721
|
methods: ["apikey"],
|
|
3456
3722
|
apiKeyLabel: "MiniMax"
|
|
3457
3723
|
},
|
|
@@ -4284,14 +4550,18 @@ function createAutoUpdater(config) {
|
|
|
4284
4550
|
HIDDEN_PROVIDERS,
|
|
4285
4551
|
LOCAL_API_KEY_PLACEHOLDER,
|
|
4286
4552
|
LOCAL_AUTH_KEY_PREFIX,
|
|
4553
|
+
MINIMAX_CN_BASE_URL,
|
|
4554
|
+
MINIMAX_GLOBAL_BASE_URL,
|
|
4287
4555
|
MODELS,
|
|
4288
4556
|
MOONSHOT_OAUTH_KEY,
|
|
4289
4557
|
NotLoggedInError,
|
|
4558
|
+
OPENROUTER_DEFAULT_BASE_URL,
|
|
4290
4559
|
PLAN_MODE_THINKING_CAP,
|
|
4291
4560
|
SubscriptionUsageError,
|
|
4292
4561
|
TelegramBot,
|
|
4293
4562
|
XAI_OAUTH_KEY,
|
|
4294
4563
|
XIAOMI_CREDITS_KEY,
|
|
4564
|
+
XIAOMI_TOKEN_PLAN_BASE_URLS,
|
|
4295
4565
|
authPriorityNote,
|
|
4296
4566
|
clampThinkingForPlanMode,
|
|
4297
4567
|
clearLocalDiscoveryCache,
|
|
@@ -4300,6 +4570,8 @@ function createAutoUpdater(config) {
|
|
|
4300
4570
|
createAutoUpdater,
|
|
4301
4571
|
decodeOggOpus,
|
|
4302
4572
|
describeAuthMethods,
|
|
4573
|
+
detectMiniMaxBaseUrl,
|
|
4574
|
+
detectXiaomiTokenPlanBaseUrl,
|
|
4303
4575
|
discoverLocalModels,
|
|
4304
4576
|
downmixToMono,
|
|
4305
4577
|
dualAuthProvider,
|
|
@@ -4325,6 +4597,7 @@ function createAutoUpdater(config) {
|
|
|
4325
4597
|
getModel,
|
|
4326
4598
|
getModelsForProvider,
|
|
4327
4599
|
getNextThinkingLevel,
|
|
4600
|
+
getProviderCatalog,
|
|
4328
4601
|
getSessionId,
|
|
4329
4602
|
getSummaryModel,
|
|
4330
4603
|
getSupportedThinkingLevels,
|
|
@@ -4354,6 +4627,7 @@ function createAutoUpdater(config) {
|
|
|
4354
4627
|
ollamaServedContext,
|
|
4355
4628
|
openLog,
|
|
4356
4629
|
parseLocalModelId,
|
|
4630
|
+
parseOpenRouterCatalog,
|
|
4357
4631
|
pendingClaudeCodeVersionRefresh,
|
|
4358
4632
|
probeEndpoint,
|
|
4359
4633
|
providerStorageKeys,
|
|
@@ -4367,6 +4641,7 @@ function createAutoUpdater(config) {
|
|
|
4367
4641
|
registerRuntimeModels,
|
|
4368
4642
|
resample,
|
|
4369
4643
|
setProgressCallback,
|
|
4644
|
+
setProviderCatalog,
|
|
4370
4645
|
toModelInfo,
|
|
4371
4646
|
transcribeVoice,
|
|
4372
4647
|
usesOpenAICodexTransport,
|