claudish 4.6.6 → 4.6.8

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
@@ -32800,6 +32800,8 @@ var init_model_parser = __esm(() => {
32800
32800
  lc: "ollamacloud",
32801
32801
  meta: "ollamacloud",
32802
32802
  poe: "poe",
32803
+ litellm: "litellm",
32804
+ ll: "litellm",
32803
32805
  ollama: "ollama",
32804
32806
  lms: "lmstudio",
32805
32807
  lmstudio: "lmstudio",
@@ -32820,7 +32822,8 @@ var init_model_parser = __esm(() => {
32820
32822
  "opencode-zen",
32821
32823
  "vertex",
32822
32824
  "gemini-codeassist",
32823
- "poe"
32825
+ "poe",
32826
+ "litellm"
32824
32827
  ]);
32825
32828
  LOCAL_PROVIDERS = new Set(["ollama", "lmstudio", "vllm", "mlx"]);
32826
32829
  NATIVE_MODEL_PATTERNS = [
@@ -33041,7 +33044,8 @@ function resolveRemoteProvider(modelId) {
33041
33044
  ollamacloud: "ollamacloud",
33042
33045
  "opencode-zen": "opencode-zen",
33043
33046
  vertex: "vertex",
33044
- "gemini-codeassist": "gemini-codeassist"
33047
+ "gemini-codeassist": "gemini-codeassist",
33048
+ litellm: "litellm"
33045
33049
  };
33046
33050
  const mappedProviderName = providerNameMap[parsed.provider];
33047
33051
  if (mappedProviderName) {
@@ -33192,7 +33196,7 @@ var getRemoteProviders = () => [
33192
33196
  prefixes: ["gc/"],
33193
33197
  capabilities: {
33194
33198
  supportsTools: true,
33195
- supportsVision: true,
33199
+ supportsVision: false,
33196
33200
  supportsStreaming: true,
33197
33201
  supportsJsonMode: true,
33198
33202
  supportsReasoning: true
@@ -33253,6 +33257,20 @@ var getRemoteProviders = () => [
33253
33257
  supportsJsonMode: false,
33254
33258
  supportsReasoning: true
33255
33259
  }
33260
+ },
33261
+ {
33262
+ name: "litellm",
33263
+ baseUrl: process.env.LITELLM_BASE_URL || "",
33264
+ apiPath: "/v1/chat/completions",
33265
+ apiKeyEnvVar: "LITELLM_API_KEY",
33266
+ prefixes: ["litellm/", "ll/"],
33267
+ capabilities: {
33268
+ supportsTools: true,
33269
+ supportsVision: true,
33270
+ supportsStreaming: true,
33271
+ supportsJsonMode: true,
33272
+ supportsReasoning: true
33273
+ }
33256
33274
  }
33257
33275
  ];
33258
33276
  var init_remote_provider_registry = __esm(() => {
@@ -33592,6 +33610,11 @@ var init_provider_resolver = __esm(() => {
33592
33610
  envVar: "ZAI_API_KEY",
33593
33611
  description: "Z.AI API Key",
33594
33612
  url: "https://z.ai/"
33613
+ },
33614
+ litellm: {
33615
+ envVar: "LITELLM_API_KEY",
33616
+ description: "LiteLLM API Key",
33617
+ url: "https://docs.litellm.ai/"
33595
33618
  }
33596
33619
  };
33597
33620
  PROVIDER_DISPLAY_NAMES = {
@@ -33607,7 +33630,8 @@ var init_provider_resolver = __esm(() => {
33607
33630
  "glm-coding": "GLM Coding",
33608
33631
  zai: "Z.AI",
33609
33632
  ollamacloud: "OllamaCloud",
33610
- "opencode-zen": "OpenCode Zen"
33633
+ "opencode-zen": "OpenCode Zen",
33634
+ litellm: "LiteLLM"
33611
33635
  };
33612
33636
  });
33613
33637
 
@@ -34890,7 +34914,7 @@ async function fetchGLMCodingModels2() {
34890
34914
  return [];
34891
34915
  }
34892
34916
  }
34893
- var __filename5, __dirname5, VERSION = "4.6.6", CACHE_MAX_AGE_DAYS3 = 2, MODELS_JSON_PATH, CLAUDISH_CACHE_DIR3, ALL_MODELS_JSON_PATH2;
34917
+ var __filename5, __dirname5, VERSION = "4.6.8", CACHE_MAX_AGE_DAYS3 = 2, MODELS_JSON_PATH, CLAUDISH_CACHE_DIR3, ALL_MODELS_JSON_PATH2;
34894
34918
  var init_cli = __esm(() => {
34895
34919
  init_config();
34896
34920
  init_model_loader();
@@ -62704,9 +62728,32 @@ class OpenAIHandler {
62704
62728
  this.sessionTotalCost += cost;
62705
62729
  this.writeTokenFile(Math.max(inputTokens, this.sessionInputTokens), this.sessionOutputTokens, pricing.isEstimate);
62706
62730
  }
62731
+ supportsVision() {
62732
+ if (this.provider.capabilities && !this.provider.capabilities.supportsVision) {
62733
+ return false;
62734
+ }
62735
+ const model = this.modelName.toLowerCase();
62736
+ if (model.startsWith("glm-") && !/\d+\.?\d*v/.test(model)) {
62737
+ return false;
62738
+ }
62739
+ return true;
62740
+ }
62707
62741
  convertMessages(claudeRequest) {
62708
62742
  const useSimpleFormat = this.provider.name === "ollamacloud";
62709
- return convertMessagesToOpenAI(claudeRequest, `openai/${this.modelName}`, filterIdentity, useSimpleFormat);
62743
+ const messages = convertMessagesToOpenAI(claudeRequest, `openai/${this.modelName}`, filterIdentity, useSimpleFormat);
62744
+ if (!this.supportsVision()) {
62745
+ for (const msg of messages) {
62746
+ if (Array.isArray(msg.content)) {
62747
+ msg.content = msg.content.filter((part) => part.type !== "image_url");
62748
+ if (msg.content.length === 1 && msg.content[0].type === "text") {
62749
+ msg.content = msg.content[0].text;
62750
+ } else if (msg.content.length === 0) {
62751
+ msg.content = "";
62752
+ }
62753
+ }
62754
+ }
62755
+ }
62756
+ return messages;
62710
62757
  }
62711
62758
  convertTools(claudeRequest) {
62712
62759
  return convertToolsToOpenAI(claudeRequest);
@@ -65394,10 +65441,212 @@ var init_ollamacloud_handler = __esm(() => {
65394
65441
  init_remote_provider_types();
65395
65442
  });
65396
65443
 
65397
- // src/services/pricing-cache.ts
65398
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync16, existsSync as existsSync12, mkdirSync as mkdirSync16, statSync } from "node:fs";
65444
+ // src/handlers/shared/remote-provider-handler.ts
65445
+ import { writeFileSync as writeFileSync16, mkdirSync as mkdirSync16 } from "node:fs";
65399
65446
  import { homedir as homedir19 } from "node:os";
65400
65447
  import { join as join20 } from "node:path";
65448
+
65449
+ class RemoteProviderHandler {
65450
+ targetModel;
65451
+ modelName;
65452
+ apiKey;
65453
+ adapterManager;
65454
+ middlewareManager;
65455
+ port;
65456
+ sessionTotalCost = 0;
65457
+ sessionInputTokens = 0;
65458
+ sessionOutputTokens = 0;
65459
+ contextWindow = 200000;
65460
+ CLAUDE_INTERNAL_CONTEXT_MAX = 200000;
65461
+ constructor(targetModel, modelName, apiKey, port) {
65462
+ this.targetModel = targetModel;
65463
+ this.modelName = modelName;
65464
+ this.apiKey = apiKey;
65465
+ this.port = port;
65466
+ this.adapterManager = new AdapterManager(targetModel);
65467
+ this.middlewareManager = new MiddlewareManager;
65468
+ this.middlewareManager.register(new GeminiThoughtSignatureMiddleware);
65469
+ this.middlewareManager.initialize().catch((err) => log(`[Handler:${targetModel}] Middleware init error: ${err}`));
65470
+ }
65471
+ getAdditionalHeaders() {
65472
+ return {};
65473
+ }
65474
+ getApiEndpoint() {
65475
+ const config3 = this.getProviderConfig();
65476
+ return `${config3.baseUrl}${config3.apiPath}`;
65477
+ }
65478
+ supportsReasoning() {
65479
+ return false;
65480
+ }
65481
+ writeTokenFile(input, output) {
65482
+ try {
65483
+ const total = input + output;
65484
+ const leftPct = this.contextWindow > 0 ? Math.max(0, Math.min(100, Math.round((this.contextWindow - total) / this.contextWindow * 100))) : 100;
65485
+ const pricing = this.getPricing();
65486
+ const data = {
65487
+ input_tokens: input,
65488
+ output_tokens: output,
65489
+ total_tokens: total,
65490
+ total_cost: this.sessionTotalCost,
65491
+ context_window: this.contextWindow,
65492
+ context_left_percent: leftPct,
65493
+ is_free: pricing.isFree || false,
65494
+ is_estimated: pricing.isEstimate || false,
65495
+ provider_name: this.getProviderName(),
65496
+ model_name: this.modelName,
65497
+ updated_at: Date.now()
65498
+ };
65499
+ const claudishDir = join20(homedir19(), ".claudish");
65500
+ mkdirSync16(claudishDir, { recursive: true });
65501
+ writeFileSync16(join20(claudishDir, `tokens-${this.port}.json`), JSON.stringify(data), "utf-8");
65502
+ } catch (e) {
65503
+ log(`[Handler] Error writing token file: ${e}`);
65504
+ }
65505
+ }
65506
+ updateTokenTracking(inputTokens, outputTokens) {
65507
+ this.sessionInputTokens = inputTokens;
65508
+ this.sessionOutputTokens += outputTokens;
65509
+ const pricing = this.getPricing();
65510
+ const cost = inputTokens / 1e6 * pricing.inputCostPer1M + outputTokens / 1e6 * pricing.outputCostPer1M;
65511
+ this.sessionTotalCost += cost;
65512
+ this.writeTokenFile(inputTokens, this.sessionOutputTokens);
65513
+ }
65514
+ convertMessages(claudeRequest) {
65515
+ return convertMessagesToOpenAI(claudeRequest, this.targetModel, filterIdentity);
65516
+ }
65517
+ convertTools(claudeRequest) {
65518
+ return convertToolsToOpenAI(claudeRequest);
65519
+ }
65520
+ handleStreamingResponse(c, response, adapter, claudeRequest, toolNameMap) {
65521
+ return createStreamingResponseHandler(c, response, adapter, this.targetModel, this.middlewareManager, (input, output) => this.updateTokenTracking(input, output), claudeRequest.tools, toolNameMap);
65522
+ }
65523
+ async handle(c, payload) {
65524
+ const config3 = this.getProviderConfig();
65525
+ const { claudeRequest, droppedParams } = transformOpenAIToClaude(payload);
65526
+ const messages = this.convertMessages(claudeRequest);
65527
+ const tools = this.convertTools(claudeRequest);
65528
+ const systemPromptLength = typeof claudeRequest.system === "string" ? claudeRequest.system.length : 0;
65529
+ logStructured(`${config3.name} Request`, {
65530
+ targetModel: this.targetModel,
65531
+ originalModel: payload.model,
65532
+ messageCount: messages.length,
65533
+ toolCount: tools.length,
65534
+ systemPromptLength,
65535
+ maxTokens: claudeRequest.max_tokens
65536
+ });
65537
+ if (getLogLevel() === "debug") {
65538
+ const lastUserMsg = messages.filter((m) => m.role === "user").pop();
65539
+ if (lastUserMsg) {
65540
+ const content = typeof lastUserMsg.content === "string" ? lastUserMsg.content : JSON.stringify(lastUserMsg.content);
65541
+ log(`[${config3.name}] Last user message: ${truncateContent(content, 500)}`);
65542
+ }
65543
+ if (tools.length > 0) {
65544
+ const toolNames = tools.map((t) => t.function?.name || t.name).join(", ");
65545
+ log(`[${config3.name}] Tools: ${toolNames}`);
65546
+ }
65547
+ }
65548
+ const requestPayload = this.buildRequestPayload(claudeRequest, messages, tools);
65549
+ const adapter = this.adapterManager.getAdapter();
65550
+ if (typeof adapter.reset === "function")
65551
+ adapter.reset();
65552
+ adapter.prepareRequest(requestPayload, claudeRequest);
65553
+ const toolNameMap = adapter.getToolNameMap();
65554
+ await this.middlewareManager.beforeRequest({
65555
+ modelId: this.targetModel,
65556
+ messages,
65557
+ tools,
65558
+ stream: true
65559
+ });
65560
+ const endpoint = this.getApiEndpoint();
65561
+ const headers = {
65562
+ "Content-Type": "application/json",
65563
+ Authorization: `Bearer ${this.apiKey}`,
65564
+ ...this.getAdditionalHeaders()
65565
+ };
65566
+ log(`[${config3.name}] Calling API: ${endpoint}`);
65567
+ const response = await fetch(endpoint, {
65568
+ method: "POST",
65569
+ headers,
65570
+ body: JSON.stringify(requestPayload)
65571
+ });
65572
+ log(`[${config3.name}] Response status: ${response.status}`);
65573
+ if (!response.ok) {
65574
+ const errorText = await response.text();
65575
+ log(`[${config3.name}] Error: ${errorText}`);
65576
+ return c.json({ error: errorText }, response.status);
65577
+ }
65578
+ if (droppedParams.length > 0) {
65579
+ c.header("X-Dropped-Params", droppedParams.join(", "));
65580
+ }
65581
+ return this.handleStreamingResponse(c, response, adapter, claudeRequest, toolNameMap);
65582
+ }
65583
+ async shutdown() {}
65584
+ }
65585
+ var init_remote_provider_handler = __esm(() => {
65586
+ init_adapter_manager();
65587
+ init_middleware();
65588
+ init_transform();
65589
+ init_logger();
65590
+ init_openai_compat();
65591
+ });
65592
+
65593
+ // src/handlers/litellm-handler.ts
65594
+ var LiteLLMHandler;
65595
+ var init_litellm_handler = __esm(() => {
65596
+ init_remote_provider_handler();
65597
+ LiteLLMHandler = class LiteLLMHandler extends RemoteProviderHandler {
65598
+ baseUrl;
65599
+ constructor(targetModel, modelName, apiKey, port, baseUrl) {
65600
+ super(targetModel, modelName, apiKey, port);
65601
+ this.baseUrl = baseUrl;
65602
+ }
65603
+ getProviderConfig() {
65604
+ return {
65605
+ name: "litellm",
65606
+ baseUrl: this.baseUrl,
65607
+ apiPath: "/v1/chat/completions",
65608
+ apiKeyEnvVar: "LITELLM_API_KEY"
65609
+ };
65610
+ }
65611
+ getPricing() {
65612
+ return {
65613
+ inputCostPer1M: 1,
65614
+ outputCostPer1M: 4,
65615
+ isEstimate: true
65616
+ };
65617
+ }
65618
+ getProviderName() {
65619
+ return "LiteLLM";
65620
+ }
65621
+ buildRequestPayload(claudeRequest, messages, tools) {
65622
+ const payload = {
65623
+ model: this.modelName,
65624
+ messages,
65625
+ temperature: claudeRequest.temperature ?? 1,
65626
+ stream: true,
65627
+ stream_options: { include_usage: true },
65628
+ max_tokens: claudeRequest.max_tokens
65629
+ };
65630
+ if (tools.length > 0) {
65631
+ payload.tools = tools;
65632
+ }
65633
+ if (claudeRequest.tool_choice) {
65634
+ const { type, name } = claudeRequest.tool_choice;
65635
+ if (type === "tool" && name) {
65636
+ payload.tool_choice = { type: "function", function: { name } };
65637
+ } else if (type === "auto" || type === "none") {
65638
+ payload.tool_choice = type;
65639
+ }
65640
+ }
65641
+ return payload;
65642
+ }
65643
+ };
65644
+ });
65645
+
65646
+ // src/services/pricing-cache.ts
65647
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync17, existsSync as existsSync12, mkdirSync as mkdirSync17, statSync } from "node:fs";
65648
+ import { homedir as homedir20 } from "node:os";
65649
+ import { join as join21 } from "node:path";
65401
65650
  function getDynamicPricingSync(provider, modelName) {
65402
65651
  if (provider === "openrouter") {
65403
65652
  const direct = pricingMap.get(modelName);
@@ -65479,12 +65728,12 @@ function loadDiskCache() {
65479
65728
  }
65480
65729
  function saveDiskCache() {
65481
65730
  try {
65482
- mkdirSync16(CACHE_DIR, { recursive: true });
65731
+ mkdirSync17(CACHE_DIR, { recursive: true });
65483
65732
  const data = {};
65484
65733
  for (const [key, pricing] of pricingMap) {
65485
65734
  data[key] = pricing;
65486
65735
  }
65487
- writeFileSync16(CACHE_FILE, JSON.stringify(data), "utf-8");
65736
+ writeFileSync17(CACHE_FILE, JSON.stringify(data), "utf-8");
65488
65737
  } catch (error46) {
65489
65738
  log(`[PricingCache] Error saving disk cache: ${error46}`);
65490
65739
  }
@@ -65514,8 +65763,8 @@ var init_pricing_cache = __esm(() => {
65514
65763
  init_model_loader();
65515
65764
  init_remote_provider_types();
65516
65765
  pricingMap = new Map;
65517
- CACHE_DIR = join20(homedir19(), ".claudish");
65518
- CACHE_FILE = join20(CACHE_DIR, "pricing-cache.json");
65766
+ CACHE_DIR = join21(homedir20(), ".claudish");
65767
+ CACHE_FILE = join21(CACHE_DIR, "pricing-cache.json");
65519
65768
  CACHE_TTL_MS = 24 * 60 * 60 * 1000;
65520
65769
  PROVIDER_TO_OR_PREFIX = {
65521
65770
  openai: ["openai/"],
@@ -65637,6 +65886,15 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
65637
65886
  } else if (resolved.provider.name === "ollamacloud") {
65638
65887
  handler = new OllamaCloudHandler(resolved.provider, resolved.modelName, apiKey, port);
65639
65888
  log(`[Proxy] Created OllamaCloud handler: ${resolved.modelName}`);
65889
+ } else if (resolved.provider.name === "litellm") {
65890
+ if (!resolved.provider.baseUrl) {
65891
+ console.error("Error: LITELLM_BASE_URL or --litellm-url is required for LiteLLM provider.");
65892
+ console.error("Set it with: export LITELLM_BASE_URL='https://your-litellm-instance.com'");
65893
+ console.error("Or use: claudish --litellm-url https://your-instance.com --model litellm@model 'task'");
65894
+ return null;
65895
+ }
65896
+ handler = new LiteLLMHandler(targetModel, resolved.modelName, apiKey, port, resolved.provider.baseUrl);
65897
+ log(`[Proxy] Created LiteLLM handler: ${resolved.modelName} (${resolved.provider.baseUrl})`);
65640
65898
  } else if (resolved.provider.name === "vertex") {
65641
65899
  const hasApiKey = !!process.env.VERTEX_API_KEY;
65642
65900
  const vertexConfig = getVertexConfig();
@@ -65771,6 +66029,7 @@ var init_proxy_server = __esm(() => {
65771
66029
  init_vertex_oauth_handler();
65772
66030
  init_poe_handler();
65773
66031
  init_ollamacloud_handler();
66032
+ init_litellm_handler();
65774
66033
  init_provider_registry();
65775
66034
  init_model_parser();
65776
66035
  init_remote_provider_registry();
@@ -65788,9 +66047,9 @@ __export(exports_update_checker, {
65788
66047
  checkForUpdates: () => checkForUpdates
65789
66048
  });
65790
66049
  import { execSync } from "node:child_process";
65791
- import { existsSync as existsSync13, mkdirSync as mkdirSync17, readFileSync as readFileSync10, unlinkSync as unlinkSync4, writeFileSync as writeFileSync17 } from "node:fs";
65792
- import { homedir as homedir20, platform as platform2, tmpdir as tmpdir2 } from "node:os";
65793
- import { join as join21 } from "node:path";
66050
+ import { existsSync as existsSync13, mkdirSync as mkdirSync18, readFileSync as readFileSync10, unlinkSync as unlinkSync4, writeFileSync as writeFileSync18 } from "node:fs";
66051
+ import { homedir as homedir21, platform as platform2, tmpdir as tmpdir2 } from "node:os";
66052
+ import { join as join22 } from "node:path";
65794
66053
  import { createInterface as createInterface2 } from "node:readline";
65795
66054
  function getUpdateCommand() {
65796
66055
  const scriptPath = process.argv[1] || "";
@@ -65802,18 +66061,18 @@ function getUpdateCommand() {
65802
66061
  function getCacheFilePath() {
65803
66062
  let cacheDir;
65804
66063
  if (isWindows2) {
65805
- const localAppData = process.env.LOCALAPPDATA || join21(homedir20(), "AppData", "Local");
65806
- cacheDir = join21(localAppData, "claudish");
66064
+ const localAppData = process.env.LOCALAPPDATA || join22(homedir21(), "AppData", "Local");
66065
+ cacheDir = join22(localAppData, "claudish");
65807
66066
  } else {
65808
- cacheDir = join21(homedir20(), ".cache", "claudish");
66067
+ cacheDir = join22(homedir21(), ".cache", "claudish");
65809
66068
  }
65810
66069
  try {
65811
66070
  if (!existsSync13(cacheDir)) {
65812
- mkdirSync17(cacheDir, { recursive: true });
66071
+ mkdirSync18(cacheDir, { recursive: true });
65813
66072
  }
65814
- return join21(cacheDir, "update-check.json");
66073
+ return join22(cacheDir, "update-check.json");
65815
66074
  } catch {
65816
- return join21(tmpdir2(), "claudish-update-check.json");
66075
+ return join22(tmpdir2(), "claudish-update-check.json");
65817
66076
  }
65818
66077
  }
65819
66078
  function readCache() {
@@ -65835,7 +66094,7 @@ function writeCache(latestVersion) {
65835
66094
  lastCheck: Date.now(),
65836
66095
  latestVersion
65837
66096
  };
65838
- writeFileSync17(cachePath, JSON.stringify(data), "utf-8");
66097
+ writeFileSync18(cachePath, JSON.stringify(data), "utf-8");
65839
66098
  } catch {}
65840
66099
  }
65841
66100
  function isCacheValid(cache) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "4.6.6",
3
+ "version": "4.6.8",
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-02-13",
3
+ "lastUpdated": "2026-02-14",
4
4
  "source": "https://openrouter.ai/models?categories=programming&fmt=cards&order=top-weekly",
5
5
  "models": [
6
6
  {