Files
fusion/packages/dashboard/app/utils/__tests__/estimateChatTokens.test.ts
gsxdsm c468c161c2 FN-7141: add chat context token budget indicator
Add a desktop Direct-chat header indicator for estimated tokens used against the active model context window.

- Estimate chat token usage client-side, including streaming text, and format compact counts.
- Render the context-window badge only for non-mobile Direct-chat threads with known model context windows.
- Cover desktop, mobile, floating-narrow, rooms, unknown-context, and streaming surfaces with tests.
- Document the dashboard behavior and add a release changeset.

Files changed:
 .changeset/fn-7141-chat-context-window.md          |   7 +
 docs/dashboard-guide.md                            |   2 +
 packages/dashboard/app/components/ChatView.css     |  22 +++
 packages/dashboard/app/components/ChatView.tsx     |  35 +++-
 .../__tests__/ChatView.context-window.test.tsx     | 193 +++++++++++++++++++++
 .../app/utils/__tests__/estimateChatTokens.test.ts |  34 ++++
 packages/dashboard/app/utils/estimateChatTokens.ts |  29 ++++
 packages/i18n/locales/en/app.json                  |   1 +
 8 files changed, 322 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-7141

Fusion-Task-Lineage: 3ede9af4-b8d6-4da6-996f-cd9277ef49ac

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-27 17:22:12 -07:00

35 lines
1.1 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { estimateChatTokens, formatTokenCount } from "../estimateChatTokens";
describe("estimateChatTokens", () => {
it("returns 0 for empty input", () => {
expect(estimateChatTokens([])).toBe(0);
});
it("sums multiple message contents with a four-character heuristic", () => {
expect(estimateChatTokens([{ content: "abcd" }, { content: "abcdefgh" }])).toBe(3);
});
it("includes streaming text in the estimate", () => {
expect(estimateChatTokens([{ content: "abcd" }], "abcdefgh")).toBe(3);
});
it("guards against null or undefined content", () => {
expect(estimateChatTokens([{ content: null }, {}, { content: "abcde" }])).toBe(2);
});
});
describe("formatTokenCount", () => {
it("renders sub-1k counts without a suffix", () => {
expect(formatTokenCount(980)).toBe("980");
});
it("renders one-decimal compact thousands below 10k", () => {
expect(formatTokenCount(1234)).toBe("~1.2k");
});
it("rounds larger thousands without a decimal", () => {
expect(formatTokenCount(200_000)).toBe("200k");
});
});