From 441fe201363624ca054b90ef66cba7fb9c4921e4 Mon Sep 17 00:00:00 2001 From: John Huang Date: Mon, 1 Jun 2026 15:52:53 -0700 Subject: [PATCH 1/4] merge parameters, don't override saved values --- src/functions/push.rs | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/functions/push.rs b/src/functions/push.rs index ebc1f28..51e4724 100644 --- a/src/functions/push.rs +++ b/src/functions/push.rs @@ -47,6 +47,8 @@ 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"]; // 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. @@ -725,6 +727,23 @@ fn build_code_function_data( }) } +fn apply_parameter_function_merge_fields(object: &mut Map) { + 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(), + Value::Array(vec![Value::Array( + PARAMETER_SCHEMA_MERGE_PATH + .iter() + .map(|component| Value::String((*component).to_string())) + .collect(), + )]), + ); +} + #[allow(clippy::too_many_arguments)] async fn push_file( auth_ctx: &super::AuthContext, @@ -846,6 +865,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()); } @@ -923,6 +943,7 @@ async fn push_file( Value::String(args.if_exists.as_str().to_string()), ); } + apply_parameter_function_merge_fields(object); } function_events.push(event); @@ -3144,6 +3165,41 @@ 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"]])) + ); + } + + #[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"); From bb79d039734b9e666d2cfecce1ca8c1768bc1a31 Mon Sep 17 00:00:00 2001 From: John Huang Date: Wed, 3 Jun 2026 21:04:22 -0700 Subject: [PATCH 2/4] don't merge metadata --- src/functions/push.rs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/functions/push.rs b/src/functions/push.rs index 51e4724..7c0d616 100644 --- a/src/functions/push.rs +++ b/src/functions/push.rs @@ -49,6 +49,7 @@ 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. @@ -735,12 +736,21 @@ fn apply_parameter_function_merge_fields(object: &mut Map) { object.insert("_is_merge".to_string(), Value::Bool(true)); object.insert( "_merge_paths".to_string(), - Value::Array(vec![Value::Array( - PARAMETER_SCHEMA_MERGE_PATH - .iter() - .map(|component| Value::String((*component).to_string())) - .collect(), - )]), + Value::Array( + [ + PARAMETER_SCHEMA_MERGE_PATH.as_slice(), + PARAMETER_METADATA_MERGE_PATH.as_slice(), + ] + .into_iter() + .map(|path| { + Value::Array( + path.iter() + .map(|component| Value::String((*component).to_string())) + .collect(), + ) + }) + .collect(), + ), ); } @@ -3181,7 +3191,10 @@ mod tests { assert_eq!(object.get("_is_merge"), Some(&Value::Bool(true))); assert_eq!( object.get("_merge_paths"), - Some(&serde_json::json!([["function_data", "__schema"]])) + Some(&serde_json::json!([ + ["function_data", "__schema"], + ["metadata"] + ])) ); } From 61dee86982d471e82e0c771f3a917bdf726be1bf Mon Sep 17 00:00:00 2001 From: john Date: Thu, 4 Jun 2026 09:52:36 -0700 Subject: [PATCH 3/4] fix test Co-authored-by: Abhijeet Prasad --- src/functions/push.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functions/push.rs b/src/functions/push.rs index 7c0d616..5177b0d 100644 --- a/src/functions/push.rs +++ b/src/functions/push.rs @@ -3179,7 +3179,7 @@ mod tests { fn parameter_function_merge_fields_are_applied() { let mut object = serde_json::json!({ "function_type": "parameters", - "is_merge": false, + "_is_merge": false, "_merge_paths": ["old.path"] }) .as_object() From 0a92c3a2577280fdd83fd46e22beed1313db8171 Mon Sep 17 00:00:00 2001 From: John Huang Date: Thu, 4 Jun 2026 10:01:23 -0700 Subject: [PATCH 4/4] json macro --- src/functions/push.rs | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/functions/push.rs b/src/functions/push.rs index 5177b0d..9515442 100644 --- a/src/functions/push.rs +++ b/src/functions/push.rs @@ -736,21 +736,7 @@ fn apply_parameter_function_merge_fields(object: &mut Map) { object.insert("_is_merge".to_string(), Value::Bool(true)); object.insert( "_merge_paths".to_string(), - Value::Array( - [ - PARAMETER_SCHEMA_MERGE_PATH.as_slice(), - PARAMETER_METADATA_MERGE_PATH.as_slice(), - ] - .into_iter() - .map(|path| { - Value::Array( - path.iter() - .map(|component| Value::String((*component).to_string())) - .collect(), - ) - }) - .collect(), - ), + json!([PARAMETER_SCHEMA_MERGE_PATH, PARAMETER_METADATA_MERGE_PATH]), ); }