@blockrun/clawrouter 0.9.2 โ 0.9.4
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 +28 -17
- package/dist/cli.js +25 -49
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +4 -8
- package/dist/index.js +25 -49
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ One wallet, 30+ models, zero API keys.
|
|
|
11
11
|
[](https://nodejs.org)
|
|
12
12
|
[](https://x.com/USDC/status/2021625822294216977)
|
|
13
13
|
|
|
14
|
-
[Docs](https://blockrun.ai/docs) · [Models](https://blockrun.ai/models) · [
|
|
14
|
+
[Docs](https://blockrun.ai/docs) · [Models](https://blockrun.ai/models) · [vs OpenRouter](docs/vs-openrouter.md) · [Configuration](docs/configuration.md) · [Features](docs/features.md) · [Troubleshooting](docs/troubleshooting.md) · [Telegram](https://t.me/blockrunAI) · [X](https://x.com/BlockRunAI)
|
|
15
15
|
|
|
16
16
|
**Winner โ Agentic Commerce Track** at the [USDC AI Agent Hackathon](https://x.com/USDC/status/2021625822294216977)<br>
|
|
17
17
|
_The world's first hackathon run entirely by AI agents, powered by USDC_
|
|
@@ -58,22 +58,6 @@ openclaw gateway restart
|
|
|
58
58
|
|
|
59
59
|
Done! Smart routing (`blockrun/auto`) is now your default model.
|
|
60
60
|
|
|
61
|
-
### Windows Installation
|
|
62
|
-
|
|
63
|
-
โ ๏ธ **Current Status:** Windows installation is temporarily unavailable due to an OpenClaw CLI bug. The issue is with the OpenClaw framework, not ClawRouter itself.
|
|
64
|
-
|
|
65
|
-
**๐ Full Windows Guide:** [docs/windows-installation.md](docs/windows-installation.md)
|
|
66
|
-
|
|
67
|
-
**Quick Summary:**
|
|
68
|
-
|
|
69
|
-
- โ
ClawRouter code is Windows-compatible
|
|
70
|
-
- โ OpenClaw CLI has a `spawn EINVAL` bug on Windows
|
|
71
|
-
- โ
Works perfectly on **Linux** and **macOS**
|
|
72
|
-
- ๐ง Manual installation workaround available for advanced users
|
|
73
|
-
- ๐งช Full Windows test infrastructure ready ([.github/workflows/test-windows.yml](.github/workflows/test-windows.yml))
|
|
74
|
-
|
|
75
|
-
**For advanced users:** See the [complete manual installation guide](docs/windows-installation.md) with step-by-step PowerShell instructions.
|
|
76
|
-
|
|
77
61
|
### Routing Profiles
|
|
78
62
|
|
|
79
63
|
Choose your routing strategy with `/model <profile>`:
|
|
@@ -357,9 +341,25 @@ They're built for developers. ClawRouter is built for **agents**.
|
|
|
357
341
|
| **Auth** | API key (shared secret) | Wallet signature (cryptographic) |
|
|
358
342
|
| **Payment** | Prepaid balance (custodial) | Per-request (non-custodial) |
|
|
359
343
|
| **Routing** | Proprietary / closed | Open source, client-side |
|
|
344
|
+
| **Rate limits** | Per-key quotas | None (your wallet, your limits) |
|
|
345
|
+
| **Cost** | $25/M (Opus equivalent) | $2.05/M blended average |
|
|
360
346
|
|
|
361
347
|
Agents shouldn't need a human to paste API keys. They should generate a wallet, receive funds, and pay per request โ programmatically.
|
|
362
348
|
|
|
349
|
+
### Real Problems with OpenRouter
|
|
350
|
+
|
|
351
|
+
Based on [50+ OpenClaw issues](https://github.com/openclaw/openclaw/issues?q=openrouter):
|
|
352
|
+
|
|
353
|
+
| Issue | Problem | ClawRouter |
|
|
354
|
+
|-------|---------|------------|
|
|
355
|
+
| [#11202](https://github.com/openclaw/openclaw/issues/11202) | API keys leaked in every LLM prompt | No API keys to leak |
|
|
356
|
+
| [#2373](https://github.com/openclaw/openclaw/issues/2373) | `openrouter/auto` path broken | `blockrun/auto` just works |
|
|
357
|
+
| [#8615](https://github.com/openclaw/openclaw/issues/8615) | Single API key rate limit hell | Non-custodial, no limits |
|
|
358
|
+
| [#2963](https://github.com/openclaw/openclaw/issues/2963) | Tool calling fails silently | Full tool support |
|
|
359
|
+
| [#10687](https://github.com/openclaw/openclaw/issues/10687) | "Unknown model" errors | 30+ models, auto-update |
|
|
360
|
+
|
|
361
|
+
**[Full comparison โ](docs/vs-openrouter.md)**
|
|
362
|
+
|
|
363
363
|
---
|
|
364
364
|
|
|
365
365
|
## Troubleshooting
|
|
@@ -399,6 +399,17 @@ BLOCKRUN_WALLET_KEY=0x... npx tsx test-e2e.ts
|
|
|
399
399
|
|
|
400
400
|
---
|
|
401
401
|
|
|
402
|
+
## Uninstall
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
openclaw plugins uninstall clawrouter
|
|
406
|
+
openclaw gateway restart
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Your wallet key remains at `~/.openclaw/blockrun/wallet.key` โ back it up before deleting if you have funds.
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
402
413
|
## Roadmap
|
|
403
414
|
|
|
404
415
|
- [x] Smart routing โ 15-dimension weighted scoring, 4-tier model selection
|
package/dist/cli.js
CHANGED
|
@@ -1989,26 +1989,14 @@ var RequestDeduplicator = class {
|
|
|
1989
1989
|
getInflight(key) {
|
|
1990
1990
|
const entry = this.inflight.get(key);
|
|
1991
1991
|
if (!entry) return void 0;
|
|
1992
|
-
|
|
1993
|
-
entry.
|
|
1994
|
-
new Promise((r) => {
|
|
1995
|
-
const orig = entry.resolve;
|
|
1996
|
-
entry.resolve = (result) => {
|
|
1997
|
-
orig(result);
|
|
1998
|
-
resolve(result);
|
|
1999
|
-
r(result);
|
|
2000
|
-
};
|
|
2001
|
-
})
|
|
2002
|
-
);
|
|
1992
|
+
return new Promise((resolve) => {
|
|
1993
|
+
entry.resolvers.push(resolve);
|
|
2003
1994
|
});
|
|
2004
|
-
return promise;
|
|
2005
1995
|
}
|
|
2006
1996
|
/** Mark a request as in-flight. */
|
|
2007
1997
|
markInflight(key) {
|
|
2008
1998
|
this.inflight.set(key, {
|
|
2009
|
-
|
|
2010
|
-
},
|
|
2011
|
-
waiters: []
|
|
1999
|
+
resolvers: []
|
|
2012
2000
|
});
|
|
2013
2001
|
}
|
|
2014
2002
|
/** Complete an in-flight request โ cache result and notify waiters. */
|
|
@@ -2018,14 +2006,31 @@ var RequestDeduplicator = class {
|
|
|
2018
2006
|
}
|
|
2019
2007
|
const entry = this.inflight.get(key);
|
|
2020
2008
|
if (entry) {
|
|
2021
|
-
entry.
|
|
2009
|
+
for (const resolve of entry.resolvers) {
|
|
2010
|
+
resolve(result);
|
|
2011
|
+
}
|
|
2022
2012
|
this.inflight.delete(key);
|
|
2023
2013
|
}
|
|
2024
2014
|
this.prune();
|
|
2025
2015
|
}
|
|
2026
|
-
/** Remove an in-flight entry on error (don't cache failures).
|
|
2016
|
+
/** Remove an in-flight entry on error (don't cache failures).
|
|
2017
|
+
* Also rejects any waiters so they can retry independently. */
|
|
2027
2018
|
removeInflight(key) {
|
|
2028
|
-
this.inflight.
|
|
2019
|
+
const entry = this.inflight.get(key);
|
|
2020
|
+
if (entry) {
|
|
2021
|
+
const errorBody = Buffer.from(JSON.stringify({
|
|
2022
|
+
error: { message: "Original request failed, please retry", type: "dedup_origin_failed" }
|
|
2023
|
+
}));
|
|
2024
|
+
for (const resolve of entry.resolvers) {
|
|
2025
|
+
resolve({
|
|
2026
|
+
status: 503,
|
|
2027
|
+
headers: { "content-type": "application/json" },
|
|
2028
|
+
body: errorBody,
|
|
2029
|
+
completedAt: Date.now()
|
|
2030
|
+
});
|
|
2031
|
+
}
|
|
2032
|
+
this.inflight.delete(key);
|
|
2033
|
+
}
|
|
2029
2034
|
}
|
|
2030
2035
|
/** Prune expired completed entries. */
|
|
2031
2036
|
prune() {
|
|
@@ -3251,6 +3256,8 @@ var FALLBACK_STATUS_CODES = [
|
|
|
3251
3256
|
// Payment required - but from upstream, not x402
|
|
3252
3257
|
403,
|
|
3253
3258
|
// Forbidden - provider restrictions
|
|
3259
|
+
413,
|
|
3260
|
+
// Payload too large - request exceeds model's context limit
|
|
3254
3261
|
429,
|
|
3255
3262
|
// Rate limited
|
|
3256
3263
|
500,
|
|
@@ -3884,7 +3891,6 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
3884
3891
|
}
|
|
3885
3892
|
const autoCompress = options.autoCompressRequests ?? true;
|
|
3886
3893
|
const compressionThreshold = options.compressionThresholdKB ?? 180;
|
|
3887
|
-
const sizeLimit = options.maxRequestSizeKB ?? 200;
|
|
3888
3894
|
const requestSizeKB = Math.ceil(body.length / 1024);
|
|
3889
3895
|
if (autoCompress && requestSizeKB > compressionThreshold) {
|
|
3890
3896
|
try {
|
|
@@ -3926,21 +3932,6 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
3926
3932
|
);
|
|
3927
3933
|
parsed.messages = compressionResult.messages;
|
|
3928
3934
|
body = Buffer.from(JSON.stringify(parsed));
|
|
3929
|
-
if (compressedSizeKB > sizeLimit) {
|
|
3930
|
-
const errorMsg = {
|
|
3931
|
-
error: {
|
|
3932
|
-
message: `Request size ${compressedSizeKB}KB still exceeds limit after compression (original: ${requestSizeKB}KB). Please reduce context size.`,
|
|
3933
|
-
type: "request_too_large",
|
|
3934
|
-
original_size_kb: requestSizeKB,
|
|
3935
|
-
compressed_size_kb: compressedSizeKB,
|
|
3936
|
-
limit_kb: sizeLimit,
|
|
3937
|
-
help: "Try: 1) Remove old messages from history, 2) Summarize large tool results, 3) Use direct API for very large contexts"
|
|
3938
|
-
}
|
|
3939
|
-
};
|
|
3940
|
-
res.writeHead(413, { "Content-Type": "application/json" });
|
|
3941
|
-
res.end(JSON.stringify(errorMsg));
|
|
3942
|
-
return;
|
|
3943
|
-
}
|
|
3944
3935
|
}
|
|
3945
3936
|
} catch (err) {
|
|
3946
3937
|
console.warn(
|
|
@@ -3948,21 +3939,6 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
3948
3939
|
);
|
|
3949
3940
|
}
|
|
3950
3941
|
}
|
|
3951
|
-
const finalSizeKB = Math.ceil(body.length / 1024);
|
|
3952
|
-
if (finalSizeKB > sizeLimit) {
|
|
3953
|
-
const errorMsg = {
|
|
3954
|
-
error: {
|
|
3955
|
-
message: `Request size ${finalSizeKB}KB exceeds limit ${sizeLimit}KB. Please reduce context size.`,
|
|
3956
|
-
type: "request_too_large",
|
|
3957
|
-
size_kb: finalSizeKB,
|
|
3958
|
-
limit_kb: sizeLimit,
|
|
3959
|
-
help: "Try: 1) Remove old messages from history, 2) Summarize large tool results, 3) Enable compression (autoCompressRequests: true)"
|
|
3960
|
-
}
|
|
3961
|
-
};
|
|
3962
|
-
res.writeHead(413, { "Content-Type": "application/json" });
|
|
3963
|
-
res.end(JSON.stringify(errorMsg));
|
|
3964
|
-
return;
|
|
3965
|
-
}
|
|
3966
3942
|
const dedupKey = RequestDeduplicator.hash(body);
|
|
3967
3943
|
const cached = deduplicator.getCached(dedupKey);
|
|
3968
3944
|
if (cached) {
|