feat(#1178): add list_containers tool to AgentServer (topology-scoped to descendants)

This commit is contained in:
damocles 2026-06-03 22:21:01 +02:00 committed by mara
commit 94c2d651c0
4 changed files with 98 additions and 0 deletions

View file

@ -50,6 +50,8 @@ pub enum SocketReply {
/// `list_schedules` result — used by the manager surface only;
/// `AgentResponse` has no equivalent variant.
Schedules(Vec<hive_sh4re::WireSchedule>),
/// `list_containers` result — descendant containers with running status.
Containers(Vec<hive_sh4re::ContainerInfo>),
LooseEnds(Vec<hive_sh4re::LooseEnd>),
PendingRemindersCount(u64),
ReminderRollup(hive_sh4re::ReminderStats),
@ -81,6 +83,7 @@ impl From<hive_sh4re::Response> for SocketReply {
hive_sh4re::Response::Logs { content } => Self::Logs(content),
hive_sh4re::Response::HostJournal { content } => Self::HostJournal(content),
hive_sh4re::Response::Schedules { schedules } => Self::Schedules(schedules),
hive_sh4re::Response::Containers { containers } => Self::Containers(containers),
hive_sh4re::Response::AgentMeta {
name,
running,
@ -1008,6 +1011,45 @@ impl AgentServer {
.await
}
// IMPORTANT: this tool is only available when the `lifecycle` tool group
// is granted to this agent. Returns all topological descendants of the
// calling agent with their running status.
#[tool(
description = "List all containers that are topological descendants of this agent \
(direct children + their subtrees). Requires the `lifecycle` tool group. \
Returns every known descendant regardless of running state check the `running` \
field to distinguish live from stopped containers. Ordered by topology depth \
(parents before children), then alphabetically within each tier."
)]
async fn list_containers(&self) -> String {
run_tool_envelope("list_containers", String::new(), async move {
let (resp, retries) = self
.dispatch(hive_sh4re::AgentRequest::ListDescendants)
.await;
let body = match resp {
Ok(SocketReply::Containers(containers)) => {
if containers.is_empty() {
"no descendant containers".to_owned()
} else {
containers
.iter()
.map(|c| {
let status = if c.running { "running" } else { "stopped" };
format!("{} ({})", c.name, status)
})
.collect::<Vec<_>>()
.join("\n")
}
}
Ok(SocketReply::Err(m)) => format!("list_containers failed: {m}"),
Ok(other) => format!("list_containers unexpected response: {other:?}"),
Err(e) => format!("list_containers transport error: {e:#}"),
};
annotate_retries(body, retries)
})
.await
}
// IMPORTANT: this tool is capability-gated (`read_host_journal`).
// It is added to `--allowedTools` by `allowed_capability_tools` only
// when `HIVE_CAPABILITIES` contains `read_host_journal`. hive-c0re