Skip to content

Commit e151663

Browse files
Initialize parameter values to default values (#1363)
Related PR: braintrustdata/braintrust#10788 After some recent discussions, I've realized that parameter data should be initialized to your default values. This is largely because when we open a parameter within our UI, we want to show the default values within forms without rendering forms in a dirty state. Here is a demo of parameter creation: https://github.com/user-attachments/assets/0bd28948-843b-41c0-bf0d-e1a2d39ccce2 Bumped the SDK version because I would like to release and share this with customers ASAP.
1 parent 99bc21b commit e151663

3 files changed

Lines changed: 123 additions & 3 deletions

File tree

js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "braintrust",
3-
"version": "2.2.1",
3+
"version": "2.2.2",
44
"description": "SDK for integrating Braintrust",
55
"repository": {
66
"type": "git",

js/src/framework.test.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,111 @@ describe("framework2 metadata support", () => {
992992
});
993993
});
994994

995+
describe("CodeParameters defaults", () => {
996+
test("toFunctionDefinition initializes data with schema defaults", async () => {
997+
const project = projects.create({ name: "test-project" });
998+
project.parameters.create({
999+
name: "test-parameters",
1000+
schema: {
1001+
title: z.string().default("default-title"),
1002+
numSamples: z.number().default(10),
1003+
enabled: z.boolean().default(true),
1004+
tags: z.array(z.string()).default(["default-tag"]),
1005+
config: z
1006+
.object({
1007+
retryCount: z.number(),
1008+
strategy: z.string(),
1009+
})
1010+
.default({
1011+
retryCount: 3,
1012+
strategy: "balanced",
1013+
}),
1014+
datasetName: z.string(),
1015+
main: {
1016+
type: "prompt",
1017+
default: {
1018+
messages: [{ role: "user", content: "{{input}}" }],
1019+
model: "gpt-4",
1020+
},
1021+
},
1022+
},
1023+
});
1024+
1025+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1026+
const parameters = (project as any)._publishableParameters;
1027+
expect(parameters).toHaveLength(1);
1028+
1029+
const mockProjectMap = {
1030+
resolve: vi.fn().mockResolvedValue("project-123"),
1031+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1032+
} as any;
1033+
1034+
const funcDef = await parameters[0].toFunctionDefinition(mockProjectMap);
1035+
1036+
expect(funcDef.function_data.type).toBe("parameters");
1037+
expect(funcDef.function_data.data).toMatchObject({
1038+
title: "default-title",
1039+
numSamples: 10,
1040+
enabled: true,
1041+
tags: ["default-tag"],
1042+
config: {
1043+
retryCount: 3,
1044+
strategy: "balanced",
1045+
},
1046+
main: {
1047+
prompt: {
1048+
type: "chat",
1049+
messages: [{ role: "user", content: "{{input}}" }],
1050+
},
1051+
options: {
1052+
model: "gpt-4",
1053+
},
1054+
},
1055+
});
1056+
expect(funcDef.function_data.data).not.toHaveProperty("datasetName");
1057+
});
1058+
1059+
test("toFunctionDefinition does not initialize data when schema has no defaults", async () => {
1060+
const project = projects.create({ name: "test-project" });
1061+
project.parameters.create({
1062+
name: "test-parameters-no-defaults",
1063+
schema: {
1064+
title: z.string(),
1065+
numSamples: z.number(),
1066+
enabled: z.boolean(),
1067+
tags: z.array(z.string()),
1068+
config: z.object({
1069+
retryCount: z.number(),
1070+
strategy: z.string(),
1071+
}),
1072+
main: {
1073+
type: "prompt",
1074+
},
1075+
},
1076+
});
1077+
1078+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1079+
const parameters = (project as any)._publishableParameters;
1080+
expect(parameters).toHaveLength(1);
1081+
1082+
const mockProjectMap = {
1083+
resolve: vi.fn().mockResolvedValue("project-123"),
1084+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1085+
} as any;
1086+
1087+
const funcDef = await parameters[0].toFunctionDefinition(mockProjectMap);
1088+
1089+
expect(funcDef.function_data.type).toBe("parameters");
1090+
expect(funcDef.function_data.data).toEqual({});
1091+
expect(funcDef.function_data.data).not.toHaveProperty("title");
1092+
expect(funcDef.function_data.data).not.toHaveProperty("numSamples");
1093+
expect(funcDef.function_data.data).not.toHaveProperty("enabled");
1094+
expect(funcDef.function_data.data).not.toHaveProperty("tags");
1095+
expect(funcDef.function_data.data).not.toHaveProperty("config");
1096+
expect(funcDef.function_data.data).not.toHaveProperty("main");
1097+
});
1098+
});
1099+
9951100
describe("Scorer metadata", () => {
9961101
test("code scorer stores metadata correctly", () => {
9971102
const project = projects.create({ name: "test-project" });

js/src/framework2.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,7 @@ export class CodeParameters {
617617
async toFunctionDefinition(
618618
projectNameToId: ProjectNameIdMap,
619619
): Promise<FunctionEvent> {
620+
const schema = serializeEvalParameterstoParametersSchema(this.schema);
620621
return {
621622
project_id: await projectNameToId.resolve(this.project),
622623
name: this.name,
@@ -625,8 +626,8 @@ export class CodeParameters {
625626
function_type: "parameters",
626627
function_data: {
627628
type: "parameters",
628-
data: {},
629-
__schema: serializeEvalParameterstoParametersSchema(this.schema),
629+
data: getDefaultDataFromParametersSchema(schema),
630+
__schema: schema,
630631
},
631632
if_exists: this.ifExists,
632633
metadata: this.metadata,
@@ -738,6 +739,20 @@ export function serializeEvalParameterstoParametersSchema(
738739
};
739740
}
740741

742+
function getDefaultDataFromParametersSchema(
743+
schema: ParametersSchema,
744+
): Record<string, unknown> {
745+
return Object.fromEntries(
746+
Object.entries(schema.properties).flatMap(([name, value]) => {
747+
if (!("default" in value)) {
748+
return [];
749+
}
750+
751+
return [[name, value.default]];
752+
}),
753+
);
754+
}
755+
741756
export function serializeRemoteEvalParametersContainer(
742757
parameters: EvalParameters | RemoteEvalParameters<boolean, boolean>,
743758
): SerializedParametersContainer {

0 commit comments

Comments
 (0)