@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 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", "minimax/minimax-m2.5"]
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", "minimax/minimax-m2.5"]
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", "minimax/minimax-m2.5"]
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 - was MORE expensive than AUTO!
1278
- fallback: ["deepseek/deepseek-reasoner", "minimax/minimax-m2.5"]
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 { readFile, readdir } from "fs/promises";
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 readFile(filePath, "utf-8");
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) return 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 ${systemMsgs.length + truncatedConversation.length} (kept ${systemMsgs.length} system + ${truncatedConversation.length} recent)`
4012
+ `[ClawRouter] Truncated messages: ${messages.length} \u2192 ${result.length} (kept ${systemMsgs.length} system + ${truncatedConversation.length} recent)`
4017
4013
  );
4018
- return [...systemMsgs, ...truncatedConversation];
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
- parsed.messages = truncateMessages(parsed.messages);
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, { "Content-Type": "application/json" });
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, readFile as readFile2, mkdir as mkdir2 } from "fs/promises";
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 readFile2(WALLET_FILE, "utf-8")).trim();
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 readFile2(WALLET_FILE, "utf-8")).trim();
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
  }