From 25ce5b7239157820e7837cff8b42c4bf4e50c2b3 Mon Sep 17 00:00:00 2001 From: Cyrus Gray <144336577+graycyrus@users.noreply.github.com> Date: Tue, 7 Jul 2026 22:38:32 +0530 Subject: [PATCH] fix(flows): default require_approval to false in the builder (B3) (#4651) --- src/openhuman/flows/builder_tools.rs | 4 +-- src/openhuman/flows/builder_tools_tests.rs | 34 ++++++++++++++++++++++ src/openhuman/flows/tools.rs | 4 +-- src/openhuman/flows/tools_tests.rs | 18 ++++++++++-- 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/openhuman/flows/builder_tools.rs b/src/openhuman/flows/builder_tools.rs index 4c1ec8210..f5d93d16d 100644 --- a/src/openhuman/flows/builder_tools.rs +++ b/src/openhuman/flows/builder_tools.rs @@ -114,7 +114,7 @@ impl Tool for ReviseWorkflowTool { }, "require_approval": { "type": "boolean", - "description": "Force a human-approval gate on every outbound action once saved. Defaults to true for agent-proposed flows." + "description": "Force a human-approval gate on every outbound action once saved. Defaults to false; set true only when the user explicitly asks for an approval step." } }, "required": ["name", "graph"] @@ -146,7 +146,7 @@ impl Tool for ReviseWorkflowTool { let require_approval = args .get("require_approval") .and_then(Value::as_bool) - .unwrap_or(true); + .unwrap_or(false); tracing::debug!( target: "flows", diff --git a/src/openhuman/flows/builder_tools_tests.rs b/src/openhuman/flows/builder_tools_tests.rs index 39dc64b3f..c00f5857c 100644 --- a/src/openhuman/flows/builder_tools_tests.rs +++ b/src/openhuman/flows/builder_tools_tests.rs @@ -57,6 +57,40 @@ async fn revise_workflow_validates_and_returns_revision_proposal() { assert_eq!(parsed["graph"]["nodes"].as_array().unwrap().len(), 2); } +#[tokio::test] +async fn revise_workflow_omitted_require_approval_defaults_false() { + let tmp = TempDir::new().unwrap(); + let tool = ReviseWorkflowTool::new(test_config(&tmp)); + + let result = tool + .execute(json!({ "name": "Revised flow", "graph": valid_graph() })) + .await + .unwrap(); + + assert!(!result.is_error, "{}", result.output()); + let parsed: Value = serde_json::from_str(&result.output()).unwrap(); + assert_eq!(parsed["require_approval"], false); +} + +#[tokio::test] +async fn revise_workflow_explicit_require_approval_true_is_respected() { + let tmp = TempDir::new().unwrap(); + let tool = ReviseWorkflowTool::new(test_config(&tmp)); + + let result = tool + .execute(json!({ + "name": "Revised flow", + "graph": valid_graph(), + "require_approval": true + })) + .await + .unwrap(); + + assert!(!result.is_error, "{}", result.output()); + let parsed: Value = serde_json::from_str(&result.output()).unwrap(); + assert_eq!(parsed["require_approval"], true); +} + #[tokio::test] async fn revise_workflow_rejects_invalid_graph() { let tmp = TempDir::new().unwrap(); diff --git a/src/openhuman/flows/tools.rs b/src/openhuman/flows/tools.rs index 2272dc433..147a310ef 100644 --- a/src/openhuman/flows/tools.rs +++ b/src/openhuman/flows/tools.rs @@ -120,7 +120,7 @@ impl Tool for ProposeWorkflowTool { }, "require_approval": { "type": "boolean", - "description": "Force a human-approval gate on every outbound tool/HTTP action this flow takes once saved. Defaults to true for agent-proposed flows." + "description": "Force a human-approval gate on every outbound tool/HTTP action this flow takes once saved. Defaults to false; set true only when the user explicitly asks for an approval step." } }, "required": ["name", "graph"] @@ -152,7 +152,7 @@ impl Tool for ProposeWorkflowTool { let require_approval = args .get("require_approval") .and_then(Value::as_bool) - .unwrap_or(true); + .unwrap_or(false); tracing::debug!( target: "flows", diff --git a/src/openhuman/flows/tools_tests.rs b/src/openhuman/flows/tools_tests.rs index 88c0e6c78..f928708d0 100644 --- a/src/openhuman/flows/tools_tests.rs +++ b/src/openhuman/flows/tools_tests.rs @@ -112,7 +112,7 @@ async fn missing_graph_is_an_error() { } #[tokio::test] -async fn omitted_require_approval_defaults_true_in_result() { +async fn omitted_require_approval_defaults_false_in_result() { let tmp = TempDir::new().unwrap(); let tool = ProposeWorkflowTool::new(test_config(&tmp)); @@ -122,7 +122,7 @@ async fn omitted_require_approval_defaults_true_in_result() { .unwrap(); let parsed: Value = serde_json::from_str(&result.output()).unwrap(); - assert_eq!(parsed["require_approval"], true); + assert_eq!(parsed["require_approval"], false); } #[tokio::test] @@ -139,6 +139,20 @@ async fn explicit_require_approval_false_is_respected() { assert_eq!(parsed["require_approval"], false); } +#[tokio::test] +async fn explicit_require_approval_true_is_respected() { + let tmp = TempDir::new().unwrap(); + let tool = ProposeWorkflowTool::new(test_config(&tmp)); + + let result = tool + .execute(json!({ "name": "demo", "graph": valid_graph(), "require_approval": true })) + .await + .unwrap(); + + let parsed: Value = serde_json::from_str(&result.output()).unwrap(); + assert_eq!(parsed["require_approval"], true); +} + #[tokio::test] async fn summary_step_count_and_kinds_are_correct() { let tmp = TempDir::new().unwrap();