dsh-model-arena 0.2.1 → 0.4.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/lib/arena-view.d.ts +4 -2
- package/lib/arena-view.js +4 -12
- package/lib/arena.d.ts +11 -21
- package/lib/arena.js +66 -10
- package/lib/arena.web.js +644 -56
- package/lib/arena.web.js.map +4 -4
- package/lib/client/locales.d.ts +15 -0
- package/lib/client/locales.js +30 -0
- package/lib/client/ui.d.ts +124 -0
- package/lib/client/ui.js +388 -0
- package/lib/client/view.d.ts +3 -20
- package/lib/client/view.js +51 -51
- package/lib/index.d.ts +3 -0
- package/lib/index.js +3 -0
- package/lib/routes.d.ts +2 -2
- package/lib/routes.js +51 -7
- package/lib/scoring.d.ts +6 -1
- package/lib/scoring.js +98 -0
- package/lib/store.d.ts +1 -0
- package/lib/store.js +8 -1
- package/lib/types.d.ts +50 -6
- package/package.json +1 -1
package/lib/arena-view.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type { PanelPayload,
|
|
1
|
+
import type { PanelPayload, RunSummary, LeaderboardEntry, ArenaStats } from './types.js';
|
|
2
2
|
/** Route paths shared between host and client. */
|
|
3
3
|
export declare const ARENA_PANEL_PATH = "/api/arena.panel";
|
|
4
4
|
export declare const ARENA_RUN_PATH = "/api/arena.run";
|
|
5
5
|
export declare const ARENA_RATE_PATH = "/api/arena.rate";
|
|
6
|
-
export declare
|
|
6
|
+
export declare const ARENA_COMPARE_PATH = "/api/arena.compare";
|
|
7
|
+
export declare const ARENA_DELETE_PATH = "/api/arena.delete";
|
|
8
|
+
export declare function panelState(runs: RunSummary[], leaderboard: LeaderboardEntry[], stats: ArenaStats): PanelPayload;
|
package/lib/arena-view.js
CHANGED
|
@@ -2,16 +2,8 @@
|
|
|
2
2
|
export const ARENA_PANEL_PATH = '/api/arena.panel';
|
|
3
3
|
export const ARENA_RUN_PATH = '/api/arena.run';
|
|
4
4
|
export const ARENA_RATE_PATH = '/api/arena.rate';
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
.slice(0, 20)
|
|
10
|
-
.map((r) => ({
|
|
11
|
-
id: r.id,
|
|
12
|
-
prompt: r.prompt,
|
|
13
|
-
timestamp: r.timestamp,
|
|
14
|
-
modelCount: r.results.length,
|
|
15
|
-
})),
|
|
16
|
-
};
|
|
5
|
+
export const ARENA_COMPARE_PATH = '/api/arena.compare';
|
|
6
|
+
export const ARENA_DELETE_PATH = '/api/arena.delete';
|
|
7
|
+
export function panelState(runs, leaderboard, stats) {
|
|
8
|
+
return { recentRuns: runs.slice(0, 20), leaderboard, stats };
|
|
17
9
|
}
|
package/lib/arena.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ArenaRun, ModelResult, Suite, RegressionReport,
|
|
1
|
+
import type { ArenaRun, ModelResult, Suite, RegressionReport, LeaderboardEntry, ArenaStats, RunSummary, ComparePayload } from './types.js';
|
|
2
2
|
export declare class Arena {
|
|
3
3
|
private projectDir;
|
|
4
4
|
private store;
|
|
@@ -6,31 +6,21 @@ export declare class Arena {
|
|
|
6
6
|
/** Save a completed run (results already collected from model calls). */
|
|
7
7
|
saveRun(prompt: string, results: ModelResult[], reference?: string): ArenaRun;
|
|
8
8
|
getRun(id: string): ArenaRun | null;
|
|
9
|
-
listRuns():
|
|
10
|
-
id: string;
|
|
11
|
-
prompt: string;
|
|
12
|
-
timestamp: number;
|
|
13
|
-
modelCount: number;
|
|
14
|
-
}[];
|
|
9
|
+
listRuns(): RunSummary[];
|
|
15
10
|
/** Compare two models' outputs within a run. */
|
|
16
|
-
compare(runId: string, modelA: string, modelB: string):
|
|
17
|
-
modelA: string;
|
|
18
|
-
modelB: string;
|
|
19
|
-
outputA: string;
|
|
20
|
-
outputB: string;
|
|
21
|
-
diff: import("./diff.js").DiffLine[];
|
|
22
|
-
summary: {
|
|
23
|
-
added: number;
|
|
24
|
-
removed: number;
|
|
25
|
-
changed: number;
|
|
26
|
-
};
|
|
27
|
-
scoreA: Score;
|
|
28
|
-
scoreB: Score;
|
|
29
|
-
} | null;
|
|
11
|
+
compare(runId: string, modelA: string, modelB: string): ComparePayload | null;
|
|
30
12
|
/** Set a user rating for a model in a run. */
|
|
31
13
|
rate(runId: string, model: string, rating: number): ArenaRun | null;
|
|
14
|
+
/** Delete a run. */
|
|
15
|
+
deleteRun(runId: string): boolean;
|
|
32
16
|
/** Save a benchmark suite. */
|
|
33
17
|
saveSuite(suite: Suite): void;
|
|
34
18
|
/** Generate a regression report between two runs of the same suite. */
|
|
35
19
|
regression(suiteName: string, baselineRunId: string, currentRunId: string): RegressionReport | null;
|
|
20
|
+
/** Elo leaderboard from all runs. */
|
|
21
|
+
leaderboard(): LeaderboardEntry[];
|
|
22
|
+
/** Aggregate stats. */
|
|
23
|
+
stats(): ArenaStats;
|
|
24
|
+
/** Pick the best model in a run by composite score. */
|
|
25
|
+
private pickWinner;
|
|
36
26
|
}
|
package/lib/arena.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ArenaStore } from './store.js';
|
|
2
|
-
import { autoScore } from './scoring.js';
|
|
2
|
+
import { autoScore, buildLeaderboard } from './scoring.js';
|
|
3
3
|
import { lineDiff, diffSummary } from './diff.js';
|
|
4
4
|
export class Arena {
|
|
5
5
|
projectDir;
|
|
@@ -13,7 +13,7 @@ export class Arena {
|
|
|
13
13
|
const models = results.map((r) => r.model);
|
|
14
14
|
const id = ArenaStore.generateId(prompt, models);
|
|
15
15
|
const scores = autoScore(results, reference);
|
|
16
|
-
const run = { id, prompt, timestamp: Date.now(), results, scores };
|
|
16
|
+
const run = { id, prompt, timestamp: Date.now(), results, scores, reference };
|
|
17
17
|
this.store.saveRun(run);
|
|
18
18
|
return run;
|
|
19
19
|
}
|
|
@@ -21,12 +21,16 @@ export class Arena {
|
|
|
21
21
|
return this.store.getRun(id);
|
|
22
22
|
}
|
|
23
23
|
listRuns() {
|
|
24
|
-
return this.store.listRuns().map((r) =>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
return this.store.listRuns().map((r) => {
|
|
25
|
+
const winner = this.pickWinner(r);
|
|
26
|
+
return {
|
|
27
|
+
id: r.id,
|
|
28
|
+
prompt: r.prompt,
|
|
29
|
+
timestamp: r.timestamp,
|
|
30
|
+
modelCount: r.results.length,
|
|
31
|
+
winner,
|
|
32
|
+
};
|
|
33
|
+
});
|
|
30
34
|
}
|
|
31
35
|
/** Compare two models' outputs within a run. */
|
|
32
36
|
compare(runId, modelA, modelB) {
|
|
@@ -38,14 +42,15 @@ export class Arena {
|
|
|
38
42
|
if (!a || !b)
|
|
39
43
|
return null;
|
|
40
44
|
return {
|
|
45
|
+
runId,
|
|
41
46
|
modelA: a.model,
|
|
42
47
|
modelB: b.model,
|
|
43
48
|
outputA: a.output,
|
|
44
49
|
outputB: b.output,
|
|
45
50
|
diff: lineDiff(a.output, b.output),
|
|
46
51
|
summary: diffSummary(a.output, b.output),
|
|
47
|
-
scoreA: run.scores[modelA],
|
|
48
|
-
scoreB: run.scores[modelB],
|
|
52
|
+
scoreA: run.scores[modelA] ?? {},
|
|
53
|
+
scoreB: run.scores[modelB] ?? {},
|
|
49
54
|
};
|
|
50
55
|
}
|
|
51
56
|
/** Set a user rating for a model in a run. */
|
|
@@ -59,6 +64,10 @@ export class Arena {
|
|
|
59
64
|
this.store.saveRun(run);
|
|
60
65
|
return run;
|
|
61
66
|
}
|
|
67
|
+
/** Delete a run. */
|
|
68
|
+
deleteRun(runId) {
|
|
69
|
+
return this.store.deleteRun(runId);
|
|
70
|
+
}
|
|
62
71
|
/** Save a benchmark suite. */
|
|
63
72
|
saveSuite(suite) {
|
|
64
73
|
this.store.saveSuite(suite);
|
|
@@ -84,4 +93,51 @@ export class Arena {
|
|
|
84
93
|
}
|
|
85
94
|
return { suiteName, baselineRunId, currentRunId, changes };
|
|
86
95
|
}
|
|
96
|
+
/** Elo leaderboard from all runs. */
|
|
97
|
+
leaderboard() {
|
|
98
|
+
const allRuns = this.store.listRuns();
|
|
99
|
+
return buildLeaderboard(allRuns);
|
|
100
|
+
}
|
|
101
|
+
/** Aggregate stats. */
|
|
102
|
+
stats() {
|
|
103
|
+
const allRuns = this.store.listRuns();
|
|
104
|
+
const allModels = new Set();
|
|
105
|
+
const allPrompts = new Set();
|
|
106
|
+
for (const run of allRuns) {
|
|
107
|
+
allPrompts.add(run.prompt);
|
|
108
|
+
for (const r of run.results)
|
|
109
|
+
allModels.add(r.model);
|
|
110
|
+
}
|
|
111
|
+
let totalRatings = 0;
|
|
112
|
+
for (const run of allRuns) {
|
|
113
|
+
for (const [, score] of Object.entries(run.scores)) {
|
|
114
|
+
if (score.userRating !== undefined)
|
|
115
|
+
totalRatings++;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
totalRuns: allRuns.length,
|
|
120
|
+
totalModels: allModels.size,
|
|
121
|
+
uniqueModels: allModels.size,
|
|
122
|
+
uniquePrompts: allPrompts.size,
|
|
123
|
+
totalRatings,
|
|
124
|
+
avgModelsPerRun: allRuns.length > 0
|
|
125
|
+
? Math.round((allRuns.reduce((s, r) => s + r.results.length, 0) / allRuns.length) * 10) / 10
|
|
126
|
+
: 0,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/** Pick the best model in a run by composite score. */
|
|
130
|
+
pickWinner(run) {
|
|
131
|
+
let best;
|
|
132
|
+
let bestScore = -Infinity;
|
|
133
|
+
for (const [model, score] of Object.entries(run.scores)) {
|
|
134
|
+
const s = (score.userRating !== undefined ? score.userRating / 5 : 0)
|
|
135
|
+
+ (score.referenceMatch ?? 0) + (score.latencyScore ?? 0);
|
|
136
|
+
if (s > bestScore) {
|
|
137
|
+
bestScore = s;
|
|
138
|
+
best = model;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return best;
|
|
142
|
+
}
|
|
87
143
|
}
|