llm-relay 0.35.0 → 0.37.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/LICENSE +21 -0
- package/README.md +12 -0
- package/THIRD_PARTY_NOTICES.md +72 -0
- package/config.example.json +8 -2
- package/dist/accounting-store-io.d.ts +124 -0
- package/dist/accounting-store-io.js +1105 -0
- package/dist/accounting-store-io.js.map +1 -0
- package/dist/accounting-store-schema.d.ts +299 -0
- package/dist/accounting-store-schema.js +1021 -0
- package/dist/accounting-store-schema.js.map +1 -0
- package/dist/accounting-store.d.ts +73 -0
- package/dist/accounting-store.js +1523 -0
- package/dist/accounting-store.js.map +1 -0
- package/dist/accounting.d.ts +177 -0
- package/dist/accounting.js +429 -0
- package/dist/accounting.js.map +1 -0
- package/dist/anthropic.d.ts +2 -2
- package/dist/anthropic.js +22 -5
- package/dist/anthropic.js.map +1 -1
- package/dist/authEnv.d.ts +19 -0
- package/dist/authEnv.js +58 -25
- package/dist/authEnv.js.map +1 -1
- package/dist/backend.d.ts +32 -3
- package/dist/backend.js +324 -41
- package/dist/backend.js.map +1 -1
- package/dist/candidates.d.ts +28 -3
- package/dist/candidates.js +86 -13
- package/dist/candidates.js.map +1 -1
- package/dist/catalog.d.ts +1 -0
- package/dist/catalog.js +36 -12
- package/dist/catalog.js.map +1 -1
- package/dist/circuit-breaker.d.ts +49 -129
- package/dist/circuit-breaker.js +166 -223
- package/dist/circuit-breaker.js.map +1 -1
- package/dist/cli.d.ts +47 -15
- package/dist/cli.js +475 -134
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +23 -1
- package/dist/config.js +189 -19
- package/dist/config.js.map +1 -1
- package/dist/context-limits.js +2 -1
- package/dist/context-limits.js.map +1 -1
- package/dist/control-authorization.js +6 -4
- package/dist/control-authorization.js.map +1 -1
- package/dist/credential-fleet.d.ts +41 -0
- package/dist/credential-fleet.js +78 -0
- package/dist/credential-fleet.js.map +1 -0
- package/dist/credential-id.d.ts +13 -0
- package/dist/credential-id.js +22 -0
- package/dist/credential-id.js.map +1 -0
- package/dist/credential-select.d.ts +86 -0
- package/dist/credential-select.js +303 -0
- package/dist/credential-select.js.map +1 -0
- package/dist/dashboard/.vite/dashboard-bundle-graph.json +32 -0
- package/dist/dashboard/.vite/manifest.json +11 -0
- package/dist/dashboard/assets/index-BeZxN4Lx.css +1 -0
- package/dist/dashboard/assets/index-RtLgb7Cg.js +74 -0
- package/dist/dashboard/index.html +4 -0
- package/dist/dashboard-auth.d.ts +68 -0
- package/dist/dashboard-auth.js +225 -0
- package/dist/dashboard-auth.js.map +1 -0
- package/dist/dashboard-contract.d.ts +391 -0
- package/dist/dashboard-contract.js +619 -0
- package/dist/dashboard-contract.js.map +1 -0
- package/dist/dashboard-routes.d.ts +91 -0
- package/dist/dashboard-routes.js +688 -0
- package/dist/dashboard-routes.js.map +1 -0
- package/dist/dashboard-snapshot.d.ts +36 -0
- package/dist/dashboard-snapshot.js +1132 -0
- package/dist/dashboard-snapshot.js.map +1 -0
- package/dist/dashboard-static.d.ts +61 -0
- package/dist/dashboard-static.js +326 -0
- package/dist/dashboard-static.js.map +1 -0
- package/dist/dispatch.js +11 -6
- package/dist/dispatch.js.map +1 -1
- package/dist/dynamic-pools.js +6 -4
- package/dist/dynamic-pools.js.map +1 -1
- package/dist/kernel/contracts.d.ts +4 -0
- package/dist/kernel/request-lifecycle.js +4 -1
- package/dist/kernel/request-lifecycle.js.map +1 -1
- package/dist/key-checker.d.ts +3 -1
- package/dist/key-checker.js +35 -11
- package/dist/key-checker.js.map +1 -1
- package/dist/key-import.d.ts +29 -0
- package/dist/key-import.js +160 -0
- package/dist/key-import.js.map +1 -0
- package/dist/log.d.ts +20 -2
- package/dist/log.js +53 -2
- package/dist/log.js.map +1 -1
- package/dist/offload.d.ts +9 -0
- package/dist/offload.js +7 -1
- package/dist/offload.js.map +1 -1
- package/dist/onboarding.d.ts +3 -3
- package/dist/onboarding.js +12 -6
- package/dist/onboarding.js.map +1 -1
- package/dist/openai-dialect.d.ts +42 -0
- package/dist/openai-dialect.js +388 -0
- package/dist/openai-dialect.js.map +1 -0
- package/dist/ping/cadence.d.ts +12 -3
- package/dist/ping/cadence.js +68 -15
- package/dist/ping/cadence.js.map +1 -1
- package/dist/ping/ping.d.ts +7 -3
- package/dist/ping/ping.js +11 -35
- package/dist/ping/ping.js.map +1 -1
- package/dist/ping/probe-cache.d.ts +14 -6
- package/dist/ping/probe-cache.js +20 -5
- package/dist/ping/probe-cache.js.map +1 -1
- package/dist/ping/runtime-telemetry.d.ts +2 -1
- package/dist/ping/runtime-telemetry.js +103 -10
- package/dist/ping/runtime-telemetry.js.map +1 -1
- package/dist/pool-health.d.ts +2 -0
- package/dist/pool-health.js +29 -13
- package/dist/pool-health.js.map +1 -1
- package/dist/quota-observation.d.ts +29 -0
- package/dist/quota-observation.js +249 -0
- package/dist/quota-observation.js.map +1 -0
- package/dist/refusal-interpretation.d.ts +13 -7
- package/dist/refusal-interpretation.js +260 -33
- package/dist/refusal-interpretation.js.map +1 -1
- package/dist/registry.d.ts +13 -2
- package/dist/registry.js +12 -4
- package/dist/registry.js.map +1 -1
- package/dist/repair.d.ts +4 -2
- package/dist/repair.js +15 -1
- package/dist/repair.js.map +1 -1
- package/dist/request-log.d.ts +2 -2
- package/dist/request-log.js +9 -1
- package/dist/request-log.js.map +1 -1
- package/dist/reshaper.d.ts +76 -11
- package/dist/reshaper.js +264 -29
- package/dist/reshaper.js.map +1 -1
- package/dist/resolved-attempt.d.ts +14 -0
- package/dist/resolved-attempt.js +21 -0
- package/dist/resolved-attempt.js.map +1 -0
- package/dist/routes/admin.js +7 -1
- package/dist/routes/admin.js.map +1 -1
- package/dist/secret-file-acl.d.ts +25 -0
- package/dist/secret-file-acl.js +37 -0
- package/dist/secret-file-acl.js.map +1 -0
- package/dist/server.d.ts +28 -3
- package/dist/server.js +1774 -467
- package/dist/server.js.map +1 -1
- package/dist/session-pin.d.ts +35 -0
- package/dist/session-pin.js +136 -0
- package/dist/session-pin.js.map +1 -0
- package/dist/stream-commit.d.ts +34 -0
- package/dist/stream-commit.js +325 -0
- package/dist/stream-commit.js.map +1 -0
- package/dist/target-facts.d.ts +23 -136
- package/dist/target-facts.js +138 -179
- package/dist/target-facts.js.map +1 -1
- package/dist/telemetry.d.ts +1 -25
- package/dist/telemetry.js +52 -45
- package/dist/telemetry.js.map +1 -1
- package/dist/think-tags.d.ts +34 -0
- package/dist/think-tags.js +219 -0
- package/dist/think-tags.js.map +1 -0
- package/dist/usage-observer.d.ts +34 -0
- package/dist/usage-observer.js +322 -0
- package/dist/usage-observer.js.map +1 -0
- package/dist/winenv.js +26 -4
- package/dist/winenv.js.map +1 -1
- package/docs/dashboard-bundle-inventory.json +16 -0
- package/package.json +29 -6
- package/skills/llm-relay/SKILL.md +48 -9
|
@@ -0,0 +1,1021 @@
|
|
|
1
|
+
import { DASHBOARD_ATTEMPT_ID_MAX_BYTES, DASHBOARD_MAX_DETAIL_ATTEMPTS, DASHBOARD_REQUEST_ID_PATTERN, isDashboardAttemptId, isDashboardSafeId, isDashboardUtcTimestamp, } from "./dashboard-contract.js";
|
|
2
|
+
/** The persisted accounting format is deliberately separate from the dashboard wire format. */
|
|
3
|
+
export const ACCOUNTING_STORE_VERSION = 1;
|
|
4
|
+
export const ACCOUNTING_DAY_SCHEMA = "accounting.day.v1";
|
|
5
|
+
export const ACCOUNTING_MINUTE_SCHEMA = "accounting.minute.v1";
|
|
6
|
+
export const ACCOUNTING_RECENT_SCHEMA = "accounting.recent.v1";
|
|
7
|
+
export const ACCOUNTING_LIFETIME_SCHEMA = "accounting.lifetime.v1";
|
|
8
|
+
export const ACCOUNTING_DEDUP_SCHEMA = "accounting.dedup.v1";
|
|
9
|
+
export const ACCOUNTING_MAX_SAMPLES = 25;
|
|
10
|
+
export const ACCOUNTING_MAX_ROWS_PER_CELL = 512;
|
|
11
|
+
export const ACCOUNTING_MAX_MINUTE_CELLS = 1_440;
|
|
12
|
+
/** Aggregate rows across all UTC minute cells in one day. */
|
|
13
|
+
export const ACCOUNTING_MAX_DAY_ROWS = 4_096;
|
|
14
|
+
export const ACCOUNTING_MAX_MONTHS = 720;
|
|
15
|
+
export const ACCOUNTING_MAX_RECENT_ROWS = 100;
|
|
16
|
+
export const ACCOUNTING_MAX_DETAIL_ATTEMPTS = DASHBOARD_MAX_DETAIL_ATTEMPTS;
|
|
17
|
+
export const ACCOUNTING_MAX_DEDUP_IDS = 16_384;
|
|
18
|
+
export const ACCOUNTING_MAX_LOSS_MARKERS = 32;
|
|
19
|
+
export const ACCOUNTING_MAX_PACKET_ATTEMPTS = 10_000;
|
|
20
|
+
export const ACCOUNTING_MAX_METHOD_BYTES = 256;
|
|
21
|
+
export const ACCOUNTING_MAX_COUNTER = Number.MAX_SAFE_INTEGER;
|
|
22
|
+
/** Maximum JSON UTF-8 size accepted for any persisted shard/document. */
|
|
23
|
+
export const ACCOUNTING_MAX_FILE_BYTES = 16 * 1024 * 1024;
|
|
24
|
+
// NOTE: there is deliberately no whole-store envelope type. The pre-journal
|
|
25
|
+
// "one file holds everything" format was replaced by journal-then-replace
|
|
26
|
+
// shards, and its schema/guard were unreferenced leftovers.
|
|
27
|
+
const MINUTE_SCHEMA = ACCOUNTING_MINUTE_SCHEMA;
|
|
28
|
+
const MAX_ID_BYTES = 256;
|
|
29
|
+
const UTC_CANONICAL = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.\d{3}Z$/;
|
|
30
|
+
const DATE_CANONICAL = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
31
|
+
const MINUTE_CANONICAL = /^(\d{2}):(\d{2})$/;
|
|
32
|
+
const MONTH_CANONICAL = /^(\d{4})-(\d{2})$/;
|
|
33
|
+
const METHOD_SPECIAL = new Set(["mixed", "unknown"]);
|
|
34
|
+
function isPlainRecord(value) {
|
|
35
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const prototype = Object.getPrototypeOf(value);
|
|
39
|
+
return prototype === Object.prototype || prototype === null;
|
|
40
|
+
}
|
|
41
|
+
function hasExactKeys(value, keys) {
|
|
42
|
+
if (!isPlainRecord(value) || Object.getOwnPropertySymbols(value).length !== 0) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
const names = Object.getOwnPropertyNames(value);
|
|
46
|
+
const enumerableNames = Object.keys(value);
|
|
47
|
+
return (names.length === keys.length &&
|
|
48
|
+
enumerableNames.length === keys.length &&
|
|
49
|
+
keys.every((key) => Object.prototype.hasOwnProperty.call(value, key)));
|
|
50
|
+
}
|
|
51
|
+
function hasExactArray(value, max, guard) {
|
|
52
|
+
if (!Array.isArray(value) || value.length > max || Object.getOwnPropertySymbols(value).length !== 0) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
const names = Object.getOwnPropertyNames(value);
|
|
56
|
+
if (names.length !== value.length + 1 || !names.includes("length"))
|
|
57
|
+
return false;
|
|
58
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
59
|
+
if (!Object.prototype.hasOwnProperty.call(value, String(index)) || !guard(value[index]))
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
function hasOnlyEnumerableStringKeys(value) {
|
|
65
|
+
return Object.getOwnPropertySymbols(value).length === 0 && Object.getOwnPropertyNames(value).length === Object.keys(value).length;
|
|
66
|
+
}
|
|
67
|
+
function serializedByteLength(value) {
|
|
68
|
+
try {
|
|
69
|
+
const serialized = JSON.stringify(value);
|
|
70
|
+
return typeof serialized === "string" ? Buffer.byteLength(serialized, "utf8") : null;
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export function accountingSerializedBytes(value) {
|
|
77
|
+
return serializedByteLength(value);
|
|
78
|
+
}
|
|
79
|
+
function withinFileCeiling(value) {
|
|
80
|
+
const bytes = serializedByteLength(value);
|
|
81
|
+
return bytes !== null && bytes <= ACCOUNTING_MAX_FILE_BYTES;
|
|
82
|
+
}
|
|
83
|
+
function isSafeId(value) {
|
|
84
|
+
if (typeof value !== "string" || value.length === 0 || Buffer.byteLength(value, "utf8") > MAX_ID_BYTES) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
88
|
+
const code = value.charCodeAt(index);
|
|
89
|
+
if (code <= 0x1f || (code >= 0x7f && code <= 0x9f))
|
|
90
|
+
return false;
|
|
91
|
+
if (code >= 0xd800 && code <= 0xdbff) {
|
|
92
|
+
const next = value.charCodeAt(index + 1);
|
|
93
|
+
if (next < 0xdc00 || next > 0xdfff)
|
|
94
|
+
return false;
|
|
95
|
+
index += 1;
|
|
96
|
+
}
|
|
97
|
+
else if (code >= 0xdc00 && code <= 0xdfff) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return isDashboardSafeId(value);
|
|
102
|
+
}
|
|
103
|
+
function isRequestId(value) {
|
|
104
|
+
return isSafeId(value) && DASHBOARD_REQUEST_ID_PATTERN.test(value);
|
|
105
|
+
}
|
|
106
|
+
function isAttemptId(value) {
|
|
107
|
+
return (isSafeId(value) &&
|
|
108
|
+
Buffer.byteLength(value, "utf8") <= DASHBOARD_ATTEMPT_ID_MAX_BYTES &&
|
|
109
|
+
isDashboardAttemptId(value));
|
|
110
|
+
}
|
|
111
|
+
function isTimestamp(value) {
|
|
112
|
+
if (!isDashboardUtcTimestamp(value) || !UTC_CANONICAL.test(value))
|
|
113
|
+
return false;
|
|
114
|
+
return new Date(value).toISOString() === value;
|
|
115
|
+
}
|
|
116
|
+
function isDate(value) {
|
|
117
|
+
if (typeof value !== "string")
|
|
118
|
+
return false;
|
|
119
|
+
const match = DATE_CANONICAL.exec(value);
|
|
120
|
+
if (!match)
|
|
121
|
+
return false;
|
|
122
|
+
const year = Number(match[1]);
|
|
123
|
+
const month = Number(match[2]);
|
|
124
|
+
const day = Number(match[3]);
|
|
125
|
+
if (month < 1 || month > 12 || day < 1)
|
|
126
|
+
return false;
|
|
127
|
+
const leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
128
|
+
const days = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1];
|
|
129
|
+
return day <= (days ?? 0);
|
|
130
|
+
}
|
|
131
|
+
function isMinute(value) {
|
|
132
|
+
const match = typeof value === "string" ? MINUTE_CANONICAL.exec(value) : null;
|
|
133
|
+
return match !== null && Number(match[1]) < 24 && Number(match[2]) < 60;
|
|
134
|
+
}
|
|
135
|
+
function isMonth(value) {
|
|
136
|
+
if (typeof value !== "string" || !MONTH_CANONICAL.test(value))
|
|
137
|
+
return false;
|
|
138
|
+
return isDate(`${value}-01`);
|
|
139
|
+
}
|
|
140
|
+
function isCounter(value) {
|
|
141
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 && value <= ACCOUNTING_MAX_COUNTER;
|
|
142
|
+
}
|
|
143
|
+
function isNullableCounter(value) {
|
|
144
|
+
return value === null || isCounter(value);
|
|
145
|
+
}
|
|
146
|
+
function isNullableId(value) {
|
|
147
|
+
return value === null || isSafeId(value);
|
|
148
|
+
}
|
|
149
|
+
function isNullableTimestamp(value) {
|
|
150
|
+
return value === null || isTimestamp(value);
|
|
151
|
+
}
|
|
152
|
+
function isOutcome(value) {
|
|
153
|
+
return value === "success" || value === "error" || value === "cancelled" || value === "unknown";
|
|
154
|
+
}
|
|
155
|
+
function isFailure(value) {
|
|
156
|
+
return (value === "timeout" ||
|
|
157
|
+
value === "provider_error" ||
|
|
158
|
+
value === "auth_error" ||
|
|
159
|
+
value === "rate_limit" ||
|
|
160
|
+
value === "aborted" ||
|
|
161
|
+
value === "protocol" ||
|
|
162
|
+
value === "unknown");
|
|
163
|
+
}
|
|
164
|
+
function isAttribution(value) {
|
|
165
|
+
return value === "relay_held" || value === "caller_operated" || value === "unknown";
|
|
166
|
+
}
|
|
167
|
+
function isRole(value) {
|
|
168
|
+
return value === "serve" || value === "repair";
|
|
169
|
+
}
|
|
170
|
+
function isFailureCoherent(outcome, failure) {
|
|
171
|
+
if (outcome === "success")
|
|
172
|
+
return failure === null;
|
|
173
|
+
return failure === null || isFailure(failure);
|
|
174
|
+
}
|
|
175
|
+
function isAggregateTokenCell(value) {
|
|
176
|
+
if (!hasExactKeys(value, ["value", "known", "unknown", "lost", "overflow", "observedAt"]) ||
|
|
177
|
+
!isNullableCounter(value.value) ||
|
|
178
|
+
!isCounter(value.known) ||
|
|
179
|
+
!isCounter(value.unknown) ||
|
|
180
|
+
!isCounter(value.lost) ||
|
|
181
|
+
typeof value.overflow !== "boolean" ||
|
|
182
|
+
!isNullableTimestamp(value.observedAt))
|
|
183
|
+
return false;
|
|
184
|
+
const uncertain = value.unknown > 0 || value.lost > 0 || value.overflow;
|
|
185
|
+
if (value.value !== null && (value.known === 0 || uncertain))
|
|
186
|
+
return false;
|
|
187
|
+
if (value.value === null && value.known > 0 && !uncertain)
|
|
188
|
+
return false;
|
|
189
|
+
if (value.known === 0 && value.observedAt !== null)
|
|
190
|
+
return false;
|
|
191
|
+
if (value.known > 0 && value.observedAt === null)
|
|
192
|
+
return false;
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
function isSafeMethod(value) {
|
|
196
|
+
return typeof value === "string" && Buffer.byteLength(value, "utf8") <= ACCOUNTING_MAX_METHOD_BYTES && isSafeId(value);
|
|
197
|
+
}
|
|
198
|
+
function isEstimatedTokenCell(value) {
|
|
199
|
+
if (!hasExactKeys(value, ["value", "known", "unknown", "lost", "overflow", "observedAt", "method"]))
|
|
200
|
+
return false;
|
|
201
|
+
const base = {
|
|
202
|
+
value: value.value,
|
|
203
|
+
known: value.known,
|
|
204
|
+
unknown: value.unknown,
|
|
205
|
+
lost: value.lost,
|
|
206
|
+
overflow: value.overflow,
|
|
207
|
+
observedAt: value.observedAt,
|
|
208
|
+
};
|
|
209
|
+
if (!isAggregateTokenCell(base))
|
|
210
|
+
return false;
|
|
211
|
+
if (value.method !== null && !isSafeMethod(value.method))
|
|
212
|
+
return false;
|
|
213
|
+
const observed = base.known > 0 || base.unknown > 0 || base.lost > 0 || base.overflow;
|
|
214
|
+
if (!observed)
|
|
215
|
+
return value.method === null;
|
|
216
|
+
if (base.known === 0)
|
|
217
|
+
return value.method === "unknown";
|
|
218
|
+
return value.method !== null && value.method !== "unknown";
|
|
219
|
+
}
|
|
220
|
+
function isAggregateTokens(value) {
|
|
221
|
+
if (!hasExactKeys(value, ["reported", "estimated"]) ||
|
|
222
|
+
!hasExactKeys(value.reported, [
|
|
223
|
+
"reportedInput",
|
|
224
|
+
"reportedOutput",
|
|
225
|
+
"reportedCachedInput",
|
|
226
|
+
"cacheCreationInputTokens",
|
|
227
|
+
"cacheReadInputTokens",
|
|
228
|
+
]) ||
|
|
229
|
+
!hasExactKeys(value.estimated, ["estimatedInput", "estimatedOutput"]))
|
|
230
|
+
return false;
|
|
231
|
+
return (isAggregateTokenCell(value.reported.reportedInput) &&
|
|
232
|
+
isAggregateTokenCell(value.reported.reportedOutput) &&
|
|
233
|
+
isAggregateTokenCell(value.reported.reportedCachedInput) &&
|
|
234
|
+
isAggregateTokenCell(value.reported.cacheCreationInputTokens) &&
|
|
235
|
+
isAggregateTokenCell(value.reported.cacheReadInputTokens) &&
|
|
236
|
+
isEstimatedTokenCell(value.estimated.estimatedInput) &&
|
|
237
|
+
isEstimatedTokenCell(value.estimated.estimatedOutput));
|
|
238
|
+
}
|
|
239
|
+
function isEmptyAggregateTokenCell(value) {
|
|
240
|
+
if (isEstimatedTokenCell(value)) {
|
|
241
|
+
return value.method === null && value.value === null && value.known === 0 && value.unknown === 0 && value.lost === 0 && !value.overflow && value.observedAt === null;
|
|
242
|
+
}
|
|
243
|
+
if (!isAggregateTokenCell(value))
|
|
244
|
+
return false;
|
|
245
|
+
return value.value === null && value.known === 0 && value.unknown === 0 && value.lost === 0 && !value.overflow && value.observedAt === null;
|
|
246
|
+
}
|
|
247
|
+
function isEmptyAggregateTokens(value) {
|
|
248
|
+
if (!isAggregateTokens(value))
|
|
249
|
+
return false;
|
|
250
|
+
return (isEmptyAggregateTokenCell(value.reported.reportedInput) &&
|
|
251
|
+
isEmptyAggregateTokenCell(value.reported.reportedOutput) &&
|
|
252
|
+
isEmptyAggregateTokenCell(value.reported.reportedCachedInput) &&
|
|
253
|
+
isEmptyAggregateTokenCell(value.reported.cacheCreationInputTokens) &&
|
|
254
|
+
isEmptyAggregateTokenCell(value.reported.cacheReadInputTokens) &&
|
|
255
|
+
isEmptyAggregateTokenCell(value.estimated.estimatedInput) &&
|
|
256
|
+
isEmptyAggregateTokenCell(value.estimated.estimatedOutput));
|
|
257
|
+
}
|
|
258
|
+
function isMetric(value) {
|
|
259
|
+
if (!hasExactKeys(value, ["sumMs", "known", "unknown", "lost", "overflow", "samples", "samplesDropped", "observedAt"]) ||
|
|
260
|
+
!isNullableCounter(value.sumMs) ||
|
|
261
|
+
!isCounter(value.known) ||
|
|
262
|
+
!isCounter(value.unknown) ||
|
|
263
|
+
!isCounter(value.lost) ||
|
|
264
|
+
typeof value.overflow !== "boolean" ||
|
|
265
|
+
!isCounter(value.samplesDropped) ||
|
|
266
|
+
!isNullableTimestamp(value.observedAt) ||
|
|
267
|
+
!hasExactArray(value.samples, ACCOUNTING_MAX_SAMPLES, isCounter))
|
|
268
|
+
return false;
|
|
269
|
+
if (value.samples.length + value.samplesDropped > value.known)
|
|
270
|
+
return false;
|
|
271
|
+
const uncertain = value.unknown > 0 || value.lost > 0 || value.overflow;
|
|
272
|
+
if (value.sumMs !== null && (value.known === 0 || uncertain))
|
|
273
|
+
return false;
|
|
274
|
+
if (value.sumMs === null && value.known > 0 && !uncertain)
|
|
275
|
+
return false;
|
|
276
|
+
if (value.known === 0 && value.observedAt !== null)
|
|
277
|
+
return false;
|
|
278
|
+
if (value.known > 0 && value.observedAt === null)
|
|
279
|
+
return false;
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
function isAggregateFields(value, owner = "general") {
|
|
283
|
+
if (!isCounter(value.requests) ||
|
|
284
|
+
!isCounter(value.attempts) ||
|
|
285
|
+
!isCounter(value.served) ||
|
|
286
|
+
!isCounter(value.errored) ||
|
|
287
|
+
!isCounter(value.cancelled) ||
|
|
288
|
+
!isAggregateTokens(value.tokens) ||
|
|
289
|
+
!isAggregateTokens(value.requestTokens) ||
|
|
290
|
+
!isMetric(value.latency) ||
|
|
291
|
+
!isMetric(value.commit) ||
|
|
292
|
+
value.spend !== null ||
|
|
293
|
+
!isCounter(value.unpricedRequests))
|
|
294
|
+
return false;
|
|
295
|
+
if (owner === "request") {
|
|
296
|
+
if (value.attempts !== 0 || !isEmptyAggregateTokens(value.tokens))
|
|
297
|
+
return false;
|
|
298
|
+
if (value.served + value.errored + value.cancelled > value.requests)
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
else if (owner === "attempt") {
|
|
302
|
+
if (value.requests !== 0 || !isEmptyAggregateTokens(value.requestTokens))
|
|
303
|
+
return false;
|
|
304
|
+
if (value.served + value.errored + value.cancelled > value.attempts)
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
if (value.served + value.errored + value.cancelled > value.requests)
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
if (owner !== "general") {
|
|
312
|
+
const count = owner === "request" ? value.requests : value.attempts;
|
|
313
|
+
if (!isOutcome(value.outcome) || count === 0)
|
|
314
|
+
return false;
|
|
315
|
+
if (value.outcome === "success" && (value.served !== count || value.errored !== 0 || value.cancelled !== 0))
|
|
316
|
+
return false;
|
|
317
|
+
if (value.outcome === "error" && (value.served !== 0 || value.errored !== count || value.cancelled !== 0))
|
|
318
|
+
return false;
|
|
319
|
+
if (value.outcome === "cancelled" && (value.served !== 0 || value.errored !== 0 || value.cancelled !== count))
|
|
320
|
+
return false;
|
|
321
|
+
if (value.outcome === "unknown" && (value.served !== 0 || value.errored !== 0 || value.cancelled !== 0))
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
return value.unpricedRequests <= value.requests;
|
|
325
|
+
}
|
|
326
|
+
function isAggregate(value) {
|
|
327
|
+
return (hasExactKeys(value, [
|
|
328
|
+
"requests",
|
|
329
|
+
"attempts",
|
|
330
|
+
"served",
|
|
331
|
+
"errored",
|
|
332
|
+
"cancelled",
|
|
333
|
+
"tokens",
|
|
334
|
+
"requestTokens",
|
|
335
|
+
"latency",
|
|
336
|
+
"commit",
|
|
337
|
+
"spend",
|
|
338
|
+
"unpricedRequests",
|
|
339
|
+
]) && isAggregateFields(value));
|
|
340
|
+
}
|
|
341
|
+
function isDimensionRow(value) {
|
|
342
|
+
if (!hasExactKeys(value, [
|
|
343
|
+
"requests",
|
|
344
|
+
"attempts",
|
|
345
|
+
"served",
|
|
346
|
+
"errored",
|
|
347
|
+
"cancelled",
|
|
348
|
+
"tokens",
|
|
349
|
+
"requestTokens",
|
|
350
|
+
"latency",
|
|
351
|
+
"commit",
|
|
352
|
+
"spend",
|
|
353
|
+
"unpricedRequests",
|
|
354
|
+
"kind",
|
|
355
|
+
"role",
|
|
356
|
+
"provider",
|
|
357
|
+
"model",
|
|
358
|
+
"client",
|
|
359
|
+
"credentialId",
|
|
360
|
+
"attribution",
|
|
361
|
+
"outcome",
|
|
362
|
+
"failureKind",
|
|
363
|
+
]) ||
|
|
364
|
+
(value.kind !== "request" && value.kind !== "attempt") ||
|
|
365
|
+
(value.kind === "request" && value.role !== "request") ||
|
|
366
|
+
(value.kind === "attempt" && !isRole(value.role)) ||
|
|
367
|
+
!isNullableId(value.provider) ||
|
|
368
|
+
!isNullableId(value.model) ||
|
|
369
|
+
!isNullableId(value.client) ||
|
|
370
|
+
!isNullableId(value.credentialId) ||
|
|
371
|
+
!isAttribution(value.attribution) ||
|
|
372
|
+
!isOutcome(value.outcome) ||
|
|
373
|
+
(value.failureKind !== null && !isFailure(value.failureKind)) ||
|
|
374
|
+
!isFailureCoherent(value.outcome, value.failureKind))
|
|
375
|
+
return false;
|
|
376
|
+
if (!isAggregateFields(value, value.kind === "request" ? "request" : "attempt"))
|
|
377
|
+
return false;
|
|
378
|
+
return true;
|
|
379
|
+
}
|
|
380
|
+
function isLossMarker(value) {
|
|
381
|
+
return (hasExactKeys(value, ["kind", "count", "field"]) &&
|
|
382
|
+
(value.kind === "unknown" || value.kind === "overflow" || value.kind === "truncated" || value.kind === "dedup" || value.kind === "corrupt") &&
|
|
383
|
+
isCounter(value.count) &&
|
|
384
|
+
value.count > 0 &&
|
|
385
|
+
(value.field === null || isSafeId(value.field)));
|
|
386
|
+
}
|
|
387
|
+
function isCoverage(value) {
|
|
388
|
+
if (!hasExactKeys(value, [
|
|
389
|
+
"state",
|
|
390
|
+
"reason",
|
|
391
|
+
"droppedRows",
|
|
392
|
+
"droppedRecent",
|
|
393
|
+
"droppedDetails",
|
|
394
|
+
"droppedDedup",
|
|
395
|
+
"retentionFrom",
|
|
396
|
+
"retentionDays",
|
|
397
|
+
"losses",
|
|
398
|
+
]) ||
|
|
399
|
+
(value.state !== "complete" && value.state !== "partial" && value.state !== "unavailable" && value.state !== "stale" && value.state !== "empty") ||
|
|
400
|
+
(value.reason !== null && value.reason !== "retention_pruned" && value.reason !== "row_cap" && value.reason !== "detail_cap" && value.reason !== "dedup_cap" && value.reason !== "counter_overflow" && value.reason !== "corrupt_recovery" && value.reason !== "unknown") ||
|
|
401
|
+
!isCounter(value.droppedRows) ||
|
|
402
|
+
!isCounter(value.droppedRecent) ||
|
|
403
|
+
!isCounter(value.droppedDetails) ||
|
|
404
|
+
!isCounter(value.droppedDedup) ||
|
|
405
|
+
!isNullableCounter(value.retentionDays) ||
|
|
406
|
+
(value.retentionDays !== null && value.retentionDays === 0) ||
|
|
407
|
+
!(value.retentionFrom === null || isDate(value.retentionFrom)) ||
|
|
408
|
+
!hasExactArray(value.losses, ACCOUNTING_MAX_LOSS_MARKERS, isLossMarker))
|
|
409
|
+
return false;
|
|
410
|
+
const hasLoss = value.droppedRows + value.droppedRecent + value.droppedDetails + value.droppedDedup > 0 || value.losses.length > 0;
|
|
411
|
+
if (value.state === "complete" && (value.reason !== null || hasLoss))
|
|
412
|
+
return false;
|
|
413
|
+
if (value.state === "empty" && (value.reason !== null || hasLoss))
|
|
414
|
+
return false;
|
|
415
|
+
if ((value.state === "partial" || value.state === "unavailable" || value.state === "stale") && value.reason === null && !hasLoss)
|
|
416
|
+
return false;
|
|
417
|
+
return true;
|
|
418
|
+
}
|
|
419
|
+
function isCellCoverage(value) {
|
|
420
|
+
if (!hasExactKeys(value, ["state", "reason", "droppedRows", "losses"]) ||
|
|
421
|
+
(value.state !== "complete" && value.state !== "partial" && value.state !== "unavailable" && value.state !== "stale" && value.state !== "empty") ||
|
|
422
|
+
(value.reason !== null && value.reason !== "retention_pruned" && value.reason !== "row_cap" && value.reason !== "detail_cap" && value.reason !== "dedup_cap" && value.reason !== "counter_overflow" && value.reason !== "corrupt_recovery" && value.reason !== "unknown") ||
|
|
423
|
+
!isCounter(value.droppedRows) ||
|
|
424
|
+
!hasExactArray(value.losses, ACCOUNTING_MAX_LOSS_MARKERS, isLossMarker))
|
|
425
|
+
return false;
|
|
426
|
+
const hasLoss = value.droppedRows > 0 || value.losses.length > 0;
|
|
427
|
+
if (value.state === "complete" && (value.reason !== null || hasLoss))
|
|
428
|
+
return false;
|
|
429
|
+
if (value.state === "empty" && (value.reason !== null || hasLoss))
|
|
430
|
+
return false;
|
|
431
|
+
if ((value.state === "partial" || value.state === "unavailable" || value.state === "stale") && value.reason === null && !hasLoss)
|
|
432
|
+
return false;
|
|
433
|
+
return true;
|
|
434
|
+
}
|
|
435
|
+
function isMinuteShard(value) {
|
|
436
|
+
if (!hasExactKeys(value, ["schema", "version", "date", "minute", "from", "to", "aggregate", "rows", "coverage"]) ||
|
|
437
|
+
value.schema !== MINUTE_SCHEMA ||
|
|
438
|
+
value.version !== ACCOUNTING_STORE_VERSION ||
|
|
439
|
+
!isDate(value.date) ||
|
|
440
|
+
!isMinute(value.minute) ||
|
|
441
|
+
!isTimestamp(value.from) ||
|
|
442
|
+
!isTimestamp(value.to) ||
|
|
443
|
+
!isAggregate(value.aggregate) ||
|
|
444
|
+
!hasExactArray(value.rows, ACCOUNTING_MAX_ROWS_PER_CELL, isDimensionRow) ||
|
|
445
|
+
!isCellCoverage(value.coverage))
|
|
446
|
+
return false;
|
|
447
|
+
const expectedFrom = `${value.date}T${value.minute}:00.000Z`;
|
|
448
|
+
const expectedTo = new Date(Date.parse(expectedFrom) + 60_000).toISOString();
|
|
449
|
+
return value.from === expectedFrom && value.to === expectedTo && withinFileCeiling(value);
|
|
450
|
+
}
|
|
451
|
+
function isDedup(value) {
|
|
452
|
+
if (!hasExactKeys(value, ["schema", "version", "date", "requestIds", "dropped", "complete"]) ||
|
|
453
|
+
value.schema !== ACCOUNTING_DEDUP_SCHEMA ||
|
|
454
|
+
value.version !== ACCOUNTING_STORE_VERSION ||
|
|
455
|
+
!isDate(value.date) ||
|
|
456
|
+
!isCounter(value.dropped) ||
|
|
457
|
+
typeof value.complete !== "boolean" ||
|
|
458
|
+
!hasExactArray(value.requestIds, ACCOUNTING_MAX_DEDUP_IDS, isRequestId))
|
|
459
|
+
return false;
|
|
460
|
+
for (let index = 1; index < value.requestIds.length; index += 1) {
|
|
461
|
+
const previous = value.requestIds[index - 1];
|
|
462
|
+
const current = value.requestIds[index];
|
|
463
|
+
if (previous === undefined || current === undefined || previous >= current)
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
return value.complete === (value.dropped === 0) && withinFileCeiling(value);
|
|
467
|
+
}
|
|
468
|
+
function isDay(value) {
|
|
469
|
+
if (!hasExactKeys(value, ["schema", "version", "date", "cells", "dedup", "coverage"]) ||
|
|
470
|
+
value.schema !== ACCOUNTING_DAY_SCHEMA ||
|
|
471
|
+
value.version !== ACCOUNTING_STORE_VERSION ||
|
|
472
|
+
!isDate(value.date) ||
|
|
473
|
+
!isPlainRecord(value.cells) ||
|
|
474
|
+
!hasOnlyEnumerableStringKeys(value.cells) ||
|
|
475
|
+
Object.keys(value.cells).length > ACCOUNTING_MAX_MINUTE_CELLS ||
|
|
476
|
+
!isDedup(value.dedup) ||
|
|
477
|
+
value.dedup.date !== value.date ||
|
|
478
|
+
!isCoverage(value.coverage))
|
|
479
|
+
return false;
|
|
480
|
+
if (value.dedup.dropped > 0 && (value.coverage.state === "complete" || value.coverage.droppedDedup < value.dedup.dropped))
|
|
481
|
+
return false;
|
|
482
|
+
let rowCount = 0;
|
|
483
|
+
for (const [key, cell] of Object.entries(value.cells)) {
|
|
484
|
+
if (!isMinute(key) || !isMinuteShard(cell) || cell.date !== value.date || cell.minute !== key)
|
|
485
|
+
return false;
|
|
486
|
+
rowCount += cell.rows.length;
|
|
487
|
+
if (rowCount > ACCOUNTING_MAX_DAY_ROWS)
|
|
488
|
+
return false;
|
|
489
|
+
}
|
|
490
|
+
return withinFileCeiling(value);
|
|
491
|
+
}
|
|
492
|
+
function isMonthAggregate(value) {
|
|
493
|
+
return hasExactKeys(value, ["month", "aggregate", "coverage"]) && isMonth(value.month) && isAggregate(value.aggregate) && isCoverage(value.coverage);
|
|
494
|
+
}
|
|
495
|
+
function isLifetime(value) {
|
|
496
|
+
if (!hasExactKeys(value, ["schema", "version", "firstRequestAt", "lastRequestAt", "aggregate", "months", "coverage"]) ||
|
|
497
|
+
value.schema !== ACCOUNTING_LIFETIME_SCHEMA ||
|
|
498
|
+
value.version !== ACCOUNTING_STORE_VERSION ||
|
|
499
|
+
!isNullableTimestamp(value.firstRequestAt) ||
|
|
500
|
+
!isNullableTimestamp(value.lastRequestAt) ||
|
|
501
|
+
!isAggregate(value.aggregate) ||
|
|
502
|
+
!isPlainRecord(value.months) ||
|
|
503
|
+
!hasOnlyEnumerableStringKeys(value.months) ||
|
|
504
|
+
Object.keys(value.months).length > ACCOUNTING_MAX_MONTHS ||
|
|
505
|
+
!Object.entries(value.months).every(([key, month]) => isMonth(key) && isMonthAggregate(month) && month.month === key) ||
|
|
506
|
+
!isCoverage(value.coverage))
|
|
507
|
+
return false;
|
|
508
|
+
if (value.firstRequestAt !== null && value.lastRequestAt !== null && value.firstRequestAt > value.lastRequestAt)
|
|
509
|
+
return false;
|
|
510
|
+
if (value.aggregate.requests === 0 && (value.firstRequestAt !== null || value.lastRequestAt !== null))
|
|
511
|
+
return false;
|
|
512
|
+
if (value.aggregate.requests > 0 && (value.firstRequestAt === null || value.lastRequestAt === null))
|
|
513
|
+
return false;
|
|
514
|
+
return withinFileCeiling(value);
|
|
515
|
+
}
|
|
516
|
+
function isAttemptPacket(value) {
|
|
517
|
+
if (!hasExactKeys(value, [
|
|
518
|
+
"requestId",
|
|
519
|
+
"attemptId",
|
|
520
|
+
"role",
|
|
521
|
+
"startedAt",
|
|
522
|
+
"endedAt",
|
|
523
|
+
"outcome",
|
|
524
|
+
"failureKind",
|
|
525
|
+
"attribution",
|
|
526
|
+
"latencyMs",
|
|
527
|
+
"commitMs",
|
|
528
|
+
"provider",
|
|
529
|
+
"model",
|
|
530
|
+
"credentialId",
|
|
531
|
+
"tokens",
|
|
532
|
+
"spend",
|
|
533
|
+
]) ||
|
|
534
|
+
!isRequestId(value.requestId) ||
|
|
535
|
+
!isAttemptId(value.attemptId) ||
|
|
536
|
+
!isRole(value.role) ||
|
|
537
|
+
!isTimestamp(value.startedAt) ||
|
|
538
|
+
!isTimestamp(value.endedAt) ||
|
|
539
|
+
value.startedAt > value.endedAt ||
|
|
540
|
+
!isOutcome(value.outcome) ||
|
|
541
|
+
(value.failureKind !== null && !isFailure(value.failureKind)) ||
|
|
542
|
+
!isFailureCoherent(value.outcome, value.failureKind) ||
|
|
543
|
+
!isAttribution(value.attribution) ||
|
|
544
|
+
!isNullableCounter(value.latencyMs) ||
|
|
545
|
+
!isNullableCounter(value.commitMs) ||
|
|
546
|
+
!isNullableId(value.provider) ||
|
|
547
|
+
!isNullableId(value.model) ||
|
|
548
|
+
!isNullableId(value.credentialId) ||
|
|
549
|
+
!isAggregateTokens(value.tokens) ||
|
|
550
|
+
value.spend !== null)
|
|
551
|
+
return false;
|
|
552
|
+
if (value.commitMs !== null && value.role !== "serve")
|
|
553
|
+
return false;
|
|
554
|
+
return true;
|
|
555
|
+
}
|
|
556
|
+
function tokenTotalsEqual(a, b) {
|
|
557
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
558
|
+
}
|
|
559
|
+
function isAttemptMetadata(value) {
|
|
560
|
+
return hasExactKeys(value, ["total", "stored", "dropped"]) && isCounter(value.total) && isCounter(value.stored) && isCounter(value.dropped) && value.total <= ACCOUNTING_MAX_PACKET_ATTEMPTS && value.stored <= ACCOUNTING_MAX_DETAIL_ATTEMPTS && value.dropped === value.total - value.stored;
|
|
561
|
+
}
|
|
562
|
+
function isRequestPacket(value) {
|
|
563
|
+
if (!hasExactKeys(value, [
|
|
564
|
+
"requestId",
|
|
565
|
+
"startedAt",
|
|
566
|
+
"endedAt",
|
|
567
|
+
"client",
|
|
568
|
+
"attribution",
|
|
569
|
+
"outcome",
|
|
570
|
+
"failureKind",
|
|
571
|
+
"attemptCount",
|
|
572
|
+
"repairIncluded",
|
|
573
|
+
"winningAttemptId",
|
|
574
|
+
"commitAttemptId",
|
|
575
|
+
"latencyMs",
|
|
576
|
+
"commitMs",
|
|
577
|
+
"provider",
|
|
578
|
+
"model",
|
|
579
|
+
"credentialId",
|
|
580
|
+
"tokens",
|
|
581
|
+
"spend",
|
|
582
|
+
"attempts",
|
|
583
|
+
"attemptMetadata",
|
|
584
|
+
]) ||
|
|
585
|
+
!isRequestId(value.requestId) ||
|
|
586
|
+
!isTimestamp(value.startedAt) ||
|
|
587
|
+
!isTimestamp(value.endedAt) ||
|
|
588
|
+
value.startedAt > value.endedAt ||
|
|
589
|
+
!isNullableId(value.client) ||
|
|
590
|
+
!isAttribution(value.attribution) ||
|
|
591
|
+
!isOutcome(value.outcome) ||
|
|
592
|
+
(value.failureKind !== null && !isFailure(value.failureKind)) ||
|
|
593
|
+
!isFailureCoherent(value.outcome, value.failureKind) ||
|
|
594
|
+
!isCounter(value.attemptCount) ||
|
|
595
|
+
typeof value.repairIncluded !== "boolean" ||
|
|
596
|
+
!(value.winningAttemptId === null || isAttemptId(value.winningAttemptId)) ||
|
|
597
|
+
!(value.commitAttemptId === null || isAttemptId(value.commitAttemptId)) ||
|
|
598
|
+
!isNullableCounter(value.latencyMs) ||
|
|
599
|
+
!isNullableCounter(value.commitMs) ||
|
|
600
|
+
!isNullableId(value.provider) ||
|
|
601
|
+
!isNullableId(value.model) ||
|
|
602
|
+
!isNullableId(value.credentialId) ||
|
|
603
|
+
!isAggregateTokens(value.tokens) ||
|
|
604
|
+
value.spend !== null ||
|
|
605
|
+
!hasExactArray(value.attempts, ACCOUNTING_MAX_DETAIL_ATTEMPTS, isAttemptPacket) ||
|
|
606
|
+
!isAttemptMetadata(value.attemptMetadata))
|
|
607
|
+
return false;
|
|
608
|
+
if (value.attemptMetadata.total !== value.attemptCount || value.attemptMetadata.stored !== value.attempts.length)
|
|
609
|
+
return false;
|
|
610
|
+
if (value.attempts.length === 0 && value.attemptMetadata.total === 0 && value.repairIncluded)
|
|
611
|
+
return false;
|
|
612
|
+
const ids = new Set();
|
|
613
|
+
let sawRepair = false;
|
|
614
|
+
let previousStartedAt = "";
|
|
615
|
+
for (const attempt of value.attempts) {
|
|
616
|
+
if (attempt.requestId !== value.requestId || ids.has(attempt.attemptId))
|
|
617
|
+
return false;
|
|
618
|
+
if (previousStartedAt > attempt.startedAt)
|
|
619
|
+
return false;
|
|
620
|
+
previousStartedAt = attempt.startedAt;
|
|
621
|
+
if (attempt.startedAt < value.startedAt || attempt.endedAt > value.endedAt)
|
|
622
|
+
return false;
|
|
623
|
+
ids.add(attempt.attemptId);
|
|
624
|
+
sawRepair ||= attempt.role === "repair";
|
|
625
|
+
}
|
|
626
|
+
if (value.attemptMetadata.dropped === 0 && value.repairIncluded !== sawRepair)
|
|
627
|
+
return false;
|
|
628
|
+
if (value.attemptMetadata.dropped === 0 && value.attemptMetadata.total !== value.attempts.length)
|
|
629
|
+
return false;
|
|
630
|
+
let authoritative;
|
|
631
|
+
if (value.winningAttemptId !== null) {
|
|
632
|
+
const winner = value.attempts.find((attempt) => attempt.attemptId === value.winningAttemptId);
|
|
633
|
+
if (!winner)
|
|
634
|
+
return false;
|
|
635
|
+
authoritative = winner;
|
|
636
|
+
if (value.outcome === "success") {
|
|
637
|
+
if (winner.role !== "serve" || winner.outcome !== "success" || winner.failureKind !== null)
|
|
638
|
+
return false;
|
|
639
|
+
}
|
|
640
|
+
if (value.outcome !== "success" && value.commitAttemptId === null)
|
|
641
|
+
return false;
|
|
642
|
+
}
|
|
643
|
+
else if (value.outcome === "success") {
|
|
644
|
+
return false;
|
|
645
|
+
}
|
|
646
|
+
if (value.commitAttemptId !== null) {
|
|
647
|
+
if (value.winningAttemptId !== value.commitAttemptId)
|
|
648
|
+
return false;
|
|
649
|
+
const committed = value.attempts.find((attempt) => attempt.attemptId === value.commitAttemptId);
|
|
650
|
+
if (!committed || committed.role !== "serve" || committed.commitMs === null || value.commitMs !== committed.commitMs)
|
|
651
|
+
return false;
|
|
652
|
+
if (value.outcome !== committed.outcome)
|
|
653
|
+
return false;
|
|
654
|
+
if (value.outcome === "success" && committed.failureKind !== null)
|
|
655
|
+
return false;
|
|
656
|
+
authoritative = committed;
|
|
657
|
+
}
|
|
658
|
+
else if (value.commitMs !== null) {
|
|
659
|
+
return false;
|
|
660
|
+
}
|
|
661
|
+
if (authoritative !== undefined) {
|
|
662
|
+
if (authoritative.provider !== value.provider ||
|
|
663
|
+
authoritative.model !== value.model ||
|
|
664
|
+
authoritative.credentialId !== value.credentialId ||
|
|
665
|
+
authoritative.attribution !== value.attribution ||
|
|
666
|
+
!tokenTotalsEqual(authoritative.tokens, value.tokens))
|
|
667
|
+
return false;
|
|
668
|
+
}
|
|
669
|
+
if (value.attemptMetadata.dropped > 0) {
|
|
670
|
+
if (value.winningAttemptId !== null && !ids.has(value.winningAttemptId))
|
|
671
|
+
return false;
|
|
672
|
+
if (value.commitAttemptId !== null && !ids.has(value.commitAttemptId))
|
|
673
|
+
return false;
|
|
674
|
+
}
|
|
675
|
+
const committedAttempts = value.attempts.filter((attempt) => attempt.commitMs !== null);
|
|
676
|
+
if (committedAttempts.length > 1)
|
|
677
|
+
return false;
|
|
678
|
+
if (committedAttempts.length === 1 && value.commitAttemptId !== committedAttempts[0]?.attemptId)
|
|
679
|
+
return false;
|
|
680
|
+
return true;
|
|
681
|
+
}
|
|
682
|
+
function isRecent(value) {
|
|
683
|
+
if (!hasExactKeys(value, ["schema", "version", "rows", "details", "coverage"]) ||
|
|
684
|
+
value.schema !== ACCOUNTING_RECENT_SCHEMA ||
|
|
685
|
+
value.version !== ACCOUNTING_STORE_VERSION ||
|
|
686
|
+
!hasExactArray(value.rows, ACCOUNTING_MAX_RECENT_ROWS, isRequestPacket) ||
|
|
687
|
+
!isPlainRecord(value.details) ||
|
|
688
|
+
!hasOnlyEnumerableStringKeys(value.details) ||
|
|
689
|
+
Object.keys(value.details).length > ACCOUNTING_MAX_RECENT_ROWS ||
|
|
690
|
+
!Object.entries(value.details).every(([key, packet]) => isRequestId(key) && isRequestPacket(packet) && packet.requestId === key) ||
|
|
691
|
+
!isCoverage(value.coverage))
|
|
692
|
+
return false;
|
|
693
|
+
const rowIds = new Set();
|
|
694
|
+
for (const row of value.rows) {
|
|
695
|
+
if (rowIds.has(row.requestId))
|
|
696
|
+
return false;
|
|
697
|
+
rowIds.add(row.requestId);
|
|
698
|
+
}
|
|
699
|
+
return withinFileCeiling(value);
|
|
700
|
+
}
|
|
701
|
+
function cloneValue(value) {
|
|
702
|
+
if (Array.isArray(value))
|
|
703
|
+
return value.map((item) => cloneValue(item));
|
|
704
|
+
if (isPlainRecord(value)) {
|
|
705
|
+
const copy = {};
|
|
706
|
+
for (const [key, item] of Object.entries(value))
|
|
707
|
+
copy[key] = cloneValue(item);
|
|
708
|
+
return copy;
|
|
709
|
+
}
|
|
710
|
+
return value;
|
|
711
|
+
}
|
|
712
|
+
/** The one deep-freeze for the accounting modules; shared, not re-implemented. */
|
|
713
|
+
export function freezeDeep(value) {
|
|
714
|
+
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
715
|
+
for (const item of Object.values(value))
|
|
716
|
+
freezeDeep(item);
|
|
717
|
+
Object.freeze(value);
|
|
718
|
+
}
|
|
719
|
+
return value;
|
|
720
|
+
}
|
|
721
|
+
function parse(value, guard, label) {
|
|
722
|
+
try {
|
|
723
|
+
if (!guard(value))
|
|
724
|
+
return Object.freeze({ ok: false, error: label });
|
|
725
|
+
const copy = cloneValue(value);
|
|
726
|
+
if (!guard(copy))
|
|
727
|
+
return Object.freeze({ ok: false, error: label });
|
|
728
|
+
return Object.freeze({ ok: true, value: freezeDeep(copy) });
|
|
729
|
+
}
|
|
730
|
+
catch {
|
|
731
|
+
return Object.freeze({ ok: false, error: label });
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
export const isAccountingAggregateTokenCellV1 = (value) => {
|
|
735
|
+
try {
|
|
736
|
+
return isAggregateTokenCell(value);
|
|
737
|
+
}
|
|
738
|
+
catch {
|
|
739
|
+
return false;
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
export const isAccountingEstimatedTokenCellV1 = (value) => {
|
|
743
|
+
try {
|
|
744
|
+
return isEstimatedTokenCell(value);
|
|
745
|
+
}
|
|
746
|
+
catch {
|
|
747
|
+
return false;
|
|
748
|
+
}
|
|
749
|
+
};
|
|
750
|
+
export const isAccountingAggregateTokenTotalsV1 = (value) => {
|
|
751
|
+
try {
|
|
752
|
+
return isAggregateTokens(value);
|
|
753
|
+
}
|
|
754
|
+
catch {
|
|
755
|
+
return false;
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
export const isAccountingMetricCellV1 = (value) => {
|
|
759
|
+
try {
|
|
760
|
+
return isMetric(value);
|
|
761
|
+
}
|
|
762
|
+
catch {
|
|
763
|
+
return false;
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
export const isAccountingAggregateV1 = (value) => {
|
|
767
|
+
try {
|
|
768
|
+
return isAggregate(value);
|
|
769
|
+
}
|
|
770
|
+
catch {
|
|
771
|
+
return false;
|
|
772
|
+
}
|
|
773
|
+
};
|
|
774
|
+
export const isAccountingDimensionRowV1 = (value) => {
|
|
775
|
+
try {
|
|
776
|
+
return isDimensionRow(value);
|
|
777
|
+
}
|
|
778
|
+
catch {
|
|
779
|
+
return false;
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
export const isAccountingCoverageV1 = (value) => {
|
|
783
|
+
try {
|
|
784
|
+
return isCoverage(value);
|
|
785
|
+
}
|
|
786
|
+
catch {
|
|
787
|
+
return false;
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
export const isAccountingMinuteShardV1 = (value) => {
|
|
791
|
+
try {
|
|
792
|
+
return isMinuteShard(value);
|
|
793
|
+
}
|
|
794
|
+
catch {
|
|
795
|
+
return false;
|
|
796
|
+
}
|
|
797
|
+
};
|
|
798
|
+
export const isAccountingCompletedRequestDedupV1 = (value) => {
|
|
799
|
+
try {
|
|
800
|
+
return isDedup(value);
|
|
801
|
+
}
|
|
802
|
+
catch {
|
|
803
|
+
return false;
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
export const isAccountingDayShardV1 = (value) => {
|
|
807
|
+
try {
|
|
808
|
+
return isDay(value);
|
|
809
|
+
}
|
|
810
|
+
catch {
|
|
811
|
+
return false;
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
export const isAccountingMonthAggregateV1 = (value) => {
|
|
815
|
+
try {
|
|
816
|
+
return isMonthAggregate(value);
|
|
817
|
+
}
|
|
818
|
+
catch {
|
|
819
|
+
return false;
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
export const isAccountingLifetimeV1 = (value) => {
|
|
823
|
+
try {
|
|
824
|
+
return isLifetime(value);
|
|
825
|
+
}
|
|
826
|
+
catch {
|
|
827
|
+
return false;
|
|
828
|
+
}
|
|
829
|
+
};
|
|
830
|
+
export const isAccountingAttemptPacketV1 = (value) => {
|
|
831
|
+
try {
|
|
832
|
+
return isAttemptPacket(value);
|
|
833
|
+
}
|
|
834
|
+
catch {
|
|
835
|
+
return false;
|
|
836
|
+
}
|
|
837
|
+
};
|
|
838
|
+
export const isAccountingRequestPacketV1 = (value) => {
|
|
839
|
+
try {
|
|
840
|
+
return isRequestPacket(value);
|
|
841
|
+
}
|
|
842
|
+
catch {
|
|
843
|
+
return false;
|
|
844
|
+
}
|
|
845
|
+
};
|
|
846
|
+
export const isAccountingRecentV1 = (value) => {
|
|
847
|
+
try {
|
|
848
|
+
return isRecent(value);
|
|
849
|
+
}
|
|
850
|
+
catch {
|
|
851
|
+
return false;
|
|
852
|
+
}
|
|
853
|
+
};
|
|
854
|
+
export const parseAccountingAggregateTokenCellV1 = (value) => parse(value, isAggregateTokenCell, "token-cell");
|
|
855
|
+
export const parseAccountingEstimatedTokenCellV1 = (value) => parse(value, isEstimatedTokenCell, "estimated-token-cell");
|
|
856
|
+
export const parseAccountingAggregateTokenTotalsV1 = (value) => parse(value, isAggregateTokens, "token-totals");
|
|
857
|
+
export const parseAccountingMetricCellV1 = (value) => parse(value, isMetric, "metric-cell");
|
|
858
|
+
export const parseAccountingAggregateV1 = (value) => parse(value, isAggregate, "aggregate");
|
|
859
|
+
export const parseAccountingDimensionRowV1 = (value) => parse(value, isDimensionRow, "dimension-row");
|
|
860
|
+
export const parseAccountingCoverageV1 = (value) => parse(value, isCoverage, "coverage");
|
|
861
|
+
export const parseAccountingMinuteShardV1 = (value) => parse(value, isMinuteShard, "minute-shard");
|
|
862
|
+
export const parseAccountingCompletedRequestDedupV1 = (value) => parse(value, isDedup, "dedup");
|
|
863
|
+
export const parseAccountingDayShardV1 = (value) => parse(value, isDay, "day-shard");
|
|
864
|
+
export const parseAccountingMonthAggregateV1 = (value) => parse(value, isMonthAggregate, "month-aggregate");
|
|
865
|
+
export const parseAccountingLifetimeV1 = (value) => parse(value, isLifetime, "lifetime");
|
|
866
|
+
export const parseAccountingAttemptPacketV1 = (value) => parse(value, isAttemptPacket, "attempt-packet");
|
|
867
|
+
export const parseAccountingRequestPacketV1 = (value) => parse(value, isRequestPacket, "request-packet");
|
|
868
|
+
export const parseAccountingRecentV1 = (value) => parse(value, isRecent, "recent");
|
|
869
|
+
export const parseAccountingTokenCell = parseAccountingAggregateTokenCellV1;
|
|
870
|
+
export const parseAccountingEstimatedTokenCell = parseAccountingEstimatedTokenCellV1;
|
|
871
|
+
export const parseAccountingTokenTotals = parseAccountingAggregateTokenTotalsV1;
|
|
872
|
+
export const parseAccountingMetricCell = parseAccountingMetricCellV1;
|
|
873
|
+
export const parseAccountingAggregate = parseAccountingAggregateV1;
|
|
874
|
+
export const parseAccountingDimensionRow = parseAccountingDimensionRowV1;
|
|
875
|
+
export const parseAccountingCoverage = parseAccountingCoverageV1;
|
|
876
|
+
export const parseAccountingMinuteShard = parseAccountingMinuteShardV1;
|
|
877
|
+
export const parseAccountingDayShard = parseAccountingDayShardV1;
|
|
878
|
+
export const parseAccountingLifetime = parseAccountingLifetimeV1;
|
|
879
|
+
export const parseAccountingAttemptPacket = parseAccountingAttemptPacketV1;
|
|
880
|
+
export const parseAccountingRequestPacket = parseAccountingRequestPacketV1;
|
|
881
|
+
export const parseAccountingRecent = parseAccountingRecentV1;
|
|
882
|
+
/** Checked addition for counters. null means the exact safe-integer domain overflowed. */
|
|
883
|
+
export function checkedAddAccountingCounter(left, right) {
|
|
884
|
+
if (!isCounter(left) || !isCounter(right) || left > ACCOUNTING_MAX_COUNTER - right)
|
|
885
|
+
return null;
|
|
886
|
+
return left + right;
|
|
887
|
+
}
|
|
888
|
+
function latestTimestamp(a, b) {
|
|
889
|
+
if (a === null)
|
|
890
|
+
return b;
|
|
891
|
+
if (b === null)
|
|
892
|
+
return a;
|
|
893
|
+
return a >= b ? a : b;
|
|
894
|
+
}
|
|
895
|
+
function mergeMethod(a, b, known) {
|
|
896
|
+
if (known === 0)
|
|
897
|
+
return a.unknown + b.unknown + a.lost + b.lost + (a.overflow ? 1 : 0) + (b.overflow ? 1 : 0) > 0 ? "unknown" : null;
|
|
898
|
+
const methods = [a.method, b.method].filter((method) => method !== null && method !== "unknown");
|
|
899
|
+
if (methods.length === 0)
|
|
900
|
+
return "unknown";
|
|
901
|
+
return methods.every((method) => method === methods[0]) ? methods[0] ?? "unknown" : "mixed";
|
|
902
|
+
}
|
|
903
|
+
function mergeCell(a, b, method = null, includeMethod = false) {
|
|
904
|
+
const aBase = {
|
|
905
|
+
value: a.value,
|
|
906
|
+
known: a.known,
|
|
907
|
+
unknown: a.unknown,
|
|
908
|
+
lost: a.lost,
|
|
909
|
+
overflow: a.overflow,
|
|
910
|
+
observedAt: a.observedAt,
|
|
911
|
+
};
|
|
912
|
+
const bBase = {
|
|
913
|
+
value: b.value,
|
|
914
|
+
known: b.known,
|
|
915
|
+
unknown: b.unknown,
|
|
916
|
+
lost: b.lost,
|
|
917
|
+
overflow: b.overflow,
|
|
918
|
+
observedAt: b.observedAt,
|
|
919
|
+
};
|
|
920
|
+
if (!isAggregateTokenCell(aBase) || !isAggregateTokenCell(bBase))
|
|
921
|
+
return null;
|
|
922
|
+
const known = checkedAddAccountingCounter(aBase.known, bBase.known);
|
|
923
|
+
const unknown = checkedAddAccountingCounter(aBase.unknown, bBase.unknown);
|
|
924
|
+
const lost = checkedAddAccountingCounter(aBase.lost, bBase.lost);
|
|
925
|
+
if (known === null || unknown === null || lost === null)
|
|
926
|
+
return null;
|
|
927
|
+
const uncertain = aBase.overflow || bBase.overflow || unknown > 0 || lost > 0;
|
|
928
|
+
let value = null;
|
|
929
|
+
let overflow = aBase.overflow || bBase.overflow;
|
|
930
|
+
if (!uncertain && aBase.value !== null && bBase.value !== null) {
|
|
931
|
+
if (aBase.value > ACCOUNTING_MAX_COUNTER - bBase.value)
|
|
932
|
+
overflow = true;
|
|
933
|
+
else
|
|
934
|
+
value = aBase.value + bBase.value;
|
|
935
|
+
}
|
|
936
|
+
const result = {
|
|
937
|
+
value: overflow || uncertain ? null : value,
|
|
938
|
+
known,
|
|
939
|
+
unknown,
|
|
940
|
+
lost,
|
|
941
|
+
overflow,
|
|
942
|
+
observedAt: latestTimestamp(aBase.observedAt, bBase.observedAt),
|
|
943
|
+
...(includeMethod || method !== null ? { method } : {}),
|
|
944
|
+
};
|
|
945
|
+
return freezeDeep(result);
|
|
946
|
+
}
|
|
947
|
+
export function mergeAccountingTokenCells(left, right) {
|
|
948
|
+
try {
|
|
949
|
+
return mergeCell(left, right);
|
|
950
|
+
}
|
|
951
|
+
catch {
|
|
952
|
+
return null;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
export function mergeAccountingEstimatedTokenCells(left, right) {
|
|
956
|
+
try {
|
|
957
|
+
if (!isEstimatedTokenCell(left) || !isEstimatedTokenCell(right))
|
|
958
|
+
return null;
|
|
959
|
+
const known = checkedAddAccountingCounter(left.known, right.known);
|
|
960
|
+
if (known === null)
|
|
961
|
+
return null;
|
|
962
|
+
const method = mergeMethod(left, right, known);
|
|
963
|
+
const merged = mergeCell(left, right, method, true);
|
|
964
|
+
return merged;
|
|
965
|
+
}
|
|
966
|
+
catch {
|
|
967
|
+
return null;
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
export function mergeAccountingMetricCells(left, right) {
|
|
971
|
+
try {
|
|
972
|
+
if (!isMetric(left) || !isMetric(right))
|
|
973
|
+
return null;
|
|
974
|
+
const known = checkedAddAccountingCounter(left.known, right.known);
|
|
975
|
+
const unknown = checkedAddAccountingCounter(left.unknown, right.unknown);
|
|
976
|
+
const lost = checkedAddAccountingCounter(left.lost, right.lost);
|
|
977
|
+
const dropped = checkedAddAccountingCounter(left.samplesDropped, right.samplesDropped);
|
|
978
|
+
if (known === null || unknown === null || lost === null || dropped === null)
|
|
979
|
+
return null;
|
|
980
|
+
const overflow = left.overflow || right.overflow;
|
|
981
|
+
let sumMs = null;
|
|
982
|
+
let sumOverflow = overflow;
|
|
983
|
+
if (!sumOverflow && left.sumMs !== null && right.sumMs !== null) {
|
|
984
|
+
if (left.sumMs > ACCOUNTING_MAX_COUNTER - right.sumMs)
|
|
985
|
+
sumOverflow = true;
|
|
986
|
+
else
|
|
987
|
+
sumMs = left.sumMs + right.sumMs;
|
|
988
|
+
}
|
|
989
|
+
const samples = [...left.samples, ...right.samples];
|
|
990
|
+
const kept = samples.slice(Math.max(0, samples.length - ACCOUNTING_MAX_SAMPLES));
|
|
991
|
+
const extraDropped = samples.length - kept.length;
|
|
992
|
+
const totalDropped = checkedAddAccountingCounter(dropped, extraDropped);
|
|
993
|
+
if (totalDropped === null)
|
|
994
|
+
return null;
|
|
995
|
+
const result = {
|
|
996
|
+
sumMs: sumOverflow || unknown > 0 || lost > 0 ? null : sumMs,
|
|
997
|
+
known,
|
|
998
|
+
unknown,
|
|
999
|
+
lost,
|
|
1000
|
+
overflow: sumOverflow,
|
|
1001
|
+
samples: kept,
|
|
1002
|
+
samplesDropped: totalDropped,
|
|
1003
|
+
observedAt: latestTimestamp(left.observedAt, right.observedAt),
|
|
1004
|
+
};
|
|
1005
|
+
return freezeDeep(result);
|
|
1006
|
+
}
|
|
1007
|
+
catch {
|
|
1008
|
+
return null;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
// Short aliases make the codec convenient in the store without weakening its explicit v1 names.
|
|
1012
|
+
export const isAggregateTokenTotals = isAccountingAggregateTokenTotalsV1;
|
|
1013
|
+
export const isMetricCell = isAccountingMetricCellV1;
|
|
1014
|
+
export const isAccountingAggregate = isAccountingAggregateV1;
|
|
1015
|
+
export const isAccountingAggregateRow = isAccountingDimensionRowV1;
|
|
1016
|
+
export const isAccountingCoverage = isAccountingCoverageV1;
|
|
1017
|
+
export const isAccountingDay = isAccountingDayShardV1;
|
|
1018
|
+
export const isAccountingLifetime = isAccountingLifetimeV1;
|
|
1019
|
+
export const isAccountingRecent = isAccountingRecentV1;
|
|
1020
|
+
export const isAccountingDetailPacket = isAccountingRequestPacketV1;
|
|
1021
|
+
//# sourceMappingURL=accounting-store-schema.js.map
|