@velum-labs/routekit-eval-service 1.0.18 → 1.0.20
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/dist/service.js +29 -5
- package/dist/test/service.test.js +55 -3
- package/package.json +5 -5
package/dist/service.js
CHANGED
|
@@ -145,14 +145,38 @@ const enforceSpendLimit = (request, manifest) => {
|
|
|
145
145
|
}
|
|
146
146
|
return Effect.void;
|
|
147
147
|
};
|
|
148
|
+
const EXECUTION_MANIFEST_NAME = "routekit.eval-manifest.json";
|
|
149
|
+
const discoverExecutionManifests = Effect.fnUntraced(function* (root) {
|
|
150
|
+
const fs = yield* FileSystem.FileSystem;
|
|
151
|
+
const paths = yield* Path.Path;
|
|
152
|
+
const directories = [root];
|
|
153
|
+
const manifests = [];
|
|
154
|
+
while (directories.length > 0) {
|
|
155
|
+
const directory = directories.pop();
|
|
156
|
+
const entries = yield* fs.readDirectory(directory);
|
|
157
|
+
for (const entry of entries) {
|
|
158
|
+
const entryPath = paths.join(directory, entry);
|
|
159
|
+
if (entry === EXECUTION_MANIFEST_NAME) {
|
|
160
|
+
manifests.push(entryPath);
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const isSymbolicLink = yield* fs.readLink(entryPath).pipe(Effect.match({
|
|
164
|
+
onFailure: () => false,
|
|
165
|
+
onSuccess: () => true
|
|
166
|
+
}));
|
|
167
|
+
if (isSymbolicLink)
|
|
168
|
+
continue;
|
|
169
|
+
const info = yield* fs.stat(entryPath);
|
|
170
|
+
if (info.type === "Directory")
|
|
171
|
+
directories.push(entryPath);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return manifests;
|
|
175
|
+
});
|
|
148
176
|
const loadExecutionManifest = Effect.fn("EvalService.loadExecutionManifest")(function* (validation, request) {
|
|
149
177
|
const fs = yield* FileSystem.FileSystem;
|
|
150
178
|
const paths = yield* Path.Path;
|
|
151
|
-
const manifests = yield*
|
|
152
|
-
.glob("**/routekit.eval-manifest.json", {
|
|
153
|
-
root: validation.workingDirectory
|
|
154
|
-
})
|
|
155
|
-
.pipe(Effect.mapError((cause) => new EvalServiceValidationError({
|
|
179
|
+
const manifests = yield* discoverExecutionManifests(validation.workingDirectory).pipe(Effect.mapError((cause) => new EvalServiceValidationError({
|
|
156
180
|
operation: "discover the comparison manifest",
|
|
157
181
|
detail: detailOf(cause),
|
|
158
182
|
cause
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
-
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { mkdir, mkdtemp, readFile, rm, symlink, writeFile } from "node:fs/promises";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { after, test } from "node:test";
|
|
6
6
|
import { layer as NodeServicesLayer } from "@effect/platform-node/NodeServices";
|
|
7
7
|
import { EvalEngine } from "@velum-labs/routekit-eval-engine";
|
|
8
|
-
import { Effect, Fiber, Layer } from "effect";
|
|
9
|
-
import { EvalService, makeEvalServiceLayer } from "../service.js";
|
|
8
|
+
import { Effect, Fiber, FileSystem, Layer, Path } from "effect";
|
|
9
|
+
import { EvalService, makeEvalService, makeEvalServiceLayer } from "../service.js";
|
|
10
10
|
const roots = [];
|
|
11
11
|
after(async () => Promise.all(roots.map((root) => rm(root, { recursive: true, force: true }))));
|
|
12
12
|
const dimensions = [
|
|
@@ -97,6 +97,58 @@ const qualification = (root) => ({
|
|
|
97
97
|
maximumUnknownWeight: 0.2,
|
|
98
98
|
suites: suites(root)
|
|
99
99
|
});
|
|
100
|
+
test("manifest discovery does not call FileSystem.glob when Node glob is unavailable", async () => {
|
|
101
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "routekit-manifest-no-glob-"));
|
|
102
|
+
roots.push(root);
|
|
103
|
+
const suiteDirectory = path.join(root, "nested", "suite");
|
|
104
|
+
const suitePath = path.join(suiteDirectory, "nested.eval.ts");
|
|
105
|
+
await mkdir(suiteDirectory, { recursive: true });
|
|
106
|
+
await writeFile(suitePath, 'import { test } from "node:test"; test("case", () => {});\n');
|
|
107
|
+
await symlink(root, path.join(suiteDirectory, "routekit-link"), "dir");
|
|
108
|
+
await writeFile(path.join(suiteDirectory, "routekit.eval-manifest.json"), `${JSON.stringify({
|
|
109
|
+
version: 1,
|
|
110
|
+
profileId: "nested",
|
|
111
|
+
candidateModels: ["openai/cheap", "anthropic/strong"],
|
|
112
|
+
judgeModel: "openai/judge",
|
|
113
|
+
caseCount: 1,
|
|
114
|
+
caseIds: ["case-1"],
|
|
115
|
+
maxOutputTokens: 256,
|
|
116
|
+
expectedCallCount: 4
|
|
117
|
+
})}\n`);
|
|
118
|
+
let globCalls = 0;
|
|
119
|
+
const inspection = await Effect.runPromise(Effect.gen(function* () {
|
|
120
|
+
const fs = yield* FileSystem.FileSystem;
|
|
121
|
+
const paths = yield* Path.Path;
|
|
122
|
+
const fileSystemWithoutNodeGlob = {
|
|
123
|
+
...fs,
|
|
124
|
+
glob: () => {
|
|
125
|
+
globCalls += 1;
|
|
126
|
+
return Effect.die(new TypeError("Function.prototype.apply was called on undefined"));
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
const service = yield* makeEvalService().pipe(Effect.provideService(EvalEngine, EvalEngine.of({
|
|
130
|
+
discover: () => Effect.die("unexpected discover"),
|
|
131
|
+
validate: () => Effect.succeed({
|
|
132
|
+
searchRoot: suitePath,
|
|
133
|
+
workingDirectory: root,
|
|
134
|
+
files: [suitePath],
|
|
135
|
+
suiteDigest: "suite-nested"
|
|
136
|
+
}),
|
|
137
|
+
runComparison: () => Effect.die("unexpected comparison")
|
|
138
|
+
})), Effect.provideService(FileSystem.FileSystem, fileSystemWithoutNodeGlob), Effect.provideService(Path.Path, paths));
|
|
139
|
+
return yield* service.inspect({
|
|
140
|
+
version: 1,
|
|
141
|
+
profileId: "nested",
|
|
142
|
+
suitePath,
|
|
143
|
+
candidateModels: ["openai/cheap", "anthropic/strong"],
|
|
144
|
+
judgeModel: "openai/judge",
|
|
145
|
+
gatewayUrl: "http://127.0.0.1:8080/v1"
|
|
146
|
+
});
|
|
147
|
+
}).pipe(Effect.provide(NodeServicesLayer)));
|
|
148
|
+
assert.equal(inspection.suiteDigest, "suite-nested");
|
|
149
|
+
assert.equal(inspection.manifest.profileId, "nested");
|
|
150
|
+
assert.equal(globCalls, 0);
|
|
151
|
+
});
|
|
100
152
|
test("dimension matrix qualification inspects every manifest before publishing one activation", async () => {
|
|
101
153
|
const root = await mkdtemp(path.join(os.tmpdir(), "routekit-dimension-matrix-"));
|
|
102
154
|
roots.push(root);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velum-labs/routekit-eval-service",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.20",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/velum-labs/routekit.git",
|
|
@@ -32,10 +32,10 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@effect/platform-node": "4.0.0-rc.108",
|
|
34
34
|
"effect": "4.0.0-rc.108",
|
|
35
|
-
"@velum-labs/routekit-eval-contracts": "1.0.
|
|
36
|
-
"@velum-labs/routekit-eval-engine": "1.0.
|
|
37
|
-
"@velum-labs/routekit-eval-store": "1.0.
|
|
38
|
-
"@velum-labs/routekit-registry": "1.0.
|
|
35
|
+
"@velum-labs/routekit-eval-contracts": "1.0.20",
|
|
36
|
+
"@velum-labs/routekit-eval-engine": "1.0.20",
|
|
37
|
+
"@velum-labs/routekit-eval-store": "1.0.20",
|
|
38
|
+
"@velum-labs/routekit-registry": "1.0.20"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"typescript": "7.0.2"
|