opencode-tokenwatch 0.4.0 → 0.5.0
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/server.js +11 -0
- package/dist/sidebar.d.ts +1 -1
- package/dist/tui.js +3611 -0
- package/package.json +16 -7
- package/dist/commands.js +0 -208
- package/dist/commands.jsx +0 -381
- package/dist/formatter.js +0 -289
- package/dist/generate-usage-html.js +0 -962
- package/dist/i18n.js +0 -173
- package/dist/index.js +0 -7
- package/dist/perf-tracker.js +0 -299
- package/dist/queries.js +0 -393
- package/dist/sidebar.jsx +0 -604
- package/dist/stats-store.js +0 -258
- package/dist/tui.jsx +0 -178
- /package/dist/{index.d.ts → server.d.ts} +0 -0
package/dist/queries.js
DELETED
|
@@ -1,393 +0,0 @@
|
|
|
1
|
-
import { exec } from "node:child_process";
|
|
2
|
-
function execAsync(cmd) {
|
|
3
|
-
return new Promise((resolve, reject) => {
|
|
4
|
-
exec(cmd, { windowsHide: true, timeout: 30000 }, (error, stdout, stderr) => {
|
|
5
|
-
if (error)
|
|
6
|
-
reject(Object.assign(error, { stderr }));
|
|
7
|
-
else
|
|
8
|
-
resolve({ stdout, stderr });
|
|
9
|
-
});
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
async function queryDb(sql) {
|
|
13
|
-
const flatSql = sql.replace(/\s+/g, " ").trim();
|
|
14
|
-
const { stdout, stderr } = await execAsync(`opencode db ${JSON.stringify(flatSql)} --format json`);
|
|
15
|
-
if (stderr)
|
|
16
|
-
throw new Error(stderr.trim());
|
|
17
|
-
const parsed = JSON.parse(stdout.trim());
|
|
18
|
-
return Array.isArray(parsed) ? parsed : parsed.data ?? [];
|
|
19
|
-
}
|
|
20
|
-
function escapeSql(value) {
|
|
21
|
-
return value.replace(/'/g, "''");
|
|
22
|
-
}
|
|
23
|
-
/** 校验日期格式必须为 YYYY-MM-DD,防止格式异常字符串进入 SQL */
|
|
24
|
-
function isValidDate(s) {
|
|
25
|
-
return /^\d{4}-\d{2}-\d{2}$/.test(s);
|
|
26
|
-
}
|
|
27
|
-
function messageWhere(filters) {
|
|
28
|
-
const where = [
|
|
29
|
-
"json_extract(m.data, '$.role') = 'assistant'",
|
|
30
|
-
"coalesce(json_extract(m.data, '$.tokens.total'), 0) > 0",
|
|
31
|
-
];
|
|
32
|
-
if (filters.sessionId)
|
|
33
|
-
where.push(`m.session_id = '${escapeSql(filters.sessionId)}'`);
|
|
34
|
-
if (filters.provider)
|
|
35
|
-
where.push(`coalesce(json_extract(m.data, '$.providerID'), '') = '${escapeSql(filters.provider)}'`);
|
|
36
|
-
if (filters.model)
|
|
37
|
-
where.push(`coalesce(json_extract(m.data, '$.modelID'), '') = '${escapeSql(filters.model)}'`);
|
|
38
|
-
// Risk fix: 日期参数先验证格式(YYYY-MM-DD),格式不符则忽略该过滤条件
|
|
39
|
-
if (filters.startDate && isValidDate(filters.startDate)) {
|
|
40
|
-
where.push(`date(m.time_created / 1000, 'unixepoch', 'localtime') >= '${filters.startDate}'`);
|
|
41
|
-
}
|
|
42
|
-
if (filters.endDate && isValidDate(filters.endDate)) {
|
|
43
|
-
where.push(`date(m.time_created / 1000, 'unixepoch', 'localtime') <= '${filters.endDate}'`);
|
|
44
|
-
}
|
|
45
|
-
return where.join(" AND ");
|
|
46
|
-
}
|
|
47
|
-
function parseList(value) {
|
|
48
|
-
if (!value)
|
|
49
|
-
return [];
|
|
50
|
-
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
51
|
-
}
|
|
52
|
-
function toSessionTokenData(row) {
|
|
53
|
-
const models = parseList(row?.models_used);
|
|
54
|
-
const providers = parseList(row?.providers_used);
|
|
55
|
-
return {
|
|
56
|
-
model: models.length === 1 ? models[0] : "",
|
|
57
|
-
provider: providers.length === 1 ? providers[0] : "",
|
|
58
|
-
modelsUsed: models,
|
|
59
|
-
totalTokens: row?.total_tokens ?? 0,
|
|
60
|
-
inputTokens: row?.input_tokens ?? 0,
|
|
61
|
-
outputTokens: row?.output_tokens ?? 0,
|
|
62
|
-
reasoningTokens: row?.reasoning_tokens ?? 0,
|
|
63
|
-
cacheRead: row?.cache_read ?? 0,
|
|
64
|
-
cacheWrite: row?.cache_write ?? 0,
|
|
65
|
-
totalCost: row?.total_cost ?? 0,
|
|
66
|
-
requestCount: row?.request_count ?? 0,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
export function getPresetRange(preset) {
|
|
70
|
-
if (preset === "all")
|
|
71
|
-
return {};
|
|
72
|
-
const end = new Date();
|
|
73
|
-
const start = new Date(end);
|
|
74
|
-
if (preset === "7d")
|
|
75
|
-
start.setDate(end.getDate() - 6);
|
|
76
|
-
if (preset === "30d")
|
|
77
|
-
start.setDate(end.getDate() - 29);
|
|
78
|
-
if (preset === "month")
|
|
79
|
-
start.setDate(1);
|
|
80
|
-
const format = (date) => {
|
|
81
|
-
const year = date.getFullYear();
|
|
82
|
-
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
83
|
-
const day = String(date.getDate()).padStart(2, "0");
|
|
84
|
-
return `${year}-${month}-${day}`;
|
|
85
|
-
};
|
|
86
|
-
return { startDate: format(start), endDate: format(end) };
|
|
87
|
-
}
|
|
88
|
-
export async function getCurrentSessionStats(sessionId) {
|
|
89
|
-
const filters = sessionId ? { sessionId } : {};
|
|
90
|
-
return getSummary(filters);
|
|
91
|
-
}
|
|
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)}
|
|
107
|
-
`.trim();
|
|
108
|
-
const rows = await queryDb(sql);
|
|
109
|
-
return toSessionTokenData(rows[0]);
|
|
110
|
-
}
|
|
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
|
|
128
|
-
`.trim();
|
|
129
|
-
const rows = await queryDb(sql);
|
|
130
|
-
return rows.map((row) => ({
|
|
131
|
-
provider: row.provider ?? "unknown",
|
|
132
|
-
model: row.model ?? "unknown",
|
|
133
|
-
requests: row.requests ?? 0,
|
|
134
|
-
sessions: row.sessions ?? 0,
|
|
135
|
-
totalTokens: row.total_tokens ?? 0,
|
|
136
|
-
inputTokens: row.input_tokens ?? 0,
|
|
137
|
-
outputTokens: row.output_tokens ?? 0,
|
|
138
|
-
reasoningTokens: row.reasoning_tokens ?? 0,
|
|
139
|
-
cacheRead: row.cache_read ?? 0,
|
|
140
|
-
totalCost: row.total_cost ?? 0,
|
|
141
|
-
}));
|
|
142
|
-
}
|
|
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
|
|
159
|
-
`.trim();
|
|
160
|
-
const rows = await queryDb(sql);
|
|
161
|
-
return rows.map((row) => ({
|
|
162
|
-
provider: row.provider ?? "unknown",
|
|
163
|
-
requests: row.requests ?? 0,
|
|
164
|
-
sessions: row.sessions ?? 0,
|
|
165
|
-
totalTokens: row.total_tokens ?? 0,
|
|
166
|
-
inputTokens: row.input_tokens ?? 0,
|
|
167
|
-
outputTokens: row.output_tokens ?? 0,
|
|
168
|
-
reasoningTokens: row.reasoning_tokens ?? 0,
|
|
169
|
-
cacheRead: row.cache_read ?? 0,
|
|
170
|
-
totalCost: row.total_cost ?? 0,
|
|
171
|
-
}));
|
|
172
|
-
}
|
|
173
|
-
export async function getDailyBreakdown(filters = {}) {
|
|
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)}
|
|
191
|
-
`.trim();
|
|
192
|
-
const rows = await queryDb(sql);
|
|
193
|
-
return rows.map((row) => ({
|
|
194
|
-
day: row.day ?? "",
|
|
195
|
-
requests: row.requests ?? 0,
|
|
196
|
-
sessions: row.sessions ?? 0,
|
|
197
|
-
totalTokens: row.total_tokens ?? 0,
|
|
198
|
-
inputTokens: row.input_tokens ?? 0,
|
|
199
|
-
outputTokens: row.output_tokens ?? 0,
|
|
200
|
-
reasoningTokens: row.reasoning_tokens ?? 0,
|
|
201
|
-
cacheRead: row.cache_read ?? 0,
|
|
202
|
-
totalCost: row.total_cost ?? 0,
|
|
203
|
-
}));
|
|
204
|
-
}
|
|
205
|
-
export async function getSessionBreakdown(filters = {}) {
|
|
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)}
|
|
227
|
-
`.trim();
|
|
228
|
-
const rows = await queryDb(sql);
|
|
229
|
-
return rows.map((row) => ({
|
|
230
|
-
sessionId: row.session_id ?? "",
|
|
231
|
-
title: row.title ?? "(untitled)",
|
|
232
|
-
provider: row.provider ?? "unknown",
|
|
233
|
-
model: row.model ?? "unknown",
|
|
234
|
-
requests: row.requests ?? 0,
|
|
235
|
-
totalTokens: row.total_tokens ?? 0,
|
|
236
|
-
inputTokens: row.input_tokens ?? 0,
|
|
237
|
-
outputTokens: row.output_tokens ?? 0,
|
|
238
|
-
reasoningTokens: row.reasoning_tokens ?? 0,
|
|
239
|
-
cacheRead: row.cache_read ?? 0,
|
|
240
|
-
totalCost: row.total_cost ?? 0,
|
|
241
|
-
day: row.day ?? "",
|
|
242
|
-
}));
|
|
243
|
-
}
|
|
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
|
|
250
|
-
`.trim();
|
|
251
|
-
const rows = await queryDb(sql);
|
|
252
|
-
return rows.map((row) => row.value ?? "unknown");
|
|
253
|
-
}
|
|
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
|
|
260
|
-
`.trim();
|
|
261
|
-
const rows = await queryDb(sql);
|
|
262
|
-
return rows.map((row) => row.value ?? "unknown");
|
|
263
|
-
}
|
|
264
|
-
/** 失败请求计数 SQL。1次运行获取成功数+失败数+按模型细分 */
|
|
265
|
-
export async function getErrorStats(filters = {}) {
|
|
266
|
-
// 构建日期/Session/Provider/Model 过滤条件(不包含 tokens.total > 0 过滤)
|
|
267
|
-
const baseConds = [
|
|
268
|
-
"json_extract(m.data, '$.role') = 'assistant'",
|
|
269
|
-
];
|
|
270
|
-
if (filters.sessionId)
|
|
271
|
-
baseConds.push(`m.session_id = '${escapeSql(filters.sessionId)}'`);
|
|
272
|
-
if (filters.provider)
|
|
273
|
-
baseConds.push(`coalesce(json_extract(m.data, '$.providerID'), '') = '${escapeSql(filters.provider)}'`);
|
|
274
|
-
if (filters.model)
|
|
275
|
-
baseConds.push(`coalesce(json_extract(m.data, '$.modelID'), '') = '${escapeSql(filters.model)}'`);
|
|
276
|
-
if (filters.startDate && isValidDate(filters.startDate)) {
|
|
277
|
-
baseConds.push(`date(m.time_created / 1000, 'unixepoch', 'localtime') >= '${filters.startDate}'`);
|
|
278
|
-
}
|
|
279
|
-
if (filters.endDate && isValidDate(filters.endDate)) {
|
|
280
|
-
baseConds.push(`date(m.time_created / 1000, 'unixepoch', 'localtime') <= '${filters.endDate}'`);
|
|
281
|
-
}
|
|
282
|
-
const baseWhere = baseConds.join(" AND ");
|
|
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
|
|
294
|
-
`.trim();
|
|
295
|
-
try {
|
|
296
|
-
const rows = await queryDb(sql);
|
|
297
|
-
let successCount = 0, failedCount = 0;
|
|
298
|
-
const byModel = rows.map(r => {
|
|
299
|
-
const total = r.total ?? 0;
|
|
300
|
-
const failed = r.failed ?? 0;
|
|
301
|
-
const success = total - failed;
|
|
302
|
-
successCount += success;
|
|
303
|
-
failedCount += failed;
|
|
304
|
-
return { provider: r.provider ?? 'unknown', model: r.model ?? 'unknown', failed, total };
|
|
305
|
-
});
|
|
306
|
-
const errorRate = (successCount + failedCount) > 0
|
|
307
|
-
? failedCount / (successCount + failedCount)
|
|
308
|
-
: 0;
|
|
309
|
-
return { successCount, failedCount, errorRate, byModel };
|
|
310
|
-
}
|
|
311
|
-
catch {
|
|
312
|
-
return { successCount: 0, failedCount: 0, errorRate: 0, byModel: [] };
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
export async function getUsageReport(filters = {}) {
|
|
316
|
-
const [summary, models, providers, daily, sessions, errors] = await Promise.all([
|
|
317
|
-
getSummary(filters),
|
|
318
|
-
getModelBreakdown(filters),
|
|
319
|
-
getProviderBreakdown(filters),
|
|
320
|
-
getDailyBreakdown(filters),
|
|
321
|
-
getSessionBreakdown(filters),
|
|
322
|
-
getErrorStats(filters),
|
|
323
|
-
]);
|
|
324
|
-
return { filters, summary, models, providers, daily, sessions, errors };
|
|
325
|
-
}
|
|
326
|
-
function csvEscape(value) {
|
|
327
|
-
const text = String(value);
|
|
328
|
-
return /[",\n]/.test(text) ? `"${text.replace(/"/g, "\"\"")}"` : text;
|
|
329
|
-
}
|
|
330
|
-
export function exportReportAsCsv(report, section) {
|
|
331
|
-
if (section === "models") {
|
|
332
|
-
const header = ["provider", "model", "requests", "sessions", "totalTokens", "inputTokens", "outputTokens", "reasoningTokens", "cacheRead", "totalCost"];
|
|
333
|
-
const rows = report.models.map((item) => [
|
|
334
|
-
item.provider,
|
|
335
|
-
item.model,
|
|
336
|
-
item.requests,
|
|
337
|
-
item.sessions,
|
|
338
|
-
item.totalTokens,
|
|
339
|
-
item.inputTokens,
|
|
340
|
-
item.outputTokens,
|
|
341
|
-
item.reasoningTokens,
|
|
342
|
-
item.cacheRead,
|
|
343
|
-
item.totalCost,
|
|
344
|
-
]);
|
|
345
|
-
return [header, ...rows].map((row) => row.map(csvEscape).join(",")).join("\n");
|
|
346
|
-
}
|
|
347
|
-
if (section === "providers") {
|
|
348
|
-
const header = ["provider", "requests", "sessions", "totalTokens", "inputTokens", "outputTokens", "reasoningTokens", "cacheRead", "totalCost"];
|
|
349
|
-
const rows = report.providers.map((item) => [
|
|
350
|
-
item.provider,
|
|
351
|
-
item.requests,
|
|
352
|
-
item.sessions,
|
|
353
|
-
item.totalTokens,
|
|
354
|
-
item.inputTokens,
|
|
355
|
-
item.outputTokens,
|
|
356
|
-
item.reasoningTokens,
|
|
357
|
-
item.cacheRead,
|
|
358
|
-
item.totalCost,
|
|
359
|
-
]);
|
|
360
|
-
return [header, ...rows].map((row) => row.map(csvEscape).join(",")).join("\n");
|
|
361
|
-
}
|
|
362
|
-
if (section === "daily") {
|
|
363
|
-
const header = ["day", "requests", "sessions", "totalTokens", "inputTokens", "outputTokens", "reasoningTokens", "cacheRead", "totalCost"];
|
|
364
|
-
const rows = report.daily.map((item) => [
|
|
365
|
-
item.day,
|
|
366
|
-
item.requests,
|
|
367
|
-
item.sessions,
|
|
368
|
-
item.totalTokens,
|
|
369
|
-
item.inputTokens,
|
|
370
|
-
item.outputTokens,
|
|
371
|
-
item.reasoningTokens,
|
|
372
|
-
item.cacheRead,
|
|
373
|
-
item.totalCost,
|
|
374
|
-
]);
|
|
375
|
-
return [header, ...rows].map((row) => row.map(csvEscape).join(",")).join("\n");
|
|
376
|
-
}
|
|
377
|
-
const header = ["day", "sessionId", "title", "provider", "model", "requests", "totalTokens", "inputTokens", "outputTokens", "reasoningTokens", "cacheRead", "totalCost"];
|
|
378
|
-
const rows = report.sessions.map((item) => [
|
|
379
|
-
item.day,
|
|
380
|
-
item.sessionId,
|
|
381
|
-
item.title,
|
|
382
|
-
item.provider,
|
|
383
|
-
item.model,
|
|
384
|
-
item.requests,
|
|
385
|
-
item.totalTokens,
|
|
386
|
-
item.inputTokens,
|
|
387
|
-
item.outputTokens,
|
|
388
|
-
item.reasoningTokens,
|
|
389
|
-
item.cacheRead,
|
|
390
|
-
item.totalCost,
|
|
391
|
-
]);
|
|
392
|
-
return [header, ...rows].map((row) => row.map(csvEscape).join(",")).join("\n");
|
|
393
|
-
}
|