scoreModels
recommend() handles scoring internally, but scoreModels() exposes the scoring engine directly. Use it when you want to score models with custom criteria without the full recommend pipeline, or when building your own selection logic on top of scored results.
Signature
Section titled “Signature”function scoreModels<T extends Model>( models: T[], criteria: WeightedCriterion[],): ScoredModel<T>[]Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
models | T[] | Models to score. |
criteria | WeightedCriterion[] | Criteria paired with weights. |
Returns
Section titled “Returns”ScoredModel<T>[]: models with added score (0-1) and coverage (0-1) properties, sorted by score descending. coverage is the fraction of criterion weight backed by real data for that model.
Behavior
Section titled “Behavior”- Normalizes weights to sum to 1 (weight 7 and weight 3 become 0.7 and 0.3).
- Computes the weighted sum per model. Criteria that return
undefined(no data for that model) contribute 0 and reduce the model’scoverage. - All-zero weights produce all-zero scores with zero coverage.
- Empty input returns
[].
import { scoreModels, costEfficiency, recency } from "pickai";
const scored = scoreModels(models, [ { criterion: costEfficiency, weight: 3 }, { criterion: recency, weight: 1 },]);
console.log(scored[0].name, scored[0].score);See Scoring & Ranking for how criteria and weights work together.
Built-in Criteria
Section titled “Built-in Criteria”All built-in criteria use min-max normalization across the candidate set. Scores are relative to the other candidates.
costEfficiency
Section titled “costEfficiency”const costEfficiency: ScoringCriterionCheaper models score higher. Based on model.cost.input (USD per 1M tokens). Models without pricing data are uncovered (unknown cost gets no credit for being cheap).
recency
Section titled “recency”const recency: ScoringCriterionNewer models score higher. Based on model.releaseDate. Models without a release date are uncovered and excluded from the scale, so one dateless model cannot compress everyone else toward the top.
contextCapacity
Section titled “contextCapacity”const contextCapacity: ScoringCriterionLarger context windows score higher. Based on model.limit.context.
outputCapacity
Section titled “outputCapacity”const outputCapacity: ScoringCriterionLarger output limits score higher. Based on model.limit.output.
knowledgeFreshness
Section titled “knowledgeFreshness”const knowledgeFreshness: ScoringCriterionMore recent knowledge cutoffs score higher. Based on model.knowledge (e.g., "2025-03"). Models without a knowledge cutoff are uncovered and excluded from the scale.
minMaxCriterion
Section titled “minMaxCriterion”Helper for creating custom min-max normalized criteria. Reduces the boilerplate of extracting values, filtering nulls, and normalizing.
function minMaxCriterion( getValue: (model: Model) => number | undefined, invert?: boolean,): ScoringCriterion| Parameter | Type | Default | Description |
|---|---|---|---|
getValue | function | required | Extracts a numeric value from a model, or undefined if unavailable. |
invert | boolean | false | If true, lower values score higher (useful for cost). |
Models where getValue returns undefined are uncovered: the criterion contributes 0 to their score and lowers their coverage.
For lower-is-better fields like cost, use invert: true rather than negating inside getValue. An expression like 1 - (cost ?? Infinity) turns missing data into a huge negative score; invert keeps undefined as “no data”.
import { minMaxCriterion, matchesModel } from "pickai";
// Score models by external benchmark dataconst arenaScore = minMaxCriterion((model) => { const match = benchmarks.find((b) => matchesModel(b.modelId, model.id)); return match?.score;});
// Score models by cost (cheaper = higher score)const cheapest = minMaxCriterion((model) => model.cost?.input, true);See the benchmark example recipes for working implementations.