use std::sync::Arc;
use uuid::Uuid;
use crate::brain::tools::registry::ToolRegistry;
use crate::brain::tools::subagent::build_child_registry;
use crate::brain::tools::tool_search::ToolSearchTool;
use crate::brain::tools::r#trait::ToolExecutionContext;
fn parent_with_tool_search() -> Arc<ToolRegistry> {
let registry = Arc::new(ToolRegistry::new());
crate::cli::tool_setup::register_runtime_tools(®istry, &crate::config::Config::default());
registry.register(Arc::new(ToolSearchTool::new(®istry)));
registry
}
#[test]
fn test_a_child_registry_is_freed_when_its_last_owner_drops() {
let parent = parent_with_tool_search();
let watch = {
let child = build_child_registry(&parent);
assert!(
child.get("tool_search").is_some(),
"precondition: the child carries a re-bound tool_search"
);
Arc::downgrade(&child)
};
assert!(
watch.upgrade().is_none(),
"#1210: the child registry outlived its owner — the re-bound \
tool_search is holding it alive"
);
}
#[tokio::test]
async fn test_an_unbound_search_tool_writes_to_the_wrong_registry() {
let parent = parent_with_tool_search();
let child = Arc::new(ToolRegistry::new());
for name in parent.list_tools() {
if let Some(tool) = parent.get(&name) {
child.register(tool); }
}
let child_session = Uuid::new_v4();
let query = child
.list_tools()
.into_iter()
.find(|n| n != "tool_search")
.expect("something to find");
let search = child.get("tool_search").expect("copied from the parent");
let result = search
.execute(
serde_json::json!({ "query": query }),
&ToolExecutionContext::new(child_session),
)
.await
.expect("tool_search executes");
assert!(result.success, "{:?}", result.error);
assert!(
child.active_tools(child_session).is_empty(),
"#1210: this is the bug — the child's request builder reads this, and \
it stayed empty"
);
assert!(
!parent.active_tools(child_session).is_empty(),
"#1210: ...because the activation landed in the parent, keyed by the \
child's session id"
);
}