@velum-labs/routekit-eval-service 1.0.11 → 1.0.12

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.
@@ -7,4 +7,12 @@ export type RouteKitEvalServiceOptions = Omit<NodeTestExecutionOptions, "bridgeO
7
7
  * execution fails before starting a child when it is absent.
8
8
  */
9
9
  readonly bearerCredential?: string;
10
+ /**
11
+ * Host-owned per-test deadline.
12
+ *
13
+ * When set, the production execution adapter applies this value at the
14
+ * node:test boundary even if an intermediate comparison request carries a
15
+ * stale or missing timeout.
16
+ */
17
+ readonly timeoutMs?: number;
10
18
  };
@@ -20,13 +20,24 @@ const makeProductionExecutionPort = (options) => Effect.map(HttpClient.HttpClien
20
20
  }))
21
21
  };
22
22
  }
23
- return makeRouteKitEvalExecutionPortService({
23
+ const execution = makeRouteKitEvalExecutionPortService({
24
24
  bearerCredential,
25
25
  ...(options.childEnvironment === undefined
26
26
  ? {}
27
27
  : { childEnvironment: options.childEnvironment }),
28
28
  ...(options.execPath === undefined ? {} : { execPath: options.execPath })
29
29
  }, httpClient);
30
+ if (options.timeoutMs === undefined)
31
+ return execution;
32
+ return {
33
+ execute: (input) => execution.execute({
34
+ ...input,
35
+ request: {
36
+ ...input.request,
37
+ timeoutMs: options.timeoutMs
38
+ }
39
+ })
40
+ };
30
41
  });
31
42
  const makeProductionEvalEngineLayer = (options) => makeEvalEngineLayer().pipe(Layer.provide(Layer.effect(EvalExecutionPort, makeProductionExecutionPort(options))));
32
43
  /**
@@ -216,3 +216,50 @@ test("production runner executes candidate and judge traffic through the live en
216
216
  await new Promise((resolve, reject) => gateway.close((error) => (error === undefined ? resolve() : reject(error))));
217
217
  }
218
218
  });
219
+ test("production runner applies the host timeout at node:test instead of a stale request deadline", async () => {
220
+ const root = await mkdtemp(path.join(os.tmpdir(), "routekit-eval-runner-timeout-"));
221
+ roots.push(root);
222
+ const suite = path.join(root, "support.eval.ts");
223
+ await writeFile(suite, [
224
+ 'import { test } from "node:test";',
225
+ 'import { setupAgent, setupJudge } from "routekit/eval";',
226
+ 'const judge = setupJudge({ agent: setupAgent({ model: "openai/judge" }), minScore: 0.8 });',
227
+ 'test("support case", async () => {',
228
+ ' const run = await setupAgent({ model: "openai/cheap" }).run({ prompt: "Help", caseId: "support-case" });',
229
+ " run.toComplete();",
230
+ ' await judge.autoEvals({ criteria: "Helpful", prompt: "Help", run });',
231
+ "});"
232
+ ].join("\n"));
233
+ await writeManifest(root, ["openai/cheap"], "openai/judge", ["support-case"]);
234
+ const gateway = createServer((incoming, outgoing) => {
235
+ void (async () => {
236
+ const body = JSON.parse(await readBody(incoming));
237
+ await new Promise((resolve) => setTimeout(resolve, 25));
238
+ const content = body.model === "openai/judge"
239
+ ? JSON.stringify({ pass: true, reason: "helpful", score: 0.9 })
240
+ : "Helpful answer";
241
+ outgoing.writeHead(200, { "content-type": "application/json" });
242
+ outgoing.end(JSON.stringify({
243
+ model: body.model,
244
+ choices: [{ message: { role: "assistant", content } }]
245
+ }));
246
+ })();
247
+ });
248
+ await new Promise((resolve) => gateway.listen(0, "127.0.0.1", resolve));
249
+ const address = gateway.address();
250
+ assert.ok(address !== null && typeof address !== "string");
251
+ try {
252
+ const result = await Effect.runPromise(withEvalService({
253
+ bearerCredential: "parent-only-token",
254
+ timeoutMs: 15_000
255
+ }, (service) => service.runComparison({
256
+ ...requestFor(suite, `http://127.0.0.1:${String(address.port)}`),
257
+ candidateModels: ["openai/cheap"],
258
+ timeoutMs: 5
259
+ }, "full")).pipe(Effect.provide(NodeHttpClient.layerUndici)));
260
+ assert.equal(result.models[0]?.cases[0]?.outcome, "passed");
261
+ }
262
+ finally {
263
+ await new Promise((resolve, reject) => gateway.close((error) => (error === undefined ? resolve() : reject(error))));
264
+ }
265
+ });
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.11",
4
+ "version": "1.0.12",
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.11",
36
- "@velum-labs/routekit-eval-engine": "1.0.11",
37
- "@velum-labs/routekit-eval-store": "1.0.11",
38
- "@velum-labs/routekit-registry": "1.0.11"
35
+ "@velum-labs/routekit-eval-contracts": "1.0.12",
36
+ "@velum-labs/routekit-eval-engine": "1.0.12",
37
+ "@velum-labs/routekit-eval-store": "1.0.12",
38
+ "@velum-labs/routekit-registry": "1.0.12"
39
39
  },
40
40
  "devDependencies": {
41
41
  "typescript": "7.0.2"