@blockrun/clawrouter 0.3.9 → 0.3.11
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 +100 -61
- package/dist/index.js +147 -115
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -215,6 +215,50 @@ USDC stays in your wallet until spent — non-custodial. Price is visible in the
|
|
|
215
215
|
|
|
216
216
|
---
|
|
217
217
|
|
|
218
|
+
## Wallet Configuration
|
|
219
|
+
|
|
220
|
+
ClawRouter uses one environment variable: `BLOCKRUN_WALLET_KEY`
|
|
221
|
+
|
|
222
|
+
### Resolution Order
|
|
223
|
+
|
|
224
|
+
| Priority | Source | Behavior |
|
|
225
|
+
| -------- | ---------------------------------------------- | --------------------------------- |
|
|
226
|
+
| 1st | Saved file (`~/.openclaw/blockrun/wallet.key`) | Used if exists |
|
|
227
|
+
| 2nd | `BLOCKRUN_WALLET_KEY` env var | Used if no saved file |
|
|
228
|
+
| 3rd | Auto-generate | Creates new wallet, saves to file |
|
|
229
|
+
|
|
230
|
+
**Important:** The saved file takes priority over the environment variable. If you have both, the env var is ignored.
|
|
231
|
+
|
|
232
|
+
### Common Scenarios
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
# Check if a saved wallet exists
|
|
236
|
+
ls -la ~/.openclaw/blockrun/wallet.key
|
|
237
|
+
|
|
238
|
+
# Use your own wallet (only works if no saved file exists)
|
|
239
|
+
export BLOCKRUN_WALLET_KEY=0x...
|
|
240
|
+
|
|
241
|
+
# Force use of a different wallet
|
|
242
|
+
rm ~/.openclaw/blockrun/wallet.key
|
|
243
|
+
export BLOCKRUN_WALLET_KEY=0x...
|
|
244
|
+
openclaw restart
|
|
245
|
+
|
|
246
|
+
# See which wallet is active
|
|
247
|
+
curl http://localhost:8402/health | jq .wallet
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Why This Order?
|
|
251
|
+
|
|
252
|
+
The saved file is checked first to ensure wallet persistence across sessions. Once a wallet is generated and funded, you don't want an accidentally-set env var to switch wallets and leave your funds inaccessible.
|
|
253
|
+
|
|
254
|
+
If you explicitly want to use a different wallet:
|
|
255
|
+
|
|
256
|
+
1. Delete `~/.openclaw/blockrun/wallet.key`
|
|
257
|
+
2. Set `BLOCKRUN_WALLET_KEY=0x...`
|
|
258
|
+
3. Restart OpenClaw
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
218
262
|
## Architecture
|
|
219
263
|
|
|
220
264
|
```
|
|
@@ -371,107 +415,102 @@ Agents shouldn't need a human to paste API keys. They should generate a wallet,
|
|
|
371
415
|
|
|
372
416
|
## Troubleshooting
|
|
373
417
|
|
|
374
|
-
|
|
418
|
+
> 💬 **Need help?** [Open a Discussion](https://github.com/BlockRunAI/ClawRouter/discussions) or check [existing issues](https://github.com/BlockRunAI/ClawRouter/issues).
|
|
375
419
|
|
|
376
|
-
|
|
420
|
+
### Quick Checklist
|
|
377
421
|
|
|
378
|
-
|
|
422
|
+
```bash
|
|
423
|
+
# 1. Check your version (should be 0.3.10+)
|
|
424
|
+
cat ~/.openclaw/extensions/clawrouter/package.json | grep version
|
|
379
425
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
3. **Race condition** — the first request fired before the plugin finished loading (wait 2-3 seconds after restart)
|
|
426
|
+
# 2. Check proxy is running
|
|
427
|
+
curl http://localhost:8402/health
|
|
383
428
|
|
|
384
|
-
|
|
429
|
+
# 3. Watch routing in action
|
|
430
|
+
openclaw logs --follow
|
|
431
|
+
# Should see: gemini-2.5-flash $0.0012 (saved 99%)
|
|
432
|
+
```
|
|
385
433
|
|
|
386
|
-
|
|
387
|
-
# 1. Verify plugin is installed
|
|
388
|
-
openclaw plugins list
|
|
389
|
-
# Should show @blockrun/clawrouter
|
|
434
|
+
### "Unknown model: blockrun/auto"
|
|
390
435
|
|
|
391
|
-
|
|
392
|
-
openclaw plugins install @blockrun/clawrouter
|
|
436
|
+
Plugin isn't loaded or outdated. **Don't change the model name** — `blockrun/auto` is correct.
|
|
393
437
|
|
|
394
|
-
|
|
395
|
-
openclaw restart
|
|
396
|
-
# Wait for log: "BlockRun provider active — http://127.0.0.1:8402/v1"
|
|
438
|
+
**Fix:**
|
|
397
439
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
440
|
+
```bash
|
|
441
|
+
rm -rf ~/.openclaw/extensions/clawrouter
|
|
442
|
+
openclaw plugins install @blockrun/clawrouter
|
|
443
|
+
# Restart OpenClaw
|
|
401
444
|
```
|
|
402
445
|
|
|
403
|
-
###
|
|
446
|
+
### "No API key found for provider blockrun"
|
|
404
447
|
|
|
405
|
-
|
|
448
|
+
Version < 0.3.10 doesn't inject auth profiles for the agent system.
|
|
449
|
+
|
|
450
|
+
**Fix:**
|
|
406
451
|
|
|
407
452
|
```bash
|
|
453
|
+
rm -rf ~/.openclaw/extensions/clawrouter
|
|
408
454
|
openclaw plugins install @blockrun/clawrouter
|
|
409
|
-
|
|
455
|
+
# Restart OpenClaw
|
|
410
456
|
```
|
|
411
457
|
|
|
412
|
-
|
|
458
|
+
After update, logs should show: `Injected BlockRun auth profile for agent: main`
|
|
413
459
|
|
|
414
|
-
|
|
415
|
-
npm view @blockrun/clawrouter version # Latest on npm
|
|
416
|
-
cat ~/.openclaw/plugins/node_modules/@blockrun/clawrouter/package.json | grep version
|
|
417
|
-
```
|
|
460
|
+
### "Config validation failed: plugin not found: clawrouter"
|
|
418
461
|
|
|
419
|
-
|
|
462
|
+
Plugin directory was removed but config still references it.
|
|
420
463
|
|
|
421
|
-
|
|
422
|
-
# Option 1: Health endpoint
|
|
423
|
-
curl http://localhost:8402/health
|
|
424
|
-
# Returns {"status":"ok","wallet":"0x..."}
|
|
464
|
+
**Fix:**
|
|
425
465
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
#
|
|
466
|
+
```bash
|
|
467
|
+
# Edit ~/.openclaw/openclaw.json and remove "clawrouter" from:
|
|
468
|
+
# - plugins.entries
|
|
469
|
+
# - plugins.installs
|
|
470
|
+
# Then reinstall:
|
|
471
|
+
openclaw plugins install @blockrun/clawrouter
|
|
429
472
|
```
|
|
430
473
|
|
|
431
|
-
###
|
|
474
|
+
### "No USDC balance" / "Insufficient funds"
|
|
432
475
|
|
|
433
|
-
|
|
476
|
+
Wallet needs funding.
|
|
434
477
|
|
|
435
478
|
**Fix:**
|
|
436
479
|
|
|
437
|
-
1.
|
|
438
|
-
2.
|
|
439
|
-
3.
|
|
440
|
-
4.
|
|
441
|
-
5. Restart OpenClaw
|
|
480
|
+
1. Find your wallet address (printed during install)
|
|
481
|
+
2. Send USDC on **Base network** to that address
|
|
482
|
+
3. $1-5 is enough for hundreds of requests
|
|
483
|
+
4. Restart OpenClaw
|
|
442
484
|
|
|
443
485
|
### Port 8402 already in use
|
|
444
486
|
|
|
445
|
-
**Fix:**
|
|
446
|
-
|
|
447
487
|
```bash
|
|
448
|
-
# Find what's using the port
|
|
449
488
|
lsof -i :8402
|
|
450
|
-
|
|
451
|
-
# Kill it or restart OpenClaw
|
|
489
|
+
# Kill the process or restart OpenClaw
|
|
452
490
|
```
|
|
453
491
|
|
|
454
|
-
###
|
|
455
|
-
|
|
456
|
-
**Cause:** Can't reach Base RPC to check wallet balance.
|
|
492
|
+
### How to Update ClawRouter
|
|
457
493
|
|
|
458
|
-
|
|
494
|
+
Always do a clean reinstall:
|
|
459
495
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
496
|
+
```bash
|
|
497
|
+
rm -rf ~/.openclaw/extensions/clawrouter
|
|
498
|
+
openclaw plugins install @blockrun/clawrouter
|
|
499
|
+
# Restart OpenClaw
|
|
500
|
+
```
|
|
463
501
|
|
|
464
|
-
|
|
502
|
+
### Verify Routing is Working
|
|
465
503
|
|
|
466
504
|
```bash
|
|
467
|
-
|
|
468
|
-
|
|
505
|
+
openclaw logs --follow
|
|
506
|
+
```
|
|
469
507
|
|
|
470
|
-
|
|
471
|
-
# "BlockRun x402 proxy listening on port 8402"
|
|
508
|
+
You should see model selection for each request:
|
|
472
509
|
|
|
473
|
-
|
|
474
|
-
|
|
510
|
+
```
|
|
511
|
+
[plugins] google/gemini-2.5-flash $0.0012 (saved 99%)
|
|
512
|
+
[plugins] deepseek/deepseek-chat $0.0003 (saved 99%)
|
|
513
|
+
[plugins] anthropic/claude-sonnet-4 $0.0450 (saved 80%)
|
|
475
514
|
```
|
|
476
515
|
|
|
477
516
|
---
|
package/dist/index.js
CHANGED
|
@@ -1,97 +1,3 @@
|
|
|
1
|
-
// src/auth.ts
|
|
2
|
-
import { writeFile, readFile, mkdir } from "fs/promises";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
import { homedir } from "os";
|
|
5
|
-
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
|
|
6
|
-
var WALLET_DIR = join(homedir(), ".openclaw", "blockrun");
|
|
7
|
-
var WALLET_FILE = join(WALLET_DIR, "wallet.key");
|
|
8
|
-
async function loadSavedWallet() {
|
|
9
|
-
try {
|
|
10
|
-
const key = (await readFile(WALLET_FILE, "utf-8")).trim();
|
|
11
|
-
if (key.startsWith("0x") && key.length === 66) return key;
|
|
12
|
-
} catch {
|
|
13
|
-
}
|
|
14
|
-
return void 0;
|
|
15
|
-
}
|
|
16
|
-
async function generateAndSaveWallet() {
|
|
17
|
-
const key = generatePrivateKey();
|
|
18
|
-
const account = privateKeyToAccount(key);
|
|
19
|
-
await mkdir(WALLET_DIR, { recursive: true });
|
|
20
|
-
await writeFile(WALLET_FILE, key + "\n", { mode: 384 });
|
|
21
|
-
return { key, address: account.address };
|
|
22
|
-
}
|
|
23
|
-
async function resolveOrGenerateWalletKey() {
|
|
24
|
-
const saved = await loadSavedWallet();
|
|
25
|
-
if (saved) {
|
|
26
|
-
const account = privateKeyToAccount(saved);
|
|
27
|
-
return { key: saved, address: account.address, source: "saved" };
|
|
28
|
-
}
|
|
29
|
-
const envKey = process.env.BLOCKRUN_WALLET_KEY;
|
|
30
|
-
if (typeof envKey === "string" && envKey.startsWith("0x") && envKey.length === 66) {
|
|
31
|
-
const account = privateKeyToAccount(envKey);
|
|
32
|
-
return { key: envKey, address: account.address, source: "env" };
|
|
33
|
-
}
|
|
34
|
-
const { key, address } = await generateAndSaveWallet();
|
|
35
|
-
return { key, address, source: "generated" };
|
|
36
|
-
}
|
|
37
|
-
var walletKeyAuth = {
|
|
38
|
-
id: "wallet-key",
|
|
39
|
-
label: "Wallet Private Key",
|
|
40
|
-
hint: "Enter your EVM wallet private key (0x...) for x402 payments to BlockRun",
|
|
41
|
-
kind: "api_key",
|
|
42
|
-
run: async (ctx) => {
|
|
43
|
-
const key = await ctx.prompter.text({
|
|
44
|
-
message: "Enter your wallet private key (0x...)",
|
|
45
|
-
validate: (value) => {
|
|
46
|
-
const trimmed = value.trim();
|
|
47
|
-
if (!trimmed.startsWith("0x")) return "Key must start with 0x";
|
|
48
|
-
if (trimmed.length !== 66) return "Key must be 66 characters (0x + 64 hex)";
|
|
49
|
-
if (!/^0x[0-9a-fA-F]{64}$/.test(trimmed)) return "Key must be valid hex";
|
|
50
|
-
return void 0;
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
if (!key || typeof key !== "string") {
|
|
54
|
-
throw new Error("Wallet key is required");
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
profiles: [
|
|
58
|
-
{
|
|
59
|
-
profileId: "default",
|
|
60
|
-
credential: { apiKey: key.trim() }
|
|
61
|
-
}
|
|
62
|
-
],
|
|
63
|
-
notes: [
|
|
64
|
-
"Wallet key stored securely in OpenClaw credentials.",
|
|
65
|
-
"Your wallet signs x402 USDC payments on Base for each LLM call.",
|
|
66
|
-
"Fund your wallet with USDC on Base to start using BlockRun models."
|
|
67
|
-
]
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
var envKeyAuth = {
|
|
72
|
-
id: "env-key",
|
|
73
|
-
label: "Environment Variable",
|
|
74
|
-
hint: "Use BLOCKRUN_WALLET_KEY environment variable",
|
|
75
|
-
kind: "api_key",
|
|
76
|
-
run: async () => {
|
|
77
|
-
const key = process.env.BLOCKRUN_WALLET_KEY;
|
|
78
|
-
if (!key) {
|
|
79
|
-
throw new Error(
|
|
80
|
-
"BLOCKRUN_WALLET_KEY environment variable is not set. Set it to your EVM wallet private key (0x...)."
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
return {
|
|
84
|
-
profiles: [
|
|
85
|
-
{
|
|
86
|
-
profileId: "default",
|
|
87
|
-
credential: { apiKey: key.trim() }
|
|
88
|
-
}
|
|
89
|
-
],
|
|
90
|
-
notes: ["Using wallet key from BLOCKRUN_WALLET_KEY environment variable."]
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
|
|
95
1
|
// src/models.ts
|
|
96
2
|
var BLOCKRUN_MODELS = [
|
|
97
3
|
// Smart routing meta-model — proxy replaces with actual model
|
|
@@ -394,23 +300,18 @@ var blockrunProvider = {
|
|
|
394
300
|
}
|
|
395
301
|
return buildProviderModels(activeProxy.baseUrl);
|
|
396
302
|
},
|
|
397
|
-
//
|
|
398
|
-
|
|
399
|
-
//
|
|
400
|
-
|
|
401
|
-
if ("apiKey" in cred && typeof cred.apiKey === "string") {
|
|
402
|
-
return cred.apiKey;
|
|
403
|
-
}
|
|
404
|
-
throw new Error("BlockRun credential must contain an apiKey (wallet private key)");
|
|
405
|
-
}
|
|
303
|
+
// No auth required — the x402 proxy handles wallet-based payments internally.
|
|
304
|
+
// The proxy auto-generates a wallet on first run and stores it at
|
|
305
|
+
// ~/.openclaw/blockrun/wallet.key. Users just fund that wallet with USDC.
|
|
306
|
+
auth: []
|
|
406
307
|
};
|
|
407
308
|
|
|
408
309
|
// src/proxy.ts
|
|
409
310
|
import { createServer } from "http";
|
|
410
|
-
import { privateKeyToAccount as
|
|
311
|
+
import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
411
312
|
|
|
412
313
|
// src/x402.ts
|
|
413
|
-
import { signTypedData, privateKeyToAccount
|
|
314
|
+
import { signTypedData, privateKeyToAccount } from "viem/accounts";
|
|
414
315
|
|
|
415
316
|
// src/payment-cache.ts
|
|
416
317
|
var DEFAULT_TTL_MS = 36e5;
|
|
@@ -519,7 +420,7 @@ async function createPaymentPayload(privateKey, fromAddress, recipient, amount,
|
|
|
519
420
|
return btoa(JSON.stringify(paymentData));
|
|
520
421
|
}
|
|
521
422
|
function createPaymentFetch(privateKey) {
|
|
522
|
-
const account =
|
|
423
|
+
const account = privateKeyToAccount(privateKey);
|
|
523
424
|
const walletAddress = account.address;
|
|
524
425
|
const paymentCache = new PaymentCache();
|
|
525
426
|
const payFetch = async (input, init, preAuth) => {
|
|
@@ -1051,21 +952,21 @@ function route(prompt, systemPrompt, maxOutputTokens, options) {
|
|
|
1051
952
|
}
|
|
1052
953
|
|
|
1053
954
|
// src/logger.ts
|
|
1054
|
-
import { appendFile, mkdir
|
|
1055
|
-
import { join
|
|
1056
|
-
import { homedir
|
|
1057
|
-
var LOG_DIR =
|
|
955
|
+
import { appendFile, mkdir } from "fs/promises";
|
|
956
|
+
import { join } from "path";
|
|
957
|
+
import { homedir } from "os";
|
|
958
|
+
var LOG_DIR = join(homedir(), ".openclaw", "blockrun", "logs");
|
|
1058
959
|
var dirReady = false;
|
|
1059
960
|
async function ensureDir() {
|
|
1060
961
|
if (dirReady) return;
|
|
1061
|
-
await
|
|
962
|
+
await mkdir(LOG_DIR, { recursive: true });
|
|
1062
963
|
dirReady = true;
|
|
1063
964
|
}
|
|
1064
965
|
async function logUsage(entry) {
|
|
1065
966
|
try {
|
|
1066
967
|
await ensureDir();
|
|
1067
968
|
const date = entry.timestamp.slice(0, 10);
|
|
1068
|
-
const file =
|
|
969
|
+
const file = join(LOG_DIR, `usage-${date}.jsonl`);
|
|
1069
970
|
await appendFile(file, JSON.stringify(entry) + "\n");
|
|
1070
971
|
} catch {
|
|
1071
972
|
}
|
|
@@ -1322,7 +1223,7 @@ var BalanceMonitor = class {
|
|
|
1322
1223
|
// src/proxy.ts
|
|
1323
1224
|
var BLOCKRUN_API = "https://blockrun.ai/api";
|
|
1324
1225
|
var AUTO_MODEL = "blockrun/auto";
|
|
1325
|
-
var USER_AGENT = "clawrouter/0.3.
|
|
1226
|
+
var USER_AGENT = "clawrouter/0.3.5";
|
|
1326
1227
|
var HEARTBEAT_INTERVAL_MS = 2e3;
|
|
1327
1228
|
var DEFAULT_REQUEST_TIMEOUT_MS = 18e4;
|
|
1328
1229
|
var DEFAULT_PORT = 8402;
|
|
@@ -1356,7 +1257,7 @@ function estimateAmount(modelId, bodyLength, maxTokens) {
|
|
|
1356
1257
|
}
|
|
1357
1258
|
async function startProxy(options) {
|
|
1358
1259
|
const apiBase = options.apiBase ?? BLOCKRUN_API;
|
|
1359
|
-
const account =
|
|
1260
|
+
const account = privateKeyToAccount2(options.walletKey);
|
|
1360
1261
|
const { fetch: payFetch } = createPaymentFetch(options.walletKey);
|
|
1361
1262
|
const balanceMonitor = new BalanceMonitor(account.address);
|
|
1362
1263
|
const routingConfig = mergeRoutingConfig(options.routingConfig);
|
|
@@ -1698,6 +1599,48 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
1698
1599
|
}
|
|
1699
1600
|
}
|
|
1700
1601
|
|
|
1602
|
+
// src/auth.ts
|
|
1603
|
+
import { writeFile, readFile, mkdir as mkdir2 } from "fs/promises";
|
|
1604
|
+
import { join as join2 } from "path";
|
|
1605
|
+
import { homedir as homedir2 } from "os";
|
|
1606
|
+
import { generatePrivateKey, privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
|
|
1607
|
+
var WALLET_DIR = join2(homedir2(), ".openclaw", "blockrun");
|
|
1608
|
+
var WALLET_FILE = join2(WALLET_DIR, "wallet.key");
|
|
1609
|
+
async function loadSavedWallet() {
|
|
1610
|
+
try {
|
|
1611
|
+
const key = (await readFile(WALLET_FILE, "utf-8")).trim();
|
|
1612
|
+
if (key.startsWith("0x") && key.length === 66) return key;
|
|
1613
|
+
} catch {
|
|
1614
|
+
}
|
|
1615
|
+
return void 0;
|
|
1616
|
+
}
|
|
1617
|
+
async function generateAndSaveWallet() {
|
|
1618
|
+
const key = generatePrivateKey();
|
|
1619
|
+
const account = privateKeyToAccount3(key);
|
|
1620
|
+
await mkdir2(WALLET_DIR, { recursive: true });
|
|
1621
|
+
await writeFile(WALLET_FILE, key + "\n", { mode: 384 });
|
|
1622
|
+
return { key, address: account.address };
|
|
1623
|
+
}
|
|
1624
|
+
async function resolveOrGenerateWalletKey() {
|
|
1625
|
+
const saved = await loadSavedWallet();
|
|
1626
|
+
if (saved) {
|
|
1627
|
+
const account = privateKeyToAccount3(saved);
|
|
1628
|
+
return { key: saved, address: account.address, source: "saved" };
|
|
1629
|
+
}
|
|
1630
|
+
const envKey = process.env.BLOCKRUN_WALLET_KEY;
|
|
1631
|
+
if (typeof envKey === "string" && envKey.startsWith("0x") && envKey.length === 66) {
|
|
1632
|
+
const account = privateKeyToAccount3(envKey);
|
|
1633
|
+
return { key: envKey, address: account.address, source: "env" };
|
|
1634
|
+
}
|
|
1635
|
+
const { key, address } = await generateAndSaveWallet();
|
|
1636
|
+
return { key, address, source: "generated" };
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
// src/index.ts
|
|
1640
|
+
import { readFileSync, writeFileSync, existsSync, readdirSync, mkdirSync } from "fs";
|
|
1641
|
+
import { homedir as homedir3 } from "os";
|
|
1642
|
+
import { join as join3 } from "path";
|
|
1643
|
+
|
|
1701
1644
|
// src/retry.ts
|
|
1702
1645
|
var DEFAULT_RETRY_CONFIG = {
|
|
1703
1646
|
maxRetries: 2,
|
|
@@ -1755,6 +1698,82 @@ function isRetryable(errorOrResponse, config) {
|
|
|
1755
1698
|
}
|
|
1756
1699
|
|
|
1757
1700
|
// src/index.ts
|
|
1701
|
+
function injectModelsConfig(logger) {
|
|
1702
|
+
const configPath = join3(homedir3(), ".openclaw", "openclaw.json");
|
|
1703
|
+
if (!existsSync(configPath)) {
|
|
1704
|
+
logger.info("OpenClaw config not found, skipping models injection");
|
|
1705
|
+
return;
|
|
1706
|
+
}
|
|
1707
|
+
try {
|
|
1708
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
1709
|
+
if (config.models?.providers?.blockrun) {
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
if (!config.models) config.models = {};
|
|
1713
|
+
if (!config.models.providers) config.models.providers = {};
|
|
1714
|
+
config.models.providers.blockrun = {
|
|
1715
|
+
baseUrl: "http://127.0.0.1:8402/v1",
|
|
1716
|
+
api: "openai-completions",
|
|
1717
|
+
models: OPENCLAW_MODELS
|
|
1718
|
+
};
|
|
1719
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
1720
|
+
logger.info("Injected BlockRun models into OpenClaw config");
|
|
1721
|
+
} catch {
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
function injectAuthProfile(logger) {
|
|
1725
|
+
const agentsDir = join3(homedir3(), ".openclaw", "agents");
|
|
1726
|
+
if (!existsSync(agentsDir)) {
|
|
1727
|
+
try {
|
|
1728
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
1729
|
+
} catch (err) {
|
|
1730
|
+
logger.info(`Could not create agents dir: ${err instanceof Error ? err.message : String(err)}`);
|
|
1731
|
+
return;
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
try {
|
|
1735
|
+
let agents = readdirSync(agentsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
1736
|
+
if (!agents.includes("main")) {
|
|
1737
|
+
agents = ["main", ...agents];
|
|
1738
|
+
}
|
|
1739
|
+
for (const agentId of agents) {
|
|
1740
|
+
const authDir = join3(agentsDir, agentId, "agent");
|
|
1741
|
+
const authPath = join3(authDir, "auth-profiles.json");
|
|
1742
|
+
if (!existsSync(authDir)) {
|
|
1743
|
+
try {
|
|
1744
|
+
mkdirSync(authDir, { recursive: true });
|
|
1745
|
+
} catch {
|
|
1746
|
+
continue;
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
let authProfiles = {};
|
|
1750
|
+
if (existsSync(authPath)) {
|
|
1751
|
+
try {
|
|
1752
|
+
authProfiles = JSON.parse(readFileSync(authPath, "utf-8"));
|
|
1753
|
+
} catch {
|
|
1754
|
+
authProfiles = {};
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
if (authProfiles.blockrun) {
|
|
1758
|
+
continue;
|
|
1759
|
+
}
|
|
1760
|
+
authProfiles.blockrun = {
|
|
1761
|
+
profileId: "default",
|
|
1762
|
+
credential: {
|
|
1763
|
+
apiKey: "x402-proxy-handles-auth"
|
|
1764
|
+
}
|
|
1765
|
+
};
|
|
1766
|
+
try {
|
|
1767
|
+
writeFileSync(authPath, JSON.stringify(authProfiles, null, 2));
|
|
1768
|
+
logger.info(`Injected BlockRun auth profile for agent: ${agentId}`);
|
|
1769
|
+
} catch (err) {
|
|
1770
|
+
logger.info(`Could not inject auth for ${agentId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
} catch (err) {
|
|
1774
|
+
logger.info(`Auth injection failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1758
1777
|
async function startProxyInBackground(api) {
|
|
1759
1778
|
const { key: walletKey, address, source } = await resolveOrGenerateWalletKey();
|
|
1760
1779
|
if (source === "generated") {
|
|
@@ -1813,9 +1832,22 @@ var plugin = {
|
|
|
1813
1832
|
id: "clawrouter",
|
|
1814
1833
|
name: "ClawRouter",
|
|
1815
1834
|
description: "Smart LLM router \u2014 30+ models, x402 micropayments, 78% cost savings",
|
|
1816
|
-
version: "0.3.
|
|
1835
|
+
version: "0.3.11",
|
|
1817
1836
|
register(api) {
|
|
1818
1837
|
api.registerProvider(blockrunProvider);
|
|
1838
|
+
injectModelsConfig(api.logger);
|
|
1839
|
+
injectAuthProfile(api.logger);
|
|
1840
|
+
if (!api.config.models) {
|
|
1841
|
+
api.config.models = { providers: {} };
|
|
1842
|
+
}
|
|
1843
|
+
if (!api.config.models.providers) {
|
|
1844
|
+
api.config.models.providers = {};
|
|
1845
|
+
}
|
|
1846
|
+
api.config.models.providers.blockrun = {
|
|
1847
|
+
baseUrl: "http://127.0.0.1:8402/v1",
|
|
1848
|
+
api: "openai-completions",
|
|
1849
|
+
models: OPENCLAW_MODELS
|
|
1850
|
+
};
|
|
1819
1851
|
api.logger.info("BlockRun provider registered (30+ models via x402)");
|
|
1820
1852
|
startProxyInBackground(api).catch((err) => {
|
|
1821
1853
|
api.logger.error(
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auth.ts","../src/models.ts","../src/provider.ts","../src/proxy.ts","../src/x402.ts","../src/payment-cache.ts","../src/router/rules.ts","../src/router/selector.ts","../src/router/config.ts","../src/router/index.ts","../src/logger.ts","../src/dedup.ts","../src/balance.ts","../src/errors.ts","../src/retry.ts","../src/index.ts"],"sourcesContent":["/**\n * BlockRun Auth Methods for OpenClaw\n *\n * Provides wallet-based authentication for the BlockRun provider.\n * Operators configure their wallet private key, which is used to\n * sign x402 micropayments for LLM inference.\n *\n * Three methods:\n * 1. Auto-generate — create a new wallet on first run, save to ~/.openclaw/blockrun/wallet.key\n * 2. Environment variable — read from BLOCKRUN_WALLET_KEY\n * 3. Manual input — operator enters private key via wizard\n */\n\nimport { writeFile, readFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { generatePrivateKey, privateKeyToAccount } from \"viem/accounts\";\nimport type { ProviderAuthMethod, ProviderAuthContext, ProviderAuthResult } from \"./types.js\";\n\nconst WALLET_DIR = join(homedir(), \".openclaw\", \"blockrun\");\nconst WALLET_FILE = join(WALLET_DIR, \"wallet.key\");\n\n/**\n * Try to load a previously auto-generated wallet key from disk.\n */\nasync function loadSavedWallet(): Promise<string | undefined> {\n try {\n const key = (await readFile(WALLET_FILE, \"utf-8\")).trim();\n if (key.startsWith(\"0x\") && key.length === 66) return key;\n } catch {\n // File doesn't exist yet\n }\n return undefined;\n}\n\n/**\n * Generate a new wallet, save to disk, return the private key.\n */\nasync function generateAndSaveWallet(): Promise<{ key: string; address: string }> {\n const key = generatePrivateKey();\n const account = privateKeyToAccount(key);\n await mkdir(WALLET_DIR, { recursive: true });\n await writeFile(WALLET_FILE, key + \"\\n\", { mode: 0o600 });\n return { key, address: account.address };\n}\n\n/**\n * Resolve wallet key: load saved → env var → auto-generate.\n * Called by index.ts before the auth wizard runs.\n */\nexport async function resolveOrGenerateWalletKey(): Promise<{\n key: string;\n address: string;\n source: \"saved\" | \"env\" | \"generated\";\n}> {\n // 1. Previously saved wallet\n const saved = await loadSavedWallet();\n if (saved) {\n const account = privateKeyToAccount(saved as `0x${string}`);\n return { key: saved, address: account.address, source: \"saved\" };\n }\n\n // 2. Environment variable\n const envKey = process.env.BLOCKRUN_WALLET_KEY;\n if (typeof envKey === \"string\" && envKey.startsWith(\"0x\") && envKey.length === 66) {\n const account = privateKeyToAccount(envKey as `0x${string}`);\n return { key: envKey, address: account.address, source: \"env\" };\n }\n\n // 3. Auto-generate\n const { key, address } = await generateAndSaveWallet();\n return { key, address, source: \"generated\" };\n}\n\n/**\n * Auth method: operator enters their wallet private key directly.\n */\nexport const walletKeyAuth: ProviderAuthMethod = {\n id: \"wallet-key\",\n label: \"Wallet Private Key\",\n hint: \"Enter your EVM wallet private key (0x...) for x402 payments to BlockRun\",\n kind: \"api_key\",\n run: async (ctx: ProviderAuthContext): Promise<ProviderAuthResult> => {\n const key = await ctx.prompter.text({\n message: \"Enter your wallet private key (0x...)\",\n validate: (value: string) => {\n const trimmed = value.trim();\n if (!trimmed.startsWith(\"0x\")) return \"Key must start with 0x\";\n if (trimmed.length !== 66) return \"Key must be 66 characters (0x + 64 hex)\";\n if (!/^0x[0-9a-fA-F]{64}$/.test(trimmed)) return \"Key must be valid hex\";\n return undefined;\n },\n });\n\n if (!key || typeof key !== \"string\") {\n throw new Error(\"Wallet key is required\");\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\n \"Wallet key stored securely in OpenClaw credentials.\",\n \"Your wallet signs x402 USDC payments on Base for each LLM call.\",\n \"Fund your wallet with USDC on Base to start using BlockRun models.\",\n ],\n };\n },\n};\n\n/**\n * Auth method: read wallet key from BLOCKRUN_WALLET_KEY environment variable.\n */\nexport const envKeyAuth: ProviderAuthMethod = {\n id: \"env-key\",\n label: \"Environment Variable\",\n hint: \"Use BLOCKRUN_WALLET_KEY environment variable\",\n kind: \"api_key\",\n run: async (): Promise<ProviderAuthResult> => {\n const key = process.env.BLOCKRUN_WALLET_KEY;\n\n if (!key) {\n throw new Error(\n \"BLOCKRUN_WALLET_KEY environment variable is not set. \" +\n \"Set it to your EVM wallet private key (0x...).\",\n );\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\"Using wallet key from BLOCKRUN_WALLET_KEY environment variable.\"],\n };\n },\n};\n","/**\n * BlockRun Model Definitions for OpenClaw\n *\n * Maps BlockRun's 30+ AI models to OpenClaw's ModelDefinitionConfig format.\n * All models use the \"openai-completions\" API since BlockRun is OpenAI-compatible.\n *\n * Pricing is in USD per 1M tokens. Operators pay these rates via x402;\n * they set their own markup when reselling to end users (Phase 2).\n */\n\nimport type { ModelDefinitionConfig, ModelProviderConfig } from \"./types.js\";\n\ntype BlockRunModel = {\n id: string;\n name: string;\n inputPrice: number;\n outputPrice: number;\n contextWindow: number;\n maxOutput: number;\n reasoning?: boolean;\n vision?: boolean;\n};\n\nexport const BLOCKRUN_MODELS: BlockRunModel[] = [\n // Smart routing meta-model — proxy replaces with actual model\n {\n id: \"blockrun/auto\",\n name: \"BlockRun Smart Router\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 1_050_000,\n maxOutput: 128_000,\n },\n\n // OpenAI GPT-5 Family\n {\n id: \"openai/gpt-5.2\",\n name: \"GPT-5.2\",\n inputPrice: 1.75,\n outputPrice: 14.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n vision: true,\n },\n {\n id: \"openai/gpt-5-mini\",\n name: \"GPT-5 Mini\",\n inputPrice: 0.25,\n outputPrice: 2.0,\n contextWindow: 200000,\n maxOutput: 65536,\n },\n {\n id: \"openai/gpt-5-nano\",\n name: \"GPT-5 Nano\",\n inputPrice: 0.05,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 32768,\n },\n {\n id: \"openai/gpt-5.2-pro\",\n name: \"GPT-5.2 Pro\",\n inputPrice: 21.0,\n outputPrice: 168.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n },\n\n // OpenAI GPT-4 Family\n {\n id: \"openai/gpt-4.1\",\n name: \"GPT-4.1\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n },\n {\n id: \"openai/gpt-4.1-mini\",\n name: \"GPT-4.1 Mini\",\n inputPrice: 0.4,\n outputPrice: 1.6,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n {\n id: \"openai/gpt-4.1-nano\",\n name: \"GPT-4.1 Nano\",\n inputPrice: 0.1,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n {\n id: \"openai/gpt-4o\",\n name: \"GPT-4o\",\n inputPrice: 2.5,\n outputPrice: 10.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n },\n {\n id: \"openai/gpt-4o-mini\",\n name: \"GPT-4o Mini\",\n inputPrice: 0.15,\n outputPrice: 0.6,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n\n // OpenAI O-series (Reasoning)\n {\n id: \"openai/o1\",\n name: \"o1\",\n inputPrice: 15.0,\n outputPrice: 60.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n },\n {\n id: \"openai/o1-mini\",\n name: \"o1-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n },\n {\n id: \"openai/o3\",\n name: \"o3\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n },\n {\n id: \"openai/o3-mini\",\n name: \"o3-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n },\n {\n id: \"openai/o4-mini\",\n name: \"o4-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n },\n\n // Anthropic\n {\n id: \"anthropic/claude-haiku-4.5\",\n name: \"Claude Haiku 4.5\",\n inputPrice: 1.0,\n outputPrice: 5.0,\n contextWindow: 200000,\n maxOutput: 8192,\n },\n {\n id: \"anthropic/claude-sonnet-4\",\n name: \"Claude Sonnet 4\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 200000,\n maxOutput: 64000,\n reasoning: true,\n },\n {\n id: \"anthropic/claude-opus-4\",\n name: \"Claude Opus 4\",\n inputPrice: 15.0,\n outputPrice: 75.0,\n contextWindow: 200000,\n maxOutput: 32000,\n reasoning: true,\n },\n {\n id: \"anthropic/claude-opus-4.5\",\n name: \"Claude Opus 4.5\",\n inputPrice: 5.0,\n outputPrice: 25.0,\n contextWindow: 200000,\n maxOutput: 32000,\n reasoning: true,\n },\n\n // Google\n {\n id: \"google/gemini-3-pro-preview\",\n name: \"Gemini 3 Pro Preview\",\n inputPrice: 2.0,\n outputPrice: 12.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n },\n {\n id: \"google/gemini-2.5-pro\",\n name: \"Gemini 2.5 Pro\",\n inputPrice: 1.25,\n outputPrice: 10.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n },\n {\n id: \"google/gemini-2.5-flash\",\n name: \"Gemini 2.5 Flash\",\n inputPrice: 0.15,\n outputPrice: 0.6,\n contextWindow: 1000000,\n maxOutput: 65536,\n },\n\n // DeepSeek\n {\n id: \"deepseek/deepseek-chat\",\n name: \"DeepSeek V3.2 Chat\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n },\n {\n id: \"deepseek/deepseek-reasoner\",\n name: \"DeepSeek V3.2 Reasoner\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n reasoning: true,\n },\n\n // Moonshot / Kimi\n {\n id: \"moonshot/kimi-k2.5\",\n name: \"Kimi K2.5\",\n inputPrice: 0.5,\n outputPrice: 2.4,\n contextWindow: 262144,\n maxOutput: 8192,\n reasoning: true,\n vision: true,\n },\n\n // xAI / Grok\n {\n id: \"xai/grok-3\",\n name: \"Grok 3\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n },\n {\n id: \"xai/grok-3-fast\",\n name: \"Grok 3 Fast\",\n inputPrice: 5.0,\n outputPrice: 25.0,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n },\n {\n id: \"xai/grok-3-mini\",\n name: \"Grok 3 Mini\",\n inputPrice: 0.3,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n },\n];\n\n/**\n * Convert BlockRun model definitions to OpenClaw ModelDefinitionConfig format.\n */\nfunction toOpenClawModel(m: BlockRunModel): ModelDefinitionConfig {\n return {\n id: m.id,\n name: m.name,\n api: \"openai-completions\",\n reasoning: m.reasoning ?? false,\n input: m.vision ? [\"text\", \"image\"] : [\"text\"],\n cost: {\n input: m.inputPrice,\n output: m.outputPrice,\n cacheRead: 0,\n cacheWrite: 0,\n },\n contextWindow: m.contextWindow,\n maxTokens: m.maxOutput,\n };\n}\n\n/**\n * All BlockRun models in OpenClaw format.\n */\nexport const OPENCLAW_MODELS: ModelDefinitionConfig[] = BLOCKRUN_MODELS.map(toOpenClawModel);\n\n/**\n * Build a ModelProviderConfig for BlockRun.\n *\n * @param baseUrl - The proxy's local base URL (e.g., \"http://127.0.0.1:12345\")\n */\nexport function buildProviderModels(baseUrl: string): ModelProviderConfig {\n return {\n baseUrl: `${baseUrl}/v1`,\n api: \"openai-completions\",\n models: OPENCLAW_MODELS,\n };\n}\n","/**\n * BlockRun ProviderPlugin for OpenClaw\n *\n * Registers BlockRun as an LLM provider in OpenClaw.\n * Uses a local x402 proxy to handle micropayments transparently —\n * pi-ai sees a standard OpenAI-compatible API at localhost.\n */\n\nimport type { ProviderPlugin, AuthProfileCredential } from \"./types.js\";\nimport { walletKeyAuth, envKeyAuth } from \"./auth.js\";\nimport { buildProviderModels } from \"./models.js\";\nimport type { ProxyHandle } from \"./proxy.js\";\n\n/**\n * State for the running proxy (set when the plugin activates).\n */\nlet activeProxy: ProxyHandle | null = null;\n\n/**\n * Update the proxy handle (called from index.ts when the proxy starts).\n */\nexport function setActiveProxy(proxy: ProxyHandle): void {\n activeProxy = proxy;\n}\n\nexport function getActiveProxy(): ProxyHandle | null {\n return activeProxy;\n}\n\n/**\n * BlockRun provider plugin definition.\n */\nexport const blockrunProvider: ProviderPlugin = {\n id: \"blockrun\",\n label: \"BlockRun\",\n docsPath: \"https://blockrun.ai/docs\",\n aliases: [\"br\"],\n envVars: [\"BLOCKRUN_WALLET_KEY\"],\n\n // Model definitions — dynamically set to proxy URL\n get models() {\n if (!activeProxy) {\n // Fallback: point to BlockRun API directly (won't handle x402, but\n // allows config loading before proxy starts)\n return buildProviderModels(\"https://blockrun.ai/api\");\n }\n return buildProviderModels(activeProxy.baseUrl);\n },\n\n // Auth methods\n auth: [envKeyAuth, walletKeyAuth],\n\n // Format the stored credential as the wallet key\n formatApiKey: (cred: AuthProfileCredential): string => {\n if (\"apiKey\" in cred && typeof cred.apiKey === \"string\") {\n return cred.apiKey;\n }\n throw new Error(\"BlockRun credential must contain an apiKey (wallet private key)\");\n },\n};\n","/**\n * Local x402 Proxy Server\n *\n * Sits between OpenClaw's pi-ai (which makes standard OpenAI-format requests)\n * and BlockRun's API (which requires x402 micropayments).\n *\n * Flow:\n * pi-ai → http://localhost:{port}/v1/chat/completions\n * → proxy forwards to https://blockrun.ai/api/v1/chat/completions\n * → gets 402 → @x402/fetch signs payment → retries\n * → streams response back to pi-ai\n *\n * Optimizations (v0.3.0):\n * - SSE heartbeat: for streaming requests, sends headers + heartbeat immediately\n * before the x402 flow, preventing OpenClaw's 10-15s timeout from firing.\n * - Response dedup: hashes request bodies and caches responses for 30s,\n * preventing double-charging when OpenClaw retries after timeout.\n * - Payment cache: after first 402, pre-signs subsequent requests to skip\n * the 402 round trip (~200ms savings per request).\n * - Smart routing: when model is \"blockrun/auto\", classify query and pick cheapest model.\n * - Usage logging: log every request as JSON line to ~/.openclaw/blockrun/logs/\n */\n\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { createPaymentFetch, type PreAuthParams } from \"./x402.js\";\nimport {\n route,\n DEFAULT_ROUTING_CONFIG,\n type RouterOptions,\n type RoutingDecision,\n type RoutingConfig,\n type ModelPricing,\n} from \"./router/index.js\";\nimport { BLOCKRUN_MODELS } from \"./models.js\";\nimport { logUsage, type UsageEntry } from \"./logger.js\";\nimport { RequestDeduplicator } from \"./dedup.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { InsufficientFundsError, EmptyWalletError } from \"./errors.js\";\n\nconst BLOCKRUN_API = \"https://blockrun.ai/api\";\nconst AUTO_MODEL = \"blockrun/auto\";\nconst USER_AGENT = \"clawrouter/0.3.9\";\nconst HEARTBEAT_INTERVAL_MS = 2_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 180_000; // 3 minutes (allows for on-chain tx + LLM response)\nconst DEFAULT_PORT = 8402;\n\n/** Callback info for low balance warning */\nexport type LowBalanceInfo = {\n balanceUSD: string;\n walletAddress: string;\n};\n\n/** Callback info for insufficient funds error */\nexport type InsufficientFundsInfo = {\n balanceUSD: string;\n requiredUSD: string;\n walletAddress: string;\n};\n\nexport type ProxyOptions = {\n walletKey: string;\n apiBase?: string;\n /** Port to listen on (default: 8402) */\n port?: number;\n routingConfig?: Partial<RoutingConfig>;\n /** Request timeout in ms (default: 180000 = 3 minutes). Covers on-chain tx + LLM response. */\n requestTimeoutMs?: number;\n onReady?: (port: number) => void;\n onError?: (error: Error) => void;\n onPayment?: (info: { model: string; amount: string; network: string }) => void;\n onRouted?: (decision: RoutingDecision) => void;\n /** Called when balance drops below $1.00 (warning, request still proceeds) */\n onLowBalance?: (info: LowBalanceInfo) => void;\n /** Called when balance is insufficient for a request (request fails) */\n onInsufficientFunds?: (info: InsufficientFundsInfo) => void;\n};\n\nexport type ProxyHandle = {\n port: number;\n baseUrl: string;\n walletAddress: string;\n balanceMonitor: BalanceMonitor;\n close: () => Promise<void>;\n};\n\n/**\n * Build model pricing map from BLOCKRUN_MODELS.\n */\nfunction buildModelPricing(): Map<string, ModelPricing> {\n const map = new Map<string, ModelPricing>();\n for (const m of BLOCKRUN_MODELS) {\n if (m.id === AUTO_MODEL) continue; // skip meta-model\n map.set(m.id, { inputPrice: m.inputPrice, outputPrice: m.outputPrice });\n }\n return map;\n}\n\n/**\n * Merge partial routing config overrides with defaults.\n */\nfunction mergeRoutingConfig(overrides?: Partial<RoutingConfig>): RoutingConfig {\n if (!overrides) return DEFAULT_ROUTING_CONFIG;\n return {\n ...DEFAULT_ROUTING_CONFIG,\n ...overrides,\n classifier: { ...DEFAULT_ROUTING_CONFIG.classifier, ...overrides.classifier },\n scoring: { ...DEFAULT_ROUTING_CONFIG.scoring, ...overrides.scoring },\n tiers: { ...DEFAULT_ROUTING_CONFIG.tiers, ...overrides.tiers },\n overrides: { ...DEFAULT_ROUTING_CONFIG.overrides, ...overrides.overrides },\n };\n}\n\n/**\n * Estimate USDC cost for a request based on model pricing.\n * Returns amount string in USDC smallest unit (6 decimals) or undefined if unknown.\n */\nfunction estimateAmount(\n modelId: string,\n bodyLength: number,\n maxTokens: number,\n): string | undefined {\n const model = BLOCKRUN_MODELS.find((m) => m.id === modelId);\n if (!model) return undefined;\n\n // Rough estimate: ~4 chars per token for input\n const estimatedInputTokens = Math.ceil(bodyLength / 4);\n const estimatedOutputTokens = maxTokens || model.maxOutput || 4096;\n\n const costUsd =\n (estimatedInputTokens / 1_000_000) * model.inputPrice +\n (estimatedOutputTokens / 1_000_000) * model.outputPrice;\n\n // Convert to USDC 6-decimal integer, add 20% buffer for estimation error\n // Minimum 100 ($0.0001) to avoid zero-amount rejections\n const amountMicros = Math.max(100, Math.ceil(costUsd * 1.2 * 1_000_000));\n return amountMicros.toString();\n}\n\n/**\n * Start the local x402 proxy server.\n *\n * Returns a handle with the assigned port, base URL, and a close function.\n */\nexport async function startProxy(options: ProxyOptions): Promise<ProxyHandle> {\n const apiBase = options.apiBase ?? BLOCKRUN_API;\n\n // Create x402 payment-enabled fetch from wallet private key\n const account = privateKeyToAccount(options.walletKey as `0x${string}`);\n const { fetch: payFetch } = createPaymentFetch(options.walletKey as `0x${string}`);\n\n // Create balance monitor for pre-request checks\n const balanceMonitor = new BalanceMonitor(account.address);\n\n // Build router options (100% local — no external API calls for routing)\n const routingConfig = mergeRoutingConfig(options.routingConfig);\n const modelPricing = buildModelPricing();\n const routerOpts: RouterOptions = {\n config: routingConfig,\n modelPricing,\n };\n\n // Request deduplicator (shared across all requests)\n const deduplicator = new RequestDeduplicator();\n\n const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n // Health check with optional balance info\n if (req.url === \"/health\" || req.url?.startsWith(\"/health?\")) {\n const url = new URL(req.url, \"http://localhost\");\n const full = url.searchParams.get(\"full\") === \"true\";\n\n const response: Record<string, unknown> = {\n status: \"ok\",\n wallet: account.address,\n };\n\n if (full) {\n try {\n const balanceInfo = await balanceMonitor.checkBalance();\n response.balance = balanceInfo.balanceUSD;\n response.isLow = balanceInfo.isLow;\n response.isEmpty = balanceInfo.isEmpty;\n } catch {\n response.balanceError = \"Could not fetch balance\";\n }\n }\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(response));\n return;\n }\n\n // Only proxy paths starting with /v1\n if (!req.url?.startsWith(\"/v1\")) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Not found\" }));\n return;\n }\n\n try {\n await proxyRequest(\n req,\n res,\n apiBase,\n payFetch,\n options,\n routerOpts,\n deduplicator,\n balanceMonitor,\n );\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n options.onError?.(error);\n\n if (!res.headersSent) {\n res.writeHead(502, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Proxy error: ${error.message}`, type: \"proxy_error\" },\n }),\n );\n } else if (!res.writableEnded) {\n // Headers already sent (streaming) — send error as SSE event\n res.write(\n `data: ${JSON.stringify({ error: { message: error.message, type: \"proxy_error\" } })}\\n\\n`,\n );\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n }\n }\n });\n\n // Listen on requested port (default: 8402)\n const listenPort = options.port ?? DEFAULT_PORT;\n\n return new Promise<ProxyHandle>((resolve, reject) => {\n server.on(\"error\", reject);\n\n server.listen(listenPort, \"127.0.0.1\", () => {\n const addr = server.address() as AddressInfo;\n const port = addr.port;\n const baseUrl = `http://127.0.0.1:${port}`;\n\n options.onReady?.(port);\n\n resolve({\n port,\n baseUrl,\n walletAddress: account.address,\n balanceMonitor,\n close: () =>\n new Promise<void>((res, rej) => {\n server.close((err) => (err ? rej(err) : res()));\n }),\n });\n });\n });\n}\n\n/**\n * Proxy a single request through x402 payment flow to BlockRun API.\n *\n * Optimizations applied in order:\n * 1. Dedup check — if same request body seen within 30s, replay cached response\n * 2. Streaming heartbeat — for stream:true, send 200 + heartbeats immediately\n * 3. Payment pre-auth — estimate USDC amount and pre-sign to skip 402 round trip\n * 4. Smart routing — when model is \"blockrun/auto\", pick cheapest capable model\n */\nasync function proxyRequest(\n req: IncomingMessage,\n res: ServerResponse,\n apiBase: string,\n payFetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>,\n options: ProxyOptions,\n routerOpts: RouterOptions,\n deduplicator: RequestDeduplicator,\n balanceMonitor: BalanceMonitor,\n): Promise<void> {\n const startTime = Date.now();\n\n // Build upstream URL: /v1/chat/completions → https://blockrun.ai/api/v1/chat/completions\n const upstreamUrl = `${apiBase}${req.url}`;\n\n // Collect request body\n const bodyChunks: Buffer[] = [];\n for await (const chunk of req) {\n bodyChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n let body = Buffer.concat(bodyChunks);\n\n // --- Smart routing ---\n let routingDecision: RoutingDecision | undefined;\n let isStreaming = false;\n let modelId = \"\";\n let maxTokens = 4096;\n const isChatCompletion = req.url?.includes(\"/chat/completions\");\n\n if (isChatCompletion && body.length > 0) {\n try {\n const parsed = JSON.parse(body.toString()) as Record<string, unknown>;\n isStreaming = parsed.stream === true;\n modelId = (parsed.model as string) || \"\";\n maxTokens = (parsed.max_tokens as number) || 4096;\n\n if (parsed.model === AUTO_MODEL) {\n // Extract prompt from messages\n type ChatMessage = { role: string; content: string };\n const messages = parsed.messages as ChatMessage[] | undefined;\n let lastUserMsg: ChatMessage | undefined;\n if (messages) {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === \"user\") {\n lastUserMsg = messages[i];\n break;\n }\n }\n }\n const systemMsg = messages?.find((m: ChatMessage) => m.role === \"system\");\n const prompt = typeof lastUserMsg?.content === \"string\" ? lastUserMsg.content : \"\";\n const systemPrompt = typeof systemMsg?.content === \"string\" ? systemMsg.content : undefined;\n\n routingDecision = route(prompt, systemPrompt, maxTokens, routerOpts);\n\n // Replace model in body\n parsed.model = routingDecision.model;\n modelId = routingDecision.model;\n body = Buffer.from(JSON.stringify(parsed));\n\n options.onRouted?.(routingDecision);\n }\n } catch {\n // JSON parse error — forward body as-is\n }\n }\n\n // --- Dedup check ---\n const dedupKey = RequestDeduplicator.hash(body);\n\n // Check completed cache first\n const cached = deduplicator.getCached(dedupKey);\n if (cached) {\n res.writeHead(cached.status, cached.headers);\n res.end(cached.body);\n return;\n }\n\n // Check in-flight — wait for the original request to complete\n const inflight = deduplicator.getInflight(dedupKey);\n if (inflight) {\n const result = await inflight;\n res.writeHead(result.status, result.headers);\n res.end(result.body);\n return;\n }\n\n // Register this request as in-flight\n deduplicator.markInflight(dedupKey);\n\n // --- Pre-request balance check ---\n // Estimate cost and check if wallet has sufficient balance\n let estimatedCostMicros: bigint | undefined;\n if (modelId) {\n const estimated = estimateAmount(modelId, body.length, maxTokens);\n if (estimated) {\n estimatedCostMicros = BigInt(estimated);\n\n // Check balance before proceeding\n const sufficiency = await balanceMonitor.checkSufficient(estimatedCostMicros);\n\n if (sufficiency.info.isEmpty) {\n // Wallet is empty — cannot proceed\n deduplicator.removeInflight(dedupKey);\n const error = new EmptyWalletError(sufficiency.info.walletAddress);\n options.onInsufficientFunds?.({\n balanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(estimatedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n throw error;\n }\n\n if (!sufficiency.sufficient) {\n // Insufficient balance — cannot proceed\n deduplicator.removeInflight(dedupKey);\n const error = new InsufficientFundsError({\n currentBalanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(estimatedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n options.onInsufficientFunds?.({\n balanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(estimatedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n throw error;\n }\n\n if (sufficiency.info.isLow) {\n // Balance is low but sufficient — warn and proceed\n options.onLowBalance?.({\n balanceUSD: sufficiency.info.balanceUSD,\n walletAddress: sufficiency.info.walletAddress,\n });\n }\n }\n }\n\n // --- Streaming: early header flush + heartbeat ---\n let heartbeatInterval: ReturnType<typeof setInterval> | undefined;\n let headersSentEarly = false;\n\n if (isStreaming) {\n // Send 200 + SSE headers immediately, before x402 flow\n res.writeHead(200, {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n });\n headersSentEarly = true;\n\n // First heartbeat immediately\n res.write(\": heartbeat\\n\\n\");\n\n // Continue heartbeats every 2s while waiting for upstream\n heartbeatInterval = setInterval(() => {\n if (!res.writableEnded) {\n res.write(\": heartbeat\\n\\n\");\n }\n }, HEARTBEAT_INTERVAL_MS);\n }\n\n // Forward headers, stripping host, connection, and content-length\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (\n key === \"host\" ||\n key === \"connection\" ||\n key === \"transfer-encoding\" ||\n key === \"content-length\"\n )\n continue;\n if (typeof value === \"string\") {\n headers[key] = value;\n }\n }\n if (!headers[\"content-type\"]) {\n headers[\"content-type\"] = \"application/json\";\n }\n headers[\"user-agent\"] = USER_AGENT;\n\n // --- Payment pre-auth: use already-estimated amount to skip 402 round trip ---\n let preAuth: PreAuthParams | undefined;\n if (estimatedCostMicros !== undefined) {\n preAuth = { estimatedAmount: estimatedCostMicros.toString() };\n }\n\n // --- Client disconnect cleanup ---\n let completed = false;\n res.on(\"close\", () => {\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n // Remove from in-flight if client disconnected before completion\n if (!completed) {\n deduplicator.removeInflight(dedupKey);\n }\n });\n\n // --- Request timeout ---\n const timeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n // Make the request through x402-wrapped fetch (with optional pre-auth)\n const upstream = await payFetch(\n upstreamUrl,\n {\n method: req.method ?? \"POST\",\n headers,\n body: body.length > 0 ? body : undefined,\n signal: controller.signal,\n },\n preAuth,\n );\n\n // Clear timeout — request succeeded\n clearTimeout(timeoutId);\n\n // Clear heartbeat — real data is about to flow\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // --- Stream response and collect for dedup cache ---\n const responseChunks: Buffer[] = [];\n\n if (headersSentEarly) {\n // Streaming: headers already sent. Check for upstream errors.\n if (upstream.status !== 200) {\n const errBody = await upstream.text();\n const errEvent = `data: ${JSON.stringify({ error: { message: errBody, type: \"upstream_error\", status: upstream.status } })}\\n\\n`;\n res.write(errEvent);\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n\n // Cache the error response for dedup\n const errBuf = Buffer.from(errEvent + \"data: [DONE]\\n\\n\");\n deduplicator.complete(dedupKey, {\n status: 200, // we already sent 200\n headers: { \"content-type\": \"text/event-stream\" },\n body: errBuf,\n completedAt: Date.now(),\n });\n return;\n }\n\n // Pipe upstream SSE data to client\n if (upstream.body) {\n const reader = upstream.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n res.write(value);\n responseChunks.push(Buffer.from(value));\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n res.end();\n\n // Cache for dedup\n deduplicator.complete(dedupKey, {\n status: 200,\n headers: { \"content-type\": \"text/event-stream\" },\n body: Buffer.concat(responseChunks),\n completedAt: Date.now(),\n });\n } else {\n // Non-streaming: forward status and headers from upstream\n const responseHeaders: Record<string, string> = {};\n upstream.headers.forEach((value, key) => {\n if (key === \"transfer-encoding\" || key === \"connection\") return;\n responseHeaders[key] = value;\n });\n\n res.writeHead(upstream.status, responseHeaders);\n\n if (upstream.body) {\n const reader = upstream.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n res.write(value);\n responseChunks.push(Buffer.from(value));\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n res.end();\n\n // Cache for dedup\n deduplicator.complete(dedupKey, {\n status: upstream.status,\n headers: responseHeaders,\n body: Buffer.concat(responseChunks),\n completedAt: Date.now(),\n });\n }\n\n // --- Optimistic balance deduction after successful response ---\n if (estimatedCostMicros !== undefined) {\n balanceMonitor.deductEstimated(estimatedCostMicros);\n }\n\n // Mark request as completed (for client disconnect cleanup)\n completed = true;\n } catch (err) {\n // Clear timeout on error\n clearTimeout(timeoutId);\n\n // Clear heartbeat on error\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // Remove in-flight entry so retries aren't blocked\n deduplicator.removeInflight(dedupKey);\n\n // Invalidate balance cache on payment failure (might be out of date)\n balanceMonitor.invalidate();\n\n // Convert abort error to more descriptive timeout error\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new Error(`Request timed out after ${timeoutMs}ms`);\n }\n\n throw err;\n }\n\n // --- Usage logging (fire-and-forget) ---\n if (routingDecision) {\n const entry: UsageEntry = {\n timestamp: new Date().toISOString(),\n model: routingDecision.model,\n cost: routingDecision.costEstimate,\n latencyMs: Date.now() - startTime,\n };\n logUsage(entry).catch(() => {});\n }\n}\n","/**\n * x402 Payment Implementation\n *\n * Based on BlockRun's proven implementation.\n * Handles 402 Payment Required responses with EIP-712 signed USDC transfers.\n *\n * Optimizations (v0.3.0):\n * - Payment cache: after first 402, caches {payTo, asset, network} per endpoint.\n * On subsequent requests, pre-signs payment and sends with first request,\n * skipping the 402 round trip (~200ms savings).\n * - Falls back to normal 402 flow if pre-signed payment is rejected.\n */\n\nimport { signTypedData, privateKeyToAccount } from \"viem/accounts\";\nimport { PaymentCache } from \"./payment-cache.js\";\n\nconst BASE_CHAIN_ID = 8453;\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\nconst USDC_DOMAIN = {\n name: \"USD Coin\",\n version: \"2\",\n chainId: BASE_CHAIN_ID,\n verifyingContract: USDC_BASE,\n} as const;\n\nconst TRANSFER_TYPES = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\nfunction createNonce(): `0x${string}` {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}` as `0x${string}`;\n}\n\ninterface PaymentOption {\n scheme: string;\n network: string;\n amount?: string;\n maxAmountRequired?: string;\n asset: string;\n payTo: string;\n maxTimeoutSeconds?: number;\n extra?: { name?: string; version?: string };\n}\n\ninterface PaymentRequired {\n accepts: PaymentOption[];\n resource?: { url?: string; description?: string };\n}\n\nfunction parsePaymentRequired(headerValue: string): PaymentRequired {\n const decoded = atob(headerValue);\n return JSON.parse(decoded) as PaymentRequired;\n}\n\nasync function createPaymentPayload(\n privateKey: `0x${string}`,\n fromAddress: string,\n recipient: string,\n amount: string,\n resourceUrl: string,\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000);\n const validAfter = now - 600;\n const validBefore = now + 300;\n const nonce = createNonce();\n\n const signature = await signTypedData({\n privateKey,\n domain: USDC_DOMAIN,\n types: TRANSFER_TYPES,\n primaryType: \"TransferWithAuthorization\",\n message: {\n from: fromAddress as `0x${string}`,\n to: recipient as `0x${string}`,\n value: BigInt(amount),\n validAfter: BigInt(validAfter),\n validBefore: BigInt(validBefore),\n nonce,\n },\n });\n\n const paymentData = {\n x402Version: 2,\n resource: {\n url: resourceUrl,\n description: \"BlockRun AI API call\",\n mimeType: \"application/json\",\n },\n accepted: {\n scheme: \"exact\",\n network: \"eip155:8453\",\n amount,\n asset: USDC_BASE,\n payTo: recipient,\n maxTimeoutSeconds: 300,\n extra: { name: \"USD Coin\", version: \"2\" },\n },\n payload: {\n signature,\n authorization: {\n from: fromAddress,\n to: recipient,\n value: amount,\n validAfter: validAfter.toString(),\n validBefore: validBefore.toString(),\n nonce,\n },\n },\n extensions: {},\n };\n\n return btoa(JSON.stringify(paymentData));\n}\n\n/** Pre-auth parameters for skipping the 402 round trip. */\nexport type PreAuthParams = {\n estimatedAmount: string; // USDC amount in smallest unit (6 decimals)\n};\n\n/** Result from createPaymentFetch — includes the fetch wrapper and payment cache. */\nexport type PaymentFetchResult = {\n fetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>;\n cache: PaymentCache;\n};\n\n/**\n * Create a fetch wrapper that handles x402 payment automatically.\n *\n * Supports pre-auth: if cached payment params + estimated amount are available,\n * pre-signs and attaches payment to the first request, skipping the 402 round trip.\n * Falls back to normal 402 flow if pre-signed payment is rejected.\n */\nexport function createPaymentFetch(privateKey: `0x${string}`): PaymentFetchResult {\n const account = privateKeyToAccount(privateKey);\n const walletAddress = account.address;\n const paymentCache = new PaymentCache();\n\n const payFetch = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ): Promise<Response> => {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n const endpointPath = new URL(url).pathname;\n\n // --- Pre-auth path: skip 402 round trip ---\n const cached = paymentCache.get(endpointPath);\n if (cached && preAuth?.estimatedAmount) {\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n cached.payTo,\n preAuth.estimatedAmount,\n url,\n );\n\n const preAuthHeaders = new Headers(init?.headers);\n preAuthHeaders.set(\"payment-signature\", paymentPayload);\n\n const response = await fetch(input, { ...init, headers: preAuthHeaders });\n\n // Pre-auth accepted — skip 402 entirely\n if (response.status !== 402) {\n return response;\n }\n\n // Pre-auth rejected (wrong amount, payTo changed, etc.)\n // Try to use this 402's payment header for a proper retry\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (paymentHeader) {\n return handle402(input, init, url, endpointPath, paymentHeader);\n }\n\n // No payment header — invalidate cache and retry clean (no payment header)\n // to get a proper 402 with payment requirements\n paymentCache.invalidate(endpointPath);\n const cleanResponse = await fetch(input, init);\n if (cleanResponse.status !== 402) {\n return cleanResponse;\n }\n const cleanHeader = cleanResponse.headers.get(\"x-payment-required\");\n if (!cleanHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n return handle402(input, init, url, endpointPath, cleanHeader);\n }\n\n // --- Normal path: first request may get 402 ---\n const response = await fetch(input, init);\n\n if (response.status !== 402) {\n return response;\n }\n\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (!paymentHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n\n return handle402(input, init, url, endpointPath, paymentHeader);\n };\n\n /** Handle a 402 response: parse, cache params, sign, retry. */\n async function handle402(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n url: string,\n endpointPath: string,\n paymentHeader: string,\n ): Promise<Response> {\n const paymentRequired = parsePaymentRequired(paymentHeader);\n const option = paymentRequired.accepts?.[0];\n if (!option) {\n throw new Error(\"No payment options in 402 response\");\n }\n\n const amount = option.amount || option.maxAmountRequired;\n if (!amount) {\n throw new Error(\"No amount in payment requirements\");\n }\n\n // Cache payment params for future pre-auth\n paymentCache.set(endpointPath, {\n payTo: option.payTo,\n asset: option.asset,\n scheme: option.scheme,\n network: option.network,\n extra: option.extra,\n maxTimeoutSeconds: option.maxTimeoutSeconds,\n });\n\n // Create signed payment\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n option.payTo,\n amount,\n url,\n );\n\n // Retry with payment\n const retryHeaders = new Headers(init?.headers);\n retryHeaders.set(\"payment-signature\", paymentPayload);\n\n return fetch(input, {\n ...init,\n headers: retryHeaders,\n });\n }\n\n return { fetch: payFetch, cache: paymentCache };\n}\n","/**\n * Payment Parameter Cache\n *\n * Caches the 402 payment parameters (payTo, asset, network, etc.) after the first\n * request to each endpoint. On subsequent requests, pre-signs the payment and\n * attaches it to the first request, skipping the 402 round trip (~200ms savings).\n */\n\nexport type CachedPaymentParams = {\n payTo: string;\n asset: string;\n scheme: string;\n network: string;\n extra?: { name?: string; version?: string };\n maxTimeoutSeconds?: number;\n cachedAt: number;\n};\n\nconst DEFAULT_TTL_MS = 3_600_000; // 1 hour\n\nexport class PaymentCache {\n private cache = new Map<string, CachedPaymentParams>();\n private ttlMs: number;\n\n constructor(ttlMs = DEFAULT_TTL_MS) {\n this.ttlMs = ttlMs;\n }\n\n /** Get cached payment params for an endpoint path. */\n get(endpointPath: string): CachedPaymentParams | undefined {\n const entry = this.cache.get(endpointPath);\n if (!entry) return undefined;\n if (Date.now() - entry.cachedAt > this.ttlMs) {\n this.cache.delete(endpointPath);\n return undefined;\n }\n return entry;\n }\n\n /** Cache payment params from a 402 response. */\n set(endpointPath: string, params: Omit<CachedPaymentParams, \"cachedAt\">): void {\n this.cache.set(endpointPath, { ...params, cachedAt: Date.now() });\n }\n\n /** Invalidate cache for an endpoint (e.g., if payTo changed). */\n invalidate(endpointPath: string): void {\n this.cache.delete(endpointPath);\n }\n}\n","/**\n * Rule-Based Classifier (v2 — Weighted Scoring)\n *\n * Scores a request across 14 weighted dimensions and maps the aggregate\n * score to a tier using configurable boundaries. Confidence is calibrated\n * via sigmoid — low confidence triggers the fallback classifier.\n *\n * Handles 70-80% of requests in < 1ms with zero cost.\n */\n\nimport type { Tier, ScoringResult, ScoringConfig } from \"./types.js\";\n\ntype DimensionScore = { name: string; score: number; signal: string | null };\n\n// ─── Dimension Scorers ───\n// Each returns a score in [-1, 1] and an optional signal string.\n\nfunction scoreTokenCount(\n estimatedTokens: number,\n thresholds: { simple: number; complex: number },\n): DimensionScore {\n if (estimatedTokens < thresholds.simple) {\n return { name: \"tokenCount\", score: -1.0, signal: `short (${estimatedTokens} tokens)` };\n }\n if (estimatedTokens > thresholds.complex) {\n return { name: \"tokenCount\", score: 1.0, signal: `long (${estimatedTokens} tokens)` };\n }\n return { name: \"tokenCount\", score: 0, signal: null };\n}\n\nfunction scoreKeywordMatch(\n text: string,\n keywords: string[],\n name: string,\n signalLabel: string,\n thresholds: { low: number; high: number },\n scores: { none: number; low: number; high: number },\n): DimensionScore {\n const matches = keywords.filter((kw) => text.includes(kw.toLowerCase()));\n if (matches.length >= thresholds.high) {\n return {\n name,\n score: scores.high,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n if (matches.length >= thresholds.low) {\n return {\n name,\n score: scores.low,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n return { name, score: scores.none, signal: null };\n}\n\nfunction scoreMultiStep(text: string): DimensionScore {\n const patterns = [/first.*then/i, /step \\d/i, /\\d\\.\\s/];\n const hits = patterns.filter((p) => p.test(text));\n if (hits.length > 0) {\n return { name: \"multiStepPatterns\", score: 0.5, signal: \"multi-step\" };\n }\n return { name: \"multiStepPatterns\", score: 0, signal: null };\n}\n\nfunction scoreQuestionComplexity(prompt: string): DimensionScore {\n const count = (prompt.match(/\\?/g) || []).length;\n if (count > 3) {\n return { name: \"questionComplexity\", score: 0.5, signal: `${count} questions` };\n }\n return { name: \"questionComplexity\", score: 0, signal: null };\n}\n\n// ─── Main Classifier ───\n\nexport function classifyByRules(\n prompt: string,\n systemPrompt: string | undefined,\n estimatedTokens: number,\n config: ScoringConfig,\n): ScoringResult {\n const text = `${systemPrompt ?? \"\"} ${prompt}`.toLowerCase();\n\n // Score all 14 dimensions\n const dimensions: DimensionScore[] = [\n // Original 8 dimensions\n scoreTokenCount(estimatedTokens, config.tokenCountThresholds),\n scoreKeywordMatch(\n text,\n config.codeKeywords,\n \"codePresence\",\n \"code\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.reasoningKeywords,\n \"reasoningMarkers\",\n \"reasoning\",\n { low: 1, high: 2 },\n { none: 0, low: 0.7, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.technicalKeywords,\n \"technicalTerms\",\n \"technical\",\n { low: 2, high: 4 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.creativeKeywords,\n \"creativeMarkers\",\n \"creative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.simpleKeywords,\n \"simpleIndicators\",\n \"simple\",\n { low: 1, high: 2 },\n { none: 0, low: -1.0, high: -1.0 },\n ),\n scoreMultiStep(text),\n scoreQuestionComplexity(prompt),\n\n // 6 new dimensions\n scoreKeywordMatch(\n text,\n config.imperativeVerbs,\n \"imperativeVerbs\",\n \"imperative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.constraintIndicators,\n \"constraintCount\",\n \"constraints\",\n { low: 1, high: 3 },\n { none: 0, low: 0.3, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.outputFormatKeywords,\n \"outputFormat\",\n \"format\",\n { low: 1, high: 2 },\n { none: 0, low: 0.4, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.referenceKeywords,\n \"referenceComplexity\",\n \"references\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.negationKeywords,\n \"negationComplexity\",\n \"negation\",\n { low: 2, high: 3 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.domainSpecificKeywords,\n \"domainSpecificity\",\n \"domain-specific\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.8 },\n ),\n ];\n\n // Collect signals\n const signals = dimensions.filter((d) => d.signal !== null).map((d) => d.signal!);\n\n // Compute weighted score\n const weights = config.dimensionWeights;\n let weightedScore = 0;\n for (const d of dimensions) {\n const w = weights[d.name] ?? 0;\n weightedScore += d.score * w;\n }\n\n // Count reasoning markers for override\n const reasoningMatches = config.reasoningKeywords.filter((kw) => text.includes(kw.toLowerCase()));\n\n // Direct reasoning override: 2+ reasoning markers = high confidence REASONING\n if (reasoningMatches.length >= 2) {\n const confidence = calibrateConfidence(\n Math.max(weightedScore, 0.3), // ensure positive for confidence calc\n config.confidenceSteepness,\n );\n return {\n score: weightedScore,\n tier: \"REASONING\",\n confidence: Math.max(confidence, 0.85),\n signals,\n };\n }\n\n // Map weighted score to tier using boundaries\n const { simpleMedium, mediumComplex, complexReasoning } = config.tierBoundaries;\n let tier: Tier;\n let distanceFromBoundary: number;\n\n if (weightedScore < simpleMedium) {\n tier = \"SIMPLE\";\n distanceFromBoundary = simpleMedium - weightedScore;\n } else if (weightedScore < mediumComplex) {\n tier = \"MEDIUM\";\n distanceFromBoundary = Math.min(weightedScore - simpleMedium, mediumComplex - weightedScore);\n } else if (weightedScore < complexReasoning) {\n tier = \"COMPLEX\";\n distanceFromBoundary = Math.min(\n weightedScore - mediumComplex,\n complexReasoning - weightedScore,\n );\n } else {\n tier = \"REASONING\";\n distanceFromBoundary = weightedScore - complexReasoning;\n }\n\n // Calibrate confidence via sigmoid of distance from nearest boundary\n const confidence = calibrateConfidence(distanceFromBoundary, config.confidenceSteepness);\n\n // If confidence is below threshold → ambiguous\n if (confidence < config.confidenceThreshold) {\n return { score: weightedScore, tier: null, confidence, signals };\n }\n\n return { score: weightedScore, tier, confidence, signals };\n}\n\n/**\n * Sigmoid confidence calibration.\n * Maps distance from tier boundary to [0.5, 1.0] confidence range.\n */\nfunction calibrateConfidence(distance: number, steepness: number): number {\n return 1 / (1 + Math.exp(-steepness * distance));\n}\n","/**\n * Tier → Model Selection\n *\n * Maps a classification tier to the cheapest capable model.\n * Builds RoutingDecision metadata with cost estimates and savings.\n */\n\nimport type { Tier, TierConfig, RoutingDecision } from \"./types.js\";\n\nexport type ModelPricing = {\n inputPrice: number; // per 1M tokens\n outputPrice: number; // per 1M tokens\n};\n\n/**\n * Select the primary model for a tier and build the RoutingDecision.\n */\nexport function selectModel(\n tier: Tier,\n confidence: number,\n method: \"rules\" | \"llm\",\n reasoning: string,\n tierConfigs: Record<Tier, TierConfig>,\n modelPricing: Map<string, ModelPricing>,\n estimatedInputTokens: number,\n maxOutputTokens: number,\n): RoutingDecision {\n const tierConfig = tierConfigs[tier];\n const model = tierConfig.primary;\n const pricing = modelPricing.get(model);\n\n const inputCost = pricing ? (estimatedInputTokens / 1_000_000) * pricing.inputPrice : 0;\n const outputCost = pricing ? (maxOutputTokens / 1_000_000) * pricing.outputPrice : 0;\n const costEstimate = inputCost + outputCost;\n\n // Baseline: what Claude Opus would cost (the premium default)\n const opusPricing = modelPricing.get(\"anthropic/claude-opus-4\");\n const baselineInput = opusPricing\n ? (estimatedInputTokens / 1_000_000) * opusPricing.inputPrice\n : 0;\n const baselineOutput = opusPricing ? (maxOutputTokens / 1_000_000) * opusPricing.outputPrice : 0;\n const baselineCost = baselineInput + baselineOutput;\n\n const savings = baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;\n\n return {\n model,\n tier,\n confidence,\n method,\n reasoning,\n costEstimate,\n baselineCost,\n savings,\n };\n}\n\n/**\n * Get the ordered fallback chain for a tier: [primary, ...fallbacks].\n */\nexport function getFallbackChain(tier: Tier, tierConfigs: Record<Tier, TierConfig>): string[] {\n const config = tierConfigs[tier];\n return [config.primary, ...config.fallback];\n}\n","/**\n * Default Routing Config\n *\n * All routing parameters as a TypeScript constant.\n * Operators override via openclaw.yaml plugin config.\n *\n * Scoring uses 14 weighted dimensions with sigmoid confidence calibration.\n */\n\nimport type { RoutingConfig } from \"./types.js\";\n\nexport const DEFAULT_ROUTING_CONFIG: RoutingConfig = {\n version: \"2.0\",\n\n classifier: {\n llmModel: \"google/gemini-2.5-flash\",\n llmMaxTokens: 10,\n llmTemperature: 0,\n promptTruncationChars: 500,\n cacheTtlMs: 3_600_000, // 1 hour\n },\n\n scoring: {\n tokenCountThresholds: { simple: 50, complex: 500 },\n codeKeywords: [\n \"function\",\n \"class\",\n \"import\",\n \"def\",\n \"SELECT\",\n \"async\",\n \"await\",\n \"const\",\n \"let\",\n \"var\",\n \"return\",\n \"```\",\n ],\n reasoningKeywords: [\n \"prove\",\n \"theorem\",\n \"derive\",\n \"step by step\",\n \"chain of thought\",\n \"formally\",\n \"mathematical\",\n \"proof\",\n \"logically\",\n ],\n simpleKeywords: [\n \"what is\",\n \"define\",\n \"translate\",\n \"hello\",\n \"yes or no\",\n \"capital of\",\n \"how old\",\n \"who is\",\n \"when was\",\n ],\n technicalKeywords: [\n \"algorithm\",\n \"optimize\",\n \"architecture\",\n \"distributed\",\n \"kubernetes\",\n \"microservice\",\n \"database\",\n \"infrastructure\",\n ],\n creativeKeywords: [\"story\", \"poem\", \"compose\", \"brainstorm\", \"creative\", \"imagine\", \"write a\"],\n\n // New dimension keyword lists\n imperativeVerbs: [\n \"build\",\n \"create\",\n \"implement\",\n \"design\",\n \"develop\",\n \"construct\",\n \"generate\",\n \"deploy\",\n \"configure\",\n \"set up\",\n ],\n constraintIndicators: [\n \"under\",\n \"at most\",\n \"at least\",\n \"within\",\n \"no more than\",\n \"o(\",\n \"maximum\",\n \"minimum\",\n \"limit\",\n \"budget\",\n ],\n outputFormatKeywords: [\n \"json\",\n \"yaml\",\n \"xml\",\n \"table\",\n \"csv\",\n \"markdown\",\n \"schema\",\n \"format as\",\n \"structured\",\n ],\n referenceKeywords: [\n \"above\",\n \"below\",\n \"previous\",\n \"following\",\n \"the docs\",\n \"the api\",\n \"the code\",\n \"earlier\",\n \"attached\",\n ],\n negationKeywords: [\n \"don't\",\n \"do not\",\n \"avoid\",\n \"never\",\n \"without\",\n \"except\",\n \"exclude\",\n \"no longer\",\n ],\n domainSpecificKeywords: [\n \"quantum\",\n \"fpga\",\n \"vlsi\",\n \"risc-v\",\n \"asic\",\n \"photonics\",\n \"genomics\",\n \"proteomics\",\n \"topological\",\n \"homomorphic\",\n \"zero-knowledge\",\n \"lattice-based\",\n ],\n\n // Dimension weights (sum to 1.0)\n dimensionWeights: {\n tokenCount: 0.08,\n codePresence: 0.15,\n reasoningMarkers: 0.18,\n technicalTerms: 0.1,\n creativeMarkers: 0.05,\n simpleIndicators: 0.12,\n multiStepPatterns: 0.12,\n questionComplexity: 0.05,\n imperativeVerbs: 0.03,\n constraintCount: 0.04,\n outputFormat: 0.03,\n referenceComplexity: 0.02,\n negationComplexity: 0.01,\n domainSpecificity: 0.02,\n },\n\n // Tier boundaries on weighted score axis\n tierBoundaries: {\n simpleMedium: 0.0,\n mediumComplex: 0.15,\n complexReasoning: 0.25,\n },\n\n // Sigmoid steepness for confidence calibration\n confidenceSteepness: 12,\n // Below this confidence → ambiguous (null tier)\n confidenceThreshold: 0.7,\n },\n\n tiers: {\n SIMPLE: {\n primary: \"google/gemini-2.5-flash\",\n fallback: [\"deepseek/deepseek-chat\", \"openai/gpt-4o-mini\"],\n },\n MEDIUM: {\n primary: \"deepseek/deepseek-chat\",\n fallback: [\"google/gemini-2.5-flash\", \"openai/gpt-4o-mini\"],\n },\n COMPLEX: {\n primary: \"anthropic/claude-opus-4\",\n fallback: [\"anthropic/claude-sonnet-4\", \"openai/gpt-4o\"],\n },\n REASONING: {\n primary: \"openai/o3\",\n fallback: [\"google/gemini-2.5-pro\", \"anthropic/claude-sonnet-4\"],\n },\n },\n\n overrides: {\n maxTokensForceComplex: 100_000,\n structuredOutputMinTier: \"MEDIUM\",\n ambiguousDefaultTier: \"MEDIUM\",\n },\n};\n","/**\n * Smart Router Entry Point\n *\n * Classifies requests and routes to the cheapest capable model.\n * 100% local — rules-based scoring handles all requests in <1ms.\n * Ambiguous cases default to configurable tier (MEDIUM by default).\n */\n\nimport type { Tier, RoutingDecision, RoutingConfig } from \"./types.js\";\nimport { classifyByRules } from \"./rules.js\";\nimport { selectModel, type ModelPricing } from \"./selector.js\";\n\nexport type RouterOptions = {\n config: RoutingConfig;\n modelPricing: Map<string, ModelPricing>;\n};\n\n/**\n * Route a request to the cheapest capable model.\n *\n * 1. Check overrides (large context, structured output)\n * 2. Run rule-based classifier (14 weighted dimensions, <1ms)\n * 3. If ambiguous, default to configurable tier (no external API calls)\n * 4. Select model for tier\n * 5. Return RoutingDecision with metadata\n */\nexport function route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n): RoutingDecision {\n const { config, modelPricing } = options;\n\n // Estimate input tokens (~4 chars per token)\n const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedTokens = Math.ceil(fullText.length / 4);\n\n // --- Override: large context → force COMPLEX ---\n if (estimatedTokens > config.overrides.maxTokensForceComplex) {\n return selectModel(\n \"COMPLEX\",\n 0.95,\n \"rules\",\n `Input exceeds ${config.overrides.maxTokensForceComplex} tokens`,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n }\n\n // Structured output detection\n const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;\n\n // --- Rule-based classification ---\n const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);\n\n let tier: Tier;\n let confidence: number;\n const method: \"rules\" | \"llm\" = \"rules\";\n let reasoning = `score=${ruleResult.score} | ${ruleResult.signals.join(\", \")}`;\n\n if (ruleResult.tier !== null) {\n tier = ruleResult.tier;\n confidence = ruleResult.confidence;\n } else {\n // Ambiguous — default to configurable tier (no external API call)\n tier = config.overrides.ambiguousDefaultTier;\n confidence = 0.5;\n reasoning += ` | ambiguous -> default: ${tier}`;\n }\n\n // Apply structured output minimum tier\n if (hasStructuredOutput) {\n const tierRank: Record<Tier, number> = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };\n const minTier = config.overrides.structuredOutputMinTier;\n if (tierRank[tier] < tierRank[minTier]) {\n reasoning += ` | upgraded to ${minTier} (structured output)`;\n tier = minTier;\n }\n }\n\n return selectModel(\n tier,\n confidence,\n method,\n reasoning,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n}\n\nexport { getFallbackChain } from \"./selector.js\";\nexport { DEFAULT_ROUTING_CONFIG } from \"./config.js\";\nexport type { RoutingDecision, Tier, RoutingConfig } from \"./types.js\";\nexport type { ModelPricing } from \"./selector.js\";\n","/**\n * Usage Logger\n *\n * Logs every LLM request as a JSON line to a daily log file.\n * Files: ~/.openclaw/blockrun/logs/usage-YYYY-MM-DD.jsonl\n *\n * MVP: append-only JSON lines. No rotation, no cleanup.\n * Logging never breaks the request flow — all errors are swallowed.\n */\n\nimport { appendFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nexport type UsageEntry = {\n timestamp: string;\n model: string;\n cost: number;\n latencyMs: number;\n};\n\nconst LOG_DIR = join(homedir(), \".openclaw\", \"blockrun\", \"logs\");\nlet dirReady = false;\n\nasync function ensureDir(): Promise<void> {\n if (dirReady) return;\n await mkdir(LOG_DIR, { recursive: true });\n dirReady = true;\n}\n\n/**\n * Log a usage entry as a JSON line.\n */\nexport async function logUsage(entry: UsageEntry): Promise<void> {\n try {\n await ensureDir();\n const date = entry.timestamp.slice(0, 10); // YYYY-MM-DD\n const file = join(LOG_DIR, `usage-${date}.jsonl`);\n await appendFile(file, JSON.stringify(entry) + \"\\n\");\n } catch {\n // Never break the request flow\n }\n}\n","/**\n * Request Deduplication\n *\n * Prevents double-charging when OpenClaw retries a request after timeout.\n * Tracks in-flight requests and caches completed responses for a short TTL.\n */\n\nimport { createHash } from \"node:crypto\";\n\nexport type CachedResponse = {\n status: number;\n headers: Record<string, string>;\n body: Buffer;\n completedAt: number;\n};\n\ntype InflightEntry = {\n resolve: (result: CachedResponse) => void;\n waiters: Promise<CachedResponse>[];\n};\n\nconst DEFAULT_TTL_MS = 30_000; // 30 seconds\nconst MAX_BODY_SIZE = 1_048_576; // 1MB\n\nexport class RequestDeduplicator {\n private inflight = new Map<string, InflightEntry>();\n private completed = new Map<string, CachedResponse>();\n private ttlMs: number;\n\n constructor(ttlMs = DEFAULT_TTL_MS) {\n this.ttlMs = ttlMs;\n }\n\n /** Hash request body to create a dedup key. */\n static hash(body: Buffer): string {\n return createHash(\"sha256\").update(body).digest(\"hex\").slice(0, 16);\n }\n\n /** Check if a response is cached for this key. */\n getCached(key: string): CachedResponse | undefined {\n const entry = this.completed.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.completedAt > this.ttlMs) {\n this.completed.delete(key);\n return undefined;\n }\n return entry;\n }\n\n /** Check if a request with this key is currently in-flight. Returns a promise to wait on. */\n getInflight(key: string): Promise<CachedResponse> | undefined {\n const entry = this.inflight.get(key);\n if (!entry) return undefined;\n const promise = new Promise<CachedResponse>((resolve) => {\n // Will be resolved when the original request completes\n entry.waiters.push(\n new Promise<CachedResponse>((r) => {\n const orig = entry.resolve;\n entry.resolve = (result) => {\n orig(result);\n resolve(result);\n r(result);\n };\n }),\n );\n });\n return promise;\n }\n\n /** Mark a request as in-flight. */\n markInflight(key: string): void {\n this.inflight.set(key, {\n resolve: () => {},\n waiters: [],\n });\n }\n\n /** Complete an in-flight request — cache result and notify waiters. */\n complete(key: string, result: CachedResponse): void {\n // Only cache responses within size limit\n if (result.body.length <= MAX_BODY_SIZE) {\n this.completed.set(key, result);\n }\n\n const entry = this.inflight.get(key);\n if (entry) {\n entry.resolve(result);\n this.inflight.delete(key);\n }\n\n this.prune();\n }\n\n /** Remove an in-flight entry on error (don't cache failures). */\n removeInflight(key: string): void {\n this.inflight.delete(key);\n }\n\n /** Prune expired completed entries. */\n private prune(): void {\n const now = Date.now();\n for (const [key, entry] of this.completed) {\n if (now - entry.completedAt > this.ttlMs) {\n this.completed.delete(key);\n }\n }\n }\n}\n","/**\n * Balance Monitor for ClawRouter\n *\n * Monitors USDC balance on Base network with intelligent caching.\n * Provides pre-request balance checks to prevent failed payments.\n *\n * Caching Strategy:\n * - TTL: 30 seconds (balance is cached to avoid excessive RPC calls)\n * - Optimistic deduction: after successful payment, subtract estimated cost from cache\n * - Invalidation: on payment failure, immediately refresh from RPC\n */\n\nimport { createPublicClient, http, erc20Abi } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { RpcError } from \"./errors.js\";\n\n/** USDC contract address on Base mainnet */\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\n/** Cache TTL in milliseconds (30 seconds) */\nconst CACHE_TTL_MS = 30_000;\n\n/** Balance thresholds in USDC smallest unit (6 decimals) */\nexport const BALANCE_THRESHOLDS = {\n /** Low balance warning threshold: $1.00 */\n LOW_BALANCE_MICROS: 1_000_000n,\n /** Effectively zero threshold: $0.0001 (covers dust/rounding) */\n ZERO_THRESHOLD: 100n,\n} as const;\n\n/** Balance information returned by checkBalance() */\nexport type BalanceInfo = {\n /** Raw balance in USDC smallest unit (6 decimals) */\n balance: bigint;\n /** Formatted balance as \"$X.XX\" */\n balanceUSD: string;\n /** True if balance < $1.00 */\n isLow: boolean;\n /** True if balance < $0.0001 (effectively zero) */\n isEmpty: boolean;\n /** Wallet address for funding instructions */\n walletAddress: string;\n};\n\n/** Result from checkSufficient() */\nexport type SufficiencyResult = {\n /** True if balance >= estimated cost */\n sufficient: boolean;\n /** Current balance info */\n info: BalanceInfo;\n /** If insufficient, the shortfall as \"$X.XX\" */\n shortfall?: string;\n};\n\n/**\n * Monitors USDC balance on Base network.\n *\n * Usage:\n * const monitor = new BalanceMonitor(\"0x...\");\n * const info = await monitor.checkBalance();\n * if (info.isLow) console.warn(\"Low balance!\");\n */\nexport class BalanceMonitor {\n private readonly client;\n private readonly walletAddress: `0x${string}`;\n\n /** Cached balance (null = not yet fetched) */\n private cachedBalance: bigint | null = null;\n /** Timestamp when cache was last updated */\n private cachedAt = 0;\n\n constructor(walletAddress: string) {\n this.walletAddress = walletAddress as `0x${string}`;\n this.client = createPublicClient({\n chain: base,\n transport: http(),\n });\n }\n\n /**\n * Check current USDC balance.\n * Uses cache if valid, otherwise fetches from RPC.\n */\n async checkBalance(): Promise<BalanceInfo> {\n const now = Date.now();\n\n // Use cache if valid\n if (this.cachedBalance !== null && now - this.cachedAt < CACHE_TTL_MS) {\n return this.buildInfo(this.cachedBalance);\n }\n\n // Fetch from RPC\n const balance = await this.fetchBalance();\n this.cachedBalance = balance;\n this.cachedAt = now;\n\n return this.buildInfo(balance);\n }\n\n /**\n * Check if balance is sufficient for an estimated cost.\n *\n * @param estimatedCostMicros - Estimated cost in USDC smallest unit (6 decimals)\n */\n async checkSufficient(estimatedCostMicros: bigint): Promise<SufficiencyResult> {\n const info = await this.checkBalance();\n\n if (info.balance >= estimatedCostMicros) {\n return { sufficient: true, info };\n }\n\n const shortfall = estimatedCostMicros - info.balance;\n return {\n sufficient: false,\n info,\n shortfall: this.formatUSDC(shortfall),\n };\n }\n\n /**\n * Optimistically deduct estimated cost from cached balance.\n * Call this after a successful payment to keep cache accurate.\n *\n * @param amountMicros - Amount to deduct in USDC smallest unit\n */\n deductEstimated(amountMicros: bigint): void {\n if (this.cachedBalance !== null && this.cachedBalance >= amountMicros) {\n this.cachedBalance -= amountMicros;\n }\n }\n\n /**\n * Invalidate cache, forcing next checkBalance() to fetch from RPC.\n * Call this after a payment failure to get accurate balance.\n */\n invalidate(): void {\n this.cachedBalance = null;\n this.cachedAt = 0;\n }\n\n /**\n * Force refresh balance from RPC (ignores cache).\n */\n async refresh(): Promise<BalanceInfo> {\n this.invalidate();\n return this.checkBalance();\n }\n\n /**\n * Format USDC amount (in micros) as \"$X.XX\".\n */\n formatUSDC(amountMicros: bigint): string {\n // USDC has 6 decimals\n const dollars = Number(amountMicros) / 1_000_000;\n return `$${dollars.toFixed(2)}`;\n }\n\n /**\n * Get the wallet address being monitored.\n */\n getWalletAddress(): string {\n return this.walletAddress;\n }\n\n /** Fetch balance from RPC */\n private async fetchBalance(): Promise<bigint> {\n try {\n const balance = await this.client.readContract({\n address: USDC_BASE,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.walletAddress],\n });\n return balance;\n } catch (error) {\n // Throw typed error instead of silently returning 0\n // This allows callers to distinguish \"node down\" from \"wallet empty\"\n throw new RpcError(error instanceof Error ? error.message : \"Unknown error\", error);\n }\n }\n\n /** Build BalanceInfo from raw balance */\n private buildInfo(balance: bigint): BalanceInfo {\n return {\n balance,\n balanceUSD: this.formatUSDC(balance),\n isLow: balance < BALANCE_THRESHOLDS.LOW_BALANCE_MICROS,\n isEmpty: balance < BALANCE_THRESHOLDS.ZERO_THRESHOLD,\n walletAddress: this.walletAddress,\n };\n }\n}\n","/**\n * Typed Error Classes for ClawRouter\n *\n * Provides structured errors for balance-related failures with\n * all necessary information for user-friendly error messages.\n */\n\n/**\n * Thrown when wallet has insufficient USDC balance for a request.\n */\nexport class InsufficientFundsError extends Error {\n readonly code = \"INSUFFICIENT_FUNDS\" as const;\n readonly currentBalanceUSD: string;\n readonly requiredUSD: string;\n readonly walletAddress: string;\n\n constructor(opts: { currentBalanceUSD: string; requiredUSD: string; walletAddress: string }) {\n super(\n `Insufficient USDC balance. Current: ${opts.currentBalanceUSD}, Required: ${opts.requiredUSD}. Fund wallet: ${opts.walletAddress}`,\n );\n this.name = \"InsufficientFundsError\";\n this.currentBalanceUSD = opts.currentBalanceUSD;\n this.requiredUSD = opts.requiredUSD;\n this.walletAddress = opts.walletAddress;\n }\n}\n\n/**\n * Thrown when wallet has no USDC balance (or effectively zero).\n */\nexport class EmptyWalletError extends Error {\n readonly code = \"EMPTY_WALLET\" as const;\n readonly walletAddress: string;\n\n constructor(walletAddress: string) {\n super(`No USDC balance. Fund wallet to use ClawRouter: ${walletAddress}`);\n this.name = \"EmptyWalletError\";\n this.walletAddress = walletAddress;\n }\n}\n\n/**\n * Type guard to check if an error is InsufficientFundsError.\n */\nexport function isInsufficientFundsError(error: unknown): error is InsufficientFundsError {\n return error instanceof Error && (error as InsufficientFundsError).code === \"INSUFFICIENT_FUNDS\";\n}\n\n/**\n * Type guard to check if an error is EmptyWalletError.\n */\nexport function isEmptyWalletError(error: unknown): error is EmptyWalletError {\n return error instanceof Error && (error as EmptyWalletError).code === \"EMPTY_WALLET\";\n}\n\n/**\n * Type guard to check if an error is a balance-related error.\n */\nexport function isBalanceError(error: unknown): error is InsufficientFundsError | EmptyWalletError {\n return isInsufficientFundsError(error) || isEmptyWalletError(error);\n}\n\n/**\n * Thrown when RPC call fails (network error, node down, etc).\n * Distinguishes infrastructure failures from actual empty wallets.\n */\nexport class RpcError extends Error {\n readonly code = \"RPC_ERROR\" as const;\n readonly originalError: unknown;\n\n constructor(message: string, originalError?: unknown) {\n super(`RPC error: ${message}. Check network connectivity.`);\n this.name = \"RpcError\";\n this.originalError = originalError;\n }\n}\n\n/**\n * Type guard to check if an error is RpcError.\n */\nexport function isRpcError(error: unknown): error is RpcError {\n return error instanceof Error && (error as RpcError).code === \"RPC_ERROR\";\n}\n","/**\n * Retry Logic for ClawRouter\n *\n * Provides fetch wrapper with exponential backoff for transient errors.\n * Retries on 429 (rate limit), 502, 503, 504 (server errors).\n */\n\n/** Configuration for retry behavior */\nexport type RetryConfig = {\n /** Maximum number of retries (default: 2) */\n maxRetries: number;\n /** Base delay in ms for exponential backoff (default: 500) */\n baseDelayMs: number;\n /** HTTP status codes that trigger a retry (default: [429, 502, 503, 504]) */\n retryableCodes: number[];\n};\n\n/** Default retry configuration */\nexport const DEFAULT_RETRY_CONFIG: RetryConfig = {\n maxRetries: 2,\n baseDelayMs: 500,\n retryableCodes: [429, 502, 503, 504],\n};\n\n/** Sleep for a given number of milliseconds */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Wrap a fetch-like function with retry logic and exponential backoff.\n *\n * @param fetchFn - The fetch function to wrap (can be standard fetch or x402 payFetch)\n * @param url - URL to fetch\n * @param init - Fetch init options\n * @param config - Retry configuration (optional, uses defaults)\n * @returns Response from successful fetch or last failed attempt\n *\n * @example\n * ```typescript\n * const response = await fetchWithRetry(\n * fetch,\n * \"https://api.example.com/endpoint\",\n * { method: \"POST\", body: JSON.stringify(data) },\n * { maxRetries: 3 }\n * );\n * ```\n */\nexport async function fetchWithRetry(\n fetchFn: (url: string, init?: RequestInit) => Promise<Response>,\n url: string,\n init?: RequestInit,\n config?: Partial<RetryConfig>,\n): Promise<Response> {\n const cfg: RetryConfig = {\n ...DEFAULT_RETRY_CONFIG,\n ...config,\n };\n\n let lastError: Error | undefined;\n let lastResponse: Response | undefined;\n\n for (let attempt = 0; attempt <= cfg.maxRetries; attempt++) {\n try {\n const response = await fetchFn(url, init);\n\n // Success or non-retryable status — return immediately\n if (!cfg.retryableCodes.includes(response.status)) {\n return response;\n }\n\n // Retryable status — save response and maybe retry\n lastResponse = response;\n\n // Check for Retry-After header (common with 429)\n const retryAfter = response.headers.get(\"retry-after\");\n let delay: number;\n\n if (retryAfter) {\n // Retry-After can be seconds or HTTP-date\n const seconds = parseInt(retryAfter, 10);\n delay = isNaN(seconds) ? cfg.baseDelayMs * Math.pow(2, attempt) : seconds * 1000;\n } else {\n delay = cfg.baseDelayMs * Math.pow(2, attempt);\n }\n\n // Only retry if we have attempts left\n if (attempt < cfg.maxRetries) {\n await sleep(delay);\n }\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n\n // Network errors are retryable\n if (attempt < cfg.maxRetries) {\n const delay = cfg.baseDelayMs * Math.pow(2, attempt);\n await sleep(delay);\n }\n }\n }\n\n // All retries exhausted — return last response or throw last error\n if (lastResponse) {\n return lastResponse;\n }\n\n throw lastError ?? new Error(\"Max retries exceeded\");\n}\n\n/**\n * Check if an error or response indicates a retryable condition.\n */\nexport function isRetryable(\n errorOrResponse: Error | Response,\n config?: Partial<RetryConfig>,\n): boolean {\n const retryableCodes = config?.retryableCodes ?? DEFAULT_RETRY_CONFIG.retryableCodes;\n\n if (errorOrResponse instanceof Response) {\n return retryableCodes.includes(errorOrResponse.status);\n }\n\n // Network errors are generally retryable\n const message = errorOrResponse.message.toLowerCase();\n return (\n message.includes(\"network\") ||\n message.includes(\"timeout\") ||\n message.includes(\"econnreset\") ||\n message.includes(\"econnrefused\") ||\n message.includes(\"socket hang up\")\n );\n}\n","/**\n * @blockrun/clawrouter\n *\n * Smart LLM router for OpenClaw — 30+ models, x402 micropayments, 78% cost savings.\n * Routes each request to the cheapest model that can handle it.\n *\n * Usage:\n * # Install the plugin\n * openclaw plugin install @blockrun/clawrouter\n *\n * # Fund your wallet with USDC on Base (address printed on install)\n *\n * # Use smart routing (auto-picks cheapest model)\n * openclaw models set blockrun/auto\n *\n * # Or use any specific BlockRun model\n * openclaw models set openai/gpt-5.2\n */\n\nimport type { OpenClawPluginDefinition, OpenClawPluginApi } from \"./types.js\";\nimport { blockrunProvider, setActiveProxy } from \"./provider.js\";\nimport { startProxy } from \"./proxy.js\";\nimport { resolveOrGenerateWalletKey } from \"./auth.js\";\nimport type { RoutingConfig } from \"./router/index.js\";\nimport { BalanceMonitor } from \"./balance.js\";\n\n/**\n * Start the x402 proxy in the background.\n * Called from register() because OpenClaw's loader only invokes register(),\n * treating activate() as an alias (def.register ?? def.activate).\n */\nasync function startProxyInBackground(api: OpenClawPluginApi): Promise<void> {\n // Resolve wallet key: saved file → env var → auto-generate\n const { key: walletKey, address, source } = await resolveOrGenerateWalletKey();\n\n // Log wallet source\n if (source === \"generated\") {\n api.logger.info(`Generated new wallet: ${address}`);\n api.logger.info(`Fund with USDC on Base to start using ClawRouter.`);\n } else if (source === \"saved\") {\n api.logger.info(`Using saved wallet: ${address}`);\n } else {\n api.logger.info(`Using wallet from BLOCKRUN_WALLET_KEY: ${address}`);\n }\n\n // --- Startup balance check ---\n const startupMonitor = new BalanceMonitor(address);\n try {\n const startupBalance = await startupMonitor.checkBalance();\n if (startupBalance.isEmpty) {\n api.logger.warn(`[!] No USDC balance. Fund wallet to use ClawRouter: ${address}`);\n } else if (startupBalance.isLow) {\n api.logger.warn(\n `[!] Low balance: ${startupBalance.balanceUSD} remaining. Fund wallet: ${address}`,\n );\n } else {\n api.logger.info(`Wallet balance: ${startupBalance.balanceUSD}`);\n }\n } catch (err) {\n api.logger.warn(\n `Could not check wallet balance: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n // Resolve routing config overrides from plugin config\n const routingConfig = api.pluginConfig?.routing as Partial<RoutingConfig> | undefined;\n\n const proxy = await startProxy({\n walletKey,\n routingConfig,\n onReady: (port) => {\n api.logger.info(`BlockRun x402 proxy listening on port ${port}`);\n },\n onError: (error) => {\n api.logger.error(`BlockRun proxy error: ${error.message}`);\n },\n onRouted: (decision) => {\n const cost = decision.costEstimate.toFixed(4);\n const saved = (decision.savings * 100).toFixed(0);\n api.logger.info(`${decision.model} $${cost} (saved ${saved}%)`);\n },\n onLowBalance: (info) => {\n api.logger.warn(`[!] Low balance: ${info.balanceUSD}. Fund wallet: ${info.walletAddress}`);\n },\n onInsufficientFunds: (info) => {\n api.logger.error(\n `[!] Insufficient funds. Balance: ${info.balanceUSD}, Needed: ${info.requiredUSD}. Fund wallet: ${info.walletAddress}`,\n );\n },\n });\n\n setActiveProxy(proxy);\n api.logger.info(`BlockRun provider active — ${proxy.baseUrl}/v1 (smart routing enabled)`);\n}\n\nconst plugin: OpenClawPluginDefinition = {\n id: \"clawrouter\",\n name: \"ClawRouter\",\n description: \"Smart LLM router — 30+ models, x402 micropayments, 78% cost savings\",\n version: \"0.3.2\",\n\n register(api: OpenClawPluginApi) {\n // Register BlockRun as a provider (sync — available immediately)\n api.registerProvider(blockrunProvider);\n api.logger.info(\"BlockRun provider registered (30+ models via x402)\");\n\n // Start x402 proxy in background (fire-and-forget)\n // OpenClaw only calls register(), not activate() — so all init goes here.\n // The loader ignores async returns, but the proxy starts in the background\n // and setActiveProxy() makes it available to the provider once ready.\n startProxyInBackground(api).catch((err) => {\n api.logger.error(\n `Failed to start BlockRun proxy: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n },\n};\n\nexport default plugin;\n\n// Re-export for programmatic use\nexport { startProxy } from \"./proxy.js\";\nexport type { ProxyOptions, ProxyHandle, LowBalanceInfo, InsufficientFundsInfo } from \"./proxy.js\";\nexport { blockrunProvider } from \"./provider.js\";\nexport { OPENCLAW_MODELS, BLOCKRUN_MODELS, buildProviderModels } from \"./models.js\";\nexport { route, DEFAULT_ROUTING_CONFIG } from \"./router/index.js\";\nexport type { RoutingDecision, RoutingConfig, Tier } from \"./router/index.js\";\nexport { logUsage } from \"./logger.js\";\nexport type { UsageEntry } from \"./logger.js\";\nexport { RequestDeduplicator } from \"./dedup.js\";\nexport type { CachedResponse } from \"./dedup.js\";\nexport { PaymentCache } from \"./payment-cache.js\";\nexport type { CachedPaymentParams } from \"./payment-cache.js\";\nexport { createPaymentFetch } from \"./x402.js\";\nexport type { PreAuthParams, PaymentFetchResult } from \"./x402.js\";\nexport { BalanceMonitor, BALANCE_THRESHOLDS } from \"./balance.js\";\nexport type { BalanceInfo, SufficiencyResult } from \"./balance.js\";\nexport {\n InsufficientFundsError,\n EmptyWalletError,\n RpcError,\n isInsufficientFundsError,\n isEmptyWalletError,\n isBalanceError,\n isRpcError,\n} from \"./errors.js\";\nexport { fetchWithRetry, isRetryable, DEFAULT_RETRY_CONFIG } from \"./retry.js\";\nexport type { RetryConfig } from \"./retry.js\";\n"],"mappings":"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","names":["privateKeyToAccount","privateKeyToAccount","privateKeyToAccount","response","paymentHeader","confidence","mkdir","join","homedir","DEFAULT_TTL_MS","USDC_BASE","privateKeyToAccount"]}
|
|
1
|
+
{"version":3,"sources":["../src/models.ts","../src/provider.ts","../src/proxy.ts","../src/x402.ts","../src/payment-cache.ts","../src/router/rules.ts","../src/router/selector.ts","../src/router/config.ts","../src/router/index.ts","../src/logger.ts","../src/dedup.ts","../src/balance.ts","../src/errors.ts","../src/auth.ts","../src/index.ts","../src/retry.ts"],"sourcesContent":["/**\n * BlockRun Model Definitions for OpenClaw\n *\n * Maps BlockRun's 30+ AI models to OpenClaw's ModelDefinitionConfig format.\n * All models use the \"openai-completions\" API since BlockRun is OpenAI-compatible.\n *\n * Pricing is in USD per 1M tokens. Operators pay these rates via x402;\n * they set their own markup when reselling to end users (Phase 2).\n */\n\nimport type { ModelDefinitionConfig, ModelProviderConfig } from \"./types.js\";\n\ntype BlockRunModel = {\n id: string;\n name: string;\n inputPrice: number;\n outputPrice: number;\n contextWindow: number;\n maxOutput: number;\n reasoning?: boolean;\n vision?: boolean;\n};\n\nexport const BLOCKRUN_MODELS: BlockRunModel[] = [\n // Smart routing meta-model — proxy replaces with actual model\n {\n id: \"blockrun/auto\",\n name: \"BlockRun Smart Router\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 1_050_000,\n maxOutput: 128_000,\n },\n\n // OpenAI GPT-5 Family\n {\n id: \"openai/gpt-5.2\",\n name: \"GPT-5.2\",\n inputPrice: 1.75,\n outputPrice: 14.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n vision: true,\n },\n {\n id: \"openai/gpt-5-mini\",\n name: \"GPT-5 Mini\",\n inputPrice: 0.25,\n outputPrice: 2.0,\n contextWindow: 200000,\n maxOutput: 65536,\n },\n {\n id: \"openai/gpt-5-nano\",\n name: \"GPT-5 Nano\",\n inputPrice: 0.05,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 32768,\n },\n {\n id: \"openai/gpt-5.2-pro\",\n name: \"GPT-5.2 Pro\",\n inputPrice: 21.0,\n outputPrice: 168.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n },\n\n // OpenAI GPT-4 Family\n {\n id: \"openai/gpt-4.1\",\n name: \"GPT-4.1\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n },\n {\n id: \"openai/gpt-4.1-mini\",\n name: \"GPT-4.1 Mini\",\n inputPrice: 0.4,\n outputPrice: 1.6,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n {\n id: \"openai/gpt-4.1-nano\",\n name: \"GPT-4.1 Nano\",\n inputPrice: 0.1,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n {\n id: \"openai/gpt-4o\",\n name: \"GPT-4o\",\n inputPrice: 2.5,\n outputPrice: 10.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n },\n {\n id: \"openai/gpt-4o-mini\",\n name: \"GPT-4o Mini\",\n inputPrice: 0.15,\n outputPrice: 0.6,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n\n // OpenAI O-series (Reasoning)\n {\n id: \"openai/o1\",\n name: \"o1\",\n inputPrice: 15.0,\n outputPrice: 60.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n },\n {\n id: \"openai/o1-mini\",\n name: \"o1-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n },\n {\n id: \"openai/o3\",\n name: \"o3\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n },\n {\n id: \"openai/o3-mini\",\n name: \"o3-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n },\n {\n id: \"openai/o4-mini\",\n name: \"o4-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n },\n\n // Anthropic\n {\n id: \"anthropic/claude-haiku-4.5\",\n name: \"Claude Haiku 4.5\",\n inputPrice: 1.0,\n outputPrice: 5.0,\n contextWindow: 200000,\n maxOutput: 8192,\n },\n {\n id: \"anthropic/claude-sonnet-4\",\n name: \"Claude Sonnet 4\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 200000,\n maxOutput: 64000,\n reasoning: true,\n },\n {\n id: \"anthropic/claude-opus-4\",\n name: \"Claude Opus 4\",\n inputPrice: 15.0,\n outputPrice: 75.0,\n contextWindow: 200000,\n maxOutput: 32000,\n reasoning: true,\n },\n {\n id: \"anthropic/claude-opus-4.5\",\n name: \"Claude Opus 4.5\",\n inputPrice: 5.0,\n outputPrice: 25.0,\n contextWindow: 200000,\n maxOutput: 32000,\n reasoning: true,\n },\n\n // Google\n {\n id: \"google/gemini-3-pro-preview\",\n name: \"Gemini 3 Pro Preview\",\n inputPrice: 2.0,\n outputPrice: 12.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n },\n {\n id: \"google/gemini-2.5-pro\",\n name: \"Gemini 2.5 Pro\",\n inputPrice: 1.25,\n outputPrice: 10.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n },\n {\n id: \"google/gemini-2.5-flash\",\n name: \"Gemini 2.5 Flash\",\n inputPrice: 0.15,\n outputPrice: 0.6,\n contextWindow: 1000000,\n maxOutput: 65536,\n },\n\n // DeepSeek\n {\n id: \"deepseek/deepseek-chat\",\n name: \"DeepSeek V3.2 Chat\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n },\n {\n id: \"deepseek/deepseek-reasoner\",\n name: \"DeepSeek V3.2 Reasoner\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n reasoning: true,\n },\n\n // Moonshot / Kimi\n {\n id: \"moonshot/kimi-k2.5\",\n name: \"Kimi K2.5\",\n inputPrice: 0.5,\n outputPrice: 2.4,\n contextWindow: 262144,\n maxOutput: 8192,\n reasoning: true,\n vision: true,\n },\n\n // xAI / Grok\n {\n id: \"xai/grok-3\",\n name: \"Grok 3\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n },\n {\n id: \"xai/grok-3-fast\",\n name: \"Grok 3 Fast\",\n inputPrice: 5.0,\n outputPrice: 25.0,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n },\n {\n id: \"xai/grok-3-mini\",\n name: \"Grok 3 Mini\",\n inputPrice: 0.3,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n },\n];\n\n/**\n * Convert BlockRun model definitions to OpenClaw ModelDefinitionConfig format.\n */\nfunction toOpenClawModel(m: BlockRunModel): ModelDefinitionConfig {\n return {\n id: m.id,\n name: m.name,\n api: \"openai-completions\",\n reasoning: m.reasoning ?? false,\n input: m.vision ? [\"text\", \"image\"] : [\"text\"],\n cost: {\n input: m.inputPrice,\n output: m.outputPrice,\n cacheRead: 0,\n cacheWrite: 0,\n },\n contextWindow: m.contextWindow,\n maxTokens: m.maxOutput,\n };\n}\n\n/**\n * All BlockRun models in OpenClaw format.\n */\nexport const OPENCLAW_MODELS: ModelDefinitionConfig[] = BLOCKRUN_MODELS.map(toOpenClawModel);\n\n/**\n * Build a ModelProviderConfig for BlockRun.\n *\n * @param baseUrl - The proxy's local base URL (e.g., \"http://127.0.0.1:12345\")\n */\nexport function buildProviderModels(baseUrl: string): ModelProviderConfig {\n return {\n baseUrl: `${baseUrl}/v1`,\n api: \"openai-completions\",\n models: OPENCLAW_MODELS,\n };\n}\n","/**\n * BlockRun ProviderPlugin for OpenClaw\n *\n * Registers BlockRun as an LLM provider in OpenClaw.\n * Uses a local x402 proxy to handle micropayments transparently —\n * pi-ai sees a standard OpenAI-compatible API at localhost.\n */\n\nimport type { ProviderPlugin } from \"./types.js\";\nimport { buildProviderModels } from \"./models.js\";\nimport type { ProxyHandle } from \"./proxy.js\";\n\n/**\n * State for the running proxy (set when the plugin activates).\n */\nlet activeProxy: ProxyHandle | null = null;\n\n/**\n * Update the proxy handle (called from index.ts when the proxy starts).\n */\nexport function setActiveProxy(proxy: ProxyHandle): void {\n activeProxy = proxy;\n}\n\nexport function getActiveProxy(): ProxyHandle | null {\n return activeProxy;\n}\n\n/**\n * BlockRun provider plugin definition.\n */\nexport const blockrunProvider: ProviderPlugin = {\n id: \"blockrun\",\n label: \"BlockRun\",\n docsPath: \"https://blockrun.ai/docs\",\n aliases: [\"br\"],\n envVars: [\"BLOCKRUN_WALLET_KEY\"],\n\n // Model definitions — dynamically set to proxy URL\n get models() {\n if (!activeProxy) {\n // Fallback: point to BlockRun API directly (won't handle x402, but\n // allows config loading before proxy starts)\n return buildProviderModels(\"https://blockrun.ai/api\");\n }\n return buildProviderModels(activeProxy.baseUrl);\n },\n\n // No auth required — the x402 proxy handles wallet-based payments internally.\n // The proxy auto-generates a wallet on first run and stores it at\n // ~/.openclaw/blockrun/wallet.key. Users just fund that wallet with USDC.\n auth: [],\n};\n","/**\n * Local x402 Proxy Server\n *\n * Sits between OpenClaw's pi-ai (which makes standard OpenAI-format requests)\n * and BlockRun's API (which requires x402 micropayments).\n *\n * Flow:\n * pi-ai → http://localhost:{port}/v1/chat/completions\n * → proxy forwards to https://blockrun.ai/api/v1/chat/completions\n * → gets 402 → @x402/fetch signs payment → retries\n * → streams response back to pi-ai\n *\n * Optimizations (v0.3.0):\n * - SSE heartbeat: for streaming requests, sends headers + heartbeat immediately\n * before the x402 flow, preventing OpenClaw's 10-15s timeout from firing.\n * - Response dedup: hashes request bodies and caches responses for 30s,\n * preventing double-charging when OpenClaw retries after timeout.\n * - Payment cache: after first 402, pre-signs subsequent requests to skip\n * the 402 round trip (~200ms savings per request).\n * - Smart routing: when model is \"blockrun/auto\", classify query and pick cheapest model.\n * - Usage logging: log every request as JSON line to ~/.openclaw/blockrun/logs/\n */\n\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { createPaymentFetch, type PreAuthParams } from \"./x402.js\";\nimport {\n route,\n DEFAULT_ROUTING_CONFIG,\n type RouterOptions,\n type RoutingDecision,\n type RoutingConfig,\n type ModelPricing,\n} from \"./router/index.js\";\nimport { BLOCKRUN_MODELS } from \"./models.js\";\nimport { logUsage, type UsageEntry } from \"./logger.js\";\nimport { RequestDeduplicator } from \"./dedup.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { InsufficientFundsError, EmptyWalletError } from \"./errors.js\";\n\nconst BLOCKRUN_API = \"https://blockrun.ai/api\";\nconst AUTO_MODEL = \"blockrun/auto\";\nconst USER_AGENT = \"clawrouter/0.3.5\";\nconst HEARTBEAT_INTERVAL_MS = 2_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 180_000; // 3 minutes (allows for on-chain tx + LLM response)\nconst DEFAULT_PORT = 8402;\n\n/** Callback info for low balance warning */\nexport type LowBalanceInfo = {\n balanceUSD: string;\n walletAddress: string;\n};\n\n/** Callback info for insufficient funds error */\nexport type InsufficientFundsInfo = {\n balanceUSD: string;\n requiredUSD: string;\n walletAddress: string;\n};\n\nexport type ProxyOptions = {\n walletKey: string;\n apiBase?: string;\n /** Port to listen on (default: 8402) */\n port?: number;\n routingConfig?: Partial<RoutingConfig>;\n /** Request timeout in ms (default: 180000 = 3 minutes). Covers on-chain tx + LLM response. */\n requestTimeoutMs?: number;\n onReady?: (port: number) => void;\n onError?: (error: Error) => void;\n onPayment?: (info: { model: string; amount: string; network: string }) => void;\n onRouted?: (decision: RoutingDecision) => void;\n /** Called when balance drops below $1.00 (warning, request still proceeds) */\n onLowBalance?: (info: LowBalanceInfo) => void;\n /** Called when balance is insufficient for a request (request fails) */\n onInsufficientFunds?: (info: InsufficientFundsInfo) => void;\n};\n\nexport type ProxyHandle = {\n port: number;\n baseUrl: string;\n walletAddress: string;\n balanceMonitor: BalanceMonitor;\n close: () => Promise<void>;\n};\n\n/**\n * Build model pricing map from BLOCKRUN_MODELS.\n */\nfunction buildModelPricing(): Map<string, ModelPricing> {\n const map = new Map<string, ModelPricing>();\n for (const m of BLOCKRUN_MODELS) {\n if (m.id === AUTO_MODEL) continue; // skip meta-model\n map.set(m.id, { inputPrice: m.inputPrice, outputPrice: m.outputPrice });\n }\n return map;\n}\n\n/**\n * Merge partial routing config overrides with defaults.\n */\nfunction mergeRoutingConfig(overrides?: Partial<RoutingConfig>): RoutingConfig {\n if (!overrides) return DEFAULT_ROUTING_CONFIG;\n return {\n ...DEFAULT_ROUTING_CONFIG,\n ...overrides,\n classifier: { ...DEFAULT_ROUTING_CONFIG.classifier, ...overrides.classifier },\n scoring: { ...DEFAULT_ROUTING_CONFIG.scoring, ...overrides.scoring },\n tiers: { ...DEFAULT_ROUTING_CONFIG.tiers, ...overrides.tiers },\n overrides: { ...DEFAULT_ROUTING_CONFIG.overrides, ...overrides.overrides },\n };\n}\n\n/**\n * Estimate USDC cost for a request based on model pricing.\n * Returns amount string in USDC smallest unit (6 decimals) or undefined if unknown.\n */\nfunction estimateAmount(\n modelId: string,\n bodyLength: number,\n maxTokens: number,\n): string | undefined {\n const model = BLOCKRUN_MODELS.find((m) => m.id === modelId);\n if (!model) return undefined;\n\n // Rough estimate: ~4 chars per token for input\n const estimatedInputTokens = Math.ceil(bodyLength / 4);\n const estimatedOutputTokens = maxTokens || model.maxOutput || 4096;\n\n const costUsd =\n (estimatedInputTokens / 1_000_000) * model.inputPrice +\n (estimatedOutputTokens / 1_000_000) * model.outputPrice;\n\n // Convert to USDC 6-decimal integer, add 20% buffer for estimation error\n // Minimum 100 ($0.0001) to avoid zero-amount rejections\n const amountMicros = Math.max(100, Math.ceil(costUsd * 1.2 * 1_000_000));\n return amountMicros.toString();\n}\n\n/**\n * Start the local x402 proxy server.\n *\n * Returns a handle with the assigned port, base URL, and a close function.\n */\nexport async function startProxy(options: ProxyOptions): Promise<ProxyHandle> {\n const apiBase = options.apiBase ?? BLOCKRUN_API;\n\n // Create x402 payment-enabled fetch from wallet private key\n const account = privateKeyToAccount(options.walletKey as `0x${string}`);\n const { fetch: payFetch } = createPaymentFetch(options.walletKey as `0x${string}`);\n\n // Create balance monitor for pre-request checks\n const balanceMonitor = new BalanceMonitor(account.address);\n\n // Build router options (100% local — no external API calls for routing)\n const routingConfig = mergeRoutingConfig(options.routingConfig);\n const modelPricing = buildModelPricing();\n const routerOpts: RouterOptions = {\n config: routingConfig,\n modelPricing,\n };\n\n // Request deduplicator (shared across all requests)\n const deduplicator = new RequestDeduplicator();\n\n const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n // Health check with optional balance info\n if (req.url === \"/health\" || req.url?.startsWith(\"/health?\")) {\n const url = new URL(req.url, \"http://localhost\");\n const full = url.searchParams.get(\"full\") === \"true\";\n\n const response: Record<string, unknown> = {\n status: \"ok\",\n wallet: account.address,\n };\n\n if (full) {\n try {\n const balanceInfo = await balanceMonitor.checkBalance();\n response.balance = balanceInfo.balanceUSD;\n response.isLow = balanceInfo.isLow;\n response.isEmpty = balanceInfo.isEmpty;\n } catch {\n response.balanceError = \"Could not fetch balance\";\n }\n }\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(response));\n return;\n }\n\n // Only proxy paths starting with /v1\n if (!req.url?.startsWith(\"/v1\")) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Not found\" }));\n return;\n }\n\n try {\n await proxyRequest(\n req,\n res,\n apiBase,\n payFetch,\n options,\n routerOpts,\n deduplicator,\n balanceMonitor,\n );\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n options.onError?.(error);\n\n if (!res.headersSent) {\n res.writeHead(502, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Proxy error: ${error.message}`, type: \"proxy_error\" },\n }),\n );\n } else if (!res.writableEnded) {\n // Headers already sent (streaming) — send error as SSE event\n res.write(\n `data: ${JSON.stringify({ error: { message: error.message, type: \"proxy_error\" } })}\\n\\n`,\n );\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n }\n }\n });\n\n // Listen on requested port (default: 8402)\n const listenPort = options.port ?? DEFAULT_PORT;\n\n return new Promise<ProxyHandle>((resolve, reject) => {\n server.on(\"error\", reject);\n\n server.listen(listenPort, \"127.0.0.1\", () => {\n const addr = server.address() as AddressInfo;\n const port = addr.port;\n const baseUrl = `http://127.0.0.1:${port}`;\n\n options.onReady?.(port);\n\n resolve({\n port,\n baseUrl,\n walletAddress: account.address,\n balanceMonitor,\n close: () =>\n new Promise<void>((res, rej) => {\n server.close((err) => (err ? rej(err) : res()));\n }),\n });\n });\n });\n}\n\n/**\n * Proxy a single request through x402 payment flow to BlockRun API.\n *\n * Optimizations applied in order:\n * 1. Dedup check — if same request body seen within 30s, replay cached response\n * 2. Streaming heartbeat — for stream:true, send 200 + heartbeats immediately\n * 3. Payment pre-auth — estimate USDC amount and pre-sign to skip 402 round trip\n * 4. Smart routing — when model is \"blockrun/auto\", pick cheapest capable model\n */\nasync function proxyRequest(\n req: IncomingMessage,\n res: ServerResponse,\n apiBase: string,\n payFetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>,\n options: ProxyOptions,\n routerOpts: RouterOptions,\n deduplicator: RequestDeduplicator,\n balanceMonitor: BalanceMonitor,\n): Promise<void> {\n const startTime = Date.now();\n\n // Build upstream URL: /v1/chat/completions → https://blockrun.ai/api/v1/chat/completions\n const upstreamUrl = `${apiBase}${req.url}`;\n\n // Collect request body\n const bodyChunks: Buffer[] = [];\n for await (const chunk of req) {\n bodyChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n let body = Buffer.concat(bodyChunks);\n\n // --- Smart routing ---\n let routingDecision: RoutingDecision | undefined;\n let isStreaming = false;\n let modelId = \"\";\n let maxTokens = 4096;\n const isChatCompletion = req.url?.includes(\"/chat/completions\");\n\n if (isChatCompletion && body.length > 0) {\n try {\n const parsed = JSON.parse(body.toString()) as Record<string, unknown>;\n isStreaming = parsed.stream === true;\n modelId = (parsed.model as string) || \"\";\n maxTokens = (parsed.max_tokens as number) || 4096;\n\n if (parsed.model === AUTO_MODEL) {\n // Extract prompt from messages\n type ChatMessage = { role: string; content: string };\n const messages = parsed.messages as ChatMessage[] | undefined;\n let lastUserMsg: ChatMessage | undefined;\n if (messages) {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === \"user\") {\n lastUserMsg = messages[i];\n break;\n }\n }\n }\n const systemMsg = messages?.find((m: ChatMessage) => m.role === \"system\");\n const prompt = typeof lastUserMsg?.content === \"string\" ? lastUserMsg.content : \"\";\n const systemPrompt = typeof systemMsg?.content === \"string\" ? systemMsg.content : undefined;\n\n routingDecision = route(prompt, systemPrompt, maxTokens, routerOpts);\n\n // Replace model in body\n parsed.model = routingDecision.model;\n modelId = routingDecision.model;\n body = Buffer.from(JSON.stringify(parsed));\n\n options.onRouted?.(routingDecision);\n }\n } catch {\n // JSON parse error — forward body as-is\n }\n }\n\n // --- Dedup check ---\n const dedupKey = RequestDeduplicator.hash(body);\n\n // Check completed cache first\n const cached = deduplicator.getCached(dedupKey);\n if (cached) {\n res.writeHead(cached.status, cached.headers);\n res.end(cached.body);\n return;\n }\n\n // Check in-flight — wait for the original request to complete\n const inflight = deduplicator.getInflight(dedupKey);\n if (inflight) {\n const result = await inflight;\n res.writeHead(result.status, result.headers);\n res.end(result.body);\n return;\n }\n\n // Register this request as in-flight\n deduplicator.markInflight(dedupKey);\n\n // --- Pre-request balance check ---\n // Estimate cost and check if wallet has sufficient balance\n let estimatedCostMicros: bigint | undefined;\n if (modelId) {\n const estimated = estimateAmount(modelId, body.length, maxTokens);\n if (estimated) {\n estimatedCostMicros = BigInt(estimated);\n\n // Check balance before proceeding\n const sufficiency = await balanceMonitor.checkSufficient(estimatedCostMicros);\n\n if (sufficiency.info.isEmpty) {\n // Wallet is empty — cannot proceed\n deduplicator.removeInflight(dedupKey);\n const error = new EmptyWalletError(sufficiency.info.walletAddress);\n options.onInsufficientFunds?.({\n balanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(estimatedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n throw error;\n }\n\n if (!sufficiency.sufficient) {\n // Insufficient balance — cannot proceed\n deduplicator.removeInflight(dedupKey);\n const error = new InsufficientFundsError({\n currentBalanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(estimatedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n options.onInsufficientFunds?.({\n balanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(estimatedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n throw error;\n }\n\n if (sufficiency.info.isLow) {\n // Balance is low but sufficient — warn and proceed\n options.onLowBalance?.({\n balanceUSD: sufficiency.info.balanceUSD,\n walletAddress: sufficiency.info.walletAddress,\n });\n }\n }\n }\n\n // --- Streaming: early header flush + heartbeat ---\n let heartbeatInterval: ReturnType<typeof setInterval> | undefined;\n let headersSentEarly = false;\n\n if (isStreaming) {\n // Send 200 + SSE headers immediately, before x402 flow\n res.writeHead(200, {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n });\n headersSentEarly = true;\n\n // First heartbeat immediately\n res.write(\": heartbeat\\n\\n\");\n\n // Continue heartbeats every 2s while waiting for upstream\n heartbeatInterval = setInterval(() => {\n if (!res.writableEnded) {\n res.write(\": heartbeat\\n\\n\");\n }\n }, HEARTBEAT_INTERVAL_MS);\n }\n\n // Forward headers, stripping host, connection, and content-length\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (\n key === \"host\" ||\n key === \"connection\" ||\n key === \"transfer-encoding\" ||\n key === \"content-length\"\n )\n continue;\n if (typeof value === \"string\") {\n headers[key] = value;\n }\n }\n if (!headers[\"content-type\"]) {\n headers[\"content-type\"] = \"application/json\";\n }\n headers[\"user-agent\"] = USER_AGENT;\n\n // --- Payment pre-auth: use already-estimated amount to skip 402 round trip ---\n let preAuth: PreAuthParams | undefined;\n if (estimatedCostMicros !== undefined) {\n preAuth = { estimatedAmount: estimatedCostMicros.toString() };\n }\n\n // --- Client disconnect cleanup ---\n let completed = false;\n res.on(\"close\", () => {\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n // Remove from in-flight if client disconnected before completion\n if (!completed) {\n deduplicator.removeInflight(dedupKey);\n }\n });\n\n // --- Request timeout ---\n const timeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n // Make the request through x402-wrapped fetch (with optional pre-auth)\n const upstream = await payFetch(\n upstreamUrl,\n {\n method: req.method ?? \"POST\",\n headers,\n body: body.length > 0 ? body : undefined,\n signal: controller.signal,\n },\n preAuth,\n );\n\n // Clear timeout — request succeeded\n clearTimeout(timeoutId);\n\n // Clear heartbeat — real data is about to flow\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // --- Stream response and collect for dedup cache ---\n const responseChunks: Buffer[] = [];\n\n if (headersSentEarly) {\n // Streaming: headers already sent. Check for upstream errors.\n if (upstream.status !== 200) {\n const errBody = await upstream.text();\n const errEvent = `data: ${JSON.stringify({ error: { message: errBody, type: \"upstream_error\", status: upstream.status } })}\\n\\n`;\n res.write(errEvent);\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n\n // Cache the error response for dedup\n const errBuf = Buffer.from(errEvent + \"data: [DONE]\\n\\n\");\n deduplicator.complete(dedupKey, {\n status: 200, // we already sent 200\n headers: { \"content-type\": \"text/event-stream\" },\n body: errBuf,\n completedAt: Date.now(),\n });\n return;\n }\n\n // Pipe upstream SSE data to client\n if (upstream.body) {\n const reader = upstream.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n res.write(value);\n responseChunks.push(Buffer.from(value));\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n res.end();\n\n // Cache for dedup\n deduplicator.complete(dedupKey, {\n status: 200,\n headers: { \"content-type\": \"text/event-stream\" },\n body: Buffer.concat(responseChunks),\n completedAt: Date.now(),\n });\n } else {\n // Non-streaming: forward status and headers from upstream\n const responseHeaders: Record<string, string> = {};\n upstream.headers.forEach((value, key) => {\n if (key === \"transfer-encoding\" || key === \"connection\") return;\n responseHeaders[key] = value;\n });\n\n res.writeHead(upstream.status, responseHeaders);\n\n if (upstream.body) {\n const reader = upstream.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n res.write(value);\n responseChunks.push(Buffer.from(value));\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n res.end();\n\n // Cache for dedup\n deduplicator.complete(dedupKey, {\n status: upstream.status,\n headers: responseHeaders,\n body: Buffer.concat(responseChunks),\n completedAt: Date.now(),\n });\n }\n\n // --- Optimistic balance deduction after successful response ---\n if (estimatedCostMicros !== undefined) {\n balanceMonitor.deductEstimated(estimatedCostMicros);\n }\n\n // Mark request as completed (for client disconnect cleanup)\n completed = true;\n } catch (err) {\n // Clear timeout on error\n clearTimeout(timeoutId);\n\n // Clear heartbeat on error\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // Remove in-flight entry so retries aren't blocked\n deduplicator.removeInflight(dedupKey);\n\n // Invalidate balance cache on payment failure (might be out of date)\n balanceMonitor.invalidate();\n\n // Convert abort error to more descriptive timeout error\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new Error(`Request timed out after ${timeoutMs}ms`);\n }\n\n throw err;\n }\n\n // --- Usage logging (fire-and-forget) ---\n if (routingDecision) {\n const entry: UsageEntry = {\n timestamp: new Date().toISOString(),\n model: routingDecision.model,\n cost: routingDecision.costEstimate,\n latencyMs: Date.now() - startTime,\n };\n logUsage(entry).catch(() => {});\n }\n}\n","/**\n * x402 Payment Implementation\n *\n * Based on BlockRun's proven implementation.\n * Handles 402 Payment Required responses with EIP-712 signed USDC transfers.\n *\n * Optimizations (v0.3.0):\n * - Payment cache: after first 402, caches {payTo, asset, network} per endpoint.\n * On subsequent requests, pre-signs payment and sends with first request,\n * skipping the 402 round trip (~200ms savings).\n * - Falls back to normal 402 flow if pre-signed payment is rejected.\n */\n\nimport { signTypedData, privateKeyToAccount } from \"viem/accounts\";\nimport { PaymentCache } from \"./payment-cache.js\";\n\nconst BASE_CHAIN_ID = 8453;\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\nconst USDC_DOMAIN = {\n name: \"USD Coin\",\n version: \"2\",\n chainId: BASE_CHAIN_ID,\n verifyingContract: USDC_BASE,\n} as const;\n\nconst TRANSFER_TYPES = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\nfunction createNonce(): `0x${string}` {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}` as `0x${string}`;\n}\n\ninterface PaymentOption {\n scheme: string;\n network: string;\n amount?: string;\n maxAmountRequired?: string;\n asset: string;\n payTo: string;\n maxTimeoutSeconds?: number;\n extra?: { name?: string; version?: string };\n}\n\ninterface PaymentRequired {\n accepts: PaymentOption[];\n resource?: { url?: string; description?: string };\n}\n\nfunction parsePaymentRequired(headerValue: string): PaymentRequired {\n const decoded = atob(headerValue);\n return JSON.parse(decoded) as PaymentRequired;\n}\n\nasync function createPaymentPayload(\n privateKey: `0x${string}`,\n fromAddress: string,\n recipient: string,\n amount: string,\n resourceUrl: string,\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000);\n const validAfter = now - 600;\n const validBefore = now + 300;\n const nonce = createNonce();\n\n const signature = await signTypedData({\n privateKey,\n domain: USDC_DOMAIN,\n types: TRANSFER_TYPES,\n primaryType: \"TransferWithAuthorization\",\n message: {\n from: fromAddress as `0x${string}`,\n to: recipient as `0x${string}`,\n value: BigInt(amount),\n validAfter: BigInt(validAfter),\n validBefore: BigInt(validBefore),\n nonce,\n },\n });\n\n const paymentData = {\n x402Version: 2,\n resource: {\n url: resourceUrl,\n description: \"BlockRun AI API call\",\n mimeType: \"application/json\",\n },\n accepted: {\n scheme: \"exact\",\n network: \"eip155:8453\",\n amount,\n asset: USDC_BASE,\n payTo: recipient,\n maxTimeoutSeconds: 300,\n extra: { name: \"USD Coin\", version: \"2\" },\n },\n payload: {\n signature,\n authorization: {\n from: fromAddress,\n to: recipient,\n value: amount,\n validAfter: validAfter.toString(),\n validBefore: validBefore.toString(),\n nonce,\n },\n },\n extensions: {},\n };\n\n return btoa(JSON.stringify(paymentData));\n}\n\n/** Pre-auth parameters for skipping the 402 round trip. */\nexport type PreAuthParams = {\n estimatedAmount: string; // USDC amount in smallest unit (6 decimals)\n};\n\n/** Result from createPaymentFetch — includes the fetch wrapper and payment cache. */\nexport type PaymentFetchResult = {\n fetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>;\n cache: PaymentCache;\n};\n\n/**\n * Create a fetch wrapper that handles x402 payment automatically.\n *\n * Supports pre-auth: if cached payment params + estimated amount are available,\n * pre-signs and attaches payment to the first request, skipping the 402 round trip.\n * Falls back to normal 402 flow if pre-signed payment is rejected.\n */\nexport function createPaymentFetch(privateKey: `0x${string}`): PaymentFetchResult {\n const account = privateKeyToAccount(privateKey);\n const walletAddress = account.address;\n const paymentCache = new PaymentCache();\n\n const payFetch = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ): Promise<Response> => {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n const endpointPath = new URL(url).pathname;\n\n // --- Pre-auth path: skip 402 round trip ---\n const cached = paymentCache.get(endpointPath);\n if (cached && preAuth?.estimatedAmount) {\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n cached.payTo,\n preAuth.estimatedAmount,\n url,\n );\n\n const preAuthHeaders = new Headers(init?.headers);\n preAuthHeaders.set(\"payment-signature\", paymentPayload);\n\n const response = await fetch(input, { ...init, headers: preAuthHeaders });\n\n // Pre-auth accepted — skip 402 entirely\n if (response.status !== 402) {\n return response;\n }\n\n // Pre-auth rejected (wrong amount, payTo changed, etc.)\n // Try to use this 402's payment header for a proper retry\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (paymentHeader) {\n return handle402(input, init, url, endpointPath, paymentHeader);\n }\n\n // No payment header — invalidate cache and retry clean (no payment header)\n // to get a proper 402 with payment requirements\n paymentCache.invalidate(endpointPath);\n const cleanResponse = await fetch(input, init);\n if (cleanResponse.status !== 402) {\n return cleanResponse;\n }\n const cleanHeader = cleanResponse.headers.get(\"x-payment-required\");\n if (!cleanHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n return handle402(input, init, url, endpointPath, cleanHeader);\n }\n\n // --- Normal path: first request may get 402 ---\n const response = await fetch(input, init);\n\n if (response.status !== 402) {\n return response;\n }\n\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (!paymentHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n\n return handle402(input, init, url, endpointPath, paymentHeader);\n };\n\n /** Handle a 402 response: parse, cache params, sign, retry. */\n async function handle402(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n url: string,\n endpointPath: string,\n paymentHeader: string,\n ): Promise<Response> {\n const paymentRequired = parsePaymentRequired(paymentHeader);\n const option = paymentRequired.accepts?.[0];\n if (!option) {\n throw new Error(\"No payment options in 402 response\");\n }\n\n const amount = option.amount || option.maxAmountRequired;\n if (!amount) {\n throw new Error(\"No amount in payment requirements\");\n }\n\n // Cache payment params for future pre-auth\n paymentCache.set(endpointPath, {\n payTo: option.payTo,\n asset: option.asset,\n scheme: option.scheme,\n network: option.network,\n extra: option.extra,\n maxTimeoutSeconds: option.maxTimeoutSeconds,\n });\n\n // Create signed payment\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n option.payTo,\n amount,\n url,\n );\n\n // Retry with payment\n const retryHeaders = new Headers(init?.headers);\n retryHeaders.set(\"payment-signature\", paymentPayload);\n\n return fetch(input, {\n ...init,\n headers: retryHeaders,\n });\n }\n\n return { fetch: payFetch, cache: paymentCache };\n}\n","/**\n * Payment Parameter Cache\n *\n * Caches the 402 payment parameters (payTo, asset, network, etc.) after the first\n * request to each endpoint. On subsequent requests, pre-signs the payment and\n * attaches it to the first request, skipping the 402 round trip (~200ms savings).\n */\n\nexport type CachedPaymentParams = {\n payTo: string;\n asset: string;\n scheme: string;\n network: string;\n extra?: { name?: string; version?: string };\n maxTimeoutSeconds?: number;\n cachedAt: number;\n};\n\nconst DEFAULT_TTL_MS = 3_600_000; // 1 hour\n\nexport class PaymentCache {\n private cache = new Map<string, CachedPaymentParams>();\n private ttlMs: number;\n\n constructor(ttlMs = DEFAULT_TTL_MS) {\n this.ttlMs = ttlMs;\n }\n\n /** Get cached payment params for an endpoint path. */\n get(endpointPath: string): CachedPaymentParams | undefined {\n const entry = this.cache.get(endpointPath);\n if (!entry) return undefined;\n if (Date.now() - entry.cachedAt > this.ttlMs) {\n this.cache.delete(endpointPath);\n return undefined;\n }\n return entry;\n }\n\n /** Cache payment params from a 402 response. */\n set(endpointPath: string, params: Omit<CachedPaymentParams, \"cachedAt\">): void {\n this.cache.set(endpointPath, { ...params, cachedAt: Date.now() });\n }\n\n /** Invalidate cache for an endpoint (e.g., if payTo changed). */\n invalidate(endpointPath: string): void {\n this.cache.delete(endpointPath);\n }\n}\n","/**\n * Rule-Based Classifier (v2 — Weighted Scoring)\n *\n * Scores a request across 14 weighted dimensions and maps the aggregate\n * score to a tier using configurable boundaries. Confidence is calibrated\n * via sigmoid — low confidence triggers the fallback classifier.\n *\n * Handles 70-80% of requests in < 1ms with zero cost.\n */\n\nimport type { Tier, ScoringResult, ScoringConfig } from \"./types.js\";\n\ntype DimensionScore = { name: string; score: number; signal: string | null };\n\n// ─── Dimension Scorers ───\n// Each returns a score in [-1, 1] and an optional signal string.\n\nfunction scoreTokenCount(\n estimatedTokens: number,\n thresholds: { simple: number; complex: number },\n): DimensionScore {\n if (estimatedTokens < thresholds.simple) {\n return { name: \"tokenCount\", score: -1.0, signal: `short (${estimatedTokens} tokens)` };\n }\n if (estimatedTokens > thresholds.complex) {\n return { name: \"tokenCount\", score: 1.0, signal: `long (${estimatedTokens} tokens)` };\n }\n return { name: \"tokenCount\", score: 0, signal: null };\n}\n\nfunction scoreKeywordMatch(\n text: string,\n keywords: string[],\n name: string,\n signalLabel: string,\n thresholds: { low: number; high: number },\n scores: { none: number; low: number; high: number },\n): DimensionScore {\n const matches = keywords.filter((kw) => text.includes(kw.toLowerCase()));\n if (matches.length >= thresholds.high) {\n return {\n name,\n score: scores.high,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n if (matches.length >= thresholds.low) {\n return {\n name,\n score: scores.low,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n return { name, score: scores.none, signal: null };\n}\n\nfunction scoreMultiStep(text: string): DimensionScore {\n const patterns = [/first.*then/i, /step \\d/i, /\\d\\.\\s/];\n const hits = patterns.filter((p) => p.test(text));\n if (hits.length > 0) {\n return { name: \"multiStepPatterns\", score: 0.5, signal: \"multi-step\" };\n }\n return { name: \"multiStepPatterns\", score: 0, signal: null };\n}\n\nfunction scoreQuestionComplexity(prompt: string): DimensionScore {\n const count = (prompt.match(/\\?/g) || []).length;\n if (count > 3) {\n return { name: \"questionComplexity\", score: 0.5, signal: `${count} questions` };\n }\n return { name: \"questionComplexity\", score: 0, signal: null };\n}\n\n// ─── Main Classifier ───\n\nexport function classifyByRules(\n prompt: string,\n systemPrompt: string | undefined,\n estimatedTokens: number,\n config: ScoringConfig,\n): ScoringResult {\n const text = `${systemPrompt ?? \"\"} ${prompt}`.toLowerCase();\n\n // Score all 14 dimensions\n const dimensions: DimensionScore[] = [\n // Original 8 dimensions\n scoreTokenCount(estimatedTokens, config.tokenCountThresholds),\n scoreKeywordMatch(\n text,\n config.codeKeywords,\n \"codePresence\",\n \"code\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.reasoningKeywords,\n \"reasoningMarkers\",\n \"reasoning\",\n { low: 1, high: 2 },\n { none: 0, low: 0.7, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.technicalKeywords,\n \"technicalTerms\",\n \"technical\",\n { low: 2, high: 4 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.creativeKeywords,\n \"creativeMarkers\",\n \"creative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.simpleKeywords,\n \"simpleIndicators\",\n \"simple\",\n { low: 1, high: 2 },\n { none: 0, low: -1.0, high: -1.0 },\n ),\n scoreMultiStep(text),\n scoreQuestionComplexity(prompt),\n\n // 6 new dimensions\n scoreKeywordMatch(\n text,\n config.imperativeVerbs,\n \"imperativeVerbs\",\n \"imperative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.constraintIndicators,\n \"constraintCount\",\n \"constraints\",\n { low: 1, high: 3 },\n { none: 0, low: 0.3, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.outputFormatKeywords,\n \"outputFormat\",\n \"format\",\n { low: 1, high: 2 },\n { none: 0, low: 0.4, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.referenceKeywords,\n \"referenceComplexity\",\n \"references\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.negationKeywords,\n \"negationComplexity\",\n \"negation\",\n { low: 2, high: 3 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.domainSpecificKeywords,\n \"domainSpecificity\",\n \"domain-specific\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.8 },\n ),\n ];\n\n // Collect signals\n const signals = dimensions.filter((d) => d.signal !== null).map((d) => d.signal!);\n\n // Compute weighted score\n const weights = config.dimensionWeights;\n let weightedScore = 0;\n for (const d of dimensions) {\n const w = weights[d.name] ?? 0;\n weightedScore += d.score * w;\n }\n\n // Count reasoning markers for override\n const reasoningMatches = config.reasoningKeywords.filter((kw) => text.includes(kw.toLowerCase()));\n\n // Direct reasoning override: 2+ reasoning markers = high confidence REASONING\n if (reasoningMatches.length >= 2) {\n const confidence = calibrateConfidence(\n Math.max(weightedScore, 0.3), // ensure positive for confidence calc\n config.confidenceSteepness,\n );\n return {\n score: weightedScore,\n tier: \"REASONING\",\n confidence: Math.max(confidence, 0.85),\n signals,\n };\n }\n\n // Map weighted score to tier using boundaries\n const { simpleMedium, mediumComplex, complexReasoning } = config.tierBoundaries;\n let tier: Tier;\n let distanceFromBoundary: number;\n\n if (weightedScore < simpleMedium) {\n tier = \"SIMPLE\";\n distanceFromBoundary = simpleMedium - weightedScore;\n } else if (weightedScore < mediumComplex) {\n tier = \"MEDIUM\";\n distanceFromBoundary = Math.min(weightedScore - simpleMedium, mediumComplex - weightedScore);\n } else if (weightedScore < complexReasoning) {\n tier = \"COMPLEX\";\n distanceFromBoundary = Math.min(\n weightedScore - mediumComplex,\n complexReasoning - weightedScore,\n );\n } else {\n tier = \"REASONING\";\n distanceFromBoundary = weightedScore - complexReasoning;\n }\n\n // Calibrate confidence via sigmoid of distance from nearest boundary\n const confidence = calibrateConfidence(distanceFromBoundary, config.confidenceSteepness);\n\n // If confidence is below threshold → ambiguous\n if (confidence < config.confidenceThreshold) {\n return { score: weightedScore, tier: null, confidence, signals };\n }\n\n return { score: weightedScore, tier, confidence, signals };\n}\n\n/**\n * Sigmoid confidence calibration.\n * Maps distance from tier boundary to [0.5, 1.0] confidence range.\n */\nfunction calibrateConfidence(distance: number, steepness: number): number {\n return 1 / (1 + Math.exp(-steepness * distance));\n}\n","/**\n * Tier → Model Selection\n *\n * Maps a classification tier to the cheapest capable model.\n * Builds RoutingDecision metadata with cost estimates and savings.\n */\n\nimport type { Tier, TierConfig, RoutingDecision } from \"./types.js\";\n\nexport type ModelPricing = {\n inputPrice: number; // per 1M tokens\n outputPrice: number; // per 1M tokens\n};\n\n/**\n * Select the primary model for a tier and build the RoutingDecision.\n */\nexport function selectModel(\n tier: Tier,\n confidence: number,\n method: \"rules\" | \"llm\",\n reasoning: string,\n tierConfigs: Record<Tier, TierConfig>,\n modelPricing: Map<string, ModelPricing>,\n estimatedInputTokens: number,\n maxOutputTokens: number,\n): RoutingDecision {\n const tierConfig = tierConfigs[tier];\n const model = tierConfig.primary;\n const pricing = modelPricing.get(model);\n\n const inputCost = pricing ? (estimatedInputTokens / 1_000_000) * pricing.inputPrice : 0;\n const outputCost = pricing ? (maxOutputTokens / 1_000_000) * pricing.outputPrice : 0;\n const costEstimate = inputCost + outputCost;\n\n // Baseline: what Claude Opus would cost (the premium default)\n const opusPricing = modelPricing.get(\"anthropic/claude-opus-4\");\n const baselineInput = opusPricing\n ? (estimatedInputTokens / 1_000_000) * opusPricing.inputPrice\n : 0;\n const baselineOutput = opusPricing ? (maxOutputTokens / 1_000_000) * opusPricing.outputPrice : 0;\n const baselineCost = baselineInput + baselineOutput;\n\n const savings = baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;\n\n return {\n model,\n tier,\n confidence,\n method,\n reasoning,\n costEstimate,\n baselineCost,\n savings,\n };\n}\n\n/**\n * Get the ordered fallback chain for a tier: [primary, ...fallbacks].\n */\nexport function getFallbackChain(tier: Tier, tierConfigs: Record<Tier, TierConfig>): string[] {\n const config = tierConfigs[tier];\n return [config.primary, ...config.fallback];\n}\n","/**\n * Default Routing Config\n *\n * All routing parameters as a TypeScript constant.\n * Operators override via openclaw.yaml plugin config.\n *\n * Scoring uses 14 weighted dimensions with sigmoid confidence calibration.\n */\n\nimport type { RoutingConfig } from \"./types.js\";\n\nexport const DEFAULT_ROUTING_CONFIG: RoutingConfig = {\n version: \"2.0\",\n\n classifier: {\n llmModel: \"google/gemini-2.5-flash\",\n llmMaxTokens: 10,\n llmTemperature: 0,\n promptTruncationChars: 500,\n cacheTtlMs: 3_600_000, // 1 hour\n },\n\n scoring: {\n tokenCountThresholds: { simple: 50, complex: 500 },\n codeKeywords: [\n \"function\",\n \"class\",\n \"import\",\n \"def\",\n \"SELECT\",\n \"async\",\n \"await\",\n \"const\",\n \"let\",\n \"var\",\n \"return\",\n \"```\",\n ],\n reasoningKeywords: [\n \"prove\",\n \"theorem\",\n \"derive\",\n \"step by step\",\n \"chain of thought\",\n \"formally\",\n \"mathematical\",\n \"proof\",\n \"logically\",\n ],\n simpleKeywords: [\n \"what is\",\n \"define\",\n \"translate\",\n \"hello\",\n \"yes or no\",\n \"capital of\",\n \"how old\",\n \"who is\",\n \"when was\",\n ],\n technicalKeywords: [\n \"algorithm\",\n \"optimize\",\n \"architecture\",\n \"distributed\",\n \"kubernetes\",\n \"microservice\",\n \"database\",\n \"infrastructure\",\n ],\n creativeKeywords: [\"story\", \"poem\", \"compose\", \"brainstorm\", \"creative\", \"imagine\", \"write a\"],\n\n // New dimension keyword lists\n imperativeVerbs: [\n \"build\",\n \"create\",\n \"implement\",\n \"design\",\n \"develop\",\n \"construct\",\n \"generate\",\n \"deploy\",\n \"configure\",\n \"set up\",\n ],\n constraintIndicators: [\n \"under\",\n \"at most\",\n \"at least\",\n \"within\",\n \"no more than\",\n \"o(\",\n \"maximum\",\n \"minimum\",\n \"limit\",\n \"budget\",\n ],\n outputFormatKeywords: [\n \"json\",\n \"yaml\",\n \"xml\",\n \"table\",\n \"csv\",\n \"markdown\",\n \"schema\",\n \"format as\",\n \"structured\",\n ],\n referenceKeywords: [\n \"above\",\n \"below\",\n \"previous\",\n \"following\",\n \"the docs\",\n \"the api\",\n \"the code\",\n \"earlier\",\n \"attached\",\n ],\n negationKeywords: [\n \"don't\",\n \"do not\",\n \"avoid\",\n \"never\",\n \"without\",\n \"except\",\n \"exclude\",\n \"no longer\",\n ],\n domainSpecificKeywords: [\n \"quantum\",\n \"fpga\",\n \"vlsi\",\n \"risc-v\",\n \"asic\",\n \"photonics\",\n \"genomics\",\n \"proteomics\",\n \"topological\",\n \"homomorphic\",\n \"zero-knowledge\",\n \"lattice-based\",\n ],\n\n // Dimension weights (sum to 1.0)\n dimensionWeights: {\n tokenCount: 0.08,\n codePresence: 0.15,\n reasoningMarkers: 0.18,\n technicalTerms: 0.1,\n creativeMarkers: 0.05,\n simpleIndicators: 0.12,\n multiStepPatterns: 0.12,\n questionComplexity: 0.05,\n imperativeVerbs: 0.03,\n constraintCount: 0.04,\n outputFormat: 0.03,\n referenceComplexity: 0.02,\n negationComplexity: 0.01,\n domainSpecificity: 0.02,\n },\n\n // Tier boundaries on weighted score axis\n tierBoundaries: {\n simpleMedium: 0.0,\n mediumComplex: 0.15,\n complexReasoning: 0.25,\n },\n\n // Sigmoid steepness for confidence calibration\n confidenceSteepness: 12,\n // Below this confidence → ambiguous (null tier)\n confidenceThreshold: 0.7,\n },\n\n tiers: {\n SIMPLE: {\n primary: \"google/gemini-2.5-flash\",\n fallback: [\"deepseek/deepseek-chat\", \"openai/gpt-4o-mini\"],\n },\n MEDIUM: {\n primary: \"deepseek/deepseek-chat\",\n fallback: [\"google/gemini-2.5-flash\", \"openai/gpt-4o-mini\"],\n },\n COMPLEX: {\n primary: \"anthropic/claude-opus-4\",\n fallback: [\"anthropic/claude-sonnet-4\", \"openai/gpt-4o\"],\n },\n REASONING: {\n primary: \"openai/o3\",\n fallback: [\"google/gemini-2.5-pro\", \"anthropic/claude-sonnet-4\"],\n },\n },\n\n overrides: {\n maxTokensForceComplex: 100_000,\n structuredOutputMinTier: \"MEDIUM\",\n ambiguousDefaultTier: \"MEDIUM\",\n },\n};\n","/**\n * Smart Router Entry Point\n *\n * Classifies requests and routes to the cheapest capable model.\n * 100% local — rules-based scoring handles all requests in <1ms.\n * Ambiguous cases default to configurable tier (MEDIUM by default).\n */\n\nimport type { Tier, RoutingDecision, RoutingConfig } from \"./types.js\";\nimport { classifyByRules } from \"./rules.js\";\nimport { selectModel, type ModelPricing } from \"./selector.js\";\n\nexport type RouterOptions = {\n config: RoutingConfig;\n modelPricing: Map<string, ModelPricing>;\n};\n\n/**\n * Route a request to the cheapest capable model.\n *\n * 1. Check overrides (large context, structured output)\n * 2. Run rule-based classifier (14 weighted dimensions, <1ms)\n * 3. If ambiguous, default to configurable tier (no external API calls)\n * 4. Select model for tier\n * 5. Return RoutingDecision with metadata\n */\nexport function route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n): RoutingDecision {\n const { config, modelPricing } = options;\n\n // Estimate input tokens (~4 chars per token)\n const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedTokens = Math.ceil(fullText.length / 4);\n\n // --- Override: large context → force COMPLEX ---\n if (estimatedTokens > config.overrides.maxTokensForceComplex) {\n return selectModel(\n \"COMPLEX\",\n 0.95,\n \"rules\",\n `Input exceeds ${config.overrides.maxTokensForceComplex} tokens`,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n }\n\n // Structured output detection\n const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;\n\n // --- Rule-based classification ---\n const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);\n\n let tier: Tier;\n let confidence: number;\n const method: \"rules\" | \"llm\" = \"rules\";\n let reasoning = `score=${ruleResult.score} | ${ruleResult.signals.join(\", \")}`;\n\n if (ruleResult.tier !== null) {\n tier = ruleResult.tier;\n confidence = ruleResult.confidence;\n } else {\n // Ambiguous — default to configurable tier (no external API call)\n tier = config.overrides.ambiguousDefaultTier;\n confidence = 0.5;\n reasoning += ` | ambiguous -> default: ${tier}`;\n }\n\n // Apply structured output minimum tier\n if (hasStructuredOutput) {\n const tierRank: Record<Tier, number> = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };\n const minTier = config.overrides.structuredOutputMinTier;\n if (tierRank[tier] < tierRank[minTier]) {\n reasoning += ` | upgraded to ${minTier} (structured output)`;\n tier = minTier;\n }\n }\n\n return selectModel(\n tier,\n confidence,\n method,\n reasoning,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n}\n\nexport { getFallbackChain } from \"./selector.js\";\nexport { DEFAULT_ROUTING_CONFIG } from \"./config.js\";\nexport type { RoutingDecision, Tier, RoutingConfig } from \"./types.js\";\nexport type { ModelPricing } from \"./selector.js\";\n","/**\n * Usage Logger\n *\n * Logs every LLM request as a JSON line to a daily log file.\n * Files: ~/.openclaw/blockrun/logs/usage-YYYY-MM-DD.jsonl\n *\n * MVP: append-only JSON lines. No rotation, no cleanup.\n * Logging never breaks the request flow — all errors are swallowed.\n */\n\nimport { appendFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nexport type UsageEntry = {\n timestamp: string;\n model: string;\n cost: number;\n latencyMs: number;\n};\n\nconst LOG_DIR = join(homedir(), \".openclaw\", \"blockrun\", \"logs\");\nlet dirReady = false;\n\nasync function ensureDir(): Promise<void> {\n if (dirReady) return;\n await mkdir(LOG_DIR, { recursive: true });\n dirReady = true;\n}\n\n/**\n * Log a usage entry as a JSON line.\n */\nexport async function logUsage(entry: UsageEntry): Promise<void> {\n try {\n await ensureDir();\n const date = entry.timestamp.slice(0, 10); // YYYY-MM-DD\n const file = join(LOG_DIR, `usage-${date}.jsonl`);\n await appendFile(file, JSON.stringify(entry) + \"\\n\");\n } catch {\n // Never break the request flow\n }\n}\n","/**\n * Request Deduplication\n *\n * Prevents double-charging when OpenClaw retries a request after timeout.\n * Tracks in-flight requests and caches completed responses for a short TTL.\n */\n\nimport { createHash } from \"node:crypto\";\n\nexport type CachedResponse = {\n status: number;\n headers: Record<string, string>;\n body: Buffer;\n completedAt: number;\n};\n\ntype InflightEntry = {\n resolve: (result: CachedResponse) => void;\n waiters: Promise<CachedResponse>[];\n};\n\nconst DEFAULT_TTL_MS = 30_000; // 30 seconds\nconst MAX_BODY_SIZE = 1_048_576; // 1MB\n\nexport class RequestDeduplicator {\n private inflight = new Map<string, InflightEntry>();\n private completed = new Map<string, CachedResponse>();\n private ttlMs: number;\n\n constructor(ttlMs = DEFAULT_TTL_MS) {\n this.ttlMs = ttlMs;\n }\n\n /** Hash request body to create a dedup key. */\n static hash(body: Buffer): string {\n return createHash(\"sha256\").update(body).digest(\"hex\").slice(0, 16);\n }\n\n /** Check if a response is cached for this key. */\n getCached(key: string): CachedResponse | undefined {\n const entry = this.completed.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.completedAt > this.ttlMs) {\n this.completed.delete(key);\n return undefined;\n }\n return entry;\n }\n\n /** Check if a request with this key is currently in-flight. Returns a promise to wait on. */\n getInflight(key: string): Promise<CachedResponse> | undefined {\n const entry = this.inflight.get(key);\n if (!entry) return undefined;\n const promise = new Promise<CachedResponse>((resolve) => {\n // Will be resolved when the original request completes\n entry.waiters.push(\n new Promise<CachedResponse>((r) => {\n const orig = entry.resolve;\n entry.resolve = (result) => {\n orig(result);\n resolve(result);\n r(result);\n };\n }),\n );\n });\n return promise;\n }\n\n /** Mark a request as in-flight. */\n markInflight(key: string): void {\n this.inflight.set(key, {\n resolve: () => {},\n waiters: [],\n });\n }\n\n /** Complete an in-flight request — cache result and notify waiters. */\n complete(key: string, result: CachedResponse): void {\n // Only cache responses within size limit\n if (result.body.length <= MAX_BODY_SIZE) {\n this.completed.set(key, result);\n }\n\n const entry = this.inflight.get(key);\n if (entry) {\n entry.resolve(result);\n this.inflight.delete(key);\n }\n\n this.prune();\n }\n\n /** Remove an in-flight entry on error (don't cache failures). */\n removeInflight(key: string): void {\n this.inflight.delete(key);\n }\n\n /** Prune expired completed entries. */\n private prune(): void {\n const now = Date.now();\n for (const [key, entry] of this.completed) {\n if (now - entry.completedAt > this.ttlMs) {\n this.completed.delete(key);\n }\n }\n }\n}\n","/**\n * Balance Monitor for ClawRouter\n *\n * Monitors USDC balance on Base network with intelligent caching.\n * Provides pre-request balance checks to prevent failed payments.\n *\n * Caching Strategy:\n * - TTL: 30 seconds (balance is cached to avoid excessive RPC calls)\n * - Optimistic deduction: after successful payment, subtract estimated cost from cache\n * - Invalidation: on payment failure, immediately refresh from RPC\n */\n\nimport { createPublicClient, http, erc20Abi } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { RpcError } from \"./errors.js\";\n\n/** USDC contract address on Base mainnet */\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\n/** Cache TTL in milliseconds (30 seconds) */\nconst CACHE_TTL_MS = 30_000;\n\n/** Balance thresholds in USDC smallest unit (6 decimals) */\nexport const BALANCE_THRESHOLDS = {\n /** Low balance warning threshold: $1.00 */\n LOW_BALANCE_MICROS: 1_000_000n,\n /** Effectively zero threshold: $0.0001 (covers dust/rounding) */\n ZERO_THRESHOLD: 100n,\n} as const;\n\n/** Balance information returned by checkBalance() */\nexport type BalanceInfo = {\n /** Raw balance in USDC smallest unit (6 decimals) */\n balance: bigint;\n /** Formatted balance as \"$X.XX\" */\n balanceUSD: string;\n /** True if balance < $1.00 */\n isLow: boolean;\n /** True if balance < $0.0001 (effectively zero) */\n isEmpty: boolean;\n /** Wallet address for funding instructions */\n walletAddress: string;\n};\n\n/** Result from checkSufficient() */\nexport type SufficiencyResult = {\n /** True if balance >= estimated cost */\n sufficient: boolean;\n /** Current balance info */\n info: BalanceInfo;\n /** If insufficient, the shortfall as \"$X.XX\" */\n shortfall?: string;\n};\n\n/**\n * Monitors USDC balance on Base network.\n *\n * Usage:\n * const monitor = new BalanceMonitor(\"0x...\");\n * const info = await monitor.checkBalance();\n * if (info.isLow) console.warn(\"Low balance!\");\n */\nexport class BalanceMonitor {\n private readonly client;\n private readonly walletAddress: `0x${string}`;\n\n /** Cached balance (null = not yet fetched) */\n private cachedBalance: bigint | null = null;\n /** Timestamp when cache was last updated */\n private cachedAt = 0;\n\n constructor(walletAddress: string) {\n this.walletAddress = walletAddress as `0x${string}`;\n this.client = createPublicClient({\n chain: base,\n transport: http(),\n });\n }\n\n /**\n * Check current USDC balance.\n * Uses cache if valid, otherwise fetches from RPC.\n */\n async checkBalance(): Promise<BalanceInfo> {\n const now = Date.now();\n\n // Use cache if valid\n if (this.cachedBalance !== null && now - this.cachedAt < CACHE_TTL_MS) {\n return this.buildInfo(this.cachedBalance);\n }\n\n // Fetch from RPC\n const balance = await this.fetchBalance();\n this.cachedBalance = balance;\n this.cachedAt = now;\n\n return this.buildInfo(balance);\n }\n\n /**\n * Check if balance is sufficient for an estimated cost.\n *\n * @param estimatedCostMicros - Estimated cost in USDC smallest unit (6 decimals)\n */\n async checkSufficient(estimatedCostMicros: bigint): Promise<SufficiencyResult> {\n const info = await this.checkBalance();\n\n if (info.balance >= estimatedCostMicros) {\n return { sufficient: true, info };\n }\n\n const shortfall = estimatedCostMicros - info.balance;\n return {\n sufficient: false,\n info,\n shortfall: this.formatUSDC(shortfall),\n };\n }\n\n /**\n * Optimistically deduct estimated cost from cached balance.\n * Call this after a successful payment to keep cache accurate.\n *\n * @param amountMicros - Amount to deduct in USDC smallest unit\n */\n deductEstimated(amountMicros: bigint): void {\n if (this.cachedBalance !== null && this.cachedBalance >= amountMicros) {\n this.cachedBalance -= amountMicros;\n }\n }\n\n /**\n * Invalidate cache, forcing next checkBalance() to fetch from RPC.\n * Call this after a payment failure to get accurate balance.\n */\n invalidate(): void {\n this.cachedBalance = null;\n this.cachedAt = 0;\n }\n\n /**\n * Force refresh balance from RPC (ignores cache).\n */\n async refresh(): Promise<BalanceInfo> {\n this.invalidate();\n return this.checkBalance();\n }\n\n /**\n * Format USDC amount (in micros) as \"$X.XX\".\n */\n formatUSDC(amountMicros: bigint): string {\n // USDC has 6 decimals\n const dollars = Number(amountMicros) / 1_000_000;\n return `$${dollars.toFixed(2)}`;\n }\n\n /**\n * Get the wallet address being monitored.\n */\n getWalletAddress(): string {\n return this.walletAddress;\n }\n\n /** Fetch balance from RPC */\n private async fetchBalance(): Promise<bigint> {\n try {\n const balance = await this.client.readContract({\n address: USDC_BASE,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.walletAddress],\n });\n return balance;\n } catch (error) {\n // Throw typed error instead of silently returning 0\n // This allows callers to distinguish \"node down\" from \"wallet empty\"\n throw new RpcError(error instanceof Error ? error.message : \"Unknown error\", error);\n }\n }\n\n /** Build BalanceInfo from raw balance */\n private buildInfo(balance: bigint): BalanceInfo {\n return {\n balance,\n balanceUSD: this.formatUSDC(balance),\n isLow: balance < BALANCE_THRESHOLDS.LOW_BALANCE_MICROS,\n isEmpty: balance < BALANCE_THRESHOLDS.ZERO_THRESHOLD,\n walletAddress: this.walletAddress,\n };\n }\n}\n","/**\n * Typed Error Classes for ClawRouter\n *\n * Provides structured errors for balance-related failures with\n * all necessary information for user-friendly error messages.\n */\n\n/**\n * Thrown when wallet has insufficient USDC balance for a request.\n */\nexport class InsufficientFundsError extends Error {\n readonly code = \"INSUFFICIENT_FUNDS\" as const;\n readonly currentBalanceUSD: string;\n readonly requiredUSD: string;\n readonly walletAddress: string;\n\n constructor(opts: { currentBalanceUSD: string; requiredUSD: string; walletAddress: string }) {\n super(\n `Insufficient USDC balance. Current: ${opts.currentBalanceUSD}, Required: ${opts.requiredUSD}. Fund wallet: ${opts.walletAddress}`,\n );\n this.name = \"InsufficientFundsError\";\n this.currentBalanceUSD = opts.currentBalanceUSD;\n this.requiredUSD = opts.requiredUSD;\n this.walletAddress = opts.walletAddress;\n }\n}\n\n/**\n * Thrown when wallet has no USDC balance (or effectively zero).\n */\nexport class EmptyWalletError extends Error {\n readonly code = \"EMPTY_WALLET\" as const;\n readonly walletAddress: string;\n\n constructor(walletAddress: string) {\n super(`No USDC balance. Fund wallet to use ClawRouter: ${walletAddress}`);\n this.name = \"EmptyWalletError\";\n this.walletAddress = walletAddress;\n }\n}\n\n/**\n * Type guard to check if an error is InsufficientFundsError.\n */\nexport function isInsufficientFundsError(error: unknown): error is InsufficientFundsError {\n return error instanceof Error && (error as InsufficientFundsError).code === \"INSUFFICIENT_FUNDS\";\n}\n\n/**\n * Type guard to check if an error is EmptyWalletError.\n */\nexport function isEmptyWalletError(error: unknown): error is EmptyWalletError {\n return error instanceof Error && (error as EmptyWalletError).code === \"EMPTY_WALLET\";\n}\n\n/**\n * Type guard to check if an error is a balance-related error.\n */\nexport function isBalanceError(error: unknown): error is InsufficientFundsError | EmptyWalletError {\n return isInsufficientFundsError(error) || isEmptyWalletError(error);\n}\n\n/**\n * Thrown when RPC call fails (network error, node down, etc).\n * Distinguishes infrastructure failures from actual empty wallets.\n */\nexport class RpcError extends Error {\n readonly code = \"RPC_ERROR\" as const;\n readonly originalError: unknown;\n\n constructor(message: string, originalError?: unknown) {\n super(`RPC error: ${message}. Check network connectivity.`);\n this.name = \"RpcError\";\n this.originalError = originalError;\n }\n}\n\n/**\n * Type guard to check if an error is RpcError.\n */\nexport function isRpcError(error: unknown): error is RpcError {\n return error instanceof Error && (error as RpcError).code === \"RPC_ERROR\";\n}\n","/**\n * BlockRun Auth Methods for OpenClaw\n *\n * Provides wallet-based authentication for the BlockRun provider.\n * Operators configure their wallet private key, which is used to\n * sign x402 micropayments for LLM inference.\n *\n * Three methods:\n * 1. Auto-generate — create a new wallet on first run, save to ~/.openclaw/blockrun/wallet.key\n * 2. Environment variable — read from BLOCKRUN_WALLET_KEY\n * 3. Manual input — operator enters private key via wizard\n */\n\nimport { writeFile, readFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { generatePrivateKey, privateKeyToAccount } from \"viem/accounts\";\nimport type { ProviderAuthMethod, ProviderAuthContext, ProviderAuthResult } from \"./types.js\";\n\nconst WALLET_DIR = join(homedir(), \".openclaw\", \"blockrun\");\nconst WALLET_FILE = join(WALLET_DIR, \"wallet.key\");\n\n/**\n * Try to load a previously auto-generated wallet key from disk.\n */\nasync function loadSavedWallet(): Promise<string | undefined> {\n try {\n const key = (await readFile(WALLET_FILE, \"utf-8\")).trim();\n if (key.startsWith(\"0x\") && key.length === 66) return key;\n } catch {\n // File doesn't exist yet\n }\n return undefined;\n}\n\n/**\n * Generate a new wallet, save to disk, return the private key.\n */\nasync function generateAndSaveWallet(): Promise<{ key: string; address: string }> {\n const key = generatePrivateKey();\n const account = privateKeyToAccount(key);\n await mkdir(WALLET_DIR, { recursive: true });\n await writeFile(WALLET_FILE, key + \"\\n\", { mode: 0o600 });\n return { key, address: account.address };\n}\n\n/**\n * Resolve wallet key: load saved → env var → auto-generate.\n * Called by index.ts before the auth wizard runs.\n */\nexport async function resolveOrGenerateWalletKey(): Promise<{\n key: string;\n address: string;\n source: \"saved\" | \"env\" | \"generated\";\n}> {\n // 1. Previously saved wallet\n const saved = await loadSavedWallet();\n if (saved) {\n const account = privateKeyToAccount(saved as `0x${string}`);\n return { key: saved, address: account.address, source: \"saved\" };\n }\n\n // 2. Environment variable\n const envKey = process.env.BLOCKRUN_WALLET_KEY;\n if (typeof envKey === \"string\" && envKey.startsWith(\"0x\") && envKey.length === 66) {\n const account = privateKeyToAccount(envKey as `0x${string}`);\n return { key: envKey, address: account.address, source: \"env\" };\n }\n\n // 3. Auto-generate\n const { key, address } = await generateAndSaveWallet();\n return { key, address, source: \"generated\" };\n}\n\n/**\n * Auth method: operator enters their wallet private key directly.\n */\nexport const walletKeyAuth: ProviderAuthMethod = {\n id: \"wallet-key\",\n label: \"Wallet Private Key\",\n hint: \"Enter your EVM wallet private key (0x...) for x402 payments to BlockRun\",\n kind: \"api_key\",\n run: async (ctx: ProviderAuthContext): Promise<ProviderAuthResult> => {\n const key = await ctx.prompter.text({\n message: \"Enter your wallet private key (0x...)\",\n validate: (value: string) => {\n const trimmed = value.trim();\n if (!trimmed.startsWith(\"0x\")) return \"Key must start with 0x\";\n if (trimmed.length !== 66) return \"Key must be 66 characters (0x + 64 hex)\";\n if (!/^0x[0-9a-fA-F]{64}$/.test(trimmed)) return \"Key must be valid hex\";\n return undefined;\n },\n });\n\n if (!key || typeof key !== \"string\") {\n throw new Error(\"Wallet key is required\");\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\n \"Wallet key stored securely in OpenClaw credentials.\",\n \"Your wallet signs x402 USDC payments on Base for each LLM call.\",\n \"Fund your wallet with USDC on Base to start using BlockRun models.\",\n ],\n };\n },\n};\n\n/**\n * Auth method: read wallet key from BLOCKRUN_WALLET_KEY environment variable.\n */\nexport const envKeyAuth: ProviderAuthMethod = {\n id: \"env-key\",\n label: \"Environment Variable\",\n hint: \"Use BLOCKRUN_WALLET_KEY environment variable\",\n kind: \"api_key\",\n run: async (): Promise<ProviderAuthResult> => {\n const key = process.env.BLOCKRUN_WALLET_KEY;\n\n if (!key) {\n throw new Error(\n \"BLOCKRUN_WALLET_KEY environment variable is not set. \" +\n \"Set it to your EVM wallet private key (0x...).\",\n );\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\"Using wallet key from BLOCKRUN_WALLET_KEY environment variable.\"],\n };\n },\n};\n","/**\n * @blockrun/clawrouter\n *\n * Smart LLM router for OpenClaw — 30+ models, x402 micropayments, 78% cost savings.\n * Routes each request to the cheapest model that can handle it.\n *\n * Usage:\n * # Install the plugin\n * openclaw plugin install @blockrun/clawrouter\n *\n * # Fund your wallet with USDC on Base (address printed on install)\n *\n * # Use smart routing (auto-picks cheapest model)\n * openclaw models set blockrun/auto\n *\n * # Or use any specific BlockRun model\n * openclaw models set openai/gpt-5.2\n */\n\nimport type { OpenClawPluginDefinition, OpenClawPluginApi } from \"./types.js\";\nimport { blockrunProvider, setActiveProxy } from \"./provider.js\";\nimport { startProxy } from \"./proxy.js\";\nimport { resolveOrGenerateWalletKey } from \"./auth.js\";\nimport type { RoutingConfig } from \"./router/index.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { OPENCLAW_MODELS } from \"./models.js\";\nimport { readFileSync, writeFileSync, existsSync, readdirSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * Inject BlockRun models config into OpenClaw config file.\n * This is required because registerProvider() alone doesn't make models available.\n */\nfunction injectModelsConfig(logger: { info: (msg: string) => void }): void {\n const configPath = join(homedir(), \".openclaw\", \"openclaw.json\");\n if (!existsSync(configPath)) {\n logger.info(\"OpenClaw config not found, skipping models injection\");\n return;\n }\n\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n\n // Check if already configured\n if (config.models?.providers?.blockrun) {\n return; // Already configured\n }\n\n // Inject models config\n if (!config.models) config.models = {};\n if (!config.models.providers) config.models.providers = {};\n\n config.models.providers.blockrun = {\n baseUrl: \"http://127.0.0.1:8402/v1\",\n api: \"openai-completions\",\n models: OPENCLAW_MODELS,\n };\n\n writeFileSync(configPath, JSON.stringify(config, null, 2));\n logger.info(\"Injected BlockRun models into OpenClaw config\");\n } catch {\n // Silently fail — config injection is best-effort\n }\n}\n\n/**\n * Inject dummy auth profile for BlockRun into agent auth stores.\n * OpenClaw's agent system looks for auth credentials even if provider has auth: [].\n * We inject a placeholder so the lookup succeeds (proxy handles real auth internally).\n */\nfunction injectAuthProfile(logger: { info: (msg: string) => void }): void {\n const agentsDir = join(homedir(), \".openclaw\", \"agents\");\n\n // Create agents directory if it doesn't exist\n if (!existsSync(agentsDir)) {\n try {\n mkdirSync(agentsDir, { recursive: true });\n } catch (err) {\n logger.info(`Could not create agents dir: ${err instanceof Error ? err.message : String(err)}`);\n return;\n }\n }\n\n try {\n // Find all agent directories\n let agents = readdirSync(agentsDir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n\n // Always ensure \"main\" agent has auth (most common agent)\n if (!agents.includes(\"main\")) {\n agents = [\"main\", ...agents];\n }\n\n for (const agentId of agents) {\n const authDir = join(agentsDir, agentId, \"agent\");\n const authPath = join(authDir, \"auth-profiles.json\");\n\n // Create agent dir if needed\n if (!existsSync(authDir)) {\n try {\n mkdirSync(authDir, { recursive: true });\n } catch {\n continue; // Skip if we can't create the dir\n }\n }\n\n // Load or create auth-profiles.json\n let authProfiles: Record<string, unknown> = {};\n if (existsSync(authPath)) {\n try {\n authProfiles = JSON.parse(readFileSync(authPath, \"utf-8\"));\n } catch {\n authProfiles = {};\n }\n }\n\n // Check if blockrun auth already exists\n if (authProfiles.blockrun) {\n continue; // Already configured\n }\n\n // Inject placeholder auth for blockrun\n // The proxy handles real x402 auth internally, this just satisfies OpenClaw's lookup\n authProfiles.blockrun = {\n profileId: \"default\",\n credential: {\n apiKey: \"x402-proxy-handles-auth\",\n },\n };\n\n try {\n writeFileSync(authPath, JSON.stringify(authProfiles, null, 2));\n logger.info(`Injected BlockRun auth profile for agent: ${agentId}`);\n } catch (err) {\n logger.info(`Could not inject auth for ${agentId}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n } catch (err) {\n logger.info(`Auth injection failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\n/**\n * Start the x402 proxy in the background.\n * Called from register() because OpenClaw's loader only invokes register(),\n * treating activate() as an alias (def.register ?? def.activate).\n */\nasync function startProxyInBackground(api: OpenClawPluginApi): Promise<void> {\n // Resolve wallet key: saved file → env var → auto-generate\n const { key: walletKey, address, source } = await resolveOrGenerateWalletKey();\n\n // Log wallet source\n if (source === \"generated\") {\n api.logger.info(`Generated new wallet: ${address}`);\n api.logger.info(`Fund with USDC on Base to start using ClawRouter.`);\n } else if (source === \"saved\") {\n api.logger.info(`Using saved wallet: ${address}`);\n } else {\n api.logger.info(`Using wallet from BLOCKRUN_WALLET_KEY: ${address}`);\n }\n\n // --- Startup balance check ---\n const startupMonitor = new BalanceMonitor(address);\n try {\n const startupBalance = await startupMonitor.checkBalance();\n if (startupBalance.isEmpty) {\n api.logger.warn(`[!] No USDC balance. Fund wallet to use ClawRouter: ${address}`);\n } else if (startupBalance.isLow) {\n api.logger.warn(\n `[!] Low balance: ${startupBalance.balanceUSD} remaining. Fund wallet: ${address}`,\n );\n } else {\n api.logger.info(`Wallet balance: ${startupBalance.balanceUSD}`);\n }\n } catch (err) {\n api.logger.warn(\n `Could not check wallet balance: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n // Resolve routing config overrides from plugin config\n const routingConfig = api.pluginConfig?.routing as Partial<RoutingConfig> | undefined;\n\n const proxy = await startProxy({\n walletKey,\n routingConfig,\n onReady: (port) => {\n api.logger.info(`BlockRun x402 proxy listening on port ${port}`);\n },\n onError: (error) => {\n api.logger.error(`BlockRun proxy error: ${error.message}`);\n },\n onRouted: (decision) => {\n const cost = decision.costEstimate.toFixed(4);\n const saved = (decision.savings * 100).toFixed(0);\n api.logger.info(`${decision.model} $${cost} (saved ${saved}%)`);\n },\n onLowBalance: (info) => {\n api.logger.warn(`[!] Low balance: ${info.balanceUSD}. Fund wallet: ${info.walletAddress}`);\n },\n onInsufficientFunds: (info) => {\n api.logger.error(\n `[!] Insufficient funds. Balance: ${info.balanceUSD}, Needed: ${info.requiredUSD}. Fund wallet: ${info.walletAddress}`,\n );\n },\n });\n\n setActiveProxy(proxy);\n api.logger.info(`BlockRun provider active — ${proxy.baseUrl}/v1 (smart routing enabled)`);\n}\n\nconst plugin: OpenClawPluginDefinition = {\n id: \"clawrouter\",\n name: \"ClawRouter\",\n description: \"Smart LLM router — 30+ models, x402 micropayments, 78% cost savings\",\n version: \"0.3.11\",\n\n register(api: OpenClawPluginApi) {\n // Register BlockRun as a provider (sync — available immediately)\n api.registerProvider(blockrunProvider);\n\n // Inject models config into OpenClaw config file\n // This persists the config so models are recognized on restart\n injectModelsConfig(api.logger);\n\n // Inject dummy auth profiles into agent auth stores\n // OpenClaw's agent system looks for auth even if provider has auth: []\n injectAuthProfile(api.logger);\n\n // Also set runtime config for immediate availability\n if (!api.config.models) {\n api.config.models = { providers: {} };\n }\n if (!api.config.models.providers) {\n api.config.models.providers = {};\n }\n api.config.models.providers.blockrun = {\n baseUrl: \"http://127.0.0.1:8402/v1\",\n api: \"openai-completions\",\n models: OPENCLAW_MODELS,\n };\n\n api.logger.info(\"BlockRun provider registered (30+ models via x402)\");\n\n // Start x402 proxy in background (fire-and-forget)\n // OpenClaw only calls register(), not activate() — so all init goes here.\n // The loader ignores async returns, but the proxy starts in the background\n // and setActiveProxy() makes it available to the provider once ready.\n startProxyInBackground(api).catch((err) => {\n api.logger.error(\n `Failed to start BlockRun proxy: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n },\n};\n\nexport default plugin;\n\n// Re-export for programmatic use\nexport { startProxy } from \"./proxy.js\";\nexport type { ProxyOptions, ProxyHandle, LowBalanceInfo, InsufficientFundsInfo } from \"./proxy.js\";\nexport { blockrunProvider } from \"./provider.js\";\nexport { OPENCLAW_MODELS, BLOCKRUN_MODELS, buildProviderModels } from \"./models.js\";\nexport { route, DEFAULT_ROUTING_CONFIG } from \"./router/index.js\";\nexport type { RoutingDecision, RoutingConfig, Tier } from \"./router/index.js\";\nexport { logUsage } from \"./logger.js\";\nexport type { UsageEntry } from \"./logger.js\";\nexport { RequestDeduplicator } from \"./dedup.js\";\nexport type { CachedResponse } from \"./dedup.js\";\nexport { PaymentCache } from \"./payment-cache.js\";\nexport type { CachedPaymentParams } from \"./payment-cache.js\";\nexport { createPaymentFetch } from \"./x402.js\";\nexport type { PreAuthParams, PaymentFetchResult } from \"./x402.js\";\nexport { BalanceMonitor, BALANCE_THRESHOLDS } from \"./balance.js\";\nexport type { BalanceInfo, SufficiencyResult } from \"./balance.js\";\nexport {\n InsufficientFundsError,\n EmptyWalletError,\n RpcError,\n isInsufficientFundsError,\n isEmptyWalletError,\n isBalanceError,\n isRpcError,\n} from \"./errors.js\";\nexport { fetchWithRetry, isRetryable, DEFAULT_RETRY_CONFIG } from \"./retry.js\";\nexport type { RetryConfig } from \"./retry.js\";\n","/**\n * Retry Logic for ClawRouter\n *\n * Provides fetch wrapper with exponential backoff for transient errors.\n * Retries on 429 (rate limit), 502, 503, 504 (server errors).\n */\n\n/** Configuration for retry behavior */\nexport type RetryConfig = {\n /** Maximum number of retries (default: 2) */\n maxRetries: number;\n /** Base delay in ms for exponential backoff (default: 500) */\n baseDelayMs: number;\n /** HTTP status codes that trigger a retry (default: [429, 502, 503, 504]) */\n retryableCodes: number[];\n};\n\n/** Default retry configuration */\nexport const DEFAULT_RETRY_CONFIG: RetryConfig = {\n maxRetries: 2,\n baseDelayMs: 500,\n retryableCodes: [429, 502, 503, 504],\n};\n\n/** Sleep for a given number of milliseconds */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Wrap a fetch-like function with retry logic and exponential backoff.\n *\n * @param fetchFn - The fetch function to wrap (can be standard fetch or x402 payFetch)\n * @param url - URL to fetch\n * @param init - Fetch init options\n * @param config - Retry configuration (optional, uses defaults)\n * @returns Response from successful fetch or last failed attempt\n *\n * @example\n * ```typescript\n * const response = await fetchWithRetry(\n * fetch,\n * \"https://api.example.com/endpoint\",\n * { method: \"POST\", body: JSON.stringify(data) },\n * { maxRetries: 3 }\n * );\n * ```\n */\nexport async function fetchWithRetry(\n fetchFn: (url: string, init?: RequestInit) => Promise<Response>,\n url: string,\n init?: RequestInit,\n config?: Partial<RetryConfig>,\n): Promise<Response> {\n const cfg: RetryConfig = {\n ...DEFAULT_RETRY_CONFIG,\n ...config,\n };\n\n let lastError: Error | undefined;\n let lastResponse: Response | undefined;\n\n for (let attempt = 0; attempt <= cfg.maxRetries; attempt++) {\n try {\n const response = await fetchFn(url, init);\n\n // Success or non-retryable status — return immediately\n if (!cfg.retryableCodes.includes(response.status)) {\n return response;\n }\n\n // Retryable status — save response and maybe retry\n lastResponse = response;\n\n // Check for Retry-After header (common with 429)\n const retryAfter = response.headers.get(\"retry-after\");\n let delay: number;\n\n if (retryAfter) {\n // Retry-After can be seconds or HTTP-date\n const seconds = parseInt(retryAfter, 10);\n delay = isNaN(seconds) ? cfg.baseDelayMs * Math.pow(2, attempt) : seconds * 1000;\n } else {\n delay = cfg.baseDelayMs * Math.pow(2, attempt);\n }\n\n // Only retry if we have attempts left\n if (attempt < cfg.maxRetries) {\n await sleep(delay);\n }\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n\n // Network errors are retryable\n if (attempt < cfg.maxRetries) {\n const delay = cfg.baseDelayMs * Math.pow(2, attempt);\n await sleep(delay);\n }\n }\n }\n\n // All retries exhausted — return last response or throw last error\n if (lastResponse) {\n return lastResponse;\n }\n\n throw lastError ?? new Error(\"Max retries exceeded\");\n}\n\n/**\n * Check if an error or response indicates a retryable condition.\n */\nexport function isRetryable(\n errorOrResponse: Error | Response,\n config?: Partial<RetryConfig>,\n): boolean {\n const retryableCodes = config?.retryableCodes ?? DEFAULT_RETRY_CONFIG.retryableCodes;\n\n if (errorOrResponse instanceof Response) {\n return retryableCodes.includes(errorOrResponse.status);\n }\n\n // Network errors are generally retryable\n const message = errorOrResponse.message.toLowerCase();\n return (\n message.includes(\"network\") ||\n message.includes(\"timeout\") ||\n message.includes(\"econnreset\") ||\n message.includes(\"econnrefused\") ||\n message.includes(\"socket hang up\")\n );\n}\n"],"mappings":"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","names":["privateKeyToAccount","response","paymentHeader","confidence","DEFAULT_TTL_MS","USDC_BASE","privateKeyToAccount","mkdir","join","homedir","privateKeyToAccount","homedir","join","join","homedir"]}
|
package/package.json
CHANGED