@velum-labs/routekit-eval-service 1.3.1 → 1.4.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/dist/layer-options.d.ts +2 -0
- package/dist/production-runner.js +24 -3
- package/dist/service.d.ts +9 -3
- package/dist/service.js +52 -55
- package/dist/test/production-runner.test.js +11 -5
- package/dist/test/service.test.js +5 -4
- package/package.json +5 -5
package/dist/layer-options.d.ts
CHANGED
|
@@ -4,11 +4,13 @@ export type RouteKitEvalGatewayCallEvent = {
|
|
|
4
4
|
readonly observationId: string;
|
|
5
5
|
readonly phase: "issued";
|
|
6
6
|
readonly role: "candidate" | "judge";
|
|
7
|
+
readonly model: string;
|
|
7
8
|
} | {
|
|
8
9
|
readonly callId?: string;
|
|
9
10
|
readonly observationId: string;
|
|
10
11
|
readonly phase: "completed";
|
|
11
12
|
readonly role: "candidate" | "judge";
|
|
13
|
+
readonly model: string;
|
|
12
14
|
};
|
|
13
15
|
export type RouteKitEvalServiceOptions = Omit<NodeTestExecutionOptions, "bridgeOrigin"> & {
|
|
14
16
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { layer as NodeServicesLayer } from "@effect/platform-node/NodeServices";
|
|
2
2
|
import { EVAL_ATTRIBUTION_HEADER } from "@velum-labs/routekit-eval-contracts";
|
|
3
3
|
import { EvalEngineExecutionError, EvalExecutionPort, makeEvalEngineLayer, makeRouteKitEvalExecutionPortService } from "@velum-labs/routekit-eval-engine";
|
|
4
|
+
import { CostServiceLive } from "@velum-labs/routekit-registry";
|
|
4
5
|
import { Data, Effect, FileSystem, Layer, Path, Stream } from "effect";
|
|
5
6
|
import { HttpClient } from "effect/unstable/http";
|
|
6
7
|
import { makeEvalServiceLayer } from "./service.js";
|
|
@@ -21,22 +22,42 @@ const gatewayCallRole = (raw) => {
|
|
|
21
22
|
return undefined;
|
|
22
23
|
}
|
|
23
24
|
};
|
|
25
|
+
const gatewayCallModel = (body) => {
|
|
26
|
+
const raw = body._tag === "Uint8Array"
|
|
27
|
+
? new TextDecoder().decode(body.body)
|
|
28
|
+
: body._tag === "Raw" && typeof body.body === "string"
|
|
29
|
+
? body.body
|
|
30
|
+
: undefined;
|
|
31
|
+
if (raw === undefined)
|
|
32
|
+
return undefined;
|
|
33
|
+
try {
|
|
34
|
+
const decoded = JSON.parse(raw);
|
|
35
|
+
return typeof decoded.model === "string" && decoded.model.length > 0
|
|
36
|
+
? decoded.model
|
|
37
|
+
: undefined;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
24
43
|
const observeGatewayCalls = (client, observe) => {
|
|
25
44
|
let nextObservationId = 0;
|
|
26
45
|
return HttpClient.transform(client, (responseEffect, request) => {
|
|
27
46
|
const role = gatewayCallRole(request.headers[EVAL_ATTRIBUTION_HEADER]);
|
|
28
|
-
|
|
47
|
+
const model = gatewayCallModel(request.body);
|
|
48
|
+
if (role === undefined || model === undefined)
|
|
29
49
|
return responseEffect;
|
|
30
50
|
return Effect.gen(function* () {
|
|
31
51
|
nextObservationId += 1;
|
|
32
52
|
const observationId = `gateway-call-${String(nextObservationId)}`;
|
|
33
|
-
yield* observe({ observationId, phase: "issued", role });
|
|
53
|
+
yield* observe({ observationId, phase: "issued", role, model });
|
|
34
54
|
const response = yield* responseEffect;
|
|
35
55
|
const rawCallId = response.headers[MODEL_CALL_ID_HEADER]?.trim();
|
|
36
56
|
yield* observe({
|
|
37
57
|
observationId,
|
|
38
58
|
phase: "completed",
|
|
39
59
|
role,
|
|
60
|
+
model,
|
|
40
61
|
...(rawCallId === undefined || rawCallId.length === 0 ? {} : { callId: rawCallId })
|
|
41
62
|
});
|
|
42
63
|
return response;
|
|
@@ -112,4 +133,4 @@ const makeProductionEvalEngineLayer = (options) => makeEvalEngineLayer().pipe(La
|
|
|
112
133
|
* execution port is the only adapter; no parallel comparison-runner service
|
|
113
134
|
* mirrors or wraps the engine API.
|
|
114
135
|
*/
|
|
115
|
-
export const makeRouteKitEvalServiceLayer = (configuration, options) => makeEvalServiceLayer(configuration).pipe(Layer.provide(makeProductionEvalEngineLayer(options)), Layer.provide(NodeServicesLayer));
|
|
136
|
+
export const makeRouteKitEvalServiceLayer = (configuration, options) => makeEvalServiceLayer(configuration).pipe(Layer.provide(makeProductionEvalEngineLayer(options)), Layer.provide(CostServiceLive), Layer.provide(NodeServicesLayer));
|
package/dist/service.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { EvalComparisonRequest, EvalComparisonResult, EvalReasoningEffort, PublishedRoutingActivation, RoutingActivationConstraints, RoutingBasis, RoutingObjectivePolicy } from "@velum-labs/routekit-eval-contracts";
|
|
2
2
|
import { EvalRunManifest } from "@velum-labs/routekit-eval-contracts";
|
|
3
3
|
import { EvalEngine } from "@velum-labs/routekit-eval-engine";
|
|
4
|
+
import { CostService } from "@velum-labs/routekit-registry";
|
|
4
5
|
import { Context, Effect, FileSystem, Layer, Path } from "effect";
|
|
5
6
|
import { EvalServiceComparisonError, EvalServiceConfigurationError, EvalServiceEstimateError, EvalServicePolicyError, EvalServicePublicationError, EvalServiceSpendLimitError, EvalServiceValidationError } from "./errors.js";
|
|
6
7
|
export type EvalComparisonMode = "pilot" | "full";
|
|
@@ -10,8 +11,13 @@ export type EvalSuiteInspection = {
|
|
|
10
11
|
};
|
|
11
12
|
export type EvalComparisonEstimate = {
|
|
12
13
|
readonly callCount: number;
|
|
14
|
+
readonly maximumInputTokens: number;
|
|
15
|
+
readonly maximumOutputTokens: number;
|
|
13
16
|
readonly maximumCostUsd?: number;
|
|
14
|
-
readonly
|
|
17
|
+
readonly knownPricedMaximumUsd: number;
|
|
18
|
+
readonly unpricedCalls: number;
|
|
19
|
+
readonly subscriptionUnitCalls: number;
|
|
20
|
+
readonly unknowns: readonly string[];
|
|
15
21
|
};
|
|
16
22
|
export type EvalRunConfiguration = {
|
|
17
23
|
readonly concurrency?: number;
|
|
@@ -52,6 +58,6 @@ export type EvalServiceShape = {
|
|
|
52
58
|
declare const EvalService_base: Context.ServiceClass<EvalService, "@velum-labs/routekit-eval-service/EvalService", EvalServiceShape>;
|
|
53
59
|
export declare class EvalService extends EvalService_base {
|
|
54
60
|
}
|
|
55
|
-
export declare const makeEvalService: (configuration?: EvalServiceConfiguration) => Effect.Effect<EvalService["Service"], never, EvalEngine | FileSystem.FileSystem | Path.Path>;
|
|
56
|
-
export declare const makeEvalServiceLayer: (configuration?: EvalServiceConfiguration) => Layer.Layer<EvalService, never, EvalEngine | FileSystem.FileSystem | Path.Path>;
|
|
61
|
+
export declare const makeEvalService: (configuration?: EvalServiceConfiguration) => Effect.Effect<EvalService["Service"], never, CostService | EvalEngine | FileSystem.FileSystem | Path.Path>;
|
|
62
|
+
export declare const makeEvalServiceLayer: (configuration?: EvalServiceConfiguration) => Layer.Layer<EvalService, never, CostService | EvalEngine | FileSystem.FileSystem | Path.Path>;
|
|
57
63
|
export {};
|
package/dist/service.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { assertExplicitEvalModel, assertRoutingBasis, EvalRunManifest } from "@velum-labs/routekit-eval-contracts";
|
|
2
2
|
import { EvalEngine } from "@velum-labs/routekit-eval-engine";
|
|
3
3
|
import { makeRoutingActivationStore } from "@velum-labs/routekit-eval-store";
|
|
4
|
-
import {
|
|
4
|
+
import { CostService } from "@velum-labs/routekit-registry";
|
|
5
5
|
import { Context, Effect, FileSystem, Layer, Path, Schema } from "effect";
|
|
6
6
|
import { compileDimensionEvidenceMatrix } from "./dimension-evidence.js";
|
|
7
7
|
import { EvalServiceComparisonError, EvalServiceConfigurationError, EvalServiceEstimateError, EvalServicePolicyError, EvalServicePublicationError, EvalServiceSpendLimitError, EvalServiceValidationError } from "./errors.js";
|
|
@@ -101,61 +101,57 @@ const comparisonRequest = (configuration, gatewayUrl, input, suite) => ({
|
|
|
101
101
|
: { timeoutMs: configuration.full.timeoutMs })
|
|
102
102
|
});
|
|
103
103
|
const MAXIMUM_INPUT_TOKENS_PER_CALL = 256 * 1024;
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const candidatePrices = manifest.candidateModels.map(modelPricing);
|
|
124
|
-
const judgePrice = modelPricing(manifest.judgeModel);
|
|
125
|
-
if (candidatePrices.some((pricing) => pricing === undefined) || judgePrice === undefined) {
|
|
126
|
-
return {
|
|
127
|
-
callCount: manifest.expectedCallCount,
|
|
128
|
-
pricingKnown: false
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
const candidateCost = candidatePrices.reduce((total, pricing) => total + manifest.caseCount * maximumCallCost(pricing, manifest.maxOutputTokens), 0);
|
|
132
|
-
const judgeCost = manifest.caseCount *
|
|
133
|
-
manifest.candidateModels.length *
|
|
134
|
-
maximumCallCost(judgePrice, manifest.maxOutputTokens);
|
|
135
|
-
return {
|
|
104
|
+
const estimateManifest = (manifest, costService) => {
|
|
105
|
+
const calls = [
|
|
106
|
+
...manifest.candidateModels.map((model) => ({
|
|
107
|
+
model,
|
|
108
|
+
callCount: manifest.caseCount,
|
|
109
|
+
maximumInputTokens: MAXIMUM_INPUT_TOKENS_PER_CALL,
|
|
110
|
+
maximumOutputTokens: manifest.maxOutputTokens,
|
|
111
|
+
...(manifest.candidateReasoningEfforts?.[model] === undefined
|
|
112
|
+
? {}
|
|
113
|
+
: { reasoningEffort: manifest.candidateReasoningEfforts[model] })
|
|
114
|
+
})),
|
|
115
|
+
{
|
|
116
|
+
model: manifest.judgeModel,
|
|
117
|
+
callCount: manifest.caseCount * manifest.candidateModels.length,
|
|
118
|
+
maximumInputTokens: MAXIMUM_INPUT_TOKENS_PER_CALL,
|
|
119
|
+
maximumOutputTokens: manifest.maxOutputTokens
|
|
120
|
+
}
|
|
121
|
+
];
|
|
122
|
+
return costService.estimate(calls).pipe(Effect.map((estimate) => ({
|
|
136
123
|
callCount: manifest.expectedCallCount,
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
124
|
+
maximumInputTokens: estimate.knownInputTokens,
|
|
125
|
+
maximumOutputTokens: estimate.knownOutputTokens,
|
|
126
|
+
...(estimate.maximumCostUsd === undefined ? {} : { maximumCostUsd: estimate.maximumCostUsd }),
|
|
127
|
+
knownPricedMaximumUsd: estimate.knownPricedMaximumUsd,
|
|
128
|
+
unpricedCalls: estimate.unpricedCalls + estimate.upstreamManagedCalls + estimate.unknownBillingCalls,
|
|
129
|
+
subscriptionUnitCalls: estimate.subscriptionUnitCalls,
|
|
130
|
+
unknowns: estimate.unknowns
|
|
131
|
+
})));
|
|
140
132
|
};
|
|
141
|
-
const enforceSpendLimit = (request, manifest) => {
|
|
142
|
-
|
|
133
|
+
const enforceSpendLimit = (request, manifest, costService) => {
|
|
134
|
+
const spendLimitUsd = request.spendLimitUsd;
|
|
135
|
+
if (spendLimitUsd === undefined)
|
|
143
136
|
return Effect.void;
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
137
|
+
return estimateManifest(manifest, costService).pipe(Effect.flatMap((estimate) => {
|
|
138
|
+
if (estimate.unpricedCalls > 0 ||
|
|
139
|
+
estimate.maximumCostUsd === undefined ||
|
|
140
|
+
estimate.unknowns.length > 0) {
|
|
141
|
+
return Effect.fail(new EvalServiceSpendLimitError({
|
|
142
|
+
operation: "enforce the comparison spend limit",
|
|
143
|
+
detail: "RouteKit Eval cannot enforce spendLimitUsd because pricing is unknown for one or more manifest models."
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
if (estimate.maximumCostUsd > spendLimitUsd) {
|
|
147
|
+
return Effect.fail(new EvalServiceSpendLimitError({
|
|
148
|
+
operation: "enforce the comparison spend limit",
|
|
149
|
+
detail: `RouteKit Eval maximum estimated cost $${estimate.maximumCostUsd.toFixed(6)} ` +
|
|
150
|
+
`exceeds spendLimitUsd $${spendLimitUsd.toFixed(6)}.`
|
|
151
|
+
}));
|
|
152
|
+
}
|
|
153
|
+
return Effect.void;
|
|
154
|
+
}));
|
|
159
155
|
};
|
|
160
156
|
const EXECUTION_MANIFEST_NAME = "routekit.eval-manifest.json";
|
|
161
157
|
const discoverExecutionManifests = Effect.fnUntraced(function* (root) {
|
|
@@ -253,6 +249,7 @@ const loadExecutionManifest = Effect.fn("EvalService.loadExecutionManifest")(fun
|
|
|
253
249
|
});
|
|
254
250
|
export const makeEvalService = (configuration = {}) => Effect.gen(function* () {
|
|
255
251
|
const engine = yield* EvalEngine;
|
|
252
|
+
const costService = yield* CostService;
|
|
256
253
|
const fs = yield* FileSystem.FileSystem;
|
|
257
254
|
const paths = yield* Path.Path;
|
|
258
255
|
const inspectRaw = Effect.fn("EvalService.inspectRaw")(function* (request) {
|
|
@@ -273,12 +270,12 @@ export const makeEvalService = (configuration = {}) => Effect.gen(function* () {
|
|
|
273
270
|
detail: detailOf(cause),
|
|
274
271
|
cause
|
|
275
272
|
})));
|
|
276
|
-
const estimate = (request) => inspectRaw(request).pipe(Effect.
|
|
273
|
+
const estimate = (request) => inspectRaw(request).pipe(Effect.flatMap((inspection) => estimateManifest(inspection.manifest, costService)), Effect.mapError((cause) => new EvalServiceEstimateError({
|
|
277
274
|
operation: "estimate the comparison",
|
|
278
275
|
detail: detailOf(cause),
|
|
279
276
|
cause
|
|
280
277
|
})));
|
|
281
|
-
const runInspectedComparison = (request, inspection) => enforceSpendLimit(request, inspection.manifest).pipe(Effect.flatMap(() => engine
|
|
278
|
+
const runInspectedComparison = (request, inspection) => enforceSpendLimit(request, inspection.manifest, costService).pipe(Effect.flatMap(() => engine
|
|
282
279
|
.runComparison({
|
|
283
280
|
...request,
|
|
284
281
|
expectedCaseIds: [...inspection.manifest.caseIds],
|
|
@@ -99,7 +99,10 @@ test("production runner estimates the exact imported nested-loop testdrive suite
|
|
|
99
99
|
}, "pilot");
|
|
100
100
|
})).pipe(Effect.provide(NodeHttpClient.layerUndici)));
|
|
101
101
|
assert.equal(result.callCount, 30);
|
|
102
|
-
assert.equal(result.
|
|
102
|
+
assert.equal(result.unpricedCalls, 0);
|
|
103
|
+
assert.equal(result.subscriptionUnitCalls, 0);
|
|
104
|
+
assert.equal(result.maximumInputTokens, 30 * 256 * 1024);
|
|
105
|
+
assert.equal(result.maximumOutputTokens, 30 * 1_024);
|
|
103
106
|
assert.equal((result.maximumCostUsd ?? 0) > 0, true);
|
|
104
107
|
});
|
|
105
108
|
test("production runner rejects a manifest for a different profile", async () => {
|
|
@@ -234,6 +237,7 @@ test("production runner executes candidate and judge traffic through the live en
|
|
|
234
237
|
observed.push({
|
|
235
238
|
phase: event.phase,
|
|
236
239
|
role: event.role,
|
|
240
|
+
model: event.model,
|
|
237
241
|
...(event.phase === "completed" && event.callId !== undefined
|
|
238
242
|
? { callId: event.callId }
|
|
239
243
|
: {})
|
|
@@ -251,17 +255,19 @@ test("production runner executes candidate and judge traffic through the live en
|
|
|
251
255
|
{ model: "openai/judge", reasoningEffort: undefined }
|
|
252
256
|
]);
|
|
253
257
|
assert.deepEqual(observed, [
|
|
254
|
-
{ phase: "issued", role: "candidate" },
|
|
258
|
+
{ phase: "issued", role: "candidate", model: "openai/cheap" },
|
|
255
259
|
{
|
|
256
260
|
callId: "model-call-1",
|
|
257
261
|
phase: "completed",
|
|
258
|
-
role: "candidate"
|
|
262
|
+
role: "candidate",
|
|
263
|
+
model: "openai/cheap"
|
|
259
264
|
},
|
|
260
|
-
{ phase: "issued", role: "judge" },
|
|
265
|
+
{ phase: "issued", role: "judge", model: "openai/judge" },
|
|
261
266
|
{
|
|
262
267
|
callId: "model-call-2",
|
|
263
268
|
phase: "completed",
|
|
264
|
-
role: "judge"
|
|
269
|
+
role: "judge",
|
|
270
|
+
model: "openai/judge"
|
|
265
271
|
}
|
|
266
272
|
]);
|
|
267
273
|
assert.deepEqual(result.models.map(({ model }) => model), ["openai/cheap"]);
|
|
@@ -5,6 +5,7 @@ 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 { CostServiceLive } from "@velum-labs/routekit-registry";
|
|
8
9
|
import { Effect, Fiber, FileSystem, Layer, Path } from "effect";
|
|
9
10
|
import { EvalService, makeEvalService, makeEvalServiceLayer } from "../service.js";
|
|
10
11
|
const roots = [];
|
|
@@ -135,7 +136,7 @@ test("manifest discovery does not call FileSystem.glob when Node glob is unavail
|
|
|
135
136
|
suiteDigest: "suite-nested"
|
|
136
137
|
}),
|
|
137
138
|
runComparison: () => Effect.die("unexpected comparison")
|
|
138
|
-
})), Effect.provideService(FileSystem.FileSystem, fileSystemWithoutNodeGlob), Effect.provideService(Path.Path, paths));
|
|
139
|
+
})), Effect.provideService(FileSystem.FileSystem, fileSystemWithoutNodeGlob), Effect.provideService(Path.Path, paths), Effect.provide(CostServiceLive));
|
|
139
140
|
return yield* service.inspect({
|
|
140
141
|
version: 1,
|
|
141
142
|
profileId: "nested",
|
|
@@ -162,7 +163,7 @@ test("dimension matrix qualification inspects every manifest before publishing o
|
|
|
162
163
|
const layer = makeEvalServiceLayer({
|
|
163
164
|
gatewayUrl: "http://127.0.0.1:8080/v1",
|
|
164
165
|
snapshotRoot
|
|
165
|
-
}).pipe(Layer.provide(engine), Layer.provide(NodeServicesLayer));
|
|
166
|
+
}).pipe(Layer.provide(engine), Layer.provide(CostServiceLive), Layer.provide(NodeServicesLayer));
|
|
166
167
|
const result = await Effect.runPromise(Effect.gen(function* () {
|
|
167
168
|
return yield* (yield* EvalService).qualifyDimensionMatrix(qualification(root));
|
|
168
169
|
}).pipe(Effect.provide(layer)));
|
|
@@ -184,7 +185,7 @@ test("dimension matrix qualification never publishes incomplete comparison evide
|
|
|
184
185
|
const layer = makeEvalServiceLayer({
|
|
185
186
|
gatewayUrl: "http://127.0.0.1:8080/v1",
|
|
186
187
|
snapshotRoot
|
|
187
|
-
}).pipe(Layer.provide(engine), Layer.provide(NodeServicesLayer));
|
|
188
|
+
}).pipe(Layer.provide(engine), Layer.provide(CostServiceLive), Layer.provide(NodeServicesLayer));
|
|
188
189
|
const exit = await Effect.runPromiseExit(Effect.gen(function* () {
|
|
189
190
|
return yield* (yield* EvalService).qualifyDimensionMatrix(qualification(root));
|
|
190
191
|
}).pipe(Effect.provide(layer)));
|
|
@@ -204,7 +205,7 @@ test("interrupted qualification leaves no half-published activation for a daemon
|
|
|
204
205
|
const layer = makeEvalServiceLayer({
|
|
205
206
|
gatewayUrl: "http://127.0.0.1:8080/v1",
|
|
206
207
|
snapshotRoot
|
|
207
|
-
}).pipe(Layer.provide(engine), Layer.provide(NodeServicesLayer));
|
|
208
|
+
}).pipe(Layer.provide(engine), Layer.provide(CostServiceLive), Layer.provide(NodeServicesLayer));
|
|
208
209
|
await Effect.runPromise(Effect.gen(function* () {
|
|
209
210
|
const fiber = yield* Effect.forkChild((yield* EvalService).qualifyDimensionMatrix(qualification(root)));
|
|
210
211
|
yield* Effect.yieldNow;
|
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.
|
|
4
|
+
"version": "1.4.0",
|
|
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.
|
|
36
|
-
"@velum-labs/routekit-eval-engine": "1.
|
|
37
|
-
"@velum-labs/routekit-eval-store": "1.
|
|
38
|
-
"@velum-labs/routekit-registry": "1.
|
|
35
|
+
"@velum-labs/routekit-eval-contracts": "1.4.0",
|
|
36
|
+
"@velum-labs/routekit-eval-engine": "1.4.0",
|
|
37
|
+
"@velum-labs/routekit-eval-store": "1.4.0",
|
|
38
|
+
"@velum-labs/routekit-registry": "1.4.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"typescript": "7.0.2"
|