import { Gauge } from "lucide-react"; import { useTranslation } from "react-i18next"; import { I18nKey } from "#/i18n/declaration"; import { ConversationTabEmptyState } from "#/components/features/conversation/conversation-tab-empty-state"; import { useLiveConversationMetrics } from "#/hooks/use-live-conversation-metrics"; import { useActiveConversation } from "#/hooks/query/use-active-conversation"; import { CostSection } from "../metrics-modal/cost-section"; import { UsageSection } from "../metrics-modal/usage-section"; import { CompactContextButton } from "./compact-context-button"; import { ContextMeter } from "./context-meter"; import { ProviderBalanceCard } from "./provider-balance-card"; import { getContextWindowUsagePercentage } from "#/utils/format-token-count"; /** * "Usage" right-panel tab: context-fill meter with a manual "Compact * context" action, accumulated token/cost stats, and the provider credit * balance (when the agent server reports one). * * Metrics come from {@link useLiveConversationMetrics}: live WebSocket * updates plus a 30s REST poll while the tab is mounted. */ export function UsagePanel() { const { t } = useTranslation("openhands"); const metrics = useLiveConversationMetrics(); const { data: conversation } = useActiveConversation(); // ACP conversations (e.g. Claude Code) draw on the CLI's own subscription // plan; the dollar figure is an API-equivalent estimate, not a bill. const isAcp = conversation?.agent_kind === "acp"; const { usage } = metrics; const hasMetrics = metrics.cost !== null || usage !== null; if (!hasMetrics) { return ( }> {t(I18nKey.CONVERSATION$NO_METRICS)} ); } return (
{usage !== null && (
)}
{t(I18nKey.CONVERSATION$TOKEN_USAGE)}
{isAcp && ( {t(I18nKey.CONVERSATION$PLAN_USAGE_NOTE)} )} {usage !== null && }
); }