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 CHANGED
@@ -29458,7 +29458,7 @@ var getRemoteProviders = () => [
29458
29458
  authScheme: "bearer",
29459
29459
  capabilities: {
29460
29460
  supportsTools: true,
29461
- supportsVision: true,
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
- var API_KEY_ENV_VARS, PROVIDER_HINT_MAP;
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.8.0", CACHE_MAX_AGE_DAYS2 = 2, MODELS_JSON_PATH, CLAUDISH_CACHE_DIR2, ALL_MODELS_JSON_PATH;
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", { signal: AbortSignal.timeout(5000) });
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({ model: modelId, messages: [{ role: "user", content: "hi" }], max_tokens: 1 }),
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
- { name: "OpenRouter", promise: fetchAllModels(forceUpdate).then((models) => models.map(toModelInfo)) },
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({ name: "LiteLLM", promise: fetchLiteLLMModels(litellmBaseUrl, litellmApiKey, forceUpdate) });
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
- { id: "oai@gpt-5.3-codex", name: "GPT-5.3 Codex", context: "400K", description: "Latest coding model" },
35209
- { id: "oai@gpt-5.2-codex", name: "GPT-5.2 Codex", context: "400K", description: "Coding model" },
35210
- { id: "oai@gpt-5.1-codex-mini", name: "GPT-5.1 Codex Mini", context: "400K", description: "Fast coding model" },
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
- { id: "xai@grok-code-fast-1", name: "Grok Code Fast 1", context: "256K", description: "Optimized for coding" }
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
- { id: "mm@minimax-m2.1", name: "MiniMax M2.1", context: "196K", description: "Lightweight coding model" }
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
- { id: "mmc@minimax-m2.5", name: "MiniMax M2.5", context: "196K", description: "MiniMax Coding subscription model" },
35225
- { id: "mmc@minimax-m2.1", name: "MiniMax M2.1", context: "196K", description: "MiniMax Coding subscription model" }
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
- { id: "kc@kimi-for-coding", name: "Kimi for Coding", context: "128K", description: "Kimi Coding subscription model" }
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
- { id: "glm@glm-5", name: "GLM-5", context: "200K", description: "Latest GLM model with reasoning" },
35236
- { id: "glm@glm-4.7", name: "GLM-4.7", context: "200K", description: "GLM 4.7 with reasoning" },
35237
- { id: "glm@glm-4.7-flash", name: "GLM-4.7 Flash", context: "200K", description: "Fast GLM 4.7" },
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
- { id: "oc@deepseek-v3.2", name: "DeepSeek V3.2", context: "164K", description: "DeepSeek V3.2 on OllamaCloud" },
35247
- { id: "oc@gemini-3-pro-preview", name: "Gemini 3 Pro Preview", context: "1M", description: "Gemini 3 Pro on OllamaCloud" },
35248
- { id: "oc@kimi-k2.5", name: "Kimi K2.5", context: "262K", description: "Kimi K2.5 on OllamaCloud" },
35249
- { id: "oc@qwen3-coder-next", name: "Qwen3 Coder Next", context: "262K", description: "Qwen3 Coder on OllamaCloud" },
35250
- { id: "oc@minimax-m2.1", name: "MiniMax M2.1", context: "205K", description: "MiniMax M2.1 on OllamaCloud" }
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
- { name: "Skip (keep Claude default)", value: "skip", description: "Use native Claude model for this tier" },
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
- { name: "Google Gemini", value: "google", description: "Direct API (GEMINI_API_KEY)", envVar: "GEMINI_API_KEY" },
35489
- { name: "OpenAI", value: "openai", description: "Direct API (OPENAI_API_KEY)", envVar: "OPENAI_API_KEY" },
35490
- { name: "xAI / Grok", value: "xai", description: "Direct API (XAI_API_KEY)", envVar: "XAI_API_KEY" },
35491
- { name: "MiniMax", value: "minimax", description: "Direct API (MINIMAX_API_KEY)", envVar: "MINIMAX_API_KEY" },
35492
- { name: "MiniMax Coding", value: "minimax-coding", description: "MiniMax Coding subscription (MINIMAX_CODING_API_KEY)", envVar: "MINIMAX_CODING_API_KEY" },
35493
- { name: "Kimi / Moonshot", value: "kimi", description: "Direct API (MOONSHOT_API_KEY)", envVar: "MOONSHOT_API_KEY" },
35494
- { name: "Kimi Coding", value: "kimi-coding", description: "Kimi Coding subscription (KIMI_CODING_API_KEY)", envVar: "KIMI_CODING_API_KEY" },
35495
- { name: "GLM / Zhipu", value: "glm", description: "Direct API (ZHIPU_API_KEY)", envVar: "ZHIPU_API_KEY" },
35496
- { name: "GLM Coding Plan", value: "glm-coding", description: "GLM Coding subscription (GLM_CODING_API_KEY)", envVar: "GLM_CODING_API_KEY" },
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
- { name: "Enter custom model", value: "custom", description: "Type a provider@model specification" }
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
- type: msg.role === "user" ? "input_text" : "output_text",
41360
- text: msg.content
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 = DISPLAY_NAMES[config3.name] || "Local";
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, DISPLAY_NAMES;
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
- DISPLAY_NAMES = {
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", { type: "content_block_stop", index: thinkingIdx });
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", { type: "content_block_stop", index: thinkingIdx });
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 { ...block, content: filtered.length > 0 ? filtered : [{ type: "text", text: "" }] };
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, { adapter: orAdapter, isInteractive: options.isInteractive }));
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, { isInteractive: options.isInteractive }));
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "5.8.0",
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",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "1.2.0",
3
- "lastUpdated": "2026-03-06",
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.29/1M",
15
+ "input": "$0.25/1M",
16
16
  "output": "$1.20/1M",
17
- "average": "$0.75/1M"
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.80/1M",
60
- "output": "$2.56/1M",
61
- "average": "$1.68/1M"
59
+ "input": "$0.72/1M",
60
+ "output": "$2.30/1M",
61
+ "average": "$1.51/1M"
62
62
  },
63
63
  "context": "202K",
64
- "maxOutputTokens": null,
64
+ "maxOutputTokens": 131072,
65
65
  "modality": "text->text",
66
66
  "supportsTools": true,
67
67
  "supportsReasoning": true,