@contractspec/module.provider-ranking 0.1.2

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 ADDED
@@ -0,0 +1,34 @@
1
+ # @contractspec/module.provider-ranking
2
+
3
+ Website: https://contractspec.io/
4
+
5
+ **AI provider ranking module with persistence and pipeline orchestration**
6
+
7
+ AI provider ranking module for benchmarks, model rankings, and ingestion. Re-exports entities, storage adapters, and pipeline orchestration.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ bun add @contractspec/module.provider-ranking
13
+ ```
14
+
15
+ ## Exports
16
+
17
+ - `.` — Main entry: entities, storage, and pipelines
18
+ - `./entities` — Schema entities (BenchmarkResult, ModelRanking, IngestionRun)
19
+ - `./storage` — Postgres storage adapter (PostgresProviderRankingStore)
20
+ - `./pipeline` — IngestionPipeline and RankingPipeline orchestration
21
+
22
+ ## Usage
23
+
24
+ ```typescript
25
+ import {
26
+ PostgresProviderRankingStore,
27
+ RankingPipeline,
28
+ } from "@contractspec/module.provider-ranking";
29
+
30
+ const store = new PostgresProviderRankingStore({ database });
31
+ const ranking = new RankingPipeline({ store });
32
+
33
+ const result = await ranking.refresh();
34
+ ```
@@ -0,0 +1,107 @@
1
+ // src/entities/index.ts
2
+ import { defineEntity, field, index } from "@contractspec/lib.schema";
3
+ var BenchmarkResultEntity = defineEntity({
4
+ name: "BenchmarkResult",
5
+ description: "Individual benchmark score for a model from a specific source.",
6
+ schema: "lssm_ranking",
7
+ map: "benchmark_result",
8
+ fields: {
9
+ id: field.id({ description: "Benchmark result ID" }),
10
+ modelId: field.string({ description: "Model identifier" }),
11
+ providerKey: field.string({
12
+ description: "Provider key (e.g. openai, anthropic)"
13
+ }),
14
+ source: field.string({
15
+ description: "Benchmark source (e.g. swe-bench, chatbot-arena)"
16
+ }),
17
+ dimension: field.string({
18
+ description: "Ranking dimension (coding, reasoning, etc.)"
19
+ }),
20
+ score: field.float({ description: "Normalized score 0-100" }),
21
+ rawScore: field.json({ description: "Original score from source" }),
22
+ metadata: field.json({ isOptional: true }),
23
+ measuredAt: field.dateTime({
24
+ description: "When the benchmark was measured"
25
+ }),
26
+ ingestedAt: field.dateTime({ description: "When the result was ingested" })
27
+ },
28
+ indexes: [
29
+ index.unique(["id"]),
30
+ index.on(["modelId"]),
31
+ index.on(["providerKey"]),
32
+ index.on(["source"]),
33
+ index.on(["dimension"]),
34
+ index.on(["modelId", "source", "dimension"])
35
+ ]
36
+ });
37
+ var ModelRankingEntity = defineEntity({
38
+ name: "ModelRanking",
39
+ description: "Computed composite ranking for a model.",
40
+ schema: "lssm_ranking",
41
+ map: "model_ranking",
42
+ fields: {
43
+ modelId: field.id({ description: "Model identifier (primary key)" }),
44
+ providerKey: field.string({ description: "Provider key" }),
45
+ compositeScore: field.float({
46
+ description: "Weighted composite score 0-100"
47
+ }),
48
+ dimensionScores: field.json({
49
+ description: "Per-dimension score breakdown"
50
+ }),
51
+ rank: field.int({ description: "Current rank position" }),
52
+ previousRank: field.int({
53
+ isOptional: true,
54
+ description: "Previous rank position"
55
+ }),
56
+ updatedAt: field.updatedAt()
57
+ },
58
+ indexes: [
59
+ index.on(["providerKey"]),
60
+ index.on(["rank"]),
61
+ index.on(["compositeScore"])
62
+ ]
63
+ });
64
+ var IngestionRunEntity = defineEntity({
65
+ name: "IngestionRun",
66
+ description: "Tracks a benchmark data ingestion run.",
67
+ schema: "lssm_ranking",
68
+ map: "ingestion_run",
69
+ fields: {
70
+ id: field.id({ description: "Ingestion run ID" }),
71
+ source: field.string({ description: "Benchmark source" }),
72
+ status: field.string({
73
+ description: "Run status: pending, running, completed, failed"
74
+ }),
75
+ resultsCount: field.int({ description: "Number of results ingested" }),
76
+ startedAt: field.dateTime({ description: "When the run started" }),
77
+ completedAt: field.dateTime({
78
+ isOptional: true,
79
+ description: "When the run completed"
80
+ }),
81
+ error: field.string({
82
+ isOptional: true,
83
+ description: "Error message if failed"
84
+ })
85
+ },
86
+ indexes: [
87
+ index.on(["source"]),
88
+ index.on(["status"]),
89
+ index.on(["startedAt"])
90
+ ]
91
+ });
92
+ var providerRankingEntities = [
93
+ BenchmarkResultEntity,
94
+ ModelRankingEntity,
95
+ IngestionRunEntity
96
+ ];
97
+ var providerRankingSchemaContribution = {
98
+ moduleId: "@contractspec/module.provider-ranking",
99
+ entities: providerRankingEntities
100
+ };
101
+ export {
102
+ providerRankingSchemaContribution,
103
+ providerRankingEntities,
104
+ ModelRankingEntity,
105
+ IngestionRunEntity,
106
+ BenchmarkResultEntity
107
+ };
@@ -0,0 +1,538 @@
1
+ // src/entities/index.ts
2
+ import { defineEntity, field, index } from "@contractspec/lib.schema";
3
+ var BenchmarkResultEntity = defineEntity({
4
+ name: "BenchmarkResult",
5
+ description: "Individual benchmark score for a model from a specific source.",
6
+ schema: "lssm_ranking",
7
+ map: "benchmark_result",
8
+ fields: {
9
+ id: field.id({ description: "Benchmark result ID" }),
10
+ modelId: field.string({ description: "Model identifier" }),
11
+ providerKey: field.string({
12
+ description: "Provider key (e.g. openai, anthropic)"
13
+ }),
14
+ source: field.string({
15
+ description: "Benchmark source (e.g. swe-bench, chatbot-arena)"
16
+ }),
17
+ dimension: field.string({
18
+ description: "Ranking dimension (coding, reasoning, etc.)"
19
+ }),
20
+ score: field.float({ description: "Normalized score 0-100" }),
21
+ rawScore: field.json({ description: "Original score from source" }),
22
+ metadata: field.json({ isOptional: true }),
23
+ measuredAt: field.dateTime({
24
+ description: "When the benchmark was measured"
25
+ }),
26
+ ingestedAt: field.dateTime({ description: "When the result was ingested" })
27
+ },
28
+ indexes: [
29
+ index.unique(["id"]),
30
+ index.on(["modelId"]),
31
+ index.on(["providerKey"]),
32
+ index.on(["source"]),
33
+ index.on(["dimension"]),
34
+ index.on(["modelId", "source", "dimension"])
35
+ ]
36
+ });
37
+ var ModelRankingEntity = defineEntity({
38
+ name: "ModelRanking",
39
+ description: "Computed composite ranking for a model.",
40
+ schema: "lssm_ranking",
41
+ map: "model_ranking",
42
+ fields: {
43
+ modelId: field.id({ description: "Model identifier (primary key)" }),
44
+ providerKey: field.string({ description: "Provider key" }),
45
+ compositeScore: field.float({
46
+ description: "Weighted composite score 0-100"
47
+ }),
48
+ dimensionScores: field.json({
49
+ description: "Per-dimension score breakdown"
50
+ }),
51
+ rank: field.int({ description: "Current rank position" }),
52
+ previousRank: field.int({
53
+ isOptional: true,
54
+ description: "Previous rank position"
55
+ }),
56
+ updatedAt: field.updatedAt()
57
+ },
58
+ indexes: [
59
+ index.on(["providerKey"]),
60
+ index.on(["rank"]),
61
+ index.on(["compositeScore"])
62
+ ]
63
+ });
64
+ var IngestionRunEntity = defineEntity({
65
+ name: "IngestionRun",
66
+ description: "Tracks a benchmark data ingestion run.",
67
+ schema: "lssm_ranking",
68
+ map: "ingestion_run",
69
+ fields: {
70
+ id: field.id({ description: "Ingestion run ID" }),
71
+ source: field.string({ description: "Benchmark source" }),
72
+ status: field.string({
73
+ description: "Run status: pending, running, completed, failed"
74
+ }),
75
+ resultsCount: field.int({ description: "Number of results ingested" }),
76
+ startedAt: field.dateTime({ description: "When the run started" }),
77
+ completedAt: field.dateTime({
78
+ isOptional: true,
79
+ description: "When the run completed"
80
+ }),
81
+ error: field.string({
82
+ isOptional: true,
83
+ description: "Error message if failed"
84
+ })
85
+ },
86
+ indexes: [
87
+ index.on(["source"]),
88
+ index.on(["status"]),
89
+ index.on(["startedAt"])
90
+ ]
91
+ });
92
+ var providerRankingEntities = [
93
+ BenchmarkResultEntity,
94
+ ModelRankingEntity,
95
+ IngestionRunEntity
96
+ ];
97
+ var providerRankingSchemaContribution = {
98
+ moduleId: "@contractspec/module.provider-ranking",
99
+ entities: providerRankingEntities
100
+ };
101
+
102
+ // src/storage/index.ts
103
+ class PostgresProviderRankingStore {
104
+ database;
105
+ schema;
106
+ createTablesIfMissing;
107
+ ensured = false;
108
+ constructor(options) {
109
+ this.database = options.database;
110
+ this.schema = options.schema ?? "lssm_ranking";
111
+ this.createTablesIfMissing = options.createTablesIfMissing ?? true;
112
+ }
113
+ async upsertBenchmarkResult(result) {
114
+ await this.ensureTables();
115
+ await this.database.execute(`INSERT INTO ${this.table("benchmark_result")}
116
+ (id, model_id, provider_key, source, dimension, score, raw_score, metadata, measured_at, ingested_at)
117
+ VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb, $8::jsonb, $9, $10)
118
+ ON CONFLICT (id)
119
+ DO UPDATE SET
120
+ score = EXCLUDED.score,
121
+ raw_score = EXCLUDED.raw_score,
122
+ metadata = EXCLUDED.metadata,
123
+ measured_at = EXCLUDED.measured_at,
124
+ ingested_at = EXCLUDED.ingested_at;`, [
125
+ result.id,
126
+ result.modelId,
127
+ result.providerKey,
128
+ result.source,
129
+ result.dimension,
130
+ result.score,
131
+ JSON.stringify(result.rawScore),
132
+ result.metadata ? JSON.stringify(result.metadata) : null,
133
+ result.measuredAt.toISOString(),
134
+ result.ingestedAt.toISOString()
135
+ ]);
136
+ }
137
+ async getBenchmarkResult(id) {
138
+ await this.ensureTables();
139
+ const rows = await this.database.query(`SELECT * FROM ${this.table("benchmark_result")} WHERE id = $1;`, [id]);
140
+ return rows.rows[0] ? this.mapBenchmarkResult(rows.rows[0]) : null;
141
+ }
142
+ async listBenchmarkResults(query) {
143
+ await this.ensureTables();
144
+ const limit = query.limit ?? 50;
145
+ const offset = query.offset ?? 0;
146
+ const countFilters = [];
147
+ const countParams = [];
148
+ if (query.source) {
149
+ countParams.push(query.source);
150
+ countFilters.push(`source = $${countParams.length}`);
151
+ }
152
+ if (query.modelId) {
153
+ countParams.push(query.modelId);
154
+ countFilters.push(`model_id = $${countParams.length}`);
155
+ }
156
+ if (query.dimension) {
157
+ countParams.push(query.dimension);
158
+ countFilters.push(`dimension = $${countParams.length}`);
159
+ }
160
+ if (query.providerKey) {
161
+ countParams.push(query.providerKey);
162
+ countFilters.push(`provider_key = $${countParams.length}`);
163
+ }
164
+ const where = countFilters.length ? `WHERE ${countFilters.join(" AND ")}` : "";
165
+ const countResult = await this.database.query(`SELECT COUNT(*)::int as total FROM ${this.table("benchmark_result")} ${where};`, countParams);
166
+ const total = Number(countResult.rows[0]?.total ?? 0);
167
+ const dataParams = [
168
+ limit,
169
+ offset,
170
+ ...countParams
171
+ ];
172
+ const dataFilters = countFilters.map((_f, i) => _f.replace(`$${i + 1}`, `$${i + 3}`));
173
+ const dataWhere = dataFilters.length ? `WHERE ${dataFilters.join(" AND ")}` : "";
174
+ const rows = await this.database.query(`SELECT * FROM ${this.table("benchmark_result")}
175
+ ${dataWhere}
176
+ ORDER BY ingested_at DESC
177
+ LIMIT $1 OFFSET $2;`, dataParams);
178
+ const results = rows.rows.map((row) => this.mapBenchmarkResult(row));
179
+ const nextOffset = offset + results.length < total ? offset + results.length : undefined;
180
+ return { results, total, nextOffset };
181
+ }
182
+ async upsertModelRanking(ranking) {
183
+ await this.ensureTables();
184
+ await this.database.execute(`INSERT INTO ${this.table("model_ranking")}
185
+ (model_id, provider_key, composite_score, dimension_scores, rank, previous_rank, updated_at)
186
+ VALUES ($1, $2, $3, $4::jsonb, $5, $6, $7)
187
+ ON CONFLICT (model_id)
188
+ DO UPDATE SET
189
+ provider_key = EXCLUDED.provider_key,
190
+ composite_score = EXCLUDED.composite_score,
191
+ dimension_scores = EXCLUDED.dimension_scores,
192
+ rank = EXCLUDED.rank,
193
+ previous_rank = EXCLUDED.previous_rank,
194
+ updated_at = EXCLUDED.updated_at;`, [
195
+ ranking.modelId,
196
+ ranking.providerKey,
197
+ ranking.compositeScore,
198
+ JSON.stringify(ranking.dimensionScores),
199
+ ranking.rank,
200
+ ranking.previousRank,
201
+ ranking.updatedAt.toISOString()
202
+ ]);
203
+ }
204
+ async getModelRanking(modelId) {
205
+ await this.ensureTables();
206
+ const rows = await this.database.query(`SELECT * FROM ${this.table("model_ranking")} WHERE model_id = $1;`, [modelId]);
207
+ return rows.rows[0] ? this.mapModelRanking(rows.rows[0]) : null;
208
+ }
209
+ async listModelRankings(query) {
210
+ await this.ensureTables();
211
+ const limit = query.limit ?? 50;
212
+ const offset = query.offset ?? 0;
213
+ const countFilters = [];
214
+ const countParams = [];
215
+ if (query.providerKey) {
216
+ countParams.push(query.providerKey);
217
+ countFilters.push(`provider_key = $${countParams.length}`);
218
+ }
219
+ const where = countFilters.length ? `WHERE ${countFilters.join(" AND ")}` : "";
220
+ const countResult = await this.database.query(`SELECT COUNT(*)::int as total FROM ${this.table("model_ranking")} ${where};`, countParams);
221
+ const total = Number(countResult.rows[0]?.total ?? 0);
222
+ const dataParams = [
223
+ limit,
224
+ offset,
225
+ ...countParams
226
+ ];
227
+ const dataFilters = countFilters.map((_f, i) => _f.replace(`$${i + 1}`, `$${i + 3}`));
228
+ const dataWhere = dataFilters.length ? `WHERE ${dataFilters.join(" AND ")}` : "";
229
+ const orderBy = query.dimension ? `(dimension_scores->>'${query.dimension}')::jsonb->>'score' DESC NULLS LAST` : "rank ASC";
230
+ const rows = await this.database.query(`SELECT * FROM ${this.table("model_ranking")}
231
+ ${dataWhere}
232
+ ORDER BY ${orderBy}
233
+ LIMIT $1 OFFSET $2;`, dataParams);
234
+ const rankings = rows.rows.map((row) => this.mapModelRanking(row));
235
+ const nextOffset = offset + rankings.length < total ? offset + rankings.length : undefined;
236
+ return { rankings, total, nextOffset };
237
+ }
238
+ async getModelProfile(modelId) {
239
+ await this.ensureTables();
240
+ const ranking = await this.getModelRanking(modelId);
241
+ const benchResults = await this.database.query(`SELECT * FROM ${this.table("benchmark_result")}
242
+ WHERE model_id = $1
243
+ ORDER BY ingested_at DESC;`, [modelId]);
244
+ if (!ranking && benchResults.rows.length === 0)
245
+ return null;
246
+ return {
247
+ modelId,
248
+ providerKey: ranking?.providerKey ?? String(benchResults.rows[0]?.provider_key ?? "unknown"),
249
+ displayName: modelId,
250
+ contextWindow: 0,
251
+ costPerMillion: null,
252
+ capabilities: [],
253
+ ranking: ranking ?? null,
254
+ benchmarkResults: benchResults.rows.map((row) => this.mapBenchmarkResult(row))
255
+ };
256
+ }
257
+ async createIngestionRun(run) {
258
+ await this.ensureTables();
259
+ await this.database.execute(`INSERT INTO ${this.table("ingestion_run")}
260
+ (id, source, status, results_count, started_at, completed_at, error)
261
+ VALUES ($1, $2, $3, $4, $5, $6, $7);`, [
262
+ run.id,
263
+ run.source,
264
+ run.status,
265
+ run.resultsCount,
266
+ run.startedAt.toISOString(),
267
+ run.completedAt?.toISOString() ?? null,
268
+ run.error
269
+ ]);
270
+ }
271
+ async updateIngestionRun(id, update) {
272
+ await this.ensureTables();
273
+ const sets = [];
274
+ const params = [id];
275
+ if (update.status !== undefined) {
276
+ params.push(update.status);
277
+ sets.push(`status = $${params.length}`);
278
+ }
279
+ if (update.resultsCount !== undefined) {
280
+ params.push(update.resultsCount);
281
+ sets.push(`results_count = $${params.length}`);
282
+ }
283
+ if (update.completedAt !== undefined) {
284
+ params.push(update.completedAt?.toISOString() ?? null);
285
+ sets.push(`completed_at = $${params.length}`);
286
+ }
287
+ if (update.error !== undefined) {
288
+ params.push(update.error);
289
+ sets.push(`error = $${params.length}`);
290
+ }
291
+ if (sets.length === 0)
292
+ return;
293
+ await this.database.execute(`UPDATE ${this.table("ingestion_run")} SET ${sets.join(", ")} WHERE id = $1;`, params);
294
+ }
295
+ async getIngestionRun(id) {
296
+ await this.ensureTables();
297
+ const rows = await this.database.query(`SELECT * FROM ${this.table("ingestion_run")} WHERE id = $1;`, [id]);
298
+ return rows.rows[0] ? this.mapIngestionRun(rows.rows[0]) : null;
299
+ }
300
+ async ensureTables() {
301
+ if (this.ensured || !this.createTablesIfMissing)
302
+ return;
303
+ await this.database.execute(`CREATE SCHEMA IF NOT EXISTS ${this.schema};`);
304
+ await this.database.execute(`CREATE TABLE IF NOT EXISTS ${this.table("benchmark_result")} (
305
+ id text PRIMARY KEY,
306
+ model_id text NOT NULL,
307
+ provider_key text NOT NULL,
308
+ source text NOT NULL,
309
+ dimension text NOT NULL,
310
+ score double precision NOT NULL,
311
+ raw_score jsonb,
312
+ metadata jsonb,
313
+ measured_at timestamptz NOT NULL,
314
+ ingested_at timestamptz NOT NULL
315
+ );`);
316
+ await this.database.execute(`CREATE INDEX IF NOT EXISTS benchmark_result_model_idx
317
+ ON ${this.table("benchmark_result")} (model_id);`);
318
+ await this.database.execute(`CREATE INDEX IF NOT EXISTS benchmark_result_source_idx
319
+ ON ${this.table("benchmark_result")} (source);`);
320
+ await this.database.execute(`CREATE INDEX IF NOT EXISTS benchmark_result_dimension_idx
321
+ ON ${this.table("benchmark_result")} (dimension);`);
322
+ await this.database.execute(`CREATE TABLE IF NOT EXISTS ${this.table("model_ranking")} (
323
+ model_id text PRIMARY KEY,
324
+ provider_key text NOT NULL,
325
+ composite_score double precision NOT NULL,
326
+ dimension_scores jsonb NOT NULL,
327
+ rank int NOT NULL,
328
+ previous_rank int,
329
+ updated_at timestamptz NOT NULL
330
+ );`);
331
+ await this.database.execute(`CREATE INDEX IF NOT EXISTS model_ranking_rank_idx
332
+ ON ${this.table("model_ranking")} (rank);`);
333
+ await this.database.execute(`CREATE TABLE IF NOT EXISTS ${this.table("ingestion_run")} (
334
+ id text PRIMARY KEY,
335
+ source text NOT NULL,
336
+ status text NOT NULL,
337
+ results_count int NOT NULL DEFAULT 0,
338
+ started_at timestamptz NOT NULL,
339
+ completed_at timestamptz,
340
+ error text
341
+ );`);
342
+ this.ensured = true;
343
+ }
344
+ table(name) {
345
+ return `${this.schema}.${name}`;
346
+ }
347
+ mapBenchmarkResult(row) {
348
+ return {
349
+ id: String(row.id),
350
+ modelId: String(row.model_id),
351
+ providerKey: String(row.provider_key),
352
+ source: String(row.source),
353
+ dimension: String(row.dimension),
354
+ score: Number(row.score),
355
+ rawScore: parseJson(row.raw_score),
356
+ metadata: parseJson(row.metadata) ?? {},
357
+ measuredAt: new Date(String(row.measured_at)),
358
+ ingestedAt: new Date(String(row.ingested_at))
359
+ };
360
+ }
361
+ mapModelRanking(row) {
362
+ return {
363
+ modelId: String(row.model_id),
364
+ providerKey: String(row.provider_key),
365
+ compositeScore: Number(row.composite_score),
366
+ dimensionScores: parseJson(row.dimension_scores) ?? {},
367
+ rank: Number(row.rank),
368
+ previousRank: row.previous_rank != null ? Number(row.previous_rank) : null,
369
+ updatedAt: new Date(String(row.updated_at))
370
+ };
371
+ }
372
+ mapIngestionRun(row) {
373
+ return {
374
+ id: String(row.id),
375
+ source: String(row.source),
376
+ status: String(row.status),
377
+ resultsCount: Number(row.results_count),
378
+ startedAt: new Date(String(row.started_at)),
379
+ completedAt: row.completed_at ? new Date(String(row.completed_at)) : null,
380
+ error: row.error ? String(row.error) : null
381
+ };
382
+ }
383
+ }
384
+ function parseJson(value) {
385
+ if (value == null)
386
+ return null;
387
+ if (typeof value === "object")
388
+ return value;
389
+ if (typeof value === "string") {
390
+ try {
391
+ return JSON.parse(value);
392
+ } catch {
393
+ return null;
394
+ }
395
+ }
396
+ return value;
397
+ }
398
+
399
+ // src/pipeline/ingestion-pipeline.ts
400
+ import { normalizeBenchmarkResults } from "@contractspec/lib.provider-ranking/scoring";
401
+
402
+ class IngestionPipeline {
403
+ store;
404
+ registry;
405
+ ingesterOptions;
406
+ constructor(options) {
407
+ this.store = options.store;
408
+ this.registry = options.ingesterRegistry;
409
+ this.ingesterOptions = options.ingesterOptions;
410
+ }
411
+ async ingest(source, params) {
412
+ const ingester = this.registry.get(source);
413
+ if (!ingester) {
414
+ throw new Error(`No ingester registered for source: ${source}`);
415
+ }
416
+ return this.runIngester(ingester, params);
417
+ }
418
+ async ingestAll(params) {
419
+ const results = [];
420
+ for (const ingester of this.registry.list()) {
421
+ const result = await this.runIngester(ingester, params);
422
+ results.push(result);
423
+ }
424
+ return results;
425
+ }
426
+ mergeOptions(params) {
427
+ const merged = { ...this.ingesterOptions };
428
+ if (params?.fromDate)
429
+ merged.fromDate = new Date(params.fromDate);
430
+ if (params?.toDate)
431
+ merged.toDate = new Date(params.toDate);
432
+ if (params?.dimensions?.length)
433
+ merged.dimensions = params.dimensions;
434
+ return merged;
435
+ }
436
+ async runIngester(ingester, params) {
437
+ const ingestionId = `ingest-${ingester.source}-${Date.now()}`;
438
+ const run = {
439
+ id: ingestionId,
440
+ source: ingester.source,
441
+ status: "running",
442
+ resultsCount: 0,
443
+ startedAt: new Date,
444
+ completedAt: null,
445
+ error: null
446
+ };
447
+ await this.store.createIngestionRun(run);
448
+ try {
449
+ const opts = this.mergeOptions(params);
450
+ const rawResults = await ingester.ingest(opts);
451
+ const normalized = normalizeBenchmarkResults(rawResults);
452
+ for (const result of normalized) {
453
+ await this.store.upsertBenchmarkResult(result);
454
+ }
455
+ await this.store.updateIngestionRun(ingestionId, {
456
+ status: "completed",
457
+ resultsCount: normalized.length,
458
+ completedAt: new Date
459
+ });
460
+ return {
461
+ ingestionId,
462
+ source: ingester.source,
463
+ resultsCount: normalized.length,
464
+ status: "completed"
465
+ };
466
+ } catch (error) {
467
+ const errorMessage = error instanceof Error ? error.message : String(error);
468
+ await this.store.updateIngestionRun(ingestionId, {
469
+ status: "failed",
470
+ completedAt: new Date,
471
+ error: errorMessage
472
+ });
473
+ return {
474
+ ingestionId,
475
+ source: ingester.source,
476
+ resultsCount: 0,
477
+ status: "failed"
478
+ };
479
+ }
480
+ }
481
+ }
482
+
483
+ // src/pipeline/ranking-pipeline.ts
484
+ import { computeModelRankings } from "@contractspec/lib.provider-ranking/scoring";
485
+
486
+ class RankingPipeline {
487
+ store;
488
+ constructor(options) {
489
+ this.store = options.store;
490
+ }
491
+ async refresh(params) {
492
+ let allResults = await this.loadAllBenchmarkResults();
493
+ if (params?.dimensions?.length) {
494
+ const dimSet = new Set(params.dimensions);
495
+ allResults = allResults.filter((r) => dimSet.has(r.dimension));
496
+ }
497
+ const existingRankings = params?.forceRecalculate ? new Map : new Map((await this.store.listModelRankings({
498
+ limit: 1e4,
499
+ requiredTransport: params?.requiredTransport,
500
+ requiredAuthMethod: params?.requiredAuthMethod
501
+ })).rankings.map((r) => [r.modelId, r]));
502
+ const newRankings = computeModelRankings(allResults, params?.weightOverrides ? { weightOverrides: params.weightOverrides } : undefined, existingRankings);
503
+ for (const ranking of newRankings) {
504
+ await this.store.upsertModelRanking(ranking);
505
+ }
506
+ return {
507
+ modelsRanked: newRankings.length,
508
+ updatedAt: new Date
509
+ };
510
+ }
511
+ async loadAllBenchmarkResults() {
512
+ const pageSize = 500;
513
+ let offset = 0;
514
+ const allResults = [];
515
+ while (true) {
516
+ const page = await this.store.listBenchmarkResults({
517
+ limit: pageSize,
518
+ offset
519
+ });
520
+ allResults.push(...page.results);
521
+ if (allResults.length >= page.total || page.results.length < pageSize) {
522
+ break;
523
+ }
524
+ offset += pageSize;
525
+ }
526
+ return allResults;
527
+ }
528
+ }
529
+ export {
530
+ providerRankingSchemaContribution,
531
+ providerRankingEntities,
532
+ RankingPipeline,
533
+ PostgresProviderRankingStore,
534
+ ModelRankingEntity,
535
+ IngestionRunEntity,
536
+ IngestionPipeline,
537
+ BenchmarkResultEntity
538
+ };