Repository navigation
(draft, not ready for review) feat: add conversation cost tracking - #8531
ConstantTime wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
ESLint found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
e1e9fd3 to
c5e7993
Compare
|
@ConstantTime hi, how is it going? Are you stuck on ESLint, or are there some more issues you need help resolving? |
Hey @michnovka, sorry for the late response. Planning to wrap this up during the weekend and open up for review. |
5998d33 to
e364282
Compare
🚨 Unused i18next Keys DetectedThe following translation keys are defined in
|
78fa244 to
a199930
Compare
a52c997 to
068e1ad
Compare
068e1ad to
2c8df88
Compare
…ting - Add comprehensive ModelPricing service with 100+ models and historical pricing - Create real-time ConversationCost component that displays in chat header - Use actual token counts from model APIs instead of client-side estimation - Fix BaseClient.js to preserve tokenCount in response messages - Add tokenCount, usage, and tokens fields to message schema - Update Header component to include ConversationCost display - Support OpenAI, Anthropic, Google, and other major model providers - Include color-coded cost display based on amount - Add 32 unit tests for pricing calculation logic 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
2c8df88 to
3edf6fd
Compare
| // Persist usage metadata on the assistant message if available for accurate costing | ||
| if (this.getStreamUsage != null) { | ||
| const streamUsage = this.getStreamUsage(); | ||
| if (streamUsage && (Number(streamUsage[this.inputTokensKey]) > 0 || Number(streamUsage[this.outputTokensKey]) > 0)) { |
Check failure
Code scanning / ESLint
Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.
| }; | ||
|
|
||
| if (message.usage) { | ||
| currentTokenUsage.promptTokens = message.usage.prompt_tokens || message.usage.input_tokens || 0; |
Check failure
Code scanning / ESLint
Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.
|
|
||
| if (message.usage) { | ||
| currentTokenUsage.promptTokens = message.usage.prompt_tokens || message.usage.input_tokens || 0; | ||
| currentTokenUsage.completionTokens = message.usage.completion_tokens || message.usage.output_tokens || 0; |
Check failure
Code scanning / ESLint
Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.
| currentTokenUsage.cacheReadTokens = read; | ||
| } else if (message.tokens) { | ||
| currentTokenUsage.promptTokens = message.tokens.prompt || message.tokens.input || 0; | ||
| currentTokenUsage.completionTokens = message.tokens.completion || message.tokens.output || 0; |
Check failure
Code scanning / ESLint
Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.
| getMultipleConversationCosts, | ||
| }; | ||
|
|
||
| const { calculateTokenCost, getModelProvider } = require('./ModelPricing'); |
Check failure
Code scanning / ESLint
Disallow variable redeclaration
| * @returns {Array} returns.modelBreakdown - Per-model cost and usage | ||
| * @returns {Date} returns.lastUpdated - Timestamp of the last message | ||
| */ | ||
| function calculateConversationCostFromMessages(messages) { |
Check failure
Code scanning / ESLint
Disallow variable redeclaration
| * @returns {number} returns.totalTokens - Total token count across all messages | ||
| * @returns {Date} returns.lastUpdated - Timestamp of the last message | ||
| */ | ||
| function getConversationCostDisplayFromMessages(messages) { |
Check failure
Code scanning / ESLint
Disallow variable redeclaration
| * @param {string} userId - User ID | ||
| * @returns {Object} Map of conversationId to cost display data | ||
| */ | ||
| async function getMultipleConversationCosts(conversationIds, userId) { |
Check failure
Code scanning / ESLint
Disallow variable redeclaration
|
|
||
| if (!data || data.totalCostRaw === 0) { | ||
| return ( | ||
| <div className="flex items-center gap-1 rounded-md px-2 py-1 text-xs text-gray-400" title={t('com_ui_conversation_cost')}> |
Check failure
Code scanning / ESLint
Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.
| const tooltipText = `${t('com_ui_conversation_cost')}: ${data.totalCost} | ${t('com_ui_primary_model')}: ${data.primaryModel} | ${t('com_ui_total_tokens')}: ${data.totalTokens.toLocaleString()} | ${t('com_ui_last_updated')}: ${new Date(data.lastUpdated).toLocaleTimeString()}`; | ||
|
|
||
| return ( | ||
| <div className="flex items-center gap-1 rounded-md px-2 py-1 text-xs transition-colors hover:bg-surface-hover" title={tooltipText}> |
Check failure
Code scanning / ESLint
Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.
Summary
Adds real-time cost tracking for conversations. Users can now see how much their conversations cost as messages stream, with automatic updates and color-coded indicators.
Features
Implementation
The cost display appears in the conversation header and updates automatically as new messages arrive. Hover over the cost to see detailed breakdown including model used, token count, and last update time.
Testing
Change Type
Checklist