pi-harness-runtime 0.2.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/windows.ts ADDED
@@ -0,0 +1,121 @@
1
+ /**
2
+ * WindowAggregator — compute rolling 5h + weekly windows from local records.
3
+ *
4
+ * We do NOT need provider-reported reset times — we can DERIVE them from our
5
+ * own data: oldest record in window + window duration = when that record
6
+ * will fall out of the window = the "reset" moment for OUR local usage.
7
+ *
8
+ * For provider-mirror reset times, we just read them from MirrorStore.
9
+ */
10
+
11
+ import type { UsageRecord } from "./tracker.ts";
12
+
13
+ export const FIVE_HOURS_MS = 5 * 60 * 60 * 1000;
14
+ export const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;
15
+
16
+ export interface WindowStats {
17
+ tokens: number;
18
+ requests: number;
19
+ cost: number;
20
+ oldest_ts: number | null; // oldest record in window (for reset calculation)
21
+ }
22
+
23
+ export interface AggregatedWindows {
24
+ five_h: WindowStats;
25
+ weekly: WindowStats;
26
+ today: WindowStats; // since midnight UTC (computed too — handy)
27
+ lifetime: WindowStats;
28
+ }
29
+
30
+ function emptyWindow(): WindowStats {
31
+ return { tokens: 0, requests: 0, cost: 0, oldest_ts: null };
32
+ }
33
+
34
+ function rollUp(records: UsageRecord[]): WindowStats {
35
+ const stats = emptyWindow();
36
+ for (const r of records) {
37
+ const tokens = r.input + r.output + r.cache_read + r.cache_write;
38
+ stats.tokens += tokens;
39
+ stats.requests += 1;
40
+ stats.cost += r.cost;
41
+ if (stats.oldest_ts === null || r.ts < stats.oldest_ts) {
42
+ stats.oldest_ts = r.ts;
43
+ }
44
+ }
45
+ return stats;
46
+ }
47
+
48
+ /** Compute reset time for a rolling window from its oldest record. */
49
+ export function computeLocalResetTime(stats: WindowStats, windowMs: number): number | null {
50
+ if (stats.oldest_ts === null) return null;
51
+ return stats.oldest_ts + windowMs;
52
+ }
53
+
54
+ /** Filter records within a rolling window. */
55
+ function withinWindow(records: UsageRecord[], nowMs: number, windowMs: number): UsageRecord[] {
56
+ const cutoff = nowMs - windowMs;
57
+ return records.filter((r) => r.ts >= cutoff);
58
+ }
59
+
60
+ /** UTC midnight (ms) of the day containing `nowMs`. */
61
+ function utcMidnight(nowMs: number): number {
62
+ const d = new Date(nowMs);
63
+ return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
64
+ }
65
+
66
+ /** Monday 00:00 UTC of the week containing `nowMs`. */
67
+ function weeklyCutoff(nowMs: number): number {
68
+ const d = new Date(nowMs);
69
+ const day = d.getUTCDay(); // 0=Sun..6=Sat
70
+ const diff = (day + 6) % 7; // days since Monday
71
+ const mondayMidnight = utcMidnight(nowMs) - diff * 86400 * 1000;
72
+ return mondayMidnight;
73
+ }
74
+
75
+ /** Main entry: aggregate all windows from raw records. */
76
+ export function aggregateWindows(records: UsageRecord[], nowMs: number = Date.now()): AggregatedWindows {
77
+ const five_h = rollUp(withinWindow(records, nowMs, FIVE_HOURS_MS));
78
+ const weekly = rollUp(withinWindow(records, nowMs, SEVEN_DAYS_MS));
79
+ const today = rollUp(records.filter((r) => r.ts >= utcMidnight(nowMs)));
80
+ const lifetime = rollUp(records);
81
+ return { five_h, weekly, today, lifetime };
82
+ }
83
+
84
+ /**
85
+ * Compute burn rate (% per day) from the weekly mirror.
86
+ * mirror.weekly_used_pct used, time since weekly reset = nowMs - weekly_resets_at.
87
+ */
88
+ export function computeBurnRate(
89
+ mirrorWeeklyUsedPct: number,
90
+ weeklyResetsAtMs: number,
91
+ nowMs: number,
92
+ ): { pct_per_day: number; days_until_full: number | null } {
93
+ const elapsedMs = nowMs - weeklyResetsAtMs;
94
+ if (elapsedMs <= 0) {
95
+ return { pct_per_day: 0, days_until_full: null };
96
+ }
97
+ const elapsedDays = elapsedMs / (24 * 60 * 60 * 1000);
98
+ const pctPerDay = mirrorWeeklyUsedPct / elapsedDays;
99
+ const remainingPct = 100 - mirrorWeeklyUsedPct;
100
+ if (pctPerDay <= 0) {
101
+ return { pct_per_day: 0, days_until_full: null };
102
+ }
103
+ const daysUntilFull = remainingPct / pctPerDay;
104
+ return { pct_per_day: pctPerDay, days_until_full: daysUntilFull };
105
+ }
106
+
107
+ /**
108
+ * Compute the divergence between local-tracked usage and provider mirror.
109
+ * Returns the difference in percentage points (positive = local > mirror).
110
+ *
111
+ * This is a rough check: if local tracking shows 5% used but provider
112
+ * mirror shows 30%, you know other clients (or pre-existing quota) are
113
+ * using the same provider account.
114
+ */
115
+ export function computeLocalVsMirrorDelta(
116
+ localFiveHPct: number,
117
+ mirrorFiveHPct: number | undefined,
118
+ ): number | null {
119
+ if (mirrorFiveHPct === undefined) return null;
120
+ return localFiveHPct - mirrorFiveHPct;
121
+ }