@swestash/agent-lens 0.6.0 → 0.7.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/agent-lens.js +93 -1
- package/dist/agent-lens.js.map +1 -1
- package/package.json +1 -1
- package/web/assets/{CopyButton-XWWtxa5T.js → CopyButton--e68pO3S.js} +1 -1
- package/web/assets/Dashboard-Ce5pBLCZ.js +69 -0
- package/web/assets/SecurityView-C2cpbxxV.js +1 -0
- package/web/assets/{SessionView-qPYTooYU.js → SessionView-Q6Ec76B9.js} +1 -1
- package/web/assets/{SkillView-BuWdX4As.js → SkillView-ByxQC40e.js} +1 -1
- package/web/assets/{SkillsView-D8Wtsxi6.js → SkillsView-D_CwXBGT.js} +1 -1
- package/web/assets/{WorkflowView-Afsv_IWs.js → WorkflowView-Ddmg3evU.js} +1 -1
- package/web/assets/{index-T6SPgI6b.js → index--T4VdWmP.js} +1 -1
- package/web/assets/index-BTQM3Zlg.js +68 -0
- package/web/assets/index-DuZ7WdnZ.css +1 -0
- package/web/assets/{severity-DkldRG9Z.js → severity-B-8BLd1n.js} +1 -1
- package/web/index.html +2 -2
- package/web/assets/Dashboard-BQX66iZp.js +0 -69
- package/web/assets/SecurityView-C_CfNLoD.js +0 -1
- package/web/assets/index-BkDuOrzs.js +0 -68
- package/web/assets/index-CPyBa1Te.css +0 -1
package/dist/agent-lens.js
CHANGED
|
@@ -4487,6 +4487,53 @@ function pct(sorted, p) {
|
|
|
4487
4487
|
const rank = Math.ceil(p / 100 * sorted.length) - 1;
|
|
4488
4488
|
return sorted[Math.min(Math.max(rank, 0), sorted.length - 1)];
|
|
4489
4489
|
}
|
|
4490
|
+
function tableExists2(db, name) {
|
|
4491
|
+
return !!db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name = ?").get(name);
|
|
4492
|
+
}
|
|
4493
|
+
function workflowWhere(f) {
|
|
4494
|
+
const where = [];
|
|
4495
|
+
const params = [];
|
|
4496
|
+
if (f.source)
|
|
4497
|
+
where.push("source_id = ?"), params.push(f.source);
|
|
4498
|
+
if (f.from)
|
|
4499
|
+
where.push("date(started_at) >= date(?)"), params.push(f.from);
|
|
4500
|
+
if (f.to)
|
|
4501
|
+
where.push("date(started_at) <= date(?)"), params.push(f.to);
|
|
4502
|
+
return { sql: where.length ? `WHERE ${where.join(" AND ")}` : "", params };
|
|
4503
|
+
}
|
|
4504
|
+
function workflowAgg(db, f) {
|
|
4505
|
+
const empty = { total: 0, by_status: [], completed: 0, failed: 0, success_rate: 0, total_tokens: 0, avg_duration_ms: 0 };
|
|
4506
|
+
if (!tableExists2(db, "workflow_results"))
|
|
4507
|
+
return empty;
|
|
4508
|
+
const ww = workflowWhere(f);
|
|
4509
|
+
const rows = db.prepare(`SELECT COALESCE(status, '(unknown)') status, COUNT(*) n,
|
|
4510
|
+
SUM(COALESCE(total_tokens, 0)) tokens,
|
|
4511
|
+
SUM(COALESCE(duration_ms, 0)) dur,
|
|
4512
|
+
SUM(CASE WHEN duration_ms IS NOT NULL THEN 1 ELSE 0 END) dur_n
|
|
4513
|
+
FROM workflow_results ${ww.sql} GROUP BY status ORDER BY n DESC`).all(...ww.params);
|
|
4514
|
+
let total = 0, completed = 0, failed = 0, tokens = 0, durSum = 0, durN = 0;
|
|
4515
|
+
const by_status = rows.map((r) => {
|
|
4516
|
+
total += r.n;
|
|
4517
|
+
if (r.status === "completed")
|
|
4518
|
+
completed += r.n;
|
|
4519
|
+
else if (r.status === "failed")
|
|
4520
|
+
failed += r.n;
|
|
4521
|
+
tokens += r.tokens ?? 0;
|
|
4522
|
+
durSum += r.dur ?? 0;
|
|
4523
|
+
durN += r.dur_n ?? 0;
|
|
4524
|
+
return { status: r.status, n: r.n };
|
|
4525
|
+
});
|
|
4526
|
+
const decided = completed + failed;
|
|
4527
|
+
return {
|
|
4528
|
+
total,
|
|
4529
|
+
by_status,
|
|
4530
|
+
completed,
|
|
4531
|
+
failed,
|
|
4532
|
+
success_rate: decided ? completed / decided : 0,
|
|
4533
|
+
total_tokens: tokens,
|
|
4534
|
+
avg_duration_ms: durN ? Math.round(durSum / durN) : 0
|
|
4535
|
+
};
|
|
4536
|
+
}
|
|
4490
4537
|
function dashboardOverview(db, f) {
|
|
4491
4538
|
const w = sessionWhere(f);
|
|
4492
4539
|
const counts = db.prepare(`SELECT
|
|
@@ -4513,6 +4560,8 @@ function dashboardOverview(db, f) {
|
|
|
4513
4560
|
const totalTokens = tokens.input + tokens.output + tokens.cache_creation + tokens.cache_read;
|
|
4514
4561
|
const durs = db.prepare(`SELECT tn.duration_ms d FROM turns tn JOIN sessions s ON s.id = tn.session_id
|
|
4515
4562
|
${w.sql ? w.sql + " AND" : "WHERE"} tn.duration_ms IS NOT NULL ORDER BY tn.duration_ms`).all(...w.params).map((r) => r.d);
|
|
4563
|
+
const sessDurs = db.prepare(`SELECT s.duration_ms d FROM sessions s
|
|
4564
|
+
${w.sql ? w.sql + " AND" : "WHERE"} s.is_sidechain = 0 AND s.duration_ms IS NOT NULL ORDER BY s.duration_ms`).all(...w.params).map((r) => r.d);
|
|
4516
4565
|
return {
|
|
4517
4566
|
range: { from: f.from ?? null, to: f.to ?? null, source: f.source ?? null },
|
|
4518
4567
|
sessions: counts.sessions ?? 0,
|
|
@@ -4527,7 +4576,9 @@ function dashboardOverview(db, f) {
|
|
|
4527
4576
|
cache_read_ratio: totalTokens ? tokens.cache_read / totalTokens : 0,
|
|
4528
4577
|
cost: Number(cost.toFixed(4)),
|
|
4529
4578
|
unpriced_models: [...new Set(unpriced)].sort(),
|
|
4530
|
-
turn_duration_ms: { p50: pct(durs, 50), p95: pct(durs, 95), count: durs.length }
|
|
4579
|
+
turn_duration_ms: { p50: pct(durs, 50), p95: pct(durs, 95), count: durs.length },
|
|
4580
|
+
session_duration_ms: { p50: pct(sessDurs, 50), p95: pct(sessDurs, 95), count: sessDurs.length },
|
|
4581
|
+
workflows: workflowAgg(db, f)
|
|
4531
4582
|
};
|
|
4532
4583
|
}
|
|
4533
4584
|
function chooseBucket(db, f) {
|
|
@@ -4751,12 +4802,33 @@ function listMutes(db) {
|
|
|
4751
4802
|
return db.prepare("SELECT rule_id, scope, scope_id, note, muted_at FROM muted_rules ORDER BY muted_at DESC").all();
|
|
4752
4803
|
}
|
|
4753
4804
|
|
|
4805
|
+
// ../server/dist/prefs.js
|
|
4806
|
+
var PREFS_SCHEMA_SQL = (
|
|
4807
|
+
/* sql */
|
|
4808
|
+
`
|
|
4809
|
+
CREATE TABLE IF NOT EXISTS ui_prefs (
|
|
4810
|
+
key TEXT PRIMARY KEY, -- e.g. 'dashboard.charts', 'sessions.columns'
|
|
4811
|
+
value TEXT NOT NULL, -- JSON blob, opaque to the server
|
|
4812
|
+
updated_at TEXT NOT NULL
|
|
4813
|
+
);
|
|
4814
|
+
`
|
|
4815
|
+
);
|
|
4816
|
+
function getPref(db, key) {
|
|
4817
|
+
const row = db.prepare("SELECT value FROM ui_prefs WHERE key = ?").get(key);
|
|
4818
|
+
return row ? row.value : null;
|
|
4819
|
+
}
|
|
4820
|
+
function setPref(db, key, value) {
|
|
4821
|
+
db.prepare(`INSERT INTO ui_prefs (key, value, updated_at) VALUES (?, ?, ?)
|
|
4822
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`).run(key, value, (/* @__PURE__ */ new Date()).toISOString());
|
|
4823
|
+
}
|
|
4824
|
+
|
|
4754
4825
|
// ../server/dist/app.js
|
|
4755
4826
|
async function createApp(db, opts = {}) {
|
|
4756
4827
|
const app = Fastify({ logger: false });
|
|
4757
4828
|
let triageDb = null;
|
|
4758
4829
|
if (opts.triageDbPath) {
|
|
4759
4830
|
triageDb = openTriage(opts.triageDbPath);
|
|
4831
|
+
triageDb.exec(PREFS_SCHEMA_SQL);
|
|
4760
4832
|
db.exec(`ATTACH DATABASE '${opts.triageDbPath.replace(/'/g, "''")}' AS triage`);
|
|
4761
4833
|
app.addHook("onClose", async () => triageDb?.close());
|
|
4762
4834
|
}
|
|
@@ -4803,6 +4875,26 @@ async function createApp(db, opts = {}) {
|
|
|
4803
4875
|
return dashboardTimeseries(db, dashFilters(req), q.bucket);
|
|
4804
4876
|
});
|
|
4805
4877
|
app.get("/api/dashboard/breakdowns", async (req) => dashboardBreakdowns(db, dashFilters(req)));
|
|
4878
|
+
const PREF_KEY = /^[a-z0-9._-]{1,64}$/i;
|
|
4879
|
+
app.get("/api/prefs/:key", async (req, reply) => {
|
|
4880
|
+
const { key } = req.params;
|
|
4881
|
+
if (!PREF_KEY.test(key))
|
|
4882
|
+
return reply.code(400).send({ error: { code: "BAD_KEY", message: "invalid pref key" } });
|
|
4883
|
+
if (!triageDb)
|
|
4884
|
+
return { value: null };
|
|
4885
|
+
const raw = getPref(triageDb, key);
|
|
4886
|
+
return { value: raw == null ? null : JSON.parse(raw) };
|
|
4887
|
+
});
|
|
4888
|
+
app.put("/api/prefs/:key", async (req, reply) => {
|
|
4889
|
+
const { key } = req.params;
|
|
4890
|
+
if (!PREF_KEY.test(key))
|
|
4891
|
+
return reply.code(400).send({ error: { code: "BAD_KEY", message: "invalid pref key" } });
|
|
4892
|
+
if (!guardWrite(req, reply))
|
|
4893
|
+
return;
|
|
4894
|
+
const body = req.body;
|
|
4895
|
+
setPref(triageDb, key, JSON.stringify(body?.value ?? null));
|
|
4896
|
+
return { ok: true };
|
|
4897
|
+
});
|
|
4806
4898
|
app.get("/api/sessions", async (req) => {
|
|
4807
4899
|
const q = req.query;
|
|
4808
4900
|
return listSessions(db, {
|