Files
boxmaker/docs/plans/M6a/files/crates/loopd/tests/subagent_dispatch.rs
T
2026-10-03 19:39:35 -07:00

58 lines
1.9 KiB
Rust

//! Dispatch of `subagent`: not the port, unknown keys, child ids. Do not edit.
use bxcore::CallId;
use bxcore::SessionId;
use loopd::subagent::{self, SUBAGENT};
use loopd::tools::{Dispatch, Registry, dispatch};
#[test]
fn call_tool_unwraps_subagent_and_does_not_send_it_to_the_port() {
let r = Registry::m5c();
match dispatch(
&r,
"call_tool",
r#"{"name":"subagent","arguments":{"task":"look around"}}"#,
) {
Dispatch::Subagent { task } => assert_eq!(task, "look around"),
other => panic!("{other:?}"),
}
match dispatch(&r, SUBAGENT, r#"{"task":"look around"}"#) {
Dispatch::Subagent { task } => assert_eq!(task, "look around"),
other => panic!("{other:?}"),
}
}
#[test]
fn unknown_keys_and_a_missing_task_are_invalid_arguments() {
let r = Registry::m5c();
let cases = [
(r#"{"task":"x","extra":1}"#, "unknown field: extra"),
(r#"{"text":"x"}"#, "unknown field: text"),
("{}", "task is required"),
(r#"{"task":1}"#, "task must be a string"),
("[]", "arguments must be a JSON object"),
("not json", "arguments must be a JSON object"),
];
for (args, want) in cases {
match dispatch(&r, SUBAGENT, args) {
Dispatch::Local(text) => {
assert!(
text.starts_with("Denied: the arguments are not valid for this tool:"),
"{args}: {text}"
);
assert!(text.contains(want), "{args}: {text}");
}
other => panic!("{args}: {other:?}"),
}
}
}
#[test]
fn a_parent_id_that_cannot_fit_a_child_is_named_in_the_denial() {
let parent = SessionId::new(&"a".repeat(59)).unwrap();
let err = subagent::child_id(&parent, CallId(1)).unwrap_err();
assert!(err.len() > 64, "{err}");
assert!(err.starts_with("sub-"), "{err}");
assert!(subagent::child_id(&SessionId::new("mm-thread").unwrap(), CallId(3)).is_ok());
}