mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-07 00:44:49 +00:00
fix(usage): complete enterprise spending percentages
Derive missing remaining percentages so CLI spending output matches the Usage card. Preserve explicitly reported percentages and cover missing currency and absent rolling windows. Co-authored-by: Matt Cowger <matt@cowger.us> Co-authored-by: JasprW <wang@jaspr.me>
This commit is contained in:
co-authored by
Matt Cowger
JasprW
parent
c9b03eb309
commit
f56a1add91
@@ -162,7 +162,7 @@ describe("claude usage source", () => {
|
||||
expect.objectContaining({ signal: expect.any(AbortSignal) }),
|
||||
);
|
||||
});
|
||||
it("reports USD extra usage monthly limit and used credits in dollars", async () => {
|
||||
it.each([false, true])("reports USD extra usage with rolling windows %j", async (hasWindows) => {
|
||||
writeClaudeCredentials(claudeHome, "at_valid");
|
||||
fetchApi = mockFetch(
|
||||
new Map([
|
||||
@@ -170,7 +170,7 @@ describe("claude usage source", () => {
|
||||
"https://api.anthropic.com/api/oauth/usage",
|
||||
() =>
|
||||
jsonResponse({
|
||||
...makeClaudeResponse(),
|
||||
...(hasWindows ? makeClaudeResponse() : {}),
|
||||
extra_usage: {
|
||||
is_enabled: true,
|
||||
monthly_limit: 5000,
|
||||
@@ -198,25 +198,28 @@ describe("claude usage source", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("does not report extra usage balances without explicit USD currency", async () => {
|
||||
writeClaudeCredentials(claudeHome, "at_valid");
|
||||
fetchApi = mockFetch(
|
||||
new Map([
|
||||
[
|
||||
"https://api.anthropic.com/api/oauth/usage",
|
||||
() =>
|
||||
jsonResponse({
|
||||
...makeClaudeResponse(),
|
||||
extra_usage: { monthly_limit: 5000, used_credits: 1250, currency: "EUR" },
|
||||
}),
|
||||
],
|
||||
]),
|
||||
);
|
||||
it.each(["EUR", null, undefined])(
|
||||
"does not report extra usage balances for currency %j",
|
||||
async (currency) => {
|
||||
writeClaudeCredentials(claudeHome, "at_valid");
|
||||
fetchApi = mockFetch(
|
||||
new Map([
|
||||
[
|
||||
"https://api.anthropic.com/api/oauth/usage",
|
||||
() =>
|
||||
jsonResponse({
|
||||
...makeClaudeResponse(),
|
||||
extra_usage: { monthly_limit: 5000, used_credits: 1250, currency },
|
||||
}),
|
||||
],
|
||||
]),
|
||||
);
|
||||
|
||||
const claude = findProvider(await service().listUsage(), "claude");
|
||||
const claude = findProvider(await service().listUsage(), "claude");
|
||||
|
||||
expect(claude.balances).toEqual([]);
|
||||
});
|
||||
expect(claude.balances).toEqual([]);
|
||||
},
|
||||
);
|
||||
|
||||
it("accepts a null Claude resets_at when a window has no scheduled reset", async () => {
|
||||
writeClaudeCredentials(claudeHome, "at_valid");
|
||||
|
||||
@@ -142,6 +142,24 @@ test("reports enterprise individual spend limit percentage and reset", async ()
|
||||
});
|
||||
});
|
||||
|
||||
test.each([
|
||||
[{ used_percent: 5 }, 5, 95],
|
||||
[{ remaining_percent: 95 }, 5, 95],
|
||||
[{ used_percent: 5, remaining_percent: 90 }, 5, 90],
|
||||
[{ used_percent: 110 }, 110, 0],
|
||||
])(
|
||||
"completes individual spending percentages for %j",
|
||||
async (individual_limit, usedPct, remainingPct) => {
|
||||
const report = await fetchUsage(authInput(fixtureHome), async () =>
|
||||
Response.json({ spend_control: { individual_limit } }),
|
||||
);
|
||||
expect(report).toMatchObject({
|
||||
status: "available",
|
||||
windows: [expect.objectContaining({ id: "individual_limit", usedPct, remainingPct })],
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test("omits individual spend limit without a percentage", async () => {
|
||||
const report = await fetchUsage(authInput(fixtureHome), async () =>
|
||||
Response.json({ spend_control: { individual_limit: { reset_at: 1795996800 } } }),
|
||||
|
||||
@@ -243,14 +243,14 @@ export async function fetchUsage(
|
||||
const usedPct =
|
||||
limit.used_percent ??
|
||||
(limit.remaining_percent != null ? 100 - limit.remaining_percent : undefined);
|
||||
if (usedPct === undefined && limit.remaining_percent == null) return [];
|
||||
if (usedPct === undefined) return [];
|
||||
return [
|
||||
{
|
||||
id: "individual_limit",
|
||||
label: "Individual spend limit",
|
||||
summary: true,
|
||||
usedPct,
|
||||
remainingPct: limit.remaining_percent,
|
||||
remainingPct: limit.remaining_percent ?? Math.max(0, 100 - usedPct),
|
||||
resetsAt:
|
||||
limit.reset_at != null ? new Date(limit.reset_at * 1000).toISOString() : null,
|
||||
tone: toneFromUsedPct(usedPct),
|
||||
|
||||
Reference in New Issue
Block a user