Add toggle for usage metrics

This commit is contained in:
Shantur Rathore
2025-11-25 12:26:38 +00:00
parent bf32fcf136
commit 1fd3b2e75c
6 changed files with 46 additions and 13 deletions

View File

@@ -47,6 +47,7 @@ const App: Component = () => {
preferences, preferences,
recordWorkspaceLaunch, recordWorkspaceLaunch,
toggleShowThinkingBlocks, toggleShowThinkingBlocks,
toggleUsageMetrics,
setDiffViewMode, setDiffViewMode,
setToolOutputExpansion, setToolOutputExpansion,
setDiagnosticsExpansion, setDiagnosticsExpansion,
@@ -205,6 +206,7 @@ const App: Component = () => {
const { commands: paletteCommands, executeCommand } = useCommands({ const { commands: paletteCommands, executeCommand } = useCommands({
preferences, preferences,
toggleShowThinkingBlocks, toggleShowThinkingBlocks,
toggleUsageMetrics,
setDiffViewMode, setDiffViewMode,
setToolOutputExpansion, setToolOutputExpansion,
setDiagnosticsExpansion, setDiagnosticsExpansion,

View File

@@ -2,6 +2,7 @@ import { For, Show, createMemo } from "solid-js"
import type { Message, SDKPart, MessageInfo, ClientPart } from "../types/message" import type { Message, SDKPart, MessageInfo, ClientPart } from "../types/message"
import { partHasRenderableText } from "../types/message" import { partHasRenderableText } from "../types/message"
import { formatTokenTotal } from "../lib/formatters" import { formatTokenTotal } from "../lib/formatters"
import { preferences } from "../stores/preferences"
import MessagePart from "./message-part" import MessagePart from "./message-part"
interface MessageItemProps { interface MessageItemProps {
@@ -17,6 +18,7 @@ interface MessageItemProps {
export default function MessageItem(props: MessageItemProps) { export default function MessageItem(props: MessageItemProps) {
const isUser = () => props.message.type === "user" const isUser = () => props.message.type === "user"
const showUsageMetrics = () => preferences().showUsageMetrics ?? true
const timestamp = () => { const timestamp = () => {
const date = new Date(props.message.timestamp) const date = new Date(props.message.timestamp)
return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })
@@ -150,6 +152,9 @@ export default function MessageItem(props: MessageItemProps) {
if (!info || info.role !== "assistant" || !info.tokens) { if (!info || info.role !== "assistant" || !info.tokens) {
return null return null
} }
if (!showUsageMetrics()) {
return null
}
const tokens = info.tokens const tokens = info.tokens
const input = tokens.input ?? 0 const input = tokens.input ?? 0

View File

@@ -545,21 +545,22 @@ export default function MessageStream(props: MessageStreamProps) {
return ( return (
<div class="message-stream-container"> <div class="message-stream-container">
<div class="connection-status"> <div class="connection-status">
<div class="connection-status-text connection-status-info flex flex-wrap items-center gap-2 text-sm font-medium"> <div class="connection-status-text connection-status-info flex flex-wrap items-center gap-2 text-sm font-medium">
<div class="inline-flex items-center gap-1 rounded-full border border-base px-2 py-0.5 text-xs text-primary"> <div class="inline-flex items-center gap-1 rounded-full border border-base px-2 py-0.5 text-xs text-primary">
<span class="uppercase text-[10px] tracking-wide text-primary/70">Used</span> <span class="uppercase text-[10px] tracking-wide text-primary/70">Used</span>
<span class="font-semibold text-primary">{formatTokens(sessionInfo().actualUsageTokens ?? 0)}</span> <span class="font-semibold text-primary">{formatTokens(sessionInfo().actualUsageTokens ?? 0)}</span>
</div>
<div class="inline-flex items-center gap-1 rounded-full border border-base px-2 py-0.5 text-xs text-primary">
<span class="uppercase text-[10px] tracking-wide text-primary/70">Avail</span>
<span class="font-semibold text-primary">
{sessionInfo().contextAvailableTokens !== null ? formatTokens(sessionInfo().contextAvailableTokens ?? 0) : "--"}
</span>
</div>
</div> </div>
<div class="inline-flex items-center gap-1 rounded-full border border-base px-2 py-0.5 text-xs text-primary">
<span class="uppercase text-[10px] tracking-wide text-primary/70">Avail</span>
<span class="font-semibold text-primary">
{sessionInfo().contextAvailableTokens !== null ? formatTokens(sessionInfo().contextAvailableTokens ?? 0) : "--"}
</span>
</div>
</div>
<div class="connection-status-text connection-status-shortcut"> <div class="connection-status-text connection-status-shortcut">
<div class="connection-status-shortcut-action"> <div class="connection-status-shortcut-action">
<button <button
type="button" type="button"

View File

@@ -37,6 +37,7 @@ const ContextUsagePanel: Component<ContextUsagePanelProps> = (props) => {
return value > 0 ? value : 0 return value > 0 ? value : 0
}) })
const formatTokenValue = (value: number | null | undefined) => { const formatTokenValue = (value: number | null | undefined) => {
if (value === null || value === undefined) return "--" if (value === null || value === undefined) return "--"
return formatTokenTotal(value) return formatTokenTotal(value)

View File

@@ -17,6 +17,7 @@ import type { Instance } from "../../types/instance"
export interface UseCommandsOptions { export interface UseCommandsOptions {
preferences: Accessor<Preferences> preferences: Accessor<Preferences>
toggleShowThinkingBlocks: () => void toggleShowThinkingBlocks: () => void
toggleUsageMetrics: () => void
setDiffViewMode: (mode: "split" | "unified") => void setDiffViewMode: (mode: "split" | "unified") => void
setToolOutputExpansion: (mode: ExpansionPreference) => void setToolOutputExpansion: (mode: ExpansionPreference) => void
setDiagnosticsExpansion: (mode: ExpansionPreference) => void setDiagnosticsExpansion: (mode: ExpansionPreference) => void
@@ -421,9 +422,22 @@ export function useCommands(options: UseCommandsOptions) {
}, },
}) })
commandRegistry.register({
id: "token-usage-visibility",
label: () => {
const visible = options.preferences().showUsageMetrics ?? true
return `Token Usage Display · ${visible ? "Visible" : "Hidden"}`
},
description: "Show or hide token and cost stats for assistant messages",
category: "System",
keywords: ["token", "usage", "cost", "stats"],
action: options.toggleUsageMetrics,
})
commandRegistry.register({ commandRegistry.register({
id: "help", id: "help",
label: "Show Help", label: "Show Help",
description: "Display keyboard shortcuts and help", description: "Display keyboard shortcuts and help",
category: "System", category: "System",
keywords: ["/help", "shortcuts", "help"], keywords: ["/help", "shortcuts", "help"],

View File

@@ -35,6 +35,7 @@ export interface Preferences {
diffViewMode: DiffViewMode diffViewMode: DiffViewMode
toolOutputExpansion: ExpansionPreference toolOutputExpansion: ExpansionPreference
diagnosticsExpansion: ExpansionPreference diagnosticsExpansion: ExpansionPreference
showUsageMetrics: boolean
} }
export interface OpenCodeBinary { export interface OpenCodeBinary {
@@ -60,6 +61,7 @@ const defaultPreferences: Preferences = {
diffViewMode: "split", diffViewMode: "split",
toolOutputExpansion: "expanded", toolOutputExpansion: "expanded",
diagnosticsExpansion: "expanded", diagnosticsExpansion: "expanded",
showUsageMetrics: true,
} }
function deepEqual(a: unknown, b: unknown): boolean { function deepEqual(a: unknown, b: unknown): boolean {
@@ -92,6 +94,7 @@ function normalizePreferences(pref?: Partial<Preferences> & { agentModelSelectio
diffViewMode: sanitized.diffViewMode ?? defaultPreferences.diffViewMode, diffViewMode: sanitized.diffViewMode ?? defaultPreferences.diffViewMode,
toolOutputExpansion: sanitized.toolOutputExpansion ?? defaultPreferences.toolOutputExpansion, toolOutputExpansion: sanitized.toolOutputExpansion ?? defaultPreferences.toolOutputExpansion,
diagnosticsExpansion: sanitized.diagnosticsExpansion ?? defaultPreferences.diagnosticsExpansion, diagnosticsExpansion: sanitized.diagnosticsExpansion ?? defaultPreferences.diagnosticsExpansion,
showUsageMetrics: sanitized.showUsageMetrics ?? defaultPreferences.showUsageMetrics,
} }
} }
@@ -270,6 +273,10 @@ function toggleShowThinkingBlocks(): void {
updatePreferences({ showThinkingBlocks: !preferences().showThinkingBlocks }) updatePreferences({ showThinkingBlocks: !preferences().showThinkingBlocks })
} }
function toggleUsageMetrics(): void {
updatePreferences({ showUsageMetrics: !preferences().showUsageMetrics })
}
function addRecentFolder(path: string): void { function addRecentFolder(path: string): void {
updateConfig((draft) => { updateConfig((draft) => {
draft.recentFolders = buildRecentFolderList(path, draft.recentFolders) draft.recentFolders = buildRecentFolderList(path, draft.recentFolders)
@@ -370,6 +377,7 @@ interface ConfigContextValue {
setThemePreference: typeof setThemePreference setThemePreference: typeof setThemePreference
updateConfig: typeof updateConfig updateConfig: typeof updateConfig
toggleShowThinkingBlocks: typeof toggleShowThinkingBlocks toggleShowThinkingBlocks: typeof toggleShowThinkingBlocks
toggleUsageMetrics: typeof toggleUsageMetrics
setDiffViewMode: typeof setDiffViewMode setDiffViewMode: typeof setDiffViewMode
setToolOutputExpansion: typeof setToolOutputExpansion setToolOutputExpansion: typeof setToolOutputExpansion
setDiagnosticsExpansion: typeof setDiagnosticsExpansion setDiagnosticsExpansion: typeof setDiagnosticsExpansion
@@ -400,6 +408,7 @@ const configContextValue: ConfigContextValue = {
setThemePreference, setThemePreference,
updateConfig, updateConfig,
toggleShowThinkingBlocks, toggleShowThinkingBlocks,
toggleUsageMetrics,
setDiffViewMode, setDiffViewMode,
setToolOutputExpansion, setToolOutputExpansion,
setDiagnosticsExpansion, setDiagnosticsExpansion,
@@ -454,6 +463,7 @@ export {
updateConfig, updateConfig,
updatePreferences, updatePreferences,
toggleShowThinkingBlocks, toggleShowThinkingBlocks,
toggleUsageMetrics,
recentFolders, recentFolders,
addRecentFolder, addRecentFolder,
removeRecentFolder, removeRecentFolder,