| 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; |
| 3 | |
| 4 | import { agentStatus, budgetBlock, chargedMicros, costMicros, dayKey, monthKey, personBlock, personLimit, replyCapMicros, spendSpan, totalTokens } from "./budget.ts"; |
| 5 | |
| 6 | const OCT_8 = new Date("2026-10-08T15:00:00Z"); |
| 7 | const none = { monthly_micros: null, daily_micros: null, task_micros: null }; |
| 8 | |
| 9 | test("spend rolls up by UTC month and day", () => { |
| 10 | assert.equal(monthKey(OCT_8), "2026-10"); |
| 11 | assert.equal(dayKey(OCT_8), "2026-10-08"); |
| 12 | assert.equal(dayKey(new Date("2026-10-31T23:59:59Z")), "2026-10-31"); |
| 13 | }); |
| 14 | |
| 15 | test("a breakdown's span: this month by default, last month whole, or the last 7 or 30 days", () => { |
| 16 | assert.deepEqual(spendSpan(null, OCT_8), { span: "month", from: "2026-10-01", until: "2026-10-08", period: "2026-10" }); |
| 17 | assert.deepEqual(spendSpan("nonsense", OCT_8), spendSpan("month", OCT_8)); |
| 18 | assert.deepEqual(spendSpan("last_month", OCT_8), { span: "last_month", from: "2026-09-01", until: "2026-09-30", period: "2026-09" }); |
| 19 | assert.deepEqual(spendSpan("last_month", new Date("2026-01-15T00:00:00Z")), { span: "last_month", from: "2025-12-01", until: "2025-12-31", period: "2025-12" }); |
| 20 | assert.deepEqual(spendSpan("7d", OCT_8), { span: "7d", from: "2026-10-02", until: "2026-10-08", period: "2026-10" }); |
| 21 | assert.deepEqual(spendSpan("30d", OCT_8), { span: "30d", from: "2026-09-09", until: "2026-10-08", period: "2026-10" }); |
| 22 | }); |
| 23 | |
| 24 | test("a person's own budget wins over the default; 0 of their own is no budget at all", () => { |
| 25 | assert.equal(personLimit(null, null), null); |
| 26 | assert.equal(personLimit(20_000_000, null), 20_000_000); |
| 27 | assert.equal(personLimit(20_000_000, 50_000_000), 50_000_000); |
| 28 | assert.equal(personLimit(20_000_000, 0), null); |
| 29 | assert.equal(personLimit(0, null), null); |
| 30 | }); |
| 31 | |
| 32 | test("a person's budget blocks at 100%, naming them and where it is raised", () => { |
| 33 | assert.equal(personBlock("ana", null, 9e9, OCT_8), null); |
| 34 | assert.equal(personBlock("ana", 10_000_000, 9_999_999, OCT_8), null); |
| 35 | assert.equal( |
| 36 | personBlock("ana", 10_000_000, 10_000_000, OCT_8), |
| 37 | "@ana has used their agent budget for October. An owner can raise it under Workspace → Spend.", |
| 38 | ); |
| 39 | }); |
| 40 | |
| 41 | test("no caps, no block; a cap of zero is no cap", () => { |
| 42 | assert.equal(budgetBlock(none, { month: 9e9, day: 9e9 }, OCT_8), null); |
| 43 | assert.equal(budgetBlock({ ...none, monthly_micros: 0 }, { month: 9e9, day: 0 }, OCT_8), null); |
| 44 | }); |
| 45 | |
| 46 | test("the monthly cap blocks at 100%, and says so in plain words", () => { |
| 47 | const budget = { ...none, monthly_micros: 5_000_000 }; |
| 48 | assert.equal(budgetBlock(budget, { month: 4_999_999, day: 0 }, OCT_8), null); |
| 49 | const blocked = budgetBlock(budget, { month: 5_000_000, day: 0 }, OCT_8); |
| 50 | assert.equal(blocked?.cap, "month"); |
| 51 | assert.equal(blocked?.message, "I'm out of budget for October. An owner can raise my monthly limit on my profile."); |
| 52 | }); |
| 53 | |
| 54 | test("the daily cap blocks too, after the monthly one is checked", () => { |
| 55 | const budget = { ...none, monthly_micros: 5_000_000, daily_micros: 1_000_000 }; |
| 56 | assert.equal(budgetBlock(budget, { month: 2_000_000, day: 1_000_000 }, OCT_8)?.cap, "day"); |
| 57 | assert.equal(budgetBlock(budget, { month: 5_000_000, day: 1_000_000 }, OCT_8)?.cap, "month"); |
| 58 | }); |
| 59 | |
| 60 | test("a reply's cap is the lowest of what is left and the per-task and plan caps", () => { |
| 61 | assert.equal(replyCapMicros(none, { month: 0, day: 0 }, null), null); |
| 62 | assert.equal(replyCapMicros({ ...none, monthly_micros: 1_000_000 }, { month: 900_000, day: 0 }, null), 100_000); |
| 63 | assert.equal(replyCapMicros({ ...none, monthly_micros: 1_000_000, task_micros: 50_000 }, { month: 0, day: 0 }, 2_000_000), 50_000); |
| 64 | assert.equal(replyCapMicros(none, { month: 0, day: 0 }, 30_000), 30_000, "the plan's per-run cap"); |
| 65 | assert.equal(replyCapMicros({ ...none, daily_micros: 10 }, { month: 0, day: 50 }, null), 1, "never read as no cap"); |
| 66 | }); |
| 67 | |
| 68 | test("cost is tokens at the provider's price per million, rounded up to a micro-dollar", () => { |
| 69 | const price = { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 }; |
| 70 | const tokens = { input: 2_000, output: 300, cacheRead: 1_000, cacheWrite: 0 }; |
| 71 | // 2000*0.1 + 300*0.5 + 1000*0.01 = 200 + 150 + 10 |
| 72 | assert.equal(costMicros(tokens, price), 360); |
| 73 | assert.equal(costMicros(tokens, null), 0, "an unpriced model costs g1t nothing here"); |
| 74 | assert.equal(totalTokens(tokens), 3_300); |
| 75 | }); |
| 76 | |
| 77 | test("what a reply counts: the model with its margin on g1t's models, the agent rate always", () => { |
| 78 | // $0.25 per million tokens is 250,000 micros per million. |
| 79 | assert.equal(chargedMicros({ costMicros: 1_000, hosted: true, marginPercent: 0, ratePerMillionMicros: 250_000, tokens: 4_000 }), 2_000); |
| 80 | assert.equal(chargedMicros({ costMicros: 1_000, hosted: true, marginPercent: 20, ratePerMillionMicros: 0, tokens: 4_000 }), 1_200); |
| 81 | assert.equal(chargedMicros({ costMicros: 1_000, hosted: false, marginPercent: 20, ratePerMillionMicros: 250_000, tokens: 4_000 }), 1_000, "own provider: the agent rate only"); |
| 82 | }); |
| 83 | |
| 84 | test("status: working while a reply is in flight, out of budget when capped, else idle", () => { |
| 85 | const later = new Date(OCT_8.getTime() + 60_000).toISOString(); |
| 86 | const earlier = new Date(OCT_8.getTime() - 60_000).toISOString(); |
| 87 | assert.equal(agentStatus({ busyUntil: later, now: OCT_8, blocked: true }), "working"); |
| 88 | assert.equal(agentStatus({ busyUntil: earlier, now: OCT_8, blocked: false }), "idle", "a desk that died is not working forever"); |
| 89 | assert.equal(agentStatus({ busyUntil: null, now: OCT_8, blocked: true }), "out_of_budget"); |
| 90 | }); |