Merge pull request #6843 from ouchihao/codex/issue-6841-usage-cost-precision

fix(usage): show eight decimal places in cost details
This commit is contained in:
Wesley Liddick
2026-09-11 09:34:36 +08:00
committed by GitHub
2 changed files with 59 additions and 12 deletions
@@ -410,19 +410,19 @@
<div class="text-xs font-semibold text-gray-300 mb-1">{{ t('usage.costDetails') }}</div>
<div v-if="tooltipData && tooltipData.input_cost > 0" class="flex items-center justify-between gap-4">
<span class="text-gray-400">{{ t('admin.usage.inputCost') }}</span>
<span class="font-medium text-white">${{ tooltipData.input_cost.toFixed(6) }}</span>
<span class="font-medium text-white">${{ tooltipData.input_cost.toFixed(8) }}</span>
</div>
<div v-if="tooltipData && hasImageInputCost(tooltipData)" class="flex items-center justify-between gap-4">
<span class="text-gray-400">{{ t('usage.imageInputCost') }}</span>
<span class="font-medium text-fuchsia-300">${{ tooltipData.image_input_cost.toFixed(6) }}</span>
<span class="font-medium text-fuchsia-300">${{ tooltipData.image_input_cost.toFixed(8) }}</span>
</div>
<div v-if="tooltipData && tooltipData.output_cost > 0" class="flex items-center justify-between gap-4">
<span class="text-gray-400">{{ t('admin.usage.outputCost') }}</span>
<span class="font-medium text-white">${{ tooltipData.output_cost.toFixed(6) }}</span>
<span class="font-medium text-white">${{ tooltipData.output_cost.toFixed(8) }}</span>
</div>
<div v-if="tooltipData && hasImageOutputCost(tooltipData)" class="flex items-center justify-between gap-4">
<span class="text-gray-400">{{ t('usage.imageOutputCost') }}</span>
<span class="font-medium text-pink-300">${{ tooltipData.image_output_cost.toFixed(6) }}</span>
<span class="font-medium text-pink-300">${{ tooltipData.image_output_cost.toFixed(8) }}</span>
</div>
<!-- Token billing: show unit prices per 1M tokens -->
<template v-if="tooltipData && !isImageUsage(tooltipData) && (!tooltipData.billing_mode || tooltipData.billing_mode === BILLING_MODE_TOKEN)">
@@ -470,24 +470,24 @@
</div>
<div class="flex items-center justify-between gap-4">
<span class="text-gray-400">{{ t('usage.imageUnitPrice') }}</span>
<span class="font-medium text-sky-300">${{ imageUnitPrice(tooltipData).toFixed(6) }}</span>
<span class="font-medium text-sky-300">${{ imageUnitPrice(tooltipData).toFixed(8) }}</span>
</div>
<div class="flex items-center justify-between gap-4">
<span class="text-gray-400">{{ t('usage.imageTotalPrice') }}</span>
<span class="font-medium text-white">${{ tooltipData.total_cost?.toFixed(6) || '0.000000' }}</span>
<span class="font-medium text-white">${{ tooltipData.total_cost?.toFixed(8) || '0.00000000' }}</span>
</div>
</template>
<div v-else class="flex items-center justify-between gap-4">
<span class="text-gray-400">{{ t('usage.unitPrice') }}</span>
<span class="font-medium text-sky-300">${{ tooltipData?.total_cost?.toFixed(6) || '0.000000' }}</span>
<span class="font-medium text-sky-300">${{ tooltipData?.total_cost?.toFixed(8) || '0.00000000' }}</span>
</div>
<div v-if="tooltipData && tooltipData.cache_creation_cost > 0" class="flex items-center justify-between gap-4">
<span class="text-gray-400">{{ t('admin.usage.cacheCreationCost') }}</span>
<span class="font-medium text-white">${{ tooltipData.cache_creation_cost.toFixed(6) }}</span>
<span class="font-medium text-white">${{ tooltipData.cache_creation_cost.toFixed(8) }}</span>
</div>
<div v-if="tooltipData && tooltipData.cache_read_cost > 0" class="flex items-center justify-between gap-4">
<span class="text-gray-400">{{ t('admin.usage.cacheReadCost') }}</span>
<span class="font-medium text-white">${{ tooltipData.cache_read_cost.toFixed(6) }}</span>
<span class="font-medium text-white">${{ tooltipData.cache_read_cost.toFixed(8) }}</span>
</div>
</div>
<!-- Rate and Summary -->
@@ -501,11 +501,11 @@
</div>
<div class="flex items-center justify-between gap-6">
<span class="text-gray-400">{{ t('usage.original') }}</span>
<span class="font-medium text-white">${{ tooltipData?.total_cost?.toFixed(6) || '0.000000' }}</span>
<span class="font-medium text-white">${{ tooltipData?.total_cost?.toFixed(8) || '0.00000000' }}</span>
</div>
<div class="flex items-center justify-between gap-6">
<span class="text-gray-400">{{ t('usage.userBilled') }}</span>
<span class="font-semibold text-green-400">${{ tooltipData?.actual_cost?.toFixed(6) || '0.000000' }}</span>
<span class="font-semibold text-green-400">${{ tooltipData?.actual_cost?.toFixed(8) || '0.00000000' }}</span>
</div>
<!-- Account billing (separated from user billing) -->
<template v-if="showAccountBilling">
@@ -520,7 +520,7 @@
total_cost: tooltipData?.total_cost,
account_stats_cost: tooltipData?.account_stats_cost,
account_rate_multiplier: tooltipData?.account_rate_multiplier,
}).toFixed(6) }}
}).toFixed(8) }}
</span>
</div>
</template>
@@ -275,6 +275,53 @@ describe('admin UsageTable tooltip', () => {
expect(text).toContain('$0.069568')
})
it.each(['token', 'image', 'per_request'])('keeps eight decimal places in %s cost details', async (billingMode) => {
const row = {
...baseImageRow,
billing_mode: billingMode,
image_count: billingMode === 'image' ? 2 : 0,
input_cost: 0.00000001,
image_input_cost: 0.00000002,
output_cost: 0.00000003,
image_output_cost: 0.00000004,
cache_creation_cost: 0.00000005,
cache_read_cost: 0.00000006,
total_cost: 0.00000022,
actual_cost: 0.00000042,
account_stats_cost: 0.00000012,
account_rate_multiplier: 1.5,
}
const wrapper = mount(UsageTable, {
props: { data: [row], loading: false, columns: [] },
global: { stubs: { DataTable: DataTableStub, EmptyState: true, Icon: true, Teleport: true } },
})
const triggers = wrapper.findAll('.group.relative')
await triggers[triggers.length - 1].trigger('mouseenter')
const amounts = wrapper.get('.fixed').findAll('span').map(span => span.text())
expect(amounts).toEqual(expect.arrayContaining([
'$0.00000001', '$0.00000002', '$0.00000003', '$0.00000004',
'$0.00000005', '$0.00000006', '$0.00000022', '$0.00000042', '$0.00000018',
]))
if (billingMode === 'image') expect(amounts).toContain('$0.00000011')
wrapper.unmount()
})
it('uses eight decimal places for missing cost values', async () => {
const wrapper = mount(UsageTable, {
props: {
data: [{ ...baseImageRow, billing_mode: 'per_request', image_count: 0, total_cost: undefined, actual_cost: undefined }],
loading: false,
columns: [],
},
global: { stubs: { DataTable: DataTableStub, EmptyState: true, Icon: true, Teleport: true } },
})
const triggers = wrapper.findAll('.group.relative')
await triggers[triggers.length - 1].trigger('mouseenter')
const amounts = wrapper.get('.fixed').findAll('span').map(span => span.text()).filter(text => text.startsWith('$'))
expect(amounts).toEqual(['$0.00000000', '$0.00000000', '$0.00000000', '$0.00000000'])
wrapper.unmount()
})
it('shows requested and upstream models separately for admin rows', () => {
const row = {
request_id: 'req-admin-model-1',