@@ -332,6 +348,28 @@
+ {#if providerID === "grok-build"}
+
+
+
+ {$_("usage.reportedCost")}
+ {#if report.summary.reported_cost_status !== "reported"}{report.summary.reported_cost_coverage > 0 ? $_("usage.reportedCostStatus.partial") : $_("usage.reportedCostStatus.unavailable")}{/if}
+
+
+ {report.summary.reported_cost_coverage > 0 ? formatReportedCurrency(report.summary.known_reported_cost_usd) : "—"}
+
+
+ {#if report.summary.reported_cost_status === "reported"}
+ {$_("usage.reportedCostSource")}
+ {:else if report.summary.reported_cost_coverage > 0}
+ {$_("usage.reportedCostCoverage", { values: { coverage: formatPercent(report.summary.reported_cost_coverage) } })}
+ {:else}
+ {$_("usage.reportedCostUnavailable")}
+ {/if}
+
+
+
+ {/if}
{$_("usage.sessions")}
@@ -351,7 +389,8 @@
{$_("usage.trendTitle")}
- {$_("usage.chart.cost")}
+ {providerID === "grok-build" ? $_("usage.chart.apiCost") : $_("usage.chart.cost")}
+ {#if providerID === "grok-build"}{$_("usage.chart.reportedCost")}{/if}
{$_("usage.chart.tokens")}
@@ -363,7 +402,7 @@
{$_("usage.modelsTitle")}
-
+
{/if}
{/if}
diff --git a/desktop/frontend/src/features/usage/UsageTrendChart.svelte b/desktop/frontend/src/features/usage/UsageTrendChart.svelte
index b3c99ae..f1c5459 100644
--- a/desktop/frontend/src/features/usage/UsageTrendChart.svelte
+++ b/desktop/frontend/src/features/usage/UsageTrendChart.svelte
@@ -5,7 +5,7 @@
import { currentDesktopLocale, translate } from "$lib/i18n";
- type UsageMetric = "cost" | "tokens";
+ type UsageMetric = "cost" | "reported" | "tokens";
type TooltipSource = "pointer" | "focus";
type TooltipState = {
index: number;
@@ -58,15 +58,27 @@
}
function metricValue(point: UsageTrendPoint): number {
- if (metric === "cost") return costValue(point);
+ if (metric !== "tokens") return costValue(point);
return point.summary.fresh_input_tokens + point.summary.cached_input_tokens + point.summary.output_tokens;
}
function costValue(point: UsageTrendPoint): number {
- const value = Number(point.summary.known_estimated_cost_usd);
+ const value = Number(metric === "reported" ? point.summary.known_reported_cost_usd : point.summary.known_estimated_cost_usd);
return Number.isFinite(value) ? Math.max(0, value) : 0;
}
+ function chartTitle(): string {
+ if (metric === "cost") return translate("usage.chart.costTitle");
+ if (metric === "reported") return translate("usage.chart.reportedCostTitle");
+ return translate("usage.chart.tokenTitle");
+ }
+
+ function chartDescription(): string {
+ if (metric === "cost") return translate("usage.chart.costDescription");
+ if (metric === "reported") return translate("usage.chart.reportedCostDescription");
+ return translate("usage.chart.tokenDescription");
+ }
+
function segmentHeight(value: number): number {
return Math.max(0, value / maximum * plotHeight);
}
@@ -81,7 +93,7 @@
style: "currency",
currency: "USD",
minimumFractionDigits: 0,
- maximumFractionDigits: value > 0 && value < 0.01 ? 6 : 2,
+ maximumFractionDigits: metric === "reported" ? 10 : value > 0 && value < 0.01 ? 6 : 2,
}).format(value);
}
@@ -107,6 +119,17 @@
}).format(parsed);
}
+ function formatReportedCurrency(value: string): string {
+ const parsed = Number(value);
+ if (!Number.isFinite(parsed)) return value;
+ return new Intl.NumberFormat(currentDesktopLocale(), {
+ style: "currency",
+ currency: "USD",
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 10,
+ }).format(parsed);
+ }
+
function formatPercent(value: number): string {
return new Intl.NumberFormat(currentDesktopLocale(), {
style: "percent",
@@ -180,6 +203,16 @@
coverage: formatPercent(point.summary.pricing_coverage),
});
}
+ if (metric === "reported") {
+ const key = point.summary.partial_reported_cost_event_count > 0
+ ? "usage.chart.partialReportedCostBucketAria"
+ : "usage.chart.reportedCostBucketAria";
+ return translate(key, {
+ bucket: fullBucketLabel(point.start_unix_ms),
+ cost: formatReportedCurrency(point.summary.known_reported_cost_usd),
+ coverage: formatPercent(point.summary.reported_cost_coverage),
+ });
+ }
return translate("usage.chart.tokenBucketAria", {
bucket: fullBucketLabel(point.start_unix_ms),
fresh: formatInteger(point.summary.fresh_input_tokens),
@@ -286,8 +319,8 @@
{/if}