@blockrun/clawrouter 0.6.8 → 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 +132 -109
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -715,7 +715,7 @@ function scoreAgenticTask(text, keywords) {
|
|
|
715
715
|
}
|
|
716
716
|
}
|
|
717
717
|
}
|
|
718
|
-
if (matchCount >=
|
|
718
|
+
if (matchCount >= 4) {
|
|
719
719
|
return {
|
|
720
720
|
dimensionScore: {
|
|
721
721
|
name: "agenticTask",
|
|
@@ -724,7 +724,7 @@ function scoreAgenticTask(text, keywords) {
|
|
|
724
724
|
},
|
|
725
725
|
agenticScore: 1
|
|
726
726
|
};
|
|
727
|
-
} else if (matchCount >=
|
|
727
|
+
} else if (matchCount >= 3) {
|
|
728
728
|
return {
|
|
729
729
|
dimensionScore: {
|
|
730
730
|
name: "agenticTask",
|
|
@@ -737,10 +737,10 @@ function scoreAgenticTask(text, keywords) {
|
|
|
737
737
|
return {
|
|
738
738
|
dimensionScore: {
|
|
739
739
|
name: "agenticTask",
|
|
740
|
-
score: 0.
|
|
741
|
-
signal: `agentic (${signals.join(", ")})`
|
|
740
|
+
score: 0.2,
|
|
741
|
+
signal: `agentic-light (${signals.join(", ")})`
|
|
742
742
|
},
|
|
743
|
-
agenticScore: 0.
|
|
743
|
+
agenticScore: 0.2
|
|
744
744
|
};
|
|
745
745
|
}
|
|
746
746
|
return {
|
|
@@ -1479,8 +1479,9 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1479
1479
|
"gitterbasiert"
|
|
1480
1480
|
],
|
|
1481
1481
|
// Agentic task keywords - file ops, execution, multi-step, iterative work
|
|
1482
|
+
// Pruned: removed overly common words like "then", "first", "run", "test", "build"
|
|
1482
1483
|
agenticTaskKeywords: [
|
|
1483
|
-
// English - File operations
|
|
1484
|
+
// English - File operations (clearly agentic)
|
|
1484
1485
|
"read file",
|
|
1485
1486
|
"read the file",
|
|
1486
1487
|
"look at",
|
|
@@ -1492,30 +1493,19 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1492
1493
|
"change the",
|
|
1493
1494
|
"write to",
|
|
1494
1495
|
"create file",
|
|
1495
|
-
// English - Execution
|
|
1496
|
-
"run",
|
|
1496
|
+
// English - Execution (specific commands only)
|
|
1497
1497
|
"execute",
|
|
1498
|
-
"test",
|
|
1499
|
-
"build",
|
|
1500
1498
|
"deploy",
|
|
1501
1499
|
"install",
|
|
1502
1500
|
"npm",
|
|
1503
1501
|
"pip",
|
|
1504
1502
|
"compile",
|
|
1505
|
-
|
|
1506
|
-
"launch",
|
|
1507
|
-
// English - Multi-step patterns
|
|
1508
|
-
"then",
|
|
1503
|
+
// English - Multi-step patterns (specific only)
|
|
1509
1504
|
"after that",
|
|
1510
|
-
"next",
|
|
1511
1505
|
"and also",
|
|
1512
|
-
"finally",
|
|
1513
1506
|
"once done",
|
|
1514
1507
|
"step 1",
|
|
1515
1508
|
"step 2",
|
|
1516
|
-
"first",
|
|
1517
|
-
"second",
|
|
1518
|
-
"lastly",
|
|
1519
1509
|
// English - Iterative work
|
|
1520
1510
|
"fix",
|
|
1521
1511
|
"debug",
|
|
@@ -1525,7 +1515,7 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1525
1515
|
"make sure",
|
|
1526
1516
|
"verify",
|
|
1527
1517
|
"confirm",
|
|
1528
|
-
// Chinese
|
|
1518
|
+
// Chinese (keep specific ones)
|
|
1529
1519
|
"\u8BFB\u53D6\u6587\u4EF6",
|
|
1530
1520
|
"\u67E5\u770B",
|
|
1531
1521
|
"\u6253\u5F00",
|
|
@@ -1533,15 +1523,9 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1533
1523
|
"\u4FEE\u6539",
|
|
1534
1524
|
"\u66F4\u65B0",
|
|
1535
1525
|
"\u521B\u5EFA",
|
|
1536
|
-
"\u8FD0\u884C",
|
|
1537
1526
|
"\u6267\u884C",
|
|
1538
|
-
"\u6D4B\u8BD5",
|
|
1539
|
-
"\u6784\u5EFA",
|
|
1540
1527
|
"\u90E8\u7F72",
|
|
1541
1528
|
"\u5B89\u88C5",
|
|
1542
|
-
"\u7136\u540E",
|
|
1543
|
-
"\u63A5\u4E0B\u6765",
|
|
1544
|
-
"\u6700\u540E",
|
|
1545
1529
|
"\u7B2C\u4E00\u6B65",
|
|
1546
1530
|
"\u7B2C\u4E8C\u6B65",
|
|
1547
1531
|
"\u4FEE\u590D",
|
|
@@ -1567,14 +1551,15 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1567
1551
|
referenceComplexity: 0.02,
|
|
1568
1552
|
negationComplexity: 0.01,
|
|
1569
1553
|
domainSpecificity: 0.02,
|
|
1570
|
-
agenticTask: 0.
|
|
1571
|
-
//
|
|
1554
|
+
agenticTask: 0.04
|
|
1555
|
+
// Reduced - agentic signals influence tier selection, not dominate it
|
|
1572
1556
|
},
|
|
1573
1557
|
// Tier boundaries on weighted score axis
|
|
1574
1558
|
tierBoundaries: {
|
|
1575
1559
|
simpleMedium: 0,
|
|
1576
|
-
mediumComplex: 0.
|
|
1577
|
-
complexReasoning: 0.
|
|
1560
|
+
mediumComplex: 0.18,
|
|
1561
|
+
complexReasoning: 0.4
|
|
1562
|
+
// Raised from 0.25 - requires strong reasoning signals
|
|
1578
1563
|
},
|
|
1579
1564
|
// Sigmoid steepness for confidence calibration
|
|
1580
1565
|
confidenceSteepness: 12,
|
|
@@ -1621,9 +1606,9 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1621
1606
|
fallback: ["anthropic/claude-opus-4", "xai/grok-4-0709", "openai/gpt-4o"]
|
|
1622
1607
|
},
|
|
1623
1608
|
REASONING: {
|
|
1624
|
-
primary: "
|
|
1625
|
-
//
|
|
1626
|
-
fallback: ["
|
|
1609
|
+
primary: "anthropic/claude-sonnet-4",
|
|
1610
|
+
// Strong tool use + reasoning for agentic tasks
|
|
1611
|
+
fallback: ["xai/grok-4-fast-reasoning", "moonshot/kimi-k2.5", "deepseek/deepseek-reasoner"]
|
|
1627
1612
|
}
|
|
1628
1613
|
},
|
|
1629
1614
|
overrides: {
|
|
@@ -2339,6 +2324,8 @@ var DEFAULT_PORT = 8402;
|
|
|
2339
2324
|
var MAX_FALLBACK_ATTEMPTS = 3;
|
|
2340
2325
|
var HEALTH_CHECK_TIMEOUT_MS = 2e3;
|
|
2341
2326
|
var RATE_LIMIT_COOLDOWN_MS = 6e4;
|
|
2327
|
+
var PORT_RETRY_ATTEMPTS = 5;
|
|
2328
|
+
var PORT_RETRY_DELAY_MS = 1e3;
|
|
2342
2329
|
var rateLimitedModels = /* @__PURE__ */ new Map();
|
|
2343
2330
|
function isRateLimited(modelId) {
|
|
2344
2331
|
const hitTime = rateLimitedModels.get(modelId);
|
|
@@ -2628,7 +2615,7 @@ async function startProxy(options) {
|
|
|
2628
2615
|
if (existingWallet) {
|
|
2629
2616
|
const account2 = privateKeyToAccount2(options.walletKey);
|
|
2630
2617
|
const balanceMonitor2 = new BalanceMonitor(account2.address);
|
|
2631
|
-
const
|
|
2618
|
+
const baseUrl2 = `http://127.0.0.1:${listenPort}`;
|
|
2632
2619
|
if (existingWallet !== account2.address) {
|
|
2633
2620
|
console.warn(
|
|
2634
2621
|
`[ClawRouter] Existing proxy on port ${listenPort} uses wallet ${existingWallet}, but current config uses ${account2.address}. Reusing existing proxy.`
|
|
@@ -2637,7 +2624,7 @@ async function startProxy(options) {
|
|
|
2637
2624
|
options.onReady?.(listenPort);
|
|
2638
2625
|
return {
|
|
2639
2626
|
port: listenPort,
|
|
2640
|
-
baseUrl,
|
|
2627
|
+
baseUrl: baseUrl2,
|
|
2641
2628
|
walletAddress: existingWallet,
|
|
2642
2629
|
balanceMonitor: balanceMonitor2,
|
|
2643
2630
|
close: async () => {
|
|
@@ -2763,80 +2750,123 @@ async function startProxy(options) {
|
|
|
2763
2750
|
}
|
|
2764
2751
|
}
|
|
2765
2752
|
});
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
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}`;
|
|
2770
2795
|
options.onReady?.(listenPort);
|
|
2771
|
-
|
|
2796
|
+
return {
|
|
2772
2797
|
port: listenPort,
|
|
2773
|
-
baseUrl,
|
|
2774
|
-
walletAddress:
|
|
2798
|
+
baseUrl: baseUrl2,
|
|
2799
|
+
walletAddress: error.wallet,
|
|
2775
2800
|
balanceMonitor,
|
|
2776
2801
|
close: async () => {
|
|
2777
2802
|
}
|
|
2778
|
-
}
|
|
2779
|
-
return;
|
|
2803
|
+
};
|
|
2780
2804
|
}
|
|
2781
|
-
|
|
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();
|
|
2782
2836
|
});
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
options.onError?.(err);
|
|
2791
|
-
});
|
|
2792
|
-
server.on("clientError", (err, socket) => {
|
|
2793
|
-
console.error(`[ClawRouter] Client error: ${err.message}`);
|
|
2794
|
-
if (socket.writable && !socket.destroyed) {
|
|
2795
|
-
socket.end("HTTP/1.1 400 Bad Request\r\n\r\n");
|
|
2796
|
-
}
|
|
2797
|
-
});
|
|
2798
|
-
server.on("connection", (socket) => {
|
|
2799
|
-
connections.add(socket);
|
|
2800
|
-
socket.setTimeout(3e5);
|
|
2801
|
-
socket.on("timeout", () => {
|
|
2802
|
-
console.error(`[ClawRouter] Socket timeout, destroying connection`);
|
|
2803
|
-
socket.destroy();
|
|
2804
|
-
});
|
|
2805
|
-
socket.on("end", () => {
|
|
2806
|
-
});
|
|
2807
|
-
socket.on("error", (err) => {
|
|
2808
|
-
console.error(`[ClawRouter] Socket error: ${err.message}`);
|
|
2809
|
-
});
|
|
2810
|
-
socket.on("close", () => {
|
|
2811
|
-
connections.delete(socket);
|
|
2812
|
-
});
|
|
2813
|
-
});
|
|
2814
|
-
resolve({
|
|
2815
|
-
port,
|
|
2816
|
-
baseUrl,
|
|
2817
|
-
walletAddress: account.address,
|
|
2818
|
-
balanceMonitor,
|
|
2819
|
-
close: () => new Promise((res, rej) => {
|
|
2820
|
-
const timeout = setTimeout(() => {
|
|
2821
|
-
rej(new Error("[ClawRouter] Close timeout after 4s"));
|
|
2822
|
-
}, 4e3);
|
|
2823
|
-
sessionStore.close();
|
|
2824
|
-
for (const socket of connections) {
|
|
2825
|
-
socket.destroy();
|
|
2826
|
-
}
|
|
2827
|
-
connections.clear();
|
|
2828
|
-
server.close((err) => {
|
|
2829
|
-
clearTimeout(timeout);
|
|
2830
|
-
if (err) {
|
|
2831
|
-
rej(err);
|
|
2832
|
-
} else {
|
|
2833
|
-
res();
|
|
2834
|
-
}
|
|
2835
|
-
});
|
|
2836
|
-
})
|
|
2837
|
-
});
|
|
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);
|
|
2838
2844
|
});
|
|
2839
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
|
+
};
|
|
2840
2870
|
}
|
|
2841
2871
|
async function tryModelRequest(upstreamUrl, method, headers, body, modelId, maxTokens, payFetch, balanceMonitor, signal) {
|
|
2842
2872
|
let requestBody = body;
|
|
@@ -2958,17 +2988,10 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
2958
2988
|
const systemPrompt = typeof systemMsg?.content === "string" ? systemMsg.content : void 0;
|
|
2959
2989
|
const tools = parsed.tools;
|
|
2960
2990
|
const hasTools = Array.isArray(tools) && tools.length > 0;
|
|
2961
|
-
const effectiveRouterOpts = hasTools ? {
|
|
2962
|
-
...routerOpts,
|
|
2963
|
-
config: {
|
|
2964
|
-
...routerOpts.config,
|
|
2965
|
-
overrides: { ...routerOpts.config.overrides, agenticMode: true }
|
|
2966
|
-
}
|
|
2967
|
-
} : routerOpts;
|
|
2968
2991
|
if (hasTools) {
|
|
2969
|
-
console.log(`[ClawRouter] Tools detected (${tools.length}),
|
|
2992
|
+
console.log(`[ClawRouter] Tools detected (${tools.length}), agentic mode via keywords`);
|
|
2970
2993
|
}
|
|
2971
|
-
routingDecision = route(prompt, systemPrompt, maxTokens,
|
|
2994
|
+
routingDecision = route(prompt, systemPrompt, maxTokens, routerOpts);
|
|
2972
2995
|
parsed.model = routingDecision.model;
|
|
2973
2996
|
modelId = routingDecision.model;
|
|
2974
2997
|
bodyModified = true;
|