Feat/pricing config enhancement (#781)

* feat(db): add pricing config fields to proxy_config table

- Add default_cost_multiplier field per app type
- Add pricing_model_source field (request/response)
- Add request_model field to proxy_request_logs table
- Implement schema migration v5

* feat(api): add pricing config commands and provider meta fields

- Add get/set commands for default cost multiplier
- Add get/set commands for pricing model source
- Extend ProviderMeta with cost_multiplier and pricing_model_source
- Register new commands in Tauri invoke handler

* fix(proxy): apply cost multiplier to total cost only

- Move multiplier calculation from per-item to total cost
- Add resolve_pricing_config for provider-level override
- Include request_model and cost_multiplier in usage logs
- Return new fields in get_request_logs API

* feat(ui): add pricing config UI and usage log enhancements

- Add pricing config section to provider advanced settings
- Refactor PricingConfigPanel to compact table layout
- Display all three apps (Claude/Codex/Gemini) in one view
- Add multiplier column and request model display to logs
- Add frontend API wrappers for pricing config

* feat(i18n): add pricing config translations

- Add zh/en/ja translations for pricing defaults config
- Add translations for multiplier, requestModel, responseModel
- Add provider pricing config translations

* fix(pricing): align backfill cost calculation with real-time logic

- Fix backfill to deduct cache_read_tokens from input (avoid double billing)
- Apply multiplier only to total cost, not to each item
- Add multiplier display in request detail panel with i18n support
- Use AppError::localized for backend error messages
- Fix init_proxy_config_rows to use per-app default values
- Fix silent failure in set_default_cost_multiplier/set_pricing_model_source
- Add clippy allow annotation for test mutex across await

* style: format code with cargo fmt and prettier

* fix(tests): correct error type assertions in proxy DAO tests

The tests expected AppError::InvalidInput but the DAO functions use
AppError::localized() which returns AppError::Localized variant.
Updated assertions to match the correct error type with key validation.

---------

Co-authored-by: Jason <farion1231@gmail.com>
This commit is contained in:
Dex Miller
2026-01-27 10:43:05 +08:00
committed by GitHub
parent c00f431d67
commit 785e1b5add
27 changed files with 2123 additions and 283 deletions
+33 -7
View File
@@ -250,7 +250,7 @@ export function RequestLogTable() {
<TableHead className="whitespace-nowrap">
{t("usage.provider")}
</TableHead>
<TableHead className="min-w-[280px] whitespace-nowrap">
<TableHead className="min-w-[200px] whitespace-nowrap">
{t("usage.billingModel")}
</TableHead>
<TableHead className="text-right whitespace-nowrap">
@@ -265,6 +265,9 @@ export function RequestLogTable() {
<TableHead className="text-right min-w-[90px] whitespace-nowrap">
{t("usage.cacheCreationTokens")}
</TableHead>
<TableHead className="text-right whitespace-nowrap">
{t("usage.multiplier")}
</TableHead>
<TableHead className="text-right whitespace-nowrap">
{t("usage.totalCost")}
</TableHead>
@@ -280,7 +283,7 @@ export function RequestLogTable() {
{logs.length === 0 ? (
<TableRow>
<TableCell
colSpan={10}
colSpan={11}
className="text-center text-muted-foreground"
>
{t("usage.noData")}
@@ -297,11 +300,25 @@ export function RequestLogTable() {
<TableCell>
{log.providerName || t("usage.unknownProvider")}
</TableCell>
<TableCell
className="font-mono text-sm max-w-[280px] truncate"
title={log.model}
>
{log.model}
<TableCell className="font-mono text-xs max-w-[200px]">
<div
className="truncate"
title={
log.requestModel && log.requestModel !== log.model
? `${t("usage.requestModel")}: ${log.requestModel}\n${t("usage.responseModel")}: ${log.model}`
: log.model
}
>
{log.model}
</div>
{log.requestModel && log.requestModel !== log.model && (
<div
className="truncate text-muted-foreground text-[10px]"
title={log.requestModel}
>
{log.requestModel}
</div>
)}
</TableCell>
<TableCell className="text-right">
{log.inputTokens.toLocaleString()}
@@ -315,6 +332,15 @@ export function RequestLogTable() {
<TableCell className="text-right">
{log.cacheCreationTokens.toLocaleString()}
</TableCell>
<TableCell className="text-right font-mono text-xs">
{parseFloat(log.costMultiplier) !== 1 ? (
<span className="text-orange-600">
×{log.costMultiplier}
</span>
) : (
<span className="text-muted-foreground">×1</span>
)}
</TableCell>
<TableCell className="text-right">
${parseFloat(log.totalCostUsd).toFixed(6)}
</TableCell>