claudish 5.8.0 → 5.9.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/dist/index.js +468 -52
- package/package.json +1 -1
- package/recommended-models.json +7 -7
package/dist/index.js
CHANGED
|
@@ -29458,7 +29458,7 @@ var getRemoteProviders = () => [
|
|
|
29458
29458
|
authScheme: "bearer",
|
|
29459
29459
|
capabilities: {
|
|
29460
29460
|
supportsTools: true,
|
|
29461
|
-
supportsVision:
|
|
29461
|
+
supportsVision: false,
|
|
29462
29462
|
supportsStreaming: true,
|
|
29463
29463
|
supportsJsonMode: false,
|
|
29464
29464
|
supportsReasoning: false
|
|
@@ -29941,9 +29941,7 @@ function checkApiKeyForProvider(nativeProvider, modelName) {
|
|
|
29941
29941
|
}
|
|
29942
29942
|
function getAutoRouteHint(modelName, nativeProvider) {
|
|
29943
29943
|
const hint = PROVIDER_HINT_MAP[nativeProvider];
|
|
29944
|
-
const lines = [
|
|
29945
|
-
`No credentials found for "${modelName}". Options:`
|
|
29946
|
-
];
|
|
29944
|
+
const lines = [`No credentials found for "${modelName}". Options:`];
|
|
29947
29945
|
let hasOption = false;
|
|
29948
29946
|
if (hint?.loginFlag) {
|
|
29949
29947
|
lines.push(` Run: claudish ${hint.loginFlag} (authenticate via OAuth)`);
|
|
@@ -30004,7 +30002,61 @@ function autoRoute(modelName, nativeProvider) {
|
|
|
30004
30002
|
}
|
|
30005
30003
|
return null;
|
|
30006
30004
|
}
|
|
30007
|
-
|
|
30005
|
+
function hasProviderCredentials(provider) {
|
|
30006
|
+
const keyInfo = API_KEY_ENV_VARS[provider];
|
|
30007
|
+
if (keyInfo?.envVar && process.env[keyInfo.envVar])
|
|
30008
|
+
return true;
|
|
30009
|
+
if (keyInfo?.aliases?.some((a) => process.env[a]))
|
|
30010
|
+
return true;
|
|
30011
|
+
return hasOAuthCredentials(provider);
|
|
30012
|
+
}
|
|
30013
|
+
function getFallbackChain(modelName, nativeProvider) {
|
|
30014
|
+
const routes = [];
|
|
30015
|
+
const litellmBaseUrl = process.env.LITELLM_BASE_URL;
|
|
30016
|
+
if (litellmBaseUrl && process.env.LITELLM_API_KEY) {
|
|
30017
|
+
routes.push({
|
|
30018
|
+
provider: "litellm",
|
|
30019
|
+
modelSpec: `litellm@${modelName}`,
|
|
30020
|
+
displayName: "LiteLLM"
|
|
30021
|
+
});
|
|
30022
|
+
}
|
|
30023
|
+
if (process.env.OPENCODE_API_KEY) {
|
|
30024
|
+
routes.push({
|
|
30025
|
+
provider: "opencode-zen",
|
|
30026
|
+
modelSpec: `zen@${modelName}`,
|
|
30027
|
+
displayName: "OpenCode Zen"
|
|
30028
|
+
});
|
|
30029
|
+
}
|
|
30030
|
+
const sub = SUBSCRIPTION_ALTERNATIVES[nativeProvider];
|
|
30031
|
+
if (sub && hasProviderCredentials(sub.subscriptionProvider)) {
|
|
30032
|
+
const subModelName = sub.modelName || modelName;
|
|
30033
|
+
routes.push({
|
|
30034
|
+
provider: sub.subscriptionProvider,
|
|
30035
|
+
modelSpec: `${sub.prefix}@${subModelName}`,
|
|
30036
|
+
displayName: sub.displayName
|
|
30037
|
+
});
|
|
30038
|
+
}
|
|
30039
|
+
if (nativeProvider !== "unknown" && nativeProvider !== "qwen" && nativeProvider !== "native-anthropic") {
|
|
30040
|
+
if (hasProviderCredentials(nativeProvider)) {
|
|
30041
|
+
const prefix = PROVIDER_TO_PREFIX[nativeProvider] || nativeProvider;
|
|
30042
|
+
routes.push({
|
|
30043
|
+
provider: nativeProvider,
|
|
30044
|
+
modelSpec: `${prefix}@${modelName}`,
|
|
30045
|
+
displayName: DISPLAY_NAMES[nativeProvider] || nativeProvider
|
|
30046
|
+
});
|
|
30047
|
+
}
|
|
30048
|
+
}
|
|
30049
|
+
if (process.env.OPENROUTER_API_KEY) {
|
|
30050
|
+
const resolution = resolveModelNameSync(modelName, "openrouter");
|
|
30051
|
+
routes.push({
|
|
30052
|
+
provider: "openrouter",
|
|
30053
|
+
modelSpec: resolution.resolvedId,
|
|
30054
|
+
displayName: "OpenRouter"
|
|
30055
|
+
});
|
|
30056
|
+
}
|
|
30057
|
+
return routes;
|
|
30058
|
+
}
|
|
30059
|
+
var API_KEY_ENV_VARS, PROVIDER_HINT_MAP, PROVIDER_TO_PREFIX, DISPLAY_NAMES, SUBSCRIPTION_ALTERNATIVES;
|
|
30008
30060
|
var init_auto_route = __esm(() => {
|
|
30009
30061
|
init_oauth_registry();
|
|
30010
30062
|
init_model_catalog_resolver();
|
|
@@ -30068,6 +30120,65 @@ var init_auto_route = __esm(() => {
|
|
|
30068
30120
|
apiKeyEnvVar: "OLLAMA_API_KEY"
|
|
30069
30121
|
}
|
|
30070
30122
|
};
|
|
30123
|
+
PROVIDER_TO_PREFIX = {
|
|
30124
|
+
google: "g",
|
|
30125
|
+
openai: "oai",
|
|
30126
|
+
minimax: "mm",
|
|
30127
|
+
"minimax-coding": "mmc",
|
|
30128
|
+
kimi: "kimi",
|
|
30129
|
+
"kimi-coding": "kc",
|
|
30130
|
+
glm: "glm",
|
|
30131
|
+
"glm-coding": "gc",
|
|
30132
|
+
zai: "zai",
|
|
30133
|
+
ollamacloud: "oc",
|
|
30134
|
+
"opencode-zen": "zen",
|
|
30135
|
+
"opencode-zen-go": "zengo",
|
|
30136
|
+
litellm: "ll",
|
|
30137
|
+
vertex: "v",
|
|
30138
|
+
"gemini-codeassist": "go"
|
|
30139
|
+
};
|
|
30140
|
+
DISPLAY_NAMES = {
|
|
30141
|
+
google: "Gemini",
|
|
30142
|
+
openai: "OpenAI",
|
|
30143
|
+
minimax: "MiniMax",
|
|
30144
|
+
"minimax-coding": "MiniMax Coding",
|
|
30145
|
+
kimi: "Kimi",
|
|
30146
|
+
"kimi-coding": "Kimi Coding",
|
|
30147
|
+
glm: "GLM",
|
|
30148
|
+
"glm-coding": "GLM Coding",
|
|
30149
|
+
zai: "Z.AI",
|
|
30150
|
+
ollamacloud: "OllamaCloud",
|
|
30151
|
+
"opencode-zen": "OpenCode Zen",
|
|
30152
|
+
"opencode-zen-go": "OpenCode Zen Go",
|
|
30153
|
+
litellm: "LiteLLM",
|
|
30154
|
+
openrouter: "OpenRouter"
|
|
30155
|
+
};
|
|
30156
|
+
SUBSCRIPTION_ALTERNATIVES = {
|
|
30157
|
+
kimi: {
|
|
30158
|
+
subscriptionProvider: "kimi-coding",
|
|
30159
|
+
modelName: "kimi-for-coding",
|
|
30160
|
+
prefix: "kc",
|
|
30161
|
+
displayName: "Kimi Coding"
|
|
30162
|
+
},
|
|
30163
|
+
minimax: {
|
|
30164
|
+
subscriptionProvider: "minimax-coding",
|
|
30165
|
+
modelName: null,
|
|
30166
|
+
prefix: "mmc",
|
|
30167
|
+
displayName: "MiniMax Coding"
|
|
30168
|
+
},
|
|
30169
|
+
glm: {
|
|
30170
|
+
subscriptionProvider: "glm-coding",
|
|
30171
|
+
modelName: null,
|
|
30172
|
+
prefix: "gc",
|
|
30173
|
+
displayName: "GLM Coding"
|
|
30174
|
+
},
|
|
30175
|
+
google: {
|
|
30176
|
+
subscriptionProvider: "gemini-codeassist",
|
|
30177
|
+
modelName: null,
|
|
30178
|
+
prefix: "go",
|
|
30179
|
+
displayName: "Gemini Code Assist"
|
|
30180
|
+
}
|
|
30181
|
+
};
|
|
30071
30182
|
});
|
|
30072
30183
|
|
|
30073
30184
|
// src/providers/provider-resolver.ts
|
|
@@ -31844,7 +31955,7 @@ async function fetchGLMCodingModels() {
|
|
|
31844
31955
|
return [];
|
|
31845
31956
|
}
|
|
31846
31957
|
}
|
|
31847
|
-
var __filename4, __dirname4, VERSION = "5.
|
|
31958
|
+
var __filename4, __dirname4, VERSION = "5.9.0", CACHE_MAX_AGE_DAYS2 = 2, MODELS_JSON_PATH, CLAUDISH_CACHE_DIR2, ALL_MODELS_JSON_PATH;
|
|
31848
31959
|
var init_cli = __esm(() => {
|
|
31849
31960
|
init_config();
|
|
31850
31961
|
init_model_loader();
|
|
@@ -34509,7 +34620,9 @@ async function fetchZenGoModels() {
|
|
|
34509
34620
|
return [];
|
|
34510
34621
|
const ZEN_GO_BASE = process.env.OPENCODE_BASE_URL ? process.env.OPENCODE_BASE_URL.replace("/zen", "/zen/go") : "https://opencode.ai/zen/go";
|
|
34511
34622
|
try {
|
|
34512
|
-
const mdevResp = await fetch("https://models.dev/api.json", {
|
|
34623
|
+
const mdevResp = await fetch("https://models.dev/api.json", {
|
|
34624
|
+
signal: AbortSignal.timeout(5000)
|
|
34625
|
+
});
|
|
34513
34626
|
if (!mdevResp.ok)
|
|
34514
34627
|
return [];
|
|
34515
34628
|
const mdevData = await mdevResp.json();
|
|
@@ -34521,7 +34634,11 @@ async function fetchZenGoModels() {
|
|
|
34521
34634
|
const r = await fetch(`${ZEN_GO_BASE}/v1/chat/completions`, {
|
|
34522
34635
|
method: "POST",
|
|
34523
34636
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
|
|
34524
|
-
body: JSON.stringify({
|
|
34637
|
+
body: JSON.stringify({
|
|
34638
|
+
model: modelId,
|
|
34639
|
+
messages: [{ role: "user", content: "hi" }],
|
|
34640
|
+
max_tokens: 1
|
|
34641
|
+
}),
|
|
34525
34642
|
signal: AbortSignal.timeout(8000)
|
|
34526
34643
|
});
|
|
34527
34644
|
if (!r.ok)
|
|
@@ -34982,7 +35099,10 @@ async function getAllModelsForSearch(forceUpdate = false) {
|
|
|
34982
35099
|
const litellmBaseUrl = process.env.LITELLM_BASE_URL;
|
|
34983
35100
|
const litellmApiKey = process.env.LITELLM_API_KEY;
|
|
34984
35101
|
const fetchEntries = [
|
|
34985
|
-
{
|
|
35102
|
+
{
|
|
35103
|
+
name: "OpenRouter",
|
|
35104
|
+
promise: fetchAllModels(forceUpdate).then((models) => models.map(toModelInfo))
|
|
35105
|
+
},
|
|
34986
35106
|
{ name: "xAI", promise: fetchXAIModels() },
|
|
34987
35107
|
{ name: "Gemini", promise: fetchGeminiModels() },
|
|
34988
35108
|
{ name: "OpenAI", promise: fetchOpenAIModels() },
|
|
@@ -34993,7 +35113,10 @@ async function getAllModelsForSearch(forceUpdate = false) {
|
|
|
34993
35113
|
{ name: "Zen Go", promise: fetchZenGoModels() }
|
|
34994
35114
|
];
|
|
34995
35115
|
if (litellmBaseUrl && litellmApiKey) {
|
|
34996
|
-
fetchEntries.push({
|
|
35116
|
+
fetchEntries.push({
|
|
35117
|
+
name: "LiteLLM",
|
|
35118
|
+
promise: fetchLiteLLMModels(litellmBaseUrl, litellmApiKey, forceUpdate)
|
|
35119
|
+
});
|
|
34997
35120
|
}
|
|
34998
35121
|
const settled = await Promise.allSettled(fetchEntries.map((e) => e.promise));
|
|
34999
35122
|
const fetchResults = {};
|
|
@@ -35205,9 +35328,24 @@ function getKnownModels(provider) {
|
|
|
35205
35328
|
{ id: "google@gemini-2.0-flash", name: "Gemini 2.0 Flash", context: "1M" }
|
|
35206
35329
|
],
|
|
35207
35330
|
openai: [
|
|
35208
|
-
{
|
|
35209
|
-
|
|
35210
|
-
|
|
35331
|
+
{
|
|
35332
|
+
id: "oai@gpt-5.3-codex",
|
|
35333
|
+
name: "GPT-5.3 Codex",
|
|
35334
|
+
context: "400K",
|
|
35335
|
+
description: "Latest coding model"
|
|
35336
|
+
},
|
|
35337
|
+
{
|
|
35338
|
+
id: "oai@gpt-5.2-codex",
|
|
35339
|
+
name: "GPT-5.2 Codex",
|
|
35340
|
+
context: "400K",
|
|
35341
|
+
description: "Coding model"
|
|
35342
|
+
},
|
|
35343
|
+
{
|
|
35344
|
+
id: "oai@gpt-5.1-codex-mini",
|
|
35345
|
+
name: "GPT-5.1 Codex Mini",
|
|
35346
|
+
context: "400K",
|
|
35347
|
+
description: "Fast coding model"
|
|
35348
|
+
},
|
|
35211
35349
|
{ id: "oai@o3", name: "o3", context: "200K", description: "Reasoning model" },
|
|
35212
35350
|
{ id: "oai@o4-mini", name: "o4-mini", context: "200K", description: "Fast reasoning model" },
|
|
35213
35351
|
{ id: "oai@gpt-4.1", name: "GPT-4.1", context: "1M", description: "Large context model" }
|
|
@@ -35215,39 +35353,102 @@ function getKnownModels(provider) {
|
|
|
35215
35353
|
xai: [
|
|
35216
35354
|
{ id: "xai@grok-4", name: "Grok 4", context: "256K" },
|
|
35217
35355
|
{ id: "xai@grok-4-fast", name: "Grok 4 Fast", context: "2M" },
|
|
35218
|
-
{
|
|
35356
|
+
{
|
|
35357
|
+
id: "xai@grok-code-fast-1",
|
|
35358
|
+
name: "Grok Code Fast 1",
|
|
35359
|
+
context: "256K",
|
|
35360
|
+
description: "Optimized for coding"
|
|
35361
|
+
}
|
|
35219
35362
|
],
|
|
35220
35363
|
minimax: [
|
|
35221
|
-
{
|
|
35364
|
+
{
|
|
35365
|
+
id: "mm@minimax-m2.1",
|
|
35366
|
+
name: "MiniMax M2.1",
|
|
35367
|
+
context: "196K",
|
|
35368
|
+
description: "Lightweight coding model"
|
|
35369
|
+
}
|
|
35222
35370
|
],
|
|
35223
35371
|
"minimax-coding": [
|
|
35224
|
-
{
|
|
35225
|
-
|
|
35372
|
+
{
|
|
35373
|
+
id: "mmc@minimax-m2.5",
|
|
35374
|
+
name: "MiniMax M2.5",
|
|
35375
|
+
context: "196K",
|
|
35376
|
+
description: "MiniMax Coding subscription model"
|
|
35377
|
+
},
|
|
35378
|
+
{
|
|
35379
|
+
id: "mmc@minimax-m2.1",
|
|
35380
|
+
name: "MiniMax M2.1",
|
|
35381
|
+
context: "196K",
|
|
35382
|
+
description: "MiniMax Coding subscription model"
|
|
35383
|
+
}
|
|
35226
35384
|
],
|
|
35227
35385
|
kimi: [
|
|
35228
35386
|
{ id: "kimi@kimi-k2-thinking-turbo", name: "Kimi K2 Thinking Turbo", context: "128K" },
|
|
35229
35387
|
{ id: "kimi@moonshot-v1-128k", name: "Moonshot V1 128K", context: "128K" }
|
|
35230
35388
|
],
|
|
35231
35389
|
"kimi-coding": [
|
|
35232
|
-
{
|
|
35390
|
+
{
|
|
35391
|
+
id: "kc@kimi-for-coding",
|
|
35392
|
+
name: "Kimi for Coding",
|
|
35393
|
+
context: "128K",
|
|
35394
|
+
description: "Kimi Coding subscription model"
|
|
35395
|
+
}
|
|
35233
35396
|
],
|
|
35234
35397
|
glm: [
|
|
35235
|
-
{
|
|
35236
|
-
|
|
35237
|
-
|
|
35398
|
+
{
|
|
35399
|
+
id: "glm@glm-5",
|
|
35400
|
+
name: "GLM-5",
|
|
35401
|
+
context: "200K",
|
|
35402
|
+
description: "Latest GLM model with reasoning"
|
|
35403
|
+
},
|
|
35404
|
+
{
|
|
35405
|
+
id: "glm@glm-4.7",
|
|
35406
|
+
name: "GLM-4.7",
|
|
35407
|
+
context: "200K",
|
|
35408
|
+
description: "GLM 4.7 with reasoning"
|
|
35409
|
+
},
|
|
35410
|
+
{
|
|
35411
|
+
id: "glm@glm-4.7-flash",
|
|
35412
|
+
name: "GLM-4.7 Flash",
|
|
35413
|
+
context: "200K",
|
|
35414
|
+
description: "Fast GLM 4.7"
|
|
35415
|
+
},
|
|
35238
35416
|
{ id: "glm@glm-4.6", name: "GLM-4.6", context: "200K" },
|
|
35239
35417
|
{ id: "glm@glm-4.5-flash", name: "GLM-4.5 Flash", context: "128K" }
|
|
35240
35418
|
],
|
|
35241
|
-
zai: [
|
|
35242
|
-
{ id: "zai@glm-4.7", name: "GLM 4.7 (Z.AI)", context: "128K" }
|
|
35243
|
-
],
|
|
35419
|
+
zai: [{ id: "zai@glm-4.7", name: "GLM 4.7 (Z.AI)", context: "128K" }],
|
|
35244
35420
|
ollamacloud: [
|
|
35245
35421
|
{ id: "oc@glm-5", name: "GLM-5", context: "203K", description: "GLM-5 on OllamaCloud" },
|
|
35246
|
-
{
|
|
35247
|
-
|
|
35248
|
-
|
|
35249
|
-
|
|
35250
|
-
|
|
35422
|
+
{
|
|
35423
|
+
id: "oc@deepseek-v3.2",
|
|
35424
|
+
name: "DeepSeek V3.2",
|
|
35425
|
+
context: "164K",
|
|
35426
|
+
description: "DeepSeek V3.2 on OllamaCloud"
|
|
35427
|
+
},
|
|
35428
|
+
{
|
|
35429
|
+
id: "oc@gemini-3-pro-preview",
|
|
35430
|
+
name: "Gemini 3 Pro Preview",
|
|
35431
|
+
context: "1M",
|
|
35432
|
+
description: "Gemini 3 Pro on OllamaCloud"
|
|
35433
|
+
},
|
|
35434
|
+
{
|
|
35435
|
+
id: "oc@kimi-k2.5",
|
|
35436
|
+
name: "Kimi K2.5",
|
|
35437
|
+
context: "262K",
|
|
35438
|
+
description: "Kimi K2.5 on OllamaCloud"
|
|
35439
|
+
},
|
|
35440
|
+
{
|
|
35441
|
+
id: "oc@qwen3-coder-next",
|
|
35442
|
+
name: "Qwen3 Coder Next",
|
|
35443
|
+
context: "262K",
|
|
35444
|
+
description: "Qwen3 Coder on OllamaCloud"
|
|
35445
|
+
},
|
|
35446
|
+
{
|
|
35447
|
+
id: "oc@minimax-m2.1",
|
|
35448
|
+
name: "MiniMax M2.1",
|
|
35449
|
+
context: "205K",
|
|
35450
|
+
description: "MiniMax M2.1 on OllamaCloud"
|
|
35451
|
+
}
|
|
35251
35452
|
]
|
|
35252
35453
|
};
|
|
35253
35454
|
const providerDisplay = provider.charAt(0).toUpperCase() + provider.slice(1);
|
|
@@ -35482,23 +35683,76 @@ var init_model_selector = __esm(() => {
|
|
|
35482
35683
|
ll: "LiteLLM"
|
|
35483
35684
|
};
|
|
35484
35685
|
ALL_PROVIDER_CHOICES = [
|
|
35485
|
-
{
|
|
35686
|
+
{
|
|
35687
|
+
name: "Skip (keep Claude default)",
|
|
35688
|
+
value: "skip",
|
|
35689
|
+
description: "Use native Claude model for this tier"
|
|
35690
|
+
},
|
|
35486
35691
|
{ name: "OpenRouter", value: "openrouter", description: "580+ models via unified API" },
|
|
35487
35692
|
{ name: "OpenCode Zen", value: "zen", description: "Free models, no API key needed" },
|
|
35488
|
-
{
|
|
35489
|
-
|
|
35490
|
-
|
|
35491
|
-
|
|
35492
|
-
|
|
35493
|
-
|
|
35494
|
-
{
|
|
35495
|
-
|
|
35496
|
-
|
|
35693
|
+
{
|
|
35694
|
+
name: "Google Gemini",
|
|
35695
|
+
value: "google",
|
|
35696
|
+
description: "Direct API (GEMINI_API_KEY)",
|
|
35697
|
+
envVar: "GEMINI_API_KEY"
|
|
35698
|
+
},
|
|
35699
|
+
{
|
|
35700
|
+
name: "OpenAI",
|
|
35701
|
+
value: "openai",
|
|
35702
|
+
description: "Direct API (OPENAI_API_KEY)",
|
|
35703
|
+
envVar: "OPENAI_API_KEY"
|
|
35704
|
+
},
|
|
35705
|
+
{
|
|
35706
|
+
name: "xAI / Grok",
|
|
35707
|
+
value: "xai",
|
|
35708
|
+
description: "Direct API (XAI_API_KEY)",
|
|
35709
|
+
envVar: "XAI_API_KEY"
|
|
35710
|
+
},
|
|
35711
|
+
{
|
|
35712
|
+
name: "MiniMax",
|
|
35713
|
+
value: "minimax",
|
|
35714
|
+
description: "Direct API (MINIMAX_API_KEY)",
|
|
35715
|
+
envVar: "MINIMAX_API_KEY"
|
|
35716
|
+
},
|
|
35717
|
+
{
|
|
35718
|
+
name: "MiniMax Coding",
|
|
35719
|
+
value: "minimax-coding",
|
|
35720
|
+
description: "MiniMax Coding subscription (MINIMAX_CODING_API_KEY)",
|
|
35721
|
+
envVar: "MINIMAX_CODING_API_KEY"
|
|
35722
|
+
},
|
|
35723
|
+
{
|
|
35724
|
+
name: "Kimi / Moonshot",
|
|
35725
|
+
value: "kimi",
|
|
35726
|
+
description: "Direct API (MOONSHOT_API_KEY)",
|
|
35727
|
+
envVar: "MOONSHOT_API_KEY"
|
|
35728
|
+
},
|
|
35729
|
+
{
|
|
35730
|
+
name: "Kimi Coding",
|
|
35731
|
+
value: "kimi-coding",
|
|
35732
|
+
description: "Kimi Coding subscription (KIMI_CODING_API_KEY)",
|
|
35733
|
+
envVar: "KIMI_CODING_API_KEY"
|
|
35734
|
+
},
|
|
35735
|
+
{
|
|
35736
|
+
name: "GLM / Zhipu",
|
|
35737
|
+
value: "glm",
|
|
35738
|
+
description: "Direct API (ZHIPU_API_KEY)",
|
|
35739
|
+
envVar: "ZHIPU_API_KEY"
|
|
35740
|
+
},
|
|
35741
|
+
{
|
|
35742
|
+
name: "GLM Coding Plan",
|
|
35743
|
+
value: "glm-coding",
|
|
35744
|
+
description: "GLM Coding subscription (GLM_CODING_API_KEY)",
|
|
35745
|
+
envVar: "GLM_CODING_API_KEY"
|
|
35746
|
+
},
|
|
35497
35747
|
{ name: "Z.AI", value: "zai", description: "Z.AI API (ZAI_API_KEY)", envVar: "ZAI_API_KEY" },
|
|
35498
35748
|
{ name: "OllamaCloud", value: "ollamacloud", description: "Cloud models (OLLAMA_API_KEY)" },
|
|
35499
35749
|
{ name: "Ollama (local)", value: "ollama", description: "Local Ollama instance" },
|
|
35500
35750
|
{ name: "LM Studio (local)", value: "lmstudio", description: "Local LM Studio instance" },
|
|
35501
|
-
{
|
|
35751
|
+
{
|
|
35752
|
+
name: "Enter custom model",
|
|
35753
|
+
value: "custom",
|
|
35754
|
+
description: "Type a provider@model specification"
|
|
35755
|
+
}
|
|
35502
35756
|
];
|
|
35503
35757
|
PROVIDER_MODEL_PREFIX = {
|
|
35504
35758
|
google: "google@",
|
|
@@ -41355,10 +41609,12 @@ var init_openai_adapter = __esm(() => {
|
|
|
41355
41609
|
result.push({
|
|
41356
41610
|
type: "message",
|
|
41357
41611
|
role: msg.role,
|
|
41358
|
-
content: [
|
|
41359
|
-
|
|
41360
|
-
|
|
41361
|
-
|
|
41612
|
+
content: [
|
|
41613
|
+
{
|
|
41614
|
+
type: msg.role === "user" ? "input_text" : "output_text",
|
|
41615
|
+
text: msg.content
|
|
41616
|
+
}
|
|
41617
|
+
]
|
|
41362
41618
|
});
|
|
41363
41619
|
continue;
|
|
41364
41620
|
}
|
|
@@ -62098,7 +62354,7 @@ class LocalTransport {
|
|
|
62098
62354
|
this.config = config3;
|
|
62099
62355
|
this.modelName = modelName;
|
|
62100
62356
|
this.name = config3.name;
|
|
62101
|
-
this.displayName =
|
|
62357
|
+
this.displayName = DISPLAY_NAMES2[config3.name] || "Local";
|
|
62102
62358
|
this.concurrency = options?.concurrency;
|
|
62103
62359
|
const envContextWindow = process.env.CLAUDISH_CONTEXT_WINDOW;
|
|
62104
62360
|
if (envContextWindow) {
|
|
@@ -62279,7 +62535,7 @@ class LocalTransport {
|
|
|
62279
62535
|
}
|
|
62280
62536
|
}
|
|
62281
62537
|
}
|
|
62282
|
-
var localProviderAgent,
|
|
62538
|
+
var localProviderAgent, DISPLAY_NAMES2;
|
|
62283
62539
|
var init_local = __esm(() => {
|
|
62284
62540
|
init_local_queue();
|
|
62285
62541
|
init_logger();
|
|
@@ -62290,7 +62546,7 @@ var init_local = __esm(() => {
|
|
|
62290
62546
|
keepAliveTimeout: 30000,
|
|
62291
62547
|
keepAliveMaxTimeout: 600000
|
|
62292
62548
|
});
|
|
62293
|
-
|
|
62549
|
+
DISPLAY_NAMES2 = {
|
|
62294
62550
|
ollama: "Ollama",
|
|
62295
62551
|
lmstudio: "LM Studio",
|
|
62296
62552
|
vllm: "vLLM",
|
|
@@ -63981,7 +64237,10 @@ data: ${JSON.stringify(data)}
|
|
|
63981
64237
|
}
|
|
63982
64238
|
if (part.text) {
|
|
63983
64239
|
if (thinkingStarted) {
|
|
63984
|
-
send("content_block_stop", {
|
|
64240
|
+
send("content_block_stop", {
|
|
64241
|
+
type: "content_block_stop",
|
|
64242
|
+
index: thinkingIdx
|
|
64243
|
+
});
|
|
63985
64244
|
thinkingStarted = false;
|
|
63986
64245
|
}
|
|
63987
64246
|
let cleanedText = part.text;
|
|
@@ -64011,7 +64270,10 @@ data: ${JSON.stringify(data)}
|
|
|
64011
64270
|
}
|
|
64012
64271
|
if (part.functionCall) {
|
|
64013
64272
|
if (thinkingStarted) {
|
|
64014
|
-
send("content_block_stop", {
|
|
64273
|
+
send("content_block_stop", {
|
|
64274
|
+
type: "content_block_stop",
|
|
64275
|
+
index: thinkingIdx
|
|
64276
|
+
});
|
|
64015
64277
|
thinkingStarted = false;
|
|
64016
64278
|
}
|
|
64017
64279
|
if (textStarted) {
|
|
@@ -64943,7 +65205,10 @@ var init_anthropic_passthrough_adapter = __esm(() => {
|
|
|
64943
65205
|
const filteredContent = message.content.map((block) => {
|
|
64944
65206
|
if (block.type === "tool_result" && Array.isArray(block.content)) {
|
|
64945
65207
|
const filtered = block.content.filter((c) => c.type !== "tool_reference");
|
|
64946
|
-
return {
|
|
65208
|
+
return {
|
|
65209
|
+
...block,
|
|
65210
|
+
content: filtered.length > 0 ? filtered : [{ type: "text", text: "" }]
|
|
65211
|
+
};
|
|
64947
65212
|
}
|
|
64948
65213
|
return block;
|
|
64949
65214
|
}).filter((block) => block.type !== "tool_reference");
|
|
@@ -65250,6 +65515,117 @@ var init_pricing_cache = __esm(() => {
|
|
|
65250
65515
|
};
|
|
65251
65516
|
});
|
|
65252
65517
|
|
|
65518
|
+
// src/handlers/fallback-handler.ts
|
|
65519
|
+
class FallbackHandler {
|
|
65520
|
+
candidates;
|
|
65521
|
+
constructor(candidates) {
|
|
65522
|
+
this.candidates = candidates;
|
|
65523
|
+
}
|
|
65524
|
+
async handle(c, payload) {
|
|
65525
|
+
const errors6 = [];
|
|
65526
|
+
for (let i = 0;i < this.candidates.length; i++) {
|
|
65527
|
+
const { name, handler } = this.candidates[i];
|
|
65528
|
+
const isLast = i === this.candidates.length - 1;
|
|
65529
|
+
try {
|
|
65530
|
+
const response = await handler.handle(c, payload);
|
|
65531
|
+
if (response.ok) {
|
|
65532
|
+
if (errors6.length > 0) {
|
|
65533
|
+
logStderr(`[Fallback] ${name} succeeded after ${errors6.length} failed attempt(s)`);
|
|
65534
|
+
}
|
|
65535
|
+
return response;
|
|
65536
|
+
}
|
|
65537
|
+
const errorBody = await response.clone().text();
|
|
65538
|
+
if (!isRetryableError(response.status, errorBody)) {
|
|
65539
|
+
if (errors6.length > 0) {
|
|
65540
|
+
errors6.push({ provider: name, status: response.status, message: errorBody });
|
|
65541
|
+
return this.formatCombinedError(c, errors6, payload.model);
|
|
65542
|
+
}
|
|
65543
|
+
return response;
|
|
65544
|
+
}
|
|
65545
|
+
errors6.push({ provider: name, status: response.status, message: errorBody });
|
|
65546
|
+
if (!isLast) {
|
|
65547
|
+
logStderr(`[Fallback] ${name} failed (HTTP ${response.status}), trying next provider...`);
|
|
65548
|
+
}
|
|
65549
|
+
} catch (err) {
|
|
65550
|
+
errors6.push({ provider: name, status: 0, message: err.message });
|
|
65551
|
+
if (!isLast) {
|
|
65552
|
+
logStderr(`[Fallback] ${name} error: ${err.message}, trying next provider...`);
|
|
65553
|
+
}
|
|
65554
|
+
}
|
|
65555
|
+
}
|
|
65556
|
+
return this.formatCombinedError(c, errors6, payload.model);
|
|
65557
|
+
}
|
|
65558
|
+
formatCombinedError(c, errors6, modelName) {
|
|
65559
|
+
const summary = errors6.map((e) => ` ${e.provider}: HTTP ${e.status || "ERR"} — ${truncate(parseErrorMessage(e.message), 150)}`).join(`
|
|
65560
|
+
`);
|
|
65561
|
+
logStderr(`[Fallback] All ${errors6.length} provider(s) failed for ${modelName || "model"}:
|
|
65562
|
+
${summary}`);
|
|
65563
|
+
return c.json({
|
|
65564
|
+
error: {
|
|
65565
|
+
type: "all_providers_failed",
|
|
65566
|
+
message: `All ${errors6.length} providers failed for model '${modelName || "unknown"}'`,
|
|
65567
|
+
attempts: errors6.map((e) => ({
|
|
65568
|
+
provider: e.provider,
|
|
65569
|
+
status: e.status,
|
|
65570
|
+
error: truncate(parseErrorMessage(e.message), 200)
|
|
65571
|
+
}))
|
|
65572
|
+
}
|
|
65573
|
+
}, 502);
|
|
65574
|
+
}
|
|
65575
|
+
async shutdown() {
|
|
65576
|
+
for (const { handler } of this.candidates) {
|
|
65577
|
+
if (typeof handler.shutdown === "function") {
|
|
65578
|
+
await handler.shutdown();
|
|
65579
|
+
}
|
|
65580
|
+
}
|
|
65581
|
+
}
|
|
65582
|
+
}
|
|
65583
|
+
function isRetryableError(status, errorBody) {
|
|
65584
|
+
if (status === 401 || status === 403)
|
|
65585
|
+
return true;
|
|
65586
|
+
if (status === 402)
|
|
65587
|
+
return true;
|
|
65588
|
+
if (status === 404)
|
|
65589
|
+
return true;
|
|
65590
|
+
if (status === 429)
|
|
65591
|
+
return true;
|
|
65592
|
+
const lower = errorBody.toLowerCase();
|
|
65593
|
+
if (status === 422) {
|
|
65594
|
+
if (lower.includes("not available") || lower.includes("model not found") || lower.includes("not supported")) {
|
|
65595
|
+
return true;
|
|
65596
|
+
}
|
|
65597
|
+
}
|
|
65598
|
+
if (status === 400) {
|
|
65599
|
+
if (lower.includes("model not found") || lower.includes("not registered") || lower.includes("does not exist") || lower.includes("unknown model") || lower.includes("unsupported model")) {
|
|
65600
|
+
return true;
|
|
65601
|
+
}
|
|
65602
|
+
}
|
|
65603
|
+
if (status === 500) {
|
|
65604
|
+
if (lower.includes("insufficient balance") || lower.includes("insufficient credit") || lower.includes("quota exceeded") || lower.includes("billing")) {
|
|
65605
|
+
return true;
|
|
65606
|
+
}
|
|
65607
|
+
}
|
|
65608
|
+
return false;
|
|
65609
|
+
}
|
|
65610
|
+
function parseErrorMessage(body) {
|
|
65611
|
+
try {
|
|
65612
|
+
const parsed = JSON.parse(body);
|
|
65613
|
+
if (typeof parsed.error === "string")
|
|
65614
|
+
return parsed.error;
|
|
65615
|
+
if (typeof parsed.error?.message === "string")
|
|
65616
|
+
return parsed.error.message;
|
|
65617
|
+
if (typeof parsed.message === "string")
|
|
65618
|
+
return parsed.message;
|
|
65619
|
+
} catch {}
|
|
65620
|
+
return body;
|
|
65621
|
+
}
|
|
65622
|
+
function truncate(s, max) {
|
|
65623
|
+
return s.length > max ? s.slice(0, max) + "..." : s;
|
|
65624
|
+
}
|
|
65625
|
+
var init_fallback_handler = __esm(() => {
|
|
65626
|
+
init_logger();
|
|
65627
|
+
});
|
|
65628
|
+
|
|
65253
65629
|
// src/proxy-server.ts
|
|
65254
65630
|
var exports_proxy_server = {};
|
|
65255
65631
|
__export(exports_proxy_server, {
|
|
@@ -65267,7 +65643,10 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
|
|
|
65267
65643
|
if (!openRouterHandlers.has(modelId)) {
|
|
65268
65644
|
const orProvider = new OpenRouterProvider(openrouterApiKey || "");
|
|
65269
65645
|
const orAdapter = new OpenRouterAdapter(modelId);
|
|
65270
|
-
openRouterHandlers.set(modelId, new ComposedHandler(orProvider, modelId, modelId, port, {
|
|
65646
|
+
openRouterHandlers.set(modelId, new ComposedHandler(orProvider, modelId, modelId, port, {
|
|
65647
|
+
adapter: orAdapter,
|
|
65648
|
+
isInteractive: options.isInteractive
|
|
65649
|
+
}));
|
|
65271
65650
|
}
|
|
65272
65651
|
return openRouterHandlers.get(modelId);
|
|
65273
65652
|
};
|
|
@@ -65280,7 +65659,9 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
|
|
|
65280
65659
|
const modelId = targetModel.replace(/^poe:/, "");
|
|
65281
65660
|
if (!poeHandlers.has(modelId)) {
|
|
65282
65661
|
const poeTransport = new PoeProvider(poeApiKey);
|
|
65283
|
-
poeHandlers.set(modelId, new ComposedHandler(poeTransport, modelId, modelId, port, {
|
|
65662
|
+
poeHandlers.set(modelId, new ComposedHandler(poeTransport, modelId, modelId, port, {
|
|
65663
|
+
isInteractive: options.isInteractive
|
|
65664
|
+
}));
|
|
65284
65665
|
}
|
|
65285
65666
|
return poeHandlers.get(modelId);
|
|
65286
65667
|
};
|
|
@@ -65495,6 +65876,7 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
|
|
|
65495
65876
|
log("[Proxy] LiteLLM model cache pre-warmed for auto-routing");
|
|
65496
65877
|
}).catch(() => {});
|
|
65497
65878
|
}
|
|
65879
|
+
const fallbackHandlerCache = new Map;
|
|
65498
65880
|
const getHandlerForRequest = (requestedModel) => {
|
|
65499
65881
|
if (monitorMode)
|
|
65500
65882
|
return nativeHandler;
|
|
@@ -65522,6 +65904,38 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
|
|
|
65522
65904
|
}
|
|
65523
65905
|
}
|
|
65524
65906
|
}
|
|
65907
|
+
{
|
|
65908
|
+
const parsedForFallback = parseModelSpec(target);
|
|
65909
|
+
if (!parsedForFallback.isExplicitProvider && parsedForFallback.provider !== "native-anthropic" && !isPoeModel(target)) {
|
|
65910
|
+
const cacheKey2 = `fallback:${target}`;
|
|
65911
|
+
if (fallbackHandlerCache.has(cacheKey2)) {
|
|
65912
|
+
return fallbackHandlerCache.get(cacheKey2);
|
|
65913
|
+
}
|
|
65914
|
+
const chain = getFallbackChain(parsedForFallback.model, parsedForFallback.provider);
|
|
65915
|
+
if (chain.length > 0) {
|
|
65916
|
+
const candidates = [];
|
|
65917
|
+
for (const route of chain) {
|
|
65918
|
+
let handler = null;
|
|
65919
|
+
if (route.provider === "openrouter") {
|
|
65920
|
+
handler = getOpenRouterHandler(route.modelSpec);
|
|
65921
|
+
} else {
|
|
65922
|
+
handler = getRemoteProviderHandler(route.modelSpec);
|
|
65923
|
+
}
|
|
65924
|
+
if (handler) {
|
|
65925
|
+
candidates.push({ name: route.displayName, handler });
|
|
65926
|
+
}
|
|
65927
|
+
}
|
|
65928
|
+
if (candidates.length > 0) {
|
|
65929
|
+
const resultHandler = candidates.length > 1 ? new FallbackHandler(candidates) : candidates[0].handler;
|
|
65930
|
+
fallbackHandlerCache.set(cacheKey2, resultHandler);
|
|
65931
|
+
if (!options.quiet && candidates.length > 1) {
|
|
65932
|
+
logStderr(`[Fallback] ${candidates.length} providers for ${parsedForFallback.model}: ${candidates.map((c) => c.name).join(" → ")}`);
|
|
65933
|
+
}
|
|
65934
|
+
return resultHandler;
|
|
65935
|
+
}
|
|
65936
|
+
}
|
|
65937
|
+
}
|
|
65938
|
+
}
|
|
65525
65939
|
if (isPoeModel(target)) {
|
|
65526
65940
|
const poeHandler = getPoeHandler(target);
|
|
65527
65941
|
if (poeHandler) {
|
|
@@ -65633,6 +66047,8 @@ var init_proxy_server = __esm(() => {
|
|
|
65633
66047
|
init_pricing_cache();
|
|
65634
66048
|
init_model_loader();
|
|
65635
66049
|
init_model_catalog_resolver();
|
|
66050
|
+
init_fallback_handler();
|
|
66051
|
+
init_auto_route();
|
|
65636
66052
|
});
|
|
65637
66053
|
|
|
65638
66054
|
// src/index.ts
|
package/package.json
CHANGED
package/recommended-models.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "1.2.0",
|
|
3
|
-
"lastUpdated": "2026-03-
|
|
3
|
+
"lastUpdated": "2026-03-14",
|
|
4
4
|
"source": "https://openrouter.ai/models?categories=programming&fmt=cards&order=top-weekly",
|
|
5
5
|
"models": [
|
|
6
6
|
{
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
"category": "programming",
|
|
13
13
|
"priority": 1,
|
|
14
14
|
"pricing": {
|
|
15
|
-
"input": "$0.
|
|
15
|
+
"input": "$0.25/1M",
|
|
16
16
|
"output": "$1.20/1M",
|
|
17
|
-
"average": "$0.
|
|
17
|
+
"average": "$0.72/1M"
|
|
18
18
|
},
|
|
19
19
|
"context": "196K",
|
|
20
20
|
"maxOutputTokens": 196608,
|
|
@@ -56,12 +56,12 @@
|
|
|
56
56
|
"category": "reasoning",
|
|
57
57
|
"priority": 3,
|
|
58
58
|
"pricing": {
|
|
59
|
-
"input": "$0.
|
|
60
|
-
"output": "$2.
|
|
61
|
-
"average": "$1.
|
|
59
|
+
"input": "$0.72/1M",
|
|
60
|
+
"output": "$2.30/1M",
|
|
61
|
+
"average": "$1.51/1M"
|
|
62
62
|
},
|
|
63
63
|
"context": "202K",
|
|
64
|
-
"maxOutputTokens":
|
|
64
|
+
"maxOutputTokens": 131072,
|
|
65
65
|
"modality": "text->text",
|
|
66
66
|
"supportsTools": true,
|
|
67
67
|
"supportsReasoning": true,
|