@blockrun/clawrouter 0.12.251 → 0.12.253
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 +2 -2
- package/dist/cli.js +37 -6
- package/dist/index.js +37 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,7 +105,7 @@ openclaw gateway restart
|
|
|
105
105
|
|
|
106
106
|
### Option B — Standalone (continue.dev, Cursor, VS Code, any OpenAI-compatible client)
|
|
107
107
|
|
|
108
|
-
> **Using Claude Code?** Check out [BRCC](https://
|
|
108
|
+
> **Using Claude Code?** Check out [BRCC](https://github.com/BlockRunAI/brcc) — it's purpose-built for Claude Code with the same smart routing and x402 payments.
|
|
109
109
|
>
|
|
110
110
|
> **Using NousResearch Hermes?** See [ClawRouter-Hermes](https://github.com/BlockRunAI/ClawRouter-Hermes) — a Python plugin that wires Hermes into the ClawRouter proxy. Same wallet, same <!-- br:models.chatVisible -->71<!-- /br:models.chatVisible --> models, same x402 USDC settlement on Base & Solana.
|
|
111
111
|
|
|
@@ -674,7 +674,7 @@ You're here. <!-- br:models.chatVisible -->71<!-- /br:models.chatVisible --> mod
|
|
|
674
674
|
</td>
|
|
675
675
|
<td width="50%">
|
|
676
676
|
|
|
677
|
-
### 🤖 [BRCC](https://
|
|
677
|
+
### 🤖 [BRCC](https://github.com/BlockRunAI/brcc)
|
|
678
678
|
|
|
679
679
|
**BlockRun for Claude Code**
|
|
680
680
|
|
package/dist/cli.js
CHANGED
|
@@ -89597,6 +89597,15 @@ function debrandSystemMessages(messages, resolvedModel) {
|
|
|
89597
89597
|
});
|
|
89598
89598
|
return hasChanges ? result : messages;
|
|
89599
89599
|
}
|
|
89600
|
+
function isToolResultMessage(msg) {
|
|
89601
|
+
if (msg.role === "tool") return true;
|
|
89602
|
+
if (Array.isArray(msg.content)) {
|
|
89603
|
+
return msg.content.some(
|
|
89604
|
+
(b) => b && typeof b === "object" && b.type === "tool_result"
|
|
89605
|
+
);
|
|
89606
|
+
}
|
|
89607
|
+
return false;
|
|
89608
|
+
}
|
|
89600
89609
|
function truncateMessages(messages) {
|
|
89601
89610
|
if (!messages || messages.length <= MAX_MESSAGES) {
|
|
89602
89611
|
return {
|
|
@@ -89609,7 +89618,11 @@ function truncateMessages(messages) {
|
|
|
89609
89618
|
const systemMsgs = messages.filter((m) => m.role === "system");
|
|
89610
89619
|
const conversationMsgs = messages.filter((m) => m.role !== "system");
|
|
89611
89620
|
const maxConversation = MAX_MESSAGES - systemMsgs.length;
|
|
89612
|
-
|
|
89621
|
+
let start = Math.max(0, conversationMsgs.length - maxConversation);
|
|
89622
|
+
while (start < conversationMsgs.length && isToolResultMessage(conversationMsgs[start])) {
|
|
89623
|
+
start++;
|
|
89624
|
+
}
|
|
89625
|
+
const truncatedConversation = conversationMsgs.slice(start);
|
|
89613
89626
|
const result = [...systemMsgs, ...truncatedConversation];
|
|
89614
89627
|
console.log(
|
|
89615
89628
|
`[ClawRouter] Truncated messages: ${messages.length} \u2192 ${result.length} (kept ${systemMsgs.length} system + ${truncatedConversation.length} recent)`
|
|
@@ -90472,6 +90485,10 @@ async function startProxy(options) {
|
|
|
90472
90485
|
}
|
|
90473
90486
|
if (req.url === "/v1/images/image2image" && req.method === "POST") {
|
|
90474
90487
|
const img2imgStartTime = Date.now();
|
|
90488
|
+
const clientAbort = new AbortController();
|
|
90489
|
+
res.on("close", () => {
|
|
90490
|
+
if (!res.writableEnded) clientAbort.abort();
|
|
90491
|
+
});
|
|
90475
90492
|
const chunks = [];
|
|
90476
90493
|
for await (const chunk of req) {
|
|
90477
90494
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
@@ -90487,7 +90504,7 @@ async function startProxy(options) {
|
|
|
90487
90504
|
if (typeof val !== "string" || !val) continue;
|
|
90488
90505
|
if (val.startsWith("data:")) {
|
|
90489
90506
|
} else if (val.startsWith("https://") || val.startsWith("http://")) {
|
|
90490
|
-
const imgResp = await fetch(val);
|
|
90507
|
+
const imgResp = await fetch(val, { signal: clientAbort.signal });
|
|
90491
90508
|
if (!imgResp.ok)
|
|
90492
90509
|
throw new Error(`Failed to download ${field} from ${val}: HTTP ${imgResp.status}`);
|
|
90493
90510
|
const contentType = imgResp.headers.get("content-type") ?? "image/png";
|
|
@@ -90515,7 +90532,8 @@ async function startProxy(options) {
|
|
|
90515
90532
|
const upstream = await payFetch(`${apiBase}/v1/images/image2image`, {
|
|
90516
90533
|
method: "POST",
|
|
90517
90534
|
headers: { "content-type": "application/json", "user-agent": USER_AGENT },
|
|
90518
|
-
body: reqBody
|
|
90535
|
+
body: reqBody,
|
|
90536
|
+
signal: clientAbort.signal
|
|
90519
90537
|
});
|
|
90520
90538
|
const text = await upstream.text();
|
|
90521
90539
|
if (!upstream.ok) {
|
|
@@ -90577,6 +90595,7 @@ async function startProxy(options) {
|
|
|
90577
90595
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
90578
90596
|
res.end(JSON.stringify(result));
|
|
90579
90597
|
} catch (err) {
|
|
90598
|
+
if (clientAbort.signal.aborted) return;
|
|
90580
90599
|
const msg = err instanceof Error ? err.message : String(err);
|
|
90581
90600
|
console.error(`[ClawRouter] Image editing error: ${msg}`);
|
|
90582
90601
|
if (!res.headersSent) {
|
|
@@ -90588,6 +90607,10 @@ async function startProxy(options) {
|
|
|
90588
90607
|
}
|
|
90589
90608
|
if (req.url === "/v1/audio/generations" && req.method === "POST") {
|
|
90590
90609
|
const audioStartTime = Date.now();
|
|
90610
|
+
const clientAbort = new AbortController();
|
|
90611
|
+
res.on("close", () => {
|
|
90612
|
+
if (!res.writableEnded) clientAbort.abort();
|
|
90613
|
+
});
|
|
90591
90614
|
const chunks = [];
|
|
90592
90615
|
for await (const chunk of req) {
|
|
90593
90616
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
@@ -90603,7 +90626,8 @@ async function startProxy(options) {
|
|
|
90603
90626
|
const upstream = await payFetch(`${apiBase}/v1/audio/generations`, {
|
|
90604
90627
|
method: "POST",
|
|
90605
90628
|
headers: { "content-type": "application/json", "user-agent": USER_AGENT },
|
|
90606
|
-
body: reqBody
|
|
90629
|
+
body: reqBody,
|
|
90630
|
+
signal: clientAbort.signal
|
|
90607
90631
|
});
|
|
90608
90632
|
const text = await upstream.text();
|
|
90609
90633
|
if (!upstream.ok) {
|
|
@@ -90625,7 +90649,7 @@ async function startProxy(options) {
|
|
|
90625
90649
|
for (const track of result.data) {
|
|
90626
90650
|
if (track.url?.startsWith("https://") || track.url?.startsWith("http://")) {
|
|
90627
90651
|
try {
|
|
90628
|
-
const audioResp = await fetch(track.url);
|
|
90652
|
+
const audioResp = await fetch(track.url, { signal: clientAbort.signal });
|
|
90629
90653
|
if (audioResp.ok) {
|
|
90630
90654
|
const contentType = audioResp.headers.get("content-type") ?? "audio/mpeg";
|
|
90631
90655
|
const ext = contentType.includes("wav") ? "wav" : "mp3";
|
|
@@ -90657,6 +90681,7 @@ async function startProxy(options) {
|
|
|
90657
90681
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
90658
90682
|
res.end(JSON.stringify(result));
|
|
90659
90683
|
} catch (err) {
|
|
90684
|
+
if (clientAbort.signal.aborted) return;
|
|
90660
90685
|
const msg = err instanceof Error ? err.message : String(err);
|
|
90661
90686
|
console.error(`[ClawRouter] Audio generation error: ${msg}`);
|
|
90662
90687
|
if (!res.headersSent) {
|
|
@@ -91676,6 +91701,10 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
91676
91701
|
console.log(
|
|
91677
91702
|
`[ClawRouter] /img2img \u2192 ${img2imgModel} (${img2imgSize}): ${img2imgPrompt.slice(0, 80)}`
|
|
91678
91703
|
);
|
|
91704
|
+
const img2imgAbort = new AbortController();
|
|
91705
|
+
res.on("close", () => {
|
|
91706
|
+
if (!res.writableEnded) img2imgAbort.abort();
|
|
91707
|
+
});
|
|
91679
91708
|
try {
|
|
91680
91709
|
const img2imgBody = JSON.stringify({
|
|
91681
91710
|
model: img2imgModel,
|
|
@@ -91688,7 +91717,8 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
91688
91717
|
const img2imgResponse = await payFetch(`${apiBase}/v1/images/image2image`, {
|
|
91689
91718
|
method: "POST",
|
|
91690
91719
|
headers: { "content-type": "application/json", "user-agent": USER_AGENT },
|
|
91691
|
-
body: img2imgBody
|
|
91720
|
+
body: img2imgBody,
|
|
91721
|
+
signal: img2imgAbort.signal
|
|
91692
91722
|
});
|
|
91693
91723
|
const img2imgResult = await img2imgResponse.json();
|
|
91694
91724
|
let responseText;
|
|
@@ -91738,6 +91768,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
91738
91768
|
}
|
|
91739
91769
|
sendImg2ImgText(responseText);
|
|
91740
91770
|
} catch (err) {
|
|
91771
|
+
if (img2imgAbort.signal.aborted) return;
|
|
91741
91772
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
91742
91773
|
console.error(`[ClawRouter] /img2img error: ${errMsg}`);
|
|
91743
91774
|
if (!res.headersSent) {
|
package/dist/index.js
CHANGED
|
@@ -89417,6 +89417,15 @@ function debrandSystemMessages(messages, resolvedModel) {
|
|
|
89417
89417
|
});
|
|
89418
89418
|
return hasChanges ? result : messages;
|
|
89419
89419
|
}
|
|
89420
|
+
function isToolResultMessage(msg) {
|
|
89421
|
+
if (msg.role === "tool") return true;
|
|
89422
|
+
if (Array.isArray(msg.content)) {
|
|
89423
|
+
return msg.content.some(
|
|
89424
|
+
(b) => b && typeof b === "object" && b.type === "tool_result"
|
|
89425
|
+
);
|
|
89426
|
+
}
|
|
89427
|
+
return false;
|
|
89428
|
+
}
|
|
89420
89429
|
function truncateMessages(messages) {
|
|
89421
89430
|
if (!messages || messages.length <= MAX_MESSAGES) {
|
|
89422
89431
|
return {
|
|
@@ -89429,7 +89438,11 @@ function truncateMessages(messages) {
|
|
|
89429
89438
|
const systemMsgs = messages.filter((m) => m.role === "system");
|
|
89430
89439
|
const conversationMsgs = messages.filter((m) => m.role !== "system");
|
|
89431
89440
|
const maxConversation = MAX_MESSAGES - systemMsgs.length;
|
|
89432
|
-
|
|
89441
|
+
let start = Math.max(0, conversationMsgs.length - maxConversation);
|
|
89442
|
+
while (start < conversationMsgs.length && isToolResultMessage(conversationMsgs[start])) {
|
|
89443
|
+
start++;
|
|
89444
|
+
}
|
|
89445
|
+
const truncatedConversation = conversationMsgs.slice(start);
|
|
89433
89446
|
const result = [...systemMsgs, ...truncatedConversation];
|
|
89434
89447
|
console.log(
|
|
89435
89448
|
`[ClawRouter] Truncated messages: ${messages.length} \u2192 ${result.length} (kept ${systemMsgs.length} system + ${truncatedConversation.length} recent)`
|
|
@@ -90292,6 +90305,10 @@ async function startProxy(options) {
|
|
|
90292
90305
|
}
|
|
90293
90306
|
if (req.url === "/v1/images/image2image" && req.method === "POST") {
|
|
90294
90307
|
const img2imgStartTime = Date.now();
|
|
90308
|
+
const clientAbort = new AbortController();
|
|
90309
|
+
res.on("close", () => {
|
|
90310
|
+
if (!res.writableEnded) clientAbort.abort();
|
|
90311
|
+
});
|
|
90295
90312
|
const chunks = [];
|
|
90296
90313
|
for await (const chunk of req) {
|
|
90297
90314
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
@@ -90307,7 +90324,7 @@ async function startProxy(options) {
|
|
|
90307
90324
|
if (typeof val !== "string" || !val) continue;
|
|
90308
90325
|
if (val.startsWith("data:")) {
|
|
90309
90326
|
} else if (val.startsWith("https://") || val.startsWith("http://")) {
|
|
90310
|
-
const imgResp = await fetch(val);
|
|
90327
|
+
const imgResp = await fetch(val, { signal: clientAbort.signal });
|
|
90311
90328
|
if (!imgResp.ok)
|
|
90312
90329
|
throw new Error(`Failed to download ${field} from ${val}: HTTP ${imgResp.status}`);
|
|
90313
90330
|
const contentType = imgResp.headers.get("content-type") ?? "image/png";
|
|
@@ -90335,7 +90352,8 @@ async function startProxy(options) {
|
|
|
90335
90352
|
const upstream = await payFetch(`${apiBase}/v1/images/image2image`, {
|
|
90336
90353
|
method: "POST",
|
|
90337
90354
|
headers: { "content-type": "application/json", "user-agent": USER_AGENT },
|
|
90338
|
-
body: reqBody
|
|
90355
|
+
body: reqBody,
|
|
90356
|
+
signal: clientAbort.signal
|
|
90339
90357
|
});
|
|
90340
90358
|
const text = await upstream.text();
|
|
90341
90359
|
if (!upstream.ok) {
|
|
@@ -90397,6 +90415,7 @@ async function startProxy(options) {
|
|
|
90397
90415
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
90398
90416
|
res.end(JSON.stringify(result));
|
|
90399
90417
|
} catch (err) {
|
|
90418
|
+
if (clientAbort.signal.aborted) return;
|
|
90400
90419
|
const msg = err instanceof Error ? err.message : String(err);
|
|
90401
90420
|
console.error(`[ClawRouter] Image editing error: ${msg}`);
|
|
90402
90421
|
if (!res.headersSent) {
|
|
@@ -90408,6 +90427,10 @@ async function startProxy(options) {
|
|
|
90408
90427
|
}
|
|
90409
90428
|
if (req.url === "/v1/audio/generations" && req.method === "POST") {
|
|
90410
90429
|
const audioStartTime = Date.now();
|
|
90430
|
+
const clientAbort = new AbortController();
|
|
90431
|
+
res.on("close", () => {
|
|
90432
|
+
if (!res.writableEnded) clientAbort.abort();
|
|
90433
|
+
});
|
|
90411
90434
|
const chunks = [];
|
|
90412
90435
|
for await (const chunk of req) {
|
|
90413
90436
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
@@ -90423,7 +90446,8 @@ async function startProxy(options) {
|
|
|
90423
90446
|
const upstream = await payFetch(`${apiBase}/v1/audio/generations`, {
|
|
90424
90447
|
method: "POST",
|
|
90425
90448
|
headers: { "content-type": "application/json", "user-agent": USER_AGENT },
|
|
90426
|
-
body: reqBody
|
|
90449
|
+
body: reqBody,
|
|
90450
|
+
signal: clientAbort.signal
|
|
90427
90451
|
});
|
|
90428
90452
|
const text = await upstream.text();
|
|
90429
90453
|
if (!upstream.ok) {
|
|
@@ -90445,7 +90469,7 @@ async function startProxy(options) {
|
|
|
90445
90469
|
for (const track of result.data) {
|
|
90446
90470
|
if (track.url?.startsWith("https://") || track.url?.startsWith("http://")) {
|
|
90447
90471
|
try {
|
|
90448
|
-
const audioResp = await fetch(track.url);
|
|
90472
|
+
const audioResp = await fetch(track.url, { signal: clientAbort.signal });
|
|
90449
90473
|
if (audioResp.ok) {
|
|
90450
90474
|
const contentType = audioResp.headers.get("content-type") ?? "audio/mpeg";
|
|
90451
90475
|
const ext = contentType.includes("wav") ? "wav" : "mp3";
|
|
@@ -90477,6 +90501,7 @@ async function startProxy(options) {
|
|
|
90477
90501
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
90478
90502
|
res.end(JSON.stringify(result));
|
|
90479
90503
|
} catch (err) {
|
|
90504
|
+
if (clientAbort.signal.aborted) return;
|
|
90480
90505
|
const msg = err instanceof Error ? err.message : String(err);
|
|
90481
90506
|
console.error(`[ClawRouter] Audio generation error: ${msg}`);
|
|
90482
90507
|
if (!res.headersSent) {
|
|
@@ -91496,6 +91521,10 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
91496
91521
|
console.log(
|
|
91497
91522
|
`[ClawRouter] /img2img \u2192 ${img2imgModel} (${img2imgSize}): ${img2imgPrompt.slice(0, 80)}`
|
|
91498
91523
|
);
|
|
91524
|
+
const img2imgAbort = new AbortController();
|
|
91525
|
+
res.on("close", () => {
|
|
91526
|
+
if (!res.writableEnded) img2imgAbort.abort();
|
|
91527
|
+
});
|
|
91499
91528
|
try {
|
|
91500
91529
|
const img2imgBody = JSON.stringify({
|
|
91501
91530
|
model: img2imgModel,
|
|
@@ -91508,7 +91537,8 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
91508
91537
|
const img2imgResponse = await payFetch(`${apiBase}/v1/images/image2image`, {
|
|
91509
91538
|
method: "POST",
|
|
91510
91539
|
headers: { "content-type": "application/json", "user-agent": USER_AGENT },
|
|
91511
|
-
body: img2imgBody
|
|
91540
|
+
body: img2imgBody,
|
|
91541
|
+
signal: img2imgAbort.signal
|
|
91512
91542
|
});
|
|
91513
91543
|
const img2imgResult = await img2imgResponse.json();
|
|
91514
91544
|
let responseText;
|
|
@@ -91558,6 +91588,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
91558
91588
|
}
|
|
91559
91589
|
sendImg2ImgText(responseText);
|
|
91560
91590
|
} catch (err) {
|
|
91591
|
+
if (img2imgAbort.signal.aborted) return;
|
|
91561
91592
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
91562
91593
|
console.error(`[ClawRouter] /img2img error: ${errMsg}`);
|
|
91563
91594
|
if (!res.headersSent) {
|
package/package.json
CHANGED