@blockrun/clawrouter 0.12.95 → 0.12.96

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.
Files changed (282) hide show
  1. package/dist/auth.d.ts +82 -0
  2. package/dist/auth.d.ts.map +1 -0
  3. package/dist/auth.js +388 -0
  4. package/dist/auth.js.map +1 -0
  5. package/dist/balance.d.ts +97 -0
  6. package/dist/balance.d.ts.map +1 -0
  7. package/dist/balance.js +157 -0
  8. package/dist/balance.js.map +1 -0
  9. package/dist/cli.d.ts +15 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +256 -54994
  12. package/dist/cli.js.map +1 -1
  13. package/dist/compression/codebook.d.ts +24 -0
  14. package/dist/compression/codebook.d.ts.map +1 -0
  15. package/dist/compression/codebook.js +119 -0
  16. package/dist/compression/codebook.js.map +1 -0
  17. package/dist/compression/index.d.ts +33 -0
  18. package/dist/compression/index.d.ts.map +1 -0
  19. package/dist/compression/index.js +246 -0
  20. package/dist/compression/index.js.map +1 -0
  21. package/dist/compression/layers/deduplication.d.ts +28 -0
  22. package/dist/compression/layers/deduplication.d.ts.map +1 -0
  23. package/dist/compression/layers/deduplication.js +101 -0
  24. package/dist/compression/layers/deduplication.js.map +1 -0
  25. package/dist/compression/layers/dictionary.d.ts +21 -0
  26. package/dist/compression/layers/dictionary.d.ts.map +1 -0
  27. package/dist/compression/layers/dictionary.js +73 -0
  28. package/dist/compression/layers/dictionary.js.map +1 -0
  29. package/dist/compression/layers/dynamic-codebook.d.ts +26 -0
  30. package/dist/compression/layers/dynamic-codebook.d.ts.map +1 -0
  31. package/dist/compression/layers/dynamic-codebook.js +149 -0
  32. package/dist/compression/layers/dynamic-codebook.js.map +1 -0
  33. package/dist/compression/layers/json-compact.d.ts +23 -0
  34. package/dist/compression/layers/json-compact.d.ts.map +1 -0
  35. package/dist/compression/layers/json-compact.js +79 -0
  36. package/dist/compression/layers/json-compact.js.map +1 -0
  37. package/dist/compression/layers/observation.d.ts +21 -0
  38. package/dist/compression/layers/observation.d.ts.map +1 -0
  39. package/dist/compression/layers/observation.js +130 -0
  40. package/dist/compression/layers/observation.js.map +1 -0
  41. package/dist/compression/layers/paths.d.ts +24 -0
  42. package/dist/compression/layers/paths.d.ts.map +1 -0
  43. package/dist/compression/layers/paths.js +110 -0
  44. package/dist/compression/layers/paths.js.map +1 -0
  45. package/dist/compression/layers/whitespace.d.ts +27 -0
  46. package/dist/compression/layers/whitespace.d.ts.map +1 -0
  47. package/dist/compression/layers/whitespace.js +60 -0
  48. package/dist/compression/layers/whitespace.js.map +1 -0
  49. package/dist/compression/types.d.ts +84 -0
  50. package/dist/compression/types.d.ts.map +1 -0
  51. package/dist/compression/types.js +27 -0
  52. package/dist/compression/types.js.map +1 -0
  53. package/dist/config.d.ts +12 -0
  54. package/dist/config.d.ts.map +1 -0
  55. package/dist/config.js +22 -0
  56. package/dist/config.js.map +1 -0
  57. package/dist/dedup.d.ts +34 -0
  58. package/dist/dedup.d.ts.map +1 -0
  59. package/dist/dedup.js +150 -0
  60. package/dist/dedup.js.map +1 -0
  61. package/dist/doctor.d.ts +8 -0
  62. package/dist/doctor.d.ts.map +1 -0
  63. package/dist/doctor.js +375 -0
  64. package/dist/doctor.js.map +1 -0
  65. package/dist/error-classification.test.d.ts +2 -0
  66. package/dist/error-classification.test.d.ts.map +1 -0
  67. package/dist/error-classification.test.js +59 -0
  68. package/dist/error-classification.test.js.map +1 -0
  69. package/dist/errors.d.ts +54 -0
  70. package/dist/errors.d.ts.map +1 -0
  71. package/dist/errors.js +85 -0
  72. package/dist/errors.js.map +1 -0
  73. package/dist/exclude-models.d.ts +28 -0
  74. package/dist/exclude-models.d.ts.map +1 -0
  75. package/dist/exclude-models.integration.test.d.ts +2 -0
  76. package/dist/exclude-models.integration.test.d.ts.map +1 -0
  77. package/dist/exclude-models.integration.test.js +46 -0
  78. package/dist/exclude-models.integration.test.js.map +1 -0
  79. package/dist/exclude-models.js +70 -0
  80. package/dist/exclude-models.js.map +1 -0
  81. package/dist/exclude-models.test.d.ts +5 -0
  82. package/dist/exclude-models.test.d.ts.map +1 -0
  83. package/dist/exclude-models.test.js +95 -0
  84. package/dist/exclude-models.test.js.map +1 -0
  85. package/dist/fs-read.d.ts +11 -0
  86. package/dist/fs-read.d.ts.map +1 -0
  87. package/dist/fs-read.js +47 -0
  88. package/dist/fs-read.js.map +1 -0
  89. package/dist/index.d.ts +34 -1368
  90. package/dist/index.d.ts.map +1 -0
  91. package/dist/index.js +1071 -56194
  92. package/dist/index.js.map +1 -1
  93. package/dist/journal.d.ts +67 -0
  94. package/dist/journal.d.ts.map +1 -0
  95. package/dist/journal.js +184 -0
  96. package/dist/journal.js.map +1 -0
  97. package/dist/journal.test.d.ts +2 -0
  98. package/dist/journal.test.d.ts.map +1 -0
  99. package/dist/journal.test.js +201 -0
  100. package/dist/journal.test.js.map +1 -0
  101. package/dist/logger.d.ts +33 -0
  102. package/dist/logger.d.ts.map +1 -0
  103. package/dist/logger.js +35 -0
  104. package/dist/logger.js.map +1 -0
  105. package/dist/models.d.ts +107 -0
  106. package/dist/models.d.ts.map +1 -0
  107. package/dist/models.js +941 -0
  108. package/dist/models.js.map +1 -0
  109. package/dist/models.test.d.ts +2 -0
  110. package/dist/models.test.d.ts.map +1 -0
  111. package/dist/models.test.js +38 -0
  112. package/dist/models.test.js.map +1 -0
  113. package/dist/partners/index.d.ts +8 -0
  114. package/dist/partners/index.d.ts.map +1 -0
  115. package/dist/partners/index.js +6 -0
  116. package/dist/partners/index.js.map +1 -0
  117. package/dist/partners/registry.d.ts +51 -0
  118. package/dist/partners/registry.d.ts.map +1 -0
  119. package/dist/partners/registry.js +256 -0
  120. package/dist/partners/registry.js.map +1 -0
  121. package/dist/partners/tools.d.ts +24 -0
  122. package/dist/partners/tools.d.ts.map +1 -0
  123. package/dist/partners/tools.js +97 -0
  124. package/dist/partners/tools.js.map +1 -0
  125. package/dist/payment-preauth.d.ts +17 -0
  126. package/dist/payment-preauth.d.ts.map +1 -0
  127. package/dist/payment-preauth.js +102 -0
  128. package/dist/payment-preauth.js.map +1 -0
  129. package/dist/provider.d.ts +19 -0
  130. package/dist/provider.d.ts.map +1 -0
  131. package/dist/provider.js +45 -0
  132. package/dist/provider.js.map +1 -0
  133. package/dist/proxy.d.ts +210 -0
  134. package/dist/proxy.d.ts.map +1 -0
  135. package/dist/proxy.debrand.test.d.ts +2 -0
  136. package/dist/proxy.debrand.test.d.ts.map +1 -0
  137. package/dist/proxy.debrand.test.js +101 -0
  138. package/dist/proxy.debrand.test.js.map +1 -0
  139. package/dist/proxy.degraded-response.test.d.ts +2 -0
  140. package/dist/proxy.degraded-response.test.d.ts.map +1 -0
  141. package/dist/proxy.degraded-response.test.js +105 -0
  142. package/dist/proxy.degraded-response.test.js.map +1 -0
  143. package/dist/proxy.image-download.test.d.ts +2 -0
  144. package/dist/proxy.image-download.test.d.ts.map +1 -0
  145. package/dist/proxy.image-download.test.js +92 -0
  146. package/dist/proxy.image-download.test.js.map +1 -0
  147. package/dist/proxy.js +3810 -0
  148. package/dist/proxy.js.map +1 -0
  149. package/dist/proxy.models-endpoint.test.d.ts +2 -0
  150. package/dist/proxy.models-endpoint.test.d.ts.map +1 -0
  151. package/dist/proxy.models-endpoint.test.js +19 -0
  152. package/dist/proxy.models-endpoint.test.js.map +1 -0
  153. package/dist/proxy.multiturn-thinking.test.d.ts +2 -0
  154. package/dist/proxy.multiturn-thinking.test.d.ts.map +1 -0
  155. package/dist/proxy.multiturn-thinking.test.js +82 -0
  156. package/dist/proxy.multiturn-thinking.test.js.map +1 -0
  157. package/dist/proxy.payment-chain-reuse.test.d.ts +2 -0
  158. package/dist/proxy.payment-chain-reuse.test.d.ts.map +1 -0
  159. package/dist/proxy.payment-chain-reuse.test.js +30 -0
  160. package/dist/proxy.payment-chain-reuse.test.js.map +1 -0
  161. package/dist/proxy.solana-resilience.test.d.ts +12 -0
  162. package/dist/proxy.solana-resilience.test.d.ts.map +1 -0
  163. package/dist/proxy.solana-resilience.test.js +39 -0
  164. package/dist/proxy.solana-resilience.test.js.map +1 -0
  165. package/dist/report.d.ts +6 -0
  166. package/dist/report.d.ts.map +1 -0
  167. package/dist/report.js +44 -0
  168. package/dist/report.js.map +1 -0
  169. package/dist/response-cache.advanced.test.d.ts +2 -0
  170. package/dist/response-cache.advanced.test.d.ts.map +1 -0
  171. package/dist/response-cache.advanced.test.js +566 -0
  172. package/dist/response-cache.advanced.test.js.map +1 -0
  173. package/dist/response-cache.d.ts +85 -0
  174. package/dist/response-cache.d.ts.map +1 -0
  175. package/dist/response-cache.edge-cases.test.d.ts +2 -0
  176. package/dist/response-cache.edge-cases.test.d.ts.map +1 -0
  177. package/dist/response-cache.edge-cases.test.js +488 -0
  178. package/dist/response-cache.edge-cases.test.js.map +1 -0
  179. package/dist/response-cache.extreme.test.d.ts +2 -0
  180. package/dist/response-cache.extreme.test.d.ts.map +1 -0
  181. package/dist/response-cache.extreme.test.js +561 -0
  182. package/dist/response-cache.extreme.test.js.map +1 -0
  183. package/dist/response-cache.js +240 -0
  184. package/dist/response-cache.js.map +1 -0
  185. package/dist/response-cache.test.d.ts +2 -0
  186. package/dist/response-cache.test.d.ts.map +1 -0
  187. package/dist/response-cache.test.js +242 -0
  188. package/dist/response-cache.test.js.map +1 -0
  189. package/dist/retry.d.ts +42 -0
  190. package/dist/retry.d.ts.map +1 -0
  191. package/dist/retry.js +99 -0
  192. package/dist/retry.js.map +1 -0
  193. package/dist/router/config.d.ts +11 -0
  194. package/dist/router/config.d.ts.map +1 -0
  195. package/dist/router/config.js +1215 -0
  196. package/dist/router/config.js.map +1 -0
  197. package/dist/router/index.d.ts +18 -0
  198. package/dist/router/index.d.ts.map +1 -0
  199. package/dist/router/index.js +19 -0
  200. package/dist/router/index.js.map +1 -0
  201. package/dist/router/llm-classifier.d.ts +29 -0
  202. package/dist/router/llm-classifier.d.ts.map +1 -0
  203. package/dist/router/llm-classifier.js +99 -0
  204. package/dist/router/llm-classifier.js.map +1 -0
  205. package/dist/router/rules.d.ts +12 -0
  206. package/dist/router/rules.d.ts.map +1 -0
  207. package/dist/router/rules.js +202 -0
  208. package/dist/router/rules.js.map +1 -0
  209. package/dist/router/selector.d.ts +58 -0
  210. package/dist/router/selector.d.ts.map +1 -0
  211. package/dist/router/selector.js +165 -0
  212. package/dist/router/selector.js.map +1 -0
  213. package/dist/router/selector.test.d.ts +2 -0
  214. package/dist/router/selector.test.d.ts.map +1 -0
  215. package/dist/router/selector.test.js +67 -0
  216. package/dist/router/selector.test.js.map +1 -0
  217. package/dist/router/strategy.d.ts +19 -0
  218. package/dist/router/strategy.d.ts.map +1 -0
  219. package/dist/router/strategy.js +138 -0
  220. package/dist/router/strategy.js.map +1 -0
  221. package/dist/router/strategy.test.d.ts +2 -0
  222. package/dist/router/strategy.test.d.ts.map +1 -0
  223. package/dist/router/strategy.test.js +131 -0
  224. package/dist/router/strategy.test.js.map +1 -0
  225. package/dist/router/types.d.ts +127 -0
  226. package/dist/router/types.d.ts.map +1 -0
  227. package/dist/router/types.js +11 -0
  228. package/dist/router/types.js.map +1 -0
  229. package/dist/session.d.ts +124 -0
  230. package/dist/session.d.ts.map +1 -0
  231. package/dist/session.js +256 -0
  232. package/dist/session.js.map +1 -0
  233. package/dist/session.test.d.ts +2 -0
  234. package/dist/session.test.d.ts.map +1 -0
  235. package/dist/session.test.js +163 -0
  236. package/dist/session.test.js.map +1 -0
  237. package/dist/solana-balance.d.ts +48 -0
  238. package/dist/solana-balance.d.ts.map +1 -0
  239. package/dist/solana-balance.js +142 -0
  240. package/dist/solana-balance.js.map +1 -0
  241. package/dist/spend-control.d.ts +112 -0
  242. package/dist/spend-control.d.ts.map +1 -0
  243. package/dist/spend-control.js +278 -0
  244. package/dist/spend-control.js.map +1 -0
  245. package/dist/spend-control.test.d.ts +5 -0
  246. package/dist/spend-control.test.d.ts.map +1 -0
  247. package/dist/spend-control.test.js +210 -0
  248. package/dist/spend-control.test.js.map +1 -0
  249. package/dist/stats.d.ts +64 -0
  250. package/dist/stats.d.ts.map +1 -0
  251. package/dist/stats.js +295 -0
  252. package/dist/stats.js.map +1 -0
  253. package/dist/types.d.ts +150 -0
  254. package/dist/types.d.ts.map +1 -0
  255. package/dist/types.js +9 -0
  256. package/dist/types.js.map +1 -0
  257. package/dist/update-hint.test.d.ts +9 -0
  258. package/dist/update-hint.test.d.ts.map +1 -0
  259. package/dist/update-hint.test.js +156 -0
  260. package/dist/update-hint.test.js.map +1 -0
  261. package/dist/updater.d.ts +10 -0
  262. package/dist/updater.d.ts.map +1 -0
  263. package/dist/updater.js +55 -0
  264. package/dist/updater.js.map +1 -0
  265. package/dist/version.d.ts +3 -0
  266. package/dist/version.d.ts.map +1 -0
  267. package/dist/version.js +16 -0
  268. package/dist/version.js.map +1 -0
  269. package/dist/wallet.d.ts +52 -0
  270. package/dist/wallet.d.ts.map +1 -0
  271. package/dist/wallet.js +93 -0
  272. package/dist/wallet.js.map +1 -0
  273. package/dist/wallet.test.d.ts +6 -0
  274. package/dist/wallet.test.d.ts.map +1 -0
  275. package/dist/wallet.test.js +117 -0
  276. package/dist/wallet.test.js.map +1 -0
  277. package/dist/x402-sdk.test.d.ts +6 -0
  278. package/dist/x402-sdk.test.d.ts.map +1 -0
  279. package/dist/x402-sdk.test.js +161 -0
  280. package/dist/x402-sdk.test.js.map +1 -0
  281. package/package.json +1 -1
  282. package/scripts/e2e-multiturn.mjs +4 -1
package/dist/stats.js ADDED
@@ -0,0 +1,295 @@
1
+ /**
2
+ * Usage Statistics Aggregator
3
+ *
4
+ * Reads usage log files and aggregates statistics for terminal display.
5
+ * Supports filtering by date range and provides multiple aggregation views.
6
+ */
7
+ import { readdir, unlink } from "node:fs/promises";
8
+ import { readTextFile } from "./fs-read.js";
9
+ import { join } from "node:path";
10
+ import { homedir } from "node:os";
11
+ import { VERSION } from "./version.js";
12
+ const LOG_DIR = join(homedir(), ".openclaw", "blockrun", "logs");
13
+ /**
14
+ * Parse a JSONL log file into usage entries.
15
+ * Handles both old format (without tier/baselineCost) and new format.
16
+ */
17
+ async function parseLogFile(filePath) {
18
+ try {
19
+ const content = await readTextFile(filePath);
20
+ const lines = content.trim().split("\n").filter(Boolean);
21
+ const entries = [];
22
+ for (const line of lines) {
23
+ try {
24
+ const entry = JSON.parse(line);
25
+ entries.push({
26
+ timestamp: entry.timestamp || new Date().toISOString(),
27
+ model: entry.model || "unknown",
28
+ tier: entry.tier || "UNKNOWN",
29
+ cost: entry.cost || 0,
30
+ baselineCost: entry.baselineCost || entry.cost || 0,
31
+ savings: entry.savings || 0,
32
+ latencyMs: entry.latencyMs || 0,
33
+ });
34
+ }
35
+ catch {
36
+ // Skip malformed lines, keep valid ones
37
+ }
38
+ }
39
+ return entries;
40
+ }
41
+ catch {
42
+ return [];
43
+ }
44
+ }
45
+ /**
46
+ * Get list of available log files sorted by date (newest first).
47
+ */
48
+ async function getLogFiles() {
49
+ try {
50
+ const files = await readdir(LOG_DIR);
51
+ return files
52
+ .filter((f) => f.startsWith("usage-") && f.endsWith(".jsonl"))
53
+ .sort()
54
+ .reverse();
55
+ }
56
+ catch {
57
+ return [];
58
+ }
59
+ }
60
+ /**
61
+ * Aggregate stats for a single day.
62
+ */
63
+ function aggregateDay(date, entries) {
64
+ const byTier = {};
65
+ const byModel = {};
66
+ let totalLatency = 0;
67
+ for (const entry of entries) {
68
+ // By tier
69
+ if (!byTier[entry.tier])
70
+ byTier[entry.tier] = { count: 0, cost: 0 };
71
+ byTier[entry.tier].count++;
72
+ byTier[entry.tier].cost += entry.cost;
73
+ // By model
74
+ if (!byModel[entry.model])
75
+ byModel[entry.model] = { count: 0, cost: 0 };
76
+ byModel[entry.model].count++;
77
+ byModel[entry.model].cost += entry.cost;
78
+ totalLatency += entry.latencyMs;
79
+ }
80
+ const totalCost = entries.reduce((sum, e) => sum + e.cost, 0);
81
+ const totalBaselineCost = entries.reduce((sum, e) => sum + e.baselineCost, 0);
82
+ return {
83
+ date,
84
+ totalRequests: entries.length,
85
+ totalCost,
86
+ totalBaselineCost,
87
+ totalSavings: totalBaselineCost - totalCost,
88
+ avgLatencyMs: entries.length > 0 ? totalLatency / entries.length : 0,
89
+ byTier,
90
+ byModel,
91
+ };
92
+ }
93
+ /**
94
+ * Get aggregated statistics for the last N days.
95
+ */
96
+ export async function getStats(days = 7) {
97
+ const logFiles = await getLogFiles();
98
+ const filesToRead = logFiles.slice(0, days);
99
+ const dailyBreakdown = [];
100
+ const allByTier = {};
101
+ const allByModel = {};
102
+ let totalRequests = 0;
103
+ let totalCost = 0;
104
+ let totalBaselineCost = 0;
105
+ let totalLatency = 0;
106
+ for (const file of filesToRead) {
107
+ const date = file.replace("usage-", "").replace(".jsonl", "");
108
+ const filePath = join(LOG_DIR, file);
109
+ const entries = await parseLogFile(filePath);
110
+ if (entries.length === 0)
111
+ continue;
112
+ const dayStats = aggregateDay(date, entries);
113
+ dailyBreakdown.push(dayStats);
114
+ totalRequests += dayStats.totalRequests;
115
+ totalCost += dayStats.totalCost;
116
+ totalBaselineCost += dayStats.totalBaselineCost;
117
+ totalLatency += dayStats.avgLatencyMs * dayStats.totalRequests;
118
+ // Merge tier stats
119
+ for (const [tier, stats] of Object.entries(dayStats.byTier)) {
120
+ if (!allByTier[tier])
121
+ allByTier[tier] = { count: 0, cost: 0 };
122
+ allByTier[tier].count += stats.count;
123
+ allByTier[tier].cost += stats.cost;
124
+ }
125
+ // Merge model stats
126
+ for (const [model, stats] of Object.entries(dayStats.byModel)) {
127
+ if (!allByModel[model])
128
+ allByModel[model] = { count: 0, cost: 0 };
129
+ allByModel[model].count += stats.count;
130
+ allByModel[model].cost += stats.cost;
131
+ }
132
+ }
133
+ // Calculate percentages
134
+ const byTierWithPercentage = {};
135
+ for (const [tier, stats] of Object.entries(allByTier)) {
136
+ byTierWithPercentage[tier] = {
137
+ ...stats,
138
+ percentage: totalRequests > 0 ? (stats.count / totalRequests) * 100 : 0,
139
+ };
140
+ }
141
+ const byModelWithPercentage = {};
142
+ for (const [model, stats] of Object.entries(allByModel)) {
143
+ byModelWithPercentage[model] = {
144
+ ...stats,
145
+ percentage: totalRequests > 0 ? (stats.count / totalRequests) * 100 : 0,
146
+ };
147
+ }
148
+ const totalSavings = totalBaselineCost - totalCost;
149
+ const savingsPercentage = totalBaselineCost > 0 ? (totalSavings / totalBaselineCost) * 100 : 0;
150
+ // Count entries with valid baseline tracking (baseline != cost means tracking was active)
151
+ let entriesWithBaseline = 0;
152
+ for (const day of dailyBreakdown) {
153
+ if (day.totalBaselineCost !== day.totalCost) {
154
+ entriesWithBaseline += day.totalRequests;
155
+ }
156
+ }
157
+ return {
158
+ period: days === 1 ? "today" : `last ${days} days`,
159
+ totalRequests,
160
+ totalCost,
161
+ totalBaselineCost,
162
+ totalSavings,
163
+ savingsPercentage,
164
+ avgLatencyMs: totalRequests > 0 ? totalLatency / totalRequests : 0,
165
+ avgCostPerRequest: totalRequests > 0 ? totalCost / totalRequests : 0,
166
+ byTier: byTierWithPercentage,
167
+ byModel: byModelWithPercentage,
168
+ dailyBreakdown: dailyBreakdown.reverse(), // Oldest first for charts
169
+ entriesWithBaseline, // How many entries have valid baseline tracking
170
+ };
171
+ }
172
+ /**
173
+ * Format stats as ASCII table for terminal display.
174
+ */
175
+ export function formatStatsAscii(stats) {
176
+ const lines = [];
177
+ // Header
178
+ lines.push("╔════════════════════════════════════════════════════════════╗");
179
+ lines.push(`║ ClawRouter by BlockRun v${VERSION}`.padEnd(61) + "║");
180
+ lines.push("║ Usage Statistics ║");
181
+ lines.push("╠════════════════════════════════════════════════════════════╣");
182
+ // Summary
183
+ lines.push(`║ Period: ${stats.period.padEnd(49)}║`);
184
+ lines.push(`║ Total Requests: ${stats.totalRequests.toString().padEnd(41)}║`);
185
+ lines.push(`║ Total Cost: $${stats.totalCost.toFixed(4).padEnd(43)}║`);
186
+ lines.push(`║ Baseline Cost (Opus 4.5): $${stats.totalBaselineCost.toFixed(4).padEnd(30)}║`);
187
+ // Show savings with note if some entries lack baseline tracking
188
+ const savingsLine = `║ 💰 Total Saved: $${stats.totalSavings.toFixed(4)} (${stats.savingsPercentage.toFixed(1)}%)`;
189
+ if (stats.entriesWithBaseline < stats.totalRequests && stats.entriesWithBaseline > 0) {
190
+ lines.push(savingsLine.padEnd(61) + "║");
191
+ const note = `║ (based on ${stats.entriesWithBaseline}/${stats.totalRequests} tracked requests)`;
192
+ lines.push(note.padEnd(61) + "║");
193
+ }
194
+ else {
195
+ lines.push(savingsLine.padEnd(61) + "║");
196
+ }
197
+ lines.push(`║ Avg Latency: ${stats.avgLatencyMs.toFixed(0)}ms`.padEnd(61) + "║");
198
+ // Tier breakdown
199
+ lines.push("╠════════════════════════════════════════════════════════════╣");
200
+ lines.push("║ Routing by Tier: ║");
201
+ // Show all tiers found in data, ordered by known tiers first then others
202
+ const knownTiers = ["SIMPLE", "MEDIUM", "COMPLEX", "REASONING", "DIRECT"];
203
+ const allTiers = Object.keys(stats.byTier);
204
+ const otherTiers = allTiers.filter((t) => !knownTiers.includes(t));
205
+ const tierOrder = [...knownTiers.filter((t) => stats.byTier[t]), ...otherTiers];
206
+ for (const tier of tierOrder) {
207
+ const data = stats.byTier[tier];
208
+ if (data) {
209
+ const bar = "█".repeat(Math.min(20, Math.round(data.percentage / 5)));
210
+ const displayTier = tier === "UNKNOWN" ? "OTHER" : tier;
211
+ const line = `║ ${displayTier.padEnd(10)} ${bar.padEnd(20)} ${data.percentage.toFixed(1).padStart(5)}% (${data.count})`;
212
+ lines.push(line.padEnd(61) + "║");
213
+ }
214
+ }
215
+ // Top models
216
+ lines.push("╠════════════════════════════════════════════════════════════╣");
217
+ lines.push("║ Top Models: ║");
218
+ const sortedModels = Object.entries(stats.byModel)
219
+ .sort((a, b) => b[1].count - a[1].count)
220
+ .slice(0, 5);
221
+ for (const [model, data] of sortedModels) {
222
+ const shortModel = model.length > 25 ? model.slice(0, 22) + "..." : model;
223
+ const line = `║ ${shortModel.padEnd(25)} ${data.count.toString().padStart(5)} reqs $${data.cost.toFixed(4)}`;
224
+ lines.push(line.padEnd(61) + "║");
225
+ }
226
+ // Daily breakdown (last 7 days)
227
+ if (stats.dailyBreakdown.length > 0) {
228
+ lines.push("╠════════════════════════════════════════════════════════════╣");
229
+ lines.push("║ Daily Breakdown: ║");
230
+ lines.push("║ Date Requests Cost Saved ║");
231
+ for (const day of stats.dailyBreakdown.slice(-7)) {
232
+ const saved = day.totalBaselineCost - day.totalCost;
233
+ const line = `║ ${day.date} ${day.totalRequests.toString().padStart(6)} $${day.totalCost.toFixed(4).padStart(8)} $${saved.toFixed(4)}`;
234
+ lines.push(line.padEnd(61) + "║");
235
+ }
236
+ }
237
+ lines.push("╚════════════════════════════════════════════════════════════╝");
238
+ return lines.join("\n");
239
+ }
240
+ /**
241
+ * Format per-request log entries as an ASCII table for terminal display.
242
+ * Reads the last N days of log files and shows each request individually.
243
+ */
244
+ export async function formatRecentLogs(days = 1) {
245
+ const logFiles = await getLogFiles();
246
+ const filesToRead = logFiles.slice(0, days);
247
+ const allEntries = [];
248
+ for (const file of filesToRead) {
249
+ const entries = await parseLogFile(join(LOG_DIR, file));
250
+ allEntries.push(...entries);
251
+ }
252
+ // Sort chronologically (oldest first)
253
+ allEntries.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
254
+ const lines = [];
255
+ lines.push("╔════════════════════════════════════════════════════════════════════════╗");
256
+ lines.push(`║ ClawRouter Request Log — last ${days === 1 ? "24h" : `${days} days`}`.padEnd(72) + "║");
257
+ lines.push("╠══════════════════╦══════════════════════════╦═════════╦══════╦════════╣");
258
+ lines.push("║ Time ║ Model ║ Cost ║ ms ║ Status ║");
259
+ lines.push("╠══════════════════╬══════════════════════════╬═════════╬══════╬════════╣");
260
+ if (allEntries.length === 0) {
261
+ lines.push("║ No requests found".padEnd(72) + "║");
262
+ }
263
+ let totalCost = 0;
264
+ for (const e of allEntries) {
265
+ const time = e.timestamp.slice(11, 19); // HH:MM:SS
266
+ const date = e.timestamp.slice(5, 10); // MM-DD
267
+ const displayTime = `${date} ${time}`;
268
+ const model = e.model.length > 24 ? e.model.slice(0, 21) + "..." : e.model;
269
+ const cost = `$${e.cost.toFixed(4)}`;
270
+ const ms = e.latencyMs > 9999 ? `${(e.latencyMs / 1000).toFixed(1)}s` : `${e.latencyMs}ms`;
271
+ const status = e.status === "error" ? " ERROR " : " OK ";
272
+ totalCost += e.cost;
273
+ lines.push(`║ ${displayTime.padEnd(16)}║ ${model.padEnd(24)}║ ${cost.padStart(7)}║ ${ms.padStart(4)}║${status}║`);
274
+ }
275
+ lines.push("╠══════════════════╩══════════════════════════╩═════════╩══════╩════════╣");
276
+ lines.push(`║ ${allEntries.length} request${allEntries.length !== 1 ? "s" : ""} Total spent: $${totalCost.toFixed(4)}`.padEnd(72) + "║");
277
+ lines.push("║ Logs: ~/.openclaw/blockrun/logs/ (JSONL — one entry per request)".padEnd(72) + "║");
278
+ lines.push("╚════════════════════════════════════════════════════════════════════════╝");
279
+ return lines.join("\n");
280
+ }
281
+ /**
282
+ * Delete all usage log files, resetting stats to zero.
283
+ */
284
+ export async function clearStats() {
285
+ try {
286
+ const files = await readdir(LOG_DIR);
287
+ const logFiles = files.filter((f) => f.startsWith("usage-") && f.endsWith(".jsonl"));
288
+ await Promise.all(logFiles.map((f) => unlink(join(LOG_DIR, f))));
289
+ return { deletedFiles: logFiles.length };
290
+ }
291
+ catch {
292
+ return { deletedFiles: 0 };
293
+ }
294
+ }
295
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../src/stats.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * OpenClaw Plugin Types (locally defined)
3
+ *
4
+ * OpenClaw's plugin SDK uses duck typing — these match the shapes
5
+ * expected by registerProvider() and the plugin system.
6
+ * Defined locally to avoid depending on internal OpenClaw paths.
7
+ */
8
+ export type ModelApi = "openai-completions" | "openai-responses" | "anthropic-messages" | "google-generative-ai" | "github-copilot" | "bedrock-converse-stream";
9
+ export type ModelDefinitionConfig = {
10
+ id: string;
11
+ name: string;
12
+ api?: ModelApi;
13
+ reasoning: boolean;
14
+ input: Array<"text" | "image">;
15
+ cost: {
16
+ input: number;
17
+ output: number;
18
+ cacheRead: number;
19
+ cacheWrite: number;
20
+ };
21
+ contextWindow: number;
22
+ maxTokens: number;
23
+ headers?: Record<string, string>;
24
+ };
25
+ export type ModelProviderConfig = {
26
+ baseUrl: string;
27
+ apiKey?: string;
28
+ api?: ModelApi;
29
+ headers?: Record<string, string>;
30
+ authHeader?: boolean;
31
+ models: ModelDefinitionConfig[];
32
+ };
33
+ export type AuthProfileCredential = {
34
+ apiKey?: string;
35
+ type?: string;
36
+ [key: string]: unknown;
37
+ };
38
+ export type ProviderAuthResult = {
39
+ profiles: Array<{
40
+ profileId: string;
41
+ credential: AuthProfileCredential;
42
+ }>;
43
+ configPatch?: Record<string, unknown>;
44
+ defaultModel?: string;
45
+ notes?: string[];
46
+ };
47
+ export type WizardPrompter = {
48
+ text: (opts: {
49
+ message: string;
50
+ validate?: (value: string) => string | undefined;
51
+ }) => Promise<string | symbol>;
52
+ note: (message: string) => void;
53
+ progress: (message: string) => {
54
+ stop: (message?: string) => void;
55
+ };
56
+ };
57
+ export type ProviderAuthContext = {
58
+ config: Record<string, unknown>;
59
+ agentDir?: string;
60
+ workspaceDir?: string;
61
+ prompter: WizardPrompter;
62
+ runtime: {
63
+ log: (message: string) => void;
64
+ };
65
+ isRemote: boolean;
66
+ openUrl: (url: string) => Promise<void>;
67
+ };
68
+ export type ProviderAuthMethod = {
69
+ id: string;
70
+ label: string;
71
+ hint?: string;
72
+ kind: "oauth" | "api_key" | "token" | "device_code" | "custom";
73
+ run: (ctx: ProviderAuthContext) => Promise<ProviderAuthResult>;
74
+ };
75
+ export type ProviderPlugin = {
76
+ id: string;
77
+ label: string;
78
+ docsPath?: string;
79
+ aliases?: string[];
80
+ envVars?: string[];
81
+ models?: ModelProviderConfig;
82
+ auth: ProviderAuthMethod[];
83
+ formatApiKey?: (cred: AuthProfileCredential) => string;
84
+ };
85
+ export type PluginLogger = {
86
+ debug?: (message: string) => void;
87
+ info: (message: string) => void;
88
+ warn: (message: string) => void;
89
+ error: (message: string) => void;
90
+ };
91
+ export type OpenClawPluginService = {
92
+ id: string;
93
+ start: () => void | Promise<void>;
94
+ stop?: () => void | Promise<void>;
95
+ };
96
+ export type OpenClawPluginApi = {
97
+ id: string;
98
+ name: string;
99
+ version?: string;
100
+ description?: string;
101
+ source: string;
102
+ config: Record<string, unknown> & {
103
+ models?: {
104
+ providers?: Record<string, ModelProviderConfig>;
105
+ };
106
+ agents?: Record<string, unknown>;
107
+ };
108
+ pluginConfig?: Record<string, unknown>;
109
+ logger: PluginLogger;
110
+ registerProvider: (provider: ProviderPlugin) => void;
111
+ registerTool: (tool: unknown, opts?: unknown) => void;
112
+ registerHook: (events: string | string[], handler: unknown, opts?: unknown) => void;
113
+ registerHttpRoute: (params: {
114
+ path: string;
115
+ handler: unknown;
116
+ }) => void;
117
+ registerService: (service: OpenClawPluginService) => void;
118
+ registerCommand: (command: unknown) => void;
119
+ resolvePath: (input: string) => string;
120
+ on: (hookName: string, handler: unknown, opts?: unknown) => void;
121
+ };
122
+ export type OpenClawPluginDefinition = {
123
+ id?: string;
124
+ name?: string;
125
+ description?: string;
126
+ version?: string;
127
+ register?: (api: OpenClawPluginApi) => void | Promise<void>;
128
+ activate?: (api: OpenClawPluginApi) => void | Promise<void>;
129
+ };
130
+ export type PluginCommandContext = {
131
+ senderId?: string;
132
+ channel: string;
133
+ isAuthorizedSender: boolean;
134
+ args?: string;
135
+ commandBody: string;
136
+ config: Record<string, unknown>;
137
+ };
138
+ export type PluginCommandResult = {
139
+ text?: string;
140
+ isError?: boolean;
141
+ };
142
+ export type PluginCommandHandler = (ctx: PluginCommandContext) => PluginCommandResult | Promise<PluginCommandResult>;
143
+ export type OpenClawPluginCommandDefinition = {
144
+ name: string;
145
+ description: string;
146
+ acceptsArgs?: boolean;
147
+ requireAuth?: boolean;
148
+ handler: PluginCommandHandler;
149
+ };
150
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * OpenClaw Plugin Types (locally defined)
3
+ *
4
+ * OpenClaw's plugin SDK uses duck typing — these match the shapes
5
+ * expected by registerProvider() and the plugin system.
6
+ * Defined locally to avoid depending on internal OpenClaw paths.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Tests for server-side update hint parsing from 429 response bodies.
3
+ *
4
+ * When BlockRun's API detects a stale ClawRouter user-agent, it includes
5
+ * { update_available, update_url } in 429 responses. The proxy parses
6
+ * these and logs a prominent update message.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=update-hint.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-hint.test.d.ts","sourceRoot":"","sources":["../src/update-hint.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Tests for server-side update hint parsing from 429 response bodies.
3
+ *
4
+ * When BlockRun's API detects a stale ClawRouter user-agent, it includes
5
+ * { update_available, update_url } in 429 responses. The proxy parses
6
+ * these and logs a prominent update message.
7
+ */
8
+ import { describe, expect, it, vi, afterEach } from "vitest";
9
+ /** Mirrors the parsing logic in proxy.ts's 429 handler */
10
+ function parseUpdateHint(errorBody) {
11
+ try {
12
+ const parsed = JSON.parse(errorBody || "{}");
13
+ if (parsed.update_available) {
14
+ return { update_available: parsed.update_available, update_url: parsed.update_url };
15
+ }
16
+ }
17
+ catch {
18
+ // ignore parse errors
19
+ }
20
+ return null;
21
+ }
22
+ /** Mirrors getUpdateHint() on the blockrun server side */
23
+ function getUpdateHint(userAgent, currentVersion) {
24
+ if (!userAgent)
25
+ return null;
26
+ const match = userAgent.match(/^clawrouter\/(\d+\.\d+\.\d+)/);
27
+ if (!match)
28
+ return null;
29
+ const clientVersion = match[1];
30
+ const [cMaj, cMin, cPatch] = clientVersion.split(".").map(Number);
31
+ const [sMaj, sMin, sPatch] = currentVersion.split(".").map(Number);
32
+ if (cMaj < sMaj ||
33
+ (cMaj === sMaj && cMin < sMin) ||
34
+ (cMaj === sMaj && cMin === sMin && cPatch < sPatch)) {
35
+ return {
36
+ update_available: currentVersion,
37
+ update_url: "https://blockrun.ai/ClawRouter-update",
38
+ };
39
+ }
40
+ return null;
41
+ }
42
+ describe("update hint — server-side generation (getUpdateHint)", () => {
43
+ const CURRENT = "0.12.12";
44
+ it("returns hint when client is older (patch)", () => {
45
+ expect(getUpdateHint("clawrouter/0.12.11", CURRENT)).toEqual({
46
+ update_available: "0.12.12",
47
+ update_url: "https://blockrun.ai/ClawRouter-update",
48
+ });
49
+ });
50
+ it("returns hint when client is older (minor)", () => {
51
+ expect(getUpdateHint("clawrouter/0.10.22", CURRENT)).toEqual({
52
+ update_available: "0.12.12",
53
+ update_url: "https://blockrun.ai/ClawRouter-update",
54
+ });
55
+ });
56
+ it("returns hint when client is older (major)", () => {
57
+ expect(getUpdateHint("clawrouter/0.9.0", "1.0.0")).toEqual({
58
+ update_available: "1.0.0",
59
+ update_url: "https://blockrun.ai/ClawRouter-update",
60
+ });
61
+ });
62
+ it("returns null when client is current", () => {
63
+ expect(getUpdateHint("clawrouter/0.12.12", CURRENT)).toBeNull();
64
+ });
65
+ it("returns null when client is newer", () => {
66
+ expect(getUpdateHint("clawrouter/0.13.0", CURRENT)).toBeNull();
67
+ });
68
+ it("returns null for non-clawrouter user agents", () => {
69
+ expect(getUpdateHint("curl/7.88.0", CURRENT)).toBeNull();
70
+ expect(getUpdateHint("Mozilla/5.0", CURRENT)).toBeNull();
71
+ });
72
+ it("returns null for undefined user agent", () => {
73
+ expect(getUpdateHint(undefined, CURRENT)).toBeNull();
74
+ });
75
+ });
76
+ describe("update hint — client-side parsing (parseUpdateHint)", () => {
77
+ it("parses update_available from 429 body", () => {
78
+ const body = JSON.stringify({
79
+ error: "Rate limited",
80
+ message: "Free tier: max 60 requests/hour.",
81
+ update_available: "0.12.12",
82
+ update_url: "https://blockrun.ai/ClawRouter-update",
83
+ });
84
+ expect(parseUpdateHint(body)).toEqual({
85
+ update_available: "0.12.12",
86
+ update_url: "https://blockrun.ai/ClawRouter-update",
87
+ });
88
+ });
89
+ it("returns null when no update_available in body", () => {
90
+ const body = JSON.stringify({
91
+ error: "Rate limited",
92
+ message: "Free tier: max 60 requests/hour.",
93
+ });
94
+ expect(parseUpdateHint(body)).toBeNull();
95
+ });
96
+ it("returns null for malformed JSON", () => {
97
+ expect(parseUpdateHint("not json")).toBeNull();
98
+ });
99
+ it("returns null for undefined body", () => {
100
+ expect(parseUpdateHint(undefined)).toBeNull();
101
+ });
102
+ it("returns null for empty body", () => {
103
+ expect(parseUpdateHint("")).toBeNull();
104
+ });
105
+ });
106
+ describe("update hint — console output", () => {
107
+ afterEach(() => {
108
+ vi.restoreAllMocks();
109
+ });
110
+ it("logs prominent update message when hint is present in 429", () => {
111
+ const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
112
+ const VERSION = "0.12.11";
113
+ // Simulate what proxy.ts does on 429 with update hint
114
+ const errorBody = JSON.stringify({
115
+ error: "Rate limited",
116
+ update_available: "0.12.12",
117
+ update_url: "https://blockrun.ai/ClawRouter-update",
118
+ });
119
+ try {
120
+ const parsed = JSON.parse(errorBody || "{}");
121
+ if (parsed.update_available) {
122
+ console.log("");
123
+ console.log(`\x1b[33m⬆️ ClawRouter ${parsed.update_available} available (you have ${VERSION})\x1b[0m`);
124
+ console.log(` Run: \x1b[36mcurl -fsSL ${parsed.update_url || "https://blockrun.ai/ClawRouter-update"} | bash\x1b[0m`);
125
+ console.log("");
126
+ }
127
+ }
128
+ catch {
129
+ /* ignore */
130
+ }
131
+ // Should have logged 4 calls (empty, version, run command, empty)
132
+ expect(logSpy).toHaveBeenCalledTimes(4);
133
+ const allCalls = logSpy.mock.calls.map((c) => c.join(" "));
134
+ expect(allCalls.some((c) => c.includes("0.12.12 available"))).toBe(true);
135
+ expect(allCalls.some((c) => c.includes("you have 0.12.11"))).toBe(true);
136
+ expect(allCalls.some((c) => c.includes("curl -fsSL"))).toBe(true);
137
+ });
138
+ it("does not log when no update hint in 429", () => {
139
+ const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
140
+ const errorBody = JSON.stringify({
141
+ error: "Rate limited",
142
+ message: "Provider rate limited",
143
+ });
144
+ try {
145
+ const parsed = JSON.parse(errorBody || "{}");
146
+ if (parsed.update_available) {
147
+ console.log("should not reach here");
148
+ }
149
+ }
150
+ catch {
151
+ /* ignore */
152
+ }
153
+ expect(logSpy).not.toHaveBeenCalled();
154
+ });
155
+ });
156
+ //# sourceMappingURL=update-hint.test.js.map