fix(quota): match the Claude Code integration provider to Claude quota
The opencode-claude integration registers its provider as `claude-code`, which never matched the `claude` quota provider, so the collapsed Usage section in the work status panel showed no limit for a model from that integration. Claude windows also reported no duration, leaving the headline to fall back to whichever row came first instead of the limit that runs out soonest. The session and weekly windows now carry their length; extra usage stays without one because it is a monthly spend cap.
This commit is contained in:
@@ -16,6 +16,11 @@ const SESSION_WINDOW = '5h';
|
||||
const WEEKLY_WINDOW = '7d';
|
||||
const EXTRA_USAGE_WINDOW = 'extra_usage';
|
||||
|
||||
// Consumers rank limits by how soon they run out, so each window carries its
|
||||
// duration. Extra usage is a monthly spend cap, not a rolling window.
|
||||
const SESSION_WINDOW_SECONDS = 5 * 60 * 60;
|
||||
const WEEKLY_WINDOW_SECONDS = 7 * 24 * 60 * 60;
|
||||
|
||||
const asArray = (value) => (Array.isArray(value) ? value : []);
|
||||
|
||||
/** Money in Anthropic's minor-unit form, e.g. `{ amount_minor: 10000, exponent: 2 }`. */
|
||||
@@ -35,9 +40,9 @@ const formatSpendLabel = (used, limit, currency) => {
|
||||
return limitLabel === null ? `${prefix}${usedLabel}` : `${prefix}${usedLabel} / ${prefix}${limitLabel}`;
|
||||
};
|
||||
|
||||
const addWindow = (target, key, { percent, resetAt, valueLabel }) => {
|
||||
const addWindow = (target, key, { percent, resetAt, valueLabel, windowSeconds = null }) => {
|
||||
if (percent === null && !valueLabel) return;
|
||||
target[key] = toUsageWindow({ usedPercent: percent, windowSeconds: null, resetAt, valueLabel });
|
||||
target[key] = toUsageWindow({ usedPercent: percent, windowSeconds, resetAt, valueLabel });
|
||||
};
|
||||
|
||||
const applyLimitsArray = (limits, windows, models) => {
|
||||
@@ -49,16 +54,16 @@ const applyLimitsArray = (limits, windows, models) => {
|
||||
const modelName = asNonEmptyString(asObject(asObject(limit.scope)?.model)?.display_name);
|
||||
|
||||
if (limit.kind === 'session') {
|
||||
addWindow(windows, SESSION_WINDOW, { percent, resetAt });
|
||||
addWindow(windows, SESSION_WINDOW, { percent, resetAt, windowSeconds: SESSION_WINDOW_SECONDS });
|
||||
continue;
|
||||
}
|
||||
if (limit.kind === 'weekly_all') {
|
||||
addWindow(windows, WEEKLY_WINDOW, { percent, resetAt });
|
||||
addWindow(windows, WEEKLY_WINDOW, { percent, resetAt, windowSeconds: WEEKLY_WINDOW_SECONDS });
|
||||
continue;
|
||||
}
|
||||
if (limit.kind === 'weekly_scoped' && modelName) {
|
||||
const modelWindows = {};
|
||||
addWindow(modelWindows, WEEKLY_WINDOW, { percent, resetAt });
|
||||
addWindow(modelWindows, WEEKLY_WINDOW, { percent, resetAt, windowSeconds: WEEKLY_WINDOW_SECONDS });
|
||||
if (Object.keys(modelWindows).length > 0) models[modelName] = { windows: modelWindows };
|
||||
}
|
||||
}
|
||||
@@ -70,13 +75,15 @@ const applyLegacyFields = (payload, windows) => {
|
||||
if (fiveHour) {
|
||||
addWindow(windows, SESSION_WINDOW, {
|
||||
percent: toNumber(fiveHour.utilization),
|
||||
resetAt: toTimestamp(fiveHour.resets_at)
|
||||
resetAt: toTimestamp(fiveHour.resets_at),
|
||||
windowSeconds: SESSION_WINDOW_SECONDS
|
||||
});
|
||||
}
|
||||
if (sevenDay) {
|
||||
addWindow(windows, WEEKLY_WINDOW, {
|
||||
percent: toNumber(sevenDay.utilization),
|
||||
resetAt: toTimestamp(sevenDay.resets_at)
|
||||
resetAt: toTimestamp(sevenDay.resets_at),
|
||||
windowSeconds: WEEKLY_WINDOW_SECONDS
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -39,6 +39,15 @@ describe('Claude usage transforms', () => {
|
||||
expect(models.Fable.windows['7d'].usedPercent).toBe(12);
|
||||
});
|
||||
|
||||
it('reports each window duration so callers can rank limits by urgency', () => {
|
||||
const { windows, models } = toClaudeUsage(LIVE_PAYLOAD);
|
||||
|
||||
expect(windows['5h'].windowSeconds).toBe(5 * 60 * 60);
|
||||
expect(windows['7d'].windowSeconds).toBe(7 * 24 * 60 * 60);
|
||||
expect(models.Fable.windows['7d'].windowSeconds).toBe(7 * 24 * 60 * 60);
|
||||
expect(windows.extra_usage.windowSeconds).toBeNull();
|
||||
});
|
||||
|
||||
it('reports extra usage as a spend window with a money label', () => {
|
||||
const { windows } = toClaudeUsage(LIVE_PAYLOAD);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user