use super::*;
#[test]
fn subagents_schema_bounds_tasks_and_concurrency() {
let definitions = mvp_tool_definitions_json();
let parallel = definitions
.as_array()
.unwrap()
.iter()
.find(|definition| definition["name"] == "subagents")
.unwrap();
let tasks = ¶llel["parameters"]["properties"]["tasks"];
assert_eq!(tasks["minItems"], 1);
assert_eq!(tasks["maxItems"], 10);
assert_eq!(
parallel["parameters"]["properties"]["concurrency"]["minimum"],
1
);
assert_eq!(
parallel["parameters"]["properties"]["concurrency"]["maximum"],
4
);
let task_properties = &tasks["items"]["properties"];
assert_eq!(tasks["items"]["required"], json!(["intent"]));
assert!(task_properties.get("identity").is_some());
assert!(
parallel["description"]
.as_str()
.unwrap()
.contains("identity")
);
assert!(
task_properties["agent"]["description"]
.as_str()
.unwrap()
.contains("not the same as identity")
);
}
#[test]
fn subagents_accepts_missing_identity_before_dispatch() {
let (_temp, runtime) = runtime();
let captured_arguments = Arc::new(Mutex::new(None));
let captured_by_runner = Arc::clone(&captured_arguments);
let runtime = runtime.with_subagents(move |arguments, _context| {
*captured_by_runner.lock().unwrap() = Some(arguments);
ToolResult {
tool_name: "subagents".to_string(),
success: true,
content: "runner called".to_string(),
metadata: json!({}),
display: crate::tools::ToolResultDisplay::default(),
}
});
let result = runtime.dispatch(
"subagents",
json!({"tasks":[{"intent":"inspect"}],"concurrency":1}),
);
assert!(result.success, "{}", result.content);
assert_eq!(result.content, "runner called");
let arguments = captured_arguments
.lock()
.unwrap()
.clone()
.expect("runner should receive validated arguments");
let task = &arguments["tasks"][0];
assert_eq!(task["intent"], "inspect");
assert!(
task.get("identity").is_none(),
"missing identity must stay omitted before dispatch: {arguments}"
);
}
#[test]
fn subagents_accepts_optional_identity_and_rejects_invalid_identity() {
let (_temp, runtime) = runtime();
let valid = runtime.dispatch(
"subagents",
json!({"tasks":[{"intent":"inspect","identity":"frontend-dev_1"}],"concurrency":1}),
);
assert!(!valid.success);
assert!(
valid.content.contains("runtime is not configured"),
"{}",
valid.content
);
for identity in ["../frontend", " frontend-dev", "frontend-dev "] {
let invalid = runtime.dispatch(
"subagents",
json!({"tasks":[{"intent":"inspect","identity":identity}],"concurrency":1}),
);
assert!(!invalid.success);
assert!(
invalid.content.contains("identity id"),
"identity {identity:?}: {}",
invalid.content
);
}
}
#[test]
fn subagents_rejects_whitespace_identity_before_dispatch() {
let (_temp, runtime) = runtime();
let runtime = runtime.with_subagents(|_arguments, _context| ToolResult {
tool_name: "subagents".to_string(),
success: true,
content: "runner called".to_string(),
metadata: json!({}),
display: crate::tools::ToolResultDisplay::default(),
});
let result = runtime.dispatch(
"subagents",
json!({"tasks":[{"intent":"inspect","identity":" frontend-dev"}],"concurrency":1}),
);
assert!(!result.success);
assert!(result.content.contains("identity id"), "{}", result.content);
assert_ne!(result.content, "runner called");
}