diff --git a/packages/app/src/components/context-window-meter.tsx b/packages/app/src/components/context-window-meter.tsx index 4ea10a936b..d41ca87528 100644 --- a/packages/app/src/components/context-window-meter.tsx +++ b/packages/app/src/components/context-window-meter.tsx @@ -3,6 +3,7 @@ import Svg, { Circle } from "react-native-svg"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; import { useTranslation } from "react-i18next"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; +import { ContextWindowUsageTooltip } from "@/usage/context-window-section"; import { formatContextPercentage, formatTokenCount } from "./context-window-meter.utils"; interface ContextWindowMeterProps { @@ -10,6 +11,8 @@ interface ContextWindowMeterProps { usedTokens: number | null; totalCostUsd?: number | null; showPercentage?: boolean; + serverId?: string; + agentId?: string; /** Reserve the meter footprint and show a loading ring while usage is pending. */ pending?: boolean; /** Optional glyph envelope for icon-toolbar alignment. */ @@ -95,6 +98,8 @@ export function ContextWindowMeter({ usedTokens, totalCostUsd, showPercentage = false, + serverId, + agentId, pending = false, glyphSize, }: ContextWindowMeterProps) { @@ -104,13 +109,9 @@ export function ContextWindowMeter({ maxTokens !== null && usedTokens !== null ? getUsagePercentage(maxTokens, usedTokens) : null; const geometry = getMeterGeometry(showPercentage, glyphSize); - // No usage yet: reserve the footprint with a track-only ring while a session is - // active so the real ring fades in without shifting siblings. Render nothing when - // no usage is expected. + // No context telemetry yet: reserve the meter footprint while it is pending. if (percentage === null || maxTokens === null || usedTokens === null) { - if (!pending) { - return null; - } + if (!pending) return null; return ( ) : null} + {serverId && agentId ? ( + + ) : null} diff --git a/packages/app/src/composer/index.tsx b/packages/app/src/composer/index.tsx index 6cf9136c20..65ca01b0bb 100644 --- a/packages/app/src/composer/index.tsx +++ b/packages/app/src/composer/index.tsx @@ -289,7 +289,7 @@ function renderContextWindowMeter( glyphSize: number, ): ReactElement | null { const hasData = contextWindowMaxTokens !== null && contextWindowUsedTokens !== null; - if (!hasData && !pending && !showPercentage) { + if (!hasData && !pending) { return null; } return ( diff --git a/packages/app/src/usage/balance-bar.tsx b/packages/app/src/usage/balance-bar.tsx index 2e5302c938..cf6f5929fa 100644 --- a/packages/app/src/usage/balance-bar.tsx +++ b/packages/app/src/usage/balance-bar.tsx @@ -12,11 +12,7 @@ interface ResolvedBalance { usedPct: number | null; } -function resolveBalance( - balance: UsageBalance, - t: TFunction, - locale?: string, -): ResolvedBalance { +function resolveBalance(balance: UsageBalance, t: TFunction, locale?: string): ResolvedBalance { const { used, remaining, limit, unit } = balance; const format = (value: number) => formatAmount(value, unit, locale); if (limit != null && limit > 0) { diff --git a/packages/app/src/usage/context-window-section.tsx b/packages/app/src/usage/context-window-section.tsx new file mode 100644 index 0000000000..81f1e29746 --- /dev/null +++ b/packages/app/src/usage/context-window-section.tsx @@ -0,0 +1,34 @@ +import { View } from "react-native"; +import { StyleSheet } from "react-native-unistyles"; +import { UsageCard } from "./card"; +import { useUsagePreferences } from "./display"; +import { useAgentUsage } from "./queries"; + +/** The active agent's usage inside its context-window tooltip. */ +export function ContextWindowUsageTooltip({ + serverId, + agentId, +}: { + serverId: string; + agentId: string; +}) { + const { entry } = useAgentUsage(serverId, agentId); + const { display } = useUsagePreferences(); + if (!entry) return null; + + return ( + <> + + + + ); +} + +const styles = StyleSheet.create((theme) => ({ + divider: { + height: 1, + backgroundColor: theme.colors.borderAccent, + marginVertical: theme.spacing[2], + marginHorizontal: -theme.spacing[2], + }, +}));