feat(credits): port computeCreditsDeductedCents from open-agents (step 2/6)#611
feat(credits): port computeCreditsDeductedCents from open-agents (step 2/6)#611sweetmantech wants to merge 1 commit into
Conversation
…ost from open-agents
First piece of the chat-workflow billing path. Ports the per-turn cost
math from open-agents' `apps/web/lib/credits/compute-credits-deducted-cents.ts`
and `apps/web/lib/models.ts:estimateModelUsageCost` so the same billing
logic runs on both sides during the cutover.
Resolution order matches open-agents exactly:
1. gateway-reported cost on responseMessage.metadata.totalMessageCost
(the same number the chat UI shows next to the response)
2. token-based estimate against the model catalog's cost entry
3. 1c floor when no pricing is available — so a successful turn
never lands as a free run
Three new files (per api's one-exported-function-per-file SRP):
- AvailableModelCost.ts — shape mirroring open-agents' richer cost
type (input, output, cache_read, context_over_200k) so the same
estimator runs against either catalog
- estimateModelUsageCost.ts — token-based USD estimator including
the 200k+ context tier swap and cache_read pricing
- computeCreditsDeductedCents.ts — top-level orchestrator (gateway
cost → token estimate → 1c floor) using api's getAvailableModels
directly (no HTTP self-fetch like open-agents does)
Test coverage: 27 new unit tests across the two test files. All pricing
edge cases covered (NaN/Infinity/negative gateway cost, cached-tokens-
exceeding-input clamping, context_over_200k tier swap with partial
overrides, catalog miss / fetch failure fallbacks).
Unblocks step 3 (deductCreditsWithAudit TS wrapper) of the chat credits
gap in #605.
Full suite: 3191 → 3205 passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Your plan includes 1 review of capacity. Refill in 46 seconds. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more review capacity refills, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (3)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
2 issues found across 5 files
Confidence score: 4/5
- This PR looks safe to merge with low functional risk, since both findings are test-organization/style issues rather than runtime logic defects.
- The most severe issue is in
lib/credits/__tests__/computeCreditsDeductedCents.test.ts(6/10): exceeding the 100-line limit and mixing concerns can make tests harder to maintain and debug over time. lib/credits/__tests__/estimateModelUsageCost.test.tshas a similar but lower-severity length violation (3/10), which is mainly a housekeeping concern and not likely to cause regression by itself.- Pay close attention to
lib/credits/__tests__/computeCreditsDeductedCents.test.tsandlib/credits/__tests__/estimateModelUsageCost.test.ts- both exceed repository test file size/style expectations and may benefit from splitting for maintainability.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="lib/credits/__tests__/computeCreditsDeductedCents.test.ts">
<violation number="1" location="lib/credits/__tests__/computeCreditsDeductedCents.test.ts:1">
P2: Custom agent: **Enforce Clear Code Style and Maintainability Practices**
Test file exceeds the repository’s 100-line limit and combines multiple concerns in one module.</violation>
</file>
<file name="lib/credits/__tests__/estimateModelUsageCost.test.ts">
<violation number="1" location="lib/credits/__tests__/estimateModelUsageCost.test.ts:1">
P3: Custom agent: **Enforce Clear Code Style and Maintainability Practices**
This new test file exceeds the repository’s 100-line limit.</violation>
</file>
Architecture diagram
sequenceDiagram
participant UI as Chat UI
participant API as Chat API (runAgentWorkflow)
participant Cost as computeCreditsDeductedCents
participant Est as estimateModelUsageCost
participant Catalog as getAvailableModels
participant Models as models.dev / Gateway
Note over UI,Models: NEW: Per-turn credit charge computation
API->>Cost: NEW: computeCreditsDeductedCents(usage, modelId, gatewayCostUsd)
alt Gateway cost available (positive finite number)
Cost->>Cost: NEW: Round to cents, apply 1c floor
Cost-->>API: cents (integer ≥ 1)
else Gateway cost missing/0/negative/NaN/Infinity
Cost->>Catalog: NEW: fetch model catalog
Catalog->>Models: getAvailableModels()
Models-->>Catalog: [{ id, cost }, ...]
alt Model found with cost entry
Catalog-->>Cost: model cost tier
Cost->>Est: NEW: estimateModelUsageCost(usage, cost)
Est->>Est: NEW: resolveCostTier (base vs 200k+ override)
alt Base tier (input ≤ 200k)
Est->>Est: NEW: compute uncached input + cached input + output
else Context over 200k tier (input > 200k AND override present)
Est->>Est: NEW: use overridden input/output/cache_read prices
end
Est-->>Cost: USD estimate or undefined
alt Estimate is valid positive number
Cost->>Cost: NEW: Round to cents, apply 1c floor
else Estimate undefined or ≤ 0
Cost->>Cost: NEW: return 1c floor
end
else Model not found or no cost entry
Cost->>Cost: NEW: return 1c floor
end
alt Catalog fetch fails (error)
Cost->>Cost: NEW: log error, return 1c floor
end
Cost-->>API: cents (integer ≥ 1)
end
Note over API,Cost: Result used by step 3 (deductCreditsWithAudit)
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| @@ -0,0 +1,183 @@ | |||
| import { describe, it, expect, vi, beforeEach } from "vitest"; | |||
There was a problem hiding this comment.
P2: Custom agent: Enforce Clear Code Style and Maintainability Practices
Test file exceeds the repository’s 100-line limit and combines multiple concerns in one module.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/credits/__tests__/computeCreditsDeductedCents.test.ts, line 1:
<comment>Test file exceeds the repository’s 100-line limit and combines multiple concerns in one module.</comment>
<file context>
@@ -0,0 +1,183 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { computeCreditsDeductedCents } from "@/lib/credits/computeCreditsDeductedCents";
+import { getAvailableModels } from "@/lib/ai/getAvailableModels";
</file context>
| @@ -0,0 +1,165 @@ | |||
| import { describe, it, expect } from "vitest"; | |||
There was a problem hiding this comment.
P3: Custom agent: Enforce Clear Code Style and Maintainability Practices
This new test file exceeds the repository’s 100-line limit.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/credits/__tests__/estimateModelUsageCost.test.ts, line 1:
<comment>This new test file exceeds the repository’s 100-line limit.</comment>
<file context>
@@ -0,0 +1,165 @@
+import { describe, it, expect } from "vitest";
+import { estimateModelUsageCost } from "@/lib/credits/estimateModelUsageCost";
+
</file context>
|
Closing — this slice was pure library code with no integration point, which made the preview deployment untestable (no route or workflow exercises the new functions yet). Per feedback on the "step 2/6" framing, reshaping the work into a single user-testable PR on the same branch (`feat/charge-credits-per-chat-turn`). The next PR will include:
So one merge = chat turns actually charge credits, demonstrable on the preview by triggering a workflow and watching `GET /api/accounts/{id}/credits` drop. |
Summary
Step 2 of 6 in closing the chat-workflow credits gap tracked in #605 (silent revenue loss — every chat turn on `/api/chat/workflow` is currently free).
Ports the per-turn cost math from open-agents so the same billing math runs on both sides of the chat cutover. No behavior change yet — this PR only adds the foundation that step 3 (the `deductCreditsWithAudit` wrapper) will use.
What landed
Three new files in `lib/credits/` (one exported function each, matching api's SRP convention):
Resolution order (unchanged from open-agents)
Tests
27 new unit tests:
`estimateModelUsageCost.test.ts` — 13 tests:
`computeCreditsDeductedCents.test.ts` — 14 tests:
Full suite: 3191 → 3205 passing.
What's next
After this merges:
Test plan
🤖 Generated with Claude Code
Summary by cubic
Ports the per-turn billing math from open-agents to compute chat turn charges consistently across the cutover. Step 2/6 for #605; no behavior change yet.
lib/credits/computeCreditsDeductedCents.tsto compute cents per turn: gateway-reported cost → token estimate → 1c floor.lib/credits/estimateModelUsageCost.tsfor token-based USD estimates, including 200k+ context tier andcache_readpricing.lib/credits/AvailableModelCost.tstypes mirroring open-agents; uses thegetAvailableModels()catalog.Written for commit 319d2e6. Summary will update on new commits. Review in cubic