mirror of
https://github.com/github/awesome-copilot.git
synced 2026-10-13 07:14:24 +00:00
239 lines
14 KiB
JavaScript
239 lines
14 KiB
JavaScript
import { calendarDate, shiftDate } from "./time.mjs";
|
|
|
|
export const COUNTERS = ["aiu", "tokens", "input", "output", "cacheRead", "cacheWrite", "reasoning"];
|
|
const FIELDS = {
|
|
aiu: "total_nano_aiu", input: "input_tokens", output: "output_tokens",
|
|
cacheRead: "cache_read_tokens", cacheWrite: "cache_write_tokens", reasoning: "reasoning_tokens",
|
|
};
|
|
const iso = value => value == null ? null
|
|
: new Date(Math.round((value - 2440587.5) * 86400000)).toISOString();
|
|
|
|
function metric(value, recordedCalls, completeCalls, totalCalls) {
|
|
return { value: value == null ? null : Number(value), recordedCalls, completeCalls,
|
|
totalCalls, complete: totalCalls > 0 && completeCalls === totalCalls };
|
|
}
|
|
|
|
function decode(row) {
|
|
const requests = Number(row.requests);
|
|
const metrics = Object.fromEntries(COUNTERS.map(key => [key, metric(
|
|
row[key], Number(row[`${key}Recorded`]), Number(row[`${key}Complete`]), requests,
|
|
)]));
|
|
metrics.requests = metric(requests, requests, requests, requests);
|
|
return {
|
|
requests, activeDays: Number(row.activeDays), metrics,
|
|
aiu: metrics.aiu.value, tokens: metrics.tokens.value,
|
|
tokenComposition: Object.fromEntries(COUNTERS.slice(2).map(key => [key, metrics[key].value])),
|
|
avgTtftMs: row.ttft == null ? null : Math.round(row.ttft),
|
|
avgDurationMs: row.duration == null ? null : Math.round(row.duration),
|
|
first: iso(row.first), last: iso(row.last),
|
|
};
|
|
}
|
|
|
|
export function readUsageWindow(db, start, end, now, { details = false, startAt, endAt } = {}) {
|
|
const columns = new Set(db.prepare("PRAGMA table_info(assistant_usage_events)")
|
|
.all().map(row => row.name));
|
|
if (!columns.has("created_at")) {
|
|
const metrics = Object.fromEntries([...COUNTERS, "requests"].map(key =>
|
|
[key, metric(key === "requests" ? 0 : null, 0, 0, 0)]));
|
|
return {
|
|
requests: 0, activeDays: 0, aiu: null, tokens: null, metrics, tokenComposition: {},
|
|
models: [], effort: [], initiator: [], series: [], sessionGroups: [],
|
|
avgTtftMs: null, avgDurationMs: null, first: null, last: null,
|
|
coverage: { status: "unavailable", first: null, last: null,
|
|
recordingSince: null, missingFields: ["assistant_usage_events.created_at"],
|
|
message: "Detailed usage is not recorded in this store. Activity history is still available." },
|
|
attribution: { supported: false, matchedCalls: 0, unattributedCalls: 0 },
|
|
};
|
|
}
|
|
const field = name => columns.has(name) ? `u.${name}` : "NULL";
|
|
const input = field("input_tokens"), output = field("output_tokens");
|
|
const anyTokens = `(${input} IS NOT NULL OR ${output} IS NOT NULL)`;
|
|
const bothTokens = `(${input} IS NOT NULL AND ${output} IS NOT NULL)`;
|
|
const select = ["COUNT(*) requests", "COUNT(DISTINCT calendar_date(u.created_at)) activeDays",
|
|
"MIN(julianday(u.created_at)) first",
|
|
"MAX(julianday(u.created_at)) last"];
|
|
for (const key of COUNTERS) {
|
|
const expr = key === "tokens"
|
|
? `CASE WHEN ${anyTokens} THEN COALESCE(${input},0)+COALESCE(${output},0) END`
|
|
: field(FIELDS[key]);
|
|
const recorded = key === "tokens" ? anyTokens : `${expr} IS NOT NULL`;
|
|
const complete = key === "tokens" ? bothTokens : recorded;
|
|
select.push(`SUM(${expr})${key === "aiu" ? "/1e9" : ""} ${key}`,
|
|
`COUNT(CASE WHEN ${recorded} THEN 1 END) ${key}Recorded`,
|
|
`COUNT(CASE WHEN ${complete} THEN 1 END) ${key}Complete`);
|
|
}
|
|
select.push(`AVG(${field("time_to_first_token_ms")}) ttft`,
|
|
`AVG(${field("duration_ms")}) duration`);
|
|
const metricSql = select.join(", ");
|
|
let predicate = "calendar_date(u.created_at) >= ? AND calendar_date(u.created_at) < ? AND julianday(u.created_at) <= julianday(?)";
|
|
const args = [start, end, now.toISOString()];
|
|
if (startAt) { predicate += " AND julianday(u.created_at) >= julianday(?)"; args.push(startAt); }
|
|
if (endAt) { predicate += " AND julianday(u.created_at) < julianday(?)"; args.push(endAt); }
|
|
const from = `FROM assistant_usage_events u WHERE ${predicate}`;
|
|
const modelExpr = `COALESCE(NULLIF(${field("model")},''), 'unknown')`;
|
|
const row = db.prepare(`SELECT ${metricSql} ${from}`).get(...args);
|
|
const summary = decode(row);
|
|
const models = db.prepare(`SELECT ${modelExpr} modelKey, ${metricSql} ${from}
|
|
GROUP BY modelKey ORDER BY aiu DESC`).all(...args).map(value => ({
|
|
model: value.modelKey, reqs: Number(value.requests), ...decode(value),
|
|
}));
|
|
const distribution = name => columns.has(name) ? db.prepare(`SELECT
|
|
COALESCE(NULLIF(u.${name},''), 'unknown') label, COUNT(*) count ${from}
|
|
GROUP BY label ORDER BY count DESC`).all(...args) : [];
|
|
const global = db.prepare(`SELECT MIN(julianday(created_at)) first,
|
|
MAX(julianday(created_at)) last FROM assistant_usage_events
|
|
WHERE julianday(created_at) <= julianday(?)`).get(now.toISOString());
|
|
const invalid = db.prepare(`SELECT COUNT(*) count FROM assistant_usage_events
|
|
WHERE julianday(created_at) IS NULL`).get();
|
|
const coverage = {
|
|
status: summary.requests ? "available" : "empty", first: summary.first, last: summary.last,
|
|
recordingSince: iso(global.first), latestRecorded: iso(global.last),
|
|
invalidTimestampCalls: Number(invalid.count),
|
|
missingFields: [...Object.values(FIELDS), "model", "session_id",
|
|
"reasoning_effort", "initiator", "time_to_first_token_ms", "duration_ms"]
|
|
.filter(name => !columns.has(name)),
|
|
message: "Local recorded calls only, not account-wide billing. Gaps may mean inactivity or missing recording.",
|
|
};
|
|
const result = { ...summary, models, effort: distribution("reasoning_effort"),
|
|
initiator: distribution("initiator"), coverage };
|
|
if (!details) return result;
|
|
const daily = db.prepare(`SELECT calendar_date(u.created_at) date, ${metricSql} ${from}
|
|
GROUP BY date ORDER BY date`).all(...args).map(value => ({ date: value.date, ...decode(value) }));
|
|
const modelDays = db.prepare(`SELECT ${modelExpr} modelKey,
|
|
calendar_date(u.created_at) date, ${metricSql} ${from}
|
|
GROUP BY modelKey, date ORDER BY date`).all(...args)
|
|
.map(value => ({ model: value.modelKey, date: value.date, ...decode(value) }));
|
|
let sessionGroups = [];
|
|
if (columns.has("session_id")) {
|
|
sessionGroups = db.prepare(`SELECT ${modelExpr} modelKey,
|
|
s.id sessionKey, MIN(julianday(s.created_at)) started,
|
|
MAX(s.repository) repository, ${metricSql}
|
|
FROM assistant_usage_events u LEFT JOIN sessions s ON s.id=u.session_id
|
|
WHERE ${predicate} GROUP BY modelKey, sessionKey LIMIT 20001`).all(...args);
|
|
if (sessionGroups.length > 20000) {
|
|
throw Object.assign(new Error("This range is too large for session inspection. Choose a narrower range."),
|
|
{ code: "RANGE_TOO_LARGE", statusCode: 413 });
|
|
}
|
|
sessionGroups = sessionGroups.map(value => ({
|
|
model: value.modelKey, sessionId: value.sessionKey,
|
|
startedAt: iso(value.started), repository: value.repository || null,
|
|
beforeRange: value.started != null && calendarDate(iso(value.started)) < start,
|
|
...decode(value),
|
|
}));
|
|
}
|
|
const matchedCalls = sessionGroups.filter(value => value.sessionId != null)
|
|
.reduce((sum, value) => sum + value.requests, 0);
|
|
return { ...result, daily, modelDays, sessionGroups,
|
|
attribution: { supported: columns.has("session_id"), matchedCalls,
|
|
unattributedCalls: summary.requests - matchedCalls } };
|
|
}
|
|
|
|
export function combineMetrics(rows) {
|
|
const totalCalls = rows.reduce((sum, row) => sum + row.requests, 0);
|
|
const metrics = Object.fromEntries(COUNTERS.map(key => {
|
|
const values = rows.map(row => row.metrics[key]);
|
|
const known = values.filter(value => value.value != null);
|
|
return [key, metric(known.length ? known.reduce((sum, value) => sum + value.value, 0) : null,
|
|
values.reduce((sum, value) => sum + value.recordedCalls, 0),
|
|
values.reduce((sum, value) => sum + value.completeCalls, 0), totalCalls)];
|
|
}));
|
|
metrics.requests = metric(totalCalls, totalCalls, totalCalls, totalCalls);
|
|
return metrics;
|
|
}
|
|
|
|
export function makeSeries(daily, start, end) {
|
|
if (!daily.length) return { points: [], granularity: "day" };
|
|
const first = start === "0000-01-01" ? daily[0].date : start;
|
|
const dayCount = Math.round((Date.parse(`${end}T12:00:00Z`) -
|
|
Date.parse(`${first}T12:00:00Z`)) / 86400000);
|
|
const granularity = dayCount <= 120 ? "day" : dayCount <= 1825 ? "week" : "month";
|
|
const bucket = date => {
|
|
if (granularity === "month") return `${date.slice(0, 7)}-01`;
|
|
if (granularity === "week") {
|
|
return shiftDate(date, -((new Date(`${date}T12:00:00Z`).getUTCDay() + 6) % 7));
|
|
}
|
|
return date;
|
|
};
|
|
const groups = new Map();
|
|
for (const row of daily) {
|
|
const key = bucket(row.date);
|
|
if (!groups.has(key)) groups.set(key, []);
|
|
groups.get(key).push(row);
|
|
}
|
|
const points = [];
|
|
for (let date = first; date < end;) {
|
|
const key = bucket(date);
|
|
const metrics = combineMetrics(groups.get(key) || []);
|
|
points.push({ date: key, metrics, aiu: metrics.aiu.value,
|
|
tokens: metrics.tokens.value, requests: metrics.requests.value });
|
|
if (granularity === "month") {
|
|
const next = new Date(`${key}T12:00:00Z`);
|
|
next.setUTCMonth(next.getUTCMonth() + 1);
|
|
date = next.toISOString().slice(0, 10);
|
|
} else {
|
|
date = shiftDate(key, granularity === "week" ? 7 : 1);
|
|
}
|
|
}
|
|
return { points, granularity };
|
|
}
|
|
|
|
export const PULSE_RULES = Object.freeze({
|
|
minimumCalls: 20, minimumActiveDays: 3, minimumAiuBaseline: 1,
|
|
minimumChangePct: 20, concentrationShare: 0.7,
|
|
});
|
|
|
|
export function buildPulse(stats, current, previous, comparisonWindow) {
|
|
const evidence = [
|
|
`${stats.range === "all" ? "All recorded history" : `${stats.range} calendar days`}; snapshot as of ${stats.generatedAt}.`,
|
|
`${stats.kpis.requests} recorded model calls. These are not premium requests or a productivity score.`,
|
|
stats.usageCoverage.message,
|
|
];
|
|
if (stats.usageCoverage.recordingSince) {
|
|
evidence.push(`Earliest retained usage: ${stats.usageCoverage.recordingSince}. This is not proof of uninterrupted coverage.`);
|
|
}
|
|
const ready = value => value.requests >= PULSE_RULES.minimumCalls &&
|
|
value.activeDays >= PULSE_RULES.minimumActiveDays;
|
|
if (comparisonWindow) {
|
|
evidence.push(`Comparison excludes partial today: ${comparisonWindow.start} to ${shiftDate(comparisonWindow.end, -1)} versus ${comparisonWindow.previousStart} to ${shiftDate(comparisonWindow.start, -1)}.`);
|
|
evidence.push(`Samples: ${current.requests} calls on ${current.activeDays} active recording days versus ${previous.requests} calls on ${previous.activeDays} days. Gates: 20 calls and 3 active days in each period.`);
|
|
const retainedBaseline = stats.usageCoverage.recordingSince &&
|
|
calendarDate(stats.usageCoverage.recordingSince) <= comparisonWindow.previousStart;
|
|
if (!retainedBaseline) evidence.push("Retained usage begins after the previous period starts; a partial baseline cannot support a comparison.");
|
|
if (retainedBaseline && ready(current) && ready(previous)) {
|
|
const costReady = current.metrics.aiu.complete && previous.metrics.aiu.complete &&
|
|
previous.aiu >= PULSE_RULES.minimumAiuBaseline;
|
|
const key = costReady ? "aiu" : "requests";
|
|
const before = previous[key], after = current[key];
|
|
const change = before ? (after - before) / before * 100 : null;
|
|
if (change != null && Math.abs(change) >= PULSE_RULES.minimumChangePct - Number.EPSILON * 100) {
|
|
const label = key === "aiu" ? "Recorded AIU" : "Recorded model calls";
|
|
return { kind: "change",
|
|
headline: `${label} ${change > 0 ? "rose" : "fell"} ${Math.abs(change).toFixed(0)}% across comparable days`,
|
|
summary: `${current.requests} calls versus ${previous.requests} in the preceding period. This describes recorded consumption, not efficiency or quality.`,
|
|
comparison: { key, current: after, previous: before, change, window: comparisonWindow },
|
|
evidence: [...evidence, `${label}: ${after} versus ${before}. Percentage gate: at least 20% change; AIU baseline must be at least 1 with complete counters.`] };
|
|
}
|
|
}
|
|
} else {
|
|
evidence.push("All-time has no previous-period comparison.");
|
|
}
|
|
const ranked = stats.models.filter(row => row.aiu != null).slice().sort((a, b) => b.aiu - a.aiu);
|
|
if (stats.kpis.requests >= PULSE_RULES.minimumCalls && stats.metrics.aiu.complete &&
|
|
ranked.length >= 2 && stats.kpis.aiu > 0 &&
|
|
ranked[0].aiu / stats.kpis.aiu >= PULSE_RULES.concentrationShare) {
|
|
const share = ranked[0].aiu / stats.kpis.aiu;
|
|
return { kind: "concentration", headline: `${ranked[0].model} accounts for ${(share * 100).toFixed(0)}% of recorded AIU`,
|
|
driver: { model: ranked[0].model, value: ranked[0].aiu, total: stats.kpis.aiu, share },
|
|
summary: "Explore its contributing sessions before deciding whether to change anything. Model mix alone does not establish value or waste.",
|
|
evidence: [...evidence, `${ranked[0].aiu} of ${stats.kpis.aiu} AIU. Gates: at least 2 models, 20 calls, complete AIU, and 70% contribution.`] };
|
|
}
|
|
if (!stats.hasUsage) {
|
|
return { kind: "unavailable", headline: "Your activity is here; detailed usage needs a baseline",
|
|
summary: "Browse recorded activity or use local Copilot sessions, then refresh. Missing token counters are not zero usage.",
|
|
evidence };
|
|
}
|
|
return { kind: "baseline", headline: "Your recorded usage is taking shape",
|
|
summary: `${stats.kpis.requests} model calls in this view. There is not yet a qualifying comparison or multi-model concentration signal.`,
|
|
evidence: [...evidence, "No claim passed the conservative evidence gates. Missing counters and sparse or partial periods cannot establish a trend."] };
|
|
}
|