@valerypopoff/rivet2-evaluations 2.3.0 → 2.5.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.
@@ -1,4 +1,4 @@
1
- import type { EvaluationAggregate, EvaluationBaselineSnapshot, EvaluationCaseAggregate, EvaluationDataset, EvaluationExecutionMetrics, EvaluationGraphRunner, EvaluationGraphEvaluator, EvaluationProjectData, EvaluationRun, EvaluationRunPurpose, EvaluationSuite, EvaluationSuiteMode, EvaluationThreshold, EvaluationThresholdResult } from './types.js';
1
+ import type { EvaluationAggregate, EvaluationBaselineSnapshot, EvaluationCaseAggregate, EvaluationDataset, EvaluationExecutionMetrics, EvaluationGraphRunner, EvaluationGraphEvaluator, EvaluationProjectData, EvaluationRun, EvaluationRunEvent, EvaluationRunPurpose, EvaluationSuite, EvaluationSuiteMode, EvaluationThreshold, EvaluationThresholdResult, EvaluationTrial } from './types.js';
2
2
  import type { Project } from '@valerypopoff/rivet2-core';
3
3
  export declare const LEGACY_EVALUATOR_INPUT_IDS: readonly ["case", "inputs", "expected", "outputs", "run"];
4
4
  export type RunEvaluationSuiteOptions = {
@@ -15,6 +15,9 @@ export type RunEvaluationSuiteOptions = {
15
15
  purpose?: EvaluationRunPurpose;
16
16
  /** Explicit caller selection; otherwise the suite's saved baseline is used. */
17
17
  baseline?: EvaluationBaselineSnapshot;
18
+ /** Incremental live-run transport. Prefer this over onUpdate in new integrations. */
19
+ onEvent?: (event: EvaluationRunEvent) => void | Promise<void>;
20
+ /** @deprecated Prefer onEvent; this clones the complete accumulated run after every trial. */
18
21
  onUpdate?: (run: EvaluationRun) => void;
19
22
  };
20
23
  export declare function hasAuthoritativeEvaluationCriteria(suite: EvaluationSuite): boolean;
@@ -35,7 +38,7 @@ export type RunEvaluationWorkPoolOptions<TWork, TResult> = {
35
38
  concurrency: number;
36
39
  signal?: AbortSignal;
37
40
  execute: (work: TWork, index: number) => Promise<TResult>;
38
- onSettled?: (result: TResult, index: number, results: readonly (TResult | undefined)[]) => void;
41
+ onSettled?: (result: TResult, index: number, results: readonly (TResult | undefined)[]) => void | Promise<void>;
39
42
  };
40
43
  export declare function runEvaluationWorkPool<TWork, TResult>(options: RunEvaluationWorkPoolOptions<TWork, TResult>): Promise<readonly (TResult | undefined)[]>;
41
44
  export declare function createEmptyMetrics(): EvaluationExecutionMetrics;
@@ -50,7 +53,60 @@ export declare function createEmptyMetrics(): EvaluationExecutionMetrics;
50
53
  * otherwise-successful recording in the suite.
51
54
  */
52
55
  export declare function finalizeEvaluationRecordingRetention(run: EvaluationRun, policy?: 'failures-and-baselines' | 'all', now?: number): EvaluationRun;
56
+ export type RunEvaluationTrialOptions = {
57
+ project: Project;
58
+ suite: EvaluationSuite;
59
+ dataset: EvaluationDataset;
60
+ purpose: EvaluationRunPurpose;
61
+ testCase: EvaluationDataset['cases'][number];
62
+ caseIndex: number;
63
+ trialIndex: number;
64
+ runId: string;
65
+ runGraph: EvaluationGraphRunner;
66
+ signal?: AbortSignal;
67
+ /** Stable server-owned job id. Local callers may omit it. */
68
+ trialId?: string;
69
+ };
70
+ export declare function runEvaluationTrial(input: RunEvaluationTrialOptions): Promise<EvaluationTrial>;
53
71
  export declare function evaluateThresholdResults(aggregateValue: EvaluationAggregate, thresholds?: EvaluationThreshold[], baseline?: EvaluationBaselineSnapshot): EvaluationThresholdResult[];
72
+ export type EvaluationRunWorkItem = {
73
+ testCase: EvaluationDataset['cases'][number];
74
+ caseIndex: number;
75
+ trialIndex: number;
76
+ };
77
+ export type EvaluationRunPlan = {
78
+ suite: EvaluationSuite;
79
+ purpose: EvaluationRunPurpose;
80
+ evaluationMode: EvaluationSuiteMode;
81
+ work: readonly EvaluationRunWorkItem[];
82
+ };
83
+ /**
84
+ * Validates an immutable Evaluation submission and expands its enabled cases
85
+ * into deterministic work. Hosts can persist this plan before any graph side
86
+ * effect, while local callers continue to use runEvaluationSuite.
87
+ */
88
+ export declare function createEvaluationRunPlan(options: Pick<RunEvaluationSuiteOptions, 'project' | 'evaluationData' | 'dataset' | 'suiteId' | 'purpose'>): EvaluationRunPlan;
89
+ export type FinalizeEvaluationRunOptions = {
90
+ run: EvaluationRun;
91
+ trials: readonly EvaluationTrial[];
92
+ suite: EvaluationSuite;
93
+ evaluationData: EvaluationProjectData;
94
+ baseline?: EvaluationBaselineSnapshot;
95
+ canceled?: boolean;
96
+ completedAt?: string;
97
+ };
98
+ /**
99
+ * Applies the same aggregate, quality, accounting, and baseline semantics to
100
+ * locally scheduled and durably hosted trials. Callers must provide every
101
+ * settled trial in deterministic case/trial order; never synthesize retries.
102
+ */
103
+ export declare function finalizeEvaluationRun(options: FinalizeEvaluationRunOptions): EvaluationRun;
104
+ export type CreateEvaluationRunShellOptions = Pick<RunEvaluationSuiteOptions, 'project' | 'evaluationData' | 'dataset' | 'suiteId' | 'purpose' | 'runId' | 'projectFingerprint' | 'executionMode'>;
105
+ /** Creates a durable running shell only after the complete submission validates. */
106
+ export declare function createEvaluationRunShell(options: CreateEvaluationRunShellOptions): {
107
+ run: EvaluationRun;
108
+ plan: EvaluationRunPlan;
109
+ };
54
110
  export declare function runEvaluationSuite(options: RunEvaluationSuiteOptions): Promise<EvaluationRun>;
55
111
  export declare function runEvaluationCases(options: RunEvaluationSuiteOptions & {
56
112
  caseIds: readonly string[];
@@ -1,7 +1,14 @@
1
- import type { EvaluationDatasetSnapshot, EvaluationRecordingArtifact, EvaluationRun, EvaluationRunStore } from './types.js';
2
- export declare class InMemoryEvaluationRunStore implements EvaluationRunStore {
1
+ import type { EvaluationDatasetSnapshot, EvaluationLibrary, EvaluationRecordingArtifact, EvaluationRun, EvaluationStore } from './types.js';
2
+ export declare class InMemoryEvaluationRunStore implements EvaluationStore {
3
3
  #private;
4
+ getLibrary(): Promise<EvaluationLibrary>;
5
+ putLibrary(library: EvaluationLibrary): Promise<void>;
4
6
  put(run: EvaluationRun): Promise<void>;
7
+ updateRunName(input: {
8
+ projectId: string;
9
+ runId: string;
10
+ name?: string;
11
+ }): Promise<EvaluationRun | undefined>;
5
12
  get(input: {
6
13
  projectId: string;
7
14
  runId: string;
@@ -29,7 +36,7 @@ export declare class InMemoryEvaluationRunStore implements EvaluationRunStore {
29
36
  recordingId: string;
30
37
  retention: EvaluationRecordingArtifact['reference']['retention'];
31
38
  expiresAt?: string;
32
- }): Promise<void>;
39
+ }): Promise<boolean>;
33
40
  promoteBaseline(input: {
34
41
  projectId: string;
35
42
  runId: string;
@@ -27,7 +27,7 @@ export type EvaluationDataset = {
27
27
  * Legacy project ownership retained only while importing older project
28
28
  * files. Locally persisted evaluation datasets intentionally omit it so
29
29
  * they can be reused with any currently open project.
30
- */
30
+ */
31
31
  projectId?: ProjectId;
32
32
  name: string;
33
33
  fields: EvaluationDatasetField[];
@@ -158,6 +158,125 @@ export type EvaluationProjectData = {
158
158
  suites: EvaluationSuite[];
159
159
  baselines: EvaluationBaselineSnapshot[];
160
160
  };
161
+ /**
162
+ * Rivet-local evaluation resources. This is deliberately outside project
163
+ * files so one Rivet instance can retain its evaluation library independently
164
+ * of whichever project is currently open.
165
+ */
166
+ export type EvaluationLibrary = {
167
+ version: 1;
168
+ data: EvaluationProjectData;
169
+ datasets: EvaluationDataset[];
170
+ /** Legacy project IDs whose embedded evaluation resources were imported. */
171
+ migratedLegacyProjectIds: ProjectId[];
172
+ };
173
+ /**
174
+ * A collaboration boundary for the shared evaluation library. A suite owns
175
+ * its baselines because a baseline is only meaningful with that suite; a
176
+ * dataset is independently editable and reusable by many suites.
177
+ */
178
+ export type EvaluationLibraryResourceKind = 'suite' | 'dataset';
179
+ export type EvaluationLibraryResourceVersions = {
180
+ suites: Record<string, string>;
181
+ datasets: Record<string, string>;
182
+ };
183
+ /** A server-authoritative library snapshot used by collaborative hosts. */
184
+ export type EvaluationLibrarySyncSnapshot = {
185
+ revision: number;
186
+ library: EvaluationLibrary;
187
+ resourceVersions: EvaluationLibraryResourceVersions;
188
+ };
189
+ /**
190
+ * A validated, external change token for the shared evaluation library.
191
+ * `epoch` identifies one SSE generation so reconnects can require a resync
192
+ * even when a server's revision counter has not advanced.
193
+ */
194
+ export type EvaluationLibraryInvalidation = {
195
+ epoch: string;
196
+ revision: number;
197
+ };
198
+ /** The durable value for one independently synchronized library resource. */
199
+ export type EvaluationLibrarySuiteBundle = {
200
+ suite: EvaluationSuite;
201
+ baselines: EvaluationBaselineSnapshot[];
202
+ };
203
+ export type EvaluationLibraryResourceValue = {
204
+ kind: 'suite';
205
+ id: string;
206
+ value: EvaluationLibrarySuiteBundle | undefined;
207
+ } | {
208
+ kind: 'dataset';
209
+ id: string;
210
+ value: EvaluationDataset | undefined;
211
+ };
212
+ /**
213
+ * Every mutation is an all-or-nothing resource batch. Existing resources use
214
+ * their opaque version token; null means that creation requires the resource
215
+ * to remain absent.
216
+ */
217
+ export type EvaluationLibraryMutationChange = {
218
+ kind: 'put-suite';
219
+ id: string;
220
+ expectedVersion: string | null;
221
+ suite: EvaluationSuite;
222
+ baselines: EvaluationBaselineSnapshot[];
223
+ } | {
224
+ kind: 'delete-suite';
225
+ id: string;
226
+ expectedVersion: string;
227
+ } | {
228
+ kind: 'put-dataset';
229
+ id: string;
230
+ expectedVersion: string | null;
231
+ dataset: EvaluationDataset;
232
+ } | {
233
+ kind: 'delete-dataset';
234
+ id: string;
235
+ expectedVersion: string;
236
+ };
237
+ export type EvaluationLibraryMutation = {
238
+ changes: EvaluationLibraryMutationChange[];
239
+ };
240
+ export type EvaluationLibraryConflictResource = {
241
+ kind: EvaluationLibraryResourceKind;
242
+ id: string;
243
+ expectedVersion: string | null;
244
+ currentVersion: string | null;
245
+ };
246
+ /**
247
+ * A conflict is deliberately expressed with both values. Hosts use this to
248
+ * present an explicit choice instead of silently overwriting either editor.
249
+ */
250
+ export type EvaluationLibraryConflictDraft = EvaluationLibraryConflictResource & {
251
+ local: EvaluationLibraryResourceValue;
252
+ server: EvaluationLibraryResourceValue;
253
+ };
254
+ export type EvaluationLibrarySyncIssue = {
255
+ id: string;
256
+ kind: 'conflict';
257
+ message: string;
258
+ conflicts: readonly EvaluationLibraryConflictDraft[];
259
+ } | {
260
+ id: string;
261
+ kind: 'retryable' | 'failed';
262
+ message: string;
263
+ };
264
+ export type EvaluationLibraryConflictResolution = {
265
+ issueId: string;
266
+ kind: EvaluationLibraryResourceKind;
267
+ id: string;
268
+ action: 'use-server' | 'keep-mine-as-copy';
269
+ };
270
+ /** A host can expose this optional capability without changing local stores. */
271
+ export type EvaluationLibrarySyncStore = {
272
+ getLibrarySyncSnapshot(): Promise<EvaluationLibrarySyncSnapshot>;
273
+ mutateLibrary(input: EvaluationLibraryMutation): Promise<EvaluationLibrarySyncSnapshot>;
274
+ subscribeLibraryInvalidation?(listener: (invalidation: EvaluationLibraryInvalidation) => void): () => void;
275
+ /** An unresolved hosted save requiring an explicit user decision. */
276
+ subscribeLibrarySyncIssue?(listener: (issue: EvaluationLibrarySyncIssue | undefined) => void): () => void;
277
+ resolveLibraryConflict?(input: EvaluationLibraryConflictResolution): Promise<EvaluationLibrary>;
278
+ retryLibrarySync?(): Promise<EvaluationLibrary>;
279
+ };
161
280
  export type EvaluationObservationStatus = 'passed' | 'failed' | 'scored' | 'error' | 'skipped';
162
281
  export type EvaluationObservation = {
163
282
  id: string;
@@ -284,7 +403,13 @@ export type EvaluationAggregate = {
284
403
  /** Normalized internal score in the closed 0..1 range. */
285
404
  meanScore?: number;
286
405
  averageLatencyMs: number;
406
+ /** Optional so historical persisted runs without this newer factoid remain readable. */
407
+ medianLatencyMs?: number;
287
408
  p95LatencyMs: number;
409
+ /** Score distribution statistics use equal-weight per-case mean scores. */
410
+ medianScore?: number;
411
+ /** Score distribution statistics use equal-weight per-case mean scores. */
412
+ p95Score?: number;
288
413
  totalCostUsd?: number;
289
414
  averageCostUsd?: number;
290
415
  targetErrorRate: number;
@@ -307,6 +432,8 @@ export type EvaluationRun = {
307
432
  projectId: ProjectId;
308
433
  suiteId: string;
309
434
  suiteName: string;
435
+ /** Optional user-assigned label for distinguishing retained runs. */
436
+ name?: string;
310
437
  /**
311
438
  * Monotonically increases while a run is persisted. Stores use it to reject
312
439
  * a delayed live-progress write after a newer completed snapshot.
@@ -318,6 +445,8 @@ export type EvaluationRun = {
318
445
  purpose: EvaluationRunPurpose;
319
446
  /** Captures the suite semantics that produced this run. */
320
447
  evaluationMode?: EvaluationSuiteMode;
448
+ /** Planned target executions, retained so live progress does not depend on a later suite edit. */
449
+ requestedTrialCount?: number;
321
450
  executionStatus: 'queued' | 'running' | 'completed' | 'canceled' | 'error';
322
451
  qualityStatus: EvaluationQualityStatus;
323
452
  qualityReason: EvaluationQualityReason;
@@ -329,6 +458,31 @@ export type EvaluationRun = {
329
458
  trials: EvaluationTrial[];
330
459
  warnings: string[];
331
460
  };
461
+ /**
462
+ * Incremental live-run protocol. A started event carries only the empty run
463
+ * shell, a settled event carries one immutable trial, and the terminal event
464
+ * carries the complete reporting shape once. Consumers that still need full
465
+ * snapshots can use RunEvaluationSuiteOptions.onUpdate during the compatibility
466
+ * period.
467
+ */
468
+ export type EvaluationRunEvent = {
469
+ type: 'run-started';
470
+ revision: number;
471
+ run: EvaluationRun;
472
+ } | {
473
+ type: 'trial-settled';
474
+ revision: number;
475
+ runId: string;
476
+ projectId: ProjectId;
477
+ suiteId: string;
478
+ requestedTrialCount: number;
479
+ settledTrialCount: number;
480
+ trial: EvaluationTrial;
481
+ } | {
482
+ type: 'run-finalized';
483
+ revision: number;
484
+ run: EvaluationRun;
485
+ };
332
486
  export type EvaluationRecordingReference = {
333
487
  id: string;
334
488
  retention: 'temporary' | 'failure' | 'baseline' | 'retained';
@@ -386,6 +540,12 @@ export type EvaluationGraphRunner = (input: {
386
540
  }) => Promise<EvaluationGraphExecution>;
387
541
  export type EvaluationRunStore = {
388
542
  put(run: EvaluationRun): Promise<void>;
543
+ /** Sets a user-assigned run name; omit the name to restore the Unnamed label. */
544
+ updateRunName(input: {
545
+ projectId: ProjectId;
546
+ runId: string;
547
+ name?: string;
548
+ }): Promise<EvaluationRun | undefined>;
389
549
  get(input: {
390
550
  projectId: ProjectId;
391
551
  runId: string;
@@ -417,12 +577,38 @@ export type EvaluationRunStore = {
417
577
  recordingId: string;
418
578
  retention: EvaluationRecordingReference['retention'];
419
579
  expiresAt?: string;
420
- }): Promise<void>;
580
+ }): Promise<boolean>;
421
581
  /** Pins all artifacts belonging to the run before its compact baseline is saved in the project. */
422
582
  promoteBaseline(input: {
423
583
  projectId: ProjectId;
424
584
  runId: string;
425
585
  }): Promise<void>;
586
+ /**
587
+ * Optional V2 capability. Persists an idempotent incremental lifecycle event
588
+ * so a host can recover settled work after a process interruption.
589
+ */
590
+ applyRunEvent?(event: EvaluationRunEvent): Promise<void>;
591
+ };
592
+ export type EvaluationStoreInitialization = {
593
+ /** A recoverable persistence warning that a host may surface to the user. */
594
+ warning?: string;
595
+ };
596
+ /**
597
+ * Complete persistence boundary for Evaluations. Desktop, browser, and hosted
598
+ * Rivet instances implement this same contract so definitions and operational
599
+ * evidence cannot silently land in different stores.
600
+ */
601
+ export type EvaluationStore = EvaluationRunStore & {
602
+ initialize?(): Promise<EvaluationStoreInitialization | void>;
603
+ getLibrary(): Promise<EvaluationLibrary>;
604
+ putLibrary(library: EvaluationLibrary): Promise<void>;
605
+ /** Optional hosted capability for resource-scoped collaborative saves. */
606
+ getLibrarySyncSnapshot?: EvaluationLibrarySyncStore['getLibrarySyncSnapshot'];
607
+ mutateLibrary?: EvaluationLibrarySyncStore['mutateLibrary'];
608
+ subscribeLibraryInvalidation?: EvaluationLibrarySyncStore['subscribeLibraryInvalidation'];
609
+ subscribeLibrarySyncIssue?: EvaluationLibrarySyncStore['subscribeLibrarySyncIssue'];
610
+ resolveLibraryConflict?: EvaluationLibrarySyncStore['resolveLibraryConflict'];
611
+ retryLibrarySync?: EvaluationLibrarySyncStore['retryLibrarySync'];
426
612
  };
427
613
  export type EvaluationReporter = {
428
614
  report(run: EvaluationRun): Promise<void> | void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valerypopoff/rivet2-evaluations",
3
- "version": "2.3.0",
3
+ "version": "2.5.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/cjs/bundle.cjs",
6
6
  "module": "dist/esm/index.js",
@@ -36,7 +36,7 @@
36
36
  "access": "public"
37
37
  },
38
38
  "dependencies": {
39
- "@valerypopoff/rivet2-core": "^2.3.0",
39
+ "@valerypopoff/rivet2-core": "^2.5.0",
40
40
  "yaml": "^2.9.0"
41
41
  }
42
42
  }