From 97ac52fc6c4d5bc268a1b938d4747f3f6886e2d6 Mon Sep 17 00:00:00 2001 From: Dustin Healy Date: Thu, 21 Aug 2025 02:57:34 -0700 Subject: [PATCH] feat: add toggle for cost tracking --- client/src/components/Chat/CostBar.tsx | 6 +++++- client/src/components/Chat/Messages/ui/MessageRender.tsx | 6 +++--- client/src/components/Messages/ContentRender.tsx | 5 +++-- client/src/components/Nav/SettingsTabs/Chat/Chat.tsx | 7 +++++++ client/src/locales/en/translation.json | 2 ++ client/src/store/settings.ts | 1 + 6 files changed, 21 insertions(+), 6 deletions(-) diff --git a/client/src/components/Chat/CostBar.tsx b/client/src/components/Chat/CostBar.tsx index 8e143d141a..7b2f9dbc97 100644 --- a/client/src/components/Chat/CostBar.tsx +++ b/client/src/components/Chat/CostBar.tsx @@ -1,7 +1,9 @@ +import { useRecoilValue } from 'recoil'; import { ArrowIcon } from '@librechat/client'; import type { TConversationCosts } from 'librechat-data-provider'; import { useLocalize } from '~/hooks'; import { cn } from '~/utils'; +import store from '~/store'; interface CostBarProps { conversationCosts: TConversationCosts; @@ -10,7 +12,9 @@ interface CostBarProps { export default function CostBar({ conversationCosts, showCostBar }: CostBarProps) { const localize = useLocalize(); - if (!conversationCosts || !conversationCosts.totals) { + const showCostTracking = useRecoilValue(store.showCostTracking); + + if (!showCostTracking || !conversationCosts || !conversationCosts.totals) { return null; } diff --git a/client/src/components/Chat/Messages/ui/MessageRender.tsx b/client/src/components/Chat/Messages/ui/MessageRender.tsx index e889d1feab..59bc42d042 100644 --- a/client/src/components/Chat/Messages/ui/MessageRender.tsx +++ b/client/src/components/Chat/Messages/ui/MessageRender.tsx @@ -64,10 +64,10 @@ const MessageRender = memo( }); const maximizeChatSpace = useRecoilValue(store.maximizeChatSpace); const fontSize = useRecoilValue(store.fontSize); - const convoId = conversation?.conversationId ?? ''; + const showCostTracking = useRecoilValue(store.showCostTracking); const perMessageCost = useMemo(() => { - if (!costs || !costs.perMessage || !msg?.messageId) { + if (!showCostTracking || !costs || !costs.perMessage || !msg?.messageId) { return null; } const entry = costs.perMessage.find((p) => p.messageId === msg.messageId); @@ -75,7 +75,7 @@ const MessageRender = memo( return null; } return entry; - }, [costs, msg?.messageId]); + }, [showCostTracking, costs, msg?.messageId]); const handleRegenerateMessage = useCallback(() => regenerateMessage(), [regenerateMessage]); const hasNoChildren = !(msg?.children?.length ?? 0); diff --git a/client/src/components/Messages/ContentRender.tsx b/client/src/components/Messages/ContentRender.tsx index bb5cb332a6..ae0ae1613a 100644 --- a/client/src/components/Messages/ContentRender.tsx +++ b/client/src/components/Messages/ContentRender.tsx @@ -66,13 +66,14 @@ const ContentRender = memo( }); const maximizeChatSpace = useRecoilValue(store.maximizeChatSpace); const fontSize = useRecoilValue(store.fontSize); + const showCostTracking = useRecoilValue(store.showCostTracking); const perMessageCost = useMemo(() => { - if (!costs || !costs.perMessage || !msg?.messageId) { + if (!showCostTracking || !costs || !costs.perMessage || !msg?.messageId) { return null; } return costs.perMessage.find((p) => p.messageId === msg.messageId) ?? null; - }, [costs, msg?.messageId]); + }, [showCostTracking, costs, msg?.messageId]); const handleRegenerateMessage = useCallback(() => regenerateMessage(), [regenerateMessage]); const isLast = useMemo( diff --git a/client/src/components/Nav/SettingsTabs/Chat/Chat.tsx b/client/src/components/Nav/SettingsTabs/Chat/Chat.tsx index 70858a9b72..efbb9b0ab5 100644 --- a/client/src/components/Nav/SettingsTabs/Chat/Chat.tsx +++ b/client/src/components/Nav/SettingsTabs/Chat/Chat.tsx @@ -76,6 +76,13 @@ const toggleSwitchConfigs = [ hoverCardText: undefined, key: 'modularChat', }, + { + stateAtom: store.showCostTracking, + localizationKey: 'com_nav_show_cost_tracking', + switchId: 'showCostTracking', + hoverCardText: 'com_nav_info_show_cost_tracking', + key: 'showCostTracking', + }, ]; function Chat() { diff --git a/client/src/locales/en/translation.json b/client/src/locales/en/translation.json index 12c24adccd..edb6665938 100644 --- a/client/src/locales/en/translation.json +++ b/client/src/locales/en/translation.json @@ -568,6 +568,8 @@ "com_nav_settings": "Settings", "com_nav_shared_links": "Shared links", "com_nav_show_code": "Always show code when using code interpreter", + "com_nav_show_cost_tracking": "Show cost tracking", + "com_nav_info_show_cost_tracking": "Display conversation costs and per-message cost breakdowns", "com_nav_show_thinking": "Open Thinking Dropdowns by Default", "com_nav_slash_command": "/-Command", "com_nav_slash_command_description": "Toggle command \"/\" for selecting a prompt via keyboard", diff --git a/client/src/store/settings.ts b/client/src/store/settings.ts index 0fe4dccd2c..9f5bdc7014 100644 --- a/client/src/store/settings.ts +++ b/client/src/store/settings.ts @@ -34,6 +34,7 @@ const localStorageAtoms = { showCode: atomWithLocalStorage(LocalStorageKeys.SHOW_ANALYSIS_CODE, true), saveDrafts: atomWithLocalStorage('saveDrafts', true), showScrollButton: atomWithLocalStorage('showScrollButton', true), + showCostTracking: atomWithLocalStorage('showCostTracking', true), forkSetting: atomWithLocalStorage('forkSetting', ''), splitAtTarget: atomWithLocalStorage('splitAtTarget', false), rememberDefaultFork: atomWithLocalStorage(LocalStorageKeys.REMEMBER_FORK_OPTION, false),