Skip to content

Commit c3f5e36

Browse files
authored
fix(server): avoid replaying stale Codex usage limits (#26331)
1 parent cfc8be9 commit c3f5e36

3 files changed

Lines changed: 38 additions & 3 deletions

File tree

‎apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4304,7 +4304,7 @@ export const makeCodexAdapterV2 = Effect.fn("makeCodexAdapterV2")(function* (
43044304

43054305
yield* client.handleServerNotification("account/rateLimits/updated", (payload) =>
43064306
Effect.gen(function* () {
4307-
yield* Ref.update(rateLimitSnapshot, (previous) =>
4307+
const previous = yield* Ref.getAndUpdate(rateLimitSnapshot, (previous) =>
43084308
mergeCodexRateLimits(previous, payload.rateLimits),
43094309
);
43104310
const resetAt = codexUsageLimitResetAt(yield* Ref.get(rateLimitSnapshot));
@@ -4324,7 +4324,7 @@ export const makeCodexAdapterV2 = Effect.fn("makeCodexAdapterV2")(function* (
43244324
turnItem: updated,
43254325
});
43264326
}
4327-
const update = codexRateLimitsToUpdate(payload.rateLimits);
4327+
const update = codexRateLimitsToUpdate(payload.rateLimits, previous);
43284328
if (update && adapterOptions.onUsageLimits) {
43294329
const checkedAt = DateTime.formatIso(yield* DateTime.now);
43304330
yield* adapterOptions.onUsageLimits({ ...update, checkedAt });

‎apps/server/src/provider/codexUsageLimits.test.ts‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,29 @@ describe("codexRateLimitsToLimits", () => {
128128
});
129129

130130
describe("codexRateLimitsToUpdate", () => {
131+
it("does not republish cached windows over a newer account probe", () => {
132+
const cached = {
133+
primary: { usedPercent: 0, resetsAt: 1_784_000_000, windowDurationMins: 300 },
134+
secondary: { usedPercent: 20, resetsAt: 1_784_500_000, windowDurationMins: 10080 },
135+
};
136+
expect(codexRateLimitsToUpdate(cached)?.windows).toHaveLength(2);
137+
expect(codexRateLimitsToUpdate(structuredClone(cached), cached)).toBeUndefined();
138+
139+
const changed = { ...cached, secondary: { ...cached.secondary, usedPercent: 21 } };
140+
expect(codexRateLimitsToUpdate(changed, cached)?.windows.map((window) => window.id)).toEqual([
141+
"secondary",
142+
]);
143+
expect(codexRateLimitsToUpdate({ primary: cached.primary }, cached)).toBeUndefined();
144+
expect(
145+
codexRateLimitsToUpdate({ primary: { ...cached.primary, resetsAt: 1_784_001_000 } }, cached)
146+
?.windows,
147+
).toHaveLength(1);
148+
expect(
149+
codexRateLimitsToUpdate({ primary: { ...cached.primary, usedPercent: 76 } }, cached)
150+
?.windows[0]?.usedPercent,
151+
).toBe(76);
152+
});
153+
131154
it("carries only the windows the notification names", () => {
132155
expect(
133156
codexRateLimitsToUpdate({

‎apps/server/src/provider/codexUsageLimits.ts‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,20 @@ export function codexRateLimitsToLimits(input: {
135135

136136
export function codexRateLimitsToUpdate(
137137
snapshot: CodexRateLimitSnapshot,
138+
previous?: CodexRateLimitSnapshot,
138139
): ProviderUsageLimitsUpdate | undefined {
139-
const windows = codexRateLimitsToWindows(snapshot);
140+
const previousWindows = previous ? codexRateLimitsToWindows(previous) : [];
141+
// Token ticks repeat session-cached limits that may predate an account probe or reset.
142+
const windows = codexRateLimitsToWindows(snapshot).filter((window) => {
143+
const existing = previousWindows.find((candidate) => candidate.id === window.id);
144+
return (
145+
!existing ||
146+
existing.kind !== window.kind ||
147+
existing.usedPercent !== window.usedPercent ||
148+
existing.resetsAt !== window.resetsAt ||
149+
existing.windowDurationMins !== window.windowDurationMins
150+
);
151+
});
140152
return windows.length > 0 ? { windows } : undefined;
141153
}
142154

0 commit comments

Comments
 (0)