@blockrun/clawrouter 0.9.0 → 0.9.1
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 +14 -12
- package/dist/cli.js +62 -61
- package/dist/cli.js.map +1 -1
- package/dist/index.js +63 -67
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
82
|
-
|
|
83
|
-
| `/model auto`
|
|
84
|
-
| `/model eco`
|
|
85
|
-
| `/model premium` | Quality focused
|
|
86
|
-
| `/model free`
|
|
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
|
|
133
|
-
|
|
134
|
-
| **auto** (default) | Balanced quality + cost | 74-100%
|
|
135
|
-
| **eco**
|
|
136
|
-
| **premium**
|
|
137
|
-
| **free**
|
|
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
|
-
|
|
2301
|
+
$OC01: "unbrowse_",
|
|
2302
2302
|
// Common prefix in tool names
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
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
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2313
|
+
$SK01: "<available_skills>",
|
|
2314
|
+
$SK02: "</available_skills>",
|
|
2315
|
+
$SK03: "<skill>",
|
|
2316
|
+
$SK04: "</skill>",
|
|
2317
2317
|
// Schema patterns (very common in tool definitions)
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
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
|
-
|
|
2327
|
-
|
|
2326
|
+
$D01: "description:",
|
|
2327
|
+
$D02: '"description":',
|
|
2328
2328
|
// Common instructions
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
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
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2335
|
+
$S01: "Do not manipulate or persuade",
|
|
2336
|
+
$S02: "Prioritize safety and human oversight",
|
|
2337
|
+
$S03: "unless explicitly requested",
|
|
2338
2338
|
// JSON patterns
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2339
|
+
$J01: '"required": ["',
|
|
2340
|
+
$J02: '"properties": {',
|
|
2341
|
+
$J03: '"additionalProperties": false',
|
|
2342
2342
|
// Heartbeat patterns
|
|
2343
|
-
|
|
2344
|
-
|
|
2343
|
+
$H01: "HEARTBEAT_OK",
|
|
2344
|
+
$H02: "Read HEARTBEAT.md if it exists",
|
|
2345
2345
|
// Role markers
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2346
|
+
$R01: '"role": "system"',
|
|
2347
|
+
$R02: '"role": "user"',
|
|
2348
|
+
$R03: '"role": "assistant"',
|
|
2349
|
+
$R04: '"role": "tool"',
|
|
2350
2350
|
// Common endings/phrases
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
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
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
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(([
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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);
|