Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions src/functions/push.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ const RUNNER_COMMON_SOURCE: &str = include_str!("../../scripts/runner-common.ts"
const PYTHON_RUNNER_COMMON_SOURCE: &str = include_str!("../../scripts/python_runner_common.py");
const PYTHON_BASELINE_DEPS: &[&str] =
&["pydantic", "braintrust", "autoevals", "requests", "openai"];
const PARAMETER_FUNCTION_TYPE: &str = "parameters";
const PARAMETER_SCHEMA_MERGE_PATH: [&str; 2] = ["function_data", "__schema"];
const PARAMETER_METADATA_MERGE_PATH: [&str; 1] = ["metadata"];
// Compatibility shim for existing test harnesses and eval workflows that set
// Python interpreter via BT_EVAL_* variables. Preferred path is still
// --runner / BT_FUNCTIONS_PUSH_RUNNER.
Expand Down Expand Up @@ -725,6 +728,18 @@ fn build_code_function_data(
})
}

fn apply_parameter_function_merge_fields(object: &mut Map<String, Value>) {
if object.get("function_type").and_then(Value::as_str) != Some(PARAMETER_FUNCTION_TYPE) {
return;
}

object.insert("_is_merge".to_string(), Value::Bool(true));
object.insert(
"_merge_paths".to_string(),
json!([PARAMETER_SCHEMA_MERGE_PATH, PARAMETER_METADATA_MERGE_PATH]),
);
}

#[allow(clippy::too_many_arguments)]
async fn push_file(
auth_ctx: &super::AuthContext,
Expand Down Expand Up @@ -846,6 +861,7 @@ async fn push_file(
Value::String(function_type.clone()),
);
}
apply_parameter_function_merge_fields(&mut obj);
if let Some(metadata) = &code.metadata {
obj.insert("metadata".to_string(), metadata.clone());
}
Expand Down Expand Up @@ -923,6 +939,7 @@ async fn push_file(
Value::String(args.if_exists.as_str().to_string()),
);
}
apply_parameter_function_merge_fields(object);
}

function_events.push(event);
Expand Down Expand Up @@ -3144,6 +3161,44 @@ mod tests {
assert_eq!(calculate_upload_counts(3, None), (3, 0));
}

#[test]
fn parameter_function_merge_fields_are_applied() {
let mut object = serde_json::json!({
"function_type": "parameters",
"_is_merge": false,
"_merge_paths": ["old.path"]
})
.as_object()
.expect("object")
.clone();

apply_parameter_function_merge_fields(&mut object);

assert_eq!(object.get("_is_merge"), Some(&Value::Bool(true)));
assert_eq!(
object.get("_merge_paths"),
Some(&serde_json::json!([
["function_data", "__schema"],
["metadata"]
]))
);
}

#[test]
fn merge_fields_are_not_applied_to_non_parameter_functions() {
let mut object = serde_json::json!({
"function_type": "tool"
})
.as_object()
.expect("object")
.clone();

apply_parameter_function_merge_fields(&mut object);

assert!(object.get("_is_merge").is_none());
assert!(object.get("_merge_paths").is_none());
}

#[test]
fn requirements_reference_escape_is_rejected() {
let dir = tempfile::tempdir().expect("tempdir");
Expand Down
Loading