@blockrun/clawrouter 0.6.4 → 0.6.7
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 +85 -14
- package/dist/index.js.map +1 -1
- package/package.json +8 -2
- package/scripts/reinstall.sh +29 -29
package/dist/index.js
CHANGED
|
@@ -467,6 +467,7 @@ var blockrunProvider = {
|
|
|
467
467
|
|
|
468
468
|
// src/proxy.ts
|
|
469
469
|
import { createServer } from "http";
|
|
470
|
+
import { finished } from "stream";
|
|
470
471
|
import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
471
472
|
|
|
472
473
|
// src/x402.ts
|
|
@@ -2365,6 +2366,15 @@ function prioritizeNonRateLimited(models) {
|
|
|
2365
2366
|
}
|
|
2366
2367
|
return [...available, ...rateLimited];
|
|
2367
2368
|
}
|
|
2369
|
+
function canWrite(res) {
|
|
2370
|
+
return !res.writableEnded && !res.destroyed && res.socket !== null && !res.socket.destroyed && res.socket.writable;
|
|
2371
|
+
}
|
|
2372
|
+
function safeWrite(res, data) {
|
|
2373
|
+
if (!canWrite(res)) {
|
|
2374
|
+
return false;
|
|
2375
|
+
}
|
|
2376
|
+
return res.write(data);
|
|
2377
|
+
}
|
|
2368
2378
|
var BALANCE_CHECK_BUFFER = 1.5;
|
|
2369
2379
|
function getProxyPort() {
|
|
2370
2380
|
const envPort = process.env.BLOCKRUN_PROXY_PORT;
|
|
@@ -2573,7 +2583,24 @@ async function startProxy(options) {
|
|
|
2573
2583
|
};
|
|
2574
2584
|
const deduplicator = new RequestDeduplicator();
|
|
2575
2585
|
const sessionStore = new SessionStore(options.sessionConfig);
|
|
2586
|
+
const connections = /* @__PURE__ */ new Set();
|
|
2576
2587
|
const server = createServer(async (req, res) => {
|
|
2588
|
+
req.on("error", (err) => {
|
|
2589
|
+
console.error(`[ClawRouter] Request stream error: ${err.message}`);
|
|
2590
|
+
});
|
|
2591
|
+
res.on("error", (err) => {
|
|
2592
|
+
console.error(`[ClawRouter] Response stream error: ${err.message}`);
|
|
2593
|
+
});
|
|
2594
|
+
finished(res, (err) => {
|
|
2595
|
+
if (err && err.code !== "ERR_STREAM_DESTROYED") {
|
|
2596
|
+
console.error(`[ClawRouter] Response finished with error: ${err.message}`);
|
|
2597
|
+
}
|
|
2598
|
+
});
|
|
2599
|
+
finished(req, (err) => {
|
|
2600
|
+
if (err && err.code !== "ERR_STREAM_DESTROYED") {
|
|
2601
|
+
console.error(`[ClawRouter] Request finished with error: ${err.message}`);
|
|
2602
|
+
}
|
|
2603
|
+
});
|
|
2577
2604
|
if (req.url === "/health" || req.url?.startsWith("/health?")) {
|
|
2578
2605
|
const url = new URL(req.url, "http://localhost");
|
|
2579
2606
|
const full = url.searchParams.get("full") === "true";
|
|
@@ -2686,14 +2713,54 @@ async function startProxy(options) {
|
|
|
2686
2713
|
const port = addr.port;
|
|
2687
2714
|
const baseUrl = `http://127.0.0.1:${port}`;
|
|
2688
2715
|
options.onReady?.(port);
|
|
2716
|
+
server.on("error", (err) => {
|
|
2717
|
+
console.error(`[ClawRouter] Server runtime error: ${err.message}`);
|
|
2718
|
+
options.onError?.(err);
|
|
2719
|
+
});
|
|
2720
|
+
server.on("clientError", (err, socket) => {
|
|
2721
|
+
console.error(`[ClawRouter] Client error: ${err.message}`);
|
|
2722
|
+
if (socket.writable && !socket.destroyed) {
|
|
2723
|
+
socket.end("HTTP/1.1 400 Bad Request\r\n\r\n");
|
|
2724
|
+
}
|
|
2725
|
+
});
|
|
2726
|
+
server.on("connection", (socket) => {
|
|
2727
|
+
connections.add(socket);
|
|
2728
|
+
socket.setTimeout(3e5);
|
|
2729
|
+
socket.on("timeout", () => {
|
|
2730
|
+
console.error(`[ClawRouter] Socket timeout, destroying connection`);
|
|
2731
|
+
socket.destroy();
|
|
2732
|
+
});
|
|
2733
|
+
socket.on("end", () => {
|
|
2734
|
+
});
|
|
2735
|
+
socket.on("error", (err) => {
|
|
2736
|
+
console.error(`[ClawRouter] Socket error: ${err.message}`);
|
|
2737
|
+
});
|
|
2738
|
+
socket.on("close", () => {
|
|
2739
|
+
connections.delete(socket);
|
|
2740
|
+
});
|
|
2741
|
+
});
|
|
2689
2742
|
resolve({
|
|
2690
2743
|
port,
|
|
2691
2744
|
baseUrl,
|
|
2692
2745
|
walletAddress: account.address,
|
|
2693
2746
|
balanceMonitor,
|
|
2694
2747
|
close: () => new Promise((res, rej) => {
|
|
2748
|
+
const timeout = setTimeout(() => {
|
|
2749
|
+
rej(new Error("[ClawRouter] Close timeout after 4s"));
|
|
2750
|
+
}, 4e3);
|
|
2695
2751
|
sessionStore.close();
|
|
2696
|
-
|
|
2752
|
+
for (const socket of connections) {
|
|
2753
|
+
socket.destroy();
|
|
2754
|
+
}
|
|
2755
|
+
connections.clear();
|
|
2756
|
+
server.close((err) => {
|
|
2757
|
+
clearTimeout(timeout);
|
|
2758
|
+
if (err) {
|
|
2759
|
+
rej(err);
|
|
2760
|
+
} else {
|
|
2761
|
+
res();
|
|
2762
|
+
}
|
|
2763
|
+
});
|
|
2697
2764
|
})
|
|
2698
2765
|
});
|
|
2699
2766
|
});
|
|
@@ -2901,10 +2968,13 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
2901
2968
|
connection: "keep-alive"
|
|
2902
2969
|
});
|
|
2903
2970
|
headersSentEarly = true;
|
|
2904
|
-
res
|
|
2971
|
+
safeWrite(res, ": heartbeat\n\n");
|
|
2905
2972
|
heartbeatInterval = setInterval(() => {
|
|
2906
|
-
if (
|
|
2907
|
-
res
|
|
2973
|
+
if (canWrite(res)) {
|
|
2974
|
+
safeWrite(res, ": heartbeat\n\n");
|
|
2975
|
+
} else {
|
|
2976
|
+
clearInterval(heartbeatInterval);
|
|
2977
|
+
heartbeatInterval = void 0;
|
|
2908
2978
|
}
|
|
2909
2979
|
}, HEARTBEAT_INTERVAL_MS);
|
|
2910
2980
|
}
|
|
@@ -3022,8 +3092,8 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
3022
3092
|
const errEvent = `data: ${JSON.stringify({ error: { message: errBody, type: "provider_error", status: errStatus } })}
|
|
3023
3093
|
|
|
3024
3094
|
`;
|
|
3025
|
-
res
|
|
3026
|
-
res
|
|
3095
|
+
safeWrite(res, errEvent);
|
|
3096
|
+
safeWrite(res, "data: [DONE]\n\n");
|
|
3027
3097
|
res.end();
|
|
3028
3098
|
const errBuf = Buffer.from(errEvent + "data: [DONE]\n\n");
|
|
3029
3099
|
deduplicator.complete(dedupKey, {
|
|
@@ -3088,7 +3158,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
3088
3158
|
const roleData = `data: ${JSON.stringify(roleChunk)}
|
|
3089
3159
|
|
|
3090
3160
|
`;
|
|
3091
|
-
res
|
|
3161
|
+
safeWrite(res, roleData);
|
|
3092
3162
|
responseChunks.push(Buffer.from(roleData));
|
|
3093
3163
|
if (content) {
|
|
3094
3164
|
const contentChunk = {
|
|
@@ -3098,7 +3168,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
3098
3168
|
const contentData = `data: ${JSON.stringify(contentChunk)}
|
|
3099
3169
|
|
|
3100
3170
|
`;
|
|
3101
|
-
res
|
|
3171
|
+
safeWrite(res, contentData);
|
|
3102
3172
|
responseChunks.push(Buffer.from(contentData));
|
|
3103
3173
|
}
|
|
3104
3174
|
const toolCalls = choice.message?.tool_calls ?? choice.delta?.tool_calls;
|
|
@@ -3117,7 +3187,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
3117
3187
|
const toolCallData = `data: ${JSON.stringify(toolCallChunk)}
|
|
3118
3188
|
|
|
3119
3189
|
`;
|
|
3120
|
-
res
|
|
3190
|
+
safeWrite(res, toolCallData);
|
|
3121
3191
|
responseChunks.push(Buffer.from(toolCallData));
|
|
3122
3192
|
}
|
|
3123
3193
|
const finishChunk = {
|
|
@@ -3134,7 +3204,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
3134
3204
|
const finishData = `data: ${JSON.stringify(finishChunk)}
|
|
3135
3205
|
|
|
3136
3206
|
`;
|
|
3137
|
-
res
|
|
3207
|
+
safeWrite(res, finishData);
|
|
3138
3208
|
responseChunks.push(Buffer.from(finishData));
|
|
3139
3209
|
}
|
|
3140
3210
|
}
|
|
@@ -3142,11 +3212,11 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
3142
3212
|
const sseData = `data: ${jsonStr}
|
|
3143
3213
|
|
|
3144
3214
|
`;
|
|
3145
|
-
res
|
|
3215
|
+
safeWrite(res, sseData);
|
|
3146
3216
|
responseChunks.push(Buffer.from(sseData));
|
|
3147
3217
|
}
|
|
3148
3218
|
}
|
|
3149
|
-
res
|
|
3219
|
+
safeWrite(res, "data: [DONE]\n\n");
|
|
3150
3220
|
responseChunks.push(Buffer.from("data: [DONE]\n\n"));
|
|
3151
3221
|
res.end();
|
|
3152
3222
|
deduplicator.complete(dedupKey, {
|
|
@@ -3169,8 +3239,9 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
3169
3239
|
while (true) {
|
|
3170
3240
|
const { done, value } = await reader.read();
|
|
3171
3241
|
if (done) break;
|
|
3172
|
-
|
|
3173
|
-
|
|
3242
|
+
const chunk = Buffer.from(value);
|
|
3243
|
+
safeWrite(res, chunk);
|
|
3244
|
+
responseChunks.push(chunk);
|
|
3174
3245
|
}
|
|
3175
3246
|
} finally {
|
|
3176
3247
|
reader.releaseLock();
|