use super::agent::{build_agent_markdown_named, to_yaml, AgentFrontmatter};
use super::gate::{authored_description, gate_grants_write, resolve_render_gate};
use super::support::DRIVER_TOOLS;
use super::types::{ContextInjection, RenderFlavor};
use crate::error::DispatchError;
use crate::ir::ComponentNode;
use crate::models::ModelConfig;
use crate::provider::ToolMap;
use crate::resolve::ResolutionReport;
use crate::targets::CONTEXT_ISOLATION_CAPABILITY;
pub(super) fn should_isolate(node: &ComponentNode) -> bool {
node.required_capabilities
.iter()
.any(|c| c == CONTEXT_ISOLATION_CAPABILITY)
}
pub(super) fn isolated_agent_name(verb: &str) -> String {
format!("{verb}__isolated")
}
pub(super) fn build_isolating_parent_markdown(
node: &ComponentNode,
report: &ResolutionReport,
flavor: RenderFlavor,
models: &ModelConfig,
) -> Result<String, DispatchError> {
let gate = resolve_render_gate(node, report, flavor);
let mut tools: Vec<String> = DRIVER_TOOLS.iter().map(|s| s.to_string()).collect();
if gate_grants_write(&gate) {
tools.push("Write".to_string());
}
let child = isolated_agent_name(&node.verb);
let frontmatter = AgentFrontmatter {
name: node.verb.clone(),
description: authored_description(node).unwrap_or_else(|| {
format!(
"{} entry point that delegates all of {}'s work to an isolated subagent (outcome: {}).",
node.component_type.as_str(),
node.verb,
node.effect.outcome.kind.as_str()
)
}),
tools,
model: Some(models.orchestrator()?.to_string()),
};
Ok([
"---".to_string(),
to_yaml(&frontmatter),
"---".to_string(),
String::new(),
format!(
"Hand the user's question to the `{child}` subagent with the Task tool, in one call, \
and report what it returns."
),
String::new(),
"That subagent does the entire job — working out what is being asked, querying, and \
repairing anything that fails. You do none of it, and you have no tools to do it with."
.to_string(),
String::new(),
"Report its final result and nothing else. Do not narrate the delegation, do not summarize \
what it did to get there, and do not restate any query, model name or error it may mention along \
the way. If it reports a derivation, keep that in the result's own `definition` block rather than \
folding it into the answer text."
.to_string(),
String::new(),
"If it comes back with a question for the user rather than an answer, pass that question \
through as it stands."
.to_string(),
String::new(),
]
.join("\n"))
}
#[allow(clippy::too_many_arguments)]
pub(super) fn build_isolated_child_markdown(
node: &ComponentNode,
report: &ResolutionReport,
flavor: RenderFlavor,
models: &ModelConfig,
context: &ContextInjection,
tool_map: &ToolMap,
include_setup_recovery_tool: bool,
include_dashboard_save_tool: bool,
) -> Result<String, DispatchError> {
build_agent_markdown_named(
&isolated_agent_name(&node.verb),
node,
report,
flavor,
models,
context,
tool_map,
include_setup_recovery_tool,
include_dashboard_save_tool,
)
}