@blockrun/clawrouter 0.9.37 → 0.9.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +60 -49
- package/dist/cli.js.map +1 -1
- package/dist/index.js +73 -53
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1201,8 +1201,6 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1201
1201
|
primary: "moonshot/kimi-k2.5",
|
|
1202
1202
|
// $0.50/$2.40 - best quality/price for simple tasks
|
|
1203
1203
|
fallback: [
|
|
1204
|
-
"minimax/minimax-m2.5",
|
|
1205
|
-
// $0.30/$1.20 - cheap with reasoning
|
|
1206
1204
|
"google/gemini-2.5-flash",
|
|
1207
1205
|
// 1M context, cost-effective
|
|
1208
1206
|
"nvidia/gpt-oss-120b",
|
|
@@ -1214,8 +1212,6 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1214
1212
|
primary: "xai/grok-code-fast-1",
|
|
1215
1213
|
// Code specialist, $0.20/$1.50
|
|
1216
1214
|
fallback: [
|
|
1217
|
-
"minimax/minimax-m2.5",
|
|
1218
|
-
// $0.30/$1.20 - cheap with reasoning
|
|
1219
1215
|
"google/gemini-2.5-flash",
|
|
1220
1216
|
// 1M context, cost-effective
|
|
1221
1217
|
"deepseek/deepseek-chat",
|
|
@@ -1230,10 +1226,7 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1230
1226
|
"google/gemini-2.5-flash",
|
|
1231
1227
|
// CRITICAL: 1M context, cheap failsafe before expensive models
|
|
1232
1228
|
"google/gemini-2.5-pro",
|
|
1233
|
-
"minimax/minimax-m2.5",
|
|
1234
|
-
// $0.30/$1.20 - cheap with reasoning
|
|
1235
1229
|
"deepseek/deepseek-chat",
|
|
1236
|
-
// Another cheap option
|
|
1237
1230
|
"xai/grok-4-0709",
|
|
1238
1231
|
"openai/gpt-5.2",
|
|
1239
1232
|
// Newer and cheaper input than gpt-4o
|
|
@@ -1245,8 +1238,6 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1245
1238
|
primary: "xai/grok-4-1-fast-reasoning",
|
|
1246
1239
|
// Upgraded Grok 4.1 reasoning $0.20/$0.50
|
|
1247
1240
|
fallback: [
|
|
1248
|
-
"minimax/minimax-m2.5",
|
|
1249
|
-
// $0.30/$1.20 - reasoning capable
|
|
1250
1241
|
"deepseek/deepseek-reasoner",
|
|
1251
1242
|
// Cheap reasoning model
|
|
1252
1243
|
"openai/o4-mini",
|
|
@@ -1260,22 +1251,22 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1260
1251
|
SIMPLE: {
|
|
1261
1252
|
primary: "nvidia/gpt-oss-120b",
|
|
1262
1253
|
// FREE! $0.00/$0.00
|
|
1263
|
-
fallback: ["google/gemini-2.5-flash", "deepseek/deepseek-chat"
|
|
1254
|
+
fallback: ["google/gemini-2.5-flash", "deepseek/deepseek-chat"]
|
|
1264
1255
|
},
|
|
1265
1256
|
MEDIUM: {
|
|
1266
1257
|
primary: "google/gemini-2.5-flash",
|
|
1267
1258
|
// $0.15/$0.60 - cheapest capable
|
|
1268
|
-
fallback: ["deepseek/deepseek-chat", "nvidia/gpt-oss-120b"
|
|
1259
|
+
fallback: ["deepseek/deepseek-chat", "nvidia/gpt-oss-120b"]
|
|
1269
1260
|
},
|
|
1270
1261
|
COMPLEX: {
|
|
1271
1262
|
primary: "google/gemini-2.5-flash",
|
|
1272
1263
|
// $0.15/$0.60 - 1M context handles complexity
|
|
1273
|
-
fallback: ["deepseek/deepseek-chat", "xai/grok-4-0709"
|
|
1264
|
+
fallback: ["deepseek/deepseek-chat", "xai/grok-4-0709"]
|
|
1274
1265
|
},
|
|
1275
1266
|
REASONING: {
|
|
1276
1267
|
primary: "xai/grok-4-1-fast-reasoning",
|
|
1277
|
-
// $0.20/$0.50
|
|
1278
|
-
fallback: ["deepseek/deepseek-reasoner"
|
|
1268
|
+
// $0.20/$0.50
|
|
1269
|
+
fallback: ["deepseek/deepseek-reasoner"]
|
|
1279
1270
|
}
|
|
1280
1271
|
},
|
|
1281
1272
|
// Premium tier configs - best quality (blockrun/premium)
|
|
@@ -1325,32 +1316,18 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1325
1316
|
SIMPLE: {
|
|
1326
1317
|
primary: "moonshot/kimi-k2.5",
|
|
1327
1318
|
// Cheaper than Haiku ($0.5/$2.4 vs $1/$5), larger context
|
|
1328
|
-
fallback: [
|
|
1329
|
-
"minimax/minimax-m2.5",
|
|
1330
|
-
// $0.30/$1.20 - agentic capable, cheaper than kimi
|
|
1331
|
-
"claude-haiku-4.5",
|
|
1332
|
-
"xai/grok-4-1-fast-non-reasoning",
|
|
1333
|
-
"openai/gpt-4o-mini"
|
|
1334
|
-
]
|
|
1319
|
+
fallback: ["claude-haiku-4.5", "xai/grok-4-1-fast-non-reasoning", "openai/gpt-4o-mini"]
|
|
1335
1320
|
},
|
|
1336
1321
|
MEDIUM: {
|
|
1337
1322
|
primary: "xai/grok-code-fast-1",
|
|
1338
1323
|
// Code specialist for agentic coding
|
|
1339
|
-
fallback: [
|
|
1340
|
-
"minimax/minimax-m2.5",
|
|
1341
|
-
// $0.30/$1.20 - agentic capable
|
|
1342
|
-
"moonshot/kimi-k2.5",
|
|
1343
|
-
"claude-haiku-4.5",
|
|
1344
|
-
"claude-sonnet-4"
|
|
1345
|
-
]
|
|
1324
|
+
fallback: ["moonshot/kimi-k2.5", "claude-haiku-4.5", "claude-sonnet-4"]
|
|
1346
1325
|
},
|
|
1347
1326
|
COMPLEX: {
|
|
1348
1327
|
primary: "claude-sonnet-4",
|
|
1349
1328
|
fallback: [
|
|
1350
1329
|
"claude-opus-4",
|
|
1351
1330
|
// Latest Opus - best agentic
|
|
1352
|
-
"minimax/minimax-m2.5",
|
|
1353
|
-
// $0.30/$1.20 - cheap agentic fallback
|
|
1354
1331
|
"openai/gpt-5.2",
|
|
1355
1332
|
"google/gemini-3-pro-preview",
|
|
1356
1333
|
"xai/grok-4-0709"
|
|
@@ -1359,13 +1336,7 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1359
1336
|
REASONING: {
|
|
1360
1337
|
primary: "claude-sonnet-4",
|
|
1361
1338
|
// Strong tool use + reasoning for agentic tasks
|
|
1362
|
-
fallback: [
|
|
1363
|
-
"claude-opus-4",
|
|
1364
|
-
"minimax/minimax-m2.5",
|
|
1365
|
-
// $0.30/$1.20 - reasoning + agentic
|
|
1366
|
-
"xai/grok-4-1-fast-reasoning",
|
|
1367
|
-
"deepseek/deepseek-reasoner"
|
|
1368
|
-
]
|
|
1339
|
+
fallback: ["claude-opus-4", "xai/grok-4-1-fast-reasoning", "deepseek/deepseek-reasoner"]
|
|
1369
1340
|
}
|
|
1370
1341
|
},
|
|
1371
1342
|
overrides: {
|
|
@@ -1913,7 +1884,23 @@ async function logUsage(entry) {
|
|
|
1913
1884
|
}
|
|
1914
1885
|
|
|
1915
1886
|
// src/stats.ts
|
|
1916
|
-
import {
|
|
1887
|
+
import { readdir } from "fs/promises";
|
|
1888
|
+
|
|
1889
|
+
// src/fs-read.ts
|
|
1890
|
+
import { open } from "fs/promises";
|
|
1891
|
+
import { openSync, readSync, closeSync, fstatSync } from "fs";
|
|
1892
|
+
async function readTextFile(filePath) {
|
|
1893
|
+
const fh = await open(filePath, "r");
|
|
1894
|
+
try {
|
|
1895
|
+
const buf = Buffer.alloc((await fh.stat()).size);
|
|
1896
|
+
await fh.read(buf, 0, buf.length, 0);
|
|
1897
|
+
return buf.toString("utf-8");
|
|
1898
|
+
} finally {
|
|
1899
|
+
await fh.close();
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
// src/stats.ts
|
|
1917
1904
|
import { join as join3 } from "path";
|
|
1918
1905
|
import { homedir as homedir2 } from "os";
|
|
1919
1906
|
|
|
@@ -1932,7 +1919,7 @@ var USER_AGENT = `clawrouter/${VERSION}`;
|
|
|
1932
1919
|
var LOG_DIR2 = join3(homedir2(), ".openclaw", "blockrun", "logs");
|
|
1933
1920
|
async function parseLogFile(filePath) {
|
|
1934
1921
|
try {
|
|
1935
|
-
const content = await
|
|
1922
|
+
const content = await readTextFile(filePath);
|
|
1936
1923
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
1937
1924
|
return lines.map((line) => {
|
|
1938
1925
|
const entry = JSON.parse(line);
|
|
@@ -3621,6 +3608,7 @@ var ROUTING_PROFILES = /* @__PURE__ */ new Set([
|
|
|
3621
3608
|
]);
|
|
3622
3609
|
var FREE_MODEL = "nvidia/gpt-oss-120b";
|
|
3623
3610
|
var MAX_MESSAGES = 200;
|
|
3611
|
+
var CONTEXT_LIMIT_KB = 5120;
|
|
3624
3612
|
var HEARTBEAT_INTERVAL_MS = 2e3;
|
|
3625
3613
|
var DEFAULT_REQUEST_TIMEOUT_MS = 18e4;
|
|
3626
3614
|
var MAX_FALLBACK_ATTEMPTS = 5;
|
|
@@ -4007,15 +3995,28 @@ function normalizeMessagesForThinking(messages) {
|
|
|
4007
3995
|
return hasChanges ? normalized : messages;
|
|
4008
3996
|
}
|
|
4009
3997
|
function truncateMessages(messages) {
|
|
4010
|
-
if (!messages || messages.length <= MAX_MESSAGES)
|
|
3998
|
+
if (!messages || messages.length <= MAX_MESSAGES) {
|
|
3999
|
+
return {
|
|
4000
|
+
messages,
|
|
4001
|
+
wasTruncated: false,
|
|
4002
|
+
originalCount: messages?.length ?? 0,
|
|
4003
|
+
truncatedCount: messages?.length ?? 0
|
|
4004
|
+
};
|
|
4005
|
+
}
|
|
4011
4006
|
const systemMsgs = messages.filter((m) => m.role === "system");
|
|
4012
4007
|
const conversationMsgs = messages.filter((m) => m.role !== "system");
|
|
4013
4008
|
const maxConversation = MAX_MESSAGES - systemMsgs.length;
|
|
4014
4009
|
const truncatedConversation = conversationMsgs.slice(-maxConversation);
|
|
4010
|
+
const result = [...systemMsgs, ...truncatedConversation];
|
|
4015
4011
|
console.log(
|
|
4016
|
-
`[ClawRouter] Truncated messages: ${messages.length} \u2192 ${
|
|
4012
|
+
`[ClawRouter] Truncated messages: ${messages.length} \u2192 ${result.length} (kept ${systemMsgs.length} system + ${truncatedConversation.length} recent)`
|
|
4017
4013
|
);
|
|
4018
|
-
return
|
|
4014
|
+
return {
|
|
4015
|
+
messages: result,
|
|
4016
|
+
wasTruncated: true,
|
|
4017
|
+
originalCount: messages.length,
|
|
4018
|
+
truncatedCount: result.length
|
|
4019
|
+
};
|
|
4019
4020
|
}
|
|
4020
4021
|
var KIMI_BLOCK_RE = /<[||][^<>]*begin[^<>]*[||]>[\s\S]*?<[||][^<>]*end[^<>]*[||]>/gi;
|
|
4021
4022
|
var KIMI_TOKEN_RE = /<[||][^<>]*[||]>/g;
|
|
@@ -4348,7 +4349,8 @@ async function tryModelRequest(upstreamUrl, method, headers, body, modelId, maxT
|
|
|
4348
4349
|
parsed.messages = normalizeMessageRoles(parsed.messages);
|
|
4349
4350
|
}
|
|
4350
4351
|
if (Array.isArray(parsed.messages)) {
|
|
4351
|
-
|
|
4352
|
+
const truncationResult = truncateMessages(parsed.messages);
|
|
4353
|
+
parsed.messages = truncationResult.messages;
|
|
4352
4354
|
}
|
|
4353
4355
|
if (Array.isArray(parsed.messages)) {
|
|
4354
4356
|
parsed.messages = sanitizeToolIds(parsed.messages);
|
|
@@ -4422,6 +4424,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
4422
4424
|
bodyChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
4423
4425
|
}
|
|
4424
4426
|
let body = Buffer.concat(bodyChunks);
|
|
4427
|
+
const originalContextSizeKB = Math.ceil(body.length / 1024);
|
|
4425
4428
|
let routingDecision;
|
|
4426
4429
|
let isStreaming = false;
|
|
4427
4430
|
let modelId = "";
|
|
@@ -4529,7 +4532,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
4529
4532
|
const systemPrompt = typeof systemMsg?.content === "string" ? systemMsg.content : void 0;
|
|
4530
4533
|
const tools = parsed.tools;
|
|
4531
4534
|
const hasTools = Array.isArray(tools) && tools.length > 0;
|
|
4532
|
-
if (hasTools) {
|
|
4535
|
+
if (hasTools && tools) {
|
|
4533
4536
|
console.log(
|
|
4534
4537
|
`[ClawRouter] Tools detected (${tools.length}), agentic mode via keywords`
|
|
4535
4538
|
);
|
|
@@ -4674,7 +4677,9 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
4674
4677
|
res.writeHead(200, {
|
|
4675
4678
|
"content-type": "text/event-stream",
|
|
4676
4679
|
"cache-control": "no-cache",
|
|
4677
|
-
connection: "keep-alive"
|
|
4680
|
+
connection: "keep-alive",
|
|
4681
|
+
"x-context-used-kb": String(originalContextSizeKB),
|
|
4682
|
+
"x-context-limit-kb": String(CONTEXT_LIMIT_KB)
|
|
4678
4683
|
});
|
|
4679
4684
|
headersSentEarly = true;
|
|
4680
4685
|
safeWrite(res, ": heartbeat\n\n");
|
|
@@ -4837,7 +4842,11 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
4837
4842
|
completedAt: Date.now()
|
|
4838
4843
|
});
|
|
4839
4844
|
} else {
|
|
4840
|
-
res.writeHead(errStatus, {
|
|
4845
|
+
res.writeHead(errStatus, {
|
|
4846
|
+
"Content-Type": "application/json",
|
|
4847
|
+
"x-context-used-kb": String(originalContextSizeKB),
|
|
4848
|
+
"x-context-limit-kb": String(CONTEXT_LIMIT_KB)
|
|
4849
|
+
});
|
|
4841
4850
|
res.end(transformedErr);
|
|
4842
4851
|
deduplicator.complete(dedupKey, {
|
|
4843
4852
|
status: errStatus,
|
|
@@ -4963,6 +4972,8 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
4963
4972
|
return;
|
|
4964
4973
|
responseHeaders[key] = value;
|
|
4965
4974
|
});
|
|
4975
|
+
responseHeaders["x-context-used-kb"] = String(originalContextSizeKB);
|
|
4976
|
+
responseHeaders["x-context-limit-kb"] = String(CONTEXT_LIMIT_KB);
|
|
4966
4977
|
res.writeHead(upstream.status, responseHeaders);
|
|
4967
4978
|
if (upstream.body) {
|
|
4968
4979
|
const reader = upstream.body.getReader();
|
|
@@ -5057,7 +5068,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
5057
5068
|
}
|
|
5058
5069
|
|
|
5059
5070
|
// src/auth.ts
|
|
5060
|
-
import { writeFile,
|
|
5071
|
+
import { writeFile, mkdir as mkdir2 } from "fs/promises";
|
|
5061
5072
|
import { join as join4 } from "path";
|
|
5062
5073
|
import { homedir as homedir3 } from "os";
|
|
5063
5074
|
import { generatePrivateKey, privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
|
|
@@ -5065,7 +5076,7 @@ var WALLET_DIR = join4(homedir3(), ".openclaw", "blockrun");
|
|
|
5065
5076
|
var WALLET_FILE = join4(WALLET_DIR, "wallet.key");
|
|
5066
5077
|
async function loadSavedWallet() {
|
|
5067
5078
|
try {
|
|
5068
|
-
const key = (await
|
|
5079
|
+
const key = (await readTextFile(WALLET_FILE)).trim();
|
|
5069
5080
|
if (key.startsWith("0x") && key.length === 66) {
|
|
5070
5081
|
console.log(`[ClawRouter] \u2713 Loaded existing wallet from ${WALLET_FILE}`);
|
|
5071
5082
|
return key;
|
|
@@ -5086,7 +5097,7 @@ async function generateAndSaveWallet() {
|
|
|
5086
5097
|
await mkdir2(WALLET_DIR, { recursive: true });
|
|
5087
5098
|
await writeFile(WALLET_FILE, key + "\n", { mode: 384 });
|
|
5088
5099
|
try {
|
|
5089
|
-
const verification = (await
|
|
5100
|
+
const verification = (await readTextFile(WALLET_FILE)).trim();
|
|
5090
5101
|
if (verification !== key) {
|
|
5091
5102
|
throw new Error("Wallet file verification failed - content mismatch");
|
|
5092
5103
|
}
|