@oh-my-pi/pi-ai 16.2.5 → 16.2.6
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/CHANGELOG.md +6 -0
- package/package.json +4 -4
- package/src/providers/openai-codex-responses.ts +22 -4
- package/src/stream.ts +13 -6
- package/src/usage/google-antigravity.ts +59 -5
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [16.2.6] - 2026-06-29
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fixed Antigravity usage reporting to correctly infer daily and weekly quota windows from unlabeled reset-only rows, preventing Cloud Code Assist payloads from collapsing these counters into the default category.
|
|
10
|
+
|
|
5
11
|
## [16.2.5] - 2026-06-28
|
|
6
12
|
|
|
7
13
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-ai",
|
|
4
|
-
"version": "16.2.
|
|
4
|
+
"version": "16.2.6",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@bufbuild/protobuf": "^2.12.0",
|
|
41
|
-
"@oh-my-pi/pi-catalog": "16.2.
|
|
42
|
-
"@oh-my-pi/pi-utils": "16.2.
|
|
43
|
-
"@oh-my-pi/pi-wire": "16.2.
|
|
41
|
+
"@oh-my-pi/pi-catalog": "16.2.6",
|
|
42
|
+
"@oh-my-pi/pi-utils": "16.2.6",
|
|
43
|
+
"@oh-my-pi/pi-wire": "16.2.6",
|
|
44
44
|
"arktype": "^2.2.0",
|
|
45
45
|
"zod": "^4"
|
|
46
46
|
},
|
|
@@ -2151,14 +2151,29 @@ function recordCodexWebSocketFailure(state: CodexWebSocketSessionState, activate
|
|
|
2151
2151
|
}
|
|
2152
2152
|
}
|
|
2153
2153
|
|
|
2154
|
+
function getCodexWebSocketEnvValue(): boolean | undefined {
|
|
2155
|
+
const envVal = $env.PI_CODEX_WEBSOCKET;
|
|
2156
|
+
if (envVal !== undefined) {
|
|
2157
|
+
return $flag("PI_CODEX_WEBSOCKET");
|
|
2158
|
+
}
|
|
2159
|
+
return undefined;
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2154
2162
|
function shouldUseCodexWebSocket(
|
|
2155
2163
|
model: Model<"openai-codex-responses">,
|
|
2156
2164
|
state: CodexWebSocketSessionState | undefined,
|
|
2157
2165
|
preferWebsockets?: boolean,
|
|
2158
2166
|
): boolean {
|
|
2167
|
+
// Explicitly disabled by the model or session state.
|
|
2168
|
+
if (model.preferWebsockets === false) return false;
|
|
2169
|
+
// Explicitly disabled by the session state.
|
|
2159
2170
|
if (!state || state.disableWebsocket) return false;
|
|
2171
|
+
// Env val > Preference
|
|
2172
|
+
const envVal = getCodexWebSocketEnvValue();
|
|
2173
|
+
if (envVal !== undefined) return envVal;
|
|
2174
|
+
// Negative preference overrides model preference; otherwise use the model's preference.
|
|
2160
2175
|
if (preferWebsockets === false) return false;
|
|
2161
|
-
return
|
|
2176
|
+
return true;
|
|
2162
2177
|
}
|
|
2163
2178
|
|
|
2164
2179
|
export interface OpenAICodexTransportDetails {
|
|
@@ -2214,10 +2229,13 @@ export function getOpenAICodexTransportDetails(
|
|
|
2214
2229
|
providerSessionState?: Map<string, ProviderSessionState>;
|
|
2215
2230
|
},
|
|
2216
2231
|
): OpenAICodexTransportDetails {
|
|
2232
|
+
const envVal = getCodexWebSocketEnvValue();
|
|
2217
2233
|
const websocketPreferred =
|
|
2218
|
-
|
|
2219
|
-
?
|
|
2220
|
-
:
|
|
2234
|
+
envVal !== undefined
|
|
2235
|
+
? envVal
|
|
2236
|
+
: options?.preferWebsockets === false
|
|
2237
|
+
? false
|
|
2238
|
+
: options?.preferWebsockets === true || model.preferWebsockets === true;
|
|
2221
2239
|
const state = getCodexWebSocketStateForPublicSession(model, options);
|
|
2222
2240
|
|
|
2223
2241
|
return {
|
package/src/stream.ts
CHANGED
|
@@ -367,14 +367,17 @@ async function tryAcquireProviderInFlightLease(
|
|
|
367
367
|
}
|
|
368
368
|
}
|
|
369
369
|
|
|
370
|
-
async function
|
|
370
|
+
async function signalProviderInFlightWaitersInDir(dir: string): Promise<void> {
|
|
371
371
|
try {
|
|
372
|
-
const dir = providerInFlightDir(provider);
|
|
373
372
|
await fs.mkdir(dir, { recursive: true });
|
|
374
|
-
await Bun.write(
|
|
373
|
+
await Bun.write(path.join(dir, ".wakeup"), String(Date.now()));
|
|
375
374
|
} catch {}
|
|
376
375
|
}
|
|
377
376
|
|
|
377
|
+
async function signalProviderInFlightWaiters(provider: string): Promise<void> {
|
|
378
|
+
await signalProviderInFlightWaitersInDir(providerInFlightDir(provider));
|
|
379
|
+
}
|
|
380
|
+
|
|
378
381
|
function waitForProviderInFlightSignal(provider: string, signal?: AbortSignal): Promise<void> {
|
|
379
382
|
if (signal?.aborted)
|
|
380
383
|
return Promise.reject(signal.reason ?? new AIError.AbortError("Provider request aborted before dispatch"));
|
|
@@ -434,11 +437,15 @@ async function removeProviderInFlightLeaseDir(leasePath: string): Promise<void>
|
|
|
434
437
|
}
|
|
435
438
|
}
|
|
436
439
|
|
|
437
|
-
|
|
440
|
+
// Signal into the lease's OWN provider directory (derived from `lease.path`)
|
|
441
|
+
// rather than recomputing it from the current root. A release that lands after
|
|
442
|
+
// the in-flight root has been repointed (only the test seam does that) must not
|
|
443
|
+
// write `.wakeup` into an unrelated provider directory.
|
|
444
|
+
async function releaseProviderInFlightLease(lease: ProviderInFlightLease): Promise<void> {
|
|
438
445
|
clearInterval(lease.heartbeat);
|
|
439
446
|
await lease.flushHeartbeat();
|
|
440
447
|
await removeProviderInFlightLeaseDir(lease.path);
|
|
441
|
-
await
|
|
448
|
+
await signalProviderInFlightWaitersInDir(path.dirname(lease.path));
|
|
442
449
|
}
|
|
443
450
|
|
|
444
451
|
async function acquireProviderInFlightSlot(
|
|
@@ -451,7 +458,7 @@ async function acquireProviderInFlightSlot(
|
|
|
451
458
|
while (true) {
|
|
452
459
|
if (signal?.aborted) throw signal.reason ?? new AIError.AbortError("Provider request aborted before dispatch");
|
|
453
460
|
const lease = await tryAcquireProviderInFlightLease(provider, limit, signal);
|
|
454
|
-
if (lease) return () => releaseProviderInFlightLease(
|
|
461
|
+
if (lease) return () => releaseProviderInFlightLease(lease);
|
|
455
462
|
if (!loggedWait) {
|
|
456
463
|
loggedWait = true;
|
|
457
464
|
logger.debug("Provider in-flight limit blocked request", { provider, limit });
|
|
@@ -68,6 +68,57 @@ function classifyWindow(id: string | undefined, label: string | undefined): Anti
|
|
|
68
68
|
return undefined;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
function parseResetTime(info: AntigravityQuotaInfo): number | undefined {
|
|
72
|
+
const resetAt = info.resetTime ? Date.parse(info.resetTime) : undefined;
|
|
73
|
+
return resetAt !== undefined && Number.isFinite(resetAt) ? resetAt : undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function inferWindowFromReset(resetAt: number | undefined, nowMs: number): AntigravityWindowDescriptor {
|
|
77
|
+
if (resetAt !== undefined && resetAt - nowMs > ONE_DAY_MS) {
|
|
78
|
+
return { id: "weekly", label: "Weekly", durationMs: ONE_WEEK_MS };
|
|
79
|
+
}
|
|
80
|
+
return { id: "daily", label: "Daily", durationMs: ONE_DAY_MS };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function quotaInferenceKey(info: AntigravityQuotaInfo): string {
|
|
84
|
+
return [info.modelProvider ?? "", info.apiProvider ?? "", info.tier ?? ""].join("|");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function inferWindowDescriptors(
|
|
88
|
+
quotaInfos: AntigravityQuotaInfo[],
|
|
89
|
+
nowMs: number,
|
|
90
|
+
): WeakMap<AntigravityQuotaInfo, AntigravityWindowDescriptor> {
|
|
91
|
+
const descriptors = new WeakMap<AntigravityQuotaInfo, AntigravityWindowDescriptor>();
|
|
92
|
+
const groups = new Map<string, { info: AntigravityQuotaInfo; resetAt: number | undefined }[]>();
|
|
93
|
+
|
|
94
|
+
for (const info of quotaInfos) {
|
|
95
|
+
const explicitDescriptor = classifyWindow(info.windowId, info.windowLabel);
|
|
96
|
+
if (explicitDescriptor) {
|
|
97
|
+
descriptors.set(info, explicitDescriptor);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const group = groups.get(quotaInferenceKey(info)) ?? [];
|
|
101
|
+
group.push({ info, resetAt: parseResetTime(info) });
|
|
102
|
+
groups.set(quotaInferenceKey(info), group);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
for (const group of groups.values()) {
|
|
106
|
+
const resetTimes = [...new Set(group.map(entry => entry.resetAt).filter(resetAt => resetAt !== undefined))].sort(
|
|
107
|
+
(a, b) => a - b,
|
|
108
|
+
);
|
|
109
|
+
const latestReset = resetTimes.length > 1 ? resetTimes.at(-1) : undefined;
|
|
110
|
+
for (const entry of group) {
|
|
111
|
+
const descriptor =
|
|
112
|
+
latestReset !== undefined && entry.resetAt === latestReset
|
|
113
|
+
? { id: "weekly", label: "Weekly", durationMs: ONE_WEEK_MS }
|
|
114
|
+
: inferWindowFromReset(entry.resetAt, nowMs);
|
|
115
|
+
descriptors.set(entry.info, descriptor);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return descriptors;
|
|
120
|
+
}
|
|
121
|
+
|
|
71
122
|
function withWindowDescriptor(
|
|
72
123
|
info: AntigravityQuotaInfo,
|
|
73
124
|
descriptor: AntigravityWindowDescriptor | undefined,
|
|
@@ -94,10 +145,12 @@ function getUsageStatus(remainingFraction: number | undefined): UsageStatus | un
|
|
|
94
145
|
return "ok";
|
|
95
146
|
}
|
|
96
147
|
|
|
97
|
-
function parseWindow(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
148
|
+
function parseWindow(
|
|
149
|
+
info: AntigravityQuotaInfo,
|
|
150
|
+
descriptor: AntigravityWindowDescriptor | undefined,
|
|
151
|
+
): UsageWindow | undefined {
|
|
152
|
+
const resetAt = parseResetTime(info);
|
|
153
|
+
const hasResetAt = resetAt !== undefined;
|
|
101
154
|
if (!descriptor && !hasResetAt) return undefined;
|
|
102
155
|
return {
|
|
103
156
|
id: descriptor?.id ?? info.windowId ?? "default",
|
|
@@ -276,9 +329,10 @@ async function fetchAntigravityUsage(params: UsageFetchParams, ctx: UsageFetchCo
|
|
|
276
329
|
|
|
277
330
|
for (const [_modelId, modelInfo] of Object.entries(data.models ?? {})) {
|
|
278
331
|
const quotaInfos = normalizeQuotaInfos(modelInfo);
|
|
332
|
+
const inferredDescriptors = inferWindowDescriptors(quotaInfos, nowMs);
|
|
279
333
|
for (const quotaInfo of quotaInfos) {
|
|
280
334
|
const amount = buildAmount(quotaInfo);
|
|
281
|
-
const window = parseWindow(quotaInfo);
|
|
335
|
+
const window = parseWindow(quotaInfo, inferredDescriptors.get(quotaInfo));
|
|
282
336
|
if (window?.resetsAt) {
|
|
283
337
|
earliestReset = earliestReset ? Math.min(earliestReset, window.resetsAt) : window.resetsAt;
|
|
284
338
|
}
|