llm-relay 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -311,26 +311,48 @@ Precedence for a subagent request: `@relay:` directive → `subagents[<tier>]`
311
311
  ### Choosing where to offload (`llm-relay candidates`)
312
312
 
313
313
  ```
314
- target pools / tiers live SWE LCB BFCL arena rank verdict p95 up% quota breaker ctx
315
- nim/z-ai/glm-5.2 coding,@opus yes 42 53 - 1469~ #31 Perfect 310ms 100 84% closed 128k
316
- nim/meta/llama-3.1-8b-instruct fast,@haiku,@fable yes - - 25.83 1211 #308 Perfect 120ms 100 84% closed 128k
314
+ target pools / tiers str agentic coding BFCL arena $/Mout verdict p95 quota breaker ctx
315
+ nim/z-ai/glm-5.2 coding,@opus 83.3/4 43.1 68.8 - - $2.402~ Perfect 310ms 84% closed 1049k~
316
+ nim/moonshotai/kimi-k2.6 coding,@sonnet 77.4/5 30.3 61.8 - 1461 $2.72~ Perfect 280ms 84% closed 262k~
317
+ nim/meta/llama-3.1-8b-instruct fast,@haiku,@fable 9.7/6 0.5 5.4 25.83 1211 $0.08~ Perfect 120ms 84% closed 131k~
317
318
  ```
318
319
 
319
- Every offload target with its dimensions side by side: capability (SWE-bench, HumanEval,
320
- LiveCodeBench, BFCL tool-use, Arena rating/rank, context window), live behaviour (verdict, avg/p95
321
- latency, jitter, uptime), availability right now (provider quota, circuit-breaker state, whether the
322
- provider still lists the model) and traffic actually observed through the proxy.
323
-
324
- A blank cell means **not measured**, not bad. The two capability sources have different coverage:
325
- SWE-bench/HumanEval/LiveCodeBench come from a hand-maintained table in `benchmarks.ts` that lags the
326
- roster, while BFCL and Arena come from the synced leaderboard (`npm run sync:tiers`). `~` marks a
327
- score **borrowed from a similarly-named model** — the leaderboard has no `glm-5.2` row, so those
328
- numbers are `glm-5.2-max`'s. The JSON carries `capability.matched_name` and `capability.match`
329
- (`exact` | `fuzzy`) so the substitution is never invisible.
330
-
331
- **Nothing is ranked or averaged** capability, latency and remaining quota trade off differently
332
- per task, and one blended number answers neither "cheapest that can do it" nor "best available". The
333
- composites the proxy itself sorts by are reported under `sortInputs`, labelled as what they drive.
320
+ Every offload target with its dimensions side by side: capability from each leaderboard separately,
321
+ live behaviour (verdict, avg/p95 latency, jitter, uptime), availability and cost right now (quota,
322
+ circuit-breaker state, price per million tokens, whether the provider still lists the model), and
323
+ traffic actually observed through the proxy.
324
+
325
+ **Capability comes from `npm run sync:tiers`**, which merges four sources into
326
+ `docs/tier-data.json` (~770 models) see [docs/capability-sources.md](docs/capability-sources.md):
327
+
328
+ | Source | Contributes |
329
+ |---|---|
330
+ | OpenRouter | Artificial Analysis intelligence / coding / **agentic** indices, Design Arena Elo, context length, pricing, tool support — and the only source whose ids match routing specs exactly |
331
+ | BFCL | tool-call accuracy, multi-turn, irrelevance detection |
332
+ | LMArena | general preference rating + rank |
333
+ | Aider | polyglot edit benchmark + edit-format compliance |
334
+
335
+ They **disagree** — the agentic index puts deepseek above kimi while the coding index puts kimi
336
+ above deepseek — which is exactly why each keeps its own column, and why a blank cell means *not
337
+ measured*, never *bad*.
338
+
339
+ **Nothing is ranked or averaged across dimensions** — capability, latency and remaining quota trade
340
+ off differently per task, and one blended number answers neither "cheapest that can do it" nor "best
341
+ available".
342
+
343
+ `str` is the single exception, and it exists only because ordering a pool requires an order. It is a
344
+ weighted mean of whatever rank-normalized signals a model actually has (tool-use and agentic ability
345
+ weighted highest — this proxy drives tool loops), and it never appears without its provenance:
346
+ `83.3/4` means four published signals backed it, while `obs` (ranked on this proxy's own traffic,
347
+ ≥5 calls) and `neut` (nothing known) mark the fallbacks.
348
+
349
+ **Limits and prices are per-(provider, model), and labelled.** The same model id on two providers is
350
+ two deployments — different context ceilings, different output caps, and possibly free on one and
351
+ metered on the other. Where a provider publishes its own figures (Groq, Mistral, OpenRouter) those
352
+ are used; where it publishes none (NIM returns only `id`/`object`/`created`/`owned_by`) the table
353
+ falls back to another provider's figure for the same id and marks it `~`, or to the hardcoded
354
+ table's guess and marks it `?`. Unmarked means the serving provider published it. An unknown price
355
+ stays blank rather than being guessed.
334
356
 
335
357
  `GET /candidates` returns the full JSON (the table shows a subset). The CLI prefers a running proxy
336
358
  so the live columns come from warm ping history rather than a cold start.
@@ -1,13 +1,39 @@
1
1
  import type { ResolvedTarget } from "./config.js";
2
- export interface BenchmarkScores {
3
- sweBench?: number;
4
- humanEval?: number;
5
- liveCodeBench?: number;
6
- arenaElo?: number;
2
+ /** Where a strength score came from. Ranking is only as trustworthy as its basis. */
3
+ export type StrengthBasis = "snapshot" | "telemetry" | "neutral";
4
+ export interface Strength {
5
+ /** 0-100, comparable across bases. Higher is better. */
6
+ score: number;
7
+ basis: StrengthBasis;
8
+ /** snapshot only: which signals backed it, and how many. 1 signal is a guess, 5 is a consensus. */
9
+ signals?: string[];
10
+ signalCount?: number;
11
+ /** snapshot only: `fuzzy` means the row belongs to a similarly-named, DIFFERENT model. */
12
+ match?: "exact" | "fuzzy";
13
+ /** snapshot only: the row actually used. */
14
+ matchedName?: string;
7
15
  }
8
- /** Find benchmark scores for a model ID or provider/model spec. */
9
- export declare function getBenchmarkScores(modelId: string): BenchmarkScores;
10
- /** Calculate a single composite quality score (0-100) for ranking targets. */
11
- export declare function calculateQualityScore(scores: BenchmarkScores): number;
12
- /** Rank an array of resolved targets by coding benchmark quality (descending). */
16
+ /**
17
+ * Strength of one target, from the best evidence available, in this order:
18
+ *
19
+ * 1. the synced multi-source snapshot — real published capability, refreshed by `sync:tiers`;
20
+ * 2. observed runtime telemetry not capability, but this deployment's own evidence that the
21
+ * model answers successfully and quickly. Needs ≥5 real calls, so a brand-new model does not
22
+ * get ranked off one lucky request;
23
+ * 3. neutral — nothing is known, so claim nothing.
24
+ *
25
+ * The basis travels with the score precisely so a telemetry-derived number is never mistaken for
26
+ * a benchmark one.
27
+ *
28
+ * There is deliberately no hardcoded-table rung. `BENCHMARK_DB` used to sit here; every pattern it
29
+ * carried is present in the snapshot, so it contributed nothing but a stale, provenance-free number
30
+ * that outranked the synced data for any model it happened to substring-match.
31
+ */
32
+ export declare function getStrength(spec: string, opts?: {
33
+ telemetryPath?: string;
34
+ }): Strength;
35
+ /**
36
+ * Rank targets strongest-first. Ties are left in config order (`sort` is stable), which is what
37
+ * makes a pool's declared order the tie-breaker when nothing distinguishes two candidates.
38
+ */
13
39
  export declare function rankTargetsByBenchmark(targets: ResolvedTarget[]): ResolvedTarget[];
@@ -1,79 +1,60 @@
1
- /** Built-in coding benchmark database for popular coding models. */
2
- const BENCHMARK_DB = [
3
- // Anthropic / Claude models
4
- { pattern: "claude-3-7-sonnet", scores: { sweBench: 70.3, humanEval: 92.0, liveCodeBench: 64.5, arenaElo: 1320 } },
5
- { pattern: "claude-3-5-sonnet", scores: { sweBench: 49.0, humanEval: 93.7, liveCodeBench: 58.2, arenaElo: 1280 } },
6
- { pattern: "claude-3-opus", scores: { sweBench: 38.0, humanEval: 84.9, liveCodeBench: 45.0, arenaElo: 1250 } },
7
- { pattern: "claude-3-5-haiku", scores: { sweBench: 40.6, humanEval: 88.1, liveCodeBench: 48.0, arenaElo: 1220 } },
8
- // OpenAI / GPT models
9
- { pattern: "o3-mini", scores: { sweBench: 71.0, humanEval: 94.5, liveCodeBench: 66.0, arenaElo: 1330 } },
10
- { pattern: "o1", scores: { sweBench: 48.9, humanEval: 92.4, liveCodeBench: 61.5, arenaElo: 1310 } },
11
- { pattern: "gpt-4o", scores: { sweBench: 38.8, humanEval: 90.2, liveCodeBench: 52.1, arenaElo: 1286 } },
12
- { pattern: "gpt-4o-mini", scores: { sweBench: 29.0, humanEval: 87.2, liveCodeBench: 41.5, arenaElo: 1200 } },
13
- // DeepSeek models
14
- { pattern: "deepseek-r1", scores: { sweBench: 49.2, humanEval: 96.1, liveCodeBench: 65.9, arenaElo: 1350 } },
15
- { pattern: "deepseek-v3", scores: { sweBench: 42.0, humanEval: 90.0, liveCodeBench: 58.0, arenaElo: 1310 } },
16
- { pattern: "deepseek-coder", scores: { sweBench: 38.5, humanEval: 90.2, liveCodeBench: 53.0, arenaElo: 1240 } },
17
- // Qwen models
18
- { pattern: "qwen-2.5-coder-32b", scores: { sweBench: 41.2, humanEval: 92.7, liveCodeBench: 56.4, arenaElo: 1250 } },
19
- { pattern: "qwen-2.5-72b", scores: { sweBench: 37.0, humanEval: 86.6, liveCodeBench: 51.0, arenaElo: 1240 } },
20
- { pattern: "qwq-32b", scores: { sweBench: 44.0, humanEval: 93.0, liveCodeBench: 59.0, arenaElo: 1270 } },
21
- // GLM / Z-AI / Nemotron / Llama / Mistral models
22
- { pattern: "glm-4", scores: { sweBench: 35.0, humanEval: 85.0, liveCodeBench: 47.0, arenaElo: 1200 } },
23
- { pattern: "glm-5", scores: { sweBench: 42.0, humanEval: 89.0, liveCodeBench: 53.0, arenaElo: 1240 } },
24
- { pattern: "nemotron", scores: { sweBench: 36.5, humanEval: 86.0, liveCodeBench: 48.0, arenaElo: 1210 } },
25
- { pattern: "llama-3.3-70b", scores: { sweBench: 36.0, humanEval: 88.6, liveCodeBench: 49.2, arenaElo: 1230 } },
26
- { pattern: "mistral-large", scores: { sweBench: 34.0, humanEval: 84.0, liveCodeBench: 45.0, arenaElo: 1210 } },
27
- { pattern: "codestral", scores: { sweBench: 33.5, humanEval: 81.1, liveCodeBench: 46.0, arenaElo: 1200 } },
28
- ];
29
- /** Find benchmark scores for a model ID or provider/model spec. */
30
- export function getBenchmarkScores(modelId) {
31
- const norm = modelId.toLowerCase();
32
- for (const entry of BENCHMARK_DB) {
33
- if (typeof entry.pattern === "string") {
34
- if (norm.includes(entry.pattern))
35
- return entry.scores;
36
- }
37
- else if (entry.pattern.test(norm)) {
38
- return entry.scores;
39
- }
40
- }
41
- return {};
42
- }
43
- /** Calculate a single composite quality score (0-100) for ranking targets. */
44
- export function calculateQualityScore(scores) {
45
- let totalWeight = 0;
46
- let weightedSum = 0;
47
- if (scores.sweBench !== undefined) {
48
- weightedSum += scores.sweBench * 3.0; // Primary coding agent benchmark
49
- totalWeight += 3.0;
1
+ import { loadTierData, findTierModel } from "./tier-data.js";
2
+ import { getRealWorldScore } from "./ping/runtime-telemetry.js";
3
+ const NEUTRAL = 50;
4
+ /**
5
+ * Strength of one target, from the best evidence available, in this order:
6
+ *
7
+ * 1. the synced multi-source snapshot real published capability, refreshed by `sync:tiers`;
8
+ * 2. observed runtime telemetry — not capability, but this deployment's own evidence that the
9
+ * model answers successfully and quickly. Needs 5 real calls, so a brand-new model does not
10
+ * get ranked off one lucky request;
11
+ * 3. neutral nothing is known, so claim nothing.
12
+ *
13
+ * The basis travels with the score precisely so a telemetry-derived number is never mistaken for
14
+ * a benchmark one.
15
+ *
16
+ * There is deliberately no hardcoded-table rung. `BENCHMARK_DB` used to sit here; every pattern it
17
+ * carried is present in the snapshot, so it contributed nothing but a stale, provenance-free number
18
+ * that outranked the synced data for any model it happened to substring-match.
19
+ */
20
+ export function getStrength(spec, opts = {}) {
21
+ const hit = findTierModel(spec, loadTierData()?.byNorm ?? []);
22
+ if (hit && typeof hit.rec.strength === "number") {
23
+ return {
24
+ score: Math.round(hit.rec.strength * 1000) / 10, // 0-1 0-100
25
+ basis: "snapshot",
26
+ signals: hit.rec.signals ?? [],
27
+ signalCount: hit.rec.signal_count ?? 0,
28
+ match: hit.match,
29
+ matchedName: hit.rec.norm,
30
+ };
50
31
  }
51
- if (scores.liveCodeBench !== undefined) {
52
- weightedSum += scores.liveCodeBench * 2.0;
53
- totalWeight += 2.0;
32
+ const i = spec.indexOf("/");
33
+ if (i !== -1) {
34
+ const observed = getRealWorldScore(spec.slice(0, i), spec.slice(i + 1), opts.telemetryPath ? { path: opts.telemetryPath } : {});
35
+ if (observed !== null)
36
+ return { score: observed, basis: "telemetry" };
54
37
  }
55
- if (scores.humanEval !== undefined) {
56
- weightedSum += scores.humanEval * 1.0;
57
- totalWeight += 1.0;
58
- }
59
- if (totalWeight > 0) {
60
- return Math.round((weightedSum / totalWeight) * 10) / 10;
61
- }
62
- if (scores.arenaElo !== undefined) {
63
- return Math.max(0, Math.min(100, Math.round((scores.arenaElo - 1000) / 4)));
64
- }
65
- return 50.0; // Default baseline score for unlisted models
38
+ return { score: NEUTRAL, basis: "neutral" };
66
39
  }
67
- /** Rank an array of resolved targets by coding benchmark quality (descending). */
40
+ /**
41
+ * Rank targets strongest-first. Ties are left in config order (`sort` is stable), which is what
42
+ * makes a pool's declared order the tie-breaker when nothing distinguishes two candidates.
43
+ */
68
44
  export function rankTargetsByBenchmark(targets) {
69
45
  if (targets.length <= 1)
70
46
  return [...targets];
71
- return [...targets].sort((a, b) => {
72
- const specA = a.model ? `${a.provider}/${a.model}` : a.provider;
73
- const specB = b.model ? `${b.provider}/${b.model}` : b.provider;
74
- const scoreA = calculateQualityScore(getBenchmarkScores(specA));
75
- const scoreB = calculateQualityScore(getBenchmarkScores(specB));
76
- return scoreB - scoreA; // Highest score first
77
- });
47
+ const specOf = (t) => (t.model ? `${t.provider}/${t.model}` : t.provider);
48
+ const cache = new Map();
49
+ const score = (t) => {
50
+ const spec = specOf(t);
51
+ let v = cache.get(spec);
52
+ if (v === undefined) {
53
+ v = getStrength(spec).score;
54
+ cache.set(spec, v);
55
+ }
56
+ return v;
57
+ };
58
+ return [...targets].sort((a, b) => score(b) - score(a));
78
59
  }
79
60
  //# sourceMappingURL=benchmarks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"benchmarks.js","sourceRoot":"","sources":["../src/benchmarks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"benchmarks.js","sourceRoot":"","sources":["../src/benchmarks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAkBhE,MAAM,OAAO,GAAG,EAAE,CAAC;AAEnB;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,OAAmC,EAAE;IAC7E,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC;IAC9D,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAChD,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,cAAc;YAC/D,KAAK,EAAE,UAAU;YACjB,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE;YAC9B,WAAW,EAAE,GAAG,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC;YACtC,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,WAAW,EAAE,GAAG,CAAC,GAAG,CAAC,IAAI;SAC1B,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACb,MAAM,QAAQ,GAAG,iBAAiB,CAChC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAChB,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,EACjB,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CACvD,CAAC;QACF,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IACxE,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAyB;IAC9D,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;IAE7C,MAAM,MAAM,GAAG,CAAC,CAAiB,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC1F,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,MAAM,KAAK,GAAG,CAAC,CAAiB,EAAE,EAAE;QAClC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;YACpB,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;YAC5B,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACrB,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC,CAAC;IAEF,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC"}
@@ -1,17 +1,19 @@
1
1
  import type { Config } from "./config.js";
2
2
  import type { ModelCatalog } from "./catalog.js";
3
3
  import type { PingLoop } from "./ping/cadence.js";
4
- import { type BenchmarkScores } from "./benchmarks.js";
4
+ import { type StrengthBasis } from "./benchmarks.js";
5
+ import { type MetadataSource } from "./metadata.js";
5
6
  import { type CircuitBreaker } from "./circuit-breaker.js";
6
7
  import { type CapabilityScore } from "./registry.js";
7
8
  /**
8
9
  * Everything known about one offload destination, kept as SEPARATE raw dimensions.
9
10
  *
10
- * Deliberately un-blended: benchmark quality, live stability, quota and observed traffic measure
11
- * different things and trade off against each other differently per task ("cheapest that can do
12
- * it" vs "best available"). Averaging them into one number would bury exactly the judgement the
13
- * reader is here to make. The two composites that already exist in the product are reported under
14
- * `sortInputs`, labelled as what they drivenot as a recommendation.
11
+ * Deliberately un-blended: each leaderboard, live stability, cost, quota and observed traffic
12
+ * measure different things and trade off against each other differently per task ("cheapest that
13
+ * can do it" vs "best available"). Averaging them into one number would bury exactly the judgement
14
+ * the reader is here to make. The one scalar that does exist lives under `sortInputs` with the
15
+ * basis and signals that produced itbecause ordering a pool requires an order, not because it
16
+ * is a recommendation.
15
17
  */
16
18
  export interface Candidate {
17
19
  spec: string;
@@ -24,7 +26,6 @@ export interface Candidate {
24
26
  hasKey: boolean;
25
27
  /** In the provider's live /models catalog. null = not checkable (anthropic kind, or catalog down). */
26
28
  listed: boolean | null;
27
- benchmarks: BenchmarkScores;
28
29
  /** BFCL tool-use + LMArena scores, best-effort id→leaderboard match (null when no confident match). */
29
30
  capability: CapabilityScore | null;
30
31
  health: {
@@ -50,12 +51,53 @@ export interface Candidate {
50
51
  avgLatencyMs: number | null;
51
52
  lastCalledAt: string | null;
52
53
  } | null;
54
+ /**
55
+ * Limits, each with its own provenance. `provider` = this provider published it about its own
56
+ * deployment; `reference` = borrowed from another provider serving the same model id (different
57
+ * deployment, so indicative only — `metadataReferenceFrom` names it); `static-table` = the
58
+ * hardcoded table, including its blanket 128k/4096 guess.
59
+ */
53
60
  contextLength: number | null;
61
+ contextLengthSource: MetadataSource | null;
54
62
  maxOutputTokens: number | null;
55
- /** Existing composites, reported for transparency about what the proxy itself sorts by. */
63
+ maxOutputTokensSource: MetadataSource | null;
64
+ metadataReferenceFrom?: string;
65
+ /** Per-million-token price, with the same provenance rules — a model free on one host and
66
+ * metered on another must not report the other's rate. */
67
+ pricePerMTokIn: number | null;
68
+ pricePerMTokOut: number | null;
69
+ priceSource: MetadataSource | null;
70
+ supportsTools: boolean | null;
71
+ /** Which leaderboards published anything about this model. */
72
+ capabilitySources: string[];
73
+ /** Raw per-source capability values — kept separate, never collapsed into one another. */
74
+ scores: {
75
+ /** Berkeley Function-Calling: tool-call accuracy, multi-turn, irrelevance detection. */
76
+ bfclOverall: number | null;
77
+ bfclMultiTurn: number | null;
78
+ bfclIrrelevance: number | null;
79
+ /** Artificial Analysis indices, via OpenRouter. */
80
+ aaIntelligence: number | null;
81
+ aaCoding: number | null;
82
+ aaAgentic: number | null;
83
+ /** Aider polyglot edit benchmark + edit-format compliance. */
84
+ aiderPassRate: number | null;
85
+ aiderWellFormed: number | null;
86
+ /** Design Arena Elo, averaged per arena (means, not measurements — see the `_mean` naming). */
87
+ designArenaAgentsEloMean: number | null;
88
+ designArenaModelsEloMean: number | null;
89
+ /** LMArena. */
90
+ arenaRating: number | null;
91
+ arenaRank: number | null;
92
+ };
93
+ /** What the proxy itself sorts by — the ONE place a scalar exists, with its provenance. */
56
94
  sortInputs: {
57
95
  /** Drives `routing.benchmarkSort` ordering within a pool. */
58
- benchmarkQuality: number;
96
+ strength: number;
97
+ /** snapshot | telemetry | neutral. A telemetry score is not a capability score. */
98
+ strengthBasis: StrengthBasis;
99
+ /** How many published signals backed it. 1 is a guess; 5 is a consensus. */
100
+ strengthSignals: string[];
59
101
  /** Drives circuit-breaker candidate ordering. 100 when untracked. */
60
102
  breakerStability: number;
61
103
  };
@@ -1,12 +1,14 @@
1
1
  import { POOL_PREFIX } from "./config.js";
2
- import { getBenchmarkScores, calculateQualityScore } from "./benchmarks.js";
3
- import { getModelMetadata } from "./metadata.js";
2
+ import { getStrength } from "./benchmarks.js";
3
+ import { findTierModel } from "./tier-data.js";
4
+ import { resolveMetadata } from "./metadata.js";
4
5
  import { globalCircuitBreaker } from "./circuit-breaker.js";
5
6
  import { loadRuntimeTelemetry } from "./ping/runtime-telemetry.js";
6
7
  import { loadTierData, joinCapability } from "./registry.js";
7
8
  const NOTE = "Raw per-dimension data for choosing an offload target. Nothing here is ranked or averaged — " +
8
- "order is config order (pools, then subagent targets). `sortInputs` reports the composites the " +
9
- "proxy already sorts by; they are not a recommendation.";
9
+ "order is config order (pools, then subagent targets), and every source's score is kept " +
10
+ "separately under `scores`. `sortInputs` reports the ONE scalar the proxy needs for pool " +
11
+ "ordering, with the basis and signal list that produced it; it is not a recommendation.";
10
12
  /** Expand a spec that may itself be `pool/<name>` into concrete "provider/model" specs. */
11
13
  function expandSpec(spec, cfg) {
12
14
  const i = spec.indexOf("/");
@@ -69,8 +71,25 @@ export async function buildCandidates(cfg, opts = {}) {
69
71
  const summary = opts.pingLoop && model ? opts.pingLoop.getModelSummary(provider, model) : null;
70
72
  const state = breaker.getState(spec);
71
73
  const obs = telemetry.models[`${provider}/${model}`];
72
- const meta = getModelMetadata(model ?? provider);
73
- const benchmarks = getBenchmarkScores(spec);
74
+ const strength = getStrength(spec);
75
+ const tier = findTierModel(model ?? spec, byNorm)?.rec;
76
+ const num = (k) => (typeof tier?.[k] === "number" ? tier[k] : null);
77
+ // Limits THIS provider publishes about its own deployment, if any. NIM publishes none;
78
+ // Groq and Mistral publish real ones. The snapshot's numbers come from OpenRouter, so for a
79
+ // NIM target they are a different deployment's figures and are labelled `reference`, never
80
+ // presented as this provider's own.
81
+ const providerLimits = p && p.kind === "openai" && model && opts.catalog
82
+ ? await opts.catalog.limits(provider, p, model).catch(() => null)
83
+ : null;
84
+ const meta = resolveMetadata(model ?? provider, {
85
+ providerLimits,
86
+ reference: {
87
+ contextLength: num("context_length"),
88
+ pricePromptPerToken: num("price_prompt"),
89
+ priceCompletionPerToken: num("price_completion"),
90
+ from: "openrouter",
91
+ },
92
+ });
74
93
  candidates.push({
75
94
  spec,
76
95
  provider,
@@ -79,7 +98,6 @@ export async function buildCandidates(cfg, opts = {}) {
79
98
  subagentTiers: membership.subagentTiers,
80
99
  hasKey: p?.authEnv ? !!process.env[p.authEnv]?.trim() : true,
81
100
  listed,
82
- benchmarks,
83
101
  capability: model ? joinCapability(model, byNorm) : null,
84
102
  health: summary
85
103
  ? {
@@ -107,10 +125,34 @@ export async function buildCandidates(cfg, opts = {}) {
107
125
  lastCalledAt: obs.lastCalledAt ? new Date(obs.lastCalledAt).toISOString() : null,
108
126
  }
109
127
  : null,
110
- contextLength: meta.contextLength ?? null,
111
- maxOutputTokens: meta.maxOutputTokens ?? null,
128
+ contextLength: meta.contextLength,
129
+ contextLengthSource: meta.contextLengthSource,
130
+ maxOutputTokens: meta.maxOutputTokens,
131
+ maxOutputTokensSource: meta.maxOutputTokensSource,
132
+ ...(meta.referenceFrom ? { metadataReferenceFrom: meta.referenceFrom } : {}),
133
+ pricePerMTokIn: meta.pricePerMTokIn,
134
+ pricePerMTokOut: meta.pricePerMTokOut,
135
+ priceSource: meta.priceSource,
136
+ supportsTools: typeof tier?.supports_tools === "boolean" ? tier.supports_tools : null,
137
+ capabilitySources: Array.isArray(tier?.sources) ? tier.sources : [],
138
+ scores: {
139
+ bfclOverall: num("bfcl_overall"),
140
+ bfclMultiTurn: num("bfcl_multi_turn"),
141
+ bfclIrrelevance: num("bfcl_irrelevance"),
142
+ aaIntelligence: num("aa_intelligence"),
143
+ aaCoding: num("aa_coding"),
144
+ aaAgentic: num("aa_agentic"),
145
+ aiderPassRate: num("aider_pass_rate"),
146
+ aiderWellFormed: num("aider_well_formed"),
147
+ designArenaAgentsEloMean: num("design_arena_agents_elo_mean"),
148
+ designArenaModelsEloMean: num("design_arena_models_elo_mean"),
149
+ arenaRating: num("arena_rating"),
150
+ arenaRank: num("arena_rank"),
151
+ },
112
152
  sortInputs: {
113
- benchmarkQuality: calculateQualityScore(benchmarks),
153
+ strength: strength.score,
154
+ strengthBasis: strength.basis,
155
+ strengthSignals: strength.signals ?? [],
114
156
  breakerStability: breaker.getStabilityScore(spec),
115
157
  },
116
158
  });
@@ -1 +1 @@
1
- {"version":3,"file":"candidates.js","sourceRoot":"","sources":["../src/candidates.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"candidates.js","sourceRoot":"","sources":["../src/candidates.ts"],"names":[],"mappings":"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"}
package/dist/catalog.d.ts CHANGED
@@ -1,4 +1,21 @@
1
1
  import type { ProviderConfig } from "./config.js";
2
+ /**
3
+ * Limits a provider publishes about its OWN deployment of a model.
4
+ *
5
+ * Deliberately per-(provider, model): the same model id served by two providers is two different
6
+ * deployments with different ceilings, so one provider's numbers must never be presented as
7
+ * another's. Null means "this provider does not publish it" — NIM's /models returns only
8
+ * id/object/created/owned_by, while Groq and Mistral publish real limits.
9
+ */
10
+ export interface ModelLimits {
11
+ contextLength: number | null;
12
+ maxOutputTokens: number | null;
13
+ /** Per-TOKEN price, as published. Per-provider for the same reason limits are. */
14
+ pricePromptPerToken: number | null;
15
+ priceCompletionPerToken: number | null;
16
+ }
17
+ /** Read limits + pricing out of one `/models` record, including a nested `top_provider` (OpenRouter). */
18
+ export declare function limitsFromRecord(rec: Record<string, unknown>): ModelLimits;
2
19
  /**
3
20
  * Live per-provider model catalog — model ids are DISCOVERED from each provider's
4
21
  * OpenAI-compatible `/models` endpoint, never hand-maintained. In-memory TTL cache
@@ -14,6 +31,8 @@ export declare class ModelCatalog {
14
31
  private refreshing;
15
32
  /** In-flight blocking fetches (cold start / forced) — dedups concurrent requests. */
16
33
  private pending;
34
+ /** Limits harvested by the most recent `fetch()`, handed to the Entry by its caller. */
35
+ private lastLimits;
17
36
  constructor(opts?: {
18
37
  ttlMs?: number;
19
38
  cachePath?: string | null;
@@ -53,5 +72,16 @@ export declare class ModelCatalog {
53
72
  now?: number;
54
73
  fetchFn?: typeof fetch;
55
74
  }): Promise<boolean | null>;
75
+ /**
76
+ * Limits this provider publishes for one of its own models, or null when it publishes none.
77
+ *
78
+ * Null is meaningful and must not be papered over with another provider's number — see
79
+ * `resolveMetadata()` in metadata.ts, which decides what to fall back to and labels it.
80
+ */
81
+ limits(name: string, cfg: ProviderConfig, model: string, opts?: {
82
+ force?: boolean;
83
+ now?: number;
84
+ fetchFn?: typeof fetch;
85
+ }): Promise<ModelLimits | null>;
56
86
  private fetch;
57
87
  }