feat(usage): user-configurable per-model cost overlay (providers.<name>.modelCosts) - #1010
feat(usage): user-configurable per-model cost overlay (providers.<name>.modelCosts)#1010harryzhou2000 wants to merge 16 commits into
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds ChangesProvider cost overlay
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant ConfigLoader
participant UserCostOverlays
participant CostEstimator
participant UsageSummaryCache
participant Logs
ConfigLoader->>UserCostOverlays: refreshUserCostOverlays(config)
UserCostOverlays-->>CostEstimator: active overlays and version
CostEstimator->>CostEstimator: resolve user price before built-in prices
CostEstimator-->>UsageSummaryCache: store estimate with overlay version
UsageSummaryCache->>UsageSummaryCache: reject stale overlay versions
CostEstimator-->>Logs: estimate with source "user"
Logs-->>Logs: map provider_cost_overlay to localized detail
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ 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.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs-site/src/content/docs/reference/configuration/providers.md`:
- Line 69: Update the `modelCosts` documentation on line 69 to explicitly
clarify that custom or internal provider model IDs—even those absent from
built-in catalogs—are valid overlay keys for cost configuration. Add a note
stating that users can define custom prices for any model identifier regardless
of catalog presence, making clear that the feature supports providers beyond the
standard built-in offerings.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: d0d55d83-385c-4beb-b349-119980acd24b
📒 Files selected for processing (16)
docs-site/src/content/docs/reference/configuration/providers.mdgui/src/i18n/de.tsgui/src/i18n/en.tsgui/src/i18n/ja.tsgui/src/i18n/ko.tsgui/src/i18n/ru.tsgui/src/i18n/zh.tsgui/src/pages/Logs.tsxsrc/config.tssrc/server/auth-cors.tssrc/server/management/shared.tssrc/types.tssrc/usage/cost.tssrc/usage/user-cost-overlays.tstests/provider-cost-overlay-config.test.tstests/usage-cost.test.ts
afc131d to
180b8b4
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs-site/src/content/docs/reference/configuration/providers.md`:
- Line 75: Update the modelCosts documentation to state the complete
display-price fallback order: user configuration, jawcode catalog,
expected-price overlay, then model-level vendor fallback. Clarify that an
all-zero user entry falls through to the next source in that sequence, while
preserving the existing display-only and non-billing behavior.
- Line 75: Add the modelCosts configuration row after modelMaxOutputTokens in
the Japanese, Korean, Russian, and Simplified Chinese provider pages,
documenting exact model-ID keys, all-zero entries falling back to built-in
catalogs, and display-only estimates that never affect billing.
In `@gui/src/i18n/de.ts`:
- Line 574: Update the German translation value for
logs.detail.estimate.provider_cost_overlay to “Ein vom Anbieter konfiguriertes
Preis-Overlay wurde verwendet.”, preserving alignment with the English catalog
entry.
In `@gui/src/pages/Logs.tsx`:
- Around line 45-49: Extend the GUI price-source contract used by
MatchedPriceInfo to include "user", then add the logs.detail.source.user
translation key to every locale alongside the existing source labels so
provider-configured overlay-priced rows display a localized source.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: a4b0f2de-a70c-4109-a5d9-f87dcbe73c8d
📒 Files selected for processing (8)
docs-site/src/content/docs/reference/configuration/providers.mdgui/src/i18n/de.tsgui/src/i18n/en.tsgui/src/i18n/ja.tsgui/src/i18n/ko.tsgui/src/i18n/ru.tsgui/src/i18n/zh.tsgui/src/pages/Logs.tsx
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 180b8b4326
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
Thanks for the review — addressed in 7a4ce62:
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs-site/src/content/docs/ja/reference/configuration/providers.md`:
- Line 68: Update the Cost4 documentation row in
docs-site/src/content/docs/ja/reference/configuration/providers.md:68-68 to list
the supported input, output, cacheRead, and cacheWrite rate fields. Apply the
equivalent field list or example to
docs-site/src/content/docs/ko/reference/configuration/providers.md:68-68,
docs-site/src/content/docs/ru/reference/configuration/providers.md:78-78, and
docs-site/src/content/docs/zh-cn/reference/configuration/providers.md:67-67,
preserving each locale’s language and existing pricing guidance.
In `@gui/src/i18n/ru.ts`:
- Line 566: Update the Russian translation for
logs.detail.estimate.provider_cost_overlay at line 592 to reuse the same
terminology from logs.detail.source.user at line 566. Replace the current
"настроенная пользователем цена провайдера" phrasing with a sentence form that
incorporates "Ценовой оверлей провайдера" (keeping the "оверлей" term
consistent). This aligns the Russian translations with every other locale in the
PR, which reuses an identical term across both the price-source label and the
estimate-reason explanation.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: a3d12d7c-bcdf-4344-b9a0-61f4e65190d7
📒 Files selected for processing (18)
docs-site/src/content/docs/ja/reference/configuration/providers.mddocs-site/src/content/docs/ko/reference/configuration/providers.mddocs-site/src/content/docs/reference/configuration/providers.mddocs-site/src/content/docs/ru/reference/configuration/providers.mddocs-site/src/content/docs/zh-cn/reference/configuration/providers.mdgui/src/i18n/de.tsgui/src/i18n/en.tsgui/src/i18n/ja.tsgui/src/i18n/ko.tsgui/src/i18n/ru.tsgui/src/i18n/zh.tsgui/src/pages/Logs.tsxsrc/config.tssrc/server/auth-cors.tssrc/server/management/shared.tssrc/usage/cost.tssrc/usage/user-cost-overlays.tstests/provider-cost-overlay-config.test.ts
|
✅ Deterministic PR hygiene checks passed. |
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/server/auth-cors.ts`:
- Around line 525-539: Update sanitizeModelCosts to create out with a null
prototype so assigning the "__proto__" model ID creates an own property and
Object.keys includes it. Add a regression test using JSON.parse() to construct
the "__proto__" key and verify safeConfigDTO exposes its valid cost row.
In `@tests/usage-cost.test.ts`:
- Around line 769-812: Move the empty-provider cleanup for user cost overlays
out of the test body and into an afterEach hook scoped to the surrounding
describe block. Ensure the hook calls refreshUserCostOverlays with an empty
providers object so the blsc overlay is reset even when assertions in “registry
refresh replaces rows, bumps the version, and invalidates the memo” fail, and
update the bun:test imports to include afterEach.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: d8697a9c-f003-4c14-ae6a-70292ae50aef
📒 Files selected for processing (20)
docs-site/src/content/docs/ja/reference/configuration/providers.mddocs-site/src/content/docs/ko/reference/configuration/providers.mddocs-site/src/content/docs/reference/configuration/providers.mddocs-site/src/content/docs/ru/reference/configuration/providers.mddocs-site/src/content/docs/zh-cn/reference/configuration/providers.mdgui/src/i18n/de.tsgui/src/i18n/en.tsgui/src/i18n/ja.tsgui/src/i18n/ko.tsgui/src/i18n/ru.tsgui/src/i18n/zh.tsgui/src/pages/Logs.tsxsrc/config.tssrc/server/auth-cors.tssrc/server/management/shared.tssrc/types.tssrc/usage/cost.tssrc/usage/user-cost-overlays.tstests/provider-cost-overlay-config.test.tstests/usage-cost.test.ts
|
@coderabbitai resume — the dev merge (f620f7f) resolved the config.ts conflict (persistConfigUnlocked now returns boolean for generation bumping while still refreshing the cost-overlay registry). Please run the full review on the merged state. |
|
✅ Action performedReviews resumed. Full review finished. |
|
Heads-up for review: the hygiene gate flags |
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/server/auth-cors.ts (1)
525-539: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winPreserve the valid
__proto__model ID.Line 527 creates a normal object.
providerModelCostsConfigErroraccepts"__proto__"because it is a nonblank model ID. For a row parsed from JSON, Line 536 changesout's prototype instead of adding an own property.Object.keys(out)then omits the row, sosafeConfigDTOdoes not expose a valid configured price.Create
outwith a null prototype. Add a regression test that builds the key throughJSON.parse().Proposed fix
- const out: Record<string, ProviderCostOverlay> = {}; + const out: Record<string, ProviderCostOverlay> = Object.create(null);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/server/auth-cors.ts` around lines 525 - 539, Update sanitizeModelCosts to create out with a null prototype so assigning the valid "__proto__" model ID produces an own property and remains included in the returned configuration. Add a regression test that obtains this key via JSON.parse() and verifies the sanitized costs preserve the valid entry.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/provider-cost-overlay-config.test.ts`:
- Around line 26-30: Reset the user overlay registry in both affected test
sites: in tests/provider-cost-overlay-config.test.ts lines 26-30, call
refreshUserCostOverlays({ providers: {} } as OcxConfig) in the existing
afterEach before deleting OPENCODEX_HOME; in tests/usage-cost.test.ts lines
769-812, add a scoped afterEach that performs the same reset and remove the
test-body cleanup near line 807.
---
Duplicate comments:
In `@src/server/auth-cors.ts`:
- Around line 525-539: Update sanitizeModelCosts to create out with a null
prototype so assigning the valid "__proto__" model ID produces an own property
and remains included in the returned configuration. Add a regression test that
obtains this key via JSON.parse() and verifies the sanitized costs preserve the
valid entry.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: a262235e-fcc4-491e-a174-d1c80bdad0fb
📒 Files selected for processing (20)
docs-site/src/content/docs/ja/reference/configuration/providers.mddocs-site/src/content/docs/ko/reference/configuration/providers.mddocs-site/src/content/docs/reference/configuration/providers.mddocs-site/src/content/docs/ru/reference/configuration/providers.mddocs-site/src/content/docs/zh-cn/reference/configuration/providers.mdgui/src/i18n/de.tsgui/src/i18n/en.tsgui/src/i18n/ja.tsgui/src/i18n/ko.tsgui/src/i18n/ru.tsgui/src/i18n/zh.tsgui/src/pages/Logs.tsxsrc/config.tssrc/server/auth-cors.tssrc/server/management/shared.tssrc/types.tssrc/usage/cost.tssrc/usage/user-cost-overlays.tstests/provider-cost-overlay-config.test.tstests/usage-cost.test.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c5db9f883f
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Line 231 in 50cc147
When a valid custom provider name happens to end with the Codex account-label suffix pattern, such as blsc-pabcdef, resolveMatchedPrice() has already collapsed it to blsc before this new user-overlay lookup runs, while refreshUserCostOverlays() stores the configured row under the exact provider name. In that scenario a valid providers.blsc-pabcdef.modelCosts.custom-model entry is never matched, so Logs/usage estimates stay unpriced despite the explicit override; try the exact provider against userOverlays before applying baseProviderLabel, or register both exact and collapsed keys.
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
… isolation - sanitizeModelCosts builds the DTO map with a null prototype so a model id literally named __proto__ stays an own row instead of mutating the map's prototype and vanishing from Object.keys (CodeRabbit minor). - usage-cost and provider-cost-overlay-config tests reset the module-level overlay registry in afterEach so rows cannot leak across test files in a shared-process run (CodeRabbit stability). - Regression test: safeConfigDTO keeps a __proto__ model id as an own row.
Codex review findings: - refreshUserCostOverlays now copies ONLY the four validated rate fields into the overlay row, so a hand-edited row carrying extra properties (e.g. a misplaced apiKey) can no longer leak through /api/logs display estimates (P1). - loadConfig/configDiagnosticsFromRaw run sanitizeModelCostsForLoad before schema validation: malformed display-price rows are dropped with a warning instead of failing the whole parse and falling back to defaults, which previously discarded otherwise valid providers. Strict rejection stays at the management/write boundary (P2). Regression tests: malformed row degradation, non-object modelCosts drop, and registry rows containing only the four rate fields.
A custom provider whose name ends with the Codex account-log-label suffix pattern (e.g. blsc-pabcdef) had its provider collapsed by baseProviderLabel before the user-overlay lookup, so providers.<name>.modelCosts rows stored under the exact name never matched and estimates stayed unpriced. resolveMatchedPrice now checks the exact provider against the user overlay first, then collapses for the compiled catalogs.
…y changes - providerModelCostsConfigError now JSON-quotes and redacts secret-shaped model ids so a malformed write cannot echo a pasted key/secret back through the management API. - /api/usage summaries are cached against userCostOverlayVersion(): an overlay save invalidates the entry even when the usage log is unchanged. - refreshUserCostOverlays is a no-op when the extracted rows are byte-identical, so reloads of an unchanged config (server start, migrations, persist paths) no longer churn the version, invalidate the summary cache, or thash the cost memo. - tests: redaction + quoted-key assertions, cache-invalidation test, and an identical-refresh no-op regression test.
…t finally block The test installs a module-level blsc overlay; reset it to empty before stopping the server so a later test (or an assertion/shutdown failure) cannot resolve user-configured prices unexpectedly.
providerManagementConfigError echoed the caller-controlled provider name verbatim in the modelCosts error path even though the route has not yet validated/sanitized it. JSON-quote and redact the name (same rule as the retryOn429 branch) so a token-shaped provider name cannot serialize back through the management API. Regression test added.
…ration - /api/providers POST now carries an existing provider's modelCosts when the overwrite payload omits it, so the dashboard's add/edit form cannot silently erase hand-edited per-model price overlays (same rule as the apiKeyPool carry-over). - The Alibaba region startup migration carries modelCosts in USER_OWNED_FIELDS so an intl migration does not drop user price overlays. - providers.md (en/ja/ko/ru/zh-cn) now states that custom, local OpenAI-compatible, and internal providers support exact model-id overlays and that overlays affect display-time estimates only — never routing, account selection, quotas, or billing. zh-cn wording fixed. - ko/zh i18n align provider terminology with logs.col.provider. - Regression tests for both carry-over paths; OcxConfig type import added.
validateConfigCandidate (ocx config validate/import) serializes the issue path as providers.<name>.modelCosts; a token-shaped provider key could leak through the CLI error even though model ids inside the message are redacted. The schema issue path now runs the provider name through redactSecretString. Regression test in tests/provider-cost-overlay-config.test.ts.
…gistry provenance - mergeLegacyOpenAiProviderRows now carries modelCosts from the openai and openai-multi rows, and managedLegacyMultiOverlay accepts modelCosts as a managed overlay field, so a v1/restored config with user price overlays no longer drops them (or collides) during the tier migration. - refreshUserCostOverlays redacts token-shaped provider/model ids in the display-only source string and in the refresh signature, so raw pasted-key identifiers never live in registry metadata or cache keys; matching still uses the raw fields. - Regression tests for both.
dbf1226 to
ea7f5a6
Compare
|
✅ Action performedReview finished.
|
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
|
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/server/auth-cors.ts`:
- Around line 534-550: Update sanitizeModelCosts to detect and omit
secret-shaped model IDs before adding entries to the output DTO, reusing the
existing token-shape validation used by providerModelCostsConfigError where
available. Preserve valid model-cost rows, and add a regression test confirming
token-shaped IDs such as sk-abcdef1234567890 are absent from safeConfigDTO.
In `@src/usage/user-cost-overlays.ts`:
- Around line 76-85: The signature in the overlay refresh logic must compare raw
provider, modelId, and all four cost rates so distinct token-shaped IDs trigger
updates; retain only source redaction for display. Update the signature
construction near the refresh function, preserve the activeSignature/version
behavior, and add a regression test that refreshes two different redacted IDs
and verifies the second ID resolves.
In `@tests/openai-provider-option-migration.test.ts`:
- Around line 172-183: Update the test around projectOpenAiTierMigration to
assert the complete merged modelCosts map, including both the openai costs and
the openai-multi multiCosts entry. Replace the single-provider equality check
while preserving the expected combined values.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 86dc4793-5134-471b-863f-af216ff4d956
⛔ Files ignored due to path filters (1)
docs/screenshots/provider-cost-overlay-logs-detail.pngis excluded by!**/*.png
📒 Files selected for processing (29)
docs-site/src/content/docs/ja/reference/configuration/providers.mddocs-site/src/content/docs/ko/reference/configuration/providers.mddocs-site/src/content/docs/reference/configuration/providers.mddocs-site/src/content/docs/ru/reference/configuration/providers.mddocs-site/src/content/docs/zh-cn/reference/configuration/providers.mdgui/src/i18n/de.tsgui/src/i18n/en.tsgui/src/i18n/ja.tsgui/src/i18n/ko.tsgui/src/i18n/ru.tsgui/src/i18n/zh.tsgui/src/pages/Logs.tsxsrc/config.tssrc/providers/alibaba-region-migration.tssrc/providers/openai-tiers.tssrc/server/auth-cors.tssrc/server/management/logs-usage-routes.tssrc/server/management/provider-routes.tssrc/server/management/shared.tssrc/server/management/usage-summary-cache.tssrc/types.tssrc/usage/cost.tssrc/usage/user-cost-overlays.tstests/alibaba-region-migration.test.tstests/api-usage.test.tstests/management-provider-validation.test.tstests/openai-provider-option-migration.test.tstests/provider-cost-overlay-config.test.tstests/usage-cost.test.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ea7f5a6974
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…d legacy merge Review round 8b230c8 findings: - safeConfigDTO redacts secret-shaped model ids in modelCosts keys so the dashboard DTO cannot echo a pasted key (validation errors already redacted). - The overlay refresh signature compares RAW matching fields again: two distinct secret-shaped ids must not collapse to the same redacted signature and skip the version bump (process-local signature; only the display source stays redacted). - providerManagementConfigError tolerates modelCosts on the canonical openai seed (validated separately), so management clients can add overlays. - mergeLegacyOpenAiProviderRows merges disjoint modelCosts from both legacy rows instead of nullish-picking one map and dropping the other. - Tests for every case, including a distinct-id change-detection regression.
…hape check
Local multi-model audit (deepseek-v4-flash, GLM-5.2) findings:
- mergeLegacyOpenAiProviderRows no longer attaches a spurious empty
modelCosts: {} when neither legacy row carries an overlay (empty object is
truthy); the minimal tier-1 migration stays clean.
- managedLegacyMultiOverlay validates the legacy modelCosts shape locally
(no config.ts import — that would cycle) so a malformed overlay is a
collision instead of being carried into the canonical row.
- safeConfigDTO drops secret-shaped model ids from modelCosts entirely
instead of collapsing distinct rows into one [REDACTED] placeholder key.
- Comment on the raw change-detection signature corrected.
- Tests: no-empty-overlay assertion, DTO drop assertions, and a
loadConfig-unchanged no-op version test.
|
✅ Action performedReview finished.
|
|
|
|
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ca12e9ee46
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- logs.detail.matchedKey is now source-neutral ("Matched price key") in all
six locales: it is also rendered when price.source is "user", where no
jawcode row was matched.
- providers.md (en/ja/ko/ru/zh-cn) now documents that modelCosts also reprices
Usage totals, including historical entries, so a price edit can move past
aggregates.
Closes #1009
Summary
Adds
providers.<name>.modelCosts— a per-model display price overlay (USD per1M tokens) so operators can price internal/custom providers whose ids do not
match the compiled catalogs, or whose actual costs vary from list prices.
Resolution order: user
modelCosts→ jawcode catalog → expected-price overlay →model-level vendor fallback. All-zero entries fall through. Display-time
estimation only; never billing.
Changes
src/usage/user-cost-overlays.ts(new): registry liftingproviders.<name>.modelCostsinto price-overlay rows; refreshed atloadConfigand every persist path; versioned so the estimator memo neverserves stale rows and edits apply without a restart.
src/usage/cost.ts: user overlay wins inresolveMatchedPrice(exactprovider/model match,
source: "user"); memo key now includes the overlayversion. Also replaces a stray NUL byte in the memo cache-key template
literal with a space separator.
src/config.ts:providerModelCostsConfigErrorvalidation (non-negativefinite 4-tuples) wired into the load-time schema refine.
src/server/auth-cors.ts: management API rejects malformedmodelCosts;safeConfigDTOexposes the field.src/server/management/shared.ts: newprovider_cost_overlayestimatereason.
gui/: reason label + i18n strings (en/de/ja/ko/ru/zh).UI change
Tests
via overlay, all-zero fall-through, combo fail-closed, registry refresh/memo
invalidation.
validation, DTO passthrough.
bun run typecheck, GUIeslint, and the touched suites pass (91 tests).Summary by CodeRabbit
New Features
Documentation
Localization
Review readiness checklist
This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:
All CI tests are green on my local testing.
I pushed my PR to the latest dev commit.
I resolved all correct Codex and CodeRabbit findings.
My PR is ready for review.