@blockrun/clawrouter 0.9.0 → 0.9.2

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 CHANGED
@@ -78,14 +78,15 @@ Done! Smart routing (`blockrun/auto`) is now your default model.
78
78
 
79
79
  Choose your routing strategy with `/model <profile>`:
80
80
 
81
- | Profile | Strategy | Savings | Use Case |
82
- |---------|----------|---------|----------|
83
- | `/model auto` | Balanced (default) | 74-100% | Best overall balance |
84
- | `/model eco` | Cost optimized | 95.9-100% | Maximum savings |
85
- | `/model premium` | Quality focused | 0% | Best quality (Opus 4.5) |
86
- | `/model free` | Free tier only | 100% | Zero cost |
81
+ | Profile | Strategy | Savings | Use Case |
82
+ | ---------------- | ------------------ | --------- | ----------------------- |
83
+ | `/model auto` | Balanced (default) | 74-100% | Best overall balance |
84
+ | `/model eco` | Cost optimized | 95.9-100% | Maximum savings |
85
+ | `/model premium` | Quality focused | 0% | Best quality (Opus 4.5) |
86
+ | `/model free` | Free tier only | 100% | Zero cost |
87
87
 
88
88
  **Other shortcuts:**
89
+
89
90
  - **Model aliases:** `/model sonnet`, `/model grok`, `/model gpt5`, `/model o3`
90
91
  - **Specific models:** `blockrun/openai/gpt-4o` or `blockrun/anthropic/claude-sonnet-4`
91
92
  - **Bring your wallet:** `export BLOCKRUN_WALLET_KEY=0x...`
@@ -129,16 +130,17 @@ No external classifier calls. Ambiguous queries default to the MEDIUM tier (Grok
129
130
 
130
131
  ClawRouter now offers 4 routing profiles to match different priorities:
131
132
 
132
- | Profile | Strategy | Savings vs Opus 4.5 | When to Use |
133
- |---------|----------|---------------------|-------------|
134
- | **auto** (default) | Balanced quality + cost | 74-100% | General use, best overall |
135
- | **eco** | Maximum cost savings | 95.9-100% | Budget-conscious, high volume |
136
- | **premium** | Best quality only | 0% | Mission-critical tasks |
137
- | **free** | Free tier only | 100% | Testing, empty wallet |
133
+ | Profile | Strategy | Savings vs Opus 4.5 | When to Use |
134
+ | ------------------ | ----------------------- | ------------------- | ----------------------------- |
135
+ | **auto** (default) | Balanced quality + cost | 74-100% | General use, best overall |
136
+ | **eco** | Maximum cost savings | 95.9-100% | Budget-conscious, high volume |
137
+ | **premium** | Best quality only | 0% | Mission-critical tasks |
138
+ | **free** | Free tier only | 100% | Testing, empty wallet |
138
139
 
139
140
  Switch profiles anytime: `/model eco`, `/model premium`, `/model auto`
140
141
 
141
142
  **Example:**
143
+
142
144
  ```
143
145
  /model eco # Switch to cost-optimized routing
144
146
  "Write a React component" # Routes to DeepSeek ($0.28/$0.42)
package/dist/cli.js CHANGED
@@ -2298,66 +2298,66 @@ function normalizeMessagesWhitespace(messages) {
2298
2298
  // src/compression/codebook.ts
2299
2299
  var STATIC_CODEBOOK = {
2300
2300
  // High-impact: OpenClaw/Agent system prompt patterns (very common)
2301
- "$OC01": "unbrowse_",
2301
+ $OC01: "unbrowse_",
2302
2302
  // Common prefix in tool names
2303
- "$OC02": "<location>",
2304
- "$OC03": "</location>",
2305
- "$OC04": "<name>",
2306
- "$OC05": "</name>",
2307
- "$OC06": "<description>",
2308
- "$OC07": "</description>",
2309
- "$OC08": "(may need login)",
2310
- "$OC09": "API skill for OpenClaw",
2311
- "$OC10": "endpoints",
2303
+ $OC02: "<location>",
2304
+ $OC03: "</location>",
2305
+ $OC04: "<name>",
2306
+ $OC05: "</name>",
2307
+ $OC06: "<description>",
2308
+ $OC07: "</description>",
2309
+ $OC08: "(may need login)",
2310
+ $OC09: "API skill for OpenClaw",
2311
+ $OC10: "endpoints",
2312
2312
  // Skill/tool markers
2313
- "$SK01": "<available_skills>",
2314
- "$SK02": "</available_skills>",
2315
- "$SK03": "<skill>",
2316
- "$SK04": "</skill>",
2313
+ $SK01: "<available_skills>",
2314
+ $SK02: "</available_skills>",
2315
+ $SK03: "<skill>",
2316
+ $SK04: "</skill>",
2317
2317
  // Schema patterns (very common in tool definitions)
2318
- "$T01": 'type: "function"',
2319
- "$T02": '"type": "function"',
2320
- "$T03": '"type": "string"',
2321
- "$T04": '"type": "object"',
2322
- "$T05": '"type": "array"',
2323
- "$T06": '"type": "boolean"',
2324
- "$T07": '"type": "number"',
2318
+ $T01: 'type: "function"',
2319
+ $T02: '"type": "function"',
2320
+ $T03: '"type": "string"',
2321
+ $T04: '"type": "object"',
2322
+ $T05: '"type": "array"',
2323
+ $T06: '"type": "boolean"',
2324
+ $T07: '"type": "number"',
2325
2325
  // Common descriptions
2326
- "$D01": "description:",
2327
- "$D02": '"description":',
2326
+ $D01: "description:",
2327
+ $D02: '"description":',
2328
2328
  // Common instructions
2329
- "$I01": "You are a personal assistant",
2330
- "$I02": "Tool names are case-sensitive",
2331
- "$I03": "Call tools exactly as listed",
2332
- "$I04": "Use when",
2333
- "$I05": "without asking",
2329
+ $I01: "You are a personal assistant",
2330
+ $I02: "Tool names are case-sensitive",
2331
+ $I03: "Call tools exactly as listed",
2332
+ $I04: "Use when",
2333
+ $I05: "without asking",
2334
2334
  // Safety phrases
2335
- "$S01": "Do not manipulate or persuade",
2336
- "$S02": "Prioritize safety and human oversight",
2337
- "$S03": "unless explicitly requested",
2335
+ $S01: "Do not manipulate or persuade",
2336
+ $S02: "Prioritize safety and human oversight",
2337
+ $S03: "unless explicitly requested",
2338
2338
  // JSON patterns
2339
- "$J01": '"required": ["',
2340
- "$J02": '"properties": {',
2341
- "$J03": '"additionalProperties": false',
2339
+ $J01: '"required": ["',
2340
+ $J02: '"properties": {',
2341
+ $J03: '"additionalProperties": false',
2342
2342
  // Heartbeat patterns
2343
- "$H01": "HEARTBEAT_OK",
2344
- "$H02": "Read HEARTBEAT.md if it exists",
2343
+ $H01: "HEARTBEAT_OK",
2344
+ $H02: "Read HEARTBEAT.md if it exists",
2345
2345
  // Role markers
2346
- "$R01": '"role": "system"',
2347
- "$R02": '"role": "user"',
2348
- "$R03": '"role": "assistant"',
2349
- "$R04": '"role": "tool"',
2346
+ $R01: '"role": "system"',
2347
+ $R02: '"role": "user"',
2348
+ $R03: '"role": "assistant"',
2349
+ $R04: '"role": "tool"',
2350
2350
  // Common endings/phrases
2351
- "$E01": "would you like to",
2352
- "$E02": "Let me know if you",
2353
- "$E03": "internal APIs",
2354
- "$E04": "session cookies",
2351
+ $E01: "would you like to",
2352
+ $E02: "Let me know if you",
2353
+ $E03: "internal APIs",
2354
+ $E04: "session cookies",
2355
2355
  // BlockRun model aliases (common in prompts)
2356
- "$M01": "blockrun/",
2357
- "$M02": "openai/",
2358
- "$M03": "anthropic/",
2359
- "$M04": "google/",
2360
- "$M05": "xai/"
2356
+ $M01: "blockrun/",
2357
+ $M02: "openai/",
2358
+ $M03: "anthropic/",
2359
+ $M04: "google/",
2360
+ $M05: "xai/"
2361
2361
  };
2362
2362
  function getInverseCodebook() {
2363
2363
  const inverse = {};
@@ -2454,7 +2454,7 @@ function findFrequentPrefixes(paths) {
2454
2454
  prefixCounts.set(prefix, (prefixCounts.get(prefix) || 0) + 1);
2455
2455
  }
2456
2456
  }
2457
- return Array.from(prefixCounts.entries()).filter(([_, count]) => count >= 3).sort((a, b) => b[0].length - a[0].length).slice(0, 5).map(([prefix]) => prefix);
2457
+ return Array.from(prefixCounts.entries()).filter(([, count]) => count >= 3).sort((a, b) => b[0].length - a[0].length).slice(0, 5).map(([prefix]) => prefix);
2458
2458
  }
2459
2459
  function shortenPaths(messages) {
2460
2460
  const allPaths = extractPaths(messages);
@@ -2523,7 +2523,7 @@ function compactToolCalls(toolCalls) {
2523
2523
  function compactMessagesJson(messages) {
2524
2524
  let charsSaved = 0;
2525
2525
  const result = messages.map((message) => {
2526
- let newMessage = { ...message };
2526
+ const newMessage = { ...message };
2527
2527
  if (message.tool_calls && message.tool_calls.length > 0) {
2528
2528
  const originalLength = JSON.stringify(message.tool_calls).length;
2529
2529
  newMessage.tool_calls = compactToolCalls(message.tool_calls);
@@ -2709,9 +2709,7 @@ function applyDynamicCodebook(messages) {
2709
2709
  for (const [code, phrase] of Object.entries(codebook)) {
2710
2710
  phraseToCode[phrase] = code;
2711
2711
  }
2712
- const sortedPhrases = Object.keys(phraseToCode).sort(
2713
- (a, b) => b.length - a.length
2714
- );
2712
+ const sortedPhrases = Object.keys(phraseToCode).sort((a, b) => b.length - a.length);
2715
2713
  let charsSaved = 0;
2716
2714
  let substitutions = 0;
2717
2715
  const result = messages.map((msg) => {
@@ -2763,10 +2761,7 @@ function prependCodebookHeader(messages, usedCodes, pathMap) {
2763
2761
  if (!header) return messages;
2764
2762
  const userIndex = messages.findIndex((m) => m.role === "user");
2765
2763
  if (userIndex === -1) {
2766
- return [
2767
- { role: "system", content: header },
2768
- ...messages
2769
- ];
2764
+ return [{ role: "system", content: header }, ...messages];
2770
2765
  }
2771
2766
  return messages.map((msg, i) => {
2772
2767
  if (i === userIndex) {
@@ -3857,7 +3852,9 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
3857
3852
  const tools = parsed.tools;
3858
3853
  const hasTools = Array.isArray(tools) && tools.length > 0;
3859
3854
  if (hasTools) {
3860
- console.log(`[ClawRouter] Tools detected (${tools.length}), agentic mode via keywords`);
3855
+ console.log(
3856
+ `[ClawRouter] Tools detected (${tools.length}), agentic mode via keywords`
3857
+ );
3861
3858
  }
3862
3859
  routingDecision = route(prompt, systemPrompt, maxTokens, {
3863
3860
  ...routerOpts,
@@ -3891,7 +3888,9 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
3891
3888
  const requestSizeKB = Math.ceil(body.length / 1024);
3892
3889
  if (autoCompress && requestSizeKB > compressionThreshold) {
3893
3890
  try {
3894
- console.log(`[ClawRouter] Request size ${requestSizeKB}KB exceeds threshold ${compressionThreshold}KB, applying compression...`);
3891
+ console.log(
3892
+ `[ClawRouter] Request size ${requestSizeKB}KB exceeds threshold ${compressionThreshold}KB, applying compression...`
3893
+ );
3895
3894
  const parsed = JSON.parse(body.toString());
3896
3895
  if (parsed.messages && parsed.messages.length > 0 && shouldCompress(parsed.messages)) {
3897
3896
  const compressionResult = await compressContext(parsed.messages, {
@@ -3944,7 +3943,9 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
3944
3943
  }
3945
3944
  }
3946
3945
  } catch (err) {
3947
- console.warn(`[ClawRouter] Compression failed: ${err instanceof Error ? err.message : String(err)}`);
3946
+ console.warn(
3947
+ `[ClawRouter] Compression failed: ${err instanceof Error ? err.message : String(err)}`
3948
+ );
3948
3949
  }
3949
3950
  }
3950
3951
  const finalSizeKB = Math.ceil(body.length / 1024);