forked from EduCraft/curriculum-project-hub
feat(hub): usage fact breakdown API + admin usage/session UI + release v0.0.34 (#10)
Expose UsageFact kind/capability rollups on org and project usage reports, and add admin pages that separate model tokens from external-capability meters. Co-authored-by: Hong Jiarong <me@jrhim.com> Co-committed-by: Hong Jiarong <me@jrhim.com>
This commit is contained in:
@@ -193,13 +193,81 @@ export interface ProjectUsageRow extends UsageTotals {
|
||||
folderId: string | null;
|
||||
}
|
||||
|
||||
/** Ledger slice from UsageFact (ADR-0026): separates model tokens vs external meters. */
|
||||
export interface UsageBreakdownRow {
|
||||
kind: string;
|
||||
provider: string;
|
||||
model: string | null;
|
||||
capabilityId: string | null;
|
||||
unit: string | null;
|
||||
factCount: number;
|
||||
factsWithCost: number;
|
||||
factsWithoutCost: number;
|
||||
inputTokens: number;
|
||||
outputTokens: number;
|
||||
quantity: number | null;
|
||||
costUsd: number | null;
|
||||
}
|
||||
|
||||
export interface UsageReport {
|
||||
from: string | null;
|
||||
to: string | null;
|
||||
projects: ProjectUsageRow[];
|
||||
totals: UsageTotals;
|
||||
breakdown: UsageBreakdownRow[];
|
||||
}
|
||||
|
||||
export interface ProjectUsageReport extends ProjectUsageRow {
|
||||
from: string | null;
|
||||
to: string | null;
|
||||
breakdown: UsageBreakdownRow[];
|
||||
}
|
||||
|
||||
export interface UsageFactRow {
|
||||
id: string;
|
||||
occurredAt: string;
|
||||
kind: string;
|
||||
provider: string;
|
||||
model: string | null;
|
||||
inputTokens: number | null;
|
||||
outputTokens: number | null;
|
||||
quantity: number | null;
|
||||
unit: string | null;
|
||||
costUsd: number | null;
|
||||
costSource: string;
|
||||
capabilityId: string | null;
|
||||
correlationId: string | null;
|
||||
}
|
||||
|
||||
export interface SessionRunRow {
|
||||
id: string;
|
||||
status: string;
|
||||
model: string;
|
||||
provider: string;
|
||||
inputTokens: number | null;
|
||||
outputTokens: number | null;
|
||||
costUsd: number | null;
|
||||
costSource: string | null;
|
||||
startedAt: string;
|
||||
finishedAt: string | null;
|
||||
error: string | null;
|
||||
usageFacts: UsageFactRow[];
|
||||
}
|
||||
|
||||
export interface SessionDetail {
|
||||
id: string;
|
||||
provider: string;
|
||||
roleId: string;
|
||||
model: string;
|
||||
title: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
archivedAt: string | null;
|
||||
project: { id: string; name: string };
|
||||
runs: SessionRunRow[];
|
||||
}
|
||||
|
||||
|
||||
export type CapacityDimension =
|
||||
| 'requestRate'
|
||||
| 'requestBodySize'
|
||||
@@ -353,6 +421,8 @@ export const api = {
|
||||
get(`${orgBase(slug)}/projects/${projectId}/sessions${limit !== undefined ? `?limit=${limit}` : ''}`) as Promise<{
|
||||
sessions: SessionSummary[];
|
||||
}>,
|
||||
session: (slug: string, sessionId: string) =>
|
||||
get(`${orgBase(slug)}/sessions/${encodeURIComponent(sessionId)}`) as Promise<SessionDetail>,
|
||||
usage: (slug: string, params?: { from?: string; to?: string; folderId?: string }) => {
|
||||
const q = new URLSearchParams();
|
||||
if (params?.from) q.set('from', params.from);
|
||||
@@ -361,6 +431,16 @@ export const api = {
|
||||
const qs = q.toString();
|
||||
return get(`${orgBase(slug)}/usage${qs ? `?${qs}` : ''}`) as Promise<UsageReport>;
|
||||
},
|
||||
projectUsage: (slug: string, projectId: string, params?: { from?: string; to?: string }) => {
|
||||
const q = new URLSearchParams();
|
||||
if (params?.from) q.set('from', params.from);
|
||||
if (params?.to) q.set('to', params.to);
|
||||
const qs = q.toString();
|
||||
return get(
|
||||
`${orgBase(slug)}/projects/${encodeURIComponent(projectId)}/usage${qs ? `?${qs}` : ''}`,
|
||||
) as Promise<ProjectUsageReport>;
|
||||
},
|
||||
|
||||
|
||||
providerConnections: (slug: string) =>
|
||||
get(`${orgBase(slug)}/provider-connections`) as Promise<{ connections: ProviderConnectionRow[] }>,
|
||||
|
||||
Reference in New Issue
Block a user