@blockrun/clawrouter 0.6.7 → 0.6.9

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: {
@@ -2457,6 +2442,78 @@ var ROLE_MAPPINGS = {
2457
2442
  model: "assistant"
2458
2443
  // Some APIs use "model" instead of "assistant"
2459
2444
  };
2445
+ var VALID_TOOL_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
2446
+ function sanitizeToolId(id) {
2447
+ if (!id || typeof id !== "string") return id;
2448
+ if (VALID_TOOL_ID_PATTERN.test(id)) return id;
2449
+ return id.replace(/[^a-zA-Z0-9_-]/g, "_");
2450
+ }
2451
+ function sanitizeToolIds(messages) {
2452
+ if (!messages || messages.length === 0) return messages;
2453
+ let hasChanges = false;
2454
+ const sanitized = messages.map((msg) => {
2455
+ const typedMsg = msg;
2456
+ let msgChanged = false;
2457
+ let newMsg = { ...msg };
2458
+ if (typedMsg.tool_calls && Array.isArray(typedMsg.tool_calls)) {
2459
+ const newToolCalls = typedMsg.tool_calls.map((tc) => {
2460
+ if (tc.id && typeof tc.id === "string") {
2461
+ const sanitized2 = sanitizeToolId(tc.id);
2462
+ if (sanitized2 !== tc.id) {
2463
+ msgChanged = true;
2464
+ return { ...tc, id: sanitized2 };
2465
+ }
2466
+ }
2467
+ return tc;
2468
+ });
2469
+ if (msgChanged) {
2470
+ newMsg = { ...newMsg, tool_calls: newToolCalls };
2471
+ }
2472
+ }
2473
+ if (typedMsg.tool_call_id && typeof typedMsg.tool_call_id === "string") {
2474
+ const sanitized2 = sanitizeToolId(typedMsg.tool_call_id);
2475
+ if (sanitized2 !== typedMsg.tool_call_id) {
2476
+ msgChanged = true;
2477
+ newMsg = { ...newMsg, tool_call_id: sanitized2 };
2478
+ }
2479
+ }
2480
+ if (Array.isArray(typedMsg.content)) {
2481
+ const newContent = typedMsg.content.map((block) => {
2482
+ if (!block || typeof block !== "object") return block;
2483
+ let blockChanged = false;
2484
+ let newBlock = { ...block };
2485
+ if (block.type === "tool_use" && block.id && typeof block.id === "string") {
2486
+ const sanitized2 = sanitizeToolId(block.id);
2487
+ if (sanitized2 !== block.id) {
2488
+ blockChanged = true;
2489
+ newBlock = { ...newBlock, id: sanitized2 };
2490
+ }
2491
+ }
2492
+ if (block.type === "tool_result" && block.tool_use_id && typeof block.tool_use_id === "string") {
2493
+ const sanitized2 = sanitizeToolId(block.tool_use_id);
2494
+ if (sanitized2 !== block.tool_use_id) {
2495
+ blockChanged = true;
2496
+ newBlock = { ...newBlock, tool_use_id: sanitized2 };
2497
+ }
2498
+ }
2499
+ if (blockChanged) {
2500
+ msgChanged = true;
2501
+ return newBlock;
2502
+ }
2503
+ return block;
2504
+ });
2505
+ if (msgChanged) {
2506
+ newMsg = { ...newMsg, content: newContent };
2507
+ }
2508
+ }
2509
+ if (msgChanged) {
2510
+ hasChanges = true;
2511
+ return newMsg;
2512
+ }
2513
+ return msg;
2514
+ });
2515
+ return hasChanges ? sanitized : messages;
2516
+ }
2460
2517
  function normalizeMessageRoles(messages) {
2461
2518
  if (!messages || messages.length === 0) return messages;
2462
2519
  let hasChanges = false;
@@ -2774,6 +2831,9 @@ async function tryModelRequest(upstreamUrl, method, headers, body, modelId, maxT
2774
2831
  if (Array.isArray(parsed.messages)) {
2775
2832
  parsed.messages = normalizeMessageRoles(parsed.messages);
2776
2833
  }
2834
+ if (Array.isArray(parsed.messages)) {
2835
+ parsed.messages = sanitizeToolIds(parsed.messages);
2836
+ }
2777
2837
  if (isGoogleModel(modelId) && Array.isArray(parsed.messages)) {
2778
2838
  parsed.messages = normalizeMessagesForGoogle(parsed.messages);
2779
2839
  }
@@ -2883,17 +2943,10 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
2883
2943
  const systemPrompt = typeof systemMsg?.content === "string" ? systemMsg.content : void 0;
2884
2944
  const tools = parsed.tools;
2885
2945
  const hasTools = Array.isArray(tools) && tools.length > 0;
2886
- const effectiveRouterOpts = hasTools ? {
2887
- ...routerOpts,
2888
- config: {
2889
- ...routerOpts.config,
2890
- overrides: { ...routerOpts.config.overrides, agenticMode: true }
2891
- }
2892
- } : routerOpts;
2893
2946
  if (hasTools) {
2894
- console.log(`[ClawRouter] Tools detected (${tools.length}), forcing agentic mode`);
2947
+ console.log(`[ClawRouter] Tools detected (${tools.length}), agentic mode via keywords`);
2895
2948
  }
2896
- routingDecision = route(prompt, systemPrompt, maxTokens, effectiveRouterOpts);
2949
+ routingDecision = route(prompt, systemPrompt, maxTokens, routerOpts);
2897
2950
  parsed.model = routingDecision.model;
2898
2951
  modelId = routingDecision.model;
2899
2952
  bodyModified = true;