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 (
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],
+ },
+}));