@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.
- package/LICENSE +201 -0
- package/README.md +23 -0
- package/dist/effect-api.d.ts +12 -0
- package/dist/effect-api.js +9 -0
- package/dist/errors.d.ts +91 -0
- package/dist/errors.js +46 -0
- package/dist/host-metadata.d.ts +32 -0
- package/dist/host-metadata.js +46 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +13 -0
- package/dist/inspection.d.ts +24 -0
- package/dist/inspection.js +261 -0
- package/dist/model-selection.d.ts +6 -0
- package/dist/model-selection.js +37 -0
- package/dist/ori-authoring.d.ts +16 -0
- package/dist/ori-authoring.js +17 -0
- package/dist/ori-result.d.ts +45 -0
- package/dist/ori-result.js +1 -0
- package/dist/project-artifacts.d.ts +31 -0
- package/dist/project-artifacts.js +353 -0
- package/dist/project-authoring.d.ts +68 -0
- package/dist/project-authoring.js +431 -0
- package/dist/project-contracts.d.ts +1197 -0
- package/dist/project-contracts.js +396 -0
- package/dist/project-store.d.ts +13 -0
- package/dist/project-store.js +53 -0
- package/dist/project-workflow.d.ts +33 -0
- package/dist/project-workflow.js +904 -0
- package/dist/questions.d.ts +7 -0
- package/dist/questions.js +67 -0
- package/dist/runner.d.ts +8 -0
- package/dist/runner.js +16 -0
- package/dist/service.d.ts +24 -0
- package/dist/service.js +279 -0
- package/dist/state-store.d.ts +21 -0
- package/dist/state-store.js +86 -0
- package/dist/test/inspection.test.d.ts +1 -0
- package/dist/test/inspection.test.js +68 -0
- package/dist/test/model-selection.test.d.ts +1 -0
- package/dist/test/model-selection.test.js +15 -0
- package/dist/test/project-authoring.test.d.ts +1 -0
- package/dist/test/project-authoring.test.js +67 -0
- package/dist/test/project-workflow.test.d.ts +1 -0
- package/dist/test/project-workflow.test.js +516 -0
- package/dist/test/questions.test.d.ts +1 -0
- package/dist/test/questions.test.js +48 -0
- package/dist/test/skill.test.d.ts +1 -0
- package/dist/test/skill.test.js +31 -0
- package/dist/test/state-store.test.d.ts +1 -0
- package/dist/test/state-store.test.js +30 -0
- package/dist/test/workflow.test.d.ts +1 -0
- package/dist/test/workflow.test.js +167 -0
- package/dist/types.d.ts +77 -0
- package/dist/types.js +1 -0
- package/package.json +52 -0
- 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 {};
|