@danypops/jittor 0.5.1 → 0.7.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 +62 -7
- package/docs/BENCHMARK_SOURCES.md +32 -0
- package/docs/OUTPUT_CHANNELS.md +31 -0
- package/docs/PROVIDER_RESEARCH.md +57 -0
- package/extension/src/benchmark-tui.ts +105 -0
- package/extension/src/footer.ts +68 -12
- package/extension/src/index.ts +263 -36
- package/extension/src/tui.ts +61 -9
- package/extension/src/usage.ts +165 -47
- package/package.json +5 -1
- package/src/adapters/metric-benchmark-store.ts +99 -0
- package/src/adapters/openrouter-benchmark-index-source.ts +94 -0
- package/src/adapters/openrouter-benchmark-source.ts +109 -0
- package/src/adapters/sqlite-metric-store.ts +43 -2
- package/src/cli.ts +660 -9
- package/src/client.ts +12 -44
- package/src/constants.ts +69 -5
- package/src/daemon.ts +65 -43
- package/src/db.ts +13 -30
- package/src/domain/benchmark.ts +264 -0
- package/src/domain/context-telemetry.ts +31 -0
- package/src/domain/metric.ts +46 -5
- package/src/domain/model-observation.ts +203 -0
- package/src/domain/model-ranking-service.ts +41 -0
- package/src/domain/model-ranking.ts +232 -0
- package/src/domain/task-cost.ts +70 -0
- package/src/domain/task-focus.ts +65 -0
- package/src/domain/usage.ts +134 -33
- package/src/log.ts +28 -0
- package/src/ports/benchmark-controller.ts +11 -0
- package/src/ports/benchmark-source.ts +7 -0
- package/src/ports/benchmark-store.ts +7 -0
- package/src/ports/metric-store.ts +30 -0
- package/src/ports/router-controller.ts +1 -0
- package/src/providers/anthropic-contracts.ts +127 -0
- package/src/providers/google-adc-auth.ts +63 -0
- package/src/providers/google-vertex-budget-contracts.ts +181 -0
- package/src/providers/google-vertex-budget.ts +127 -0
- package/src/providers/google-vertex-contracts.ts +116 -0
- package/src/providers/telemetry-sources.ts +35 -0
- package/src/router.ts +12 -0
- package/src/service.ts +132 -17
- package/src/state.ts +31 -57
- package/src/version.ts +2 -14
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BENCHMARK_MAX_MODELS_PER_SOURCE,
|
|
3
|
+
BENCHMARK_REFRESH_INTERVAL_MS,
|
|
4
|
+
BENCHMARK_SOURCE_MAX_RESPONSE_BYTES,
|
|
5
|
+
BENCHMARK_SOURCE_MAX_TOTAL_RESPONSE_BYTES,
|
|
6
|
+
} from "../constants.ts";
|
|
7
|
+
import { normalizeModelIdentity, validateBenchmarkObservation, type BenchmarkObservation, type BenchmarkSourceSnapshot } from "../domain/benchmark.ts";
|
|
8
|
+
import type { BenchmarkSource } from "../ports/benchmark-source.ts";
|
|
9
|
+
import { contractRecord, parseOpenRouterModels, type OpenRouterModel } from "../providers/openrouter-contracts.ts";
|
|
10
|
+
|
|
11
|
+
const OPENROUTER_MODELS_BASE_URL = "https://openrouter.ai/api/v1/models";
|
|
12
|
+
const OPENROUTER_MODELS_URL = `${OPENROUTER_MODELS_BASE_URL}?limit=${BENCHMARK_MAX_MODELS_PER_SOURCE}`;
|
|
13
|
+
const OPENROUTER_LATENCY_URL = `${OPENROUTER_MODELS_URL}&sort=latency-low-to-high`;
|
|
14
|
+
const OPENROUTER_THROUGHPUT_URL = `${OPENROUTER_MODELS_URL}&sort=throughput-high-to-low`;
|
|
15
|
+
const SOURCE_ID = "openrouter-models";
|
|
16
|
+
|
|
17
|
+
export type OpenRouterBenchmarkTransport = (request: Request) => Promise<Response>;
|
|
18
|
+
|
|
19
|
+
function identity(model: OpenRouterModel) {
|
|
20
|
+
const separator = model.id.indexOf("/");
|
|
21
|
+
if (separator <= 0 || separator === model.id.length - 1) throw new Error("OpenRouter model identity schema changed");
|
|
22
|
+
const provider = model.id.slice(0, separator);
|
|
23
|
+
const modelId = model.id.slice(separator + 1);
|
|
24
|
+
const aliases = [`openrouter/${model.id}`, ...(model.canonicalSlug === model.id ? [] : [model.canonicalSlug])];
|
|
25
|
+
return normalizeModelIdentity(provider, modelId, aliases);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function provenance(retrievedAt: number, revision: string, url: string, confidence: number) {
|
|
29
|
+
return {
|
|
30
|
+
sourceId: SOURCE_ID,
|
|
31
|
+
sourceType: "marketplace" as const,
|
|
32
|
+
publisher: "OpenRouter",
|
|
33
|
+
url,
|
|
34
|
+
revision,
|
|
35
|
+
publishedAt: null,
|
|
36
|
+
retrievedAt,
|
|
37
|
+
freshUntil: retrievedAt + BENCHMARK_REFRESH_INTERVAL_MS,
|
|
38
|
+
license: "OpenRouter API terms",
|
|
39
|
+
confidence,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function modelObservations(model: OpenRouterModel, retrievedAt: number, revision: string): BenchmarkObservation[] {
|
|
44
|
+
const common = { model: identity(model), provenance: provenance(retrievedAt, revision, OPENROUTER_MODELS_URL, 0.9) };
|
|
45
|
+
return [
|
|
46
|
+
validateBenchmarkObservation({ ...common, dimension: "context-window", value: model.contextLength, unit: "tokens", methodology: { basis: "OpenRouter model context_length" } }),
|
|
47
|
+
...(model.maxCompletionTokens === null ? [] : [validateBenchmarkObservation({ ...common, dimension: "max-output", value: model.maxCompletionTokens, unit: "tokens", methodology: { basis: "OpenRouter top_provider max_completion_tokens" } })]),
|
|
48
|
+
validateBenchmarkObservation({ ...common, dimension: "price-input", value: model.pricing.prompt, unit: "usd", methodology: { basis: "USD per input token" } }),
|
|
49
|
+
validateBenchmarkObservation({ ...common, dimension: "price-output", value: model.pricing.completion, unit: "usd", methodology: { basis: "USD per output token" } }),
|
|
50
|
+
validateBenchmarkObservation({ ...common, dimension: "parameter-count", value: model.supportedParameters.length, unit: "count", methodology: { basis: "OpenRouter supported_parameters", parameters: [...model.supportedParameters].sort() } }),
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function rankObservations(models: OpenRouterModel[], dimension: "latency-rank" | "throughput-rank", retrievedAt: number, revision: string, url: string): BenchmarkObservation[] {
|
|
55
|
+
return models.map((model, index) => validateBenchmarkObservation({
|
|
56
|
+
model: identity(model),
|
|
57
|
+
dimension,
|
|
58
|
+
value: index + 1,
|
|
59
|
+
unit: "count",
|
|
60
|
+
provenance: provenance(retrievedAt, revision, url, 0.7),
|
|
61
|
+
methodology: { basis: dimension === "latency-rank" ? "OpenRouter p50 TTFT server-side ordering" : "OpenRouter p50 throughput server-side ordering", rank: index + 1 },
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface ModelResponse {
|
|
66
|
+
models: OpenRouterModel[];
|
|
67
|
+
etag: string | null;
|
|
68
|
+
bytes: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export class OpenRouterBenchmarkSource implements BenchmarkSource {
|
|
72
|
+
readonly id = SOURCE_ID;
|
|
73
|
+
|
|
74
|
+
constructor(
|
|
75
|
+
private readonly transport: OpenRouterBenchmarkTransport = fetch,
|
|
76
|
+
private readonly clock: () => number = Date.now,
|
|
77
|
+
) {}
|
|
78
|
+
|
|
79
|
+
private async readModels(url: string): Promise<ModelResponse> {
|
|
80
|
+
const response = await this.transport(new Request(url));
|
|
81
|
+
if (!response.ok) throw new Error(`OpenRouter models failed with HTTP ${response.status}`);
|
|
82
|
+
const text = await response.text();
|
|
83
|
+
const bytes = new TextEncoder().encode(text).byteLength;
|
|
84
|
+
if (bytes > BENCHMARK_SOURCE_MAX_RESPONSE_BYTES) throw new Error("OpenRouter models response exceeds the size limit");
|
|
85
|
+
let payload: unknown;
|
|
86
|
+
try { payload = JSON.parse(text); } catch { throw new Error("OpenRouter models response is not valid JSON"); }
|
|
87
|
+
const root = contractRecord(payload, "models response");
|
|
88
|
+
if (!Array.isArray(root["data"]) || root["data"].length === 0 || root["data"].length > BENCHMARK_MAX_MODELS_PER_SOURCE) throw new Error("OpenRouter models response exceeds the model limit");
|
|
89
|
+
return { models: parseOpenRouterModels(payload), etag: response.headers.get("etag")?.slice(0, 120) ?? null, bytes };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async fetch(): Promise<BenchmarkSourceSnapshot> {
|
|
93
|
+
const [catalog, latency, throughput] = await Promise.all([
|
|
94
|
+
this.readModels(OPENROUTER_MODELS_URL),
|
|
95
|
+
this.readModels(OPENROUTER_LATENCY_URL),
|
|
96
|
+
this.readModels(OPENROUTER_THROUGHPUT_URL),
|
|
97
|
+
]);
|
|
98
|
+
if (catalog.bytes + latency.bytes + throughput.bytes > BENCHMARK_SOURCE_MAX_TOTAL_RESPONSE_BYTES) throw new Error("OpenRouter model evidence exceeds the total size limit");
|
|
99
|
+
const retrievedAt = this.clock();
|
|
100
|
+
if (!Number.isSafeInteger(retrievedAt) || retrievedAt <= 0) throw new Error("benchmark retrieval time is invalid");
|
|
101
|
+
const revision = catalog.etag || latency.etag || throughput.etag || `retrieved:${retrievedAt}`;
|
|
102
|
+
const observations = [
|
|
103
|
+
...catalog.models.flatMap((model) => modelObservations(model, retrievedAt, revision)),
|
|
104
|
+
...rankObservations(latency.models, "latency-rank", retrievedAt, revision, OPENROUTER_LATENCY_URL),
|
|
105
|
+
...rankObservations(throughput.models, "throughput-rank", retrievedAt, revision, OPENROUTER_THROUGHPUT_URL),
|
|
106
|
+
];
|
|
107
|
+
return { sourceId: this.id, snapshotId: `${this.id}:${revision}`, retrievedAt, observations };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { Database } from "bun:sqlite";
|
|
2
|
-
import { DEFAULT_QUERY_LIMIT, MAX_QUERY_LIMIT } from "../constants.ts";
|
|
2
|
+
import { DEFAULT_QUERY_LIMIT, MAX_QUERY_LIMIT, USAGE_AGGREGATE_MAX_ROWS } from "../constants.ts";
|
|
3
3
|
import type { MetricObservation, MetricQuery, StoredMetricObservation } from "../domain/metric.ts";
|
|
4
4
|
import { validateMetricObservation } from "../domain/metric.ts";
|
|
5
|
-
import type {
|
|
5
|
+
import type { UsageAggregateRow } from "../domain/usage.ts";
|
|
6
|
+
import type { DistinctScopesFilter, MetricStore, UsageAggregateFilter } from "../ports/metric-store.ts";
|
|
6
7
|
|
|
7
8
|
interface MetricRow {
|
|
8
9
|
id: number;
|
|
@@ -75,6 +76,46 @@ export class SQLiteMetricStore implements MetricStore {
|
|
|
75
76
|
return rows.map(fromRow);
|
|
76
77
|
}
|
|
77
78
|
|
|
79
|
+
distinctScopes(filter: DistinctScopesFilter): string[] {
|
|
80
|
+
const limit = Math.max(1, Math.min(MAX_QUERY_LIMIT, Math.floor(filter.limit)));
|
|
81
|
+
const rows = this.db.query(`
|
|
82
|
+
SELECT DISTINCT scope FROM metric_observations
|
|
83
|
+
WHERE source = ? AND observed_at >= ? AND observed_at <= ?
|
|
84
|
+
ORDER BY scope ASC
|
|
85
|
+
LIMIT ?
|
|
86
|
+
`).all(filter.source, filter.since, filter.until, limit) as Array<{ scope: string }>;
|
|
87
|
+
return rows.map((row) => row.scope);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
aggregateUsage(filter: UsageAggregateFilter): UsageAggregateRow[] {
|
|
91
|
+
if (filter.scopes.length === 0) return [];
|
|
92
|
+
if (!Number.isFinite(filter.bucketSizeMs) || filter.bucketSizeMs <= 0) throw new Error("bucketSizeMs must be a positive number");
|
|
93
|
+
if (!Number.isInteger(filter.bucketCount) || filter.bucketCount <= 0) throw new Error("bucketCount must be a positive integer");
|
|
94
|
+
const scopePlaceholders = filter.scopes.map(() => "?").join(", ");
|
|
95
|
+
// MIN(a, b) is SQLite's scalar two-argument form (smallest of the arguments), mirroring
|
|
96
|
+
// usageBucketIndex's own `Math.min(bucketCount - 1, Math.floor(...))` clamp exactly, so a bucket
|
|
97
|
+
// this returns always matches the same-indexed bucket the client-side window renders.
|
|
98
|
+
const rows = this.db.query(`
|
|
99
|
+
SELECT scope, metric,
|
|
100
|
+
MIN(CAST((observed_at - ?) AS REAL) / ?, ? - 1) AS bucket_index_raw,
|
|
101
|
+
SUM(value) AS sum
|
|
102
|
+
FROM metric_observations
|
|
103
|
+
WHERE source = ? AND observed_at >= ? AND observed_at <= ? AND value >= 0 AND scope IN (${scopePlaceholders})
|
|
104
|
+
GROUP BY scope, metric, CAST(bucket_index_raw AS INTEGER)
|
|
105
|
+
LIMIT ?
|
|
106
|
+
`).all(
|
|
107
|
+
filter.since, filter.bucketSizeMs, filter.bucketCount,
|
|
108
|
+
filter.source, filter.since, filter.until, ...filter.scopes,
|
|
109
|
+
USAGE_AGGREGATE_MAX_ROWS,
|
|
110
|
+
) as Array<{ scope: string; metric: string; bucket_index_raw: number; sum: number }>;
|
|
111
|
+
return rows.map((row) => ({
|
|
112
|
+
scope: row.scope,
|
|
113
|
+
metric: row.metric,
|
|
114
|
+
bucketIndex: Math.max(0, Math.floor(row.bucket_index_raw)),
|
|
115
|
+
sum: row.sum,
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
|
|
78
119
|
pruneBefore(cutoff: number): number {
|
|
79
120
|
if (!Number.isSafeInteger(cutoff) || cutoff < 0) throw new Error("cutoff must be a non-negative integer timestamp");
|
|
80
121
|
return this.db.query("DELETE FROM metric_observations WHERE observed_at < ?").run(cutoff).changes;
|