@musistudio/claude-code-router 1.0.45 → 1.0.46

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.
Files changed (2) hide show
  1. package/dist/cli.js +123 -86
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -66532,7 +66532,7 @@ var require_package3 = __commonJS({
66532
66532
  "package.json"(exports2, module2) {
66533
66533
  module2.exports = {
66534
66534
  name: "@musistudio/claude-code-router",
66535
- version: "1.0.45",
66535
+ version: "1.0.46",
66536
66536
  description: "Use Claude Code without an Anthropics account and route it to another LLM provider",
66537
66537
  bin: {
66538
66538
  ccr: "./dist/cli.js"
@@ -81033,10 +81033,11 @@ async function run(options = {}) {
81033
81033
  await router(req, reply, config);
81034
81034
  }
81035
81035
  });
81036
- server.addHook("onSend", async (req, reply, payload) => {
81036
+ server.addHook("onSend", (req, reply, payload, done) => {
81037
81037
  if (req.sessionId && req.url.startsWith("/v1/messages")) {
81038
81038
  if (payload instanceof ReadableStream) {
81039
81039
  if (req.agents) {
81040
+ const abortController = new AbortController();
81040
81041
  const eventStream = payload.pipeThrough(new SSEParserTransform());
81041
81042
  let currentAgent;
81042
81043
  let currentToolIndex = -1;
@@ -81045,111 +81046,147 @@ async function run(options = {}) {
81045
81046
  let currentToolId = "";
81046
81047
  const toolMessages = [];
81047
81048
  const assistantMessages = [];
81048
- return rewriteStream(eventStream, async (data, controller) => {
81049
- if (data.event === "content_block_start" && data?.data?.content_block?.name) {
81050
- const agent = req.agents.find((name) => agents_default.getAgent(name)?.tools.get(data.data.content_block.name));
81051
- if (agent) {
81052
- currentAgent = agents_default.getAgent(agent);
81053
- currentToolIndex = data.data.index;
81054
- currentToolName = data.data.content_block.name;
81055
- currentToolId = data.data.content_block.id;
81049
+ return done(null, rewriteStream(eventStream, async (data, controller) => {
81050
+ try {
81051
+ if (data.event === "content_block_start" && data?.data?.content_block?.name) {
81052
+ const agent = req.agents.find((name) => agents_default.getAgent(name)?.tools.get(data.data.content_block.name));
81053
+ if (agent) {
81054
+ currentAgent = agents_default.getAgent(agent);
81055
+ currentToolIndex = data.data.index;
81056
+ currentToolName = data.data.content_block.name;
81057
+ currentToolId = data.data.content_block.id;
81058
+ return void 0;
81059
+ }
81060
+ }
81061
+ if (currentToolIndex > -1 && data.data.index === currentToolIndex && data.data?.delta?.type === "input_json_delta") {
81062
+ currentToolArgs += data.data?.delta?.partial_json;
81056
81063
  return void 0;
81057
81064
  }
81058
- }
81059
- if (currentToolIndex > -1 && data.data.index === currentToolIndex && data.data?.delta?.type === "input_json_delta") {
81060
- currentToolArgs += data.data?.delta?.partial_json;
81061
- return void 0;
81062
- }
81063
- if (currentToolIndex > -1 && data.data.index === currentToolIndex && data.data.type === "content_block_stop") {
81064
- try {
81065
- const args = import_json52.default.parse(currentToolArgs);
81066
- assistantMessages.push({
81067
- type: "tool_use",
81068
- id: currentToolId,
81069
- name: currentToolName,
81070
- input: args
81065
+ if (currentToolIndex > -1 && data.data.index === currentToolIndex && data.data.type === "content_block_stop") {
81066
+ try {
81067
+ const args = import_json52.default.parse(currentToolArgs);
81068
+ assistantMessages.push({
81069
+ type: "tool_use",
81070
+ id: currentToolId,
81071
+ name: currentToolName,
81072
+ input: args
81073
+ });
81074
+ const toolResult = await currentAgent?.tools.get(currentToolName)?.handler(args, {
81075
+ req,
81076
+ config
81077
+ });
81078
+ console.log("result", toolResult);
81079
+ toolMessages.push({
81080
+ "tool_use_id": currentToolId,
81081
+ "type": "tool_result",
81082
+ "content": toolResult
81083
+ });
81084
+ currentAgent = void 0;
81085
+ currentToolIndex = -1;
81086
+ currentToolName = "";
81087
+ currentToolArgs = "";
81088
+ currentToolId = "";
81089
+ } catch (e) {
81090
+ console.log(e);
81091
+ }
81092
+ return void 0;
81093
+ }
81094
+ if (data.event === "message_delta" && toolMessages.length) {
81095
+ req.body.messages.push({
81096
+ role: "assistant",
81097
+ content: assistantMessages
81071
81098
  });
81072
- const toolResult = await currentAgent?.tools.get(currentToolName)?.handler(args, {
81073
- req,
81074
- config
81099
+ req.body.messages.push({
81100
+ role: "user",
81101
+ content: toolMessages
81075
81102
  });
81076
- console.log("result", toolResult);
81077
- toolMessages.push({
81078
- "tool_use_id": currentToolId,
81079
- "type": "tool_result",
81080
- "content": toolResult
81103
+ const response = await fetch(`http://127.0.0.1:${config.PORT}/v1/messages`, {
81104
+ method: "POST",
81105
+ headers: {
81106
+ "x-api-key": config.APIKEY,
81107
+ "content-type": "application/json"
81108
+ },
81109
+ body: JSON.stringify(req.body)
81081
81110
  });
81082
- currentAgent = void 0;
81083
- currentToolIndex = -1;
81084
- currentToolName = "";
81085
- currentToolArgs = "";
81086
- currentToolId = "";
81087
- } catch (e) {
81088
- console.log(e);
81089
- }
81090
- return void 0;
81091
- }
81092
- if (data.event === "message_delta" && toolMessages.length) {
81093
- req.body.messages.push({
81094
- role: "assistant",
81095
- content: assistantMessages
81096
- });
81097
- req.body.messages.push({
81098
- role: "user",
81099
- content: toolMessages
81100
- });
81101
- const response = await fetch(`http://127.0.0.1:${config.PORT}/v1/messages`, {
81102
- method: "POST",
81103
- headers: {
81104
- "x-api-key": config.APIKEY,
81105
- "content-type": "application/json"
81106
- },
81107
- body: JSON.stringify(req.body)
81108
- });
81109
- if (!response.ok) {
81110
- return void 0;
81111
- }
81112
- const stream = response.body.pipeThrough(new SSEParserTransform());
81113
- const reader = stream.getReader();
81114
- while (true) {
81115
- const { value, done } = await reader.read();
81116
- if (done) {
81117
- break;
81111
+ if (!response.ok) {
81112
+ return void 0;
81118
81113
  }
81119
- if (["message_start", "message_stop"].includes(value.event)) {
81120
- continue;
81114
+ const stream = response.body.pipeThrough(new SSEParserTransform());
81115
+ const reader = stream.getReader();
81116
+ while (true) {
81117
+ try {
81118
+ const { value, done: done2 } = await reader.read();
81119
+ if (done2) {
81120
+ break;
81121
+ }
81122
+ if (["message_start", "message_stop"].includes(value.event)) {
81123
+ continue;
81124
+ }
81125
+ if (!controller.desiredSize) {
81126
+ console.log("Stream backpressure detected");
81127
+ break;
81128
+ }
81129
+ controller.enqueue(value);
81130
+ } catch (readError) {
81131
+ if (readError.name === "AbortError" || readError.code === "ERR_STREAM_PREMATURE_CLOSE") {
81132
+ console.log("Stream reading aborted due to client disconnect");
81133
+ abortController.abort();
81134
+ break;
81135
+ }
81136
+ throw readError;
81137
+ }
81121
81138
  }
81122
- controller.enqueue(value);
81139
+ return void 0;
81123
81140
  }
81124
- return void 0;
81141
+ return data;
81142
+ } catch (error) {
81143
+ console.error("Unexpected error in stream processing:", error);
81144
+ if (error.code === "ERR_STREAM_PREMATURE_CLOSE") {
81145
+ console.log("Stream prematurely closed, aborting operations");
81146
+ abortController.abort();
81147
+ return void 0;
81148
+ }
81149
+ throw error;
81125
81150
  }
81126
- return data;
81127
- }).pipeThrough(new SSESerializerTransform());
81151
+ }).pipeThrough(new SSESerializerTransform()));
81128
81152
  }
81129
81153
  const [originalStream, clonedStream] = payload.tee();
81130
81154
  const read = async (stream) => {
81131
81155
  const reader = stream.getReader();
81132
- while (true) {
81133
- const { done, value } = await reader.read();
81134
- if (done) break;
81135
- const dataStr = new TextDecoder().decode(value);
81136
- if (!dataStr.startsWith("event: message_delta")) {
81137
- continue;
81156
+ try {
81157
+ while (true) {
81158
+ const { done: done2, value } = await reader.read();
81159
+ if (done2) break;
81160
+ const dataStr = new TextDecoder().decode(value);
81161
+ if (!dataStr.startsWith("event: message_delta")) {
81162
+ continue;
81163
+ }
81164
+ const str = dataStr.slice(27);
81165
+ try {
81166
+ const message = JSON.parse(str);
81167
+ sessionUsageCache.put(req.sessionId, message.usage);
81168
+ } catch {
81169
+ }
81138
81170
  }
81139
- const str = dataStr.slice(27);
81140
- try {
81141
- const message = JSON.parse(str);
81142
- sessionUsageCache.put(req.sessionId, message.usage);
81143
- } catch {
81171
+ } catch (readError) {
81172
+ if (readError.name === "AbortError" || readError.code === "ERR_STREAM_PREMATURE_CLOSE") {
81173
+ console.log("Background read stream closed prematurely");
81174
+ } else {
81175
+ console.error("Error in background stream reading:", readError);
81144
81176
  }
81177
+ } finally {
81178
+ reader.releaseLock();
81145
81179
  }
81146
81180
  };
81147
81181
  read(clonedStream);
81148
- return originalStream;
81182
+ return done(null, originalStream);
81149
81183
  }
81150
81184
  sessionUsageCache.put(req.sessionId, payload.usage);
81151
81185
  }
81152
- return payload;
81186
+ if (typeof payload === "object" && payload.error) {
81187
+ done(payload.error, null);
81188
+ }
81189
+ done(null, payload);
81153
81190
  });
81154
81191
  server.start();
81155
81192
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@musistudio/claude-code-router",
3
- "version": "1.0.45",
3
+ "version": "1.0.46",
4
4
  "description": "Use Claude Code without an Anthropics account and route it to another LLM provider",
5
5
  "bin": {
6
6
  "ccr": "./dist/cli.js"