local-frontier / scripts /validate-model-data.mjs
Onur Solmaz
feat: add gemma 3 4b gated profile
9efd956
Raw
History Blame Contribute Delete
4.68 kB
import fs from "node:fs";
import path from "node:path";
import vm from "node:vm";
const root = path.resolve(import.meta.dirname, "..");
const dataPath = path.join(root, "assets", "local-frontier-model-data.js");
const source = fs.readFileSync(dataPath, "utf8");
const context = { window: {} };
vm.runInNewContext(source, context, { filename: dataPath });
const data = context.window.LOCAL_FRONTIER_MODEL_DATA;
const errors = [];
const HF_REPO_ID_RE =
/^[A-Za-z0-9][A-Za-z0-9._-]*\/[A-Za-z0-9][A-Za-z0-9._-]*$/;
const LEGACY_ALIAS_RE = /^[a-z0-9][a-z0-9-]*$/;
function fail(path, message) {
errors.push(`${path}: ${message}`);
}
function isPositiveNumber(value) {
return Number.isFinite(Number(value)) && Number(value) > 0;
}
function isNonNegativeNumber(value) {
return Number.isFinite(Number(value)) && Number(value) >= 0;
}
if (!data || typeof data !== "object") {
fail("LOCAL_FRONTIER_MODEL_DATA", "missing data object");
} else {
if (!Array.isArray(data.models) || data.models.length === 0) {
fail("models", "must contain at least one model");
}
const ids = new Set();
const aliases = new Set();
for (const [index, model] of (data.models || []).entries()) {
const pathBase = `models[${index}]`;
if (!model.id || !HF_REPO_ID_RE.test(model.id))
fail(
`${pathBase}.id`,
"must be a Hugging Face repo id like namespace/model",
);
if (ids.has(model.id)) fail(`${pathBase}.id`, "duplicate id");
ids.add(model.id);
for (const [aliasIndex, alias] of (model.aliases || []).entries()) {
if (!LEGACY_ALIAS_RE.test(alias))
fail(`${pathBase}.aliases[${aliasIndex}]`, "invalid legacy alias");
if (ids.has(alias))
fail(
`${pathBase}.aliases[${aliasIndex}]`,
"alias collides with canonical id",
);
if (aliases.has(alias))
fail(`${pathBase}.aliases[${aliasIndex}]`, "duplicate alias");
aliases.add(alias);
}
for (const key of ["name", "short_name", "license"]) {
if (!model[key]) fail(`${pathBase}.${key}`, "required");
}
if (!model.hf_pipeline_tag) fail(`${pathBase}.hf_pipeline_tag`, "required");
const minDownloads = data.assumptions?.min_hf_downloads ?? 100000;
if (
!Number.isInteger(model.hf_downloads) ||
model.hf_downloads < minDownloads
) {
fail(`${pathBase}.hf_downloads`, `must be an integer >= ${minDownloads}`);
}
const arch = model.architecture || {};
for (const key of ["type", "detail"]) {
if (!arch[key]) fail(`${pathBase}.architecture.${key}`, "required");
}
for (const key of ["total_params_b", "active_params_b"]) {
if (!isPositiveNumber(arch[key]))
fail(`${pathBase}.architecture.${key}`, "must be positive");
}
if (
arch.max_context_tokens !== null &&
(!Number.isInteger(arch.max_context_tokens) ||
arch.max_context_tokens <= 0)
) {
fail(
`${pathBase}.architecture.max_context_tokens`,
"must be null or a positive integer",
);
}
const adapter = model.adapter || {};
if (!["dense", "moe", "recurrent", "hybrid"].includes(adapter.kind)) {
fail(`${pathBase}.adapter.kind`, "unknown adapter kind");
}
for (const key of [
"weight_bytes_per_param",
"resident_weight_gb",
"active_weight_gb",
]) {
if (!isPositiveNumber(adapter[key]))
fail(`${pathBase}.adapter.${key}`, "must be positive");
}
for (const key of [
"kv_alloc_gb_per_1k_tokens",
"kv_read_gb_per_1k_tokens",
"kv_alloc_fixed_gb",
"kv_read_fixed_gb",
]) {
if (adapter[key] !== undefined && !isNonNegativeNumber(adapter[key])) {
fail(`${pathBase}.adapter.${key}`, "must be non-negative when present");
}
}
if (adapter.kind === "moe") {
for (const key of ["routed_experts", "routed_experts_per_token"]) {
if (!Number.isInteger(arch[key]) || arch[key] <= 0)
fail(`${pathBase}.architecture.${key}`, "required for MoE");
}
}
if (!Array.isArray(model.sources) || model.sources.length === 0) {
fail(`${pathBase}.sources`, "at least one source is required");
} else {
for (const [sourceIndex, sourceRow] of model.sources.entries()) {
if (!sourceRow.label)
fail(`${pathBase}.sources[${sourceIndex}].label`, "required");
try {
new URL(sourceRow.url);
} catch {
fail(`${pathBase}.sources[${sourceIndex}].url`, "invalid URL");
}
}
}
}
}
if (errors.length) {
console.error(errors.join("\n"));
process.exit(1);
}
console.log(`validated ${data.models.length} models`);