codex-multi-auth 2.8.6 → 2.9.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/.codex-plugin/plugin.json +1 -1
- package/README.md +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -0
- package/dist/lib/account-policy.d.ts +3 -1
- package/dist/lib/account-policy.d.ts.map +1 -1
- package/dist/lib/account-policy.js +14 -1
- package/dist/lib/codex-manager/login-flow.js +7 -0
- package/dist/lib/codex-manager/login-menu-actions.d.ts.map +1 -1
- package/dist/lib/codex-manager/login-menu-actions.js +7 -1
- package/dist/lib/policy/runtime-policy.d.ts +7 -0
- package/dist/lib/policy/runtime-policy.d.ts.map +1 -1
- package/dist/lib/policy/runtime-policy.js +1 -0
- package/dist/lib/request/fetch-helpers.d.ts +7 -0
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
- package/dist/lib/request/fetch-helpers.js +1 -1
- package/dist/lib/request/rate-limit-decision.d.ts +27 -0
- package/dist/lib/request/rate-limit-decision.d.ts.map +1 -1
- package/dist/lib/request/rate-limit-decision.js +117 -2
- package/dist/lib/request/response-handler.d.ts +3 -1
- package/dist/lib/request/response-handler.d.ts.map +1 -1
- package/dist/lib/request/response-handler.js +26 -5
- package/dist/lib/request/stream-failover-runtime.d.ts +8 -1
- package/dist/lib/request/stream-failover-runtime.d.ts.map +1 -1
- package/dist/lib/request/stream-failover-runtime.js +9 -1
- package/dist/lib/request/stream-failover.d.ts.map +1 -1
- package/dist/lib/request/stream-failover.js +41 -0
- package/dist/lib/runtime/account-check.d.ts.map +1 -1
- package/dist/lib/runtime/account-check.js +8 -1
- package/dist/lib/runtime/account-status.d.ts +39 -10
- package/dist/lib/runtime/account-status.d.ts.map +1 -1
- package/dist/lib/runtime/account-status.js +47 -42
- package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -1
- package/dist/lib/runtime-rotation-proxy.js +73 -8
- package/dist/lib/storage.d.ts +19 -0
- package/dist/lib/storage.d.ts.map +1 -1
- package/dist/lib/storage.js +32 -0
- package/dist/lib/usage/index.d.ts +2 -0
- package/dist/lib/usage/index.d.ts.map +1 -1
- package/dist/lib/usage/index.js +2 -0
- package/dist/lib/usage/stream-usage-deferral.d.ts +39 -0
- package/dist/lib/usage/stream-usage-deferral.d.ts.map +1 -0
- package/dist/lib/usage/stream-usage-deferral.js +54 -0
- package/dist/lib/usage/usage-extraction.d.ts +42 -0
- package/dist/lib/usage/usage-extraction.d.ts.map +1 -0
- package/dist/lib/usage/usage-extraction.js +178 -0
- package/package.json +1 -1
- package/scripts/codex.js +300 -82
|
@@ -117,6 +117,34 @@ export function withStreamingFailover(initialResponse, getFallbackResponse, opti
|
|
|
117
117
|
}
|
|
118
118
|
let closed = false;
|
|
119
119
|
let releaseCurrentReaderForCancel = null;
|
|
120
|
+
// Backpressure. `pump()` runs from `start()` as a free-running loop, so
|
|
121
|
+
// without a demand signal it enqueues every chunk upstream delivers as fast
|
|
122
|
+
// as it arrives and the whole stream buffers in memory for a slow consumer.
|
|
123
|
+
// `pull()` (and cancellation) release the loop; the sibling forwarder in
|
|
124
|
+
// stream-failover-runtime.ts gets the same guarantee from waitForDrain.
|
|
125
|
+
let demandWaiter = null;
|
|
126
|
+
let demandPending = false;
|
|
127
|
+
const signalDemand = () => {
|
|
128
|
+
if (demandWaiter) {
|
|
129
|
+
demandWaiter();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
// `pull()` can fire before the loop parks. Latch it, or the next
|
|
133
|
+
// awaitDemand() would block on a signal that already happened.
|
|
134
|
+
demandPending = true;
|
|
135
|
+
};
|
|
136
|
+
const awaitDemand = () => {
|
|
137
|
+
if (demandPending || closed) {
|
|
138
|
+
demandPending = false;
|
|
139
|
+
return Promise.resolve();
|
|
140
|
+
}
|
|
141
|
+
return new Promise((resolve) => {
|
|
142
|
+
demandWaiter = () => {
|
|
143
|
+
demandWaiter = null;
|
|
144
|
+
resolve();
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
|
+
};
|
|
120
148
|
const body = new ReadableStream({
|
|
121
149
|
start(controller) {
|
|
122
150
|
let currentReader = initialResponse.body?.getReader() ?? null;
|
|
@@ -174,6 +202,13 @@ export function withStreamingFailover(initialResponse, getFallbackResponse, opti
|
|
|
174
202
|
if (result.value && result.value.byteLength > 0) {
|
|
175
203
|
emittedBytes += result.value.byteLength;
|
|
176
204
|
controller.enqueue(result.value);
|
|
205
|
+
// Park until the consumer asks for more. desiredSize is
|
|
206
|
+
// null once the controller is errored or closed, and the
|
|
207
|
+
// loop's own `closed` checks cover that case.
|
|
208
|
+
if (typeof controller.desiredSize === "number" &&
|
|
209
|
+
controller.desiredSize <= 0) {
|
|
210
|
+
await awaitDemand();
|
|
211
|
+
}
|
|
177
212
|
}
|
|
178
213
|
}
|
|
179
214
|
catch (error) {
|
|
@@ -206,8 +241,14 @@ export function withStreamingFailover(initialResponse, getFallbackResponse, opti
|
|
|
206
241
|
}
|
|
207
242
|
});
|
|
208
243
|
},
|
|
244
|
+
pull() {
|
|
245
|
+
signalDemand();
|
|
246
|
+
},
|
|
209
247
|
cancel() {
|
|
210
248
|
closed = true;
|
|
249
|
+
// Release a parked pump so it observes `closed` and unwinds instead
|
|
250
|
+
// of holding the upstream reader open for a demand that never comes.
|
|
251
|
+
signalDemand();
|
|
211
252
|
if (releaseCurrentReaderForCancel) {
|
|
212
253
|
void releaseCurrentReaderForCancel();
|
|
213
254
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account-check.d.ts","sourceRoot":"","sources":["../../../lib/runtime/account-check.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EACN,KAAK,gBAAgB,
|
|
1
|
+
{"version":3,"file":"account-check.d.ts","sourceRoot":"","sources":["../../../lib/runtime/account-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { maskEmail } from "../logger.js";
|
|
2
2
|
import { CODEX_UNAVAILABLE_PROBE_NOTE } from "../quota-probe.js";
|
|
3
3
|
import { isCodexUnavailableError } from "../errors.js";
|
|
4
|
-
import { reconcilePinnedAccountIndex, } from "../storage.js";
|
|
4
|
+
import { bumpStorageAffinityGeneration, reconcilePinnedAccountIndex, } from "../storage.js";
|
|
5
5
|
export async function runRuntimeAccountCheck(deepProbe, deps) {
|
|
6
6
|
const loadedStorage = await deps.hydrateEmails(await deps.loadAccounts());
|
|
7
7
|
const workingStorage = loadedStorage
|
|
@@ -195,6 +195,13 @@ export async function runRuntimeAccountCheck(deepProbe, deps) {
|
|
|
195
195
|
workingStorage.accounts = workingStorage.accounts.filter((account) => !state.removeFromActive.has(account.refreshToken));
|
|
196
196
|
deps.clampRuntimeActiveIndices(workingStorage, deps.MODEL_FAMILIES);
|
|
197
197
|
workingStorage.pinnedAccountIndex = reconcilePinnedAccountIndex(pinnedAccount, workingStorage.accounts);
|
|
198
|
+
// The filter can drop several accounts at once, shifting every index
|
|
199
|
+
// after each hole. Session affinity remembers accounts BY INDEX, so
|
|
200
|
+
// without a generation bump a live proxy keeps routing in-flight
|
|
201
|
+
// sessions to whatever now occupies the old slot — and this path is
|
|
202
|
+
// AUTOMATIC (revoked-token accounts are removed without a prompt), so
|
|
203
|
+
// nothing else invalidates the affinity map. See issue #474.
|
|
204
|
+
bumpStorageAffinityGeneration(workingStorage);
|
|
198
205
|
state.storageChanged = true;
|
|
199
206
|
}
|
|
200
207
|
const persistAccountAndFlaggedStorage = deps.persistAccountAndFlaggedStorage;
|
|
@@ -7,22 +7,51 @@ export declare function resolveActiveIndex(storage: {
|
|
|
7
7
|
export declare function getRateLimitResetTimeForFamily(account: {
|
|
8
8
|
rateLimitResetTimes?: Record<string, number | undefined>;
|
|
9
9
|
}, now: number, family: ModelFamily): number | null;
|
|
10
|
+
export interface AccountRecoveryBounds {
|
|
11
|
+
/**
|
|
12
|
+
* The moment the account becomes usable again: `rateLimitAtMs` widened by
|
|
13
|
+
* any active cooldown, because the account stays skipped while ANY gating
|
|
14
|
+
* record is active. Null when nothing bounds recovery.
|
|
15
|
+
*/
|
|
16
|
+
recoveryAtMs: number | null;
|
|
17
|
+
/**
|
|
18
|
+
* The rate-limit records' own contribution to `recoveryAtMs`, cooldowns
|
|
19
|
+
* excluded. The pinned-503 uses it to decide whether the deadline it
|
|
20
|
+
* advertises is in fact the rate limit's own reset — with a breaker or
|
|
21
|
+
* cooldown ending later, the full recovery bound outlives the rate limit
|
|
22
|
+
* and must not be worded as its reset. Null when no rate-limit record
|
|
23
|
+
* gates the request.
|
|
24
|
+
*/
|
|
25
|
+
rateLimitAtMs: number | null;
|
|
26
|
+
}
|
|
10
27
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
28
|
+
* Both recovery bounds for a `family`/`model` request, from ONE pass over
|
|
29
|
+
* `rateLimitResetTimes` against a single `now`.
|
|
30
|
+
*
|
|
31
|
+
* Two deliberate differences from getRateLimitResetTimeForFamily, whose
|
|
32
|
+
* earliest-reset answer feeds wait displays: the latest bound wins, because
|
|
33
|
+
* the earliest reset would send clients back into a 503 — and only the keys
|
|
34
|
+
* selection consults (`family`, plus `family:<model>` when a model is known;
|
|
35
|
+
* see isRateLimitedForFamily) may contribute, because another model's record
|
|
36
|
+
* does not block this request and would overstate its recovery.
|
|
37
|
+
*
|
|
38
|
+
* A caller that needs both bounds must take them from one call. Measuring
|
|
39
|
+
* them separately lets a record expire between the two walks, which reports
|
|
40
|
+
* a rate-limited account as if a cooldown bounded its recovery.
|
|
21
41
|
*/
|
|
42
|
+
export declare function getAccountRecoveryBoundsForFamily(account: {
|
|
43
|
+
rateLimitResetTimes?: Record<string, number | undefined>;
|
|
44
|
+
coolingDownUntil?: number;
|
|
45
|
+
}, now: number, family: ModelFamily, model?: string | null): AccountRecoveryBounds;
|
|
46
|
+
/** The `recoveryAtMs` bound alone; see getAccountRecoveryBoundsForFamily. */
|
|
22
47
|
export declare function getAccountRecoveryTimeForFamily(account: {
|
|
23
48
|
rateLimitResetTimes?: Record<string, number | undefined>;
|
|
24
49
|
coolingDownUntil?: number;
|
|
25
50
|
}, now: number, family: ModelFamily, model?: string | null): number | null;
|
|
51
|
+
/** The `rateLimitAtMs` bound alone; see getAccountRecoveryBoundsForFamily. */
|
|
52
|
+
export declare function getRateLimitRecoveryTimeForFamily(account: {
|
|
53
|
+
rateLimitResetTimes?: Record<string, number | undefined>;
|
|
54
|
+
}, now: number, family: ModelFamily, model?: string | null): number | null;
|
|
26
55
|
export declare function formatRateLimitEntry(account: {
|
|
27
56
|
rateLimitResetTimes?: Record<string, number | undefined>;
|
|
28
57
|
}, now: number, formatWaitTime: (ms: number) => string, family?: ModelFamily): string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account-status.d.ts","sourceRoot":"","sources":["../../../lib/runtime/account-status.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,wBAAgB,kBAAkB,CACjC,OAAO,EAAE;IACR,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3D,QAAQ,EAAE,OAAO,EAAE,CAAC;CACpB,EACD,MAAM,GAAE,WAAqB,GAC3B,MAAM,CAOR;AAED,wBAAgB,8BAA8B,CAC7C,OAAO,EAAE;IAAE,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CAAE,EACrE,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,WAAW,GACjB,MAAM,GAAG,IAAI,CAgBf;AAED
|
|
1
|
+
{"version":3,"file":"account-status.d.ts","sourceRoot":"","sources":["../../../lib/runtime/account-status.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,wBAAgB,kBAAkB,CACjC,OAAO,EAAE;IACR,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3D,QAAQ,EAAE,OAAO,EAAE,CAAC;CACpB,EACD,MAAM,GAAE,WAAqB,GAC3B,MAAM,CAOR;AAED,wBAAgB,8BAA8B,CAC7C,OAAO,EAAE;IAAE,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CAAE,EACrE,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,WAAW,GACjB,MAAM,GAAG,IAAI,CAgBf;AAeD,MAAM,WAAW,qBAAqB;IACrC;;;;OAIG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B;;;;;;;OAOG;IACH,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iCAAiC,CAChD,OAAO,EAAE;IACR,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B,EACD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,qBAAqB,CAevB;AAED,6EAA6E;AAC7E,wBAAgB,+BAA+B,CAC9C,OAAO,EAAE;IACR,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B,EACD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,GAAG,IAAI,CAGf;AAED,8EAA8E;AAC9E,wBAAgB,iCAAiC,CAChD,OAAO,EAAE;IACR,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CACzD,EACD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,GAAG,IAAI,CAGf;AAED,wBAAgB,oBAAoB,CACnC,OAAO,EAAE;IAAE,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CAAE,EACrE,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,EACtC,MAAM,GAAE,WAAqB,GAC3B,MAAM,GAAG,IAAI,CAMf;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,6BAA6B,CAC5C,OAAO,EAAE;IAAE,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CAAE,EACrE,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,MAAM,GACX,MAAM,GAAG,IAAI,CAGf"}
|
|
@@ -26,36 +26,54 @@ export function getRateLimitResetTimeForFamily(account, now, family) {
|
|
|
26
26
|
}
|
|
27
27
|
return minReset;
|
|
28
28
|
}
|
|
29
|
+
/** The value when it is still a live bound at `now`, otherwise null. */
|
|
30
|
+
function activeBound(value, now) {
|
|
31
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
32
|
+
return null;
|
|
33
|
+
return value > now ? value : null;
|
|
34
|
+
}
|
|
35
|
+
/** The later of two bounds, treating null as "does not bound". */
|
|
36
|
+
function laterBound(a, b) {
|
|
37
|
+
if (a === null)
|
|
38
|
+
return b;
|
|
39
|
+
if (b === null)
|
|
40
|
+
return a;
|
|
41
|
+
return a > b ? a : b;
|
|
42
|
+
}
|
|
29
43
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
44
|
+
* Both recovery bounds for a `family`/`model` request, from ONE pass over
|
|
45
|
+
* `rateLimitResetTimes` against a single `now`.
|
|
46
|
+
*
|
|
47
|
+
* Two deliberate differences from getRateLimitResetTimeForFamily, whose
|
|
48
|
+
* earliest-reset answer feeds wait displays: the latest bound wins, because
|
|
49
|
+
* the earliest reset would send clients back into a 503 — and only the keys
|
|
50
|
+
* selection consults (`family`, plus `family:<model>` when a model is known;
|
|
51
|
+
* see isRateLimitedForFamily) may contribute, because another model's record
|
|
52
|
+
* does not block this request and would overstate its recovery.
|
|
53
|
+
*
|
|
54
|
+
* A caller that needs both bounds must take them from one call. Measuring
|
|
55
|
+
* them separately lets a record expire between the two walks, which reports
|
|
56
|
+
* a rate-limited account as if a cooldown bounded its recovery.
|
|
40
57
|
*/
|
|
41
|
-
export function
|
|
42
|
-
let latest = null;
|
|
43
|
-
const consider = (value) => {
|
|
44
|
-
if (typeof value !== "number" || !Number.isFinite(value))
|
|
45
|
-
return;
|
|
46
|
-
if (value <= now)
|
|
47
|
-
return;
|
|
48
|
-
if (latest === null || value > latest)
|
|
49
|
-
latest = value;
|
|
50
|
-
};
|
|
58
|
+
export function getAccountRecoveryBoundsForFamily(account, now, family, model) {
|
|
51
59
|
const times = account.rateLimitResetTimes;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
const rateLimitAtMs = times
|
|
61
|
+
? laterBound(activeBound(times[getQuotaKey(family)], now), model ? activeBound(times[getQuotaKey(family, model)], now) : null)
|
|
62
|
+
: null;
|
|
63
|
+
return {
|
|
64
|
+
rateLimitAtMs,
|
|
65
|
+
recoveryAtMs: laterBound(rateLimitAtMs, activeBound(account.coolingDownUntil, now)),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** The `recoveryAtMs` bound alone; see getAccountRecoveryBoundsForFamily. */
|
|
69
|
+
export function getAccountRecoveryTimeForFamily(account, now, family, model) {
|
|
70
|
+
return getAccountRecoveryBoundsForFamily(account, now, family, model)
|
|
71
|
+
.recoveryAtMs;
|
|
72
|
+
}
|
|
73
|
+
/** The `rateLimitAtMs` bound alone; see getAccountRecoveryBoundsForFamily. */
|
|
74
|
+
export function getRateLimitRecoveryTimeForFamily(account, now, family, model) {
|
|
75
|
+
return getAccountRecoveryBoundsForFamily(account, now, family, model)
|
|
76
|
+
.rateLimitAtMs;
|
|
59
77
|
}
|
|
60
78
|
export function formatRateLimitEntry(account, now, formatWaitTime, family = "codex") {
|
|
61
79
|
const resetAt = getRateLimitResetTimeForFamily(account, now, family);
|
|
@@ -86,19 +104,6 @@ export function formatRateLimitEntry(account, now, formatWaitTime, family = "cod
|
|
|
86
104
|
* model key applies and should keep the family-wide union above.
|
|
87
105
|
*/
|
|
88
106
|
export function getRateLimitResetTimeForModel(account, now, family, model) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return null;
|
|
92
|
-
let latest = null;
|
|
93
|
-
const consider = (value) => {
|
|
94
|
-
if (typeof value !== "number" || !Number.isFinite(value))
|
|
95
|
-
return;
|
|
96
|
-
if (value <= now)
|
|
97
|
-
return;
|
|
98
|
-
if (latest === null || value > latest)
|
|
99
|
-
latest = value;
|
|
100
|
-
};
|
|
101
|
-
consider(times[getQuotaKey(family)]);
|
|
102
|
-
consider(times[getQuotaKey(family, model)]);
|
|
103
|
-
return latest;
|
|
107
|
+
return getAccountRecoveryBoundsForFamily(account, now, family, model)
|
|
108
|
+
.rateLimitAtMs;
|
|
104
109
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-rotation-proxy.d.ts","sourceRoot":"","sources":["../../lib/runtime-rotation-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EAIN,KAAK,cAAc,EACnB,MAAM,eAAe,CAAC;AA8BvB,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime-rotation-proxy.d.ts","sourceRoot":"","sources":["../../lib/runtime-rotation-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EAIN,KAAK,cAAc,EACnB,MAAM,eAAe,CAAC;AA8BvB,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA6CtE,OAAO,KAAK,EAKX,2BAA2B,EAC3B,0BAA0B,EAE1B,MAAM,oCAAoC,CAAC;AAe5C,YAAY,EACX,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,GAC1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACN,+BAA+B,EAC/B,0BAA0B,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,OAAO,EACN,+BAA+B,EAC/B,8BAA8B,EAC9B,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AA8DtE,kFAAkF;AAClF,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GAAG;IACvE,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,EACD,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,CAmBR;AA8bD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAC1C,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GACvC,MAAM,GAAG,IAAI,CAUf;AAED,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,2BAA2B,GAClC,OAAO,CAAC,0BAA0B,CAAC,CA4KrC"}
|
|
@@ -8,6 +8,7 @@ import { getModelFamily } from "./prompts/codex.js";
|
|
|
8
8
|
import { CURRENT_CODEX_MODEL } from "./request/helpers/model-map.js";
|
|
9
9
|
import { mutateRuntimeObservabilitySnapshot, recordRuntimeAccountRecovery, recordRuntimePoolExhaustion, } from "./runtime/runtime-observability.js";
|
|
10
10
|
import { createRuntimeUsageRecorder, evaluateRuntimePolicy, loadRuntimePolicyState, } from "./policy/runtime-policy.js";
|
|
11
|
+
import { createUsageStreamScanner } from "./usage/usage-extraction.js";
|
|
11
12
|
import { isWorkspaceDisabledError } from "./request/fetch-helpers.js";
|
|
12
13
|
import { PreemptiveQuotaScheduler, readQuotaSchedulerSnapshot, } from "./preemptive-quota-scheduler.js";
|
|
13
14
|
import { createLogger, maskString, runWithCorrelationId } from "./logger.js";
|
|
@@ -15,7 +16,7 @@ import { CodexValidationError } from "./errors.js";
|
|
|
15
16
|
import { normalizeEmailKey } from "./storage/identity.js";
|
|
16
17
|
import { buildPinnedUnavailableErrorBody, buildTokenInvalidationBody, extractErrorCodeFromBody, isTokenInvalidationError, normalizeExhaustionStatus, parseRetryAfterBodyMs, parseRetryAfterHeaderMs, } from "./request/rate-limit-decision.js";
|
|
17
18
|
import { forwardStreamingResponse, HOP_BY_HOP_HEADERS, readErrorBody, responseHeadersForClient, withTimeout, } from "./request/stream-failover-runtime.js";
|
|
18
|
-
import {
|
|
19
|
+
import { getAccountRecoveryBoundsForFamily } from "./runtime/account-status.js";
|
|
19
20
|
import { chooseAccount } from "./runtime/rotation-account-selection.js";
|
|
20
21
|
import { createRotationProxyState, recoverStaleRuntimeState, } from "./runtime/rotation-proxy-state.js";
|
|
21
22
|
import { readStorageMetaFromDisk } from "./runtime/rotation-storage-meta.js";
|
|
@@ -936,11 +937,35 @@ async function handleRequestInner(state, req, res, traceId) {
|
|
|
936
937
|
upstream = await withTimeout(state.fetchImpl(upstreamUrl, upstreamRequestInit), state.fetchTimeoutMs, () => fetchAbortController.abort(), `upstream fetch timed out after ${state.fetchTimeoutMs}ms`);
|
|
937
938
|
}
|
|
938
939
|
catch (error) {
|
|
939
|
-
|
|
940
|
+
// errors-logging-08: a custom fetchImpl, a proxy agent, or an undici
|
|
941
|
+
// cause chain can embed the request URL or credential material in the
|
|
942
|
+
// raw message, so mask before it reaches any state.status consumer.
|
|
943
|
+
const transportError = maskString(error instanceof Error ? error.message : String(error));
|
|
944
|
+
state.status.lastError = transportError;
|
|
945
|
+
// errors-logging-01: give the failure a structured, trace-correlated
|
|
946
|
+
// line instead of only a last-write-wins status string. Nothing else
|
|
947
|
+
// on this path reaches proxyLog, because the request does not throw.
|
|
948
|
+
proxyLog.error("upstream transport failure", {
|
|
949
|
+
traceId,
|
|
950
|
+
code: "codex_runtime_rotation_transport_error",
|
|
951
|
+
error: transportError,
|
|
952
|
+
});
|
|
940
953
|
accountManager.refundToken(refreshed.account, context.family, context.model);
|
|
941
|
-
|
|
954
|
+
// A pre-header transport exception is a property of the network path,
|
|
955
|
+
// not of this account's credentials or quota, so it must NOT feed the
|
|
956
|
+
// account's circuit breaker / health tracker: that is what would
|
|
957
|
+
// otherwise retire a healthy account for an outage it did not cause.
|
|
958
|
+
// See #677.
|
|
959
|
+
//
|
|
960
|
+
// The short timed cooldown IS still applied. It is self-healing, it
|
|
961
|
+
// keeps an account whose upstream hangs from stalling 1/N of every
|
|
962
|
+
// later request for the full fetch timeout, and it is what gives the
|
|
963
|
+
// exhaustion 503 a non-zero `retry_after_ms` to back the client off
|
|
964
|
+
// with (`getMinWaitTimeForFamily` returns 0 while any account is
|
|
965
|
+
// still selectable).
|
|
942
966
|
accountManager.markAccountCoolingDown(refreshed.account, state.networkErrorCooldownMs, "network-error");
|
|
943
967
|
accountManager.saveToDiskDebounced();
|
|
968
|
+
accountSkipReasons.set(refreshed.account.index, "network-error");
|
|
944
969
|
exhaustionReason = "network-error";
|
|
945
970
|
transientAttempts += 1;
|
|
946
971
|
transientExhaustionReason = "network-error";
|
|
@@ -1152,17 +1177,35 @@ async function handleRequestInner(state, req, res, traceId) {
|
|
|
1152
1177
|
state.lastGlobalSwitchAt = state.now();
|
|
1153
1178
|
}
|
|
1154
1179
|
await persistRuntimeActiveAccount(accountManager, refreshed.account, context.family, isPinned && refreshed.account.index === pinnedIndex, state.schedulingStrategy);
|
|
1180
|
+
// Recover the upstream token counts as the body streams past. Without
|
|
1181
|
+
// them every ledger row lands with all-zero tokens and a zero cost, so
|
|
1182
|
+
// evaluateBudgetGuard compares `0 >= limit` for maxTokens/maxCostUsd
|
|
1183
|
+
// and those caps never fire — `budget set --cost 50` would allow
|
|
1184
|
+
// unlimited spend, with only --requests actually enforced.
|
|
1185
|
+
const usageScanner = createUsageStreamScanner({
|
|
1186
|
+
contentType: upstream.headers.get("content-type"),
|
|
1187
|
+
});
|
|
1155
1188
|
const forwarded = await forwardStreamingResponse(upstream, res, state.status, () => {
|
|
1189
|
+
// Deliberately NOT the pre-header transport policy above,
|
|
1190
|
+
// which skips recordFailure (#677). By this point the
|
|
1191
|
+
// upstream accepted the request and began responding, so a
|
|
1192
|
+
// broken stream is a signal about THIS account's session
|
|
1193
|
+
// (upstream tearing it down) rather than about the shared
|
|
1194
|
+
// network path, and it should still credit the breaker.
|
|
1156
1195
|
accountManager.recordFailure(refreshed.account, context.family, context.model);
|
|
1157
1196
|
accountManager.markAccountCoolingDown(refreshed.account, state.networkErrorCooldownMs, "network-error");
|
|
1158
1197
|
state.sessionAffinityStore?.forgetSession(context.sessionKey);
|
|
1159
1198
|
accountManager.saveToDiskDebounced();
|
|
1160
|
-
}, state.streamStallTimeoutMs);
|
|
1199
|
+
}, state.streamStallTimeoutMs, usageScanner.push);
|
|
1200
|
+
// A stream that broke mid-flight still bills for whatever the upstream
|
|
1201
|
+
// reported before the break, so record the counts on both outcomes.
|
|
1202
|
+
const usageTokens = usageScanner.result();
|
|
1161
1203
|
await usageRecorder.record({
|
|
1162
1204
|
outcome: forwarded ? "success" : "failure",
|
|
1163
1205
|
statusCode: upstream.status,
|
|
1164
1206
|
errorCode: forwarded ? null : "stream_forward_failed",
|
|
1165
1207
|
account: refreshed.account,
|
|
1208
|
+
...(usageTokens ?? {}),
|
|
1166
1209
|
});
|
|
1167
1210
|
return;
|
|
1168
1211
|
}
|
|
@@ -1219,23 +1262,45 @@ async function handleRequestInner(state, req, res, traceId) {
|
|
|
1219
1262
|
// recovery — and with several overlapping records the account stays
|
|
1220
1263
|
// skipped until the LAST one expires, so the latest bound is the one
|
|
1221
1264
|
// worth advertising.
|
|
1222
|
-
|
|
1265
|
+
//
|
|
1266
|
+
// One clock for the whole body. The recovery bound and the
|
|
1267
|
+
// rate-limit bound are compared against each other below, so
|
|
1268
|
+
// reading state.now() per lookup would let a record expire between
|
|
1269
|
+
// them and report a rate-limited pin as bounded by something else.
|
|
1270
|
+
const evaluatedAtMs = state.now();
|
|
1271
|
+
// Both bounds come from a single pass over the account's records.
|
|
1272
|
+
const pinnedRecoveryBounds = pinnedAccount === null
|
|
1223
1273
|
? null
|
|
1224
|
-
:
|
|
1274
|
+
: getAccountRecoveryBoundsForFamily(pinnedAccount, evaluatedAtMs, context.family, context.model);
|
|
1275
|
+
const pinnedStateRecoveryAtMs = pinnedRecoveryBounds?.recoveryAtMs ?? null;
|
|
1225
1276
|
// An open circuit outlives the short failure cooldowns that tripped
|
|
1226
1277
|
// it; its deadline lives in the breaker, not the account record.
|
|
1227
1278
|
const pinnedCircuitRecoveryAtMs = pinnedAccount === null
|
|
1228
1279
|
? null
|
|
1229
|
-
: accountManager.getCircuitRecoveryTime(pinnedAccount,
|
|
1280
|
+
: accountManager.getCircuitRecoveryTime(pinnedAccount, evaluatedAtMs);
|
|
1230
1281
|
const pinnedResetAtMs = pinnedBlockedPermanently ||
|
|
1231
1282
|
(pinnedStateRecoveryAtMs === null && pinnedCircuitRecoveryAtMs === null)
|
|
1232
1283
|
? null
|
|
1233
1284
|
: Math.max(pinnedStateRecoveryAtMs ?? 0, pinnedCircuitRecoveryAtMs ?? 0);
|
|
1285
|
+
// The message only words the recovery deadline as a rate-limit reset
|
|
1286
|
+
// when the rate-limit records are in fact what supplies it — a
|
|
1287
|
+
// breaker or cooldown can end later and then bounds it instead.
|
|
1288
|
+
const pinnedRateLimitResetAtMs = pinnedRecoveryBounds?.rateLimitAtMs ?? null;
|
|
1289
|
+
const recoveryBound = pinnedResetAtMs !== null &&
|
|
1290
|
+
pinnedRateLimitResetAtMs !== null &&
|
|
1291
|
+
pinnedRateLimitResetAtMs >= pinnedResetAtMs
|
|
1292
|
+
? "rate-limit"
|
|
1293
|
+
: "other";
|
|
1234
1294
|
const errorBody = buildPinnedUnavailableErrorBody(pinnedIndex, accountSkipReasons, {
|
|
1235
1295
|
// typeof check so a forced index of 0 still reads as forced.
|
|
1236
1296
|
pinSource: typeof state.forcedAccountIndex === "number" ? "forced" : "manual",
|
|
1237
1297
|
resetAtMs: pinnedResetAtMs,
|
|
1238
|
-
|
|
1298
|
+
recoveryBound,
|
|
1299
|
+
// The recorded verdict above is the retry loop's
|
|
1300
|
+
// "already-attempted" on the dominant path; the re-read runtime
|
|
1301
|
+
// state is what the operator-facing sentence should describe.
|
|
1302
|
+
currentSkipReason: pinnedCurrentSkipReason,
|
|
1303
|
+
now: evaluatedAtMs,
|
|
1239
1304
|
});
|
|
1240
1305
|
if (errorBody.reason === null) {
|
|
1241
1306
|
state.status.lastError = `pinned-503 missing skip reason (pinnedIndex=${pinnedIndex})`;
|
package/dist/lib/storage.d.ts
CHANGED
|
@@ -83,6 +83,25 @@ export declare function normalizeAccountStorage(data: unknown): AccountStorageV3
|
|
|
83
83
|
* helper only narrows the lost-update window. See issue #474.
|
|
84
84
|
*/
|
|
85
85
|
export declare function readAffinityGenerationFromDisk(path: string): number;
|
|
86
|
+
/**
|
|
87
|
+
* Advance the session-affinity generation so a running runtime proxy drops its
|
|
88
|
+
* sticky session→account bindings on the next request.
|
|
89
|
+
*
|
|
90
|
+
* Session affinity remembers an account by ITS INDEX, so any mutation that
|
|
91
|
+
* reshuffles the pool (removing an account, restoring a backup) silently
|
|
92
|
+
* re-points every live session at a different account until the generation
|
|
93
|
+
* changes. `switch`/`best`/`unpin` already bump it; the reshuffling paths are
|
|
94
|
+
* the ones that need it most, because they move every index at once.
|
|
95
|
+
*
|
|
96
|
+
* Re-reads the on-disk generation first so concurrent CLI processes do not lose
|
|
97
|
+
* increments via lost-update on the load+mutate pair. `Math.max` keeps the
|
|
98
|
+
* counter monotonic: an extra bump only costs one additional affinity
|
|
99
|
+
* invalidation, while a missed bump lets the proxy cling to the wrong account.
|
|
100
|
+
* See issue #474.
|
|
101
|
+
*/
|
|
102
|
+
export declare function bumpStorageAffinityGeneration(storage: {
|
|
103
|
+
affinityGeneration?: number;
|
|
104
|
+
}, storagePath?: string | null): number;
|
|
86
105
|
/**
|
|
87
106
|
* Synchronously reads both the top-level `pinnedAccountIndex` and
|
|
88
107
|
* `affinityGeneration` fields from the accounts storage file. Used by
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../lib/storage.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../lib/storage.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/storage.js
CHANGED
|
@@ -951,6 +951,38 @@ export function readAffinityGenerationFromDisk(path) {
|
|
|
951
951
|
return 0;
|
|
952
952
|
}
|
|
953
953
|
}
|
|
954
|
+
/**
|
|
955
|
+
* Advance the session-affinity generation so a running runtime proxy drops its
|
|
956
|
+
* sticky session→account bindings on the next request.
|
|
957
|
+
*
|
|
958
|
+
* Session affinity remembers an account by ITS INDEX, so any mutation that
|
|
959
|
+
* reshuffles the pool (removing an account, restoring a backup) silently
|
|
960
|
+
* re-points every live session at a different account until the generation
|
|
961
|
+
* changes. `switch`/`best`/`unpin` already bump it; the reshuffling paths are
|
|
962
|
+
* the ones that need it most, because they move every index at once.
|
|
963
|
+
*
|
|
964
|
+
* Re-reads the on-disk generation first so concurrent CLI processes do not lose
|
|
965
|
+
* increments via lost-update on the load+mutate pair. `Math.max` keeps the
|
|
966
|
+
* counter monotonic: an extra bump only costs one additional affinity
|
|
967
|
+
* invalidation, while a missed bump lets the proxy cling to the wrong account.
|
|
968
|
+
* See issue #474.
|
|
969
|
+
*/
|
|
970
|
+
export function bumpStorageAffinityGeneration(storage, storagePath) {
|
|
971
|
+
let diskGeneration = 0;
|
|
972
|
+
try {
|
|
973
|
+
const path = storagePath ?? getStoragePath();
|
|
974
|
+
if (path)
|
|
975
|
+
diskGeneration = readAffinityGenerationFromDisk(path);
|
|
976
|
+
}
|
|
977
|
+
catch {
|
|
978
|
+
// No resolvable storage path (never configured). The in-memory counter
|
|
979
|
+
// is still bumped below; only the lost-update guard is unavailable.
|
|
980
|
+
}
|
|
981
|
+
const inMemoryGeneration = storage.affinityGeneration ?? 0;
|
|
982
|
+
const next = Math.max(inMemoryGeneration, diskGeneration) + 1;
|
|
983
|
+
storage.affinityGeneration = next;
|
|
984
|
+
return next;
|
|
985
|
+
}
|
|
954
986
|
/**
|
|
955
987
|
* Synchronously reads both the top-level `pinnedAccountIndex` and
|
|
956
988
|
* `affinityGeneration` fields from the accounts storage file. Used by
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/usage/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/usage/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC"}
|
package/dist/lib/usage/index.js
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { UsageTokenCounts } from "./types.js";
|
|
2
|
+
export interface StreamUsageDeferral<TRow> {
|
|
3
|
+
/** Latest counts reported by upstream, or null if none have arrived. */
|
|
4
|
+
captured: () => UsageTokenCounts | null;
|
|
5
|
+
/** Feed upstream-reported counts. Writes a deferred row immediately. */
|
|
6
|
+
onUsage: (usage: UsageTokenCounts) => void;
|
|
7
|
+
/**
|
|
8
|
+
* Hand over a row to be written once upstream reports its counts, or after
|
|
9
|
+
* `fallbackMs` without them. Only the first pending row is held.
|
|
10
|
+
*/
|
|
11
|
+
defer: (completion: TRow) => void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Holds a usage-ledger row open until a streaming response reports its tokens.
|
|
15
|
+
*
|
|
16
|
+
* A streaming request's row would otherwise be written when the request handler
|
|
17
|
+
* returns its Response — before the client has read a byte, and therefore
|
|
18
|
+
* before the upstream `usage` event exists. The ledger is append-only, so that
|
|
19
|
+
* row could never be corrected: it would stand at zero tokens and zero cost
|
|
20
|
+
* forever, which is what silently disables the `maxTokens` and `maxCostUsd`
|
|
21
|
+
* budget caps (`evaluateBudgetGuard` compares `0 >= limit`).
|
|
22
|
+
*
|
|
23
|
+
* The fallback timer is not optional bookkeeping. A client that disconnects
|
|
24
|
+
* mid-stream, or an upstream that never emits a terminal usage event, must
|
|
25
|
+
* still cost one row, because `maxRequests` counts rows — losing it would
|
|
26
|
+
* weaken a cap that currently works.
|
|
27
|
+
*
|
|
28
|
+
* Generic over the row type so this stays inside `lib/usage` rather than
|
|
29
|
+
* importing the policy layer that imports it back.
|
|
30
|
+
*/
|
|
31
|
+
export declare function createStreamUsageDeferral<TRow extends object>(options: {
|
|
32
|
+
record: (completion: TRow & Partial<UsageTokenCounts>) => void;
|
|
33
|
+
fallbackMs: number;
|
|
34
|
+
/** Injectable for tests; defaults to an unref'd setTimeout. */
|
|
35
|
+
schedule?: (run: () => void, ms: number) => {
|
|
36
|
+
cancel: () => void;
|
|
37
|
+
};
|
|
38
|
+
}): StreamUsageDeferral<TRow>;
|
|
39
|
+
//# sourceMappingURL=stream-usage-deferral.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-usage-deferral.d.ts","sourceRoot":"","sources":["../../../lib/usage/stream-usage-deferral.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,MAAM,WAAW,mBAAmB,CAAC,IAAI;IACxC,wEAAwE;IACxE,QAAQ,EAAE,MAAM,gBAAgB,GAAG,IAAI,CAAC;IACxC,wEAAwE;IACxE,OAAO,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC3C;;;OAGG;IACH,KAAK,EAAE,CAAC,UAAU,EAAE,IAAI,KAAK,IAAI,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,SAAS,MAAM,EAAE,OAAO,EAAE;IACvE,MAAM,EAAE,CAAC,UAAU,EAAE,IAAI,GAAG,OAAO,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK;QAAE,MAAM,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;CACnE,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAqC5B"}
|