feat(ui,api,admin): sveltekit admin spa, usage by day/agent/conversation/model, rate limits, memory tree, turn snapshot

This commit is contained in:
hh
2026-08-28 22:14:15 +02:00
parent 61562e947d
commit 98796a82c6
158 changed files with 8459 additions and 2531 deletions
+184
View File
@@ -0,0 +1,184 @@
const THOUSAND = 1000;
const MILLION = 1_000_000;
const MINUTE_MS = 60_000;
const HOUR_MS = 3_600_000;
const DAY_MS = 86_400_000;
const KB = 1024;
const WHITESPACE = /\s+/g;
export function fmtTokens(n: number | null | undefined): string {
if (n === null || n === undefined) {
return "";
}
if (n >= MILLION) {
return `${(n / MILLION).toFixed(n >= 10 * MILLION ? 0 : 1)}M`;
}
if (n >= THOUSAND) {
return `${(n / THOUSAND).toFixed(n >= 10 * THOUSAND ? 0 : 1)}k`;
}
return String(n);
}
export function fmtMoney(usd: number | null | undefined): string {
if (usd === null || usd === undefined) {
return "";
}
if (usd === 0) {
return "$0";
}
if (usd < 0.01) {
return `$${usd.toFixed(4)}`;
}
if (usd < 1) {
return `$${usd.toFixed(3)}`;
}
return `$${usd.toFixed(2)}`;
}
export function fmtPct(fraction: number | null | undefined): string {
if (fraction === null || fraction === undefined) {
return "";
}
return `${Math.round(fraction * 100)}%`;
}
export function fmtDuration(ms: number | null | undefined): string {
if (ms === null || ms === undefined) {
return "";
}
if (ms < THOUSAND) {
return `${Math.round(ms)}ms`;
}
if (ms < MINUTE_MS) {
return `${(ms / THOUSAND).toFixed(1)}s`;
}
if (ms < HOUR_MS) {
const minutes = Math.floor(ms / MINUTE_MS);
const seconds = Math.round((ms % MINUTE_MS) / THOUSAND);
return `${minutes}m${String(seconds).padStart(2, "0")}s`;
}
const hours = Math.floor(ms / HOUR_MS);
const minutes = Math.round((ms % HOUR_MS) / MINUTE_MS);
return `${hours}h${String(minutes).padStart(2, "0")}m`;
}
export function fmtSeconds(seconds: number | null | undefined): string {
return seconds === null || seconds === undefined
? ""
: fmtDuration(seconds * THOUSAND);
}
export function fmtBytes(bytes: number | null | undefined): string {
if (bytes === null || bytes === undefined) {
return "";
}
if (bytes >= KB * KB * KB) {
return `${(bytes / (KB * KB * KB)).toFixed(2)} GB`;
}
if (bytes >= KB * KB) {
return `${(bytes / (KB * KB)).toFixed(0)} MB`;
}
if (bytes >= KB) {
return `${(bytes / KB).toFixed(0)} kB`;
}
return `${bytes} B`;
}
export function parseDate(iso: string | null | undefined): Date | null {
if (!iso) {
return null;
}
const date = new Date(iso);
return Number.isNaN(date.getTime()) ? null : date;
}
export function fmtTime(iso: string | null | undefined): string {
const date = parseDate(iso);
return date
? date.toLocaleTimeString(undefined, {
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
})
: "";
}
export function fmtDateTime(iso: string | null | undefined): string {
const date = parseDate(iso);
return date
? date.toLocaleString(undefined, {
day: "numeric",
hour: "2-digit",
minute: "2-digit",
month: "short",
})
: "";
}
export function fmtRelative(
iso: string | null | undefined,
now = Date.now()
): string {
const date = parseDate(iso);
if (!date) {
return "";
}
const diff = now - date.getTime();
const abs = Math.abs(diff);
const suffix = diff >= 0 ? "ago" : "from now";
if (abs < MINUTE_MS) {
return diff >= 0 ? "just now" : "in <1m";
}
if (abs < HOUR_MS) {
return `${Math.round(abs / MINUTE_MS)}m ${suffix}`;
}
if (abs < DAY_MS) {
return `${Math.round(abs / HOUR_MS)}h ${suffix}`;
}
return `${Math.round(abs / DAY_MS)}d ${suffix}`;
}
export function fmtCountdown(iso: string | null | undefined, now = Date.now()) {
const date = parseDate(iso);
if (!date) {
return "";
}
const left = date.getTime() - now;
if (left <= 0) {
return "resets now";
}
if (left < HOUR_MS) {
return `resets in ${Math.ceil(left / MINUTE_MS)}m`;
}
if (left < DAY_MS) {
const hours = Math.floor(left / HOUR_MS);
const minutes = Math.round((left % HOUR_MS) / MINUTE_MS);
return `resets in ${hours}h ${String(minutes).padStart(2, "0")}m`;
}
const days = Math.floor(left / DAY_MS);
const hours = Math.round((left % DAY_MS) / HOUR_MS);
return `resets in ${days}d ${hours}h`;
}
export function elapsedMs(from: string, to: string | null, now = Date.now()) {
const a = parseDate(from)?.getTime();
const b = to ? parseDate(to)?.getTime() : now;
if (a === undefined || b === undefined) {
return 0;
}
return Math.max(0, b - a);
}
export function clip(text: string, max: number): string {
const one = text.replace(WHITESPACE, " ").trim();
return one.length > max ? `${one.slice(0, max - 1)}` : one;
}
export function shortId(id: string | null | undefined): string {
return id ? id.slice(0, 8) : "";
}
export function cacheShare(input: number, cacheRead: number): number | null {
const total = input + cacheRead;
return total > 0 ? cacheRead / total : null;
}