Model Picker — JavaScript source
Filter every major model by context window, price, modality, and tier — sort by cost, context, or tokens-per-dollar to find the right model for the task.
This is the JavaScript implementation — the same logic the interactive tool runs, in a shareable, citable form.
/**
* Model Picker - filter + rank the AI model catalog.
*
* Language: JavaScript (ES2020+, ES module; runs unmodified in Node 16+
* and modern browsers)
* Source: CosmoDev polyglot showcase port of the Model Picker tool,
* ported from src/lib/modelPicker.ts (the canonical TypeScript
* implementation).
* Live page: https://dev.cosmolabs.org/tools/model-picker
* License: display source - part of CosmoDev's polyglot tool pages.
*
* Design goals:
* - Pure + deterministic; never throws.
* - Functionally equivalent to the TS reference: same inputs -> same outputs.
* - Self-contained: no imports, no snapshot fetch.
*
* Port notes: the TS lib imports `listModels` from src/lib/ai/models.ts and
* lets `models` default to the bundled pricing snapshot (src/data/ai-models.json).
* A dependency-free port cannot load that file, so the filter step is inlined
* below and `models` is an explicit parameter (defaulting to an empty list).
*
* Every sort places null/missing values last and breaks ties on id ascending,
* so output order is fully deterministic for a given model list.
*/
/** Curated entry points: a filter + the sort that makes that filter useful. */
export const PRESETS = {
'long-context': { filter: { minContext: 500_000 }, sort: 'context' },
'cheap-bulk': { filter: { maxInputPerM: 1 }, sort: 'price' },
flagship: { filter: { tier: 'flagship' }, sort: 'tokensPerDollar' },
};
/** id ascending - the shared stable tie-break for every sort. */
const byId = (a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
/** Sort comparator per key: value order first, null last, id asc on ties. */
const COMPARATORS = {
price: (a, b) => {
if (a.inputPerM === null && b.inputPerM === null) return byId(a, b);
if (a.inputPerM === null) return 1;
if (b.inputPerM === null) return -1;
return a.inputPerM - b.inputPerM || byId(a, b);
},
context: (a, b) => b.contextWindow - a.contextWindow || byId(a, b),
tokensPerDollar: (a, b) => {
const ta = a.outputPerM === null ? null : 1_000_000 / a.outputPerM;
const tb = b.outputPerM === null ? null : 1_000_000 / b.outputPerM;
if (ta === null && tb === null) return byId(a, b);
if (ta === null) return 1;
if (tb === null) return -1;
return tb - ta || byId(a, b);
},
released: (a, b) => {
if (a.released === null && b.released === null) return byId(a, b);
if (a.released === null) return 1;
if (b.released === null) return -1;
if (a.released === b.released) return byId(a, b);
return a.released > b.released ? -1 : 1;
},
};
/** Filter the model list. Inline port of listModels() from
* src/lib/ai/models.ts: `null` prices never satisfy maxInputPerM, search is
* a case-insensitive substring match over id + name + vendor. */
export function listModels(filter = {}, models = []) {
const q = filter.search?.toLowerCase();
return models.filter((m) => {
if (filter.vendor !== undefined && m.vendor !== filter.vendor) return false;
if (filter.tier !== undefined && m.tier !== filter.tier) return false;
if (filter.minContext !== undefined && m.contextWindow < filter.minContext) return false;
if (
filter.maxInputPerM !== undefined &&
(m.inputPerM === null || m.inputPerM > filter.maxInputPerM)
)
return false;
if (filter.modality !== undefined && !m.modalities.includes(filter.modality)) return false;
if (q !== undefined && !(m.id + ' ' + m.name + ' ' + m.vendor).toLowerCase().includes(q))
return false;
return true;
});
}
/** Filter the model list, then sort it. See COMPARATORS for the exact order. */
export function pickModels(filter = {}, sort = 'price', models = []) {
return listModels(filter, models).sort(COMPARATORS[sort]);
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →