@blockrun/clawrouter 0.6.9 → 0.7.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/cli.d.ts +1 -0
- package/dist/cli.js +3418 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.js +112 -67
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -2324,6 +2324,8 @@ var DEFAULT_PORT = 8402;
|
|
|
2324
2324
|
var MAX_FALLBACK_ATTEMPTS = 3;
|
|
2325
2325
|
var HEALTH_CHECK_TIMEOUT_MS = 2e3;
|
|
2326
2326
|
var RATE_LIMIT_COOLDOWN_MS = 6e4;
|
|
2327
|
+
var PORT_RETRY_ATTEMPTS = 5;
|
|
2328
|
+
var PORT_RETRY_DELAY_MS = 1e3;
|
|
2327
2329
|
var rateLimitedModels = /* @__PURE__ */ new Map();
|
|
2328
2330
|
function isRateLimited(modelId) {
|
|
2329
2331
|
const hitTime = rateLimitedModels.get(modelId);
|
|
@@ -2613,7 +2615,7 @@ async function startProxy(options) {
|
|
|
2613
2615
|
if (existingWallet) {
|
|
2614
2616
|
const account2 = privateKeyToAccount2(options.walletKey);
|
|
2615
2617
|
const balanceMonitor2 = new BalanceMonitor(account2.address);
|
|
2616
|
-
const
|
|
2618
|
+
const baseUrl2 = `http://127.0.0.1:${listenPort}`;
|
|
2617
2619
|
if (existingWallet !== account2.address) {
|
|
2618
2620
|
console.warn(
|
|
2619
2621
|
`[ClawRouter] Existing proxy on port ${listenPort} uses wallet ${existingWallet}, but current config uses ${account2.address}. Reusing existing proxy.`
|
|
@@ -2622,7 +2624,7 @@ async function startProxy(options) {
|
|
|
2622
2624
|
options.onReady?.(listenPort);
|
|
2623
2625
|
return {
|
|
2624
2626
|
port: listenPort,
|
|
2625
|
-
baseUrl,
|
|
2627
|
+
baseUrl: baseUrl2,
|
|
2626
2628
|
walletAddress: existingWallet,
|
|
2627
2629
|
balanceMonitor: balanceMonitor2,
|
|
2628
2630
|
close: async () => {
|
|
@@ -2748,80 +2750,123 @@ async function startProxy(options) {
|
|
|
2748
2750
|
}
|
|
2749
2751
|
}
|
|
2750
2752
|
});
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2753
|
+
const tryListen = (attempt) => {
|
|
2754
|
+
return new Promise((resolveAttempt, rejectAttempt) => {
|
|
2755
|
+
const onError = async (err) => {
|
|
2756
|
+
server.removeListener("error", onError);
|
|
2757
|
+
if (err.code === "EADDRINUSE") {
|
|
2758
|
+
const existingWallet2 = await checkExistingProxy(listenPort);
|
|
2759
|
+
if (existingWallet2) {
|
|
2760
|
+
console.log(`[ClawRouter] Existing proxy detected on port ${listenPort}, reusing`);
|
|
2761
|
+
rejectAttempt({ code: "REUSE_EXISTING", wallet: existingWallet2 });
|
|
2762
|
+
return;
|
|
2763
|
+
}
|
|
2764
|
+
if (attempt < PORT_RETRY_ATTEMPTS) {
|
|
2765
|
+
console.log(
|
|
2766
|
+
`[ClawRouter] Port ${listenPort} in TIME_WAIT, retrying in ${PORT_RETRY_DELAY_MS}ms (attempt ${attempt}/${PORT_RETRY_ATTEMPTS})`
|
|
2767
|
+
);
|
|
2768
|
+
rejectAttempt({ code: "RETRY", attempt });
|
|
2769
|
+
return;
|
|
2770
|
+
}
|
|
2771
|
+
console.error(
|
|
2772
|
+
`[ClawRouter] Port ${listenPort} still in use after ${PORT_RETRY_ATTEMPTS} attempts`
|
|
2773
|
+
);
|
|
2774
|
+
rejectAttempt(err);
|
|
2775
|
+
return;
|
|
2776
|
+
}
|
|
2777
|
+
rejectAttempt(err);
|
|
2778
|
+
};
|
|
2779
|
+
server.once("error", onError);
|
|
2780
|
+
server.listen(listenPort, "127.0.0.1", () => {
|
|
2781
|
+
server.removeListener("error", onError);
|
|
2782
|
+
resolveAttempt();
|
|
2783
|
+
});
|
|
2784
|
+
});
|
|
2785
|
+
};
|
|
2786
|
+
let lastError;
|
|
2787
|
+
for (let attempt = 1; attempt <= PORT_RETRY_ATTEMPTS; attempt++) {
|
|
2788
|
+
try {
|
|
2789
|
+
await tryListen(attempt);
|
|
2790
|
+
break;
|
|
2791
|
+
} catch (err) {
|
|
2792
|
+
const error = err;
|
|
2793
|
+
if (error.code === "REUSE_EXISTING" && error.wallet) {
|
|
2794
|
+
const baseUrl2 = `http://127.0.0.1:${listenPort}`;
|
|
2755
2795
|
options.onReady?.(listenPort);
|
|
2756
|
-
|
|
2796
|
+
return {
|
|
2757
2797
|
port: listenPort,
|
|
2758
|
-
baseUrl,
|
|
2759
|
-
walletAddress:
|
|
2798
|
+
baseUrl: baseUrl2,
|
|
2799
|
+
walletAddress: error.wallet,
|
|
2760
2800
|
balanceMonitor,
|
|
2761
2801
|
close: async () => {
|
|
2762
2802
|
}
|
|
2763
|
-
}
|
|
2764
|
-
return;
|
|
2803
|
+
};
|
|
2765
2804
|
}
|
|
2766
|
-
|
|
2805
|
+
if (error.code === "RETRY") {
|
|
2806
|
+
await new Promise((r) => setTimeout(r, PORT_RETRY_DELAY_MS));
|
|
2807
|
+
continue;
|
|
2808
|
+
}
|
|
2809
|
+
lastError = err;
|
|
2810
|
+
break;
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
if (lastError) {
|
|
2814
|
+
throw lastError;
|
|
2815
|
+
}
|
|
2816
|
+
const addr = server.address();
|
|
2817
|
+
const port = addr.port;
|
|
2818
|
+
const baseUrl = `http://127.0.0.1:${port}`;
|
|
2819
|
+
options.onReady?.(port);
|
|
2820
|
+
server.on("error", (err) => {
|
|
2821
|
+
console.error(`[ClawRouter] Server runtime error: ${err.message}`);
|
|
2822
|
+
options.onError?.(err);
|
|
2823
|
+
});
|
|
2824
|
+
server.on("clientError", (err, socket) => {
|
|
2825
|
+
console.error(`[ClawRouter] Client error: ${err.message}`);
|
|
2826
|
+
if (socket.writable && !socket.destroyed) {
|
|
2827
|
+
socket.end("HTTP/1.1 400 Bad Request\r\n\r\n");
|
|
2828
|
+
}
|
|
2829
|
+
});
|
|
2830
|
+
server.on("connection", (socket) => {
|
|
2831
|
+
connections.add(socket);
|
|
2832
|
+
socket.setTimeout(3e5);
|
|
2833
|
+
socket.on("timeout", () => {
|
|
2834
|
+
console.error(`[ClawRouter] Socket timeout, destroying connection`);
|
|
2835
|
+
socket.destroy();
|
|
2767
2836
|
});
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
options.onError?.(err);
|
|
2776
|
-
});
|
|
2777
|
-
server.on("clientError", (err, socket) => {
|
|
2778
|
-
console.error(`[ClawRouter] Client error: ${err.message}`);
|
|
2779
|
-
if (socket.writable && !socket.destroyed) {
|
|
2780
|
-
socket.end("HTTP/1.1 400 Bad Request\r\n\r\n");
|
|
2781
|
-
}
|
|
2782
|
-
});
|
|
2783
|
-
server.on("connection", (socket) => {
|
|
2784
|
-
connections.add(socket);
|
|
2785
|
-
socket.setTimeout(3e5);
|
|
2786
|
-
socket.on("timeout", () => {
|
|
2787
|
-
console.error(`[ClawRouter] Socket timeout, destroying connection`);
|
|
2788
|
-
socket.destroy();
|
|
2789
|
-
});
|
|
2790
|
-
socket.on("end", () => {
|
|
2791
|
-
});
|
|
2792
|
-
socket.on("error", (err) => {
|
|
2793
|
-
console.error(`[ClawRouter] Socket error: ${err.message}`);
|
|
2794
|
-
});
|
|
2795
|
-
socket.on("close", () => {
|
|
2796
|
-
connections.delete(socket);
|
|
2797
|
-
});
|
|
2798
|
-
});
|
|
2799
|
-
resolve({
|
|
2800
|
-
port,
|
|
2801
|
-
baseUrl,
|
|
2802
|
-
walletAddress: account.address,
|
|
2803
|
-
balanceMonitor,
|
|
2804
|
-
close: () => new Promise((res, rej) => {
|
|
2805
|
-
const timeout = setTimeout(() => {
|
|
2806
|
-
rej(new Error("[ClawRouter] Close timeout after 4s"));
|
|
2807
|
-
}, 4e3);
|
|
2808
|
-
sessionStore.close();
|
|
2809
|
-
for (const socket of connections) {
|
|
2810
|
-
socket.destroy();
|
|
2811
|
-
}
|
|
2812
|
-
connections.clear();
|
|
2813
|
-
server.close((err) => {
|
|
2814
|
-
clearTimeout(timeout);
|
|
2815
|
-
if (err) {
|
|
2816
|
-
rej(err);
|
|
2817
|
-
} else {
|
|
2818
|
-
res();
|
|
2819
|
-
}
|
|
2820
|
-
});
|
|
2821
|
-
})
|
|
2822
|
-
});
|
|
2837
|
+
socket.on("end", () => {
|
|
2838
|
+
});
|
|
2839
|
+
socket.on("error", (err) => {
|
|
2840
|
+
console.error(`[ClawRouter] Socket error: ${err.message}`);
|
|
2841
|
+
});
|
|
2842
|
+
socket.on("close", () => {
|
|
2843
|
+
connections.delete(socket);
|
|
2823
2844
|
});
|
|
2824
2845
|
});
|
|
2846
|
+
return {
|
|
2847
|
+
port,
|
|
2848
|
+
baseUrl,
|
|
2849
|
+
walletAddress: account.address,
|
|
2850
|
+
balanceMonitor,
|
|
2851
|
+
close: () => new Promise((res, rej) => {
|
|
2852
|
+
const timeout = setTimeout(() => {
|
|
2853
|
+
rej(new Error("[ClawRouter] Close timeout after 4s"));
|
|
2854
|
+
}, 4e3);
|
|
2855
|
+
sessionStore.close();
|
|
2856
|
+
for (const socket of connections) {
|
|
2857
|
+
socket.destroy();
|
|
2858
|
+
}
|
|
2859
|
+
connections.clear();
|
|
2860
|
+
server.close((err) => {
|
|
2861
|
+
clearTimeout(timeout);
|
|
2862
|
+
if (err) {
|
|
2863
|
+
rej(err);
|
|
2864
|
+
} else {
|
|
2865
|
+
res();
|
|
2866
|
+
}
|
|
2867
|
+
});
|
|
2868
|
+
})
|
|
2869
|
+
};
|
|
2825
2870
|
}
|
|
2826
2871
|
async function tryModelRequest(upstreamUrl, method, headers, body, modelId, maxTokens, payFetch, balanceMonitor, signal) {
|
|
2827
2872
|
let requestBody = body;
|