@songsid/agend 2.3.0-beta.6 → 2.3.0-beta.8
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/dist/agent-cli-instructions.md +1 -1
- package/dist/agent-cli.js +21 -2
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.js +4 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-file-read.js +68 -8
- package/dist/agent-file-read.js.map +1 -1
- package/dist/agent-whats-new.js +4 -0
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/auth-api.js +3 -1
- package/dist/auth-api.js.map +1 -1
- package/dist/authority/authority-state.d.ts +38 -0
- package/dist/authority/authority-state.js +114 -0
- package/dist/authority/authority-state.js.map +1 -0
- package/dist/authority/session-authorizations.d.ts +43 -0
- package/dist/authority/session-authorizations.js +102 -0
- package/dist/authority/session-authorizations.js.map +1 -0
- package/dist/authority/web-authority.d.ts +31 -11
- package/dist/authority/web-authority.js +39 -12
- package/dist/authority/web-authority.js.map +1 -1
- package/dist/cache-ledger.d.ts +16 -3
- package/dist/cache-ledger.js +33 -13
- package/dist/cache-ledger.js.map +1 -1
- package/dist/cache-service.d.ts +55 -3
- package/dist/cache-service.js +152 -16
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/mcp-tools.js +13 -7
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/classic-channel-manager.d.ts +2 -2
- package/dist/classic-channel-manager.js +2 -6
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/config-validator.js +10 -4
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.d.ts +2 -0
- package/dist/daemon.js +31 -9
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.d.ts +8 -0
- package/dist/delivery-outbox.js +7 -1
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/fleet-manager.d.ts +109 -2
- package/dist/fleet-manager.js +280 -12
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +2 -1
- package/dist/general-knowledge/skills/multi-channel/SKILL.md +2 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +89 -30
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +62 -8
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
- package/dist/human-delivery-receipts.d.ts +14 -0
- package/dist/human-delivery-receipts.js +42 -6
- package/dist/human-delivery-receipts.js.map +1 -1
- package/dist/instance-config-impact.js +1 -0
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-names.d.ts +4 -0
- package/dist/instance-names.js +12 -0
- package/dist/instance-names.js.map +1 -0
- package/dist/instructions.d.ts +8 -1
- package/dist/instructions.js +9 -2
- package/dist/instructions.js.map +1 -1
- package/dist/locale.js +52 -0
- package/dist/locale.js.map +1 -1
- package/dist/outbound-handlers.d.ts +6 -0
- package/dist/outbound-handlers.js +49 -2
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +57 -1
- package/dist/outbound-schemas.js +34 -2
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +8 -2
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/rollout-index.d.ts +5 -0
- package/dist/rollout-index.js +26 -5
- package/dist/rollout-index.js.map +1 -1
- package/dist/settings-api.d.ts +6 -0
- package/dist/settings-api.js +54 -1
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +31 -0
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +10 -1
- package/dist/settings-effect.js.map +1 -1
- package/dist/tool-permissions.d.ts +0 -7
- package/dist/tool-permissions.js +73 -5
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.d.ts +2 -1
- package/dist/topic-commands.js +2 -4
- package/dist/topic-commands.js.map +1 -1
- package/dist/types.d.ts +13 -2
- package/dist/ui/app-effects.js +46 -28
- package/dist/ui/chat-ambient.js +307 -0
- package/dist/ui/chat-effect-posters.js +8 -8
- package/dist/ui/chat-effects.js +51 -22
- package/dist/ui/chat-strings.js +21 -6
- package/dist/ui/chat-thread.js +1 -1
- package/dist/ui/fleet-usage.js +401 -0
- package/dist/ui/panel-chat.js +22 -9
- package/dist/ui/panel-fleet.js +6 -5
- package/dist/ui/panel-settings.js +10 -2
- package/dist/ui/settings-appearance.js +8 -0
- package/dist/ui/settings-mods.js +19 -6
- package/dist/ui/settings-owner-effects.js +3 -3
- package/dist/ui/settings-strings.js +30 -0
- package/dist/ui/settings-web-authority.js +91 -0
- package/dist/ui/shared/app-route.js +1 -1
- package/dist/ui/shared/app-session.js +2 -0
- package/dist/ui/shared/app-shell.js +2 -1
- package/dist/ui/shared/app-themes.js +24 -6
- package/dist/ui/shared/app.css +95 -0
- package/dist/ui/shared/effect-app-runtime.js +68 -19
- package/dist/ui/shared/effect-chat-runtime.js +16 -3
- package/dist/ui/shared/effect-frame.js +17 -3
- package/dist/ui/shared/effect-policy.js +18 -5
- package/dist/ui/shared/effect-profiler.js +31 -9
- package/dist/ui/shared/effect-registry.js +17 -41
- package/dist/ui/shared/effect-stock-trust.js +4 -4
- package/dist/ui/shared/effect-trial-stage.js +18 -7
- package/dist/ui/shared/fx-motion.js +67 -0
- package/dist/ui/shared/usage-dialog.js +8 -0
- package/dist/ui/shared/view-strings.js +4 -0
- package/dist/ui/shared/web-authorize.js +151 -0
- package/dist/usage-report.d.ts +158 -0
- package/dist/usage-report.js +226 -0
- package/dist/usage-report.js.map +1 -0
- package/dist/usage-rollup.d.ts +51 -0
- package/dist/usage-rollup.js +168 -0
- package/dist/usage-rollup.js.map +1 -0
- package/dist/web-ambient.d.ts +72 -0
- package/dist/web-ambient.js +154 -0
- package/dist/web-ambient.js.map +1 -0
- package/dist/web-api.d.ts +33 -0
- package/dist/web-api.js +148 -18
- package/dist/web-api.js.map +1 -1
- package/dist/web-appearance-tools.d.ts +3 -0
- package/dist/web-appearance-tools.js +18 -3
- package/dist/web-appearance-tools.js.map +1 -1
- package/dist/web-appearance-view.d.ts +14 -2
- package/dist/web-appearance-view.js +32 -5
- package/dist/web-appearance-view.js.map +1 -1
- package/dist/web-appearance.d.ts +15 -1
- package/dist/web-appearance.js +77 -1
- package/dist/web-appearance.js.map +1 -1
- package/dist/web-asset-parts.d.ts +2 -2
- package/dist/web-asset-parts.js +3 -3
- package/dist/web-asset-parts.js.map +1 -1
- package/dist/web-auth.js +3 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-effect-bootstrap.d.ts +12 -0
- package/dist/web-effect-bootstrap.js +49 -0
- package/dist/web-effect-bootstrap.js.map +1 -0
- package/dist/web-effect-bundle.js +46 -1
- package/dist/web-effect-bundle.js.map +1 -1
- package/dist/web-effect-playback.d.ts +30 -0
- package/dist/web-effect-playback.js +71 -0
- package/dist/web-effect-playback.js.map +1 -0
- package/dist/web-effect-profiles.d.ts +4 -4
- package/dist/web-effect-service.d.ts +11 -4
- package/dist/web-effect-service.js +25 -4
- package/dist/web-effect-service.js.map +1 -1
- package/dist/web-effect-tools.d.ts +1 -0
- package/dist/web-effect-tools.js +2 -1
- package/dist/web-effect-tools.js.map +1 -1
- package/dist/web-effect-worker.d.ts +1 -1
- package/dist/web-effect-worker.js +2 -2
- package/dist/web-effect-worker.js.map +1 -1
- package/dist/web-guest-access.js +3 -1
- package/dist/web-guest-access.js.map +1 -1
- package/dist/web-mod-agent.js +5 -1
- package/dist/web-mod-agent.js.map +1 -1
- package/dist/web-mod-bundle.d.ts +9 -1
- package/dist/web-mod-bundle.js +62 -3
- package/dist/web-mod-bundle.js.map +1 -1
- package/dist/web-mod-export.d.ts +9 -0
- package/dist/web-mod-export.js +21 -0
- package/dist/web-mod-export.js.map +1 -1
- package/dist/web-mod-store.d.ts +2 -1
- package/dist/web-mod-store.js +13 -6
- package/dist/web-mod-store.js.map +1 -1
- package/dist/web-session-authorization.d.ts +132 -0
- package/dist/web-session-authorization.js +193 -0
- package/dist/web-session-authorization.js.map +1 -0
- package/dist/web-session.d.ts +5 -0
- package/dist/web-session.js +16 -0
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +26 -2
- package/dist/web-settings-patch.js +50 -1
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-settings-tools.d.ts +8 -0
- package/dist/web-settings-tools.js +14 -1
- package/dist/web-settings-tools.js.map +1 -1
- package/dist/web-shell-routes.d.ts +1 -1
- package/dist/web-shell-routes.js +1 -1
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/web-theme-store.d.ts +39 -0
- package/dist/web-theme-store.js +122 -11
- package/dist/web-theme-store.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #2122: the usage report — tokens, requests, delivered messages and their API-equivalent at list price, per instance
|
|
3
|
+
* (or by backend, model, credential profile or team), over a range of days. Pure: it reads the ledgers' hours after the
|
|
4
|
+
* rollup's checkpoint and the rollup's days up to it (usage-rollup.ts), and the delivered-message counts; it never reads
|
|
5
|
+
* a transcript. docs/design/2122-usage-analysis.md.
|
|
6
|
+
*
|
|
7
|
+
* Honest by construction: an amount is "API-equivalent at list price (checked <date>) — not money spent"; an unpriced
|
|
8
|
+
* model's tokens are shown and its amount is not; Codex's cache writes are "not reported" (every CLI seen records 0),
|
|
9
|
+
* never priced as uncached; an instance whose backend AgEnD cannot measure is listed with its reason, never as $0.
|
|
10
|
+
*/
|
|
11
|
+
import type { Ledger } from "./cache-ledger.js";
|
|
12
|
+
import { type UsageDays } from "./usage-rollup.js";
|
|
13
|
+
export declare const USAGE_GROUPS: readonly ["instance", "backend", "model", "profile", "team"];
|
|
14
|
+
export type UsageGroup = typeof USAGE_GROUPS[number];
|
|
15
|
+
export declare const USAGE_RANGES: readonly ["today", "7d", "month", "all"];
|
|
16
|
+
export type UsageRange = {
|
|
17
|
+
kind: typeof USAGE_RANGES[number];
|
|
18
|
+
} | {
|
|
19
|
+
kind: "custom";
|
|
20
|
+
from: string;
|
|
21
|
+
to: string;
|
|
22
|
+
};
|
|
23
|
+
/** What every amount is, in words — the page, the CSV and the agent tool all carry it. */
|
|
24
|
+
export declare const usageBasis: (checked?: string) => string;
|
|
25
|
+
/**
|
|
26
|
+
* Daily rows returned at most (the CSV and the trend): one per day, source and model. Beyond it the report keeps the
|
|
27
|
+
* latest whole days and says from which date (`dailyFrom`); the rows and totals always cover the whole range.
|
|
28
|
+
*/
|
|
29
|
+
export declare const USAGE_DAILY_MAX = 20000;
|
|
30
|
+
export interface UsageInstanceInput {
|
|
31
|
+
name: string;
|
|
32
|
+
/** Its backend now: what it is collected with from here on (each slice of its history carries its own). */
|
|
33
|
+
backend: string;
|
|
34
|
+
/** The team it is in now (fleet.yaml), for the one grouping built from current settings. */
|
|
35
|
+
team: string | null;
|
|
36
|
+
/** Whether it is collected now; what it measured before (`ledger`, `days`) is reported either way. */
|
|
37
|
+
status: "ok" | "no_data" | "credit_billed" | "unsupported" | "shared";
|
|
38
|
+
with?: string[];
|
|
39
|
+
/** A snapshot taken together with `days` (cache-service.ts usageData): read-only here. */
|
|
40
|
+
ledger?: Ledger;
|
|
41
|
+
days?: UsageDays;
|
|
42
|
+
}
|
|
43
|
+
export interface UsageInput {
|
|
44
|
+
now: number;
|
|
45
|
+
zone: string;
|
|
46
|
+
range: UsageRange;
|
|
47
|
+
group: UsageGroup;
|
|
48
|
+
instances: UsageInstanceInput[];
|
|
49
|
+
messages: Array<{
|
|
50
|
+
instance: string;
|
|
51
|
+
hour: number;
|
|
52
|
+
count: number;
|
|
53
|
+
}>;
|
|
54
|
+
scanning: {
|
|
55
|
+
active: boolean;
|
|
56
|
+
caughtUp: boolean;
|
|
57
|
+
pendingBytes: number;
|
|
58
|
+
pendingFiles: number;
|
|
59
|
+
};
|
|
60
|
+
/** Daily rows at most (default USAGE_DAILY_MAX; tests lower it to reach the same path). */
|
|
61
|
+
dailyMax?: number;
|
|
62
|
+
}
|
|
63
|
+
export interface UsageTotals {
|
|
64
|
+
/** Uncached input. */
|
|
65
|
+
input: number;
|
|
66
|
+
output: number;
|
|
67
|
+
cacheRead: number;
|
|
68
|
+
cacheWrite5m: number;
|
|
69
|
+
cacheWrite1h: number;
|
|
70
|
+
/** OpenAI's one write column (Codex records 0: see `flags`). */
|
|
71
|
+
cacheWrite: number;
|
|
72
|
+
requests: number;
|
|
73
|
+
}
|
|
74
|
+
export interface UsageRow extends UsageTotals {
|
|
75
|
+
key: string;
|
|
76
|
+
total: number;
|
|
77
|
+
/** Delivered messages; null where a message has no such key (by model, by profile). */
|
|
78
|
+
messages: number | null;
|
|
79
|
+
/** The API-equivalent at list price of what is priced; null when nothing in it is. */
|
|
80
|
+
amount: number | null;
|
|
81
|
+
priced: "all" | "partial" | "none";
|
|
82
|
+
/**
|
|
83
|
+
* "cache_write_not_reported" (Codex), "not_priced" (with `unpriced`), "source_unknown" (hours counted before #2122:
|
|
84
|
+
* which backend and profile read them was not recorded).
|
|
85
|
+
*/
|
|
86
|
+
flags: string[];
|
|
87
|
+
unpriced: string[];
|
|
88
|
+
instances: string[];
|
|
89
|
+
backends: string[];
|
|
90
|
+
models: string[];
|
|
91
|
+
profiles: string[];
|
|
92
|
+
}
|
|
93
|
+
export interface UsageDaily extends UsageTotals {
|
|
94
|
+
date: string;
|
|
95
|
+
zone: string;
|
|
96
|
+
instance: string;
|
|
97
|
+
backend: string;
|
|
98
|
+
model: string;
|
|
99
|
+
tier: "long" | "standard";
|
|
100
|
+
profile: string;
|
|
101
|
+
amount: number | null;
|
|
102
|
+
flags: string[];
|
|
103
|
+
}
|
|
104
|
+
export interface UsageReport {
|
|
105
|
+
range: {
|
|
106
|
+
kind: UsageRange["kind"];
|
|
107
|
+
from: string;
|
|
108
|
+
to: string;
|
|
109
|
+
};
|
|
110
|
+
zone: string;
|
|
111
|
+
/** Days are made of whole UTC hours (§5.3): in a half-hour zone a day's edge falls on the hour that holds midnight. */
|
|
112
|
+
granularity: "hour";
|
|
113
|
+
basis: string;
|
|
114
|
+
pricesChecked: string;
|
|
115
|
+
group: UsageGroup;
|
|
116
|
+
rows: UsageRow[];
|
|
117
|
+
totals: UsageRow;
|
|
118
|
+
daily: UsageDaily[];
|
|
119
|
+
/**
|
|
120
|
+
* The daily rows (and the messages by day) are not the whole range: they start at `dailyFrom` (earlier days were too
|
|
121
|
+
* many rows to send), or — `dailyFrom` null — there are none at all (the latest day alone was more than the cap: a
|
|
122
|
+
* part of a day is never sent as if it were the day). The rows and totals always cover the whole range.
|
|
123
|
+
*/
|
|
124
|
+
dailyTruncated: boolean;
|
|
125
|
+
dailyFrom: string | null;
|
|
126
|
+
messagesDaily: Array<{
|
|
127
|
+
date: string;
|
|
128
|
+
instance: string;
|
|
129
|
+
count: number;
|
|
130
|
+
}>;
|
|
131
|
+
notMeasured: Array<{
|
|
132
|
+
name: string;
|
|
133
|
+
backend: string;
|
|
134
|
+
reason: "credit_billed" | "unsupported" | "no_data";
|
|
135
|
+
}>;
|
|
136
|
+
shared: Array<{
|
|
137
|
+
name: string;
|
|
138
|
+
backend: string;
|
|
139
|
+
with: string[];
|
|
140
|
+
}>;
|
|
141
|
+
/** Per measured instance: the merged UTC intervals its transcripts were read over (§5.5) — never inferred. */
|
|
142
|
+
coverage: Array<{
|
|
143
|
+
name: string;
|
|
144
|
+
intervals: Array<[number, number]>;
|
|
145
|
+
}>;
|
|
146
|
+
scanning: UsageInput["scanning"];
|
|
147
|
+
}
|
|
148
|
+
/** A range as asked (query string or tool argument); anything else is the last 7 days. */
|
|
149
|
+
export declare function usageRange(kind: unknown, from?: unknown, to?: unknown): UsageRange;
|
|
150
|
+
export declare const usageGroup: (g: unknown) => UsageGroup;
|
|
151
|
+
/** A local date (YYYY-MM-DD) moved by `n` calendar days — a date's arithmetic, never 24-hour steps (a DST day is 23 or 25). */
|
|
152
|
+
export declare const shiftDate: (date: string, n: number) => string;
|
|
153
|
+
/** The range's first and last local dates (inclusive) in `zone`: "7d" is today and the 6 calendar days before it. */
|
|
154
|
+
export declare function rangeDates(range: UsageRange, now: number, zone: string): {
|
|
155
|
+
from: string;
|
|
156
|
+
to: string;
|
|
157
|
+
};
|
|
158
|
+
export declare function buildUsageReport(input: UsageInput): UsageReport;
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { PRICES_CHECKED, ratesFor } from "./cache-prices.js";
|
|
2
|
+
import { hourSources, localDate } from "./usage-rollup.js";
|
|
3
|
+
export const USAGE_GROUPS = ["instance", "backend", "model", "profile", "team"];
|
|
4
|
+
export const USAGE_RANGES = ["today", "7d", "month", "all"];
|
|
5
|
+
/** What every amount is, in words — the page, the CSV and the agent tool all carry it. */
|
|
6
|
+
export const usageBasis = (checked = PRICES_CHECKED) => `API-equivalent at list price (checked ${checked}) — not money spent`;
|
|
7
|
+
/**
|
|
8
|
+
* Daily rows returned at most (the CSV and the trend): one per day, source and model. Beyond it the report keeps the
|
|
9
|
+
* latest whole days and says from which date (`dailyFrom`); the rows and totals always cover the whole range.
|
|
10
|
+
*/
|
|
11
|
+
export const USAGE_DAILY_MAX = 20_000;
|
|
12
|
+
const M = 1_000_000;
|
|
13
|
+
const DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
14
|
+
/** A range as asked (query string or tool argument); anything else is the last 7 days. */
|
|
15
|
+
export function usageRange(kind, from, to) {
|
|
16
|
+
if (kind === "custom" && typeof from === "string" && typeof to === "string" && DATE.test(from) && DATE.test(to) && from <= to)
|
|
17
|
+
return { kind: "custom", from, to };
|
|
18
|
+
return USAGE_RANGES.includes(kind) ? { kind: kind } : { kind: "7d" };
|
|
19
|
+
}
|
|
20
|
+
export const usageGroup = (g) => USAGE_GROUPS.includes(g) ? g : "instance";
|
|
21
|
+
/** A local date (YYYY-MM-DD) moved by `n` calendar days — a date's arithmetic, never 24-hour steps (a DST day is 23 or 25). */
|
|
22
|
+
export const shiftDate = (date, n) => new Date(Date.UTC(Number(date.slice(0, 4)), Number(date.slice(5, 7)) - 1, Number(date.slice(8, 10)) + n)).toISOString().slice(0, 10);
|
|
23
|
+
/** The range's first and last local dates (inclusive) in `zone`: "7d" is today and the 6 calendar days before it. */
|
|
24
|
+
export function rangeDates(range, now, zone) {
|
|
25
|
+
const today = localDate(now, zone);
|
|
26
|
+
switch (range.kind) {
|
|
27
|
+
case "today": return { from: today, to: today };
|
|
28
|
+
case "7d": return { from: shiftDate(today, -6), to: today };
|
|
29
|
+
case "month": return { from: `${today.slice(0, 8)}01`, to: today };
|
|
30
|
+
case "all": return { from: "0000-01-01", to: today };
|
|
31
|
+
case "custom": return { from: range.from, to: range.to };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const zero = () => ({ input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0, cacheWrite: 0, requests: 0 });
|
|
35
|
+
const addTotals = (into, [n, uncached, read, w5, w1h, w, out]) => {
|
|
36
|
+
into.requests += n;
|
|
37
|
+
into.input += uncached;
|
|
38
|
+
into.cacheRead += read;
|
|
39
|
+
into.cacheWrite5m += w5;
|
|
40
|
+
into.cacheWrite1h += w1h;
|
|
41
|
+
into.cacheWrite += w;
|
|
42
|
+
into.output += out;
|
|
43
|
+
};
|
|
44
|
+
const splitKey = (mk) => { const bar = mk.lastIndexOf("|"); return { model: mk.slice(0, bar), long: mk.slice(bar + 1) === "1" }; };
|
|
45
|
+
/**
|
|
46
|
+
* The list-price amount of one slice, or null when its model is not in the table. Codex writes not reported are 0 in the
|
|
47
|
+
* ledger (it marks writesSeen on the first one above 0), so they add nothing and are never priced as uncached input.
|
|
48
|
+
*/
|
|
49
|
+
function amountOf(model, long, [, uncached, read, w5, w1h, w, out]) {
|
|
50
|
+
const r = ratesFor(model, long ? Number.MAX_SAFE_INTEGER : 0);
|
|
51
|
+
if (!r)
|
|
52
|
+
return null;
|
|
53
|
+
return (uncached * r.input + read * r.read + w5 * r.write5m + w1h * r.write1h + w * r.write + out * r.output) / M;
|
|
54
|
+
}
|
|
55
|
+
const unknownSource = (s) => s.backend === "unknown" || s.profile === "unknown";
|
|
56
|
+
export function buildUsageReport(input) {
|
|
57
|
+
const { from, to } = rangeDates(input.range, input.now, input.zone);
|
|
58
|
+
const inRange = (date) => date >= from && date <= to;
|
|
59
|
+
const slices = [];
|
|
60
|
+
const notMeasured = [];
|
|
61
|
+
const shared = [];
|
|
62
|
+
const coverage = [];
|
|
63
|
+
for (const i of input.instances) {
|
|
64
|
+
// Its status is about collecting now; what it measured before — under another backend, or before it shared a
|
|
65
|
+
// working directory — is still its history and is reported below.
|
|
66
|
+
if (i.status === "shared")
|
|
67
|
+
shared.push({ name: i.name, backend: i.backend, with: i.with ?? [] });
|
|
68
|
+
else if (i.status !== "ok")
|
|
69
|
+
notMeasured.push({ name: i.name, backend: i.backend, reason: i.status === "credit_billed" ? "credit_billed" : i.status === "no_data" ? "no_data" : "unsupported" });
|
|
70
|
+
if (!i.ledger || !i.days)
|
|
71
|
+
continue;
|
|
72
|
+
coverage.push({ name: i.name, intervals: i.days.coverage.map(([a, b]) => [a, b]) });
|
|
73
|
+
// Codex: a write is reported only once a real one has been seen (every CLI so far records 0).
|
|
74
|
+
const writesSeen = i.ledger.writesSeen === true;
|
|
75
|
+
const base = { instance: i.name, team: i.team };
|
|
76
|
+
for (const row of i.days.rows) {
|
|
77
|
+
if (!inRange(row.date))
|
|
78
|
+
continue;
|
|
79
|
+
for (const [mk, tot] of Object.entries(row.m))
|
|
80
|
+
slices.push({ ...base, backend: row.be, writesReported: row.be !== "codex" || writesSeen, date: row.date, zone: row.zone, profile: row.pf, ...splitKey(mk), tot });
|
|
81
|
+
}
|
|
82
|
+
for (const [hk, hour] of Object.entries(i.ledger.hours)) {
|
|
83
|
+
const h = Number(hk);
|
|
84
|
+
if (h <= i.days.checkpoint)
|
|
85
|
+
continue; // already in the rollup: counted once (§5.2)
|
|
86
|
+
const date = localDate(h, input.zone);
|
|
87
|
+
if (!inRange(date))
|
|
88
|
+
continue;
|
|
89
|
+
for (const src of hourSources(hour)) {
|
|
90
|
+
for (const [mk, tot] of Object.entries(src.m))
|
|
91
|
+
slices.push({ ...base, backend: src.backend, writesReported: src.backend !== "codex" || writesSeen, date, zone: input.zone, profile: src.profile, ...splitKey(mk), tot });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const keyOf = (s) => {
|
|
96
|
+
switch (input.group) {
|
|
97
|
+
case "instance": return s.instance;
|
|
98
|
+
case "backend": return s.backend;
|
|
99
|
+
case "model": return s.model;
|
|
100
|
+
case "profile": return s.profile;
|
|
101
|
+
case "team": return s.team ?? "";
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const rows = new Map();
|
|
105
|
+
const newRow = (key) => ({ key, ...zero(), total: 0, messages: null, amount: null, priced: "none", flags: [], unpriced: [], instances: [], backends: [], models: [], profiles: [], _amount: 0, _pricedAny: false, _unpricedAny: false });
|
|
106
|
+
const uniq = (list, v) => { if (!list.includes(v))
|
|
107
|
+
list.push(v); };
|
|
108
|
+
// Daily rows: one per day, zone, agent, backend, model, tier and profile (an hour's slices summed into their day).
|
|
109
|
+
const dailyBy = new Map();
|
|
110
|
+
for (const s of slices) {
|
|
111
|
+
const key = keyOf(s);
|
|
112
|
+
const row = rows.get(key) ?? (rows.set(key, newRow(key)), rows.get(key));
|
|
113
|
+
addTotals(row, s.tot);
|
|
114
|
+
uniq(row.instances, s.instance);
|
|
115
|
+
uniq(row.backends, s.backend);
|
|
116
|
+
uniq(row.models, s.model);
|
|
117
|
+
uniq(row.profiles, s.profile);
|
|
118
|
+
const amount = amountOf(s.model, s.long, s.tot);
|
|
119
|
+
if (amount === null) {
|
|
120
|
+
row._unpricedAny = true;
|
|
121
|
+
uniq(row.unpriced, s.model);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
row._pricedAny = true;
|
|
125
|
+
row._amount += amount;
|
|
126
|
+
}
|
|
127
|
+
if (!s.writesReported)
|
|
128
|
+
uniq(row.flags, "cache_write_not_reported");
|
|
129
|
+
if (unknownSource(s))
|
|
130
|
+
uniq(row.flags, "source_unknown");
|
|
131
|
+
const tier = s.long ? "long" : "standard";
|
|
132
|
+
const dk = [s.date, s.zone, s.instance, s.backend, s.model, tier, s.profile].join("\u0000");
|
|
133
|
+
let d = dailyBy.get(dk);
|
|
134
|
+
if (!d) {
|
|
135
|
+
d = { date: s.date, zone: s.zone, instance: s.instance, backend: s.backend, model: s.model, tier, profile: s.profile, ...zero(), amount: amount === null ? null : 0,
|
|
136
|
+
flags: [...(s.writesReported ? [] : ["cache_write_not_reported"]), ...(amount === null ? ["not_priced"] : []), ...(unknownSource(s) ? ["source_unknown"] : [])] };
|
|
137
|
+
dailyBy.set(dk, d);
|
|
138
|
+
}
|
|
139
|
+
addTotals(d, s.tot);
|
|
140
|
+
if (amount !== null && d.amount !== null)
|
|
141
|
+
d.amount += amount;
|
|
142
|
+
}
|
|
143
|
+
const allDaily = [...dailyBy.values()].sort((a, b) => a.date.localeCompare(b.date) || a.instance.localeCompare(b.instance) || a.model.localeCompare(b.model) || a.zone.localeCompare(b.zone));
|
|
144
|
+
// Too many: the latest whole days that fit — never part of a day (a missing row would read as nothing used). Not even
|
|
145
|
+
// the latest day fits: no daily rows at all, said so (dailyTruncated with no dailyFrom).
|
|
146
|
+
let dailyFrom = null, daily = allDaily, truncated = false;
|
|
147
|
+
const cap = input.dailyMax ?? USAGE_DAILY_MAX;
|
|
148
|
+
if (allDaily.length > cap) {
|
|
149
|
+
truncated = true;
|
|
150
|
+
const perDate = new Map();
|
|
151
|
+
for (const d of allDaily)
|
|
152
|
+
perDate.set(d.date, (perDate.get(d.date) ?? 0) + 1);
|
|
153
|
+
let kept = 0;
|
|
154
|
+
for (const date of [...perDate.keys()].sort().reverse()) {
|
|
155
|
+
if (kept + perDate.get(date) > cap)
|
|
156
|
+
break;
|
|
157
|
+
kept += perDate.get(date);
|
|
158
|
+
dailyFrom = date;
|
|
159
|
+
}
|
|
160
|
+
daily = dailyFrom === null ? [] : allDaily.filter(d => d.date >= dailyFrom);
|
|
161
|
+
}
|
|
162
|
+
// Messages: delivered, per instance and hour (§5.4); placed on days the same way as tokens.
|
|
163
|
+
const messagesDaily = new Map();
|
|
164
|
+
const perInstance = new Map();
|
|
165
|
+
for (const m of input.messages) {
|
|
166
|
+
const date = localDate(m.hour, input.zone);
|
|
167
|
+
if (!inRange(date))
|
|
168
|
+
continue;
|
|
169
|
+
perInstance.set(m.instance, (perInstance.get(m.instance) ?? 0) + m.count);
|
|
170
|
+
const k = `${date}\u0000${m.instance}`;
|
|
171
|
+
const e = messagesDaily.get(k) ?? (messagesDaily.set(k, { date, instance: m.instance, count: 0 }), messagesDaily.get(k));
|
|
172
|
+
e.count += m.count;
|
|
173
|
+
}
|
|
174
|
+
const instTeam = new Map(input.instances.map(i => [i.name, i]));
|
|
175
|
+
if (input.group === "instance" || input.group === "backend" || input.group === "team") {
|
|
176
|
+
// An instance with messages but no measured tokens still gets a row (its tokens are not measured; it says so). A
|
|
177
|
+
// message is counted per instance only, so by backend it goes under the instance's backend now.
|
|
178
|
+
for (const [name, count] of perInstance) {
|
|
179
|
+
const i = instTeam.get(name);
|
|
180
|
+
const key = input.group === "instance" ? name : input.group === "backend" ? (i?.backend ?? "") : (i?.team ?? "");
|
|
181
|
+
const row = rows.get(key) ?? (rows.set(key, newRow(key)), rows.get(key));
|
|
182
|
+
row.messages = (row.messages ?? 0) + count;
|
|
183
|
+
uniq(row.instances, name);
|
|
184
|
+
if (i)
|
|
185
|
+
uniq(row.backends, i.backend);
|
|
186
|
+
}
|
|
187
|
+
for (const row of rows.values())
|
|
188
|
+
row.messages ??= 0;
|
|
189
|
+
}
|
|
190
|
+
const finish = (row) => {
|
|
191
|
+
const { _amount, _pricedAny, _unpricedAny, ...rest } = row;
|
|
192
|
+
rest.total = rest.input + rest.output + rest.cacheRead + rest.cacheWrite5m + rest.cacheWrite1h + rest.cacheWrite;
|
|
193
|
+
rest.amount = _pricedAny ? _amount : null;
|
|
194
|
+
rest.priced = _pricedAny ? (_unpricedAny ? "partial" : "all") : "none";
|
|
195
|
+
if (_unpricedAny)
|
|
196
|
+
uniq(rest.flags, "not_priced");
|
|
197
|
+
return rest;
|
|
198
|
+
};
|
|
199
|
+
const out = [...rows.values()].map(finish)
|
|
200
|
+
.sort((a, b) => (b.amount ?? -1) - (a.amount ?? -1) || b.total - a.total || a.key.localeCompare(b.key));
|
|
201
|
+
const totals = finish(newRow("all"));
|
|
202
|
+
for (const r of out) {
|
|
203
|
+
for (const k of ["input", "output", "cacheRead", "cacheWrite5m", "cacheWrite1h", "cacheWrite", "requests"])
|
|
204
|
+
totals[k] += r[k];
|
|
205
|
+
totals.total += r.total;
|
|
206
|
+
if (r.messages !== null)
|
|
207
|
+
totals.messages = (totals.messages ?? 0) + r.messages;
|
|
208
|
+
if (r.amount !== null)
|
|
209
|
+
totals.amount = (totals.amount ?? 0) + r.amount;
|
|
210
|
+
for (const f of r.flags)
|
|
211
|
+
uniq(totals.flags, f);
|
|
212
|
+
for (const m of r.unpriced)
|
|
213
|
+
uniq(totals.unpriced, m);
|
|
214
|
+
}
|
|
215
|
+
totals.priced = out.some(r => r.priced !== "none") ? (out.some(r => r.priced !== "all" && r.total > 0) ? "partial" : "all") : "none";
|
|
216
|
+
return {
|
|
217
|
+
range: { kind: input.range.kind, from, to }, zone: input.zone, granularity: "hour", basis: usageBasis(), pricesChecked: PRICES_CHECKED,
|
|
218
|
+
group: input.group, rows: out, totals,
|
|
219
|
+
daily, dailyTruncated: truncated, dailyFrom,
|
|
220
|
+
// Messages by day: the same window as the daily rows (none when there are none); their total stays in `totals`.
|
|
221
|
+
messagesDaily: [...messagesDaily.values()].filter(m => !truncated || (dailyFrom !== null && m.date >= dailyFrom))
|
|
222
|
+
.sort((a, b) => a.date.localeCompare(b.date) || a.instance.localeCompare(b.instance)),
|
|
223
|
+
notMeasured, shared, coverage, scanning: input.scanning,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=usage-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-report.js","sourceRoot":"","sources":["../src/usage-report.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,SAAS,EAAkB,MAAM,mBAAmB,CAAC;AAE3E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAU,CAAC;AAEzF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,CAAU,CAAC;AAErE,0FAA0F;AAC1F,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAO,GAAG,cAAc,EAAU,EAAE,CAAC,yCAAyC,OAAO,qBAAqB,CAAC;AACtI;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC;AAEtC,MAAM,CAAC,GAAG,SAAS,CAAC;AACpB,MAAM,IAAI,GAAG,qBAAqB,CAAC;AA8FnC,0FAA0F;AAC1F,MAAM,UAAU,UAAU,CAAC,IAAa,EAAE,IAAc,EAAE,EAAY;IACpE,IAAI,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,IAAI,EAAE;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IACnK,OAAQ,YAAmC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAmC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC9H,CAAC;AACD,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAU,EAAc,EAAE,CAAE,YAAmC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAe,CAAC,CAAC,CAAC,UAAU,CAAC;AAEtI,+HAA+H;AAC/H,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,CAAS,EAAU,EAAE,CAC3D,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAEvI,qHAAqH;AACrH,MAAM,UAAU,UAAU,CAAC,KAAiB,EAAE,GAAW,EAAE,IAAY;IACrE,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACnC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,OAAO,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;QAChD,KAAK,IAAI,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;QAC5D,KAAK,OAAO,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;QACnE,KAAK,KAAK,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;QACrD,KAAK,QAAQ,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC;IAC3D,CAAC;AACH,CAAC;AAED,MAAM,IAAI,GAAG,GAAgB,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;AACtI,MAAM,SAAS,GAAG,CAAC,IAAiB,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAa,EAAQ,EAAE;IAC9F,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;IAAC,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC;IAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC;IAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC;IAAC,IAAI,CAAC,YAAY,IAAI,GAAG,CAAC;IAAC,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC;IAAC,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC;AAClK,CAAC,CAAC;AACF,MAAM,QAAQ,GAAG,CAAC,EAAU,EAAoC,EAAE,GAAG,MAAM,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;AAE7K;;;GAGG;AACH,SAAS,QAAQ,CAAC,KAAa,EAAE,IAAa,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAa;IAC7F,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACpH,CAAC;AAGD,MAAM,aAAa,GAAG,CAAC,CAAQ,EAAW,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC;AAEhG,MAAM,UAAU,gBAAgB,CAAC,KAAiB;IAChD,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACpE,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;IAC7D,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,MAAM,WAAW,GAA+B,EAAE,CAAC;IACnD,MAAM,MAAM,GAA0B,EAAE,CAAC;IACzC,MAAM,QAAQ,GAA4B,EAAE,CAAC;IAC7C,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QAChC,6GAA6G;QAC7G,kEAAkE;QAClE,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ;YAAE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;aAC5F,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI;YAAE,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,KAAK,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC;QAChM,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,IAAI;YAAE,SAAS;QACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAqB,CAAC,EAAE,CAAC,CAAC;QACxG,8FAA8F;QAC9F,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,UAAU,KAAK,IAAI,CAAC;QAChD,MAAM,IAAI,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAChD,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAC9B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,SAAS;YACjC,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE,KAAK,OAAO,IAAI,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QACpN,CAAC;QACD,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACxD,MAAM,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;YACrB,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU;gBAAE,SAAS,CAAiB,6CAA6C;YACnG,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;gBAAE,SAAS;YAC7B,KAAK,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;gBACpC,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;oBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,CAAC,OAAO,KAAK,OAAO,IAAI,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;YAC3N,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,CAAQ,EAAU,EAAE;QACjC,QAAQ,KAAK,CAAC,KAAK,EAAE,CAAC;YACpB,KAAK,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;YACnC,KAAK,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;YACjC,KAAK,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;YAC7B,KAAK,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;YACjC,KAAK,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;QACnC,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,IAAI,GAAG,EAAe,CAAC;IACpC,MAAM,MAAM,GAAG,CAAC,GAAW,EAAO,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;IACtP,MAAM,IAAI,GAAG,CAAC,IAAc,EAAE,CAAS,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,mHAAmH;IACnH,MAAM,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC9C,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC,CAAC;QAC1E,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;QAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;QAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;QACzH,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;QAChD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAAC,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC;YAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QAAC,CAAC;aAAM,CAAC;YAAC,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC;YAAC,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC;QAAC,CAAC;QACrI,IAAI,CAAC,CAAC,CAAC,cAAc;YAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,0BAA0B,CAAC,CAAC;QACnE,IAAI,aAAa,CAAC,CAAC,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;QACxD,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC;QAC1C,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5F,IAAI,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACxB,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACjK,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACpK,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACrB,CAAC;QACD,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;QACpB,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI;YAAE,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC;IAC/D,CAAC;IACD,MAAM,QAAQ,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9L,sHAAsH;IACtH,yFAAyF;IACzF,IAAI,SAAS,GAAkB,IAAI,EAAE,KAAK,GAAG,QAAQ,EAAE,SAAS,GAAG,KAAK,CAAC;IACzE,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,IAAI,eAAe,CAAC;IAC9C,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QAC1B,SAAS,GAAG,IAAI,CAAC;QACjB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC1C,KAAK,MAAM,CAAC,IAAI,QAAQ;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9E,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;YACxD,IAAI,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAE,GAAG,GAAG;gBAAE,MAAM;YAC3C,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;YAAC,SAAS,GAAG,IAAI,CAAC;QAC/C,CAAC;QACD,KAAK,GAAG,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,SAAU,CAAC,CAAC;IAC/E,CAAC;IAED,4FAA4F;IAC5F,MAAM,aAAa,GAAG,IAAI,GAAG,EAA6D,CAAC;IAC3F,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC9C,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,SAAS;QAC7B,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAC1E,MAAM,CAAC,GAAG,GAAG,IAAI,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC;QACvC,MAAM,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,CAAC;QAC1H,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC;IACrB,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAChE,IAAI,KAAK,CAAC,KAAK,KAAK,UAAU,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;QACtF,iHAAiH;QACjH,gGAAgG;QAChG,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC;YACxC,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC7B,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YACjH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC,CAAC;YAC1E,GAAG,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC;YAC3C,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAC1B,IAAI,CAAC;gBAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE;YAAE,GAAG,CAAC,QAAQ,KAAK,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,GAAQ,EAAY,EAAE;QACpC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,GAAG,GAAG,CAAC;QAC3D,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC;QACjH,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1C,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACvE,IAAI,YAAY;YAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IACF,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;SACvC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1G,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;QACpB,KAAK,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,UAAU,CAAU;YAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACvI,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,CAAC,QAAQ,KAAK,IAAI;YAAE,MAAM,CAAC,QAAQ,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;QAC/E,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI;YAAE,MAAM,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;QACvE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK;YAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC/C,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ;YAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAErI,OAAO;QACL,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,aAAa,EAAE,cAAc;QACtI,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM;QACrC,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS;QAC3C,gHAAgH;QAChH,aAAa,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,SAAS,IAAI,CAAC,SAAS,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,SAAS,CAAC,CAAC;aAC9G,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACvF,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACxD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { HourAgg, HourTotals, Ledger } from "./cache-ledger.js";
|
|
2
|
+
export declare const ROLLUP_KEEP_DAYS = 400;
|
|
3
|
+
/** Coverage intervals kept per instance; beyond it the two oldest merge (an over-wide interval only hides a gap). */
|
|
4
|
+
export declare const COVERAGE_MAX = 64;
|
|
5
|
+
/** One day row: its local date, the zone it was folded in, its source (backend, profile) → model|tier → totals. */
|
|
6
|
+
export interface DayRow {
|
|
7
|
+
date: string;
|
|
8
|
+
zone: string;
|
|
9
|
+
be: string;
|
|
10
|
+
pf: string;
|
|
11
|
+
m: Record<string, HourTotals>;
|
|
12
|
+
}
|
|
13
|
+
/** Where an hour's totals were read: the backend whose reader read them ("unknown" before #2122), and the profile. */
|
|
14
|
+
export interface HourSource {
|
|
15
|
+
backend: string;
|
|
16
|
+
profile: string;
|
|
17
|
+
m: Record<string, HourTotals>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* An hour's totals by source (cache-ledger.ts `src`), each exact. What `m` holds beyond them was counted before #2122:
|
|
21
|
+
* one more source, backend and profile "unknown".
|
|
22
|
+
*/
|
|
23
|
+
export declare function hourSources(hour: HourAgg): HourSource[];
|
|
24
|
+
export interface UsageDays {
|
|
25
|
+
v: 1;
|
|
26
|
+
/** The last UTC hour (ms) held here; -1: none yet. */
|
|
27
|
+
checkpoint: number;
|
|
28
|
+
rows: DayRow[];
|
|
29
|
+
/** Merged UTC intervals [from, to] the scanner has read (§5.5). */
|
|
30
|
+
coverage: Array<[number, number]>;
|
|
31
|
+
}
|
|
32
|
+
export declare const emptyDays: () => UsageDays;
|
|
33
|
+
/** A rollup read back from disk; anything that is not one is empty. */
|
|
34
|
+
export declare function reviveDays(raw: unknown): UsageDays;
|
|
35
|
+
/** The local date (YYYY-MM-DD) an instant falls on in `zone` (an IANA name; an unknown one is UTC). */
|
|
36
|
+
export declare function localDate(t: number, zone: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Fold the ledger's hours that are about to leave it (older than `cutoff`) and after the checkpoint into their days.
|
|
39
|
+
* Mutates `days`; returns whether anything moved. Never folds an hour at or before the checkpoint (it is already here),
|
|
40
|
+
* so a fold repeated after a crash adds nothing twice.
|
|
41
|
+
*/
|
|
42
|
+
export declare function foldHours(days: UsageDays, ledger: Ledger, cutoff: number, zone: string): boolean;
|
|
43
|
+
/** Drop day rows older than the rollup keeps (by date, against `now` in `zone`). */
|
|
44
|
+
export declare function pruneDays(days: UsageDays, now: number, zone: string): boolean;
|
|
45
|
+
/** Record that the scanner has read [from, to]: merged into the intervals, at most COVERAGE_MAX of them. */
|
|
46
|
+
export declare function addCoverage(days: UsageDays, from: number, to: number): void;
|
|
47
|
+
/** Whether the scanner has read the hour starting at `h`. */
|
|
48
|
+
export declare const covered: (days: UsageDays, h: number) => boolean;
|
|
49
|
+
export declare function readDays(path: string): Promise<UsageDays>;
|
|
50
|
+
/** Written whole and renamed into place (0600): a crash leaves the old file or the new one, never a mix. */
|
|
51
|
+
export declare function writeDays(path: string, days: UsageDays): Promise<boolean>;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #2122 §5: the daily usage rollup — what the cache ledger (cache-ledger.ts, hourly, 31 days) no longer keeps, folded
|
|
3
|
+
* into days so the usage report can go back up to 400 days. One file per instance, `usage-days.json`, beside the ledger.
|
|
4
|
+
*
|
|
5
|
+
* - Two tiers, one checkpoint: an hour is in the rollup if and only if it is at or before `checkpoint` (a UTC hour);
|
|
6
|
+
* otherwise it is only in the ledger. A view is the rollup up to the checkpoint plus the ledger after it.
|
|
7
|
+
* - Fold, then prune: the hours about to leave the ledger and after the checkpoint are added to their days, the rollup
|
|
8
|
+
* is written (atomic rename) with the new checkpoint, and only then may the ledger drop hours at or before it
|
|
9
|
+
* (pruneLedger's `foldedThrough`). A crash between the two leaves those hours in both; the next fold skips them (they
|
|
10
|
+
* are at or before the checkpoint) and the prune finishes. A crash before the write moves nothing.
|
|
11
|
+
* - Days at hour granularity: an hour belongs to the local date its start falls on in the fleet's zone (in a zone with
|
|
12
|
+
* a half-hour offset a day's edge falls on the hour that holds local midnight — said so on the page). Each day row
|
|
13
|
+
* records its zone; changing the zone re-buckets only the ledger's hours.
|
|
14
|
+
* - Provenance: each row is one source — the backend whose reader read it and the credential profile it was read under
|
|
15
|
+
* (hourSources) — kept apart, so an instance that changes backend or profile never relabels what it read before.
|
|
16
|
+
* Hours counted before #2122 have no source: they are "unknown", never today's backend.
|
|
17
|
+
* - Coverage: what the scanner has read, as merged UTC intervals — never inferred from missing hours (an idle hour has
|
|
18
|
+
* no bucket and is a real zero).
|
|
19
|
+
* Messages are not here: they are counted in the delivery database (human-delivery-receipts.ts).
|
|
20
|
+
*/
|
|
21
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
22
|
+
import { dirname } from "node:path";
|
|
23
|
+
export const ROLLUP_KEEP_DAYS = 400;
|
|
24
|
+
const HOUR = 3_600_000;
|
|
25
|
+
const DAY = 86_400_000;
|
|
26
|
+
/** Coverage intervals kept per instance; beyond it the two oldest merge (an over-wide interval only hides a gap). */
|
|
27
|
+
export const COVERAGE_MAX = 64;
|
|
28
|
+
const READER_BACKEND = { claude: "claude-code", codex: "codex" };
|
|
29
|
+
/**
|
|
30
|
+
* An hour's totals by source (cache-ledger.ts `src`), each exact. What `m` holds beyond them was counted before #2122:
|
|
31
|
+
* one more source, backend and profile "unknown".
|
|
32
|
+
*/
|
|
33
|
+
export function hourSources(hour) {
|
|
34
|
+
const out = [];
|
|
35
|
+
const known = dict();
|
|
36
|
+
for (const [sk, m] of Object.entries(hour.src ?? {})) {
|
|
37
|
+
const colon = sk.indexOf(":");
|
|
38
|
+
out.push({ backend: READER_BACKEND[sk.slice(0, colon)] ?? "unknown", profile: sk.slice(colon + 1), m });
|
|
39
|
+
for (const [mk, t] of Object.entries(m))
|
|
40
|
+
add(known[mk] ??= [0, 0, 0, 0, 0, 0, 0], t);
|
|
41
|
+
}
|
|
42
|
+
const legacy = dict();
|
|
43
|
+
for (const [mk, t] of Object.entries(hour.m)) {
|
|
44
|
+
const k = known[mk], rest = t.map((n, i) => n - (k?.[i] ?? 0));
|
|
45
|
+
if (rest.some(n => n > 0))
|
|
46
|
+
legacy[mk] = rest.map(n => Math.max(0, n));
|
|
47
|
+
}
|
|
48
|
+
if (Object.keys(legacy).length)
|
|
49
|
+
out.push({ backend: "unknown", profile: "unknown", m: legacy });
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
const dict = () => Object.create(null);
|
|
53
|
+
const add = (into, from) => { for (let i = 0; i < 7; i++)
|
|
54
|
+
into[i] = (into[i] ?? 0) + (from[i] ?? 0); };
|
|
55
|
+
export const emptyDays = () => ({ v: 1, checkpoint: -1, rows: [], coverage: [] });
|
|
56
|
+
/** A rollup read back from disk; anything that is not one is empty. */
|
|
57
|
+
export function reviveDays(raw) {
|
|
58
|
+
const d = emptyDays();
|
|
59
|
+
if (!raw || typeof raw !== "object" || raw.v !== 1)
|
|
60
|
+
return d;
|
|
61
|
+
const r = raw;
|
|
62
|
+
if (Number.isSafeInteger(r.checkpoint))
|
|
63
|
+
d.checkpoint = r.checkpoint;
|
|
64
|
+
if (Array.isArray(r.rows))
|
|
65
|
+
for (const row of r.rows) {
|
|
66
|
+
if (!row || typeof row.date !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(row.date) || typeof row.zone !== "string" || typeof row.be !== "string" || typeof row.pf !== "string")
|
|
67
|
+
continue;
|
|
68
|
+
const m = dict();
|
|
69
|
+
for (const [k, t] of Object.entries(row.m ?? {}))
|
|
70
|
+
if (Array.isArray(t) && t.length === 7 && t.every(n => Number.isFinite(n)))
|
|
71
|
+
m[k] = t;
|
|
72
|
+
d.rows.push({ date: row.date, zone: row.zone, be: row.be, pf: row.pf, m });
|
|
73
|
+
}
|
|
74
|
+
if (Array.isArray(r.coverage))
|
|
75
|
+
for (const c of r.coverage)
|
|
76
|
+
if (Array.isArray(c) && c.length === 2 && Number.isFinite(c[0]) && Number.isFinite(c[1]) && c[0] <= c[1])
|
|
77
|
+
d.coverage.push([c[0], c[1]]);
|
|
78
|
+
return d;
|
|
79
|
+
}
|
|
80
|
+
/** The local date (YYYY-MM-DD) an instant falls on in `zone` (an IANA name; an unknown one is UTC). */
|
|
81
|
+
export function localDate(t, zone) {
|
|
82
|
+
try {
|
|
83
|
+
return new Intl.DateTimeFormat("en-CA", { timeZone: zone, year: "numeric", month: "2-digit", day: "2-digit" }).format(new Date(t));
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return new Date(t).toISOString().slice(0, 10);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Fold the ledger's hours that are about to leave it (older than `cutoff`) and after the checkpoint into their days.
|
|
91
|
+
* Mutates `days`; returns whether anything moved. Never folds an hour at or before the checkpoint (it is already here),
|
|
92
|
+
* so a fold repeated after a crash adds nothing twice.
|
|
93
|
+
*/
|
|
94
|
+
export function foldHours(days, ledger, cutoff, zone) {
|
|
95
|
+
const hours = Object.keys(ledger.hours).map(Number).filter(h => h + HOUR <= cutoff && h > days.checkpoint).sort((a, b) => a - b);
|
|
96
|
+
if (!hours.length)
|
|
97
|
+
return false;
|
|
98
|
+
const index = new Map(days.rows.map((r, i) => [`${r.date}\u0000${r.zone}\u0000${r.be}\u0000${r.pf}`, i]));
|
|
99
|
+
for (const h of hours) {
|
|
100
|
+
const date = localDate(h, zone);
|
|
101
|
+
for (const src of hourSources(ledger.hours[String(h)])) {
|
|
102
|
+
const key = `${date}\u0000${zone}\u0000${src.backend}\u0000${src.profile}`;
|
|
103
|
+
let i = index.get(key);
|
|
104
|
+
if (i === undefined) {
|
|
105
|
+
i = days.rows.push({ date, zone, be: src.backend, pf: src.profile, m: dict() }) - 1;
|
|
106
|
+
index.set(key, i);
|
|
107
|
+
}
|
|
108
|
+
const row = days.rows[i];
|
|
109
|
+
for (const [mk, tot] of Object.entries(src.m))
|
|
110
|
+
add(row.m[mk] ??= [0, 0, 0, 0, 0, 0, 0], tot);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
days.checkpoint = hours[hours.length - 1];
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
/** Drop day rows older than the rollup keeps (by date, against `now` in `zone`). */
|
|
117
|
+
export function pruneDays(days, now, zone) {
|
|
118
|
+
const oldest = localDate(now - ROLLUP_KEEP_DAYS * DAY, zone);
|
|
119
|
+
const before = days.rows.length;
|
|
120
|
+
days.rows = days.rows.filter(r => r.date >= oldest);
|
|
121
|
+
const cov = days.coverage.filter(([, to]) => to >= now - ROLLUP_KEEP_DAYS * DAY);
|
|
122
|
+
const changed = days.rows.length !== before || cov.length !== days.coverage.length;
|
|
123
|
+
days.coverage = cov;
|
|
124
|
+
return changed;
|
|
125
|
+
}
|
|
126
|
+
/** Record that the scanner has read [from, to]: merged into the intervals, at most COVERAGE_MAX of them. */
|
|
127
|
+
export function addCoverage(days, from, to) {
|
|
128
|
+
if (!(from <= to))
|
|
129
|
+
return;
|
|
130
|
+
const all = [...days.coverage, [from, to]].sort((a, b) => a[0] - b[0]);
|
|
131
|
+
const merged = [];
|
|
132
|
+
for (const [a, b] of all) {
|
|
133
|
+
const last = merged[merged.length - 1];
|
|
134
|
+
if (last && a <= last[1] + HOUR)
|
|
135
|
+
last[1] = Math.max(last[1], b);
|
|
136
|
+
else
|
|
137
|
+
merged.push([a, b]);
|
|
138
|
+
}
|
|
139
|
+
while (merged.length > COVERAGE_MAX) {
|
|
140
|
+
const [x, y] = merged.splice(0, 2);
|
|
141
|
+
merged.unshift([x[0], y[1]]);
|
|
142
|
+
}
|
|
143
|
+
days.coverage = merged;
|
|
144
|
+
}
|
|
145
|
+
/** Whether the scanner has read the hour starting at `h`. */
|
|
146
|
+
export const covered = (days, h) => days.coverage.some(([a, b]) => h + HOUR > a && h <= b);
|
|
147
|
+
export async function readDays(path) {
|
|
148
|
+
try {
|
|
149
|
+
return reviveDays(JSON.parse(await readFile(path, "utf8")));
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return emptyDays();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/** Written whole and renamed into place (0600): a crash leaves the old file or the new one, never a mix. */
|
|
156
|
+
export async function writeDays(path, days) {
|
|
157
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
158
|
+
try {
|
|
159
|
+
await mkdir(dirname(path), { recursive: true });
|
|
160
|
+
await writeFile(tmp, JSON.stringify(days), { mode: 0o600 });
|
|
161
|
+
await rename(tmp, path);
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=usage-rollup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-rollup.js","sourceRoot":"","sources":["../src/usage-rollup.ts"],"names":[],"mappings":"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"}
|