@musistudio/claude-code-router 1.0.48 → 1.0.50

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/README.md CHANGED
@@ -1,9 +1,12 @@
1
- # Claude Code Router
1
+ ![](blog/images/claude-code-router-img.png)
2
2
 
3
- I am seeking funding support for this project to better sustain its development. If you have any ideas, feel free to reach out to me: [m@musiiot.top](mailto:m@musiiot.top)
3
+ [![](https://img.shields.io/badge/%F0%9F%87%A8%F0%9F%87%B3-%E4%B8%AD%E6%96%87%E7%89%88-ff0000?style=flat)](README_zh.md)
4
+ [![Discord](https://img.shields.io/badge/Discord-%235865F2.svg?&logo=discord&logoColor=white)](https://discord.gg/rdftVMaUcS)
5
+ [![](https://img.shields.io/github/license/musistudio/claude-code-router)](https://github.com/musistudio/claude-code-router/blob/main/LICENSE)
4
6
 
7
+ <hr>
5
8
 
6
- [中文版](README_zh.md)
9
+ I am seeking funding support for this project to better sustain its development. If you have any ideas, feel free to reach out to me: [m@musiiot.top](mailto:m@musiiot.top)
7
10
 
8
11
  > A powerful tool to route Claude Code requests to different models and customize any request.
9
12
 
package/README_zh.md CHANGED
@@ -1,4 +1,10 @@
1
- # Claude Code Router
1
+ ![](blog/images/claude-code-router-img.png)
2
+
3
+ [![](https://img.shields.io/badge/%F0%9F%87%AC%F0%9F%87%A7-English-000aff?style=flat)](README.md)
4
+ [![Discord](https://img.shields.io/badge/Discord-%235865F2.svg?&logo=discord&logoColor=white)](https://discord.gg/rdftVMaUcS)
5
+ [![](https://img.shields.io/github/license/musistudio/claude-code-router)](https://github.com/musistudio/claude-code-router/blob/main/LICENSE)
6
+
7
+ <hr>
2
8
 
3
9
  我正在为该项目寻求资金支持,以更好地维持其发展。如果您有任何想法,请随时与我联系: [m@musiiot.top](mailto:m@musiiot.top)
4
10
 
package/dist/cli.js CHANGED
@@ -47041,7 +47041,7 @@ var require_snapshot_utils = __commonJS({
47041
47041
  var require_snapshot_recorder = __commonJS({
47042
47042
  "node_modules/.pnpm/undici@7.15.0/node_modules/undici/lib/mock/snapshot-recorder.js"(exports2, module2) {
47043
47043
  "use strict";
47044
- var { writeFile: writeFile3, readFile: readFile2, mkdir: mkdir2 } = require("node:fs/promises");
47044
+ var { writeFile: writeFile3, readFile: readFile3, mkdir: mkdir2 } = require("node:fs/promises");
47045
47045
  var { dirname, resolve } = require("node:path");
47046
47046
  var { setTimeout: setTimeout3, clearTimeout: clearTimeout2 } = require("node:timers");
47047
47047
  var { InvalidArgumentError, UndiciError } = require_errors5();
@@ -47236,7 +47236,7 @@ var require_snapshot_recorder = __commonJS({
47236
47236
  throw new InvalidArgumentError("Snapshot path is required");
47237
47237
  }
47238
47238
  try {
47239
- const data = await readFile2(resolve(path6), "utf8");
47239
+ const data = await readFile3(resolve(path6), "utf8");
47240
47240
  const parsed = JSON.parse(data);
47241
47241
  if (Array.isArray(parsed)) {
47242
47242
  this.#snapshots.clear();
@@ -66519,7 +66519,7 @@ var require_package3 = __commonJS({
66519
66519
  "package.json"(exports2, module2) {
66520
66520
  module2.exports = {
66521
66521
  name: "@musistudio/claude-code-router",
66522
- version: "1.0.48",
66522
+ version: "1.0.50",
66523
66523
  description: "Use Claude Code without an Anthropics account and route it to another LLM provider",
66524
66524
  bin: {
66525
66525
  ccr: "./dist/cli.js"
@@ -66539,7 +66539,7 @@ var require_package3 = __commonJS({
66539
66539
  license: "MIT",
66540
66540
  dependencies: {
66541
66541
  "@fastify/static": "^8.2.0",
66542
- "@musistudio/llms": "^1.0.32",
66542
+ "@musistudio/llms": "^1.0.33",
66543
66543
  dotenv: "^16.4.7",
66544
66544
  "find-process": "^2.0.0",
66545
66545
  json5: "^2.2.3",
@@ -67987,12 +67987,12 @@ var require_dist6 = __commonJS({
67987
67987
 
67988
67988
  // src/index.ts
67989
67989
  var import_fs5 = require("fs");
67990
- var import_promises4 = require("fs/promises");
67990
+ var import_promises5 = require("fs/promises");
67991
67991
  var import_os2 = require("os");
67992
67992
  var import_path4 = require("path");
67993
67993
  init_utils();
67994
67994
 
67995
- // node_modules/.pnpm/@musistudio+llms@1.0.32_ws@8.18.3/node_modules/@musistudio/llms/dist/esm/server.mjs
67995
+ // node_modules/.pnpm/@musistudio+llms@1.0.33_ws@8.18.3/node_modules/@musistudio/llms/dist/esm/server.mjs
67996
67996
  var import_node_fs = require("node:fs");
67997
67997
  var import_node_path4 = require("node:path");
67998
67998
  var import_node_stream = __toESM(require("node:stream"), 1);
@@ -77019,7 +77019,7 @@ function Uf(r, e, t, n, o) {
77019
77019
  let f = { method: "POST", headers: a, body: JSON.stringify(e), signal: u };
77020
77020
  return t.httpsProxy && (f.dispatcher = new import_undici.ProxyAgent(new URL(t.httpsProxy).toString())), n?.debug({ reqId: o.req.id, request: f, headers: Object.fromEntries(a.entries()), requestUrl: typeof r == "string" ? r : r.toString(), useProxy: t.httpsProxy }, "final request"), fetch(typeof r == "string" ? r : r.toString(), f);
77021
77021
  }
77022
- var Mf = "1.0.31";
77022
+ var Mf = "1.0.33";
77023
77023
  async function a0(r, e, t, n) {
77024
77024
  let o = r.body, a = r.provider, u = t._server.providerService.getProvider(a);
77025
77025
  if (!u) throw nt(`Provider '${a}' not found`, 404, "provider_not_found");
@@ -77318,7 +77318,7 @@ var bo = class {
77318
77318
  t.push(C);
77319
77319
  });
77320
77320
  let f = a.content.filter((h) => h.type === "text" && h.text || h.type === "image" && h.source);
77321
- f.length && t.push({ role: "user", content: f.map((h) => h?.type === "image" ? { type: "image_url", image_url: { url: h.source?.type === "base64" ? `data:${h.source.media_type},${h.source.data}` : h.source.url }, media_type: h.source.media_type } : h) });
77321
+ f.length && t.push({ role: "user", content: f.map((h) => h?.type === "image" ? { type: "image_url", image_url: { url: h.source?.type === "base64" ? `data:${h.source.media_type};base64,${h.source.data}` : h.source.url }, media_type: h.source.media_type } : h) });
77322
77322
  } else if (a.role === "assistant") {
77323
77323
  let l = { role: "assistant", content: "" }, f = a.content.filter((d) => d.type === "text" && d.text);
77324
77324
  f.length && (l.content = f.map((d) => d.text).join(`
@@ -79281,6 +79281,7 @@ var LRUCache = class {
79281
79281
  var sessionUsageCache = new LRUCache(100);
79282
79282
 
79283
79283
  // src/utils/router.ts
79284
+ var import_promises3 = require("fs/promises");
79284
79285
  var enc = (0, import_tiktoken.get_encoding)("cl100k_base");
79285
79286
  var calculateTokenCount = (messages, system, tools) => {
79286
79287
  let tokenCount = 0;
@@ -79387,6 +79388,10 @@ var router = async (req, _res, context) => {
79387
79388
  }
79388
79389
  const lastMessageUsage = sessionUsageCache.get(req.sessionId);
79389
79390
  const { messages, system = [], tools } = req.body;
79391
+ if (config.REWRITE_SYSTEM_PROMPT && system.length > 1 && system[1]?.text?.includes("<env>")) {
79392
+ const prompt = await (0, import_promises3.readFile)(config.REWRITE_SYSTEM_PROMPT, "utf-8");
79393
+ system[1].text = `${prompt}<env>${system[1].text.split("<env>").pop()}`;
79394
+ }
79390
79395
  try {
79391
79396
  const tokenCount = calculateTokenCount(
79392
79397
  messages,
@@ -79436,33 +79441,6 @@ var apiKeyAuth = (config) => async (req, reply, done) => {
79436
79441
  }
79437
79442
  return done();
79438
79443
  }
79439
- const isConfigEndpoint = req.url.startsWith("/api/config");
79440
- const isRestartEndpoint = req.url === "/api/restart";
79441
- if (isConfigEndpoint || isRestartEndpoint) {
79442
- req.accessLevel = "restricted";
79443
- if (!apiKey) {
79444
- req.accessLevel = "restricted";
79445
- return done();
79446
- }
79447
- const authHeaderValue2 = req.headers.authorization || req.headers["x-api-key"];
79448
- const authKey2 = Array.isArray(authHeaderValue2) ? authHeaderValue2[0] : authHeaderValue2 || "";
79449
- if (!authKey2) {
79450
- req.accessLevel = "restricted";
79451
- return done();
79452
- }
79453
- let token2 = "";
79454
- if (authKey2.startsWith("Bearer")) {
79455
- token2 = authKey2.split(" ")[1];
79456
- } else {
79457
- token2 = authKey2;
79458
- }
79459
- if (token2 !== apiKey) {
79460
- req.accessLevel = "restricted";
79461
- return done();
79462
- }
79463
- req.accessLevel = "full";
79464
- return done();
79465
- }
79466
79444
  const authHeaderValue = req.headers.authorization || req.headers["x-api-key"];
79467
79445
  const authKey = Array.isArray(authHeaderValue) ? authHeaderValue[0] : authHeaderValue || "";
79468
79446
  if (!authKey) {
@@ -79575,7 +79553,7 @@ var import_child_process2 = require("child_process");
79575
79553
  var import_zlib = require("zlib");
79576
79554
  var import_stream = require("stream");
79577
79555
  var import_fs4 = require("fs");
79578
- var import_promises3 = require("fs/promises");
79556
+ var import_promises4 = require("fs/promises");
79579
79557
  var import_path3 = require("path");
79580
79558
  var import_util2 = require("util");
79581
79559
  var import_timers = require("timers");
@@ -79620,10 +79598,10 @@ var RotatingFileStream = class extends import_stream.Writable {
79620
79598
  this.filename = path6 + generator(null);
79621
79599
  this.fsCreateReadStream = import_fs4.createReadStream;
79622
79600
  this.fsCreateWriteStream = import_fs4.createWriteStream;
79623
- this.fsOpen = import_promises3.open;
79624
- this.fsReadFile = import_promises3.readFile;
79625
- this.fsStat = import_promises3.stat;
79626
- this.fsUnlink = import_promises3.unlink;
79601
+ this.fsOpen = import_promises4.open;
79602
+ this.fsReadFile = import_promises4.readFile;
79603
+ this.fsStat = import_promises4.stat;
79604
+ this.fsUnlink = import_promises4.unlink;
79627
79605
  this.generator = generator;
79628
79606
  this.maxTimeout = 2147483640;
79629
79607
  this.options = options;
@@ -79693,7 +79671,7 @@ var RotatingFileStream = class extends import_stream.Writable {
79693
79671
  return new Promise((resolve, reject) => process.nextTick(() => this.immutate(true).then(resolve).catch(reject)));
79694
79672
  let stats;
79695
79673
  try {
79696
- stats = await (0, import_promises3.stat)(this.filename);
79674
+ stats = await (0, import_promises4.stat)(this.filename);
79697
79675
  } catch (e) {
79698
79676
  if (e.code !== "ENOENT")
79699
79677
  throw e;
@@ -79716,17 +79694,17 @@ var RotatingFileStream = class extends import_stream.Writable {
79716
79694
  return this.rotate();
79717
79695
  }
79718
79696
  async makePath(name) {
79719
- return (0, import_promises3.mkdir)(name.split(import_path3.sep).slice(0, -1).join(import_path3.sep), { recursive: true });
79697
+ return (0, import_promises4.mkdir)(name.split(import_path3.sep).slice(0, -1).join(import_path3.sep), { recursive: true });
79720
79698
  }
79721
79699
  async reopen(size) {
79722
79700
  let file;
79723
79701
  try {
79724
- file = await (0, import_promises3.open)(this.filename, "a", this.options.mode);
79702
+ file = await (0, import_promises4.open)(this.filename, "a", this.options.mode);
79725
79703
  } catch (e) {
79726
79704
  if (e.code !== "ENOENT")
79727
79705
  throw e;
79728
79706
  await this.makePath(this.filename);
79729
- file = await (0, import_promises3.open)(this.filename, "a", this.options.mode);
79707
+ file = await (0, import_promises4.open)(this.filename, "a", this.options.mode);
79730
79708
  }
79731
79709
  this.file = file;
79732
79710
  this.size = size;
@@ -79772,7 +79750,7 @@ var RotatingFileStream = class extends import_stream.Writable {
79772
79750
  if (compress)
79773
79751
  await this.compress(filename);
79774
79752
  else
79775
- await (0, import_promises3.rename)(this.filename, filename);
79753
+ await (0, import_promises4.rename)(this.filename, filename);
79776
79754
  return this.rotated(filename);
79777
79755
  }
79778
79756
  async touch(filename) {
@@ -79783,7 +79761,7 @@ var RotatingFileStream = class extends import_stream.Writable {
79783
79761
  if (e.code !== "ENOENT")
79784
79762
  throw e;
79785
79763
  await this.makePath(filename);
79786
- file = await (0, import_promises3.open)(filename, "a");
79764
+ file = await (0, import_promises4.open)(filename, "a");
79787
79765
  }
79788
79766
  await file.close();
79789
79767
  return this.unlink(filename);
@@ -79802,12 +79780,12 @@ var RotatingFileStream = class extends import_stream.Writable {
79802
79780
  await this.compress(currName);
79803
79781
  else {
79804
79782
  try {
79805
- await (0, import_promises3.rename)(prevName, currName);
79783
+ await (0, import_promises4.rename)(prevName, currName);
79806
79784
  } catch (e) {
79807
79785
  if (e.code !== "ENOENT")
79808
79786
  throw e;
79809
79787
  await this.makePath(currName);
79810
- await (0, import_promises3.rename)(prevName, currName);
79788
+ await (0, import_promises4.rename)(prevName, currName);
79811
79789
  }
79812
79790
  }
79813
79791
  }
@@ -79953,7 +79931,7 @@ var RotatingFileStream = class extends import_stream.Writable {
79953
79931
  this.emit("removed", file.name, false);
79954
79932
  }
79955
79933
  }
79956
- await (0, import_promises3.writeFile)(history, res.map((e) => e.name).join("\n") + "\n", "utf-8");
79934
+ await (0, import_promises4.writeFile)(history, res.map((e) => e.name).join("\n") + "\n", "utf-8");
79957
79935
  this.emit("history");
79958
79936
  }
79959
79937
  async immutate(first) {
@@ -81692,7 +81670,7 @@ var ImageCache = class {
81692
81670
  constructor(maxSize = 100) {
81693
81671
  this.cache = new LRUCache2({
81694
81672
  max: maxSize,
81695
- ttl: 24 * 60 * 60 * 1e3
81673
+ ttl: 5 * 60 * 1e3
81696
81674
  });
81697
81675
  }
81698
81676
  storeImage(id2, source) {
@@ -81771,22 +81749,36 @@ var ImageAgent = class {
81771
81749
  "required": ["imageId", "task"]
81772
81750
  },
81773
81751
  handler: async (args, context) => {
81774
- console.log("args", JSON.stringify(args, null, 2));
81775
81752
  const imageMessages = [];
81776
81753
  let imageId;
81777
- if (args.imageId && Array.isArray(args.imageId)) {
81778
- args.imageId.forEach((imgId) => {
81779
- const image = imageCache.getImage(`${context.req.id}_Image#${imgId}`);
81754
+ if (args.imageId) {
81755
+ if (Array.isArray(args.imageId)) {
81756
+ args.imageId.forEach((imgId) => {
81757
+ const image = imageCache.getImage(`${context.req.id}_Image#${imgId}`);
81758
+ if (image) {
81759
+ imageMessages.push({
81760
+ type: "image",
81761
+ source: image
81762
+ });
81763
+ }
81764
+ });
81765
+ } else {
81766
+ const image = imageCache.getImage(`${context.req.id}_Image#${args.imageId}`);
81780
81767
  if (image) {
81781
81768
  imageMessages.push({
81782
81769
  type: "image",
81783
81770
  source: image
81784
81771
  });
81785
81772
  }
81786
- });
81773
+ }
81787
81774
  imageId = args.imageId;
81788
81775
  delete args.imageId;
81789
81776
  }
81777
+ const userMessage = context.req.body.messages[context.req.body.messages.length - 1];
81778
+ if (userMessage.role === "user" && Array.isArray(userMessage.content)) {
81779
+ const msgs = userMessage.content.filter((item) => item.type === "text" && !item.text.includes("This is an image, if you need to view or analyze it, you need to extract the imageId"));
81780
+ imageMessages.push(...msgs);
81781
+ }
81790
81782
  if (Object.keys(args).length > 0) {
81791
81783
  imageMessages.push({
81792
81784
  type: "text",
@@ -81819,7 +81811,6 @@ Always ensure that your response reflects a clear, accurate interpretation of th
81819
81811
  }).then((res) => res.json()).catch((err) => {
81820
81812
  return null;
81821
81813
  });
81822
- console.log(agentResponse.content);
81823
81814
  if (!agentResponse || !agentResponse.content) {
81824
81815
  return "analyzeImage Error";
81825
81816
  }
@@ -81924,7 +81915,7 @@ async function initializeClaudeConfig() {
81924
81915
  lastOnboardingVersion: "1.0.17",
81925
81916
  projects: {}
81926
81917
  };
81927
- await (0, import_promises4.writeFile)(configPath, JSON.stringify(configContent, null, 2));
81918
+ await (0, import_promises5.writeFile)(configPath, JSON.stringify(configContent, null, 2));
81928
81919
  }
81929
81920
  }
81930
81921
  async function run(options = {}) {
@@ -81991,10 +81982,10 @@ async function run(options = {}) {
81991
81982
  logger: loggerConfig
81992
81983
  });
81993
81984
  process.on("uncaughtException", (err) => {
81994
- server.log.error("Uncaught exception:", err);
81985
+ server.logger.error("Uncaught exception:", err);
81995
81986
  });
81996
81987
  process.on("unhandledRejection", (reason, promise) => {
81997
- server.log.error("Unhandled rejection at:", promise, "reason:", reason);
81988
+ server.logger.error("Unhandled rejection at:", promise, "reason:", reason);
81998
81989
  });
81999
81990
  server.addHook("preHandler", async (req, reply) => {
82000
81991
  return new Promise((resolve, reject) => {
@@ -82183,12 +82174,16 @@ async function run(options = {}) {
82183
82174
  return done(null, originalStream);
82184
82175
  }
82185
82176
  sessionUsageCache.put(req.sessionId, payload.usage);
82186
- }
82187
- if (typeof payload === "object") {
82188
- if (payload.error) {
82189
- return done(payload.error, null);
82177
+ if (typeof payload === "object") {
82178
+ if (payload.error) {
82179
+ return done(payload.error, null);
82180
+ } else {
82181
+ return done(payload, null);
82182
+ }
82190
82183
  }
82191
- return done(payload);
82184
+ }
82185
+ if (typeof payload === "object" && payload.error) {
82186
+ return done(payload.error, null);
82192
82187
  }
82193
82188
  done(null, payload);
82194
82189
  });
@@ -82319,7 +82314,7 @@ async function executeCodeCommand(args = []) {
82319
82314
  }
82320
82315
 
82321
82316
  // src/utils/statusline.ts
82322
- var import_promises5 = __toESM(require("node:fs/promises"));
82317
+ var import_promises6 = __toESM(require("node:fs/promises"));
82323
82318
  var import_child_process4 = require("child_process");
82324
82319
  var import_node_path5 = __toESM(require("node:path"));
82325
82320
  init_constants();
@@ -82398,7 +82393,7 @@ function replaceVariables(text, variables) {
82398
82393
  }
82399
82394
  async function executeScript(scriptPath, variables) {
82400
82395
  try {
82401
- await import_promises5.default.access(scriptPath);
82396
+ await import_promises6.default.access(scriptPath);
82402
82397
  const scriptModule = require(scriptPath);
82403
82398
  if (typeof scriptModule === "function") {
82404
82399
  const result = scriptModule(variables);
@@ -82555,11 +82550,11 @@ async function getProjectThemeConfig() {
82555
82550
  try {
82556
82551
  const configPath = CONFIG_FILE;
82557
82552
  try {
82558
- await import_promises5.default.access(configPath);
82553
+ await import_promises6.default.access(configPath);
82559
82554
  } catch {
82560
82555
  return { theme: null, style: "default" };
82561
82556
  }
82562
- const configContent = await import_promises5.default.readFile(configPath, "utf-8");
82557
+ const configContent = await import_promises6.default.readFile(configPath, "utf-8");
82563
82558
  const config = import_json53.default.parse(configContent);
82564
82559
  if (config.StatusLine) {
82565
82560
  const currentStyle = config.StatusLine.currentStyle || "default";
@@ -82620,7 +82615,7 @@ async function parseStatusLineData(input) {
82620
82615
  }).toString().trim();
82621
82616
  } catch (error) {
82622
82617
  }
82623
- const transcriptContent = await import_promises5.default.readFile(input.transcript_path, "utf-8");
82618
+ const transcriptContent = await import_promises6.default.readFile(input.transcript_path, "utf-8");
82624
82619
  const lines = transcriptContent.trim().split("\n");
82625
82620
  let model = "";
82626
82621
  let inputTokens = 0;
@@ -82645,11 +82640,11 @@ async function parseStatusLineData(input) {
82645
82640
  const projectConfigPath = import_node_path5.default.join(workDir, ".claude-code-router", "config.json");
82646
82641
  let configPath = projectConfigPath;
82647
82642
  try {
82648
- await import_promises5.default.access(projectConfigPath);
82643
+ await import_promises6.default.access(projectConfigPath);
82649
82644
  } catch {
82650
82645
  configPath = CONFIG_FILE;
82651
82646
  }
82652
- const configContent = await import_promises5.default.readFile(configPath, "utf-8");
82647
+ const configContent = await import_promises6.default.readFile(configPath, "utf-8");
82653
82648
  const config = import_json53.default.parse(configContent);
82654
82649
  if (config.Router && config.Router.default) {
82655
82650
  const [, defaultModel] = config.Router.default.split(",");