fix(coding-agent): preserved Codex quota identity
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed Codex reset fireworks comparing different quota tiers or plans, preventing false celebrations when usage reports switch between Spark and base weekly limits.
|
||||
- Fixed `/tan` agents being unable to read parent-session `local://` attachments by correctly resolving local protocol options against the parent session's artifacts.
|
||||
- Fixed Codex web search silently returning plain completions when the hosted web search tool was skipped.
|
||||
- Fixed TUI collaboration guest loader not starting when joining or reconnecting mid-turn.
|
||||
|
||||
@@ -28,8 +28,8 @@ type FireworkColor = keyof typeof FIREWORK_THEME_COLORS;
|
||||
export interface CodexResetUsageSnapshot {
|
||||
/** When this usage report was observed, if supplied by the provider. */
|
||||
observedAt?: number;
|
||||
/** Weekly usage and its previously scheduled reset deadline. */
|
||||
sevenDay?: { percent: number; resetsAt?: number };
|
||||
/** Weekly usage, its quota identity, and its previously scheduled reset deadline. */
|
||||
sevenDay?: { percent: number; resetsAt?: number; tier?: string; plan?: string };
|
||||
savedResets?: number;
|
||||
}
|
||||
|
||||
@@ -103,6 +103,9 @@ export function detectCodexResetFireworks(
|
||||
}
|
||||
|
||||
if (!previous.sevenDay || !current.sevenDay) return undefined;
|
||||
if (previous.sevenDay.tier !== current.sevenDay.tier || previous.sevenDay.plan !== current.sevenDay.plan) {
|
||||
return undefined;
|
||||
}
|
||||
const previousWeeklyPercent = Math.round(Math.max(0, Math.min(100, previous.sevenDay.percent)));
|
||||
const currentWeeklyPercent = Math.round(Math.max(0, Math.min(100, current.sevenDay.percent)));
|
||||
if (previousWeeklyPercent === 0 || currentWeeklyPercent >= previousWeeklyPercent) return undefined;
|
||||
|
||||
@@ -1319,6 +1319,10 @@ export class StatusLineComponent implements Component {
|
||||
}
|
||||
if (!matchingReport) return null;
|
||||
|
||||
const plan =
|
||||
typeof matchingReport.metadata?.planType === "string" && matchingReport.metadata.planType
|
||||
? matchingReport.metadata.planType
|
||||
: undefined;
|
||||
let sevenDay: CodexResetUsageSnapshot["sevenDay"];
|
||||
let sevenDayTier: string | undefined;
|
||||
for (const limit of matchingReport.limits) {
|
||||
@@ -1332,14 +1336,16 @@ export class StatusLineComponent implements Component {
|
||||
if (candidate.scope?.windowId !== "7d" || typeof fraction !== "number" || !Number.isFinite(fraction)) {
|
||||
continue;
|
||||
}
|
||||
const tier = candidate.scope.tier;
|
||||
const tier = typeof candidate.scope?.tier === "string" && candidate.scope.tier ? candidate.scope.tier : undefined;
|
||||
if (sevenDay && (sevenDayTier === undefined || tier)) continue;
|
||||
const resetsAt = candidate.window?.resetsAt;
|
||||
sevenDay = {
|
||||
percent: fraction * 100,
|
||||
resetsAt: typeof resetsAt === "number" && Number.isFinite(resetsAt) ? resetsAt : undefined,
|
||||
tier,
|
||||
plan,
|
||||
};
|
||||
sevenDayTier = tier || undefined;
|
||||
sevenDayTier = tier;
|
||||
}
|
||||
|
||||
const fetchedAt = matchingReport.fetchedAt;
|
||||
|
||||
@@ -63,6 +63,8 @@ interface CodexUsageState {
|
||||
sevenDayResetAt: number;
|
||||
savedResets?: number;
|
||||
omitFetchedAt?: boolean;
|
||||
tier?: string;
|
||||
plan?: string;
|
||||
}
|
||||
|
||||
function codexUsageReport(
|
||||
@@ -75,13 +77,23 @@ function codexUsageReport(
|
||||
{
|
||||
provider: "openai-codex",
|
||||
...(state.omitFetchedAt ? {} : { fetchedAt: Date.now() }),
|
||||
metadata: { accountId, email, ...(orgId ? { orgId } : {}) },
|
||||
metadata: {
|
||||
accountId,
|
||||
email,
|
||||
...(orgId ? { orgId } : {}),
|
||||
...(state.plan ? { planType: state.plan } : {}),
|
||||
},
|
||||
...(state.savedResets === undefined ? {} : { resetCredits: { availableCount: state.savedResets } }),
|
||||
limits: [
|
||||
{
|
||||
id: "openai-codex:secondary",
|
||||
label: "Codex 7 Day",
|
||||
scope: { provider: "openai-codex", accountId, windowId: "7d" },
|
||||
scope: {
|
||||
provider: "openai-codex",
|
||||
accountId,
|
||||
windowId: "7d",
|
||||
...(state.tier ? { tier: state.tier } : {}),
|
||||
},
|
||||
window: {
|
||||
id: "7d",
|
||||
label: "7d",
|
||||
@@ -330,6 +342,33 @@ describe("StatusLineComponent usage refresh", () => {
|
||||
component.dispose();
|
||||
});
|
||||
|
||||
it("compares weekly reset drops only within the same Codex quota tier", async () => {
|
||||
Settings.instance.set("tui.codexResetFireworks", true);
|
||||
const sevenDayResetAt = Date.now() + 80 * 3_600_000;
|
||||
let state: CodexUsageState = {
|
||||
sevenDayPercent: 42,
|
||||
sevenDayResetAt,
|
||||
savedResets: 0,
|
||||
tier: "spark",
|
||||
plan: "pro",
|
||||
};
|
||||
const component = new StatusLineComponent(makeCodexSession(async () => codexUsageReport(state)));
|
||||
const events: CodexResetFireworksEvent[] = [];
|
||||
component.setCodexResetFireworksHandler(event => events.push(event));
|
||||
|
||||
await refreshUsage(component);
|
||||
state = { ...state, sevenDayPercent: 2, tier: undefined };
|
||||
await refreshUsage(component, 5 * 60_000);
|
||||
expect(events).toEqual([]);
|
||||
|
||||
state = { ...state, sevenDayPercent: 42, tier: "spark" };
|
||||
await refreshUsage(component, 5 * 60_000);
|
||||
state = { ...state, sevenDayPercent: 2 };
|
||||
await refreshUsage(component, 5 * 60_000);
|
||||
expect(events).toEqual([{ kind: "unscheduled-weekly-reset" }]);
|
||||
component.dispose();
|
||||
});
|
||||
|
||||
it("binds each reset snapshot to the account identity used to normalize it", async () => {
|
||||
Settings.instance.set("tui.codexResetFireworks", true);
|
||||
const sevenDayResetAt = Date.now() + 80 * 3_600_000;
|
||||
|
||||
Reference in New Issue
Block a user