Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions src/lib/rateLimits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,18 @@ export const DEFAULT_RATE_LIMITS: RateLimitsConfig = {
// numbers the member portal publishes.
//
// contextTokens mirrors the backend EXACTLY: 1,048,576, raised from 500,000
// on 2026-09-10 and exactly what the Novita primary serves. It renders as
// "1M" because formatTokens rounds the display, which is the layer that
// should do it — publishing a rounded 1,000,000 here would leave the site
// 4.8% below the source it claims to mirror, and would turn the test below
// from an equality into a floor. The equality is the mechanism: it is what
// makes a backend change fail here instead of shipping quietly.
// on 2026-09-10. It equals the Novita primary's `context_size`, which
// covers input AND OUTPUT together — so it is the provider's total budget,
// not a servable input window: a prompt at the very top leaves no room for
// the reply. Nothing filters for that on our side, so a caller who uses the
// full figure gets the provider's error on a number this page publishes.
//
// It renders as "1M" because formatTokens rounds the display down, which is
// the layer that should do it. Publishing a rounded 1,000,000 here instead
// would leave the site 4.8% below the source it claims to mirror, and would
// turn the test below from an equality into a floor. The equality is the
// mechanism: it is what makes a backend change fail here instead of
// shipping quietly.
windowedModels: [
{
model: 'glm5.3',
Expand Down Expand Up @@ -103,9 +109,17 @@ export function formatTokens(tokens: number, lang: DocsLocale = 'en'): string {
// side. Rounding the DISPLAY is the right layer: the published constant
// stays equal to the backend, so the test below can keep asserting
// equality rather than a floor.
//
// `roundingMode: 'floor'` because this page is read by people who have not
// paid yet, so it must never advertise MORE than the backend allows.
// Truncating alone is not the default: `maximumFractionDigits` ROUNDS, so
// 1.5M would have printed "2M". Harmless at today's 1,048,576, and the
// exact trap the member portal already guards against with Math.floor —
// the guard belonged on the more public surface too.
const fmt = new Intl.NumberFormat(lang === 'es' ? 'es-ES' : 'en-US', {
useGrouping: 'always',
maximumFractionDigits: 0,
roundingMode: 'floor',
});
if (tokens >= 1_000_000) return `${fmt.format(tokens / 1_000_000)}M`;
if (tokens >= 1_000) return `${fmt.format(tokens / 1_000)}K`;
Expand Down
25 changes: 25 additions & 0 deletions src/tests/lib/rateLimits.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
windowedModelBody,
windowedModelHeadline,
windowedModelNote,
formatTokens,
} from '../../lib/rateLimits';

/**
Expand All @@ -32,6 +33,30 @@ const GLM = {
periodCapTokens: 3_000_000_000,
};

describe('formatTokens rounds DOWN', () => {
// 1_500_000, not the live 1_048_576: the live value renders "1M" whether
// the formatter floors or rounds, so an assert on it cannot fail if the
// guard is removed. This is the smallest value that tells them apart.
//
// It matters more here than in the member portal. `roundingMode` is an
// Intl.NumberFormat option, and a runtime that does not support it IGNORES
// IT SILENTLY — no error, just rounding again. So this is not "is the word
// still in the source", it is "does this runtime actually floor", and only
// an assert can answer that.
it('never advertises more than the backend allows', () => {
expect(formatTokens(1_500_000)).toBe('1M');
expect(formatTokens(1_900_000)).toBe('1M');
expect(formatTokens(1_500_000, 'es')).toBe('1M');
});

it('leaves the other published figures untouched', () => {
expect(formatTokens(1_048_576)).toBe('1M');
expect(formatTokens(3_000_000_000)).toBe('3,000M');
expect(formatTokens(3_000_000_000, 'es')).toBe('3.000M');
expect(formatTokens(400_000_000)).toBe('400M');
});
});

describe('rateLimits — glm5.3 windowed limits', () => {
const glm = DEFAULT_RATE_LIMITS.windowedModels.find((m) => m.model === 'glm5.3');

Expand Down
Loading