v0.2.8 operator dashboard with per-call audit log + cost tracking

This commit is contained in:
local
2026-05-12 00:26:59 -05:00
parent 9af70302b1
commit 05ebeb5d51
12 changed files with 924 additions and 13 deletions
+45
View File
@@ -12,6 +12,8 @@ import { getConfigSnapshot } from "../config.js";
import { snapshotAll } from "../credits.js";
import { snapshotCache } from "../keysat-client.js";
import { snapshotJobs } from "../job-credits.js";
import { readEntries, aggregate } from "../audit-log.js";
import { GEMINI_PRICING } from "../pricing.js";
import fs from "fs/promises";
import path from "path";
@@ -48,6 +50,49 @@ export function adminRouter({ dataDir }) {
res.json({ entries: snapshotJobs() });
});
// ── Dashboard ─────────────────────────────────────────────────────────
// Time-range aggregations over the per-call audit log. Default range
// is the last 30 days; override with ?days=N or ?since=<ms-epoch>.
// Returns { range, summary, by_tier, by_model, by_pipeline,
// by_backend, by_install, by_hour_utc, cost_vs_speed, pricing }.
router.get("/dashboard", async (req, res) => {
const days =
typeof req.query.days === "string"
? parseInt(req.query.days, 10)
: null;
const explicitSince =
typeof req.query.since === "string"
? parseInt(req.query.since, 10)
: null;
const sinceMs =
explicitSince && Number.isFinite(explicitSince)
? explicitSince
: Date.now() -
(Number.isFinite(days) && days > 0 ? days : 30) *
24 *
3600 *
1000;
try {
const entries = await readEntries({ sinceMs });
const agg = aggregate(entries);
res.json({
range: {
since_ms: sinceMs,
until_ms: Date.now(),
days: Number.isFinite(days) && days > 0 ? days : null,
total_entries: entries.length,
},
...agg,
pricing: GEMINI_PRICING,
});
} catch (err) {
console.error(`[admin/dashboard] failed: ${err?.message || err}`);
res
.status(500)
.json({ error: "dashboard_failed", message: err?.message || String(err) });
}
});
// Adjust the live quotas blob. Same shape the StartOS action writes
// to relay_tier_quotas_json — kept here so the dashboard can tune
// quotas without round-tripping the StartOS UI.