import React, { memo, useEffect, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; import { useAppTranslation } from '@features/localization/renderer'; import { CARD_ICON_MUTED, CARD_SEPARATOR, CARD_TEXT_LIGHT, COLOR_TEXT_MUTED, TAG_BG, TAG_BORDER, TAG_TEXT, } from '@renderer/constants/cssVariables'; import { formatTokensCompact } from '@renderer/utils/formatters'; // ============================================================================= // Types // ============================================================================= import type { PhaseTokenBreakdown } from '@renderer/types/data'; interface MetricsPillProps { mainSessionImpact?: { callTokens: number; resultTokens: number; totalTokens: number; }; lastUsage?: { input_tokens: number; output_tokens: number; cache_read_input_tokens?: number; cache_creation_input_tokens?: number; }; /** Label override for the right segment (e.g. "Context Window" for team members) */ isolatedLabel?: string; /** Override isolated total (for multi-phase total consumption) */ isolatedOverride?: number; /** Phase breakdown for tooltip (shown when multiple phases exist) */ phaseBreakdown?: PhaseTokenBreakdown[]; } // ============================================================================= // Unified Metrics Pill - Compact monospace pill with tooltip // ============================================================================= export const MetricsPill = memo( ({ mainSessionImpact, lastUsage, isolatedLabel, isolatedOverride, phaseBreakdown, }: Readonly): React.ReactElement | null => { const { t } = useAppTranslation('common'); const [showTooltip, setShowTooltip] = useState(false); const [tooltipStyle, setTooltipStyle] = useState({}); const containerRef = useRef(null); const hideTimeoutRef = useRef | null>(null); const hasMainImpact = mainSessionImpact && mainSessionImpact.totalTokens > 0; const hasIsolated = isolatedOverride != null ? isolatedOverride > 0 : lastUsage && lastUsage.input_tokens + lastUsage.output_tokens > 0; const isolatedTotal = isolatedOverride ?? (lastUsage ? lastUsage.input_tokens + lastUsage.output_tokens + (lastUsage.cache_read_input_tokens ?? 0) + (lastUsage.cache_creation_input_tokens ?? 0) : 0); const hasPhases = phaseBreakdown && phaseBreakdown.length > 1; const clearHideTimeout = (): void => { if (hideTimeoutRef.current) { clearTimeout(hideTimeoutRef.current); hideTimeoutRef.current = null; } }; const handleMouseEnter = (): void => { clearHideTimeout(); setShowTooltip(true); }; const handleMouseLeave = (): void => { clearHideTimeout(); hideTimeoutRef.current = setTimeout(() => setShowTooltip(false), 100); }; useEffect(() => { if (showTooltip && containerRef.current) { const rect = containerRef.current.getBoundingClientRect(); const tooltipWidth = 220; let left = rect.left + rect.width / 2 - tooltipWidth / 2; if (left < 8) left = 8; if (left + tooltipWidth > window.innerWidth - 8) { left = window.innerWidth - tooltipWidth - 8; } setTooltipStyle({ position: 'fixed', bottom: window.innerHeight - rect.top + 6, left, width: tooltipWidth, zIndex: 99999, }); } }, [showTooltip]); useEffect(() => { if (!showTooltip) return; const handleScroll = (): void => setShowTooltip(false); window.addEventListener('scroll', handleScroll, true); return () => window.removeEventListener('scroll', handleScroll, true); }, [showTooltip]); useEffect(() => { return () => clearHideTimeout(); }, []); if (!hasMainImpact && !hasIsolated) { return null; } const mainValue = hasMainImpact ? formatTokensCompact(mainSessionImpact.totalTokens) : null; const isolatedValue = hasIsolated ? formatTokensCompact(isolatedTotal) : null; const rightLabel = isolatedLabel ?? 'Subagent Context'; return ( <>
{mainValue && {mainValue}} {mainValue && isolatedValue && |} {isolatedValue && {isolatedValue}}
{showTooltip && createPortal(
{hasMainImpact && (
{t('chat.subagent.metrics.mainContext')} {mainSessionImpact.totalTokens.toLocaleString()}
)} {hasIsolated && (
{rightLabel} {isolatedTotal.toLocaleString()}
)} {hasPhases && phaseBreakdown.map((phase) => (
{t('chat.subagent.metrics.phase', { phase: phase.phaseNumber })} {formatTokensCompact(phase.peakTokens)} {phase.postCompaction != null && ( {' '} → {formatTokensCompact(phase.postCompaction)} )}
))}
{hasMainImpact && hasIsolated ? 'Left: parent injection · Right: internal' : hasMainImpact ? 'Tokens injected to parent' : 'Internal token usage'}
, document.body )} ); } ); MetricsPill.displayName = 'MetricsPill';