opencode-tokenwatch 0.3.0 → 0.3.1
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/LICENSE +21 -21
- package/README.en.md +104 -97
- package/README.md +104 -97
- package/dist/commands.js +208 -0
- package/dist/commands.jsx +11 -2
- package/dist/generate-usage-html.js +719 -707
- package/dist/i18n.js +2 -0
- package/dist/perf-tracker.d.ts +1 -0
- package/dist/perf-tracker.js +37 -0
- package/dist/queries.js +101 -101
- package/dist/sidebar.d.ts +2 -2
- package/dist/sidebar.jsx +333 -137
- package/dist/stats-store.d.ts +23 -0
- package/dist/stats-store.js +258 -0
- package/dist/tui.jsx +80 -26
- package/package.json +63 -63
package/dist/i18n.js
CHANGED
|
@@ -14,6 +14,7 @@ const zh = {
|
|
|
14
14
|
trendUp: "↑",
|
|
15
15
|
trendDown: "↓",
|
|
16
16
|
cache: "缓存",
|
|
17
|
+
lat: "延迟",
|
|
17
18
|
performance: "性能",
|
|
18
19
|
pricing: "Pricing",
|
|
19
20
|
tokenDistribution: "Token分布",
|
|
@@ -86,6 +87,7 @@ const en = {
|
|
|
86
87
|
trendUp: "↑",
|
|
87
88
|
trendDown: "↓",
|
|
88
89
|
cache: "Cache",
|
|
90
|
+
lat: "Lat",
|
|
89
91
|
performance: "Performance",
|
|
90
92
|
pricing: "Pricing",
|
|
91
93
|
tokenDistribution: "Token Distribution",
|
package/dist/perf-tracker.d.ts
CHANGED
|
@@ -54,6 +54,7 @@ declare class PerfTracker {
|
|
|
54
54
|
getSessionStats(): SessionPerfStats;
|
|
55
55
|
readLogs(last?: number): LogEntry[];
|
|
56
56
|
reset(): void;
|
|
57
|
+
loadSession(sessionID: string): void;
|
|
57
58
|
}
|
|
58
59
|
export declare function createPerfTracker(): PerfTracker;
|
|
59
60
|
export type { PartEvent, PerfTracker };
|
package/dist/perf-tracker.js
CHANGED
|
@@ -2,6 +2,7 @@ import { appendFileSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { existsSync, statSync } from "node:fs";
|
|
5
|
+
import { updatePersistedStats } from "./stats-store.js";
|
|
5
6
|
const LOG_PATH = join(homedir(), ".opencode", "tokenwatch.jsonl");
|
|
6
7
|
class PerfTracker {
|
|
7
8
|
firstPartTimes = new Map();
|
|
@@ -76,6 +77,7 @@ class PerfTracker {
|
|
|
76
77
|
try {
|
|
77
78
|
// Risk fix: JSONL 日志轮转保护,防止长期使用后文件无限增长
|
|
78
79
|
// 超过 5MB 时截断,保留最新 2000 行
|
|
80
|
+
// 注意:轮转前先调用 updatePersistedStats,确保被轮转行的数据已持久化
|
|
79
81
|
const MAX_SIZE = 5 * 1024 * 1024; // 5 MB
|
|
80
82
|
const KEEP_LINES = 2000;
|
|
81
83
|
if (existsSync(LOG_PATH) && statSync(LOG_PATH).size > MAX_SIZE) {
|
|
@@ -87,6 +89,9 @@ class PerfTracker {
|
|
|
87
89
|
catch {
|
|
88
90
|
// Silently fail — logging is non-critical
|
|
89
91
|
}
|
|
92
|
+
// 无论 JSONL 写入是否成功,都尝试更新持久化聚合统计
|
|
93
|
+
// 这样即使日志被轮转,历史统计数据也永不丢失
|
|
94
|
+
updatePersistedStats(entry);
|
|
90
95
|
}
|
|
91
96
|
handleMessageRemoved(event) {
|
|
92
97
|
const mid = event.properties?.messageID ?? "";
|
|
@@ -247,6 +252,38 @@ class PerfTracker {
|
|
|
247
252
|
this.ttftSamples.clear();
|
|
248
253
|
this.latencySamples.clear();
|
|
249
254
|
}
|
|
255
|
+
loadSession(sessionID) {
|
|
256
|
+
this.firstPartTimes.clear();
|
|
257
|
+
this.statsMap.clear();
|
|
258
|
+
this.ttftSamples.clear();
|
|
259
|
+
this.latencySamples.clear();
|
|
260
|
+
if (!sessionID)
|
|
261
|
+
return;
|
|
262
|
+
try {
|
|
263
|
+
if (!existsSync(LOG_PATH))
|
|
264
|
+
return;
|
|
265
|
+
const content = readFileSync(LOG_PATH, "utf-8").trim();
|
|
266
|
+
if (!content)
|
|
267
|
+
return;
|
|
268
|
+
const lines = content.split("\n");
|
|
269
|
+
for (const line of lines) {
|
|
270
|
+
if (!line)
|
|
271
|
+
continue;
|
|
272
|
+
try {
|
|
273
|
+
const entry = JSON.parse(line);
|
|
274
|
+
if (entry.sessionID === sessionID) {
|
|
275
|
+
this.updateStats(entry.model, entry);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
// Skip malformed lines
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
// Non-critical loading failure
|
|
285
|
+
}
|
|
286
|
+
}
|
|
250
287
|
}
|
|
251
288
|
export function createPerfTracker() {
|
|
252
289
|
return new PerfTracker();
|
package/dist/queries.js
CHANGED
|
@@ -90,41 +90,41 @@ export async function getCurrentSessionStats(sessionId) {
|
|
|
90
90
|
return getSummary(filters);
|
|
91
91
|
}
|
|
92
92
|
export async function getSummary(filters = {}) {
|
|
93
|
-
const sql = `
|
|
94
|
-
SELECT
|
|
95
|
-
group_concat(distinct coalesce(json_extract(m.data, '$.modelID'), 'unknown')) as models_used,
|
|
96
|
-
group_concat(distinct coalesce(json_extract(m.data, '$.providerID'), 'unknown')) as providers_used,
|
|
97
|
-
count(*) as request_count,
|
|
98
|
-
sum(coalesce(json_extract(m.data, '$.tokens.total'), 0)) as total_tokens,
|
|
99
|
-
sum(coalesce(json_extract(m.data, '$.tokens.input'), 0)) as input_tokens,
|
|
100
|
-
sum(coalesce(json_extract(m.data, '$.tokens.output'), 0)) as output_tokens,
|
|
101
|
-
sum(coalesce(json_extract(m.data, '$.tokens.reasoning'), 0)) as reasoning_tokens,
|
|
102
|
-
sum(coalesce(json_extract(m.data, '$.tokens.cache.read'), 0)) as cache_read,
|
|
103
|
-
sum(coalesce(json_extract(m.data, '$.tokens.cache.write'), 0)) as cache_write,
|
|
104
|
-
sum(coalesce(json_extract(m.data, '$.cost'), 0)) as total_cost
|
|
105
|
-
FROM message m
|
|
106
|
-
WHERE ${messageWhere(filters)}
|
|
93
|
+
const sql = `
|
|
94
|
+
SELECT
|
|
95
|
+
group_concat(distinct coalesce(json_extract(m.data, '$.modelID'), 'unknown')) as models_used,
|
|
96
|
+
group_concat(distinct coalesce(json_extract(m.data, '$.providerID'), 'unknown')) as providers_used,
|
|
97
|
+
count(*) as request_count,
|
|
98
|
+
sum(coalesce(json_extract(m.data, '$.tokens.total'), 0)) as total_tokens,
|
|
99
|
+
sum(coalesce(json_extract(m.data, '$.tokens.input'), 0)) as input_tokens,
|
|
100
|
+
sum(coalesce(json_extract(m.data, '$.tokens.output'), 0)) as output_tokens,
|
|
101
|
+
sum(coalesce(json_extract(m.data, '$.tokens.reasoning'), 0)) as reasoning_tokens,
|
|
102
|
+
sum(coalesce(json_extract(m.data, '$.tokens.cache.read'), 0)) as cache_read,
|
|
103
|
+
sum(coalesce(json_extract(m.data, '$.tokens.cache.write'), 0)) as cache_write,
|
|
104
|
+
sum(coalesce(json_extract(m.data, '$.cost'), 0)) as total_cost
|
|
105
|
+
FROM message m
|
|
106
|
+
WHERE ${messageWhere(filters)}
|
|
107
107
|
`.trim();
|
|
108
108
|
const rows = await queryDb(sql);
|
|
109
109
|
return toSessionTokenData(rows[0]);
|
|
110
110
|
}
|
|
111
111
|
export async function getModelBreakdown(filters = {}) {
|
|
112
|
-
const sql = `
|
|
113
|
-
SELECT
|
|
114
|
-
coalesce(json_extract(m.data, '$.providerID'), 'unknown') as provider,
|
|
115
|
-
coalesce(json_extract(m.data, '$.modelID'), 'unknown') as model,
|
|
116
|
-
count(*) as requests,
|
|
117
|
-
count(distinct m.session_id) as sessions,
|
|
118
|
-
sum(coalesce(json_extract(m.data, '$.tokens.total'), 0)) as total_tokens,
|
|
119
|
-
sum(coalesce(json_extract(m.data, '$.tokens.input'), 0)) as input_tokens,
|
|
120
|
-
sum(coalesce(json_extract(m.data, '$.tokens.output'), 0)) as output_tokens,
|
|
121
|
-
sum(coalesce(json_extract(m.data, '$.tokens.reasoning'), 0)) as reasoning_tokens,
|
|
122
|
-
sum(coalesce(json_extract(m.data, '$.tokens.cache.read'), 0)) as cache_read,
|
|
123
|
-
sum(coalesce(json_extract(m.data, '$.cost'), 0)) as total_cost
|
|
124
|
-
FROM message m
|
|
125
|
-
WHERE ${messageWhere(filters)}
|
|
126
|
-
GROUP BY provider, model
|
|
127
|
-
ORDER BY total_tokens DESC
|
|
112
|
+
const sql = `
|
|
113
|
+
SELECT
|
|
114
|
+
coalesce(json_extract(m.data, '$.providerID'), 'unknown') as provider,
|
|
115
|
+
coalesce(json_extract(m.data, '$.modelID'), 'unknown') as model,
|
|
116
|
+
count(*) as requests,
|
|
117
|
+
count(distinct m.session_id) as sessions,
|
|
118
|
+
sum(coalesce(json_extract(m.data, '$.tokens.total'), 0)) as total_tokens,
|
|
119
|
+
sum(coalesce(json_extract(m.data, '$.tokens.input'), 0)) as input_tokens,
|
|
120
|
+
sum(coalesce(json_extract(m.data, '$.tokens.output'), 0)) as output_tokens,
|
|
121
|
+
sum(coalesce(json_extract(m.data, '$.tokens.reasoning'), 0)) as reasoning_tokens,
|
|
122
|
+
sum(coalesce(json_extract(m.data, '$.tokens.cache.read'), 0)) as cache_read,
|
|
123
|
+
sum(coalesce(json_extract(m.data, '$.cost'), 0)) as total_cost
|
|
124
|
+
FROM message m
|
|
125
|
+
WHERE ${messageWhere(filters)}
|
|
126
|
+
GROUP BY provider, model
|
|
127
|
+
ORDER BY total_tokens DESC
|
|
128
128
|
`.trim();
|
|
129
129
|
const rows = await queryDb(sql);
|
|
130
130
|
return rows.map((row) => ({
|
|
@@ -141,21 +141,21 @@ ORDER BY total_tokens DESC
|
|
|
141
141
|
}));
|
|
142
142
|
}
|
|
143
143
|
export async function getProviderBreakdown(filters = {}) {
|
|
144
|
-
const sql = `
|
|
145
|
-
SELECT
|
|
146
|
-
coalesce(json_extract(m.data, '$.providerID'), 'unknown') as provider,
|
|
147
|
-
count(*) as requests,
|
|
148
|
-
count(distinct m.session_id) as sessions,
|
|
149
|
-
sum(coalesce(json_extract(m.data, '$.tokens.total'), 0)) as total_tokens,
|
|
150
|
-
sum(coalesce(json_extract(m.data, '$.tokens.input'), 0)) as input_tokens,
|
|
151
|
-
sum(coalesce(json_extract(m.data, '$.tokens.output'), 0)) as output_tokens,
|
|
152
|
-
sum(coalesce(json_extract(m.data, '$.tokens.reasoning'), 0)) as reasoning_tokens,
|
|
153
|
-
sum(coalesce(json_extract(m.data, '$.tokens.cache.read'), 0)) as cache_read,
|
|
154
|
-
sum(coalesce(json_extract(m.data, '$.cost'), 0)) as total_cost
|
|
155
|
-
FROM message m
|
|
156
|
-
WHERE ${messageWhere(filters)}
|
|
157
|
-
GROUP BY provider
|
|
158
|
-
ORDER BY total_tokens DESC
|
|
144
|
+
const sql = `
|
|
145
|
+
SELECT
|
|
146
|
+
coalesce(json_extract(m.data, '$.providerID'), 'unknown') as provider,
|
|
147
|
+
count(*) as requests,
|
|
148
|
+
count(distinct m.session_id) as sessions,
|
|
149
|
+
sum(coalesce(json_extract(m.data, '$.tokens.total'), 0)) as total_tokens,
|
|
150
|
+
sum(coalesce(json_extract(m.data, '$.tokens.input'), 0)) as input_tokens,
|
|
151
|
+
sum(coalesce(json_extract(m.data, '$.tokens.output'), 0)) as output_tokens,
|
|
152
|
+
sum(coalesce(json_extract(m.data, '$.tokens.reasoning'), 0)) as reasoning_tokens,
|
|
153
|
+
sum(coalesce(json_extract(m.data, '$.tokens.cache.read'), 0)) as cache_read,
|
|
154
|
+
sum(coalesce(json_extract(m.data, '$.cost'), 0)) as total_cost
|
|
155
|
+
FROM message m
|
|
156
|
+
WHERE ${messageWhere(filters)}
|
|
157
|
+
GROUP BY provider
|
|
158
|
+
ORDER BY total_tokens DESC
|
|
159
159
|
`.trim();
|
|
160
160
|
const rows = await queryDb(sql);
|
|
161
161
|
return rows.map((row) => ({
|
|
@@ -172,22 +172,22 @@ ORDER BY total_tokens DESC
|
|
|
172
172
|
}
|
|
173
173
|
export async function getDailyBreakdown(filters = {}) {
|
|
174
174
|
const limit = filters.limit ?? 30;
|
|
175
|
-
const sql = `
|
|
176
|
-
SELECT
|
|
177
|
-
date(m.time_created / 1000, 'unixepoch', 'localtime') as day,
|
|
178
|
-
count(*) as requests,
|
|
179
|
-
count(distinct m.session_id) as sessions,
|
|
180
|
-
sum(coalesce(json_extract(m.data, '$.tokens.total'), 0)) as total_tokens,
|
|
181
|
-
sum(coalesce(json_extract(m.data, '$.tokens.input'), 0)) as input_tokens,
|
|
182
|
-
sum(coalesce(json_extract(m.data, '$.tokens.output'), 0)) as output_tokens,
|
|
183
|
-
sum(coalesce(json_extract(m.data, '$.tokens.reasoning'), 0)) as reasoning_tokens,
|
|
184
|
-
sum(coalesce(json_extract(m.data, '$.tokens.cache.read'), 0)) as cache_read,
|
|
185
|
-
sum(coalesce(json_extract(m.data, '$.cost'), 0)) as total_cost
|
|
186
|
-
FROM message m
|
|
187
|
-
WHERE ${messageWhere(filters)}
|
|
188
|
-
GROUP BY day
|
|
189
|
-
ORDER BY day DESC
|
|
190
|
-
LIMIT ${Math.max(1, limit)}
|
|
175
|
+
const sql = `
|
|
176
|
+
SELECT
|
|
177
|
+
date(m.time_created / 1000, 'unixepoch', 'localtime') as day,
|
|
178
|
+
count(*) as requests,
|
|
179
|
+
count(distinct m.session_id) as sessions,
|
|
180
|
+
sum(coalesce(json_extract(m.data, '$.tokens.total'), 0)) as total_tokens,
|
|
181
|
+
sum(coalesce(json_extract(m.data, '$.tokens.input'), 0)) as input_tokens,
|
|
182
|
+
sum(coalesce(json_extract(m.data, '$.tokens.output'), 0)) as output_tokens,
|
|
183
|
+
sum(coalesce(json_extract(m.data, '$.tokens.reasoning'), 0)) as reasoning_tokens,
|
|
184
|
+
sum(coalesce(json_extract(m.data, '$.tokens.cache.read'), 0)) as cache_read,
|
|
185
|
+
sum(coalesce(json_extract(m.data, '$.cost'), 0)) as total_cost
|
|
186
|
+
FROM message m
|
|
187
|
+
WHERE ${messageWhere(filters)}
|
|
188
|
+
GROUP BY day
|
|
189
|
+
ORDER BY day DESC
|
|
190
|
+
LIMIT ${Math.max(1, limit)}
|
|
191
191
|
`.trim();
|
|
192
192
|
const rows = await queryDb(sql);
|
|
193
193
|
return rows.map((row) => ({
|
|
@@ -204,26 +204,26 @@ LIMIT ${Math.max(1, limit)}
|
|
|
204
204
|
}
|
|
205
205
|
export async function getSessionBreakdown(filters = {}) {
|
|
206
206
|
const limit = filters.limit ?? 15;
|
|
207
|
-
const sql = `
|
|
208
|
-
SELECT
|
|
209
|
-
s.id as session_id,
|
|
210
|
-
s.title as title,
|
|
211
|
-
coalesce(json_extract(m.data, '$.providerID'), json_extract(s.model, '$.providerID'), 'unknown') as provider,
|
|
212
|
-
coalesce(json_extract(m.data, '$.modelID'), json_extract(s.model, '$.id'), 'unknown') as model,
|
|
213
|
-
count(*) as requests,
|
|
214
|
-
sum(coalesce(json_extract(m.data, '$.tokens.total'), 0)) as total_tokens,
|
|
215
|
-
sum(coalesce(json_extract(m.data, '$.tokens.input'), 0)) as input_tokens,
|
|
216
|
-
sum(coalesce(json_extract(m.data, '$.tokens.output'), 0)) as output_tokens,
|
|
217
|
-
sum(coalesce(json_extract(m.data, '$.tokens.reasoning'), 0)) as reasoning_tokens,
|
|
218
|
-
sum(coalesce(json_extract(m.data, '$.tokens.cache.read'), 0)) as cache_read,
|
|
219
|
-
sum(coalesce(json_extract(m.data, '$.cost'), 0)) as total_cost,
|
|
220
|
-
date(max(m.time_created) / 1000, 'unixepoch', 'localtime') as day
|
|
221
|
-
FROM message m
|
|
222
|
-
JOIN session s ON s.id = m.session_id
|
|
223
|
-
WHERE ${messageWhere(filters)}
|
|
224
|
-
GROUP BY s.id, s.title, provider, model
|
|
225
|
-
ORDER BY max(m.time_created) DESC
|
|
226
|
-
LIMIT ${Math.max(1, limit)}
|
|
207
|
+
const sql = `
|
|
208
|
+
SELECT
|
|
209
|
+
s.id as session_id,
|
|
210
|
+
s.title as title,
|
|
211
|
+
coalesce(json_extract(m.data, '$.providerID'), json_extract(s.model, '$.providerID'), 'unknown') as provider,
|
|
212
|
+
coalesce(json_extract(m.data, '$.modelID'), json_extract(s.model, '$.id'), 'unknown') as model,
|
|
213
|
+
count(*) as requests,
|
|
214
|
+
sum(coalesce(json_extract(m.data, '$.tokens.total'), 0)) as total_tokens,
|
|
215
|
+
sum(coalesce(json_extract(m.data, '$.tokens.input'), 0)) as input_tokens,
|
|
216
|
+
sum(coalesce(json_extract(m.data, '$.tokens.output'), 0)) as output_tokens,
|
|
217
|
+
sum(coalesce(json_extract(m.data, '$.tokens.reasoning'), 0)) as reasoning_tokens,
|
|
218
|
+
sum(coalesce(json_extract(m.data, '$.tokens.cache.read'), 0)) as cache_read,
|
|
219
|
+
sum(coalesce(json_extract(m.data, '$.cost'), 0)) as total_cost,
|
|
220
|
+
date(max(m.time_created) / 1000, 'unixepoch', 'localtime') as day
|
|
221
|
+
FROM message m
|
|
222
|
+
JOIN session s ON s.id = m.session_id
|
|
223
|
+
WHERE ${messageWhere(filters)}
|
|
224
|
+
GROUP BY s.id, s.title, provider, model
|
|
225
|
+
ORDER BY max(m.time_created) DESC
|
|
226
|
+
LIMIT ${Math.max(1, limit)}
|
|
227
227
|
`.trim();
|
|
228
228
|
const rows = await queryDb(sql);
|
|
229
229
|
return rows.map((row) => ({
|
|
@@ -242,21 +242,21 @@ LIMIT ${Math.max(1, limit)}
|
|
|
242
242
|
}));
|
|
243
243
|
}
|
|
244
244
|
export async function getAvailableModels() {
|
|
245
|
-
const sql = `
|
|
246
|
-
SELECT distinct coalesce(json_extract(m.data, '$.modelID'), 'unknown') as value
|
|
247
|
-
FROM message m
|
|
248
|
-
WHERE ${messageWhere({})}
|
|
249
|
-
ORDER BY value ASC
|
|
245
|
+
const sql = `
|
|
246
|
+
SELECT distinct coalesce(json_extract(m.data, '$.modelID'), 'unknown') as value
|
|
247
|
+
FROM message m
|
|
248
|
+
WHERE ${messageWhere({})}
|
|
249
|
+
ORDER BY value ASC
|
|
250
250
|
`.trim();
|
|
251
251
|
const rows = await queryDb(sql);
|
|
252
252
|
return rows.map((row) => row.value ?? "unknown");
|
|
253
253
|
}
|
|
254
254
|
export async function getAvailableProviders() {
|
|
255
|
-
const sql = `
|
|
256
|
-
SELECT distinct coalesce(json_extract(m.data, '$.providerID'), 'unknown') as value
|
|
257
|
-
FROM message m
|
|
258
|
-
WHERE ${messageWhere({})}
|
|
259
|
-
ORDER BY value ASC
|
|
255
|
+
const sql = `
|
|
256
|
+
SELECT distinct coalesce(json_extract(m.data, '$.providerID'), 'unknown') as value
|
|
257
|
+
FROM message m
|
|
258
|
+
WHERE ${messageWhere({})}
|
|
259
|
+
ORDER BY value ASC
|
|
260
260
|
`.trim();
|
|
261
261
|
const rows = await queryDb(sql);
|
|
262
262
|
return rows.map((row) => row.value ?? "unknown");
|
|
@@ -281,16 +281,16 @@ export async function getErrorStats(filters = {}) {
|
|
|
281
281
|
}
|
|
282
282
|
const baseWhere = baseConds.join(" AND ");
|
|
283
283
|
// 按模型细化:同时统计成功和失败请求
|
|
284
|
-
const sql = `
|
|
285
|
-
SELECT
|
|
286
|
-
coalesce(json_extract(m.data, '$.providerID'), 'unknown') as provider,
|
|
287
|
-
coalesce(json_extract(m.data, '$.modelID'), 'unknown') as model,
|
|
288
|
-
count(*) as total,
|
|
289
|
-
sum(CASE WHEN coalesce(json_extract(m.data, '$.tokens.total'), 0) = 0 THEN 1 ELSE 0 END) as failed
|
|
290
|
-
FROM message m
|
|
291
|
-
WHERE ${baseWhere}
|
|
292
|
-
GROUP BY provider, model
|
|
293
|
-
ORDER BY failed DESC
|
|
284
|
+
const sql = `
|
|
285
|
+
SELECT
|
|
286
|
+
coalesce(json_extract(m.data, '$.providerID'), 'unknown') as provider,
|
|
287
|
+
coalesce(json_extract(m.data, '$.modelID'), 'unknown') as model,
|
|
288
|
+
count(*) as total,
|
|
289
|
+
sum(CASE WHEN coalesce(json_extract(m.data, '$.tokens.total'), 0) = 0 THEN 1 ELSE 0 END) as failed
|
|
290
|
+
FROM message m
|
|
291
|
+
WHERE ${baseWhere}
|
|
292
|
+
GROUP BY provider, model
|
|
293
|
+
ORDER BY failed DESC
|
|
294
294
|
`.trim();
|
|
295
295
|
try {
|
|
296
296
|
const rows = await queryDb(sql);
|
package/dist/sidebar.d.ts
CHANGED
|
@@ -15,8 +15,8 @@ interface TokenWatchPanelProps {
|
|
|
15
15
|
api: TuiPluginApi;
|
|
16
16
|
theme: TuiTheme;
|
|
17
17
|
perfTracker: PerfTracker;
|
|
18
|
-
messages: readonly any[];
|
|
19
|
-
allTokenMessages: TokenMessage[];
|
|
18
|
+
messages: () => readonly any[];
|
|
19
|
+
allTokenMessages: () => TokenMessage[];
|
|
20
20
|
}
|
|
21
21
|
export declare function TokenWatchPanel(props: TokenWatchPanelProps): any;
|
|
22
22
|
export {};
|