ec-web 0.0.24 → 0.0.25
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.md +17 -17
- package/dist/index.js +0 -0
- package/dist/server.js +1 -1
- package/dist/sources/basic-settings.js +0 -6
- package/dist/sources/session-codex.js +11 -11
- package/dist/sources/stats.js +92 -92
- package/dist/static/app.js +11691 -11691
- package/dist/static/index.html +427 -427
- package/dist/static/style.css +4899 -4899
- package/dist/static/vendor/echarts-5.6.0.min.js +45 -45
- package/ecweb-wrapper.cjs +67 -67
- package/package.json +35 -35
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 EvolCore contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 EvolCore contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
# EC Web
|
|
2
|
-
|
|
3
|
-
Web console and monitoring dashboard for EvolCore.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install -g ec-web
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Run
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
ec-web --home /path/to/runtime-home
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Use `ec watch web` when EC Web is managed by the main daemon.
|
|
1
|
+
# EC Web
|
|
2
|
+
|
|
3
|
+
Web console and monitoring dashboard for EvolCore.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g ec-web
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Run
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
ec-web --home /path/to/runtime-home
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Use `ec watch web` when EC Web is managed by the main daemon.
|
package/dist/index.js
CHANGED
|
File without changes
|
package/dist/server.js
CHANGED
|
@@ -796,7 +796,7 @@ export async function startWatchWebServer(opts = {}) {
|
|
|
796
796
|
res.end(JSON.stringify({ success: false, error: 'unauthorized' }));
|
|
797
797
|
return;
|
|
798
798
|
}
|
|
799
|
-
void handleBasicSettingsApi(req, res, { redactConnectionMaps: !isLocalDirect(req)
|
|
799
|
+
void handleBasicSettingsApi(req, res, { redactConnectionMaps: !isLocalDirect(req) });
|
|
800
800
|
}
|
|
801
801
|
else if (req.method === 'GET' && (req.url || '').startsWith('/api/stats/')) {
|
|
802
802
|
// Stats API — 本地直连自动发 token(免鉴权),远程需鉴权
|
|
@@ -767,9 +767,6 @@ export async function handleBasicSettingsApi(req, res, options = {}) {
|
|
|
767
767
|
return;
|
|
768
768
|
}
|
|
769
769
|
if (req.method === 'GET' && pathname === '/api/basic-settings/secret') {
|
|
770
|
-
if (options.remoteAccess) {
|
|
771
|
-
throw Object.assign(new Error('Remote access cannot reveal configuration secrets'), { statusCode: 403 });
|
|
772
|
-
}
|
|
773
770
|
const file = url.searchParams.get('file') || 'defaults';
|
|
774
771
|
const fieldPath = url.searchParams.get('path') || '';
|
|
775
772
|
if (!requestedSecretPath(file, fieldPath)) {
|
|
@@ -785,9 +782,6 @@ export async function handleBasicSettingsApi(req, res, options = {}) {
|
|
|
785
782
|
return;
|
|
786
783
|
}
|
|
787
784
|
if (req.method === 'PATCH' && pathname === '/api/basic-settings') {
|
|
788
|
-
if (options.remoteAccess) {
|
|
789
|
-
throw Object.assign(new Error('Remote access cannot mutate basic settings'), { statusCode: 403 });
|
|
790
|
-
}
|
|
791
785
|
const body = await readJsonBody(req);
|
|
792
786
|
if (!isRecord(body) || (body.file !== 'daemon' && body.file !== 'defaults'))
|
|
793
787
|
throw new Error('file must be daemon or defaults');
|
|
@@ -205,12 +205,12 @@ function listProjects() {
|
|
|
205
205
|
if (!db)
|
|
206
206
|
return [];
|
|
207
207
|
try {
|
|
208
|
-
const rows = db.prepare(`
|
|
209
|
-
SELECT cwd, COUNT(*) as count, MAX(updated_at) as lastActivity
|
|
210
|
-
FROM threads
|
|
211
|
-
WHERE archived = 0
|
|
212
|
-
GROUP BY cwd
|
|
213
|
-
ORDER BY lastActivity DESC
|
|
208
|
+
const rows = db.prepare(`
|
|
209
|
+
SELECT cwd, COUNT(*) as count, MAX(updated_at) as lastActivity
|
|
210
|
+
FROM threads
|
|
211
|
+
WHERE archived = 0
|
|
212
|
+
GROUP BY cwd
|
|
213
|
+
ORDER BY lastActivity DESC
|
|
214
214
|
`).all();
|
|
215
215
|
const projects = rows.map(r => {
|
|
216
216
|
const cwd = r.cwd || '';
|
|
@@ -382,11 +382,11 @@ function listTranscripts(encoded, cwd) {
|
|
|
382
382
|
if (!db)
|
|
383
383
|
return [];
|
|
384
384
|
try {
|
|
385
|
-
const rows = db.prepare(`
|
|
386
|
-
SELECT id, title, first_user_message, updated_at, rollout_path, source, thread_source
|
|
387
|
-
FROM threads
|
|
388
|
-
WHERE cwd = ? AND archived = 0
|
|
389
|
-
ORDER BY updated_at DESC
|
|
385
|
+
const rows = db.prepare(`
|
|
386
|
+
SELECT id, title, first_user_message, updated_at, rollout_path, source, thread_source
|
|
387
|
+
FROM threads
|
|
388
|
+
WHERE cwd = ? AND archived = 0
|
|
389
|
+
ORDER BY updated_at DESC
|
|
390
390
|
`).all(cwd);
|
|
391
391
|
const out = [];
|
|
392
392
|
let parsed = 0, hitMem = 0, hitDisk = 0;
|
package/dist/sources/stats.js
CHANGED
|
@@ -46,41 +46,41 @@ export function queryStatsForDashboard() {
|
|
|
46
46
|
const h24ago = Date.now() - 24 * 60 * 60 * 1000;
|
|
47
47
|
try {
|
|
48
48
|
// Today summary with cost
|
|
49
|
-
const todayRow = db.prepare(`
|
|
50
|
-
SELECT
|
|
51
|
-
COALESCE(SUM(input_tokens),0) AS input_tokens,
|
|
52
|
-
COALESCE(SUM(output_tokens),0) AS output_tokens,
|
|
53
|
-
COALESCE(SUM(cache_creation_tokens),0) AS cache_creation_tokens,
|
|
54
|
-
COALESCE(SUM(cache_read_tokens),0) AS cache_read_tokens,
|
|
55
|
-
COUNT(*) AS call_count,
|
|
56
|
-
COALESCE(SUM(cost_gateway_usd),0) AS cost_usd,
|
|
57
|
-
COALESCE(SUM(cost_gateway_cny),0) AS cost_cny
|
|
58
|
-
FROM usage_events WHERE ts >= ?
|
|
49
|
+
const todayRow = db.prepare(`
|
|
50
|
+
SELECT
|
|
51
|
+
COALESCE(SUM(input_tokens),0) AS input_tokens,
|
|
52
|
+
COALESCE(SUM(output_tokens),0) AS output_tokens,
|
|
53
|
+
COALESCE(SUM(cache_creation_tokens),0) AS cache_creation_tokens,
|
|
54
|
+
COALESCE(SUM(cache_read_tokens),0) AS cache_read_tokens,
|
|
55
|
+
COUNT(*) AS call_count,
|
|
56
|
+
COALESCE(SUM(cost_gateway_usd),0) AS cost_usd,
|
|
57
|
+
COALESCE(SUM(cost_gateway_cny),0) AS cost_cny
|
|
58
|
+
FROM usage_events WHERE ts >= ?
|
|
59
59
|
`).get(todayStart);
|
|
60
60
|
const totalIn = (todayRow.input_tokens ?? 0) + (todayRow.cache_read_tokens ?? 0);
|
|
61
61
|
const hitRate = totalIn > 0 ? (todayRow.cache_read_tokens ?? 0) / totalIn : 0;
|
|
62
62
|
// Hourly (last 24h)
|
|
63
|
-
const hourly = db.prepare(`
|
|
64
|
-
SELECT
|
|
65
|
-
strftime('%Y-%m-%d %H:00', ts/1000, 'unixepoch', 'localtime') AS hour,
|
|
66
|
-
COALESCE(SUM(input_tokens),0) AS input_tokens,
|
|
67
|
-
COALESCE(SUM(output_tokens),0) AS output_tokens,
|
|
68
|
-
COALESCE(SUM(cache_read_tokens),0) AS cache_read_tokens,
|
|
69
|
-
COUNT(*) AS call_count
|
|
70
|
-
FROM usage_events WHERE ts >= ?
|
|
71
|
-
GROUP BY hour ORDER BY hour
|
|
63
|
+
const hourly = db.prepare(`
|
|
64
|
+
SELECT
|
|
65
|
+
strftime('%Y-%m-%d %H:00', ts/1000, 'unixepoch', 'localtime') AS hour,
|
|
66
|
+
COALESCE(SUM(input_tokens),0) AS input_tokens,
|
|
67
|
+
COALESCE(SUM(output_tokens),0) AS output_tokens,
|
|
68
|
+
COALESCE(SUM(cache_read_tokens),0) AS cache_read_tokens,
|
|
69
|
+
COUNT(*) AS call_count
|
|
70
|
+
FROM usage_events WHERE ts >= ?
|
|
71
|
+
GROUP BY hour ORDER BY hour
|
|
72
72
|
`).all(h24ago);
|
|
73
73
|
// Top models (today)
|
|
74
|
-
const top_models = db.prepare(`
|
|
75
|
-
SELECT model, SUM(input_tokens+output_tokens) AS total_tokens, COUNT(*) AS call_count
|
|
76
|
-
FROM usage_events WHERE ts >= ?
|
|
77
|
-
GROUP BY model ORDER BY total_tokens DESC LIMIT 10
|
|
74
|
+
const top_models = db.prepare(`
|
|
75
|
+
SELECT model, SUM(input_tokens+output_tokens) AS total_tokens, COUNT(*) AS call_count
|
|
76
|
+
FROM usage_events WHERE ts >= ?
|
|
77
|
+
GROUP BY model ORDER BY total_tokens DESC LIMIT 10
|
|
78
78
|
`).all(todayStart);
|
|
79
79
|
// Top peers (today)
|
|
80
|
-
const top_peers = db.prepare(`
|
|
81
|
-
SELECT peer_key, SUM(input_tokens+output_tokens) AS total_tokens, COUNT(*) AS call_count
|
|
82
|
-
FROM usage_events WHERE ts >= ?
|
|
83
|
-
GROUP BY peer_key ORDER BY total_tokens DESC LIMIT 5
|
|
80
|
+
const top_peers = db.prepare(`
|
|
81
|
+
SELECT peer_key, SUM(input_tokens+output_tokens) AS total_tokens, COUNT(*) AS call_count
|
|
82
|
+
FROM usage_events WHERE ts >= ?
|
|
83
|
+
GROUP BY peer_key ORDER BY total_tokens DESC LIMIT 5
|
|
84
84
|
`).all(todayStart);
|
|
85
85
|
return {
|
|
86
86
|
today: { ...todayRow, cache_hit_rate: hitRate },
|
|
@@ -124,16 +124,16 @@ export function queryStatsExplorer(params) {
|
|
|
124
124
|
}
|
|
125
125
|
const where = conds.length ? 'WHERE ' + conds.join(' AND ') : '';
|
|
126
126
|
try {
|
|
127
|
-
return db.prepare(`
|
|
128
|
-
SELECT
|
|
129
|
-
strftime('${strfmt}', ts/1000, 'unixepoch', 'localtime') AS period,
|
|
130
|
-
COALESCE(SUM(input_tokens),0) AS input_tokens,
|
|
131
|
-
COALESCE(SUM(output_tokens),0) AS output_tokens,
|
|
132
|
-
COALESCE(SUM(cache_creation_tokens),0) AS cache_creation_tokens,
|
|
133
|
-
COALESCE(SUM(cache_read_tokens),0) AS cache_read_tokens,
|
|
134
|
-
COUNT(*) AS call_count
|
|
135
|
-
FROM usage_events ${where}
|
|
136
|
-
GROUP BY period ORDER BY period
|
|
127
|
+
return db.prepare(`
|
|
128
|
+
SELECT
|
|
129
|
+
strftime('${strfmt}', ts/1000, 'unixepoch', 'localtime') AS period,
|
|
130
|
+
COALESCE(SUM(input_tokens),0) AS input_tokens,
|
|
131
|
+
COALESCE(SUM(output_tokens),0) AS output_tokens,
|
|
132
|
+
COALESCE(SUM(cache_creation_tokens),0) AS cache_creation_tokens,
|
|
133
|
+
COALESCE(SUM(cache_read_tokens),0) AS cache_read_tokens,
|
|
134
|
+
COUNT(*) AS call_count
|
|
135
|
+
FROM usage_events ${where}
|
|
136
|
+
GROUP BY period ORDER BY period
|
|
137
137
|
`).all(...p);
|
|
138
138
|
}
|
|
139
139
|
finally {
|
|
@@ -162,14 +162,14 @@ export function queryStatsByPeer(params) {
|
|
|
162
162
|
const where = conds.length ? 'WHERE ' + conds.join(' AND ') : '';
|
|
163
163
|
const limit = params.limit ?? 50;
|
|
164
164
|
try {
|
|
165
|
-
const rows = db.prepare(`
|
|
166
|
-
SELECT peer_key, peer_type,
|
|
167
|
-
COALESCE(SUM(input_tokens),0) AS input_tokens,
|
|
168
|
-
COALESCE(SUM(output_tokens),0) AS output_tokens,
|
|
169
|
-
COALESCE(SUM(cache_read_tokens),0) AS cache_read_tokens,
|
|
170
|
-
COUNT(*) AS call_count
|
|
171
|
-
FROM usage_events ${where}
|
|
172
|
-
GROUP BY peer_key ORDER BY (COALESCE(SUM(input_tokens),0) + COALESCE(SUM(output_tokens),0)) DESC LIMIT ${limit}
|
|
165
|
+
const rows = db.prepare(`
|
|
166
|
+
SELECT peer_key, peer_type,
|
|
167
|
+
COALESCE(SUM(input_tokens),0) AS input_tokens,
|
|
168
|
+
COALESCE(SUM(output_tokens),0) AS output_tokens,
|
|
169
|
+
COALESCE(SUM(cache_read_tokens),0) AS cache_read_tokens,
|
|
170
|
+
COUNT(*) AS call_count
|
|
171
|
+
FROM usage_events ${where}
|
|
172
|
+
GROUP BY peer_key ORDER BY (COALESCE(SUM(input_tokens),0) + COALESCE(SUM(output_tokens),0)) DESC LIMIT ${limit}
|
|
173
173
|
`).all(...p);
|
|
174
174
|
// 为每个peer添加名称和详细信息
|
|
175
175
|
return rows.map((row) => {
|
|
@@ -212,34 +212,34 @@ export function queryStatsOverview(params) {
|
|
|
212
212
|
}
|
|
213
213
|
const where = conds.length ? 'WHERE ' + conds.join(' AND ') : '';
|
|
214
214
|
// Token and cost aggregation with filters
|
|
215
|
-
const allRow = db.prepare(`
|
|
216
|
-
SELECT
|
|
217
|
-
COALESCE(SUM(input_tokens),0) AS input_tokens,
|
|
218
|
-
COALESCE(SUM(output_tokens),0) AS output_tokens,
|
|
219
|
-
COALESCE(SUM(cache_creation_tokens),0) AS cache_creation_tokens,
|
|
220
|
-
COALESCE(SUM(cache_read_tokens),0) AS cache_read_tokens,
|
|
221
|
-
COUNT(*) AS call_count,
|
|
222
|
-
COALESCE(SUM(cost_official_usd),0) AS cost_official_usd,
|
|
223
|
-
COALESCE(SUM(cost_official_cny),0) AS cost_official_cny,
|
|
224
|
-
COALESCE(SUM(cost_gateway_usd),0) AS cost_usd,
|
|
225
|
-
COALESCE(SUM(cost_gateway_cny),0) AS cost_cny
|
|
226
|
-
FROM usage_events ${where}
|
|
215
|
+
const allRow = db.prepare(`
|
|
216
|
+
SELECT
|
|
217
|
+
COALESCE(SUM(input_tokens),0) AS input_tokens,
|
|
218
|
+
COALESCE(SUM(output_tokens),0) AS output_tokens,
|
|
219
|
+
COALESCE(SUM(cache_creation_tokens),0) AS cache_creation_tokens,
|
|
220
|
+
COALESCE(SUM(cache_read_tokens),0) AS cache_read_tokens,
|
|
221
|
+
COUNT(*) AS call_count,
|
|
222
|
+
COALESCE(SUM(cost_official_usd),0) AS cost_official_usd,
|
|
223
|
+
COALESCE(SUM(cost_official_cny),0) AS cost_official_cny,
|
|
224
|
+
COALESCE(SUM(cost_gateway_usd),0) AS cost_usd,
|
|
225
|
+
COALESCE(SUM(cost_gateway_cny),0) AS cost_cny
|
|
226
|
+
FROM usage_events ${where}
|
|
227
227
|
`).get(...p);
|
|
228
228
|
// By agent aggregation with filters
|
|
229
|
-
const byAgentRows = db.prepare(`
|
|
230
|
-
SELECT agent_aid,
|
|
231
|
-
COALESCE(SUM(input_tokens),0) AS input_tokens,
|
|
232
|
-
COALESCE(SUM(output_tokens),0) AS output_tokens,
|
|
233
|
-
COALESCE(SUM(cache_creation_tokens),0) AS cache_creation_tokens,
|
|
234
|
-
COALESCE(SUM(cache_read_tokens),0) AS cache_read_tokens,
|
|
235
|
-
COUNT(*) AS call_count,
|
|
236
|
-
COALESCE(SUM(cost_official_usd),0) AS cost_official_usd,
|
|
237
|
-
COALESCE(SUM(cost_official_cny),0) AS cost_official_cny,
|
|
238
|
-
COALESCE(SUM(cost_gateway_usd),0) AS cost_usd,
|
|
239
|
-
COALESCE(SUM(cost_gateway_cny),0) AS cost_cny
|
|
240
|
-
FROM usage_events ${where}
|
|
241
|
-
GROUP BY agent_aid
|
|
242
|
-
ORDER BY (COALESCE(SUM(input_tokens),0) + COALESCE(SUM(output_tokens),0)) DESC
|
|
229
|
+
const byAgentRows = db.prepare(`
|
|
230
|
+
SELECT agent_aid,
|
|
231
|
+
COALESCE(SUM(input_tokens),0) AS input_tokens,
|
|
232
|
+
COALESCE(SUM(output_tokens),0) AS output_tokens,
|
|
233
|
+
COALESCE(SUM(cache_creation_tokens),0) AS cache_creation_tokens,
|
|
234
|
+
COALESCE(SUM(cache_read_tokens),0) AS cache_read_tokens,
|
|
235
|
+
COUNT(*) AS call_count,
|
|
236
|
+
COALESCE(SUM(cost_official_usd),0) AS cost_official_usd,
|
|
237
|
+
COALESCE(SUM(cost_official_cny),0) AS cost_official_cny,
|
|
238
|
+
COALESCE(SUM(cost_gateway_usd),0) AS cost_usd,
|
|
239
|
+
COALESCE(SUM(cost_gateway_cny),0) AS cost_cny
|
|
240
|
+
FROM usage_events ${where}
|
|
241
|
+
GROUP BY agent_aid
|
|
242
|
+
ORDER BY (COALESCE(SUM(input_tokens),0) + COALESCE(SUM(output_tokens),0)) DESC
|
|
243
243
|
`).all(...p);
|
|
244
244
|
// 为每个agent添加名称
|
|
245
245
|
const byAgentWithNames = byAgentRows.map((row) => ({
|
|
@@ -303,14 +303,14 @@ export function queryStatsByAgent(params) {
|
|
|
303
303
|
const where = conds.length ? 'WHERE ' + conds.join(' AND ') : '';
|
|
304
304
|
const limit = params.limit ?? 50;
|
|
305
305
|
try {
|
|
306
|
-
const rows = db.prepare(`
|
|
307
|
-
SELECT agent_aid,
|
|
308
|
-
COALESCE(SUM(input_tokens),0) AS input_tokens,
|
|
309
|
-
COALESCE(SUM(output_tokens),0) AS output_tokens,
|
|
310
|
-
COALESCE(SUM(cache_read_tokens),0) AS cache_read_tokens,
|
|
311
|
-
COUNT(*) AS call_count
|
|
312
|
-
FROM usage_events ${where}
|
|
313
|
-
GROUP BY agent_aid ORDER BY (COALESCE(SUM(input_tokens),0) + COALESCE(SUM(output_tokens),0)) DESC LIMIT ${limit}
|
|
306
|
+
const rows = db.prepare(`
|
|
307
|
+
SELECT agent_aid,
|
|
308
|
+
COALESCE(SUM(input_tokens),0) AS input_tokens,
|
|
309
|
+
COALESCE(SUM(output_tokens),0) AS output_tokens,
|
|
310
|
+
COALESCE(SUM(cache_read_tokens),0) AS cache_read_tokens,
|
|
311
|
+
COUNT(*) AS call_count
|
|
312
|
+
FROM usage_events ${where}
|
|
313
|
+
GROUP BY agent_aid ORDER BY (COALESCE(SUM(input_tokens),0) + COALESCE(SUM(output_tokens),0)) DESC LIMIT ${limit}
|
|
314
314
|
`).all(...p);
|
|
315
315
|
// 为每个agent添加名称
|
|
316
316
|
return rows.map((row) => ({
|
|
@@ -353,15 +353,15 @@ export function queryUsageDetail(params) {
|
|
|
353
353
|
const countRow = db.prepare(`SELECT COUNT(*) as total FROM usage_events ${where}`).get(...p);
|
|
354
354
|
const total = countRow?.total || 0;
|
|
355
355
|
// 获取数据
|
|
356
|
-
const data = db.prepare(`
|
|
357
|
-
SELECT ts, agent_aid, peer_key, model,
|
|
358
|
-
input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens,
|
|
359
|
-
COALESCE(cost_official_usd, 0) AS cost_official_usd,
|
|
360
|
-
COALESCE(cost_official_cny, 0) AS cost_official_cny,
|
|
361
|
-
COALESCE(cost_gateway_usd, 0) AS cost_gateway_usd,
|
|
362
|
-
COALESCE(cost_gateway_cny, 0) AS cost_gateway_cny
|
|
363
|
-
FROM usage_events ${where}
|
|
364
|
-
ORDER BY ts DESC LIMIT ${limit} OFFSET ${offset}
|
|
356
|
+
const data = db.prepare(`
|
|
357
|
+
SELECT ts, agent_aid, peer_key, model,
|
|
358
|
+
input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens,
|
|
359
|
+
COALESCE(cost_official_usd, 0) AS cost_official_usd,
|
|
360
|
+
COALESCE(cost_official_cny, 0) AS cost_official_cny,
|
|
361
|
+
COALESCE(cost_gateway_usd, 0) AS cost_gateway_usd,
|
|
362
|
+
COALESCE(cost_gateway_cny, 0) AS cost_gateway_cny
|
|
363
|
+
FROM usage_events ${where}
|
|
364
|
+
ORDER BY ts DESC LIMIT ${limit} OFFSET ${offset}
|
|
365
365
|
`).all(...p);
|
|
366
366
|
// 为每条记录添加agent_name (需要从文件系统读取agent.md)
|
|
367
367
|
const dataWithNames = data.map((row) => ({
|
|
@@ -391,10 +391,10 @@ export function queryUsedModels(params) {
|
|
|
391
391
|
}
|
|
392
392
|
const where = conds.length ? 'WHERE ' + conds.join(' AND ') : '';
|
|
393
393
|
try {
|
|
394
|
-
const rows = db.prepare(`
|
|
395
|
-
SELECT DISTINCT model
|
|
396
|
-
FROM usage_events ${where}
|
|
397
|
-
ORDER BY model
|
|
394
|
+
const rows = db.prepare(`
|
|
395
|
+
SELECT DISTINCT model
|
|
396
|
+
FROM usage_events ${where}
|
|
397
|
+
ORDER BY model
|
|
398
398
|
`).all(...p);
|
|
399
399
|
return rows.map((row) => row.model).filter(Boolean);
|
|
400
400
|
}
|