claudish 5.7.1 → 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 +477 -53
- package/package.json +3 -2
- 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
|
|
@@ -30498,7 +30609,15 @@ __export(exports_cli, {
|
|
|
30498
30609
|
getMissingKeyResolutions: () => getMissingKeyResolutions,
|
|
30499
30610
|
getMissingKeyError: () => getMissingKeyError
|
|
30500
30611
|
});
|
|
30501
|
-
import {
|
|
30612
|
+
import {
|
|
30613
|
+
readFileSync as readFileSync10,
|
|
30614
|
+
writeFileSync as writeFileSync5,
|
|
30615
|
+
existsSync as existsSync12,
|
|
30616
|
+
mkdirSync as mkdirSync5,
|
|
30617
|
+
copyFileSync,
|
|
30618
|
+
readdirSync,
|
|
30619
|
+
unlinkSync as unlinkSync3
|
|
30620
|
+
} from "node:fs";
|
|
30502
30621
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
30503
30622
|
import { dirname as dirname3, join as join12 } from "node:path";
|
|
30504
30623
|
import { homedir as homedir11 } from "node:os";
|
|
@@ -31836,7 +31955,7 @@ async function fetchGLMCodingModels() {
|
|
|
31836
31955
|
return [];
|
|
31837
31956
|
}
|
|
31838
31957
|
}
|
|
31839
|
-
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;
|
|
31840
31959
|
var init_cli = __esm(() => {
|
|
31841
31960
|
init_config();
|
|
31842
31961
|
init_model_loader();
|
|
@@ -34501,7 +34620,9 @@ async function fetchZenGoModels() {
|
|
|
34501
34620
|
return [];
|
|
34502
34621
|
const ZEN_GO_BASE = process.env.OPENCODE_BASE_URL ? process.env.OPENCODE_BASE_URL.replace("/zen", "/zen/go") : "https://opencode.ai/zen/go";
|
|
34503
34622
|
try {
|
|
34504
|
-
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
|
+
});
|
|
34505
34626
|
if (!mdevResp.ok)
|
|
34506
34627
|
return [];
|
|
34507
34628
|
const mdevData = await mdevResp.json();
|
|
@@ -34513,7 +34634,11 @@ async function fetchZenGoModels() {
|
|
|
34513
34634
|
const r = await fetch(`${ZEN_GO_BASE}/v1/chat/completions`, {
|
|
34514
34635
|
method: "POST",
|
|
34515
34636
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
|
|
34516
|
-
body: JSON.stringify({
|
|
34637
|
+
body: JSON.stringify({
|
|
34638
|
+
model: modelId,
|
|
34639
|
+
messages: [{ role: "user", content: "hi" }],
|
|
34640
|
+
max_tokens: 1
|
|
34641
|
+
}),
|
|
34517
34642
|
signal: AbortSignal.timeout(8000)
|
|
34518
34643
|
});
|
|
34519
34644
|
if (!r.ok)
|
|
@@ -34974,7 +35099,10 @@ async function getAllModelsForSearch(forceUpdate = false) {
|
|
|
34974
35099
|
const litellmBaseUrl = process.env.LITELLM_BASE_URL;
|
|
34975
35100
|
const litellmApiKey = process.env.LITELLM_API_KEY;
|
|
34976
35101
|
const fetchEntries = [
|
|
34977
|
-
{
|
|
35102
|
+
{
|
|
35103
|
+
name: "OpenRouter",
|
|
35104
|
+
promise: fetchAllModels(forceUpdate).then((models) => models.map(toModelInfo))
|
|
35105
|
+
},
|
|
34978
35106
|
{ name: "xAI", promise: fetchXAIModels() },
|
|
34979
35107
|
{ name: "Gemini", promise: fetchGeminiModels() },
|
|
34980
35108
|
{ name: "OpenAI", promise: fetchOpenAIModels() },
|
|
@@ -34985,7 +35113,10 @@ async function getAllModelsForSearch(forceUpdate = false) {
|
|
|
34985
35113
|
{ name: "Zen Go", promise: fetchZenGoModels() }
|
|
34986
35114
|
];
|
|
34987
35115
|
if (litellmBaseUrl && litellmApiKey) {
|
|
34988
|
-
fetchEntries.push({
|
|
35116
|
+
fetchEntries.push({
|
|
35117
|
+
name: "LiteLLM",
|
|
35118
|
+
promise: fetchLiteLLMModels(litellmBaseUrl, litellmApiKey, forceUpdate)
|
|
35119
|
+
});
|
|
34989
35120
|
}
|
|
34990
35121
|
const settled = await Promise.allSettled(fetchEntries.map((e) => e.promise));
|
|
34991
35122
|
const fetchResults = {};
|
|
@@ -35197,9 +35328,24 @@ function getKnownModels(provider) {
|
|
|
35197
35328
|
{ id: "google@gemini-2.0-flash", name: "Gemini 2.0 Flash", context: "1M" }
|
|
35198
35329
|
],
|
|
35199
35330
|
openai: [
|
|
35200
|
-
{
|
|
35201
|
-
|
|
35202
|
-
|
|
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
|
+
},
|
|
35203
35349
|
{ id: "oai@o3", name: "o3", context: "200K", description: "Reasoning model" },
|
|
35204
35350
|
{ id: "oai@o4-mini", name: "o4-mini", context: "200K", description: "Fast reasoning model" },
|
|
35205
35351
|
{ id: "oai@gpt-4.1", name: "GPT-4.1", context: "1M", description: "Large context model" }
|
|
@@ -35207,39 +35353,102 @@ function getKnownModels(provider) {
|
|
|
35207
35353
|
xai: [
|
|
35208
35354
|
{ id: "xai@grok-4", name: "Grok 4", context: "256K" },
|
|
35209
35355
|
{ id: "xai@grok-4-fast", name: "Grok 4 Fast", context: "2M" },
|
|
35210
|
-
{
|
|
35356
|
+
{
|
|
35357
|
+
id: "xai@grok-code-fast-1",
|
|
35358
|
+
name: "Grok Code Fast 1",
|
|
35359
|
+
context: "256K",
|
|
35360
|
+
description: "Optimized for coding"
|
|
35361
|
+
}
|
|
35211
35362
|
],
|
|
35212
35363
|
minimax: [
|
|
35213
|
-
{
|
|
35364
|
+
{
|
|
35365
|
+
id: "mm@minimax-m2.1",
|
|
35366
|
+
name: "MiniMax M2.1",
|
|
35367
|
+
context: "196K",
|
|
35368
|
+
description: "Lightweight coding model"
|
|
35369
|
+
}
|
|
35214
35370
|
],
|
|
35215
35371
|
"minimax-coding": [
|
|
35216
|
-
{
|
|
35217
|
-
|
|
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
|
+
}
|
|
35218
35384
|
],
|
|
35219
35385
|
kimi: [
|
|
35220
35386
|
{ id: "kimi@kimi-k2-thinking-turbo", name: "Kimi K2 Thinking Turbo", context: "128K" },
|
|
35221
35387
|
{ id: "kimi@moonshot-v1-128k", name: "Moonshot V1 128K", context: "128K" }
|
|
35222
35388
|
],
|
|
35223
35389
|
"kimi-coding": [
|
|
35224
|
-
{
|
|
35390
|
+
{
|
|
35391
|
+
id: "kc@kimi-for-coding",
|
|
35392
|
+
name: "Kimi for Coding",
|
|
35393
|
+
context: "128K",
|
|
35394
|
+
description: "Kimi Coding subscription model"
|
|
35395
|
+
}
|
|
35225
35396
|
],
|
|
35226
35397
|
glm: [
|
|
35227
|
-
{
|
|
35228
|
-
|
|
35229
|
-
|
|
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
|
+
},
|
|
35230
35416
|
{ id: "glm@glm-4.6", name: "GLM-4.6", context: "200K" },
|
|
35231
35417
|
{ id: "glm@glm-4.5-flash", name: "GLM-4.5 Flash", context: "128K" }
|
|
35232
35418
|
],
|
|
35233
|
-
zai: [
|
|
35234
|
-
{ id: "zai@glm-4.7", name: "GLM 4.7 (Z.AI)", context: "128K" }
|
|
35235
|
-
],
|
|
35419
|
+
zai: [{ id: "zai@glm-4.7", name: "GLM 4.7 (Z.AI)", context: "128K" }],
|
|
35236
35420
|
ollamacloud: [
|
|
35237
35421
|
{ id: "oc@glm-5", name: "GLM-5", context: "203K", description: "GLM-5 on OllamaCloud" },
|
|
35238
|
-
{
|
|
35239
|
-
|
|
35240
|
-
|
|
35241
|
-
|
|
35242
|
-
|
|
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
|
+
}
|
|
35243
35452
|
]
|
|
35244
35453
|
};
|
|
35245
35454
|
const providerDisplay = provider.charAt(0).toUpperCase() + provider.slice(1);
|
|
@@ -35474,23 +35683,76 @@ var init_model_selector = __esm(() => {
|
|
|
35474
35683
|
ll: "LiteLLM"
|
|
35475
35684
|
};
|
|
35476
35685
|
ALL_PROVIDER_CHOICES = [
|
|
35477
|
-
{
|
|
35686
|
+
{
|
|
35687
|
+
name: "Skip (keep Claude default)",
|
|
35688
|
+
value: "skip",
|
|
35689
|
+
description: "Use native Claude model for this tier"
|
|
35690
|
+
},
|
|
35478
35691
|
{ name: "OpenRouter", value: "openrouter", description: "580+ models via unified API" },
|
|
35479
35692
|
{ name: "OpenCode Zen", value: "zen", description: "Free models, no API key needed" },
|
|
35480
|
-
{
|
|
35481
|
-
|
|
35482
|
-
|
|
35483
|
-
|
|
35484
|
-
|
|
35485
|
-
|
|
35486
|
-
{
|
|
35487
|
-
|
|
35488
|
-
|
|
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
|
+
},
|
|
35489
35747
|
{ name: "Z.AI", value: "zai", description: "Z.AI API (ZAI_API_KEY)", envVar: "ZAI_API_KEY" },
|
|
35490
35748
|
{ name: "OllamaCloud", value: "ollamacloud", description: "Cloud models (OLLAMA_API_KEY)" },
|
|
35491
35749
|
{ name: "Ollama (local)", value: "ollama", description: "Local Ollama instance" },
|
|
35492
35750
|
{ name: "LM Studio (local)", value: "lmstudio", description: "Local LM Studio instance" },
|
|
35493
|
-
{
|
|
35751
|
+
{
|
|
35752
|
+
name: "Enter custom model",
|
|
35753
|
+
value: "custom",
|
|
35754
|
+
description: "Type a provider@model specification"
|
|
35755
|
+
}
|
|
35494
35756
|
];
|
|
35495
35757
|
PROVIDER_MODEL_PREFIX = {
|
|
35496
35758
|
google: "google@",
|
|
@@ -41347,10 +41609,12 @@ var init_openai_adapter = __esm(() => {
|
|
|
41347
41609
|
result.push({
|
|
41348
41610
|
type: "message",
|
|
41349
41611
|
role: msg.role,
|
|
41350
|
-
content: [
|
|
41351
|
-
|
|
41352
|
-
|
|
41353
|
-
|
|
41612
|
+
content: [
|
|
41613
|
+
{
|
|
41614
|
+
type: msg.role === "user" ? "input_text" : "output_text",
|
|
41615
|
+
text: msg.content
|
|
41616
|
+
}
|
|
41617
|
+
]
|
|
41354
41618
|
});
|
|
41355
41619
|
continue;
|
|
41356
41620
|
}
|
|
@@ -62090,7 +62354,7 @@ class LocalTransport {
|
|
|
62090
62354
|
this.config = config3;
|
|
62091
62355
|
this.modelName = modelName;
|
|
62092
62356
|
this.name = config3.name;
|
|
62093
|
-
this.displayName =
|
|
62357
|
+
this.displayName = DISPLAY_NAMES2[config3.name] || "Local";
|
|
62094
62358
|
this.concurrency = options?.concurrency;
|
|
62095
62359
|
const envContextWindow = process.env.CLAUDISH_CONTEXT_WINDOW;
|
|
62096
62360
|
if (envContextWindow) {
|
|
@@ -62271,7 +62535,7 @@ class LocalTransport {
|
|
|
62271
62535
|
}
|
|
62272
62536
|
}
|
|
62273
62537
|
}
|
|
62274
|
-
var localProviderAgent,
|
|
62538
|
+
var localProviderAgent, DISPLAY_NAMES2;
|
|
62275
62539
|
var init_local = __esm(() => {
|
|
62276
62540
|
init_local_queue();
|
|
62277
62541
|
init_logger();
|
|
@@ -62282,7 +62546,7 @@ var init_local = __esm(() => {
|
|
|
62282
62546
|
keepAliveTimeout: 30000,
|
|
62283
62547
|
keepAliveMaxTimeout: 600000
|
|
62284
62548
|
});
|
|
62285
|
-
|
|
62549
|
+
DISPLAY_NAMES2 = {
|
|
62286
62550
|
ollama: "Ollama",
|
|
62287
62551
|
lmstudio: "LM Studio",
|
|
62288
62552
|
vllm: "vLLM",
|
|
@@ -63973,7 +64237,10 @@ data: ${JSON.stringify(data)}
|
|
|
63973
64237
|
}
|
|
63974
64238
|
if (part.text) {
|
|
63975
64239
|
if (thinkingStarted) {
|
|
63976
|
-
send("content_block_stop", {
|
|
64240
|
+
send("content_block_stop", {
|
|
64241
|
+
type: "content_block_stop",
|
|
64242
|
+
index: thinkingIdx
|
|
64243
|
+
});
|
|
63977
64244
|
thinkingStarted = false;
|
|
63978
64245
|
}
|
|
63979
64246
|
let cleanedText = part.text;
|
|
@@ -64003,7 +64270,10 @@ data: ${JSON.stringify(data)}
|
|
|
64003
64270
|
}
|
|
64004
64271
|
if (part.functionCall) {
|
|
64005
64272
|
if (thinkingStarted) {
|
|
64006
|
-
send("content_block_stop", {
|
|
64273
|
+
send("content_block_stop", {
|
|
64274
|
+
type: "content_block_stop",
|
|
64275
|
+
index: thinkingIdx
|
|
64276
|
+
});
|
|
64007
64277
|
thinkingStarted = false;
|
|
64008
64278
|
}
|
|
64009
64279
|
if (textStarted) {
|
|
@@ -64935,7 +65205,10 @@ var init_anthropic_passthrough_adapter = __esm(() => {
|
|
|
64935
65205
|
const filteredContent = message.content.map((block) => {
|
|
64936
65206
|
if (block.type === "tool_result" && Array.isArray(block.content)) {
|
|
64937
65207
|
const filtered = block.content.filter((c) => c.type !== "tool_reference");
|
|
64938
|
-
return {
|
|
65208
|
+
return {
|
|
65209
|
+
...block,
|
|
65210
|
+
content: filtered.length > 0 ? filtered : [{ type: "text", text: "" }]
|
|
65211
|
+
};
|
|
64939
65212
|
}
|
|
64940
65213
|
return block;
|
|
64941
65214
|
}).filter((block) => block.type !== "tool_reference");
|
|
@@ -65242,6 +65515,117 @@ var init_pricing_cache = __esm(() => {
|
|
|
65242
65515
|
};
|
|
65243
65516
|
});
|
|
65244
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
|
+
|
|
65245
65629
|
// src/proxy-server.ts
|
|
65246
65630
|
var exports_proxy_server = {};
|
|
65247
65631
|
__export(exports_proxy_server, {
|
|
@@ -65259,7 +65643,10 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
|
|
|
65259
65643
|
if (!openRouterHandlers.has(modelId)) {
|
|
65260
65644
|
const orProvider = new OpenRouterProvider(openrouterApiKey || "");
|
|
65261
65645
|
const orAdapter = new OpenRouterAdapter(modelId);
|
|
65262
|
-
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
|
+
}));
|
|
65263
65650
|
}
|
|
65264
65651
|
return openRouterHandlers.get(modelId);
|
|
65265
65652
|
};
|
|
@@ -65272,7 +65659,9 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
|
|
|
65272
65659
|
const modelId = targetModel.replace(/^poe:/, "");
|
|
65273
65660
|
if (!poeHandlers.has(modelId)) {
|
|
65274
65661
|
const poeTransport = new PoeProvider(poeApiKey);
|
|
65275
|
-
poeHandlers.set(modelId, new ComposedHandler(poeTransport, modelId, modelId, port, {
|
|
65662
|
+
poeHandlers.set(modelId, new ComposedHandler(poeTransport, modelId, modelId, port, {
|
|
65663
|
+
isInteractive: options.isInteractive
|
|
65664
|
+
}));
|
|
65276
65665
|
}
|
|
65277
65666
|
return poeHandlers.get(modelId);
|
|
65278
65667
|
};
|
|
@@ -65487,6 +65876,7 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
|
|
|
65487
65876
|
log("[Proxy] LiteLLM model cache pre-warmed for auto-routing");
|
|
65488
65877
|
}).catch(() => {});
|
|
65489
65878
|
}
|
|
65879
|
+
const fallbackHandlerCache = new Map;
|
|
65490
65880
|
const getHandlerForRequest = (requestedModel) => {
|
|
65491
65881
|
if (monitorMode)
|
|
65492
65882
|
return nativeHandler;
|
|
@@ -65514,6 +65904,38 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
|
|
|
65514
65904
|
}
|
|
65515
65905
|
}
|
|
65516
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
|
+
}
|
|
65517
65939
|
if (isPoeModel(target)) {
|
|
65518
65940
|
const poeHandler = getPoeHandler(target);
|
|
65519
65941
|
if (poeHandler) {
|
|
@@ -65625,6 +66047,8 @@ var init_proxy_server = __esm(() => {
|
|
|
65625
66047
|
init_pricing_cache();
|
|
65626
66048
|
init_model_loader();
|
|
65627
66049
|
init_model_catalog_resolver();
|
|
66050
|
+
init_fallback_handler();
|
|
66051
|
+
init_auto_route();
|
|
65628
66052
|
});
|
|
65629
66053
|
|
|
65630
66054
|
// src/index.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claudish",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.9.0",
|
|
4
4
|
"description": "Run Claude Code with any model - OpenRouter, Ollama, LM Studio & local models",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"typecheck": "tsc --noEmit",
|
|
19
19
|
"lint": "biome check .",
|
|
20
20
|
"format": "biome format --write .",
|
|
21
|
-
"test": "bun test"
|
|
21
|
+
"test": "bun test",
|
|
22
|
+
"smoke": "bun run scripts/smoke-test.ts"
|
|
22
23
|
},
|
|
23
24
|
"dependencies": {
|
|
24
25
|
"@inquirer/prompts": "^8.0.1",
|
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,
|