@centerforagenticai/pi-multi-account 0.1.1
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/NOTICE +29 -0
- package/README.md +999 -0
- package/config/models/pi-multi-account.v1.json +32 -0
- package/config/subscription-plans.v1.json +122 -0
- package/package.json +76 -0
- package/packages/pi-anthropic-oauth/LICENSE +21 -0
- package/packages/pi-anthropic-oauth/package.json +54 -0
- package/packages/pi-anthropic-oauth/src/auth.ts +396 -0
- package/packages/pi-anthropic-oauth/src/context.ts +116 -0
- package/packages/pi-anthropic-oauth/src/convert.ts +303 -0
- package/packages/pi-anthropic-oauth/src/index.ts +37 -0
- package/packages/pi-anthropic-oauth/src/prompt.ts +137 -0
- package/packages/pi-anthropic-oauth/src/stream.ts +476 -0
- package/packages/pi-antigravity/LICENSE +21 -0
- package/packages/pi-antigravity/package.json +77 -0
- package/packages/pi-antigravity/src/auth/index.ts +14 -0
- package/packages/pi-antigravity/src/auth/oauth.ts +442 -0
- package/packages/pi-antigravity/src/client/client.ts +561 -0
- package/packages/pi-antigravity/src/client/index.ts +1 -0
- package/packages/pi-antigravity/src/context.ts +110 -0
- package/packages/pi-antigravity/src/diagnostics/diagnostics.ts +96 -0
- package/packages/pi-antigravity/src/diagnostics/index.ts +1 -0
- package/packages/pi-antigravity/src/image/image.ts +336 -0
- package/packages/pi-antigravity/src/image/index.ts +1 -0
- package/packages/pi-antigravity/src/index.ts +280 -0
- package/packages/pi-antigravity/src/models/discovery.ts +154 -0
- package/packages/pi-antigravity/src/models/grouping.ts +424 -0
- package/packages/pi-antigravity/src/models/index.ts +3 -0
- package/packages/pi-antigravity/src/models/models.ts +500 -0
- package/packages/pi-antigravity/src/stream/index.ts +1 -0
- package/packages/pi-antigravity/src/stream/stream.ts +1478 -0
- package/packages/pi-antigravity/src/types/enums.ts +42 -0
- package/packages/pi-antigravity/src/types/index.ts +2 -0
- package/packages/pi-antigravity/src/types/types.ts +292 -0
- package/packages/pi-antigravity/src/usage/index.ts +1 -0
- package/packages/pi-antigravity/src/usage/usage.ts +416 -0
- package/packages/pi-antigravity/src/utils/http.ts +91 -0
- package/packages/pi-antigravity/src/utils/index.ts +3 -0
- package/packages/pi-antigravity/src/utils/security.ts +73 -0
- package/packages/pi-antigravity/src/utils/util.ts +132 -0
- package/scripts/multi-account.mjs +44 -0
- package/src/account-labels.ts +223 -0
- package/src/account-plan-assignment.ts +340 -0
- package/src/account-rate-history.ts +372 -0
- package/src/anthropic-adaptive-stream.ts +531 -0
- package/src/anthropic-alias-stream.ts +140 -0
- package/src/anthropic-context-compat.ts +80 -0
- package/src/api-pricing.ts +579 -0
- package/src/bounded-file-lines.ts +97 -0
- package/src/catalog-rebinding.ts +177 -0
- package/src/catalog-registration-probe.ts +111 -0
- package/src/codex-adapter.ts +345 -0
- package/src/codex-model-defaults.ts +785 -0
- package/src/command-completions.ts +404 -0
- package/src/commands.ts +2000 -0
- package/src/compaction.ts +14 -0
- package/src/config.ts +1317 -0
- package/src/continuation.ts +569 -0
- package/src/cooldowns.ts +110 -0
- package/src/cost-digest-store.ts +332 -0
- package/src/cost-digest.ts +1044 -0
- package/src/cost-history.ts +251 -0
- package/src/cost-period-closer.ts +160 -0
- package/src/cost-report-json.ts +318 -0
- package/src/cost-report-reader.ts +368 -0
- package/src/cost-report-render.ts +207 -0
- package/src/cost-report.ts +1104 -0
- package/src/coverage-attestation.ts +397 -0
- package/src/credential-lifecycle.ts +169 -0
- package/src/credential-refresh.ts +248 -0
- package/src/declaration-notice-marker.ts +238 -0
- package/src/diagnostic-store.ts +276 -0
- package/src/diagnostics.ts +309 -0
- package/src/discovery.ts +471 -0
- package/src/duration.ts +13 -0
- package/src/error-classification.ts +256 -0
- package/src/fuzzy.ts +15 -0
- package/src/group-policy.ts +81 -0
- package/src/history-store.ts +897 -0
- package/src/index.ts +5572 -0
- package/src/lifecycle.ts +378 -0
- package/src/logical-dispatch.ts +279 -0
- package/src/logical-model-selector.ts +254 -0
- package/src/logical-model-switcher.ts +430 -0
- package/src/logical-provider-attribution.ts +544 -0
- package/src/logical-provider.ts +1237 -0
- package/src/logical-route-indicator.ts +215 -0
- package/src/machine-lease.ts +445 -0
- package/src/model-support.ts +66 -0
- package/src/models-declaration.ts +1091 -0
- package/src/openai-adapter.ts +117 -0
- package/src/openrouter-budget.ts +304 -0
- package/src/openrouter-fallback.ts +146 -0
- package/src/period-boundaries.ts +376 -0
- package/src/pi-anthropic-oauth.d.ts +6 -0
- package/src/preflight.ts +253 -0
- package/src/pricing-cache.ts +235 -0
- package/src/project-identity.ts +100 -0
- package/src/provider-registration.ts +942 -0
- package/src/rate-formula.ts +163 -0
- package/src/recovery-engine.ts +853 -0
- package/src/recovery-output.ts +837 -0
- package/src/recovery-plan.ts +239 -0
- package/src/report-range.ts +203 -0
- package/src/route-resolver.ts +789 -0
- package/src/routing-config-transaction.ts +232 -0
- package/src/routing.ts +1163 -0
- package/src/runtime-state.ts +630 -0
- package/src/session-account-groups.ts +284 -0
- package/src/session-restore.ts +287 -0
- package/src/shared-usage.ts +1392 -0
- package/src/standalone-cli.ts +720 -0
- package/src/status-view.ts +578 -0
- package/src/subscription-plan-catalog.ts +346 -0
- package/src/tier-model-resolver.ts +46 -0
- package/src/upstream-anthropic.ts +315 -0
- package/src/upstream-antigravity.ts +327 -0
- package/src/usage-fetch.ts +1634 -0
- package/src/usage.ts +1026 -0
- package/src/vendor.ts +87 -0
- package/src/warmer.ts +231 -0
- package/src/watchdog.ts +219 -0
- package/src/window-history.ts +270 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
appendHistory,
|
|
4
|
+
iterateHistory,
|
|
5
|
+
} from "./history-store.js";
|
|
6
|
+
import { isAllowedFamily, type AllowedFamily } from "./config.js";
|
|
7
|
+
import { isCanonicalManagedProviderId } from "./runtime-state.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The subscription family a retained window sample names, or `undefined` for a
|
|
11
|
+
* non-string, unknown, or owning-vendor-api `openai` family. Its fixed
|
|
12
|
+
* `AllowedFamily | undefined` return type is what keeps the retained window
|
|
13
|
+
* schema subscription-only while still narrowing `family` to `AllowedFamily` for
|
|
14
|
+
* the downstream `isCanonicalManagedProviderId` check. The mutation control for
|
|
15
|
+
* this guard changes only this body (to `return family as AllowedFamily`), which
|
|
16
|
+
* still compiles because the signature is unchanged.
|
|
17
|
+
*/
|
|
18
|
+
function subscriptionFamilyForWindow(family: unknown): AllowedFamily | undefined {
|
|
19
|
+
return typeof family === "string" && isAllowedFamily(family)
|
|
20
|
+
? family
|
|
21
|
+
: undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const MAX_OBSERVER_ID_LENGTH = 128;
|
|
25
|
+
const DEFAULT_BUILD_PROVENANCE = "pi-multi-account@0.1.0";
|
|
26
|
+
const UNUSABLE_REASON = "reset-time-unavailable";
|
|
27
|
+
const MAX_PROJECT_DIGEST_LENGTH = 64;
|
|
28
|
+
/**
|
|
29
|
+
* Bounded, opaque, non-identifying digest shape (e.g. a truncated sha256 hex
|
|
30
|
+
* digest with a short type prefix, as produced by
|
|
31
|
+
* `usage-fetch.ts#deriveAntigravityProjectDigest`). This module never derives
|
|
32
|
+
* the digest itself and never accepts a raw project id: it only bounds and
|
|
33
|
+
* stores whatever already-projected value a caller supplies.
|
|
34
|
+
*/
|
|
35
|
+
function validProjectDigest(value: unknown): value is string {
|
|
36
|
+
return (
|
|
37
|
+
typeof value === "string" &&
|
|
38
|
+
value.length > 0 &&
|
|
39
|
+
value.length <= MAX_PROJECT_DIGEST_LENGTH &&
|
|
40
|
+
/^[a-z0-9-]+$/.test(value)
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** A retained sample for one provider-reported rate-limit window. */
|
|
45
|
+
export interface WindowSample {
|
|
46
|
+
readonly providerId: string;
|
|
47
|
+
/** Canonical account identity; deliberately not a human-readable label. */
|
|
48
|
+
readonly accountId: string;
|
|
49
|
+
readonly family: AllowedFamily;
|
|
50
|
+
readonly windowId: string;
|
|
51
|
+
/** Reset epoch used by rate calculation; absent samples are unusable. */
|
|
52
|
+
readonly resetEpoch?: number;
|
|
53
|
+
/** Canonical stored unit: fraction of the provider budget remaining. */
|
|
54
|
+
readonly remainingFraction?: number;
|
|
55
|
+
readonly resetAtMs?: number;
|
|
56
|
+
/**
|
|
57
|
+
* Bounded, non-identifying digest of an upstream account-scoped project id
|
|
58
|
+
* (e.g. Google Antigravity's Cloud project). Absent for a family with no such
|
|
59
|
+
* concept. Never the raw id -- see `validProjectDigest`.
|
|
60
|
+
*/
|
|
61
|
+
readonly projectDigest?: string;
|
|
62
|
+
readonly recordedAtMs: number;
|
|
63
|
+
readonly schemaVersion: number;
|
|
64
|
+
readonly buildProvenance: string;
|
|
65
|
+
readonly observerId: string;
|
|
66
|
+
readonly usable: boolean;
|
|
67
|
+
readonly unusableReason?: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export type WindowHistoryWriteOptions = NonNullable<
|
|
71
|
+
Parameters<typeof appendHistory>[1]
|
|
72
|
+
>;
|
|
73
|
+
|
|
74
|
+
type WindowSampleInput = Omit<
|
|
75
|
+
WindowSample,
|
|
76
|
+
"schemaVersion" | "buildProvenance" | "observerId" | "usable"
|
|
77
|
+
> &
|
|
78
|
+
Partial<
|
|
79
|
+
Pick<
|
|
80
|
+
WindowSample,
|
|
81
|
+
"schemaVersion" | "buildProvenance" | "observerId" | "usable" | "unusableReason"
|
|
82
|
+
>
|
|
83
|
+
>;
|
|
84
|
+
|
|
85
|
+
function validTimestamp(value: unknown): value is number {
|
|
86
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function validFraction(value: unknown): value is number {
|
|
90
|
+
return (
|
|
91
|
+
typeof value === "number" &&
|
|
92
|
+
Number.isFinite(value) &&
|
|
93
|
+
value >= 0 &&
|
|
94
|
+
value <= 1
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function validWindowSample(value: unknown): value is WindowSample {
|
|
99
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
const sample = value as Record<string, unknown>;
|
|
103
|
+
// Retained window schema stays subscription-only: an owning-vendor-api
|
|
104
|
+
// `openai` family yields `undefined` here and is rejected below, even though
|
|
105
|
+
// isCanonicalManagedProviderId now widens. `family` is AllowedFamily when set.
|
|
106
|
+
const family = subscriptionFamilyForWindow(sample.family);
|
|
107
|
+
if (
|
|
108
|
+
typeof sample.providerId !== "string" ||
|
|
109
|
+
typeof sample.accountId !== "string" ||
|
|
110
|
+
family === undefined ||
|
|
111
|
+
!isCanonicalManagedProviderId(sample.providerId, family) ||
|
|
112
|
+
sample.accountId !== sample.providerId ||
|
|
113
|
+
typeof sample.windowId !== "string" ||
|
|
114
|
+
sample.windowId.length === 0 ||
|
|
115
|
+
sample.windowId.length > 128 ||
|
|
116
|
+
!validTimestamp(sample.recordedAtMs) ||
|
|
117
|
+
sample.schemaVersion !== 1 ||
|
|
118
|
+
typeof sample.buildProvenance !== "string" ||
|
|
119
|
+
sample.buildProvenance.length === 0 ||
|
|
120
|
+
sample.buildProvenance.length > 128 ||
|
|
121
|
+
typeof sample.observerId !== "string" ||
|
|
122
|
+
sample.observerId.length === 0 ||
|
|
123
|
+
sample.observerId.length > MAX_OBSERVER_ID_LENGTH ||
|
|
124
|
+
typeof sample.usable !== "boolean"
|
|
125
|
+
) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
if (sample.remainingFraction !== undefined && !validFraction(sample.remainingFraction)) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
if (sample.resetAtMs !== undefined && !validTimestamp(sample.resetAtMs)) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
if (sample.resetEpoch !== undefined && !validTimestamp(sample.resetEpoch)) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
if (sample.projectDigest !== undefined && !validProjectDigest(sample.projectDigest)) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
if (sample.usable && (!validFraction(sample.remainingFraction) || !validTimestamp(sample.resetAtMs))) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
if (!sample.usable && typeof sample.unusableReason !== "string") {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function normalizeSample(sample: WindowSampleInput): WindowSample {
|
|
150
|
+
const usable =
|
|
151
|
+
sample.usable === true &&
|
|
152
|
+
validFraction(sample.remainingFraction) &&
|
|
153
|
+
validTimestamp(sample.resetAtMs);
|
|
154
|
+
const suppliedObserverId = sample.observerId;
|
|
155
|
+
const observerId =
|
|
156
|
+
typeof suppliedObserverId === "string" &&
|
|
157
|
+
/^process-[a-zA-Z0-9-]+$/.test(suppliedObserverId)
|
|
158
|
+
? suppliedObserverId
|
|
159
|
+
: `process-${process.pid}`;
|
|
160
|
+
const normalized: WindowSample = {
|
|
161
|
+
providerId: sample.providerId,
|
|
162
|
+
accountId: sample.accountId,
|
|
163
|
+
family: sample.family,
|
|
164
|
+
windowId: sample.windowId,
|
|
165
|
+
...(sample.resetAtMs === undefined ? {} : { resetAtMs: sample.resetAtMs }),
|
|
166
|
+
...(sample.resetEpoch === undefined
|
|
167
|
+
? {}
|
|
168
|
+
: { resetEpoch: sample.resetEpoch }),
|
|
169
|
+
...(sample.remainingFraction === undefined
|
|
170
|
+
? {}
|
|
171
|
+
: { remainingFraction: sample.remainingFraction }),
|
|
172
|
+
...(sample.projectDigest === undefined
|
|
173
|
+
? {}
|
|
174
|
+
: { projectDigest: sample.projectDigest }),
|
|
175
|
+
recordedAtMs: sample.recordedAtMs,
|
|
176
|
+
schemaVersion: sample.schemaVersion ?? 1,
|
|
177
|
+
buildProvenance: sample.buildProvenance ?? DEFAULT_BUILD_PROVENANCE,
|
|
178
|
+
observerId: observerId.slice(0, MAX_OBSERVER_ID_LENGTH),
|
|
179
|
+
usable,
|
|
180
|
+
...(usable
|
|
181
|
+
? {}
|
|
182
|
+
: {
|
|
183
|
+
unusableReason:
|
|
184
|
+
sample.unusableReason ?? UNUSABLE_REASON,
|
|
185
|
+
}),
|
|
186
|
+
};
|
|
187
|
+
return normalized;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Convert a utilization fraction into the canonical remaining fraction. */
|
|
191
|
+
export function remainingFractionFromUtilization(
|
|
192
|
+
utilization: number,
|
|
193
|
+
): number | undefined {
|
|
194
|
+
return validFraction(utilization)
|
|
195
|
+
? Math.round((1 - utilization) * 1_000_000_000_000) / 1_000_000_000_000
|
|
196
|
+
: undefined;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** Convert the stored remaining fraction into utilization at read time. */
|
|
200
|
+
export function utilizationFromRemainingFraction(
|
|
201
|
+
remainingFraction: number,
|
|
202
|
+
): number | undefined {
|
|
203
|
+
return validFraction(remainingFraction) ? 1 - remainingFraction : undefined;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Mark a provider window unusable without discarding or inventing its reset. */
|
|
207
|
+
export function markWindowUnusable(sample: WindowSampleInput): WindowSample {
|
|
208
|
+
return normalizeSample({ ...sample, usable: false });
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Persist one immutable window sample through the shared history lock. */
|
|
212
|
+
export async function writeHistoryWindowSample(
|
|
213
|
+
sample: WindowSampleInput,
|
|
214
|
+
options?: WindowHistoryWriteOptions,
|
|
215
|
+
): Promise<boolean> {
|
|
216
|
+
try {
|
|
217
|
+
const normalized = normalizeSample(sample);
|
|
218
|
+
if (!validWindowSample(normalized)) return false;
|
|
219
|
+
return await appendHistory(
|
|
220
|
+
{
|
|
221
|
+
schemaVersion: 1,
|
|
222
|
+
recordType: "window-sample",
|
|
223
|
+
stableId: randomUUID(),
|
|
224
|
+
observedAtMs: normalized.recordedAtMs,
|
|
225
|
+
recordedAtMs: normalized.recordedAtMs,
|
|
226
|
+
payload: normalized,
|
|
227
|
+
},
|
|
228
|
+
options,
|
|
229
|
+
);
|
|
230
|
+
} catch {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function* iterateValidWindowHistory(
|
|
236
|
+
options?: WindowHistoryWriteOptions,
|
|
237
|
+
): Generator<WindowSample> {
|
|
238
|
+
for (const record of iterateHistory("window-sample", options)) {
|
|
239
|
+
if (record.recordType !== "window-sample") continue;
|
|
240
|
+
if (validWindowSample(record.payload)) yield record.payload;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** Read valid window payloads while preserving the history store's append log. */
|
|
245
|
+
export function readWindowHistory(
|
|
246
|
+
options?: WindowHistoryWriteOptions,
|
|
247
|
+
): readonly WindowSample[] {
|
|
248
|
+
return [...iterateValidWindowHistory(options)];
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Fold status history to one latest sample per provider/window identity. */
|
|
252
|
+
export function readLatestWindowHistory(
|
|
253
|
+
options?: WindowHistoryWriteOptions,
|
|
254
|
+
): ReadonlyMap<string, readonly WindowSample[]> {
|
|
255
|
+
const latest = new Map<string, WindowSample>();
|
|
256
|
+
for (const sample of iterateValidWindowHistory(options)) {
|
|
257
|
+
const key = JSON.stringify([sample.providerId, sample.windowId]);
|
|
258
|
+
const previous = latest.get(key);
|
|
259
|
+
if (previous === undefined || sample.recordedAtMs > previous.recordedAtMs) {
|
|
260
|
+
latest.set(key, sample);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
const byProvider = new Map<string, WindowSample[]>();
|
|
264
|
+
for (const sample of latest.values()) {
|
|
265
|
+
const samples = byProvider.get(sample.providerId) ?? [];
|
|
266
|
+
samples.push(sample);
|
|
267
|
+
byProvider.set(sample.providerId, samples);
|
|
268
|
+
}
|
|
269
|
+
return byProvider;
|
|
270
|
+
}
|