/** * SessionContextHeader - Header component with title, help tooltip, and token stats. */ import React from 'react'; import { useAppTranslation } from '@features/localization/renderer'; import { COLOR_BORDER, COLOR_BORDER_SUBTLE, COLOR_SURFACE_OVERLAY, COLOR_TEXT, COLOR_TEXT_MUTED, COLOR_TEXT_SECONDARY, } from '@renderer/constants/cssVariables'; import { formatCostUsd } from '@shared/utils/costFormatting'; import { ArrowDownWideNarrow, FileText, LayoutList, X } from 'lucide-react'; import { formatTokens } from '../utils/formatting'; import { SessionContextHelpTooltip } from './SessionContextHelpTooltip'; import type { ContextViewMode } from '../types'; import type { ContextPhaseInfo } from '@renderer/types/contextInjection'; import type { SessionMetrics } from '@shared/types'; import type { DerivedContextMetrics } from '@shared/utils/contextMetrics'; interface SessionContextHeaderProps { injectionCount: number; totalTokens: number; contextMetrics?: DerivedContextMetrics; sessionMetrics?: SessionMetrics; subagentCostUsd?: number; onClose?: () => void; onViewReport?: () => void; phaseInfo?: ContextPhaseInfo; selectedPhase: number | null; onPhaseChange: (phase: number | null) => void; viewMode: ContextViewMode; onViewModeChange: (mode: ContextViewMode) => void; } export const SessionContextHeader = ({ injectionCount, totalTokens, contextMetrics, sessionMetrics, subagentCostUsd, onClose, onViewReport, phaseInfo, selectedPhase, onPhaseChange, viewMode, onViewModeChange, }: Readonly): React.ReactElement => { const { t } = useAppTranslation('common'); const formatPercentLabel = (percent: number | null, suffix: string): string | null => { if (percent === null) { return null; } return `${percent.toFixed(1)}% ${suffix}`; }; const renderMetricValue = ( label: string, tokens: number | null, percentLabel: string | null, options?: { approximate?: boolean; unavailableLabel?: string; } ): React.ReactElement => (
{label}
{tokens === null ? (options?.unavailableLabel ?? t('sessionContext.metrics.unavailable')) : `${options?.approximate ? '~' : ''}${formatTokens(tokens)}`}
{percentLabel && (
{percentLabel}
)}
); const codexTelemetryUnavailable = contextMetrics?.providerId === 'codex' && contextMetrics.promptInputSource === 'unavailable'; return (
{/* Title row */}

{t('sessionContext.header.title')}

{injectionCount}
{onClose && ( )}
{/* Primary metrics */}
{renderMetricValue( t('sessionContext.metrics.contextUsed'), contextMetrics?.contextUsedTokens ?? null, formatPercentLabel( contextMetrics?.contextUsedPercentOfContextWindow ?? null, t('sessionContext.metrics.ofContext') ) )} {renderMetricValue( t('sessionContext.metrics.promptInput'), contextMetrics?.promptInputTokens ?? null, formatPercentLabel( contextMetrics?.promptInputPercentOfContextWindow ?? null, t('sessionContext.metrics.ofContext') ) )} {renderMetricValue( t('sessionContext.metrics.visibleContext'), totalTokens, formatPercentLabel( contextMetrics?.visibleContextPercentOfPromptInput ?? null, t('sessionContext.metrics.ofPrompt') ), { approximate: true } )}
{codexTelemetryUnavailable && (
{t('sessionContext.metrics.codexTelemetryUnavailable')}
)} {/* Session Metrics Breakdown */} {sessionMetrics && (
{/* Cost */} {sessionMetrics.costUsd !== undefined && sessionMetrics.costUsd > 0 && (
{t('sessionContext.metrics.sessionCost')}{' '} {formatCostUsd(sessionMetrics.costUsd + (subagentCostUsd ?? 0))} {subagentCostUsd !== undefined && subagentCostUsd > 0 && ( {' ('} {formatCostUsd(sessionMetrics.costUsd)} {` ${t('sessionContext.metrics.parentPlus')} `} {formatCostUsd(subagentCostUsd)} {` ${t('sessionContext.metrics.subagents')}`} {onViewReport && ( <> {' ยท '} )} {')'} )}
)}
)} {/* Phase selector - only shown when compactions exist */} {phaseInfo && phaseInfo.phases.length > 1 && (
{t('sessionContext.header.phase')} {phaseInfo.phases.map((phase) => ( ))}
)} {/* View mode toggle */}
{t('sessionContext.header.view')}
); };