char-slop/berry

multipurpose self-modifiable agentic harness

git clone https://git.t4t.associates/char-slop/berry

Charlotte Somsubscription: add usage limits for opencode-goaa0b468

main
9.5 KiB260 linesraw
1import { assert, assertEquals } from "@std/assert";
2import { subscriptionUsage, usageWindows } from "./usage.ts";
3
4const token = (account: string) =>
5  `header.${
6    btoa(JSON.stringify({
7      "https://api.openai.com/auth": { chatgpt_account_id: account },
8    }))
9  }.signature`;
10const oauth = (apiKey = "secret") => ({ source: "OAuth", auth: { apiKey } });
11const claude = { five_hour: { utilization: 42, resets_at: "2026-04-01T12:00:00Z" } };
12
13Deno.test("subscription windows preserve zero usage, scoped limits, and unknown reset times", () => {
14  assertEquals(
15    usageWindows("anthropic", {
16      five_hour: { utilization: 0, resets_at: null },
17      seven_day: { utilization: 73.4, resets_at: "2026-04-02T00:00:00+00:00" },
18      seven_day_opus: null,
19      seven_day_sonnet: { utilization: "42", resets_at: "bad" },
20      limits: [
21        { percent: 12, resets_at: "bad", scope: { model: { display_name: "Fable" } } },
22        { percent: 90, is_active: false, scope: { model: { display_name: "Inactive" } } },
23        null,
24      ],
25    }),
26    [
27      { label: "5 hours", usedPercent: 0, resetsAt: null },
28      { label: "Weekly", usedPercent: 73.4, resetsAt: "2026-04-02T00:00:00.000Z" },
29      { label: "Weekly · Fable", usedPercent: 12, resetsAt: null },
30    ],
31  );
32  assertEquals(
33    usageWindows("openai-codex", {
34      rate_limit: {
35        primary_window: { used_percent: 90, reset_at: 1775044800, limit_window_seconds: 18000 },
36        secondary_window: { used_percent: 0, reset_at: null, limit_window_seconds: 604800 },
37      },
38      additional_rate_limits: [
39        { limit_name: "Spark", rate_limit: { primary_window: { used_percent: 15 } } },
40        { limit_name: "Invalid", rate_limit: { primary_window: { used_percent: -1 } } },
41        null,
42      ],
43    }),
44    [
45      { label: "5 hours", usedPercent: 90, resetsAt: "2026-04-01T12:00:00.000Z" },
46      { label: "7 days", usedPercent: 0, resetsAt: null },
47      { label: "Spark · Session", usedPercent: 15, resetsAt: null },
48    ],
49  );
50  for (const invalid of [null, [], 42, {}, { rate_limit: "bad" }]) {
51    assertEquals(usageWindows("openai", invalid), []);
52  }
53});
54
55Deno.test("usage requests are coalesced, cached, and authenticated only at the provider endpoint", async () => {
56  let now = 1775044800000;
57  let requests = 0;
58  const gate = Promise.withResolvers<void>();
59  const usage = subscriptionUsage({
60    now: () => now,
61    auth: () => Promise.resolve(oauth()),
62    fetch: async (url, init) => {
63      requests++;
64      assertEquals(url, "https://api.anthropic.com/api/oauth/usage");
65      const headers = new Headers(init?.headers);
66      assertEquals(headers.get("authorization"), "Bearer secret");
67      assertEquals(headers.get("anthropic-beta"), "oauth-2025-04-20");
68      assertEquals(init?.redirect, "error");
69      assert(init?.signal);
70      await gate.promise;
71      return Response.json({ ...claude, account_id: "private", other_secret: "private" });
72    },
73  });
74  const first = usage("anthropic");
75  const second = usage("anthropic");
76  assertEquals(first, second);
77  gate.resolve();
78  const result = await first;
79  assertEquals(result, {
80    status: "ok",
81    fetchedAt: "2026-04-01T12:00:00.000Z",
82    windows: [{ label: "5 hours", usedPercent: 42, resetsAt: "2026-04-01T12:00:00.000Z" }],
83  });
84  assertEquals(await usage("anthropic"), result);
85  assertEquals(requests, 1);
86  now += 61_000;
87  await usage("anthropic");
88  assertEquals(requests, 2);
89});
90
91Deno.test("ChatGPT OAuth and legacy Codex send the selected account and invalidate cache after login changes", async () => {
92  let account = "account-one";
93  const accounts: string[] = [];
94  const usage = subscriptionUsage({
95    auth: () => Promise.resolve(oauth(token(account))),
96    fetch: (url, init) => {
97      assertEquals(url, "https://chatgpt.com/backend-api/wham/usage");
98      const headers = new Headers(init?.headers);
99      accounts.push(headers.get("ChatGPT-Account-Id")!);
100      assertEquals(headers.get("authorization"), `Bearer ${token(account)}`);
101      return Promise.resolve(
102        Response.json({ rate_limit: { primary_window: { used_percent: 5 } } }),
103      );
104    },
105  });
106  await usage("openai");
107  await usage("openai-codex");
108  await usage("openai");
109  account = "account-two";
110  await usage("openai");
111  assertEquals(accounts, ["account-one", "account-one", "account-two"]);
112});
113
114Deno.test("OpenCode Go API keys load all allowance windows and are isolated from OAuth providers", async () => {
115  const now = Date.parse("2026-04-01T12:00:00Z");
116  let key: string | undefined = "go-key";
117  const keys: string[] = [];
118  const usage = subscriptionUsage({
119    now: () => now,
120    auth: (provider) => {
121      assertEquals(provider, "opencode-go");
122      return Promise.resolve(
123        key ? { source: "stored credential", auth: { apiKey: key } } : undefined,
124      );
125    },
126    fetch: (url, init) => {
127      assertEquals(url, "https://opencode.ai/inference/go/v1/usage");
128      const headers = new Headers(init?.headers);
129      keys.push(headers.get("authorization")!);
130      assertEquals(headers.get("ChatGPT-Account-Id"), null);
131      assertEquals(headers.get("anthropic-beta"), null);
132      assertEquals(init?.redirect, "error");
133      return Promise.resolve(Response.json({
134        usage: {
135          rolling: { status: "ok", percent: 0, resetsAt: "2026-04-01T17:00:00Z" },
136          weekly: { status: "ok", percent: 25.5, resetsAt: "2026-04-08T12:00:00Z" },
137          monthly: { status: "rate-limited", percent: 100, resetsAt: "2026-05-01T12:00:00Z" },
138        },
139      }));
140    },
141  });
142  const result = await usage("opencode-go");
143  assertEquals(result, {
144    status: "ok",
145    fetchedAt: "2026-04-01T12:00:00.000Z",
146    windows: [
147      { label: "5 hours", usedPercent: 0, resetsAt: "2026-04-01T17:00:00.000Z" },
148      { label: "Weekly", usedPercent: 25.5, resetsAt: "2026-04-08T12:00:00.000Z" },
149      { label: "Monthly", usedPercent: 100, resetsAt: "2026-05-01T12:00:00.000Z" },
150    ],
151  });
152  assertEquals(await usage("opencode-go"), result);
153  key = "replacement-key";
154  await usage("opencode-go");
155  key = undefined;
156  assertEquals((await usage("opencode-go")).status, "unavailable");
157  assertEquals(keys, ["Bearer go-key", "Bearer replacement-key"]);
158});
159
160Deno.test("Go preserves legacy relative resets and skips malformed windows without losing valid ones", () => {
161  assertEquals(
162    usageWindows("opencode-go", {
163      rollingUsage: { usagePercent: 12, resetInSec: 1800 },
164      weeklyUsage: { usagePercent: 30, resetInSec: null },
165      monthlyUsage: { usagePercent: "wrong", resetInSec: 100 },
166    }, Date.parse("2026-04-01T12:00:00Z")),
167    [
168      { label: "5 hours", usedPercent: 12, resetsAt: "2026-04-01T12:30:00.000Z" },
169      { label: "Weekly", usedPercent: 30, resetsAt: null },
170    ],
171  );
172  assertEquals(
173    usageWindows("opencode-go", {
174      usage: {
175        rolling: { percent: -1, resetsAt: null },
176        weekly: { percent: 20, resetsAt: "bad" },
177        monthly: null,
178      },
179    }),
180    [{ label: "Weekly", usedPercent: 20, resetsAt: null }],
181  );
182});
183
184Deno.test("Claude API keys and missing logins never go to the subscription endpoint", async () => {
185  for (
186    const resolved of [undefined, { source: "stored credential", auth: { apiKey: "api-key" } }]
187  ) {
188    const usage = subscriptionUsage({
189      auth: () => Promise.resolve(resolved),
190      fetch: () => {
191        throw new Error("must not request usage");
192      },
193    });
194    assertEquals((await usage("anthropic")).status, "unavailable");
195  }
196});
197
198Deno.test("rate limits honor Retry-After and provider errors never expose response bodies or tokens", async () => {
199  let now = 1775044800000;
200  let requests = 0;
201  const usage = subscriptionUsage({
202    now: () => now,
203    auth: () => Promise.resolve(oauth()),
204    fetch: () => {
205      requests++;
206      return Promise.resolve(
207        new Response("secret upstream body", {
208          status: 429,
209          headers: { "retry-after": "600" },
210        }),
211      );
212    },
213  });
214  const result = await usage("anthropic");
215  assertEquals(result.status, "error");
216  assert(!JSON.stringify(result).includes("secret"));
217  now += 301_000;
218  await usage("anthropic");
219  assertEquals(requests, 1);
220  now += 300_000;
221  await usage("anthropic");
222  assertEquals(requests, 2);
223  const failed = subscriptionUsage({
224    auth: () => Promise.resolve(oauth()),
225    fetch: () => Promise.resolve(new Response("secret", { status: 500 })),
226  });
227  const error = await failed("anthropic");
228  assertEquals(error.status, "error");
229  assert(!JSON.stringify(error).includes("secret"));
230  const refreshFailure = subscriptionUsage({
231    auth: () => Promise.reject(new Error("secret refresh error")),
232  });
233  assert(!JSON.stringify(await refreshFailure("anthropic")).includes("secret"));
234});
235
236Deno.test("malformed account tokens, usage JSON, and reset dates fail without losing valid windows", async () => {
237  for (const apiKey of ["not-a-jwt", `header.${btoa("{}")}.signature`]) {
238    let requested = false;
239    const usage = subscriptionUsage({
240      auth: () => Promise.resolve(oauth(apiKey)),
241      fetch: () => {
242        requested = true;
243        return Promise.resolve(Response.json({}));
244      },
245    });
246    assertEquals((await usage("openai")).status, "error");
247    assertEquals(requested, false);
248  }
249  const malformed = subscriptionUsage({
250    auth: () => Promise.resolve(oauth()),
251    fetch: () => Promise.resolve(new Response("not json")),
252  });
253  assertEquals((await malformed("anthropic")).status, "error");
254  assertEquals(
255    usageWindows("openai", {
256      rate_limit: { primary_window: { used_percent: 10, reset_at: 1e50 } },
257    }),
258    [{ label: "Session", usedPercent: 10, resetsAt: null }],
259  );
260});