@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/index.js CHANGED
@@ -715,7 +715,7 @@ function scoreAgenticTask(text, keywords) {
715
715
  }
716
716
  }
717
717
  }
718
- if (matchCount >= 3) {
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 >= 2) {
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.3,
741
- signal: `agentic (${signals.join(", ")})`
740
+ score: 0.2,
741
+ signal: `agentic-light (${signals.join(", ")})`
742
742
  },
743
- agenticScore: 0.3
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
- "start",
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.1
1571
- // Significant weight for agentic detection
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.15,
1577
- complexReasoning: 0.25
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: "xai/grok-4-fast-reasoning",
1625
- // Cheap reasoning for agentic tasks
1626
- fallback: ["moonshot/kimi-k2.5", "anthropic/claude-sonnet-4", "deepseek/deepseek-reasoner"]
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 baseUrl = `http://127.0.0.1:${listenPort}`;
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
- return new Promise((resolve, reject) => {
2767
- server.on("error", (err) => {
2768
- if (err.code === "EADDRINUSE") {
2769
- const baseUrl = `http://127.0.0.1:${listenPort}`;
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
- resolve({
2796
+ return {
2772
2797
  port: listenPort,
2773
- baseUrl,
2774
- walletAddress: account.address,
2798
+ baseUrl: baseUrl2,
2799
+ walletAddress: error.wallet,
2775
2800
  balanceMonitor,
2776
2801
  close: async () => {
2777
2802
  }
2778
- });
2779
- return;
2803
+ };
2780
2804
  }
2781
- reject(err);
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
- server.listen(listenPort, "127.0.0.1", () => {
2784
- const addr = server.address();
2785
- const port = addr.port;
2786
- const baseUrl = `http://127.0.0.1:${port}`;
2787
- options.onReady?.(port);
2788
- server.on("error", (err) => {
2789
- console.error(`[ClawRouter] Server runtime error: ${err.message}`);
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}), forcing agentic mode`);
2992
+ console.log(`[ClawRouter] Tools detected (${tools.length}), agentic mode via keywords`);
2970
2993
  }
2971
- routingDecision = route(prompt, systemPrompt, maxTokens, effectiveRouterOpts);
2994
+ routingDecision = route(prompt, systemPrompt, maxTokens, routerOpts);
2972
2995
  parsed.model = routingDecision.model;
2973
2996
  modelId = routingDecision.model;
2974
2997
  bodyModified = true;