@velum-labs/routekit-eval-setup 1.0.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.
Files changed (56) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +23 -0
  3. package/dist/effect-api.d.ts +12 -0
  4. package/dist/effect-api.js +9 -0
  5. package/dist/errors.d.ts +91 -0
  6. package/dist/errors.js +46 -0
  7. package/dist/host-metadata.d.ts +32 -0
  8. package/dist/host-metadata.js +46 -0
  9. package/dist/index.d.ts +20 -0
  10. package/dist/index.js +13 -0
  11. package/dist/inspection.d.ts +24 -0
  12. package/dist/inspection.js +261 -0
  13. package/dist/model-selection.d.ts +6 -0
  14. package/dist/model-selection.js +37 -0
  15. package/dist/ori-authoring.d.ts +16 -0
  16. package/dist/ori-authoring.js +17 -0
  17. package/dist/ori-result.d.ts +45 -0
  18. package/dist/ori-result.js +1 -0
  19. package/dist/project-artifacts.d.ts +31 -0
  20. package/dist/project-artifacts.js +353 -0
  21. package/dist/project-authoring.d.ts +68 -0
  22. package/dist/project-authoring.js +431 -0
  23. package/dist/project-contracts.d.ts +1197 -0
  24. package/dist/project-contracts.js +396 -0
  25. package/dist/project-store.d.ts +13 -0
  26. package/dist/project-store.js +53 -0
  27. package/dist/project-workflow.d.ts +33 -0
  28. package/dist/project-workflow.js +904 -0
  29. package/dist/questions.d.ts +7 -0
  30. package/dist/questions.js +67 -0
  31. package/dist/runner.d.ts +8 -0
  32. package/dist/runner.js +16 -0
  33. package/dist/service.d.ts +24 -0
  34. package/dist/service.js +279 -0
  35. package/dist/state-store.d.ts +21 -0
  36. package/dist/state-store.js +86 -0
  37. package/dist/test/inspection.test.d.ts +1 -0
  38. package/dist/test/inspection.test.js +68 -0
  39. package/dist/test/model-selection.test.d.ts +1 -0
  40. package/dist/test/model-selection.test.js +15 -0
  41. package/dist/test/project-authoring.test.d.ts +1 -0
  42. package/dist/test/project-authoring.test.js +67 -0
  43. package/dist/test/project-workflow.test.d.ts +1 -0
  44. package/dist/test/project-workflow.test.js +516 -0
  45. package/dist/test/questions.test.d.ts +1 -0
  46. package/dist/test/questions.test.js +48 -0
  47. package/dist/test/skill.test.d.ts +1 -0
  48. package/dist/test/skill.test.js +31 -0
  49. package/dist/test/state-store.test.d.ts +1 -0
  50. package/dist/test/state-store.test.js +30 -0
  51. package/dist/test/workflow.test.d.ts +1 -0
  52. package/dist/test/workflow.test.js +167 -0
  53. package/dist/types.d.ts +77 -0
  54. package/dist/types.js +1 -0
  55. package/package.json +52 -0
  56. package/skills/setup-eval-routing/SKILL.md +149 -0
@@ -0,0 +1,396 @@
1
+ import { DecompositionResult, EvalComparisonResult, PublishedRoutingActivation, RoutingActivationConstraints, RequestRoutingRequirements, RoutingObjectivePolicy } from "@velum-labs/routekit-eval-contracts";
2
+ import { Schema } from "effect";
3
+ export const EVAL_PROJECT_VERSION = 1;
4
+ export const EvalProjectQuestion = Schema.Struct({
5
+ id: Schema.Literals([
6
+ "workload-description",
7
+ "candidate-models",
8
+ "classifier-model",
9
+ "author-model",
10
+ "judge-model",
11
+ "routing-objective",
12
+ "maximum-unknown-weight",
13
+ "routing-constraints"
14
+ ]),
15
+ prompt: Schema.String,
16
+ options: Schema.Array(Schema.String)
17
+ });
18
+ const WorkloadDescriptionRequired = Schema.TaggedStruct("WorkloadDescriptionRequired", {});
19
+ const CandidateModelsRequired = Schema.TaggedStruct("CandidateModelsRequired", {
20
+ workloadDescription: Schema.String
21
+ });
22
+ const ClassifierModelRequired = Schema.TaggedStruct("ClassifierModelRequired", {
23
+ workloadDescription: Schema.String,
24
+ candidateModels: Schema.Array(Schema.String)
25
+ });
26
+ const AuthorModelRequired = Schema.TaggedStruct("AuthorModelRequired", {
27
+ workloadDescription: Schema.String,
28
+ candidateModels: Schema.Array(Schema.String),
29
+ classifierModel: Schema.String
30
+ });
31
+ const JudgeModelRequired = Schema.TaggedStruct("JudgeModelRequired", {
32
+ workloadDescription: Schema.String,
33
+ candidateModels: Schema.Array(Schema.String),
34
+ classifierModel: Schema.String,
35
+ authorModel: Schema.String
36
+ });
37
+ const RoutingObjectiveRequired = Schema.TaggedStruct("RoutingObjectiveRequired", {
38
+ workloadDescription: Schema.String,
39
+ candidateModels: Schema.Array(Schema.String),
40
+ classifierModel: Schema.String,
41
+ authorModel: Schema.String,
42
+ judgeModel: Schema.String
43
+ });
44
+ const MaximumUnknownWeightRequired = Schema.TaggedStruct("MaximumUnknownWeightRequired", {
45
+ workloadDescription: Schema.String,
46
+ candidateModels: Schema.Array(Schema.String),
47
+ classifierModel: Schema.String,
48
+ authorModel: Schema.String,
49
+ judgeModel: Schema.String,
50
+ objective: RoutingObjectivePolicy
51
+ });
52
+ const RoutingConstraintsRequired = Schema.TaggedStruct("RoutingConstraintsRequired", {
53
+ workloadDescription: Schema.String,
54
+ candidateModels: Schema.Array(Schema.String),
55
+ classifierModel: Schema.String,
56
+ authorModel: Schema.String,
57
+ judgeModel: Schema.String,
58
+ objective: RoutingObjectivePolicy,
59
+ maximumUnknownWeight: Schema.Finite
60
+ });
61
+ export const EvalProjectSetupProgress = Schema.Union([
62
+ WorkloadDescriptionRequired,
63
+ CandidateModelsRequired,
64
+ ClassifierModelRequired,
65
+ AuthorModelRequired,
66
+ JudgeModelRequired,
67
+ RoutingObjectiveRequired,
68
+ MaximumUnknownWeightRequired,
69
+ RoutingConstraintsRequired
70
+ ]);
71
+ export const EvalProjectConfiguration = Schema.Struct({
72
+ workloadDescription: Schema.String,
73
+ candidateModels: Schema.Array(Schema.String),
74
+ classifierModel: Schema.String,
75
+ authorModel: Schema.String,
76
+ judgeModel: Schema.String,
77
+ objective: RoutingObjectivePolicy,
78
+ maximumUnknownWeight: Schema.Finite,
79
+ constraints: Schema.optionalKey(RoutingActivationConstraints)
80
+ });
81
+ const NonNegativeInteger = Schema.Finite.pipe(Schema.check(Schema.makeFilter((value) => value >= 0 && Number.isInteger(value) ? undefined : "value must be a non-negative integer")));
82
+ const NonNegativeFinite = Schema.Finite.pipe(Schema.check(Schema.makeFilter((value) => value >= 0 ? undefined : "value must be a non-negative finite number")));
83
+ const ProjectCommon = {
84
+ version: Schema.Literal(EVAL_PROJECT_VERSION),
85
+ projectId: Schema.String,
86
+ revision: NonNegativeInteger,
87
+ createdAt: Schema.String,
88
+ updatedAt: Schema.String,
89
+ sourceInventory: Schema.Array(Schema.String)
90
+ };
91
+ const SetupRequiredState = Schema.Struct({
92
+ ...ProjectCommon,
93
+ stage: Schema.Literal("setup-required"),
94
+ progress: EvalProjectSetupProgress
95
+ });
96
+ const DimensionsReviewState = Schema.Struct({
97
+ ...ProjectCommon,
98
+ stage: Schema.Literal("dimensions-review"),
99
+ configuration: EvalProjectConfiguration
100
+ });
101
+ const EvaluationsReviewState = Schema.Struct({
102
+ ...ProjectCommon,
103
+ stage: Schema.Literal("evaluations-review"),
104
+ configuration: EvalProjectConfiguration,
105
+ basisDigest: Schema.String
106
+ });
107
+ const ReadyState = Schema.Struct({
108
+ ...ProjectCommon,
109
+ stage: Schema.Literal("ready"),
110
+ configuration: EvalProjectConfiguration,
111
+ basisDigest: Schema.String,
112
+ evaluationDigest: Schema.String
113
+ });
114
+ const RunningState = Schema.Struct({
115
+ ...ProjectCommon,
116
+ stage: Schema.Literal("running"),
117
+ configuration: EvalProjectConfiguration,
118
+ basisDigest: Schema.String,
119
+ evaluationDigest: Schema.String,
120
+ planId: Schema.String,
121
+ runId: Schema.String
122
+ });
123
+ const QualifiedState = Schema.Struct({
124
+ ...ProjectCommon,
125
+ stage: Schema.Literal("qualified"),
126
+ configuration: EvalProjectConfiguration,
127
+ basisDigest: Schema.String,
128
+ evaluationDigest: Schema.String,
129
+ runId: Schema.String,
130
+ reportPath: Schema.String
131
+ });
132
+ const ActivatedState = Schema.Struct({
133
+ ...ProjectCommon,
134
+ stage: Schema.Literal("activated"),
135
+ configuration: EvalProjectConfiguration,
136
+ basisDigest: Schema.String,
137
+ evaluationDigest: Schema.String,
138
+ runId: Schema.String,
139
+ reportPath: Schema.String,
140
+ evidenceDigest: Schema.String,
141
+ targetIdentity: Schema.String
142
+ });
143
+ export const EvalProjectState = Schema.Union([
144
+ SetupRequiredState,
145
+ DimensionsReviewState,
146
+ EvaluationsReviewState,
147
+ ReadyState,
148
+ RunningState,
149
+ QualifiedState,
150
+ ActivatedState
151
+ ]);
152
+ export const EvalDimensionCase = Schema.Struct({
153
+ id: Schema.String,
154
+ prompt: Schema.String,
155
+ context: Schema.optionalKey(Schema.String),
156
+ rubric: Schema.String
157
+ });
158
+ export const EvalDimensionSuite = Schema.Struct({
159
+ version: Schema.Literal(EVAL_PROJECT_VERSION),
160
+ dimensionId: Schema.String,
161
+ maximumOutputTokens: NonNegativeInteger,
162
+ cases: Schema.Array(EvalDimensionCase)
163
+ });
164
+ export const EvalDecompositionBenchmarkCase = Schema.Struct({
165
+ id: Schema.String,
166
+ request: Schema.String,
167
+ expected: DecompositionResult
168
+ });
169
+ export const EvalDecompositionBenchmark = Schema.Struct({
170
+ maximumVectorL1Error: Schema.Finite,
171
+ cases: Schema.Array(EvalDecompositionBenchmarkCase)
172
+ });
173
+ export const EvalCompositionCase = Schema.Struct({
174
+ id: Schema.String,
175
+ prompt: Schema.String,
176
+ context: Schema.optionalKey(Schema.String),
177
+ rubric: Schema.String,
178
+ decomposition: DecompositionResult,
179
+ requirements: RequestRoutingRequirements
180
+ });
181
+ export const EvalCompositionSuite = Schema.Struct({
182
+ maximumOutputTokens: NonNegativeInteger,
183
+ minimumWinnerScoreGap: Schema.Finite,
184
+ minimumWinnerAgreement: Schema.Finite,
185
+ cases: Schema.Array(EvalCompositionCase)
186
+ });
187
+ export const EvalEvaluationProposal = Schema.Struct({
188
+ version: Schema.Literal(EVAL_PROJECT_VERSION),
189
+ evaluationDigest: Schema.String,
190
+ basisDigest: Schema.String,
191
+ candidateModels: Schema.Array(Schema.String),
192
+ judgeModel: Schema.String,
193
+ suites: Schema.Array(EvalDimensionSuite),
194
+ decompositionBenchmark: EvalDecompositionBenchmark,
195
+ compositionSuite: EvalCompositionSuite
196
+ });
197
+ export const EvalArtifactApproval = Schema.Struct({
198
+ version: Schema.Literal(EVAL_PROJECT_VERSION),
199
+ kind: Schema.Literals(["routing-basis", "evaluations"]),
200
+ digest: Schema.String,
201
+ approvedAt: Schema.String
202
+ });
203
+ export const EvalPlanScope = Schema.Literals(["pilot", "full"]);
204
+ export const EvalExecutionPlan = Schema.Struct({
205
+ version: Schema.Literal(EVAL_PROJECT_VERSION),
206
+ planId: Schema.String,
207
+ projectId: Schema.String,
208
+ projectRevision: NonNegativeInteger,
209
+ createdAt: Schema.String,
210
+ scope: EvalPlanScope,
211
+ basisDigest: Schema.String,
212
+ evaluationDigest: Schema.String,
213
+ candidateModels: Schema.Array(Schema.String),
214
+ classifierModel: Schema.String,
215
+ authorModel: Schema.String,
216
+ judgeModel: Schema.String,
217
+ selectedCaseIds: Schema.Array(Schema.Struct({
218
+ dimensionId: Schema.String,
219
+ caseIds: Schema.Array(Schema.String)
220
+ })),
221
+ selectedDecompositionCaseIds: Schema.Array(Schema.String),
222
+ selectedCompositionCaseIds: Schema.Array(Schema.String),
223
+ maximumOutputTokens: NonNegativeInteger,
224
+ expectedDimensionCandidateCalls: NonNegativeInteger,
225
+ expectedDimensionJudgeCalls: NonNegativeInteger,
226
+ expectedClassifierCalls: NonNegativeInteger,
227
+ expectedCompositionCandidateCalls: NonNegativeInteger,
228
+ expectedCompositionJudgeCalls: NonNegativeInteger,
229
+ expectedCandidateCalls: NonNegativeInteger,
230
+ expectedJudgeCalls: NonNegativeInteger,
231
+ expectedCallCount: NonNegativeInteger
232
+ });
233
+ export const EvalRunTarget = Schema.Struct({
234
+ kind: Schema.Literals(["configured", "external"]),
235
+ identity: Schema.String,
236
+ publishAllowed: Schema.Boolean
237
+ });
238
+ export const EvalRunCleanup = Schema.Struct({
239
+ sessionOpened: Schema.Boolean,
240
+ sessionClosed: Schema.Boolean,
241
+ detail: Schema.optionalKey(Schema.String)
242
+ });
243
+ export const EvalRunLedger = Schema.Struct({
244
+ expectedCalls: NonNegativeInteger,
245
+ observedCalls: NonNegativeInteger,
246
+ observedCandidateRows: NonNegativeInteger,
247
+ knownInputTokens: NonNegativeInteger,
248
+ knownOutputTokens: NonNegativeInteger,
249
+ unknownTokenMeasurements: NonNegativeInteger,
250
+ knownPricedSubtotalUsd: NonNegativeFinite,
251
+ unpricedCalls: NonNegativeInteger
252
+ });
253
+ export const EvalClassifierObservation = Schema.Struct({
254
+ caseId: Schema.String,
255
+ weights: DecompositionResult.fields.weights,
256
+ unknownWeight: DecompositionResult.fields.unknownWeight,
257
+ vectorL1Error: NonNegativeFinite,
258
+ passed: Schema.Boolean,
259
+ classifierCallId: Schema.optionalKey(Schema.String),
260
+ measurement: Schema.Struct({
261
+ costUsd: Schema.optionalKey(NonNegativeFinite),
262
+ durationMs: Schema.optionalKey(NonNegativeFinite),
263
+ inputTokens: Schema.optionalKey(NonNegativeInteger),
264
+ outputTokens: Schema.optionalKey(NonNegativeInteger)
265
+ })
266
+ });
267
+ export const EvalCompositionCaseResult = Schema.Struct({
268
+ caseId: Schema.String,
269
+ predictedWinner: Schema.String,
270
+ observedWinner: Schema.String,
271
+ predictedScoreGap: NonNegativeFinite,
272
+ observedScoreGap: NonNegativeFinite,
273
+ passed: Schema.Boolean
274
+ });
275
+ export const EvalRunQualification = Schema.Struct({
276
+ decomposition: Schema.Struct({
277
+ expectedCases: NonNegativeInteger,
278
+ passedCases: NonNegativeInteger,
279
+ maximumObservedL1Error: NonNegativeFinite,
280
+ observations: Schema.Array(EvalClassifierObservation)
281
+ }),
282
+ composition: Schema.Struct({
283
+ expectedCases: NonNegativeInteger,
284
+ comparableCases: NonNegativeInteger,
285
+ agreeingCases: NonNegativeInteger,
286
+ winnerAgreement: NonNegativeFinite,
287
+ cases: Schema.Array(EvalCompositionCaseResult)
288
+ })
289
+ });
290
+ export function summarizeEvalRunLedger(comparisons, expectedCalls, classifierObservations = []) {
291
+ let observedCalls = 0;
292
+ let observedCandidateRows = 0;
293
+ let knownInputTokens = 0;
294
+ let knownOutputTokens = 0;
295
+ let unknownTokenMeasurements = 0;
296
+ let knownPricedSubtotalUsd = 0;
297
+ let unpricedCalls = 0;
298
+ for (const comparison of comparisons) {
299
+ const calls = comparison.calls ??
300
+ comparison.models.flatMap((model) => model.cases.map((testCase) => ({
301
+ role: "candidate",
302
+ model: model.model,
303
+ caseId: testCase.caseId,
304
+ measurement: testCase.measurement
305
+ })));
306
+ for (const call of calls) {
307
+ observedCalls += 1;
308
+ if (call.role === "candidate")
309
+ observedCandidateRows += 1;
310
+ if (call.measurement.inputTokens === undefined ||
311
+ call.measurement.outputTokens === undefined) {
312
+ unknownTokenMeasurements += 1;
313
+ }
314
+ else {
315
+ knownInputTokens += call.measurement.inputTokens;
316
+ knownOutputTokens += call.measurement.outputTokens;
317
+ }
318
+ if (call.measurement.costUsd === undefined) {
319
+ unpricedCalls += 1;
320
+ }
321
+ else {
322
+ knownPricedSubtotalUsd += call.measurement.costUsd;
323
+ }
324
+ }
325
+ }
326
+ for (const observation of classifierObservations) {
327
+ observedCalls += 1;
328
+ if (observation.measurement.inputTokens === undefined ||
329
+ observation.measurement.outputTokens === undefined) {
330
+ unknownTokenMeasurements += 1;
331
+ }
332
+ else {
333
+ knownInputTokens += observation.measurement.inputTokens;
334
+ knownOutputTokens += observation.measurement.outputTokens;
335
+ }
336
+ if (observation.measurement.costUsd === undefined) {
337
+ unpricedCalls += 1;
338
+ }
339
+ else {
340
+ knownPricedSubtotalUsd += observation.measurement.costUsd;
341
+ }
342
+ }
343
+ return {
344
+ expectedCalls,
345
+ observedCalls,
346
+ observedCandidateRows,
347
+ knownInputTokens,
348
+ knownOutputTokens,
349
+ unknownTokenMeasurements,
350
+ knownPricedSubtotalUsd,
351
+ unpricedCalls
352
+ };
353
+ }
354
+ const EvalRunReportCommon = {
355
+ version: Schema.Literal(EVAL_PROJECT_VERSION),
356
+ runId: Schema.String,
357
+ planId: Schema.String,
358
+ projectId: Schema.String,
359
+ startedAt: Schema.String,
360
+ finishedAt: Schema.String,
361
+ basisDigest: Schema.String,
362
+ evaluationDigest: Schema.String,
363
+ target: EvalRunTarget,
364
+ cleanup: EvalRunCleanup,
365
+ comparisons: Schema.Array(EvalComparisonResult),
366
+ qualification: Schema.optionalKey(EvalRunQualification),
367
+ ledger: EvalRunLedger
368
+ };
369
+ const QualifiedEvalRunReport = Schema.Struct({
370
+ ...EvalRunReportCommon,
371
+ status: Schema.Literal("passed"),
372
+ activation: PublishedRoutingActivation
373
+ });
374
+ const CompletedEvalRunReport = Schema.Struct({
375
+ ...EvalRunReportCommon,
376
+ status: Schema.Literal("completed"),
377
+ activation: PublishedRoutingActivation
378
+ });
379
+ const FailedEvalRunReport = Schema.Struct({
380
+ ...EvalRunReportCommon,
381
+ status: Schema.Literal("failed"),
382
+ failure: Schema.String
383
+ });
384
+ /**
385
+ * Sanitized durable result of one immutable execution plan.
386
+ *
387
+ * Prompts, model responses, credentials, headers, and raw child output are
388
+ * deliberately absent from this contract. Dollar totals are known-priced
389
+ * subtotals only; callers must render cost as unknown when
390
+ * `unpricedCalls` is non-zero.
391
+ */
392
+ export const EvalRunReport = Schema.Union([
393
+ QualifiedEvalRunReport,
394
+ CompletedEvalRunReport,
395
+ FailedEvalRunReport
396
+ ]);
@@ -0,0 +1,13 @@
1
+ import { Context, Effect, FileSystem, Layer, Path } from "effect";
2
+ import { EvalProjectStoreError } from "./errors.js";
3
+ import { EvalProjectState } from "./project-contracts.js";
4
+ export type EvalProjectStoreShape = {
5
+ readonly load: (repositoryRoot: string) => Effect.Effect<EvalProjectState | undefined, EvalProjectStoreError>;
6
+ readonly save: (repositoryRoot: string, state: EvalProjectState) => Effect.Effect<void, EvalProjectStoreError>;
7
+ };
8
+ declare const EvalProjectStore_base: Context.ServiceClass<EvalProjectStore, "@velum-labs/routekit-eval-setup/EvalProjectStore", EvalProjectStoreShape>;
9
+ export declare class EvalProjectStore extends EvalProjectStore_base {
10
+ }
11
+ export declare const makeFileEvalProjectStore: Effect.Effect<EvalProjectStoreShape, never, Path.Path | FileSystem.FileSystem>;
12
+ export declare const EvalProjectStoreLive: Layer.Layer<EvalProjectStore, never, Path.Path | FileSystem.FileSystem>;
13
+ export {};
@@ -0,0 +1,53 @@
1
+ import { writeFileAtomicEffect } from "@velum-labs/routekit-runtime/effect";
2
+ import { Context, Effect, FileSystem, Layer, Path, Schema } from "effect";
3
+ import { EvalProjectStoreError } from "./errors.js";
4
+ import { EvalProjectState } from "./project-contracts.js";
5
+ const PROJECT_FILE = "project.json";
6
+ export class EvalProjectStore extends Context.Service()("@velum-labs/routekit-eval-setup/EvalProjectStore") {
7
+ }
8
+ const storeFailure = (operation, path, cause) => new EvalProjectStoreError({
9
+ operation,
10
+ path,
11
+ detail: cause instanceof Error ? cause.message : String(cause),
12
+ cause
13
+ });
14
+ export const makeFileEvalProjectStore = Effect.gen(function* () {
15
+ const fs = yield* FileSystem.FileSystem;
16
+ const paths = yield* Path.Path;
17
+ const projectPath = (root) => paths.join(paths.resolve(root), ".routekit", "evals", PROJECT_FILE);
18
+ return EvalProjectStore.of({
19
+ load: (repositoryRoot) => Effect.gen(function* () {
20
+ const root = yield* fs
21
+ .realPath(repositoryRoot)
22
+ .pipe(Effect.mapError((cause) => storeFailure("resolving", repositoryRoot, cause)));
23
+ const target = projectPath(root);
24
+ const exists = yield* fs
25
+ .exists(target)
26
+ .pipe(Effect.mapError((cause) => storeFailure("checking", target, cause)));
27
+ if (!exists)
28
+ return undefined;
29
+ const encoded = yield* fs
30
+ .readFileString(target)
31
+ .pipe(Effect.mapError((cause) => storeFailure("reading", target, cause)));
32
+ const json = yield* Effect.try({
33
+ try: () => JSON.parse(encoded),
34
+ catch: (cause) => storeFailure("parsing", target, cause)
35
+ });
36
+ return yield* Schema.decodeUnknownEffect(EvalProjectState)(json).pipe(Effect.mapError((cause) => storeFailure("decoding", target, cause)));
37
+ }),
38
+ save: (repositoryRoot, state) => Effect.gen(function* () {
39
+ const root = yield* fs
40
+ .realPath(repositoryRoot)
41
+ .pipe(Effect.mapError((cause) => storeFailure("resolving", repositoryRoot, cause)));
42
+ const target = projectPath(root);
43
+ const directory = paths.dirname(target);
44
+ yield* fs
45
+ .makeDirectory(directory, { recursive: true, mode: 0o700 })
46
+ .pipe(Effect.mapError((cause) => storeFailure("creating", directory, cause)));
47
+ yield* writeFileAtomicEffect(target, `${JSON.stringify(state, null, 2)}\n`, {
48
+ mode: 0o600
49
+ }).pipe(Effect.mapError((cause) => storeFailure("committing", target, cause)), Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, paths));
50
+ })
51
+ });
52
+ });
53
+ export const EvalProjectStoreLive = Layer.effect(EvalProjectStore, makeFileEvalProjectStore);
@@ -0,0 +1,33 @@
1
+ import type { RoutingBasis } from "@velum-labs/routekit-eval-contracts";
2
+ import { Context, Effect, Layer, Path } from "effect";
3
+ import type { EvalProjectArtifactError, EvalSetupInspectionError } from "./errors.js";
4
+ import { type EvalProjectStoreError, EvalProjectTransitionError } from "./errors.js";
5
+ import { EvalRepositoryInspector } from "./inspection.js";
6
+ import { EvalProjectArtifacts } from "./project-artifacts.js";
7
+ import type { EvalEvaluationProposal, EvalExecutionPlan, EvalPlanScope, EvalProjectStatus, EvalRunReport } from "./project-contracts.js";
8
+ import { EvalProjectStore } from "./project-store.js";
9
+ export type EvalProjectWorkflowError = EvalProjectStoreError | EvalProjectArtifactError | EvalSetupInspectionError | EvalProjectTransitionError;
10
+ export type EvalProjectWorkflowShape = {
11
+ readonly setup: (repositoryRoot: string) => Effect.Effect<EvalProjectStatus, EvalProjectWorkflowError>;
12
+ readonly status: (repositoryRoot: string) => Effect.Effect<EvalProjectStatus | undefined, EvalProjectStoreError | EvalProjectArtifactError>;
13
+ readonly answer: (repositoryRoot: string, answer: string) => Effect.Effect<EvalProjectStatus, EvalProjectStoreError | EvalProjectArtifactError | EvalProjectTransitionError>;
14
+ readonly proposeDimensions: (repositoryRoot: string, dimensions: RoutingBasis["dimensions"]) => Effect.Effect<EvalProjectStatus, EvalProjectWorkflowError>;
15
+ readonly approveDimensions: (repositoryRoot: string, basisDigest: string) => Effect.Effect<EvalProjectStatus, EvalProjectWorkflowError>;
16
+ readonly proposeEvaluations: (repositoryRoot: string, proposal: Omit<EvalEvaluationProposal, "version" | "evaluationDigest" | "basisDigest" | "candidateModels" | "judgeModel">) => Effect.Effect<EvalProjectStatus, EvalProjectWorkflowError>;
17
+ readonly approveEvaluations: (repositoryRoot: string, evaluationDigest: string) => Effect.Effect<EvalProjectStatus, EvalProjectWorkflowError>;
18
+ readonly createPlan: (repositoryRoot: string, scope: EvalPlanScope) => Effect.Effect<EvalExecutionPlan, EvalProjectWorkflowError>;
19
+ readonly startRun: (repositoryRoot: string, planId: string) => Effect.Effect<{
20
+ readonly plan: EvalExecutionPlan;
21
+ readonly runId: string;
22
+ }, EvalProjectWorkflowError>;
23
+ readonly finishRun: (repositoryRoot: string, report: EvalRunReport) => Effect.Effect<EvalProjectStatus, EvalProjectWorkflowError>;
24
+ readonly failRun: (repositoryRoot: string, report: EvalRunReport) => Effect.Effect<EvalProjectStatus, EvalProjectWorkflowError>;
25
+ readonly result: (repositoryRoot: string, runId?: string) => Effect.Effect<EvalRunReport | undefined, EvalProjectWorkflowError>;
26
+ readonly markActivated: (repositoryRoot: string, runId: string, targetIdentity: string) => Effect.Effect<EvalProjectStatus, EvalProjectWorkflowError>;
27
+ };
28
+ declare const EvalProjectWorkflow_base: Context.ServiceClass<EvalProjectWorkflow, "@velum-labs/routekit-eval-setup/EvalProjectWorkflow", EvalProjectWorkflowShape>;
29
+ export declare class EvalProjectWorkflow extends EvalProjectWorkflow_base {
30
+ }
31
+ export declare const makeEvalProjectWorkflow: Effect.Effect<EvalProjectWorkflowShape, never, EvalRepositoryInspector | Path.Path | EvalProjectArtifacts | EvalProjectStore>;
32
+ export declare const EvalProjectWorkflowLive: Layer.Layer<EvalProjectWorkflow, never, EvalRepositoryInspector | Path.Path | EvalProjectArtifacts | EvalProjectStore>;
33
+ export {};