@blockrun/clawrouter 0.12.93 → 0.12.94

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
@@ -45644,6 +45644,48 @@ async function getStats(days = 7) {
45644
45644
  // How many entries have valid baseline tracking
45645
45645
  };
45646
45646
  }
45647
+ async function formatRecentLogs(days = 1) {
45648
+ const logFiles = await getLogFiles();
45649
+ const filesToRead = logFiles.slice(0, days);
45650
+ const allEntries = [];
45651
+ for (const file of filesToRead) {
45652
+ const entries = await parseLogFile(join4(LOG_DIR2, file));
45653
+ allEntries.push(...entries);
45654
+ }
45655
+ allEntries.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
45656
+ const lines = [];
45657
+ lines.push("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
45658
+ lines.push(`\u2551 ClawRouter Request Log \u2014 last ${days === 1 ? "24h" : `${days} days`}`.padEnd(72) + "\u2551");
45659
+ lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2566\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2566\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2566\u2550\u2550\u2550\u2550\u2550\u2550\u2566\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
45660
+ lines.push("\u2551 Time \u2551 Model \u2551 Cost \u2551 ms \u2551 Status \u2551");
45661
+ lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256C\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256C\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256C\u2550\u2550\u2550\u2550\u2550\u2550\u256C\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
45662
+ if (allEntries.length === 0) {
45663
+ lines.push("\u2551 No requests found".padEnd(72) + "\u2551");
45664
+ }
45665
+ let totalCost = 0;
45666
+ for (const e7 of allEntries) {
45667
+ const time = e7.timestamp.slice(11, 19);
45668
+ const date = e7.timestamp.slice(5, 10);
45669
+ const displayTime = `${date} ${time}`;
45670
+ const model = e7.model.length > 24 ? e7.model.slice(0, 21) + "..." : e7.model;
45671
+ const cost = `$${e7.cost.toFixed(4)}`;
45672
+ const ms = e7.latencyMs > 9999 ? `${(e7.latencyMs / 1e3).toFixed(1)}s` : `${e7.latencyMs}ms`;
45673
+ const status = e7.status === "error" ? " ERROR " : " OK ";
45674
+ totalCost += e7.cost;
45675
+ lines.push(
45676
+ `\u2551 ${displayTime.padEnd(16)}\u2551 ${model.padEnd(24)}\u2551 ${cost.padStart(7)}\u2551 ${ms.padStart(4)}\u2551${status}\u2551`
45677
+ );
45678
+ }
45679
+ lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2569\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2569\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2569\u2550\u2550\u2550\u2550\u2550\u2550\u2569\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
45680
+ lines.push(
45681
+ `\u2551 ${allEntries.length} request${allEntries.length !== 1 ? "s" : ""} Total spent: $${totalCost.toFixed(4)}`.padEnd(72) + "\u2551"
45682
+ );
45683
+ lines.push(
45684
+ "\u2551 Logs: ~/.openclaw/blockrun/logs/ (JSONL \u2014 one entry per request)".padEnd(72) + "\u2551"
45685
+ );
45686
+ lines.push("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D");
45687
+ return lines.join("\n");
45688
+ }
45647
45689
  async function clearStats() {
45648
45690
  try {
45649
45691
  const files = await readdir(LOG_DIR2);
@@ -52439,6 +52481,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
52439
52481
  let accumulatedContent = "";
52440
52482
  let responseInputTokens;
52441
52483
  let responseOutputTokens;
52484
+ let requestHadError = false;
52442
52485
  const isChatCompletion = req.url?.includes("/chat/completions");
52443
52486
  const sessionId = getSessionId(req.headers);
52444
52487
  let effectiveSessionId = sessionId;
@@ -53703,6 +53746,7 @@ data: [DONE]
53703
53746
  const rawErrBody = lastError?.body || structuredMessage;
53704
53747
  const errStatus = lastError?.status || 502;
53705
53748
  const transformedErr = transformPaymentError(rawErrBody);
53749
+ requestHadError = true;
53706
53750
  if (headersSentEarly) {
53707
53751
  let errPayload;
53708
53752
  try {
@@ -53746,6 +53790,21 @@ data: [DONE]
53746
53790
  completedAt: Date.now()
53747
53791
  });
53748
53792
  }
53793
+ const errModel = routingDecision?.model ?? modelId;
53794
+ if (errModel) {
53795
+ const errPayment = paymentStore.getStore()?.amountUsd ?? 0;
53796
+ logUsage({
53797
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
53798
+ model: errModel,
53799
+ tier: routingDecision?.tier ?? "DIRECT",
53800
+ cost: errPayment,
53801
+ baselineCost: errPayment,
53802
+ savings: 0,
53803
+ latencyMs: Date.now() - startTime,
53804
+ status: "error"
53805
+ }).catch(() => {
53806
+ });
53807
+ }
53749
53808
  return;
53750
53809
  }
53751
53810
  const responseChunks = [];
@@ -54080,6 +54139,7 @@ data: [DONE]
54080
54139
  baselineCost: logBaseline,
54081
54140
  savings: logSavings,
54082
54141
  latencyMs: Date.now() - startTime,
54142
+ status: requestHadError ? "error" : "success",
54083
54143
  ...responseInputTokens !== void 0 && { inputTokens: responseInputTokens },
54084
54144
  ...responseOutputTokens !== void 0 && { outputTokens: responseOutputTokens }
54085
54145
  };
@@ -54692,6 +54752,7 @@ Usage:
54692
54752
  clawrouter doctor [opus] [question]
54693
54753
  clawrouter partners [test]
54694
54754
  clawrouter report [daily|weekly|monthly] [--json]
54755
+ clawrouter logs [--days <n>]
54695
54756
 
54696
54757
  Options:
54697
54758
  --version, -v Show version number
@@ -54701,6 +54762,8 @@ Options:
54701
54762
  Commands:
54702
54763
  doctor AI-powered diagnostics (default: Sonnet ~$0.003)
54703
54764
  doctor opus Use Opus for deeper analysis (~$0.01)
54765
+ logs Per-request breakdown: model, cost, latency, status
54766
+ logs --days 7 Show last 7 days of requests (default: 1 day)
54704
54767
  partners List available partner APIs with pricing
54705
54768
  partners test Test partner API endpoints (expect 402 = alive)
54706
54769
  wallet recover Restore wallet.key from mnemonic (if generated by ClawRouter)
@@ -54735,6 +54798,8 @@ function parseArgs(args) {
54735
54798
  version: false,
54736
54799
  help: false,
54737
54800
  doctor: false,
54801
+ logs: false,
54802
+ logsDays: 1,
54738
54803
  partners: false,
54739
54804
  partnersTest: false,
54740
54805
  report: false,
@@ -54752,6 +54817,12 @@ function parseArgs(args) {
54752
54817
  result.help = true;
54753
54818
  } else if (arg === "doctor" || arg === "--doctor") {
54754
54819
  result.doctor = true;
54820
+ } else if (arg === "logs") {
54821
+ result.logs = true;
54822
+ if (args[i + 1] === "--days" && args[i + 2]) {
54823
+ result.logsDays = parseInt(args[i + 2], 10) || 1;
54824
+ i += 2;
54825
+ }
54755
54826
  } else if (arg === "partners") {
54756
54827
  result.partners = true;
54757
54828
  if (args[i + 1] === "test") {
@@ -54812,6 +54883,11 @@ async function main() {
54812
54883
  await runDoctor(userQuestion, model);
54813
54884
  process.exit(0);
54814
54885
  }
54886
+ if (args.logs) {
54887
+ const output = await formatRecentLogs(args.logsDays);
54888
+ console.log(output);
54889
+ process.exit(0);
54890
+ }
54815
54891
  if (args.partners) {
54816
54892
  if (PARTNER_SERVICES.length === 0) {
54817
54893
  console.log("No partner APIs available.");