Skip to content

Commit 4045dd4

Browse files
committed
Hydrate remote prompt parameters in evals
1 parent 97e7959 commit 4045dd4

2 files changed

Lines changed: 90 additions & 1 deletion

File tree

js/src/eval-parameters.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,5 +151,51 @@ function validateParametersWithJsonSchema<T extends Record<string, unknown>>(
151151
}
152152

153153
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
154-
return parameters as T;
154+
return hydrateRemoteParameters(parameters, schema) as T;
155+
}
156+
157+
function hydrateRemoteParameters(
158+
parameters: Record<string, unknown>,
159+
schema: Record<string, unknown>,
160+
): Record<string, unknown> {
161+
const properties =
162+
"properties" in schema &&
163+
schema.properties &&
164+
typeof schema.properties === "object"
165+
? (schema.properties as Record<string, unknown>)
166+
: undefined;
167+
if (!properties) {
168+
return parameters;
169+
}
170+
171+
return Object.fromEntries(
172+
Object.entries(parameters).map(([name, value]) => {
173+
const propertySchema = properties[name];
174+
if (!propertySchema || typeof propertySchema !== "object") {
175+
return [name, value];
176+
}
177+
178+
if (
179+
"x-bt-type" in propertySchema &&
180+
propertySchema["x-bt-type"] === "prompt"
181+
) {
182+
return [
183+
name,
184+
Prompt.fromPromptData(name, promptDataSchema.parse(value)),
185+
];
186+
}
187+
188+
if (
189+
"x-bt-type" in propertySchema &&
190+
propertySchema["x-bt-type"] === "model" &&
191+
typeof value !== "string"
192+
) {
193+
throw Error(
194+
`Invalid parameter '${name}': model values must be strings`,
195+
);
196+
}
197+
198+
return [name, value];
199+
}),
200+
);
155201
}

js/src/parameters.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { runEvaluator } from "./framework";
33
import { z } from "zod/v3";
44
import { type ProgressReporter } from "./reporters/types";
55
import { configureNode } from "./node/config";
6+
import { RemoteEvalParameters } from "./logger";
7+
import { validateParameters } from "./eval-parameters";
68

79
beforeAll(() => {
810
configureNode();
@@ -238,3 +240,44 @@ test("model parameter is required when default is missing", async () => {
238240
),
239241
).rejects.toThrow("Parameter 'model' is required");
240242
});
243+
244+
test("remote prompt parameters are hydrated to Prompt objects", async () => {
245+
const parameters = new RemoteEvalParameters({
246+
id: "params-123",
247+
project_id: "project-123",
248+
name: "Saved parameters",
249+
slug: "saved-parameters",
250+
_xact_id: "v1",
251+
function_type: "parameters",
252+
function_data: {
253+
type: "parameters",
254+
data: {
255+
main: {
256+
prompt: {
257+
type: "chat",
258+
messages: [{ role: "user", content: "{{input}}" }],
259+
},
260+
options: {
261+
model: "gpt-5-mini",
262+
},
263+
},
264+
},
265+
__schema: {
266+
type: "object",
267+
properties: {
268+
main: {
269+
type: "object",
270+
"x-bt-type": "prompt",
271+
},
272+
},
273+
additionalProperties: true,
274+
},
275+
},
276+
created: "2023-10-01T00:00:00Z",
277+
});
278+
279+
const result = await validateParameters({}, parameters);
280+
281+
expect(result.main).toBeDefined();
282+
expect(typeof result.main.build).toBe("function");
283+
});

0 commit comments

Comments
 (0)