llm-relay 0.0.11 → 0.0.13

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.
Files changed (57) hide show
  1. package/README.md +78 -5
  2. package/dist/benchmarks.d.ts +13 -0
  3. package/dist/benchmarks.js +79 -0
  4. package/dist/benchmarks.js.map +1 -0
  5. package/dist/circuit-breaker.d.ts +32 -0
  6. package/dist/circuit-breaker.js +98 -0
  7. package/dist/circuit-breaker.js.map +1 -0
  8. package/dist/cli.d.ts +4 -0
  9. package/dist/cli.js +134 -21
  10. package/dist/cli.js.map +1 -1
  11. package/dist/config.d.ts +14 -7
  12. package/dist/config.js +64 -25
  13. package/dist/config.js.map +1 -1
  14. package/dist/key-checker.d.ts +13 -0
  15. package/dist/key-checker.js +101 -0
  16. package/dist/key-checker.js.map +1 -0
  17. package/dist/metadata.d.ts +10 -0
  18. package/dist/metadata.js +74 -0
  19. package/dist/metadata.js.map +1 -0
  20. package/dist/onboarding.d.ts +14 -0
  21. package/dist/onboarding.js +100 -0
  22. package/dist/onboarding.js.map +1 -0
  23. package/dist/ping/cadence.d.ts +52 -0
  24. package/dist/ping/cadence.js +165 -0
  25. package/dist/ping/cadence.js.map +1 -0
  26. package/dist/ping/metrics.d.ts +23 -0
  27. package/dist/ping/metrics.js +88 -0
  28. package/dist/ping/metrics.js.map +1 -0
  29. package/dist/ping/ping.d.ts +40 -0
  30. package/dist/ping/ping.js +231 -0
  31. package/dist/ping/ping.js.map +1 -0
  32. package/dist/ping/probe-cache.d.ts +40 -0
  33. package/dist/ping/probe-cache.js +96 -0
  34. package/dist/ping/probe-cache.js.map +1 -0
  35. package/dist/ping/quota.d.ts +15 -0
  36. package/dist/ping/quota.js +42 -0
  37. package/dist/ping/quota.js.map +1 -0
  38. package/dist/ping/runtime-telemetry.d.ts +42 -0
  39. package/dist/ping/runtime-telemetry.js +86 -0
  40. package/dist/ping/runtime-telemetry.js.map +1 -0
  41. package/dist/presets.d.ts +23 -0
  42. package/dist/presets.js +167 -0
  43. package/dist/presets.js.map +1 -0
  44. package/dist/registry.d.ts +6 -2
  45. package/dist/registry.js +7 -1
  46. package/dist/registry.js.map +1 -1
  47. package/dist/server.d.ts +2 -0
  48. package/dist/server.js +113 -45
  49. package/dist/server.js.map +1 -1
  50. package/dist/setup-claude.d.ts +16 -0
  51. package/dist/setup-claude.js +78 -0
  52. package/dist/setup-claude.js.map +1 -0
  53. package/dist/telemetry.d.ts +26 -0
  54. package/dist/telemetry.js +43 -0
  55. package/dist/telemetry.js.map +1 -0
  56. package/docs/tier-data.json +2137 -2060
  57. package/package.json +1 -1
@@ -0,0 +1,165 @@
1
+ import { pingProviderModel } from "./ping.js";
2
+ import { getAvg, getP95, getJitter, getStabilityScore, getVerdict, getUptime } from "./metrics.js";
3
+ import { recordProbeResult, getModelsDueForProbe } from "./probe-cache.js";
4
+ export const PING_MODE_INTERVALS = {
5
+ speed: 2000,
6
+ normal: 10000,
7
+ slow: 30000,
8
+ forced: 4000,
9
+ };
10
+ export const SPEED_MODE_DURATION_MS = 60000; // 60s
11
+ export const IDLE_SLOW_AFTER_MS = 300000; // 5 min
12
+ export class PingLoop {
13
+ cfg;
14
+ catalog;
15
+ opts;
16
+ mode = "speed";
17
+ modeSource = "startup";
18
+ intervalMs = PING_MODE_INTERVALS.speed;
19
+ speedUntil = Date.now() + SPEED_MODE_DURATION_MS;
20
+ lastActivityAt = Date.now();
21
+ resumeSpeedOnActivity = false;
22
+ timerObj = null;
23
+ running = false;
24
+ pingHistory = new Map();
25
+ latestQuota = new Map();
26
+ constructor(cfg, catalog, opts = {}) {
27
+ this.cfg = cfg;
28
+ this.catalog = catalog;
29
+ this.opts = opts;
30
+ }
31
+ getMode() {
32
+ return this.mode;
33
+ }
34
+ getIntervalMs() {
35
+ return this.intervalMs;
36
+ }
37
+ setPingMode(nextMode, source = "manual") {
38
+ this.mode = nextMode;
39
+ this.modeSource = source;
40
+ this.intervalMs = PING_MODE_INTERVALS[nextMode];
41
+ this.speedUntil = nextMode === "speed" ? Date.now() + SPEED_MODE_DURATION_MS : null;
42
+ this.resumeSpeedOnActivity = source === "idle";
43
+ if (this.timerObj) {
44
+ clearTimeout(this.timerObj);
45
+ this.timerObj = null;
46
+ }
47
+ }
48
+ noteUserActivity() {
49
+ this.lastActivityAt = Date.now();
50
+ if (this.mode === "forced")
51
+ return;
52
+ if (this.resumeSpeedOnActivity || this.mode === "slow") {
53
+ this.setPingMode("speed", "activity");
54
+ }
55
+ }
56
+ refreshAutoPingMode() {
57
+ const now = Date.now();
58
+ if (this.mode === "forced")
59
+ return;
60
+ if (this.speedUntil && now >= this.speedUntil) {
61
+ this.setPingMode("normal", "auto");
62
+ return;
63
+ }
64
+ if (now - this.lastActivityAt >= IDLE_SLOW_AFTER_MS) {
65
+ if (this.mode !== "slow") {
66
+ this.setPingMode("slow", "idle");
67
+ }
68
+ else {
69
+ this.resumeSpeedOnActivity = true;
70
+ }
71
+ }
72
+ }
73
+ recordPing(providerKey, modelId, res, timestamp = Date.now()) {
74
+ const key = `${providerKey}/${modelId}`;
75
+ let history = this.pingHistory.get(key);
76
+ if (!history) {
77
+ history = [];
78
+ this.pingHistory.set(key, history);
79
+ }
80
+ history.push({ ms: res.ms, code: res.code, timestamp });
81
+ if (history.length > 50)
82
+ history.shift();
83
+ if (res.quotaPercent !== null) {
84
+ this.latestQuota.set(providerKey, res.quotaPercent);
85
+ }
86
+ recordProbeResult(providerKey, modelId, res);
87
+ }
88
+ getModelPings(providerKey, modelId) {
89
+ return this.pingHistory.get(`${providerKey}/${modelId}`) ?? [];
90
+ }
91
+ getProviderQuota(providerKey) {
92
+ return this.latestQuota.get(providerKey) ?? null;
93
+ }
94
+ getModelSummary(providerKey, modelId) {
95
+ const pings = this.getModelPings(providerKey, modelId);
96
+ const avgMs = getAvg(pings);
97
+ const p95Ms = getP95(pings);
98
+ const jitterMs = getJitter(pings);
99
+ const stabilityScore = getStabilityScore(pings);
100
+ const uptimePct = getUptime(pings);
101
+ const lastPing = pings[pings.length - 1];
102
+ const verdict = getVerdict(pings, {
103
+ httpCode: lastPing?.code ?? null,
104
+ isDown: lastPing ? lastPing.code !== "200" && lastPing.code !== "401" : false,
105
+ });
106
+ return {
107
+ providerKey,
108
+ modelId,
109
+ avgMs: avgMs === Infinity ? -1 : avgMs,
110
+ p95Ms: p95Ms === Infinity ? -1 : p95Ms,
111
+ jitterMs,
112
+ stabilityScore,
113
+ uptimePct,
114
+ verdict,
115
+ quotaPercent: this.getProviderQuota(providerKey),
116
+ lastPingCode: lastPing?.code ?? null,
117
+ lastPingMs: lastPing?.ms ?? null,
118
+ };
119
+ }
120
+ async tickOnce() {
121
+ this.refreshAutoPingMode();
122
+ for (const [providerName, pCfg] of Object.entries(this.cfg.providers)) {
123
+ const apiKey = pCfg.authEnv ? process.env[pCfg.authEnv] : undefined;
124
+ let modelIds = [];
125
+ try {
126
+ modelIds = await this.catalog.list(providerName, pCfg, optsObj(this.opts.fetchFn));
127
+ }
128
+ catch { }
129
+ if (modelIds.length === 0)
130
+ continue;
131
+ const dueIds = getModelsDueForProbe(providerName, modelIds);
132
+ // Probe up to 3 due models per provider per tick to avoid flooding
133
+ const toProbe = dueIds.slice(0, 3);
134
+ for (const mId of toProbe) {
135
+ const res = await pingProviderModel(providerName, mId, pCfg, apiKey, optsObj(this.opts.fetchFn));
136
+ this.recordPing(providerName, mId, res);
137
+ }
138
+ }
139
+ }
140
+ start() {
141
+ if (this.running)
142
+ return;
143
+ this.running = true;
144
+ const loop = async () => {
145
+ if (!this.running)
146
+ return;
147
+ await this.tickOnce().catch(() => { });
148
+ if (this.running) {
149
+ this.timerObj = setTimeout(loop, this.intervalMs);
150
+ }
151
+ };
152
+ void loop();
153
+ }
154
+ stop() {
155
+ this.running = false;
156
+ if (this.timerObj) {
157
+ clearTimeout(this.timerObj);
158
+ this.timerObj = null;
159
+ }
160
+ }
161
+ }
162
+ function optsObj(fetchFn) {
163
+ return fetchFn ? { fetchFn } : {};
164
+ }
165
+ //# sourceMappingURL=cadence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cadence.js","sourceRoot":"","sources":["../../src/ping/cadence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface PingRecord {
2
+ ms: number;
3
+ code: string;
4
+ timestamp: number;
5
+ }
6
+ export type Verdict = "Perfect" | "Normal" | "Slow" | "Spiky" | "Overloaded" | "Unstable" | "Not Active" | "Pending";
7
+ /** Calculate average latency from measurable pings (HTTP 200/401). Returns Infinity if none. */
8
+ export declare function getAvg(pings: PingRecord[]): number;
9
+ /** Calculate 95th percentile latency from measurable pings. Returns Infinity if none. */
10
+ export declare function getP95(pings: PingRecord[]): number;
11
+ /** Calculate latency standard deviation (jitter) in ms from measurable pings. */
12
+ export declare function getJitter(pings: PingRecord[]): number;
13
+ /** Calculate spike rate: fraction (0–1) of measurable pings with latency > 3000ms. */
14
+ export declare function getSpikeRate(pings: PingRecord[]): number;
15
+ /** Calculate uptime percentage (0–100) of HTTP 200 pings over total pings. */
16
+ export declare function getUptime(pings: PingRecord[]): number;
17
+ /** Calculate composite Stability Score (0–100). Returns -1 if no measurable pings exist. */
18
+ export declare function getStabilityScore(pings: PingRecord[]): number;
19
+ /** Determine human-readable health verdict for a model based on average latency and tail latency. */
20
+ export declare function getVerdict(pings: PingRecord[], opts?: {
21
+ httpCode?: string | null;
22
+ isDown?: boolean;
23
+ }): Verdict;
@@ -0,0 +1,88 @@
1
+ const MEASURABLE_CODES = new Set(["200", "401"]);
2
+ /** Calculate average latency from measurable pings (HTTP 200/401). Returns Infinity if none. */
3
+ export function getAvg(pings) {
4
+ const measurable = pings.filter((p) => MEASURABLE_CODES.has(p.code));
5
+ if (measurable.length === 0)
6
+ return Infinity;
7
+ const sum = measurable.reduce((acc, p) => acc + p.ms, 0);
8
+ return Math.round(sum / measurable.length);
9
+ }
10
+ /** Calculate 95th percentile latency from measurable pings. Returns Infinity if none. */
11
+ export function getP95(pings) {
12
+ const measurable = pings.filter((p) => MEASURABLE_CODES.has(p.code));
13
+ if (measurable.length === 0)
14
+ return Infinity;
15
+ const sorted = measurable.map((p) => p.ms).sort((a, b) => a - b);
16
+ const idx = Math.ceil(sorted.length * 0.95) - 1;
17
+ return sorted[Math.max(0, idx)];
18
+ }
19
+ /** Calculate latency standard deviation (jitter) in ms from measurable pings. */
20
+ export function getJitter(pings) {
21
+ const measurable = pings.filter((p) => MEASURABLE_CODES.has(p.code));
22
+ if (measurable.length < 2)
23
+ return 0;
24
+ const mean = measurable.reduce((acc, p) => acc + p.ms, 0) / measurable.length;
25
+ const variance = measurable.reduce((sum, p) => sum + (p.ms - mean) ** 2, 0) / measurable.length;
26
+ return Math.round(Math.sqrt(variance));
27
+ }
28
+ /** Calculate spike rate: fraction (0–1) of measurable pings with latency > 3000ms. */
29
+ export function getSpikeRate(pings) {
30
+ const measurable = pings.filter((p) => MEASURABLE_CODES.has(p.code));
31
+ if (measurable.length === 0)
32
+ return 0;
33
+ const spikes = measurable.filter((p) => p.ms > 3000).length;
34
+ return spikes / measurable.length;
35
+ }
36
+ /** Calculate uptime percentage (0–100) of HTTP 200 pings over total pings. */
37
+ export function getUptime(pings) {
38
+ if (pings.length === 0)
39
+ return 0;
40
+ const successful = pings.filter((p) => p.code === "200").length;
41
+ return Math.round((successful / pings.length) * 100);
42
+ }
43
+ /** Calculate composite Stability Score (0–100). Returns -1 if no measurable pings exist. */
44
+ export function getStabilityScore(pings) {
45
+ const measurable = pings.filter((p) => MEASURABLE_CODES.has(p.code));
46
+ if (measurable.length === 0)
47
+ return -1;
48
+ const p95 = getP95(pings);
49
+ const jitter = getJitter(pings);
50
+ const uptime = getUptime(pings);
51
+ const spikeRate = getSpikeRate(pings);
52
+ const p95Score = Math.max(0, Math.min(100, 100 * (1 - p95 / 5000)));
53
+ const jitterScore = Math.max(0, Math.min(100, 100 * (1 - jitter / 2000)));
54
+ const spikeScore = Math.max(0, 100 * (1 - spikeRate));
55
+ const reliabilityScore = uptime;
56
+ const score = 0.3 * p95Score + 0.3 * jitterScore + 0.2 * spikeScore + 0.2 * reliabilityScore;
57
+ return Math.round(score);
58
+ }
59
+ /** Determine human-readable health verdict for a model based on average latency and tail latency. */
60
+ export function getVerdict(pings, opts = {}) {
61
+ if (opts.httpCode === "429")
62
+ return "Overloaded";
63
+ const wasUpBefore = pings.length > 0 && pings.some((p) => p.code === "200");
64
+ if (opts.isDown) {
65
+ return wasUpBefore ? "Unstable" : "Not Active";
66
+ }
67
+ const avg = getAvg(pings);
68
+ if (avg === Infinity)
69
+ return "Pending";
70
+ const measurable = pings.filter((p) => MEASURABLE_CODES.has(p.code));
71
+ const p95 = getP95(pings);
72
+ if (avg < 400) {
73
+ if (measurable.length >= 3 && p95 > 3000)
74
+ return "Spiky";
75
+ return "Perfect";
76
+ }
77
+ if (avg < 1000) {
78
+ if (measurable.length >= 3 && p95 > 5000)
79
+ return "Spiky";
80
+ return "Normal";
81
+ }
82
+ if (avg < 3000)
83
+ return "Slow";
84
+ if (avg < 5000)
85
+ return "Slow";
86
+ return "Unstable";
87
+ }
88
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/ping/metrics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type { ProviderConfig } from "../config.js";
2
+ export declare const DEFAULT_PING_TIMEOUT_MS = 15000;
3
+ export declare const DEFAULT_BENCHMARK_TIMEOUT_MS = 20000;
4
+ export interface PingResult {
5
+ code: string;
6
+ ms: number;
7
+ quotaPercent: number | null;
8
+ }
9
+ export interface BenchmarkResult {
10
+ ok: boolean;
11
+ code: string;
12
+ totalMs: number;
13
+ outputTokens: number;
14
+ tokensPerSecond: number;
15
+ answerPreview: string;
16
+ }
17
+ /** Parse rate-limit response headers to calculate remaining quota percentage (0–100). */
18
+ export declare function extractQuotaPercent(headers: Headers | Record<string, string | undefined>): number | null;
19
+ export declare function markDisabledThinkingUnsupported(providerName: string): void;
20
+ export declare function shouldUseDisabledThinkingForProvider(providerName: string): boolean;
21
+ export declare function buildPingEndpoint(base: string, kind: string): string;
22
+ export declare function buildPingRequest(providerName: string, modelId: string, cfg: ProviderConfig, apiKey?: string, options?: {
23
+ disableThinking?: boolean;
24
+ }): {
25
+ url: string;
26
+ headers: Record<string, string>;
27
+ body: Record<string, unknown>;
28
+ };
29
+ /** Execute a single async ping to measure latency and remaining quota. */
30
+ export declare function pingProviderModel(providerName: string, modelId: string, cfg: ProviderConfig, apiKey?: string, opts?: {
31
+ timeoutMs?: number;
32
+ fetchFn?: typeof fetch;
33
+ }): Promise<PingResult>;
34
+ /** Execute a benchmark prompt against a provider model to measure throughput (TPS). */
35
+ export declare function benchmarkProviderModel(providerName: string, modelId: string, cfg: ProviderConfig, apiKey?: string, opts?: {
36
+ prompt?: string;
37
+ maxTokens?: number;
38
+ timeoutMs?: number;
39
+ fetchFn?: typeof fetch;
40
+ }): Promise<BenchmarkResult>;
@@ -0,0 +1,231 @@
1
+ export const DEFAULT_PING_TIMEOUT_MS = 15000;
2
+ export const DEFAULT_BENCHMARK_TIMEOUT_MS = 20000;
3
+ const DISABLED_THINKING_RETRY_STATUSES = new Set([400, 422]);
4
+ const disabledThinkingUnsupportedProviders = new Set();
5
+ function getHeaderValue(headers, key) {
6
+ if (!headers)
7
+ return null;
8
+ if (typeof headers.get === "function") {
9
+ return headers.get(key);
10
+ }
11
+ const obj = headers;
12
+ return obj[key] ?? obj[key.toLowerCase()] ?? null;
13
+ }
14
+ /** Parse rate-limit response headers to calculate remaining quota percentage (0–100). */
15
+ export function extractQuotaPercent(headers) {
16
+ const variants = [
17
+ ["x-ratelimit-remaining", "x-ratelimit-limit"],
18
+ ["x-ratelimit-remaining-requests", "x-ratelimit-limit-requests"],
19
+ ["x-ratelimit-remaining-requests-day", "x-ratelimit-limit-requests-day"],
20
+ ["x-ratelimit-remaining-tokens", "x-ratelimit-limit-tokens"],
21
+ ["x-ratelimit-remaining-tokens-minute", "x-ratelimit-limit-tokens-minute"],
22
+ ["ratelimit-remaining", "ratelimit-limit"],
23
+ ["ratelimit-remaining-requests", "ratelimit-limit-requests"],
24
+ ];
25
+ for (const [remainingKey, limitKey] of variants) {
26
+ const remainingRaw = getHeaderValue(headers, remainingKey);
27
+ const limitRaw = getHeaderValue(headers, limitKey);
28
+ if (remainingRaw !== null && limitRaw !== null) {
29
+ const remaining = parseFloat(remainingRaw);
30
+ const limit = parseFloat(limitRaw);
31
+ if (Number.isFinite(remaining) && Number.isFinite(limit) && limit > 0) {
32
+ const pct = Math.round((remaining / limit) * 100);
33
+ return Math.max(0, Math.min(100, pct));
34
+ }
35
+ }
36
+ }
37
+ return null;
38
+ }
39
+ export function markDisabledThinkingUnsupported(providerName) {
40
+ disabledThinkingUnsupportedProviders.add(providerName);
41
+ }
42
+ export function shouldUseDisabledThinkingForProvider(providerName) {
43
+ if (["cerebras", "mistral", "groq", "sambanova"].includes(providerName))
44
+ return false;
45
+ return !disabledThinkingUnsupportedProviders.has(providerName);
46
+ }
47
+ export function buildPingEndpoint(base, kind) {
48
+ const cleanBase = base.endsWith("/") ? base.slice(0, -1) : base;
49
+ if (kind === "openai") {
50
+ return cleanBase.endsWith("/chat/completions") ? cleanBase : `${cleanBase}/chat/completions`;
51
+ }
52
+ return cleanBase.endsWith("/messages") ? cleanBase : `${cleanBase}/v1/messages`;
53
+ }
54
+ export function buildPingRequest(providerName, modelId, cfg, apiKey, options = {}) {
55
+ const url = buildPingEndpoint(cfg.base, cfg.kind);
56
+ const headers = { "Content-Type": "application/json" };
57
+ if (apiKey) {
58
+ if (cfg.authHeader === "x-api-key" || cfg.kind === "anthropic") {
59
+ headers["x-api-key"] = apiKey;
60
+ }
61
+ else {
62
+ headers["authorization"] = apiKey.startsWith("Bearer ") ? apiKey : `Bearer ${apiKey}`;
63
+ }
64
+ }
65
+ if (cfg.kind === "openai") {
66
+ const body = {
67
+ model: modelId,
68
+ messages: [{ role: "user", content: "hi" }],
69
+ max_tokens: 1,
70
+ };
71
+ const allowThinkingToggle = options.disableThinking ?? shouldUseDisabledThinkingForProvider(providerName);
72
+ if (allowThinkingToggle) {
73
+ body["thinking"] = { type: "disabled" };
74
+ }
75
+ return { url, headers, body };
76
+ }
77
+ // Anthropic Messages probe
78
+ headers["anthropic-version"] = "2023-06-01";
79
+ const body = {
80
+ model: modelId,
81
+ messages: [{ role: "user", content: "hi" }],
82
+ max_tokens: 1,
83
+ };
84
+ return { url, headers, body };
85
+ }
86
+ async function sendPingFetch(req, signal, fetchFn = fetch) {
87
+ return fetchFn(req.url, {
88
+ method: "POST",
89
+ signal,
90
+ headers: req.headers,
91
+ body: JSON.stringify(req.body),
92
+ });
93
+ }
94
+ async function isDisabledThinkingRejected(resp, req) {
95
+ if (!req.body["thinking"] || !DISABLED_THINKING_RETRY_STATUSES.has(resp.status))
96
+ return false;
97
+ try {
98
+ const text = await resp.clone().text();
99
+ return /thinking/i.test(text);
100
+ }
101
+ catch {
102
+ return false;
103
+ }
104
+ }
105
+ /** Execute a single async ping to measure latency and remaining quota. */
106
+ export async function pingProviderModel(providerName, modelId, cfg, apiKey, opts = {}) {
107
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_PING_TIMEOUT_MS;
108
+ const ctrl = new AbortController();
109
+ const timer = setTimeout(() => ctrl.abort(), timeoutMs);
110
+ const t0 = performance.now();
111
+ try {
112
+ let req = buildPingRequest(providerName, modelId, cfg, apiKey);
113
+ let resp = await sendPingFetch(req, ctrl.signal, opts.fetchFn);
114
+ if (await isDisabledThinkingRejected(resp, req)) {
115
+ markDisabledThinkingUnsupported(providerName);
116
+ req = buildPingRequest(providerName, modelId, cfg, apiKey, { disableThinking: false });
117
+ resp = await sendPingFetch(req, ctrl.signal, opts.fetchFn);
118
+ }
119
+ const code = resp.status >= 200 && resp.status < 300 ? "200" : String(resp.status);
120
+ const ms = Math.round(performance.now() - t0);
121
+ const quotaPercent = extractQuotaPercent(resp.headers);
122
+ return { code, ms, quotaPercent };
123
+ }
124
+ catch (err) {
125
+ const isTimeout = err instanceof Error && err.name === "AbortError";
126
+ return {
127
+ code: isTimeout ? "000" : "ERR",
128
+ ms: isTimeout ? timeoutMs : Math.round(performance.now() - t0),
129
+ quotaPercent: null,
130
+ };
131
+ }
132
+ finally {
133
+ clearTimeout(timer);
134
+ }
135
+ }
136
+ /** Execute a benchmark prompt against a provider model to measure throughput (TPS). */
137
+ export async function benchmarkProviderModel(providerName, modelId, cfg, apiKey, opts = {}) {
138
+ const prompt = opts.prompt ?? "Why is the sky blue? Answer in exactly one paragraph of 80 to 100 words.";
139
+ const maxTokens = opts.maxTokens ?? 140;
140
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_BENCHMARK_TIMEOUT_MS;
141
+ const ctrl = new AbortController();
142
+ const timer = setTimeout(() => ctrl.abort(), timeoutMs);
143
+ const t0 = performance.now();
144
+ try {
145
+ const url = buildPingEndpoint(cfg.base, cfg.kind);
146
+ const headers = { "Content-Type": "application/json" };
147
+ if (apiKey) {
148
+ if (cfg.authHeader === "x-api-key" || cfg.kind === "anthropic") {
149
+ headers["x-api-key"] = apiKey;
150
+ }
151
+ else {
152
+ headers["authorization"] = apiKey.startsWith("Bearer ") ? apiKey : `Bearer ${apiKey}`;
153
+ }
154
+ }
155
+ let body;
156
+ if (cfg.kind === "openai") {
157
+ body = {
158
+ model: modelId,
159
+ messages: [{ role: "user", content: prompt }],
160
+ max_tokens: maxTokens,
161
+ temperature: 0,
162
+ };
163
+ }
164
+ else {
165
+ headers["anthropic-version"] = "2023-06-01";
166
+ body = {
167
+ model: modelId,
168
+ messages: [{ role: "user", content: prompt }],
169
+ max_tokens: maxTokens,
170
+ };
171
+ }
172
+ const resp = await (opts.fetchFn ?? fetch)(url, {
173
+ method: "POST",
174
+ signal: ctrl.signal,
175
+ headers,
176
+ body: JSON.stringify(body),
177
+ });
178
+ const totalMs = Math.round(performance.now() - t0);
179
+ const text = await resp.text();
180
+ let data = null;
181
+ try {
182
+ data = JSON.parse(text);
183
+ }
184
+ catch { }
185
+ if (!resp.ok) {
186
+ return {
187
+ ok: false,
188
+ code: String(resp.status),
189
+ totalMs,
190
+ outputTokens: 0,
191
+ tokensPerSecond: 0,
192
+ answerPreview: "",
193
+ };
194
+ }
195
+ let content = "";
196
+ let outputTokens = 0;
197
+ if (cfg.kind === "openai") {
198
+ content = data?.choices?.[0]?.message?.content || "";
199
+ outputTokens = data?.usage?.completion_tokens ?? Math.ceil(content.length / 4);
200
+ }
201
+ else {
202
+ content = data?.content?.[0]?.text || "";
203
+ outputTokens = data?.usage?.output_tokens ?? Math.ceil(content.length / 4);
204
+ }
205
+ const seconds = totalMs / 1000;
206
+ const tokensPerSecond = seconds > 0 ? Math.round(outputTokens / seconds) : 0;
207
+ return {
208
+ ok: true,
209
+ code: "200",
210
+ totalMs,
211
+ outputTokens,
212
+ tokensPerSecond,
213
+ answerPreview: content.slice(0, 60),
214
+ };
215
+ }
216
+ catch (err) {
217
+ const isTimeout = err instanceof Error && err.name === "AbortError";
218
+ return {
219
+ ok: false,
220
+ code: isTimeout ? "TIMEOUT" : "ERR",
221
+ totalMs: Math.round(performance.now() - t0),
222
+ outputTokens: 0,
223
+ tokensPerSecond: 0,
224
+ answerPreview: "",
225
+ };
226
+ }
227
+ finally {
228
+ clearTimeout(timer);
229
+ }
230
+ }
231
+ //# sourceMappingURL=ping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ping.js","sourceRoot":"","sources":["../../src/ping/ping.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ export declare const DEFAULT_PROBE_TTL_MS: number;
2
+ export declare const CURRENT_PROBE_VERSION = 1;
3
+ export interface ProbeEntry {
4
+ modelId: string;
5
+ status: "ok" | "broken";
6
+ lastProbedAt: number;
7
+ probeVersion: number;
8
+ ms: number;
9
+ code: string;
10
+ quotaPercent: number | null;
11
+ }
12
+ export interface ProbeCacheData {
13
+ version: number;
14
+ providers: Record<string, {
15
+ models: Record<string, ProbeEntry>;
16
+ }>;
17
+ }
18
+ export declare function getProbeCachePath(): string;
19
+ export declare function loadProbeCache(opts?: {
20
+ path?: string;
21
+ }): ProbeCacheData;
22
+ export declare function flushProbeCache(opts?: {
23
+ path?: string;
24
+ cache?: ProbeCacheData;
25
+ }): void;
26
+ export declare function getModelsDueForProbe(providerKey: string, modelIds: string[], opts?: {
27
+ ttlMs?: number;
28
+ now?: number;
29
+ probeVersion?: number;
30
+ path?: string;
31
+ }): string[];
32
+ export declare function recordProbeResult(providerKey: string, modelId: string, result: {
33
+ code: string;
34
+ ms: number;
35
+ quotaPercent: number | null;
36
+ }, opts?: {
37
+ now?: number;
38
+ probeVersion?: number;
39
+ path?: string;
40
+ }): ProbeEntry;