diff --git a/.changeset/bright-cost-subtotals.md b/.changeset/bright-cost-subtotals.md new file mode 100644 index 0000000000..fdfa3591a1 --- /dev/null +++ b/.changeset/bright-cost-subtotals.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Show partial estimated costs across all Command Center cost views when some model pricing is unavailable. +category: fix +dev: Priced subtotals use a trailing plus sign; entirely unpriced usage remains unavailable. diff --git a/packages/dashboard/app/components/command-center/__tests__/CommandCenter.test.tsx b/packages/dashboard/app/components/command-center/__tests__/CommandCenter.test.tsx index 83f4f424c1..65bba24254 100644 --- a/packages/dashboard/app/components/command-center/__tests__/CommandCenter.test.tsx +++ b/packages/dashboard/app/components/command-center/__tests__/CommandCenter.test.tsx @@ -715,6 +715,18 @@ describe("CommandCenter shell", () => { expect(liveMetricValue("command-center-live-tokens")).toBe("1,234,567,890"); }); + it("shows the priced subtotal in Overview when some usage has unknown pricing", async () => { + mockOverviewApi({ + tokens: { + ...tokenFixture(1_500), + cost: { usd: 911.39004125, unavailable: true, stale: false }, + }, + }); + render(); + + expect(await screen.findByTestId("command-center-stat-tokens")).toHaveTextContent("$911.39+"); + }); + it("live-polls token totals for the Overview card, live strip, and model charts", async () => { vi.useFakeTimers(); let resolvePoll: ((value: ReturnType) => void) | null = null; diff --git a/packages/dashboard/app/components/command-center/areas/TeamArea.tsx b/packages/dashboard/app/components/command-center/areas/TeamArea.tsx index d5f4de3799..601f9be35e 100644 --- a/packages/dashboard/app/components/command-center/areas/TeamArea.tsx +++ b/packages/dashboard/app/components/command-center/areas/TeamArea.tsx @@ -54,7 +54,7 @@ type OrgChartDragState = { }; function costSortValue(cost: CostResult): number { - return cost.unavailable || cost.usd === null ? -1 : cost.usd; + return cost.usd ?? -1; } function agentLabel(agent: TeamAgentSummary, unknownLabel: string): string { diff --git a/packages/dashboard/app/components/command-center/areas/TokensArea.tsx b/packages/dashboard/app/components/command-center/areas/TokensArea.tsx index 358d12360a..265b461c6c 100644 --- a/packages/dashboard/app/components/command-center/areas/TokensArea.tsx +++ b/packages/dashboard/app/components/command-center/areas/TokensArea.tsx @@ -38,7 +38,7 @@ The Tokens detail area is the full-fidelity by-model source of truth: every grou */ function costSortValue(cost: CostResult): number { - return cost.unavailable || cost.usd === null ? -1 : cost.usd; + return cost.usd ?? -1; } function modelGroupIdentity(group: TokenGroupSummary): string { @@ -287,16 +287,12 @@ export function TokensArea({ range, projectId }: { range: DateRange; projectId?: {formatCount(g.cachedTokens)} {formatCount(g.totalTokens)} - {g.cost.unavailable || g.cost.usd === null ? ( - - — - - ) : ( - formatCost(g.cost.usd, g.cost.unavailable) - )} + + {formatCost(g.cost.usd, g.cost.unavailable)} + ))} diff --git a/packages/dashboard/app/components/command-center/areas/WorkflowArea.tsx b/packages/dashboard/app/components/command-center/areas/WorkflowArea.tsx index 885f01a50f..8d4330dc52 100644 --- a/packages/dashboard/app/components/command-center/areas/WorkflowArea.tsx +++ b/packages/dashboard/app/components/command-center/areas/WorkflowArea.tsx @@ -14,7 +14,7 @@ import { WorkflowIcon } from "../../WorkflowIcon"; type SortKey = "workflow" | "tokens" | "cost" | "filesChanged" | "tasksCompleted" | "tasksInProgress" | "tasksInReview"; function costSortValue(cost: CostResult): number { - return cost.unavailable || cost.usd === null ? -1 : cost.usd; + return cost.usd ?? -1; } function workflowLabel(workflow: WorkflowSummary, unknownLabel: string): string { diff --git a/packages/dashboard/app/components/command-center/areas/__tests__/TokensArea.test.tsx b/packages/dashboard/app/components/command-center/areas/__tests__/TokensArea.test.tsx index 480487bf14..543f81ef7e 100644 --- a/packages/dashboard/app/components/command-center/areas/__tests__/TokensArea.test.tsx +++ b/packages/dashboard/app/components/command-center/areas/__tests__/TokensArea.test.tsx @@ -180,6 +180,24 @@ afterEach(() => { }); describe("TokensArea provider model icons", () => { + it("renders a priced subtotal when the aggregate also contains unpriced usage", async () => { + apiMock.mockResolvedValue({ + ...tokenFixture(), + cost: { usd: 11.25, unavailable: true, stale: false }, + groups: [ + { + ...tokenFixture().groups[0], + cost: { usd: 3.5, unavailable: true, stale: false }, + }, + ], + }); + + render(); + + expect(await screen.findByTestId("cc-tokens-cost")).toHaveTextContent("$11.25+"); + expect(screen.getByTestId("cc-tokens-row-claude-sonnet-4-5")).toHaveTextContent("$3.50+"); + }); + it("renders current OpenAI Codex priced costs as dollars instead of the unavailable sentinel", async () => { const usage = { inputTokens: 1_000_000, outputTokens: 200_000, cachedTokens: 500_000, cacheWriteTokens: 100_000 }; const cost = costFor(usage, { provider: "openai-codex", model: "gpt-5.5" }); diff --git a/packages/dashboard/app/components/command-center/areas/__tests__/WorkflowArea.test.tsx b/packages/dashboard/app/components/command-center/areas/__tests__/WorkflowArea.test.tsx index 6bf73566ab..6066330774 100644 --- a/packages/dashboard/app/components/command-center/areas/__tests__/WorkflowArea.test.tsx +++ b/packages/dashboard/app/components/command-center/areas/__tests__/WorkflowArea.test.tsx @@ -112,8 +112,7 @@ describe("WorkflowArea", () => { await screen.findByTestId("cc-area-workflows"); expect(mocks.api).toHaveBeenCalledWith("/command-center/workflows?from=2026-06-08", undefined); expect(screen.getByTestId("cc-workflows-total-tokens").textContent).toContain("1,650"); - expect(screen.getByTestId("cc-workflows-total-cost").textContent).toContain("—"); - expect(screen.getByTestId("cc-workflows-total-cost").textContent).not.toContain("$0"); + expect(screen.getByTestId("cc-workflows-total-cost").textContent).toContain("$4.25+"); expect(screen.getByTestId("cc-workflows-tokens-chart").textContent).toContain("Coding"); const table = screen.getByTestId("cc-workflows-table"); diff --git a/packages/dashboard/app/components/command-center/areas/__tests__/areas.test.tsx b/packages/dashboard/app/components/command-center/areas/__tests__/areas.test.tsx index 73526ebeb1..d6ed8abe0e 100644 --- a/packages/dashboard/app/components/command-center/areas/__tests__/areas.test.tsx +++ b/packages/dashboard/app/components/command-center/areas/__tests__/areas.test.tsx @@ -59,7 +59,7 @@ import { ActivityArea } from "../ActivityArea"; import { EcosystemArea } from "../EcosystemArea"; import { useAnalyticsArea } from "../useAnalyticsArea"; import { ConfirmDialogProvider } from "../../../../hooks/useConfirm"; -import { rangeQuery } from "../areaShared"; +import { formatCost, rangeQuery } from "../areaShared"; import { defaultPresets, rangeFromPreset } from "../../DateRangePicker"; import { activityFixture, @@ -80,6 +80,15 @@ import { tokenFixture, } from "./areas.test-harness"; +describe("Command Center cost formatting", () => { + it("shows priced subtotals when only part of the usage has known pricing", () => { + expect(formatCost(911.39004125, true)).toBe("$911.39+"); + expect(formatCost(12.5, false)).toBe("$12.50"); + expect(formatCost(0, false)).toBe("$0.00"); + expect(formatCost(null, true)).toBe("—"); + }); +}); + beforeEach(() => { apiMock.mockReset(); backfillGithubSourceIssueClosedAtMock.mockReset(); @@ -1394,11 +1403,16 @@ describe("TeamArea", () => { }); it("renders a large comma-grouped total unchanged in the team total tokens stat", async () => { - apiMock.mockResolvedValue(populatedTeamFixture(1_234_567_890)); + const fixture = populatedTeamFixture(1_234_567_890); + apiMock.mockResolvedValue({ + ...fixture, + totals: { ...fixture.totals, cost: { usd: 4.25, unavailable: true, stale: false } }, + }); render(); await screen.findByTestId("cc-area-team"); expect(screen.getByTestId("cc-team-total-tokens").textContent).toContain("1,234,567,890"); + expect(screen.getByTestId("cc-team-total-cost")).toHaveTextContent("$4.25+"); }); it("keeps the team pie safe for single-item and non-finite data", async () => { diff --git a/packages/dashboard/app/components/command-center/areas/areaShared.ts b/packages/dashboard/app/components/command-center/areas/areaShared.ts index e8f0cc309b..6e8a7e5f18 100644 --- a/packages/dashboard/app/components/command-center/areas/areaShared.ts +++ b/packages/dashboard/app/components/command-center/areas/areaShared.ts @@ -45,12 +45,18 @@ export function formatDurationMs(ms: number | null): string { return `${seconds}s`; } -/** Format a USD cost result, returning the unavailable sentinel "—" when unknown. */ +/** + * Format a USD cost result for every Command Center cost surface. + * + * FNXC:CommandCenterCost 2026-07-10-23:20: + * Cost aggregation deliberately preserves the priced subtotal when some usage has unknown pricing. Overview, Tokens, Team, and Workflows must display that subtotal with a trailing `+`; show `—` only when no usage can be priced, and keep an exact priced zero distinct from unavailable data. + */ export function formatCost(usd: number | null, unavailable: boolean): string { - if (unavailable || usd === null || !Number.isFinite(usd)) { + if (usd === null || !Number.isFinite(usd)) { return "—"; } - return `$${usd.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; + const formatted = `$${usd.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; + return unavailable ? `${formatted}+` : formatted; } /** True when the picker's custom range is invalid (from after to). */