Skip to content

Conversation

ConstantTime
Copy link
Collaborator

@ConstantTime ConstantTime commented Jul 18, 2025

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

  • Dynamic cost calculation from message history
  • 100+ model support across OpenAI, Anthropic, Google, and AWS Bedrock
  • Historical pricing ensures accurate costs based on when messages were sent
  • Color-coded display for quick cost assessment:
    • 🟢 Green: < $0.01
    • 🟡 Yellow: < $0.10
    • 🟠 Orange: < $1.00
    • 🔴 Red: > $1.00

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

  • 56 unit tests covering all pricing logic and edge cases
  • Tested with multiple models in single conversations
  • Verified historical pricing calculations

Change Type

  • New feature (non-breaking change which adds functionality)

Checklist

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • I have commented in any complex areas of my code
  • My changes do not introduce new warnings
  • Local unit tests pass with my changes (56 tests)
  • I have written tests demonstrating that my changes are effective

Copy link
Contributor

@github-advanced-security github-advanced-security bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ESLint found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

@ConstantTime ConstantTime changed the title feat: add conversation cost tracking (draft, not ready for review) feat: add conversation cost tracking Jul 24, 2025
@ConstantTime ConstantTime force-pushed the feat/conversation-cost-tracking branch 3 times, most recently from e1e9fd3 to c5e7993 Compare July 30, 2025 09:26
@michnovka
Copy link

@ConstantTime hi, how is it going? Are you stuck on ESLint, or are there some more issues you need help resolving?

@ConstantTime
Copy link
Collaborator Author

@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.

@ConstantTime ConstantTime force-pushed the feat/conversation-cost-tracking branch from 5998d33 to e364282 Compare August 17, 2025 12:16
Copy link
Contributor

🚨 Unused i18next Keys Detected

The following translation keys are defined in translation.json but are not used in the codebase:

  • com_ui_conversation_cost
  • com_ui_last_updated
  • com_ui_primary_model
  • com_ui_total_tokens

⚠️ Please remove these unused keys to keep the translation files clean.

@ConstantTime ConstantTime force-pushed the feat/conversation-cost-tracking branch 2 times, most recently from 78fa244 to a199930 Compare August 17, 2025 12:34
@ConstantTime ConstantTime force-pushed the feat/conversation-cost-tracking branch 2 times, most recently from a52c997 to 068e1ad Compare August 17, 2025 14:44
@ConstantTime ConstantTime force-pushed the feat/conversation-cost-tracking branch from 068e1ad to 2c8df88 Compare August 24, 2025 17:46
…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 <[email protected]>
@ConstantTime ConstantTime force-pushed the feat/conversation-cost-tracking branch from 2c8df88 to 3edf6fd Compare August 24, 2025 17:46
// 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. Error

Replace streamUsage·&&·(Number(streamUsage[this.inputTokensKey])·>·0·||·Number(streamUsage[this.outputTokensKey])·>·0) with ⏎········streamUsage·&&⏎········(Number(streamUsage[this.inputTokensKey])·>·0·||⏎··········Number(streamUsage[this.outputTokensKey])·>·0)⏎······

Copilot Autofix

AI 5 days ago

The best fix is to reformat the conditional at line 785 so that:

  • The logical AND (&&) and logical OR (||) expressions each begin on a new line with appropriate indentation.
  • Each operand of the logical operators is clearly separated, following ESLint’s suggestion for multiline formatting of long logical statements.
    This change only affects formatting, not logic, and applies only to the conditional in line 785 of api/app/clients/BaseClient.js.
Suggested changeset 1
api/app/clients/BaseClient.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/api/app/clients/BaseClient.js b/api/app/clients/BaseClient.js
--- a/api/app/clients/BaseClient.js
+++ b/api/app/clients/BaseClient.js
@@ -782,7 +782,13 @@
     // 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)) {
+      if (
+        streamUsage &&
+        (
+          Number(streamUsage[this.inputTokensKey]) > 0 ||
+          Number(streamUsage[this.outputTokensKey]) > 0
+        )
+      ) {
         responseMessage.usage = {
           prompt_tokens: streamUsage[this.inputTokensKey],
           completion_tokens: streamUsage[this.outputTokensKey],
EOF
@@ -782,7 +782,13 @@
// 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)) {
if (
streamUsage &&
(
Number(streamUsage[this.inputTokensKey]) > 0 ||
Number(streamUsage[this.outputTokensKey]) > 0
)
) {
responseMessage.usage = {
prompt_tokens: streamUsage[this.inputTokensKey],
completion_tokens: streamUsage[this.outputTokensKey],
Copilot is powered by AI and may make mistakes. Always verify output.
};

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. Error

Insert ⏎·········

Copilot Autofix

AI 5 days ago

The best way to fix the formatting issue flagged by ESLint is to follow its suggestion and properly format the assignment on line 98. Specifically, split the line so each part of the assignment (when using the logical OR expression) appears on its own line and is indented to the correct level, complying with the project's style and ESLint's expectations. This usually means putting each part of the expression on a new line, indented appropriately relative to the enclosing code. The change should be made in the function calculateConversationCostFromMessages, in the block assigning currentTokenUsage.promptTokens.


Suggested changeset 1
api/server/services/ConversationCostDynamic.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/api/server/services/ConversationCostDynamic.js b/api/server/services/ConversationCostDynamic.js
--- a/api/server/services/ConversationCostDynamic.js
+++ b/api/server/services/ConversationCostDynamic.js
@@ -95,7 +95,10 @@
       };
 
       if (message.usage) {
-        currentTokenUsage.promptTokens = message.usage.prompt_tokens || message.usage.input_tokens || 0;
+        currentTokenUsage.promptTokens =
+          message.usage.prompt_tokens ||
+          message.usage.input_tokens ||
+          0;
         currentTokenUsage.completionTokens = message.usage.completion_tokens || message.usage.output_tokens || 0;
         currentTokenUsage.reasoningTokens = message.usage.reasoning_tokens || 0;
         const write = Number(message.usage?.input_token_details?.cache_creation) || 0;
EOF
@@ -95,7 +95,10 @@
};

if (message.usage) {
currentTokenUsage.promptTokens = message.usage.prompt_tokens || message.usage.input_tokens || 0;
currentTokenUsage.promptTokens =
message.usage.prompt_tokens ||
message.usage.input_tokens ||
0;
currentTokenUsage.completionTokens = message.usage.completion_tokens || message.usage.output_tokens || 0;
currentTokenUsage.reasoningTokens = message.usage.reasoning_tokens || 0;
const write = Number(message.usage?.input_token_details?.cache_creation) || 0;
Copilot is powered by AI and may make mistakes. Always verify output.

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. Error

Insert ⏎·········

Copilot Autofix

AI 5 days ago

To fix the formatting error reported by ESLint, insert a line break (empty line) at the indicated location (after line 99), which separates the assignment of currentTokenUsage.completionTokens and currentTokenUsage.reasoningTokens. This improves code readability and matches typical formatting standards that make blocks of assignments within conditional branches easier to scan and maintain. The edit only needs to add an empty line at the specified point; no imports, methods, or functional changes are required.


Suggested changeset 1
api/server/services/ConversationCostDynamic.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/api/server/services/ConversationCostDynamic.js b/api/server/services/ConversationCostDynamic.js
--- a/api/server/services/ConversationCostDynamic.js
+++ b/api/server/services/ConversationCostDynamic.js
@@ -97,6 +97,7 @@
       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;
+
         currentTokenUsage.reasoningTokens = message.usage.reasoning_tokens || 0;
         const write = Number(message.usage?.input_token_details?.cache_creation) || 0;
         const read = Number(message.usage?.input_token_details?.cache_read) || 0;
EOF
@@ -97,6 +97,7 @@
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;

currentTokenUsage.reasoningTokens = message.usage.reasoning_tokens || 0;
const write = Number(message.usage?.input_token_details?.cache_creation) || 0;
const read = Number(message.usage?.input_token_details?.cache_read) || 0;
Copilot is powered by AI and may make mistakes. Always verify output.
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. Error

Insert ⏎·········

Copilot Autofix

AI 5 days ago

To fix the formatting issue on line 107, insert a newline and properly indent the statement assigning to currentTokenUsage.completionTokens. This means that after line 106, you should add a line break so that the assignments to promptTokens and completionTokens are clearly separated and properly formatted. Only modify lines 106 and 107; the logic remains unchanged, ensuring all existing functionality is preserved.


Suggested changeset 1
api/server/services/ConversationCostDynamic.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/api/server/services/ConversationCostDynamic.js b/api/server/services/ConversationCostDynamic.js
--- a/api/server/services/ConversationCostDynamic.js
+++ b/api/server/services/ConversationCostDynamic.js
@@ -104,6 +104,7 @@
         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;
       } else if (message.tokenCount) {
         if (inferredRole === 'assistant') {
EOF
@@ -104,6 +104,7 @@
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;
} else if (message.tokenCount) {
if (inferredRole === 'assistant') {
Copilot is powered by AI and may make mistakes. Always verify output.
getMultipleConversationCosts,
};

const { calculateTokenCost, getModelProvider } = require('./ModelPricing');

Check failure

Code scanning / ESLint

Disallow variable redeclaration Error

'calculateTokenCost' is already defined.

Copilot Autofix

AI 5 days ago

To fix the variable redeclaration error, remove the duplicated declarations from the bottom of the file (calculateTokenCost, getModelProvider, and the second logger). The correct approach is to keep only the initial import and definition at the top (lines 1–8) and delete the duplicated code blocks at lines 251–258. This change will resolve the ESLint error without impacting functionality, as the variables are already declared and can be referenced anywhere in the file. No additional imports, methods, or definitions are necessary because the relevant identifiers are already available globally in the file after their first declaration.

Suggested changeset 1
api/server/services/ConversationCostDynamic.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/api/server/services/ConversationCostDynamic.js b/api/server/services/ConversationCostDynamic.js
--- a/api/server/services/ConversationCostDynamic.js
+++ b/api/server/services/ConversationCostDynamic.js
@@ -248,14 +248,7 @@
   getMultipleConversationCosts,
 };
 
-const { calculateTokenCost, getModelProvider } = require('./ModelPricing');
 
-// Use console for logging to avoid circular dependencies
-const logger = {
-  info: (msg, data) => console.log(msg, data || ''),
-  warn: (msg) => console.warn(msg),
-  error: (msg, error) => console.error(msg, error || ''),
-};
 
 /**
  * Calculate the total cost of a conversation from messages
EOF
@@ -248,14 +248,7 @@
getMultipleConversationCosts,
};

const { calculateTokenCost, getModelProvider } = require('./ModelPricing');

// Use console for logging to avoid circular dependencies
const logger = {
info: (msg, data) => console.log(msg, data || ''),
warn: (msg) => console.warn(msg),
error: (msg, error) => console.error(msg, error || ''),
};

/**
* Calculate the total cost of a conversation from messages
Copilot is powered by AI and may make mistakes. Always verify output.
* @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 Error

'calculateConversationCostFromMessages' is already defined.

Copilot Autofix

AI 5 days ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.

* @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 Error

'getConversationCostDisplayFromMessages' is already defined.

Copilot Autofix

AI 5 days ago

To fix this issue, you need to ensure that the function getConversationCostDisplayFromMessages is defined only once in api/server/services/ConversationCostDynamic.js.

  • First, search through the whole file for multiple definitions of getConversationCostDisplayFromMessages.
  • Remove or rename all but one of the function definitions (choose the definitive implementation to keep, likely the latest or most complete one), or refactor if needed so only one remains.
  • Be careful not to change any other functionality or imports; only remove or rename as needed.
  • If the file also contains tests or calls to multiple versions of this function, update those usages as necessary.
  • As with calculateConversationCostFromMessages (which appears to be defined twice in this file and should undergo similar deduplication), do not leave both in the file as it leads to confusion about which one is actually used.

Suggested changeset 1
api/server/services/ConversationCostDynamic.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/api/server/services/ConversationCostDynamic.js b/api/server/services/ConversationCostDynamic.js
--- a/api/server/services/ConversationCostDynamic.js
+++ b/api/server/services/ConversationCostDynamic.js
@@ -463,44 +463,7 @@
  * @returns {number} returns.totalTokens - Total token count across all messages
  * @returns {Date} returns.lastUpdated - Timestamp of the last message
  */
-function getConversationCostDisplayFromMessages(messages) {
-  try {
-    if (!messages || messages.length === 0) {
-      return null;
-    }
 
-    const costSummary = calculateConversationCostFromMessages(messages);
-    if (!costSummary) {
-      return null;
-    }
-
-    // Format cost for display
-    const formatCost = (cost) => {
-      if (cost < 0.001) {
-        return '<$0.001';
-      }
-      if (cost < 0.01) {
-        return `$${cost.toFixed(4)}`;
-      }
-      if (cost < 1) {
-        return `$${cost.toFixed(3)}`;
-      }
-      return `$${cost.toFixed(2)}`;
-    };
-
-    return {
-      totalCost: formatCost(costSummary.totalCost),
-      totalCostRaw: costSummary.totalCost,
-      primaryModel: costSummary.modelBreakdown[0]?.model || 'Unknown',
-      totalTokens: costSummary.tokenUsage.promptTokens + costSummary.tokenUsage.completionTokens,
-      lastUpdated: costSummary.lastUpdated,
-    };
-  } catch (error) {
-    logger.error('Error getting conversation cost display from messages:', error);
-    return null;
-  }
-}
-
 /**
  * Get costs for multiple conversations in batch
  * @param {string[]} conversationIds - Array of conversation IDs
EOF
@@ -463,44 +463,7 @@
* @returns {number} returns.totalTokens - Total token count across all messages
* @returns {Date} returns.lastUpdated - Timestamp of the last message
*/
function getConversationCostDisplayFromMessages(messages) {
try {
if (!messages || messages.length === 0) {
return null;
}

const costSummary = calculateConversationCostFromMessages(messages);
if (!costSummary) {
return null;
}

// Format cost for display
const formatCost = (cost) => {
if (cost < 0.001) {
return '<$0.001';
}
if (cost < 0.01) {
return `$${cost.toFixed(4)}`;
}
if (cost < 1) {
return `$${cost.toFixed(3)}`;
}
return `$${cost.toFixed(2)}`;
};

return {
totalCost: formatCost(costSummary.totalCost),
totalCostRaw: costSummary.totalCost,
primaryModel: costSummary.modelBreakdown[0]?.model || 'Unknown',
totalTokens: costSummary.tokenUsage.promptTokens + costSummary.tokenUsage.completionTokens,
lastUpdated: costSummary.lastUpdated,
};
} catch (error) {
logger.error('Error getting conversation cost display from messages:', error);
return null;
}
}

/**
* Get costs for multiple conversations in batch
* @param {string[]} conversationIds - Array of conversation IDs
Copilot is powered by AI and may make mistakes. Always verify output.
* @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 Error

'getMultipleConversationCosts' is already defined.

Copilot Autofix

AI 5 days ago

To fix the variable redeclaration error, we must ensure the function getMultipleConversationCosts is only defined once in this file. The error indicates that a previous definition with this name exists. The cleanest way to resolve this without affecting functionality is to rename one of the functions to a distinct, descriptive name. We can do this by renaming the function starting at line 510 and updating all of its internal references accordingly. Additionally, we need to update any places where it is exported or referenced at the bottom of the file.

The changes required are:

  • Rename the function defined at line 510 to a unique name, such as getMultipleConversationCostsBatch.
  • Update the export at line 558 accordingly.

Since we've only been shown the definition and export near the bottom of the file, all changes are confined to this region.


Suggested changeset 1
api/server/services/ConversationCostDynamic.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/api/server/services/ConversationCostDynamic.js b/api/server/services/ConversationCostDynamic.js
--- a/api/server/services/ConversationCostDynamic.js
+++ b/api/server/services/ConversationCostDynamic.js
@@ -507,7 +507,7 @@
  * @param {string} userId - User ID
  * @returns {Object} Map of conversationId to cost display data
  */
-async function getMultipleConversationCosts(conversationIds, userId) {
+async function getMultipleConversationCostsBatch(conversationIds, userId) {
   try {
     const { getMessages } = require('~/models/Message');
     const results = {};
@@ -555,5 +555,5 @@
 module.exports = {
   calculateConversationCostFromMessages,
   getConversationCostDisplayFromMessages,
-  getMultipleConversationCosts,
+  getMultipleConversationCostsBatch,
 };
EOF
@@ -507,7 +507,7 @@
* @param {string} userId - User ID
* @returns {Object} Map of conversationId to cost display data
*/
async function getMultipleConversationCosts(conversationIds, userId) {
async function getMultipleConversationCostsBatch(conversationIds, userId) {
try {
const { getMessages } = require('~/models/Message');
const results = {};
@@ -555,5 +555,5 @@
module.exports = {
calculateConversationCostFromMessages,
getConversationCostDisplayFromMessages,
getMultipleConversationCosts,
getMultipleConversationCostsBatch,
};
Copilot is powered by AI and may make mistakes. Always verify output.

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. Error

Replace ·className="flex·items-center·gap-1·rounded-md·px-2·py-1·text-xs·text-gray-400"·title={t('com\_ui\_conversation\_cost')} with ⏎········className="flex·items-center·gap-1·rounded-md·px-2·py-1·text-xs·text-gray-400"⏎········title={t('com\_ui\_conversation\_cost')}⏎······

Copilot Autofix

AI 5 days ago

To fix the formatting issue, the relevant JSX element (a div) should be reformatted so that each prop is on its own line, after the opening tag and properly indented. In this case, on line 48, spread the className and title props over separate lines inside the opening <div> tag. The rest of the JSX remains unchanged. Only the indentation and line breaks of this tag need adjustment.

Edit only the affected line (line 48) within client/src/components/Chat/ConversationCost.tsx:

  • Break the line after the opening <div.
  • Place each prop on its own line, indented.
  • Close the tag after the last prop.

No additional imports or logic changes are required.

Suggested changeset 1
client/src/components/Chat/ConversationCost.tsx

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/client/src/components/Chat/ConversationCost.tsx b/client/src/components/Chat/ConversationCost.tsx
--- a/client/src/components/Chat/ConversationCost.tsx
+++ b/client/src/components/Chat/ConversationCost.tsx
@@ -45,7 +45,10 @@
 
   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')}>
+      <div
+        className="flex items-center gap-1 rounded-md px-2 py-1 text-xs text-gray-400"
+        title={t('com_ui_conversation_cost')}
+      >
         <span>💰</span>
         <span>$0.00</span>
       </div>
EOF
@@ -45,7 +45,10 @@

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')}>
<div
className="flex items-center gap-1 rounded-md px-2 py-1 text-xs text-gray-400"
title={t('com_ui_conversation_cost')}
>
<span>💰</span>
<span>$0.00</span>
</div>
Copilot is powered by AI and may make mistakes. Always verify output.
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. Error

Replace ·className="flex·items-center·gap-1·rounded-md·px-2·py-1·text-xs·transition-colors·hover:bg-surface-hover"·title={tooltipText} with ⏎······className="flex·items-center·gap-1·rounded-md·px-2·py-1·text-xs·transition-colors·hover:bg-surface-hover"⏎······title={tooltipText}⏎····

Copilot Autofix

AI 5 days ago

To fix this formatting issue, split the <div> opening tag on line 58 so that each prop (className and title) appears on its own line, indented to match the other code in the file. This change will improve readability and comply with the linting instructions. Make sure className and title are each on a new line, indented with four spaces to align with existing code style.

Only one code region in client/src/components/Chat/ConversationCost.tsx requires an edit.

Suggested changeset 1
client/src/components/Chat/ConversationCost.tsx

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/client/src/components/Chat/ConversationCost.tsx b/client/src/components/Chat/ConversationCost.tsx
--- a/client/src/components/Chat/ConversationCost.tsx
+++ b/client/src/components/Chat/ConversationCost.tsx
@@ -55,7 +55,10 @@
   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}>
+    <div
+        className="flex items-center gap-1 rounded-md px-2 py-1 text-xs transition-colors hover:bg-surface-hover"
+        title={tooltipText}
+    >
       <span className="text-text-tertiary">💰</span>
       <span className={`font-medium ${colorClass}`}>{data.totalCost}</span>
     </div>
EOF
@@ -55,7 +55,10 @@
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}>
<div
className="flex items-center gap-1 rounded-md px-2 py-1 text-xs transition-colors hover:bg-surface-hover"
title={tooltipText}
>
<span className="text-text-tertiary">💰</span>
<span className={`font-medium ${colorClass}`}>{data.totalCost}</span>
</div>
Copilot is powered by AI and may make mistakes. Always verify output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants