diff --git a/web/src/components/AssistantChat/messages/MessageActions.test.tsx b/web/src/components/AssistantChat/messages/MessageActions.test.tsx index e47f1d13..478f6899 100644 --- a/web/src/components/AssistantChat/messages/MessageActions.test.tsx +++ b/web/src/components/AssistantChat/messages/MessageActions.test.tsx @@ -58,7 +58,7 @@ describe('MessageActions', () => { expect(screen.getByRole('button', { name: 'Message details' })).toBeTruthy() expect(screen.getByText('Duration: 1.3s')).toBeTruthy() expect(screen.getByText('Model: gpt-5.2-codex')).toBeTruthy() - expect(screen.getByText('Usage: 125 billable tokens (100 in / 25 out)')).toBeTruthy() + expect(screen.getByText('Tokens: 125 total (100 in / 25 out)')).toBeTruthy() expect(screen.queryByText(/^Invoke:/)).toBeNull() }) diff --git a/web/src/components/AssistantChat/messages/MessageMetadata.test.ts b/web/src/components/AssistantChat/messages/MessageMetadata.test.ts index f44274b5..36a1b62f 100644 --- a/web/src/components/AssistantChat/messages/MessageMetadata.test.ts +++ b/web/src/components/AssistantChat/messages/MessageMetadata.test.ts @@ -41,12 +41,12 @@ describe('buildMessageMetadataLabels', () => { expect(buildMessageMetadataLabels({})).toEqual([]) }) - it('labels token totals as billable to clarify that cache I/O is intentionally excluded', () => { + it('renders the token total and input/output breakdown without billing claims', () => { const parts = buildMessageMetadataLabels({ usage: { input_tokens: 100, output_tokens: 200 } }) - expect(parts.some(p => /\bbillable tokens\b/.test(p))).toBe(true) - expect(parts.some(p => p.includes('300 billable tokens (100 in / 200 out)'))).toBe(true) + expect(parts).toContain('Tokens: 300 total (100 in / 200 out)') + expect(parts.some(p => /\bbillable\b/.test(p))).toBe(false) }) it('does not drop a Duration line when durationMs is exactly 0', () => { @@ -83,7 +83,7 @@ describe('buildMessageMetadataLabels', () => { expect(parts).toEqual([ 'Duration: 1.2s', 'Model: claude-sonnet-4-6', - 'Usage: 22 billable tokens (3 in / 19 out)' + 'Tokens: 22 total (3 in / 19 out)' ]) }) @@ -95,8 +95,7 @@ describe('buildMessageMetadataLabels', () => { }) expect(parts).toContain('Models: claude-sonnet-4-6, claude-haiku-4-5-20251001') expect(parts.some(p => p.startsWith('Model:'))).toBe(false) - expect(parts).toContain('Total: 300 billable tokens (100 in / 200 out)') - expect(parts.some(p => p.startsWith('Usage:'))).toBe(false) + expect(parts).toContain('Tokens: 300 total (100 in / 200 out)') expect(parts).toContain('3 turns') }) diff --git a/web/src/components/AssistantChat/messages/MessageMetadata.tsx b/web/src/components/AssistantChat/messages/MessageMetadata.tsx index bb73aca3..e2b6b375 100644 --- a/web/src/components/AssistantChat/messages/MessageMetadata.tsx +++ b/web/src/components/AssistantChat/messages/MessageMetadata.tsx @@ -37,14 +37,9 @@ export function buildMessageMetadataLabels({ durationMs, usage, model, turnCount } if (usage) { - // "Billable" because cache_read tokens are not part of the input - // figure used for billing; surfacing only input + output here is - // intentional. If we ever surface cache I/O, keep this label and - // add a separate `Cache:` line. const total = usage.input_tokens + usage.output_tokens const formatToken = (n: number) => n.toLocaleString() - const usageLabel = isAggregated ? 'Total' : 'Usage' - parts.push(`${usageLabel}: ${formatToken(total)} billable tokens (${formatToken(usage.input_tokens)} in / ${formatToken(usage.output_tokens)} out)`) + parts.push(`Tokens: ${formatToken(total)} total (${formatToken(usage.input_tokens)} in / ${formatToken(usage.output_tokens)} out)`) } if (isAggregated) {