Skip to content

Commit 5a55350

Browse files
committed
fix(provider-usage): hide stale provider usage
- treat snapshots older than 24 hours as expired - pass current time from chat view and composer
1 parent 56dce6a commit 5a55350

4 files changed

Lines changed: 72 additions & 1 deletion

File tree

apps/web/src/components/ChatView.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,10 @@ export default function ChatView({
13651365
const selectedProvider: ProviderKind = lockedProvider ?? unlockedSelectedProvider;
13661366
const activeProviderUsage = useMemo(
13671367
() =>
1368-
deriveLatestProviderUsageSnapshot(providerUsageActivities, { provider: selectedProvider }),
1368+
deriveLatestProviderUsageSnapshot(providerUsageActivities, {
1369+
provider: selectedProvider,
1370+
now: Date.now(),
1371+
}),
13691372
[providerUsageActivities, selectedProvider],
13701373
);
13711374
const activeTimelineProvider: ProviderKind =

apps/web/src/components/chat/ChatComposer.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,7 @@ export const ChatComposer = memo(
659659
() =>
660660
deriveLatestProviderUsageSnapshot(activeThreadActivities ?? [], {
661661
provider: selectedProvider,
662+
now: Date.now(),
662663
}),
663664
[activeThreadActivities, selectedProvider],
664665
);

apps/web/src/lib/providerUsage.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,60 @@ describe("providerUsage", () => {
275275
expect(snapshot).toBeNull();
276276
});
277277

278+
it("returns null when the latest provider usage update is one day old", () => {
279+
const snapshot = deriveLatestProviderUsageSnapshot(
280+
[
281+
makeActivity(
282+
"activity-1",
283+
{
284+
rateLimits: {
285+
limitId: "codex",
286+
primary: {
287+
usedPercent: 12,
288+
windowDurationMins: 300,
289+
resetsAt: 1776587601,
290+
},
291+
},
292+
},
293+
"2026-03-23T00:00:00.000Z",
294+
),
295+
],
296+
{
297+
provider: "codex",
298+
now: new Date("2026-03-24T00:00:00.000Z"),
299+
},
300+
);
301+
302+
expect(snapshot).toBeNull();
303+
});
304+
305+
it("keeps provider usage visible before it is one day old", () => {
306+
const snapshot = deriveLatestProviderUsageSnapshot(
307+
[
308+
makeActivity(
309+
"activity-1",
310+
{
311+
rateLimits: {
312+
limitId: "codex",
313+
primary: {
314+
usedPercent: 12,
315+
windowDurationMins: 300,
316+
resetsAt: 1776587601,
317+
},
318+
},
319+
},
320+
"2026-03-23T00:00:00.000Z",
321+
),
322+
],
323+
{
324+
provider: "codex",
325+
now: new Date("2026-03-23T23:59:59.999Z"),
326+
},
327+
);
328+
329+
expect(snapshot?.providerLabel).toBe("Codex");
330+
});
331+
278332
it("returns null for cursor provider even when Claude/Codex events are present", () => {
279333
const snapshot = deriveLatestProviderUsageSnapshot(
280334
[

apps/web/src/lib/providerUsage.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export interface ProviderUsageSnapshot {
3434

3535
type ProviderUsageDerivationOptions = {
3636
readonly provider?: ProviderKind | null;
37+
readonly now?: Date | number;
3738
};
3839

3940
const PROVIDER_LABEL_BY_KIND: Record<ProviderKind, string | null> = {
@@ -42,6 +43,7 @@ const PROVIDER_LABEL_BY_KIND: Record<ProviderKind, string | null> = {
4243
cursor: null,
4344
opencode: null,
4445
};
46+
const PROVIDER_USAGE_MAX_AGE_MS = 24 * 60 * 60 * 1000;
4547

4648
// ---------------------------------------------------------------------------
4749
// Claude rate_limit_event normalization
@@ -335,6 +337,17 @@ export function deriveLatestProviderUsageSnapshot(
335337
return null;
336338
}
337339

340+
const latestUpdatedAtMs = Date.parse(latestUpdatedAt);
341+
const nowMs = options.now instanceof Date ? options.now.getTime() : options.now;
342+
if (
343+
nowMs !== undefined &&
344+
Number.isFinite(latestUpdatedAtMs) &&
345+
Number.isFinite(nowMs) &&
346+
nowMs - latestUpdatedAtMs >= PROVIDER_USAGE_MAX_AGE_MS
347+
) {
348+
return null;
349+
}
350+
338351
const windows = Array.from(windowsByLabel.values());
339352

340353
return {

0 commit comments

Comments
 (0)