/**
* TokenUsage — Token 统计面板
*
* 始终展示完整结构,无会话时显示零值。
* 固定在详情面板中部,高度由内容自然决定。
*/
import { Box, Typography, Stack, Table, TableBody, TableRow, TableCell } from '@mui/material';
import { Zap } from 'lucide-react';
import { useAgentStore } from '@renderer/stores/agent-store';
import { formatTokens } from '@renderer/lib/formatters';
// v0.7.4 P3-1: 文案出层(字典含注册副作用,须在 t() 使用前 import)
import { t } from '@renderer/lib/i18n';
import '@renderer/lib/i18n-strings';
export function TokenUsage(): React.JSX.Element {
const tokenUsage = useAgentStore((s) => s.tokenUsage);
const maxIterations = useAgentStore((s) => s.maxIterations);
const currentIteration = useAgentStore((s) => s.currentIteration);
const contextWindow = useAgentStore((s) => s.contextWindow);
const maxTokens = contextWindow;
// v0.3.18 修复: 上下文占用百分比改用 lastInputTokens(单次占用),而非累计 totalTokens
// 之前 totalTokens 是所有轮次累加值,除以单次窗口得出无意义的百分比
const contextPercent =
maxTokens > 0 && tokenUsage.lastInputTokens > 0
? Math.min((tokenUsage.lastInputTokens / maxTokens) * 100, 100)
: 0;
// 累计消耗的输入/输出占比(用于进度条展示累计消耗的构成)
const inputPercent =
tokenUsage.totalTokens > 0 ? (tokenUsage.inputTokens / tokenUsage.totalTokens) * 100 : 0;
return (
{/* 标题 */}
{t('trace.token.usage')}
{/* 进度条 */}
{/* 数值卡片 */}
{/* 底部汇总 */}
{t('trace.token.total')}
{tokenUsage.totalTokens > 0 ? formatTokens(tokenUsage.totalTokens) : '-'}
{t('trace.token.context')}
80
? 'error.main'
: contextPercent > 60
? 'warning.main'
: 'text.secondary',
}}
>
{tokenUsage.lastInputTokens > 0
? `${formatTokens(tokenUsage.lastInputTokens)} (${contextPercent.toFixed(1)}%)`
: '-'}
{tokenUsage.lastCompressedSaved > 0 && (
{t('trace.token.compressedSaved')}
{formatTokens(tokenUsage.lastCompressedSaved)}
)}
迭代
{currentIteration} / {maxIterations}
);
}
function StatCard({ label, value, color }: { label: string; value: string; color: string }) {
return (
{label}
{value}
);
}