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 +40 -18
- package/dist/benchmarks.d.ts +36 -10
- package/dist/benchmarks.js +52 -71
- package/dist/benchmarks.js.map +1 -1
- package/dist/candidates.d.ts +51 -9
- package/dist/candidates.js +52 -10
- package/dist/candidates.js.map +1 -1
- package/dist/catalog.d.ts +30 -0
- package/dist/catalog.js +66 -3
- package/dist/catalog.js.map +1 -1
- package/dist/cli.js +60 -32
- package/dist/cli.js.map +1 -1
- package/dist/metadata.d.ts +51 -1
- package/dist/metadata.js +55 -1
- package/dist/metadata.js.map +1 -1
- package/dist/registry.d.ts +3 -11
- package/dist/registry.js +2 -42
- package/dist/registry.js.map +1 -1
- package/dist/tier-data.d.ts +43 -0
- package/dist/tier-data.js +61 -0
- package/dist/tier-data.js.map +1 -0
- package/docs/tier-data.json +15114 -2268
- package/package.json +1 -1
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
|
|
315
|
-
nim/z-ai/glm-5.2
|
|
316
|
-
nim/
|
|
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
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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.
|
package/dist/benchmarks.d.ts
CHANGED
|
@@ -1,13 +1,39 @@
|
|
|
1
1
|
import type { ResolvedTarget } from "./config.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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[];
|
package/dist/benchmarks.js
CHANGED
|
@@ -1,79 +1,60 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
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
|
package/dist/benchmarks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"benchmarks.js","sourceRoot":"","sources":["../src/benchmarks.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/candidates.d.ts
CHANGED
|
@@ -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
|
|
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:
|
|
11
|
-
* different things and trade off against each other differently per task ("cheapest that
|
|
12
|
-
* it" vs "best available"). Averaging them into one number would bury exactly the judgement
|
|
13
|
-
* reader is here to make. The
|
|
14
|
-
*
|
|
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 it — because 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
|
-
|
|
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
|
-
|
|
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
|
};
|
package/dist/candidates.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { POOL_PREFIX } from "./config.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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)
|
|
9
|
-
"
|
|
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
|
|
73
|
-
const
|
|
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
|
|
111
|
-
|
|
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
|
-
|
|
153
|
+
strength: strength.score,
|
|
154
|
+
strengthBasis: strength.basis,
|
|
155
|
+
strengthSignals: strength.signals ?? [],
|
|
114
156
|
breakerStability: breaker.getStabilityScore(spec),
|
|
115
157
|
},
|
|
116
158
|
});
|
package/dist/candidates.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"candidates.js","sourceRoot":"","sources":["../src/candidates.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1C,OAAO,EAAE,
|
|
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
|
}
|