general-eval-card / tests /transformations /params-parsing.test.ts
Jenny Chim
Deploy DuckDB-backed frontend to
da8db3e
Raw
History Blame
25.1 kB
import { describe, expect, it } from "vitest"
// Executable spec for `notes/transformations/10-params-parsing.md`.
//
// Five implementations of params-billions parsing exist in TS:
// - Variant A: lib/model-data.ts:312-354 (parseParamsBillions)
// - Variant B: components/eval-detail.tsx:81-119 (parseParamsBillionsFromText)
// - Variant C: components/eval-detail.tsx:121-155 (parseParamsBillionsFromModelName)
// - Variant D: components/eval-detail.tsx:157-184 (getParamsBillionsFromModelInfo β€” orchestrator)
// - Variant E: components/model-compare-dialog.tsx:44-60 (parseParamsBillionsFromModelName)
// - Variant F: app/evals/[id]/page.tsx:434-437 (inline regex on `name + " " + id`)
//
// They DIVERGE on edge cases (units accepted, anchoring, fallback chains, ≀0 handling)
// but converge on the most common production inputs (clean "7B" / "34.389" strings).
// Migration target: pipeline emits a single canonical numeric `params_billions` per
// model-result; all five parsers delete.
// === Variant A: lib/model-data.ts:312 ===
function parseParamsBillions(value: unknown): number | null {
if (typeof value === "number") {
return Number.isFinite(value) && value > 0 ? value : null
}
if (typeof value !== "string") return null
const normalized = value.trim().toLowerCase()
if (!normalized) return null
const compact = normalized.replace(/,/g, "")
const tokenMatch = compact.match(/(\d+(?:\.\d+)?)\s*(trillion|tn|t|billion|bn|b|million|mn|m|thousand|k)\b/)
if (tokenMatch) {
const amount = Number.parseFloat(tokenMatch[1])
if (!Number.isFinite(amount) || amount <= 0) return null
const unit = tokenMatch[2]
if (unit === "trillion" || unit === "tn" || unit === "t") return amount * 1000
if (unit === "billion" || unit === "bn" || unit === "b") return amount
if (unit === "million" || unit === "mn" || unit === "m") return amount / 1000
if (unit === "thousand" || unit === "k") return amount / 1_000_000
}
const numeric = Number.parseFloat(compact)
return Number.isFinite(numeric) && numeric > 0 ? numeric : null
}
// === Variant B: components/eval-detail.tsx:81 ===
function parseParamsBillionsFromText(value: string | null | undefined): number | null {
if (!value) return null
const normalized = value.trim().toLowerCase()
if (!normalized) return null
const compact = normalized.replace(/,/g, "")
const tokenMatch = compact.match(/(\d+(?:\.\d+)?)\s*(trillion|tn|t|billion|bn|b|million|mn|m|thousand|k)\b/)
if (tokenMatch) {
const amount = Number.parseFloat(tokenMatch[1])
if (!Number.isFinite(amount)) return null
const unit = tokenMatch[2]
if (unit === "trillion" || unit === "tn" || unit === "t") return amount * 1000
if (unit === "billion" || unit === "bn" || unit === "b") return amount
if (unit === "million" || unit === "mn" || unit === "m") return amount / 1000
if (unit === "thousand" || unit === "k") return amount / 1_000_000
}
const numeric = Number.parseFloat(compact)
return Number.isFinite(numeric) ? numeric : null
}
// === Variant C: components/eval-detail.tsx:121 ===
function parseParamsBillionsFromModelNameC(modelName: string | null | undefined): number | null {
if (!modelName) return null
const sizeTokens = Array.from(modelName.matchAll(/\b(\d+(?:\.\d+)?)\s*([tmbk])\b/gi))
if (sizeTokens.length === 0) return null
const lastToken = sizeTokens[sizeTokens.length - 1]
const numericValue = Number.parseFloat(lastToken[1])
if (!Number.isFinite(numericValue)) return null
const unit = lastToken[2].toLowerCase()
if (unit === "t") return numericValue * 1000
if (unit === "b") return numericValue
if (unit === "m") return numericValue / 1000
if (unit === "k") return numericValue / 1_000_000
return null
}
// === Variant E: components/model-compare-dialog.tsx:44 ===
function parseParamsBillionsFromModelNameE(modelName: string | null | undefined): number | null {
if (!modelName) return null
const sizeTokens = Array.from(modelName.matchAll(/\b(\d+(?:\.\d+)?)\s*([bm])\b/gi))
if (sizeTokens.length === 0) return null
const lastToken = sizeTokens[sizeTokens.length - 1]
const numericValue = Number(lastToken[1])
if (!Number.isFinite(numericValue)) return null
const unit = lastToken[2].toLowerCase()
if (unit === "b") return numericValue
if (unit === "m") return numericValue / 1000
return null
}
// === Variant F: app/evals/[id]/page.tsx:434-437 ===
function parseParamsBillionsInline(name: string, id: string): number | null {
const sizeMatch = (name + " " + id).match(/\b(\d+(?:\.\d+)?)\s*[bB]\b/)
if (sizeMatch) return parseFloat(sizeMatch[1])
return null
}
// ---------------------------------------------------------------------------
// Group A β€” Variant A (parseParamsBillions, lib/model-data.ts)
// ---------------------------------------------------------------------------
describe("Group A β€” parseParamsBillions (Variant A, lib/model-data.ts)", () => {
describe("number-input branch", () => {
const cases = [
{ input: 7, expected: 7, why: "finite + >0 β†’ return as-is" },
{ input: 34.389, expected: 34.389, why: "float passes through" },
{ input: 0, expected: null, why: ">0 reject" },
{ input: -3, expected: null, why: ">0 reject" },
{ input: NaN, expected: null, why: "isFinite reject" },
{ input: Infinity, expected: null, why: "isFinite reject" },
]
it.each(cases)("$input β†’ $expected ($why)", ({ input, expected }) => {
expect(parseParamsBillions(input)).toBe(expected)
})
})
describe("non-string non-number β†’ null", () => {
it.each([
{ input: null },
{ input: undefined },
{ input: [] },
{ input: {} },
{ input: true },
])("$input β†’ null", ({ input }) => {
expect(parseParamsBillions(input)).toBe(null)
})
})
describe("string-input branch β€” unit tokens", () => {
const cases = [
{ input: "7B", expected: 7, why: "b β†’ as-is" },
{ input: "7b", expected: 7, why: "lowercased" },
{ input: "70B params", expected: 70, why: "regex anchors at b\\b; trailing text ignored" },
{ input: "1.5B", expected: 1.5, why: "decimal supported" },
{ input: "405b", expected: 405, why: "lowercased" },
{ input: "7 billion", expected: 7, why: "billion β†’ as-is" },
{ input: "7bn", expected: 7, why: "bn alias" },
{ input: "1.2T", expected: 1200, why: "t β†’ Γ—1000" },
{ input: "2 trillion", expected: 2000, why: "trillion β†’ Γ—1000" },
{ input: "2T params", expected: 2000, why: "t\\b anchor; trailing text ignored" },
{ input: "3.5tn", expected: 3500, why: "tn alias" },
{ input: "560M", expected: 0.56, why: "m β†’ Γ·1000" },
{ input: "560 million", expected: 0.56, why: "million β†’ Γ·1000" },
{ input: "1000K", expected: 0.001, why: "k β†’ Γ·1_000_000" },
{ input: "1,500B", expected: 1500, why: "comma stripped" },
{ input: "7 B", expected: 7, why: "\\s* matches multiple spaces" },
]
it.each(cases)("'$input' β†’ $expected ($why)", ({ input, expected }) => {
expect(parseParamsBillions(input)).toBe(expected)
})
})
describe("string-input branch β€” parseFloat fallback (no unit token)", () => {
const cases = [
{ input: "34.389", expected: 34.389, why: "no unit β†’ parseFloat fallback" },
{ input: "7", expected: 7, why: "bare numeric β†’ parseFloat fallback" },
{ input: "7Banana", expected: 7, why: "regex `b\\b` fails; parseFloat('7banana')=7. TS quirk: trailing junk allowed" },
{ input: "abc", expected: null, why: "no match, parseFloat NaN β†’ null" },
{ input: "", expected: null, why: "trim empty β†’ early return" },
{ input: " ", expected: null, why: "trim empty β†’ early return" },
]
it.each(cases)("'$input' β†’ $expected ($why)", ({ input, expected }) => {
expect(parseParamsBillions(input)).toBe(expected)
})
})
describe("string-input branch β€” TS quirks (positive-only filtering)", () => {
it("'0B' β†’ null (regex matches; amount=0 fails ≀0 check)", () => {
expect(parseParamsBillions("0B")).toBe(null)
})
it("'-5' β†’ null (parseFloat=-5; >0 reject)", () => {
expect(parseParamsBillions("-5")).toBe(null)
})
it("'-5B' β†’ 5 (regex matches `5b` substring; leading minus silently dropped)", () => {
// TS quirk: `\d+` doesn't include `-`, but the regex isn't anchored at start,
// so it scans past `-` and matches `5b`. amount=5 β†’ returns 5 (NOT -5, NOT null).
expect(parseParamsBillions("-5B")).toBe(5)
})
})
describe("string-input branch β€” model names (Variant A on names)", () => {
// Variant A is callable on any string; using it on model names exhibits
// different behavior from Variant C because A uses `match()` (first match)
// and a regex without leading `\b`.
it("'Llama-3-70B-Instruct' β†’ 70 (first match)", () => {
expect(parseParamsBillions("Llama-3-70B-Instruct")).toBe(70)
})
it("'Llama-3-70B-Instruct-8K' β†’ 70 (first match wins, NOT last like Variant C)", () => {
expect(parseParamsBillions("Llama-3-70B-Instruct-8K")).toBe(70)
})
it("'Yi-1.5-34B-32K' β†’ 34 (first match)", () => {
expect(parseParamsBillions("Yi-1.5-34B-32K")).toBe(34)
})
it("'Mixtral-8x7B' β†’ 7 (no leading \\b β†’ matches `7b` inside `8x7b`)", () => {
// TS quirk: A's regex has no `\b` before `\d+`, so it can start matching
// mid-word. C/E/F all return null here because they DO require leading `\b`.
expect(parseParamsBillions("Mixtral-8x7B")).toBe(7)
})
})
})
// ---------------------------------------------------------------------------
// Group B β€” Variant B (parseParamsBillionsFromText, eval-detail.tsx)
// ---------------------------------------------------------------------------
describe("Group B β€” parseParamsBillionsFromText (Variant B, eval-detail.tsx)", () => {
describe("string inputs (mostly converges with Variant A)", () => {
const cases = [
{ input: "7B", expected: 7 },
{ input: "1.5B", expected: 1.5 },
{ input: "1.2T", expected: 1200 },
{ input: "560M", expected: 0.56 },
{ input: "1000K", expected: 0.001 },
{ input: "7 billion", expected: 7 },
{ input: "34.389", expected: 34.389, why: "parseFloat fallback" },
{ input: "1,500B", expected: 1500 },
{ input: "7Banana", expected: 7, why: "parseFloat lenient; same as A" },
{ input: "abc", expected: null },
{ input: "", expected: null },
{ input: " ", expected: null },
{ input: null, expected: null },
{ input: undefined, expected: null },
]
it.each(cases)("'$input' β†’ $expected", ({ input, expected }) => {
expect(parseParamsBillionsFromText(input)).toBe(expected)
})
})
describe("DIVERGES from Variant A β€” no ≀0 reject", () => {
it("'0B' β†’ 0 (B has no ≀0 check; A returns null)", () => {
expect(parseParamsBillionsFromText("0B")).toBe(0)
expect(parseParamsBillions("0B")).toBe(null)
})
it("'-5' β†’ -5 (B has no >0 check; A returns null)", () => {
expect(parseParamsBillionsFromText("-5")).toBe(-5)
expect(parseParamsBillions("-5")).toBe(null)
})
it("'-5B' β†’ 5 (matches `5b` substring; same as A)", () => {
expect(parseParamsBillionsFromText("-5B")).toBe(5)
expect(parseParamsBillions("-5B")).toBe(5)
})
})
describe("rejects non-string inputs (DIVERGES from Variant A which is polymorphic)", () => {
// Variant B is typed as string|null|undefined; passing a number falls through `if (!value)`
// when value is 0, but otherwise goes through trim/lowercase which throws on non-string.
it("number input is not supported by Variant B (Variant A handles it)", () => {
expect(parseParamsBillions(7)).toBe(7)
// parseParamsBillionsFromText(7) would throw at .trim() β€” don't call it
})
})
})
// ---------------------------------------------------------------------------
// Group C β€” Variant C (parseParamsBillionsFromModelName, eval-detail.tsx)
// ---------------------------------------------------------------------------
describe("Group C β€” parseParamsBillionsFromModelName (Variant C, eval-detail.tsx)", () => {
describe("happy-path model names", () => {
const cases = [
{ input: "Llama-3-70B-Instruct", expected: 70, why: "matchAll β†’ only `70B`; last token; b β†’ 70" },
{ input: "Phi-3.5-mini-3.8B", expected: 3.8, why: "matches `3.8B`" },
{ input: "Qwen2-7B-Instruct", expected: 7, why: "matches `7B`" },
{ input: "560M", expected: 0.56, why: "m β†’ Γ·1000" },
{ input: "1.2T", expected: 1200, why: "t β†’ Γ—1000" },
{ input: "2K", expected: 0.000002, why: "k β†’ Γ·1_000_000" },
]
it.each(cases)("'$input' β†’ $expected ($why)", ({ input, expected }) => {
expect(parseParamsBillionsFromModelNameC(input)).toBe(expected)
})
})
describe("TS quirk β€” context-window suffix beats parameter count (last-token wins)", () => {
it("'Llama-3-8B-Instruct-8K' β†’ 0.000008 (last token = `8K`, NOT `8B`)", () => {
expect(parseParamsBillionsFromModelNameC("Llama-3-8B-Instruct-8K")).toBe(0.000008)
})
it("'Llama-3-70B-Instruct-32K' β†’ 0.000032 (last token = `32K`)", () => {
expect(parseParamsBillionsFromModelNameC("Llama-3-70B-Instruct-32K")).toBe(0.000032)
})
it("'Yi-1.5-34B-32K' β†’ 0.000032 (real production model name; returns context window)", () => {
expect(parseParamsBillionsFromModelNameC("Yi-1.5-34B-32K")).toBe(0.000032)
})
})
describe("regex anchoring quirks (leading \\b required)", () => {
it("'Mixtral-8x7B' β†’ null (no `\\b` between `x` and `7` β†’ no match)", () => {
expect(parseParamsBillionsFromModelNameC("Mixtral-8x7B")).toBe(null)
})
it("'7 billion' β†’ null (single-letter unit only; `billion` doesn't match [tmbk])", () => {
expect(parseParamsBillionsFromModelNameC("7 billion")).toBe(null)
})
it("'GPT-4' β†’ null (no unit token)", () => {
expect(parseParamsBillionsFromModelNameC("GPT-4")).toBe(null)
})
})
describe("falsy inputs", () => {
it.each([
{ input: "", expected: null },
{ input: null, expected: null },
{ input: undefined, expected: null },
])("$input β†’ null", ({ input, expected }) => {
expect(parseParamsBillionsFromModelNameC(input)).toBe(expected)
})
})
})
// ---------------------------------------------------------------------------
// Group D β€” Variant E (parseParamsBillionsFromModelName, model-compare-dialog.tsx)
// ---------------------------------------------------------------------------
describe("Group D (E) β€” parseParamsBillionsFromModelName (Variant E, model-compare-dialog.tsx)", () => {
describe("converges with C on b|m inputs", () => {
const cases = [
{ input: "Llama-3-70B-Instruct", expected: 70 },
{ input: "Phi-3.5-mini-3.8B", expected: 3.8 },
{ input: "560M", expected: 0.56 },
]
it.each(cases)("'$input' β†’ $expected", ({ input, expected }) => {
expect(parseParamsBillionsFromModelNameE(input)).toBe(expected)
})
})
describe("DIVERGES from C β€” rejects t and k", () => {
it("'Llama-3-8B-Instruct-8K' β†’ 8 (E ignores K; last `b|m` token = `8B`; C returns 0.000008)", () => {
expect(parseParamsBillionsFromModelNameE("Llama-3-8B-Instruct-8K")).toBe(8)
expect(parseParamsBillionsFromModelNameC("Llama-3-8B-Instruct-8K")).toBe(0.000008)
})
it("'Yi-1.5-34B-32K' β†’ 34 (E ignores K; C returns 0.000032)", () => {
expect(parseParamsBillionsFromModelNameE("Yi-1.5-34B-32K")).toBe(34)
expect(parseParamsBillionsFromModelNameC("Yi-1.5-34B-32K")).toBe(0.000032)
})
it("'1.2T' β†’ null (E rejects t)", () => {
expect(parseParamsBillionsFromModelNameE("1.2T")).toBe(null)
expect(parseParamsBillionsFromModelNameC("1.2T")).toBe(1200)
})
it("'2K' β†’ null (E rejects k)", () => {
expect(parseParamsBillionsFromModelNameE("2K")).toBe(null)
})
})
describe("regex anchoring matches C", () => {
it("'Mixtral-8x7B' β†’ null (same as C β€” leading \\b fails)", () => {
expect(parseParamsBillionsFromModelNameE("Mixtral-8x7B")).toBe(null)
})
})
})
// ---------------------------------------------------------------------------
// Group E (F) β€” Variant F (inline regex, app/evals/[id]/page.tsx)
// ---------------------------------------------------------------------------
describe("Group E (F) β€” inline regex on `name + ' ' + id` (Variant F, app/evals/[id]/page.tsx)", () => {
describe("happy-path (b|B only)", () => {
const cases = [
{ name: "Llama-3-70B-Instruct", id: "meta/llama-3-70b-instruct", expected: 70, why: "first 70B match" },
{ name: "1.5B-instruct", id: "meta/foo-1-5b", expected: 1.5, why: "first 1.5B match" },
]
it.each(cases)("['$name' + '$id'] β†’ $expected ($why)", ({ name, id, expected }) => {
expect(parseParamsBillionsInline(name, id)).toBe(expected)
})
})
describe("DIVERGES from C/E β€” first-match (not last-match) ordering", () => {
it("name with both `8B` and `70B` β†’ returns FIRST (8), Variant C returns LAST (70)", () => {
expect(parseParamsBillionsInline("Llama-3-8B-70B-Instruct", "meta/llama-3-8b-70b")).toBe(8)
expect(parseParamsBillionsFromModelNameC("Llama-3-8B-70B-Instruct")).toBe(70)
})
it("'Llama-3-70B-Instruct-8K' β†’ 70 (8K not matched by [bB]; first 70B wins)", () => {
// Variant F is *more correct* than C here because it ignores `K` entirely.
expect(parseParamsBillionsInline("Llama-3-70B-Instruct-8K", "meta/llama-3-70b-instruct")).toBe(70)
})
it("'Yi-1.5-34B-32K' β†’ 34 (real production name; F returns correct value, C returns context window)", () => {
expect(parseParamsBillionsInline("Yi-1.5-34B-32K", "01-ai/yi-1-5-34b-32k")).toBe(34)
expect(parseParamsBillionsFromModelNameC("Yi-1.5-34B-32K")).toBe(0.000032)
})
})
describe("DIVERGES from A/B/C β€” only b|B accepted", () => {
it("'560M' β†’ null (F is B-only)", () => {
expect(parseParamsBillionsInline("560M", "openai/foo-560m")).toBe(null)
})
it("'1.2T' β†’ null (F is B-only)", () => {
expect(parseParamsBillionsInline("1.2T", "openai/foo-1-2t")).toBe(null)
})
it("'GPT-4' β†’ null (no B token at all)", () => {
expect(parseParamsBillionsInline("GPT-4", "openai/gpt-4")).toBe(null)
})
})
describe("regex anchoring matches C/E (leading \\b required)", () => {
it("'Mixtral-8x7B' β†’ null (same as C/E β€” `\\b` fails between `x` and `7`)", () => {
expect(parseParamsBillionsInline("Mixtral-8x7B", "mistralai/mixtral-8x7b")).toBe(null)
})
})
describe("uses concatenated name + id (not just name)", () => {
it("name lacks B but id has it β†’ still matches", () => {
// e.g. raw model id might carry the `7b` token even if display name omits it
expect(parseParamsBillionsInline("Llama 3", "meta/llama-3-7b")).toBe(7)
})
})
describe("empty/falsy", () => {
it("'' + '' β†’ null", () => {
expect(parseParamsBillionsInline("", "")).toBe(null)
})
})
})
// ---------------------------------------------------------------------------
// Group F β€” Cross-variant divergence (DOCUMENTED, NOT FIXED)
// ---------------------------------------------------------------------------
//
// The five variants produce different outputs for the same input.
// In production these don't usually disagree (because the input *type* per
// callsite is consistent: A sees clean numbers, B sees clean decimal strings,
// C/E/F see model-name strings).
describe("Group F β€” cross-variant divergence (TS quirks, do NOT fix)", () => {
it("'0B' β€” A rejects (≀0); B/C/E accept; F accepts", () => {
expect(parseParamsBillions("0B")).toBe(null)
expect(parseParamsBillionsFromText("0B")).toBe(0)
expect(parseParamsBillionsFromModelNameC("0B")).toBe(0)
expect(parseParamsBillionsFromModelNameE("0B")).toBe(0)
expect(parseParamsBillionsInline("0B", "")).toBe(0)
})
it("'-5' (string) β€” A rejects (>0); B accepts -5; C/E/F have no unit so return null", () => {
expect(parseParamsBillions("-5")).toBe(null)
expect(parseParamsBillionsFromText("-5")).toBe(-5)
expect(parseParamsBillionsFromModelNameC("-5")).toBe(null)
expect(parseParamsBillionsFromModelNameE("-5")).toBe(null)
expect(parseParamsBillionsInline("-5", "")).toBe(null)
})
it("'7 billion' β€” A and B parse to 7; C/E/F have no full-word `billion` β†’ null", () => {
expect(parseParamsBillions("7 billion")).toBe(7)
expect(parseParamsBillionsFromText("7 billion")).toBe(7)
expect(parseParamsBillionsFromModelNameC("7 billion")).toBe(null)
expect(parseParamsBillionsFromModelNameE("7 billion")).toBe(null)
expect(parseParamsBillionsInline("7 billion", "")).toBe(null)
})
it("'1.2T' β€” A/B/C accept; E/F reject (no `t` unit)", () => {
expect(parseParamsBillions("1.2T")).toBe(1200)
expect(parseParamsBillionsFromText("1.2T")).toBe(1200)
expect(parseParamsBillionsFromModelNameC("1.2T")).toBe(1200)
expect(parseParamsBillionsFromModelNameE("1.2T")).toBe(null)
expect(parseParamsBillionsInline("1.2T", "")).toBe(null)
})
it("'560M' β€” A/B/C/E accept; F rejects (no `m` unit)", () => {
expect(parseParamsBillions("560M")).toBe(0.56)
expect(parseParamsBillionsFromText("560M")).toBe(0.56)
expect(parseParamsBillionsFromModelNameC("560M")).toBe(0.56)
expect(parseParamsBillionsFromModelNameE("560M")).toBe(0.56)
expect(parseParamsBillionsInline("560M", "")).toBe(null)
})
it("'Mixtral-8x7B' β€” A/B accept (regex has no leading \\b β†’ matches `7b` inside `8x7b`); C/E/F reject", () => {
// Most striking divergence: A and B return 7, all model-name parsers return null.
expect(parseParamsBillions("Mixtral-8x7B")).toBe(7)
expect(parseParamsBillionsFromText("Mixtral-8x7B")).toBe(7)
expect(parseParamsBillionsFromModelNameC("Mixtral-8x7B")).toBe(null)
expect(parseParamsBillionsFromModelNameE("Mixtral-8x7B")).toBe(null)
expect(parseParamsBillionsInline("Mixtral-8x7B", "mistralai/mixtral-8x7b")).toBe(null)
})
it("'Llama-3-8B-Instruct-8K' β€” A/B/F return 8/8/8 (first match or [bB]-only); C returns 0.000008; E returns 8", () => {
// A and B both use match() (first match) on a leading-anchor-free regex β†’ first
// match is `8B` β†’ 8. C uses matchAll() (last match) and accepts `K` β†’ `8K` β†’ 0.000008.
// E uses matchAll() but rejects `K` β†’ last `b|m` token = `8B` β†’ 8. F is [bB]-only,
// first match β†’ `8B` β†’ 8.
expect(parseParamsBillions("Llama-3-8B-Instruct-8K")).toBe(8)
expect(parseParamsBillionsFromText("Llama-3-8B-Instruct-8K")).toBe(8)
expect(parseParamsBillionsFromModelNameC("Llama-3-8B-Instruct-8K")).toBe(0.000008)
expect(parseParamsBillionsFromModelNameE("Llama-3-8B-Instruct-8K")).toBe(8)
expect(parseParamsBillionsInline("Llama-3-8B-Instruct-8K", "meta/llama-3-8b-8k")).toBe(8)
})
it("'Yi-1.5-34B-32K' (real production name) β€” only Variant C is wrong (returns context window)", () => {
expect(parseParamsBillions("Yi-1.5-34B-32K")).toBe(34)
expect(parseParamsBillionsFromText("Yi-1.5-34B-32K")).toBe(34)
expect(parseParamsBillionsFromModelNameC("Yi-1.5-34B-32K")).toBe(0.000032)
expect(parseParamsBillionsFromModelNameE("Yi-1.5-34B-32K")).toBe(34)
expect(parseParamsBillionsInline("Yi-1.5-34B-32K", "01-ai/yi-1-5-34b-32k")).toBe(34)
})
it("name with multiple B-tokens β€” first vs last divergence (F vs C/E)", () => {
// Synthetic: `Llama-3-8B-70B-Instruct` β€” first is 8B, last is 70B
expect(parseParamsBillionsInline("Llama-3-8B-70B-Instruct", "")).toBe(8) // F: first
expect(parseParamsBillionsFromModelNameC("Llama-3-8B-70B-Instruct")).toBe(70) // C: last
expect(parseParamsBillionsFromModelNameE("Llama-3-8B-70B-Instruct")).toBe(70) // E: last
expect(parseParamsBillions("Llama-3-8B-70B-Instruct")).toBe(8) // A: first via match()
expect(parseParamsBillionsFromText("Llama-3-8B-70B-Instruct")).toBe(8) // B: first via match()
})
it("clean production-shaped inputs β€” all variants converge", () => {
// The empirical reason this divergence rarely fires: in production, A/B see
// `additional_details.params_billions` strings like "34.389" (clean decimal),
// while C/E/F see model names like "Llama-3-70B-Instruct" (single B-token,
// no context-window suffix). For these inputs all variants agree.
expect(parseParamsBillions("34.389")).toBe(34.389)
expect(parseParamsBillionsFromText("34.389")).toBe(34.389)
// C/E/F can't handle bare decimals (no unit) but they're not given them
expect(parseParamsBillionsFromModelNameC("Llama-3-70B-Instruct")).toBe(70)
expect(parseParamsBillionsFromModelNameE("Llama-3-70B-Instruct")).toBe(70)
expect(parseParamsBillionsInline("Llama-3-70B-Instruct", "meta/llama-3-70b-instruct")).toBe(70)
})
})