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

@ -45,6 +45,7 @@ Tools (hyperhive surface):
- `mcp__hyperhive__restart(name)`*(requires `lifecycle` tool group)* restart a direct child sub-agent (stop + start). The server enforces topology: the call is rejected unless `name` is a direct child of yours per `topology.json`. No approval required.
- `mcp__hyperhive__kill(name)`*(requires `lifecycle` tool group)* stop a direct child sub-agent (graceful). Direct children only — server enforces topology. State dir kept; recreating reuses prior config + credentials. No approval required.
- `mcp__hyperhive__update(name)`*(requires `lifecycle` tool group)* rebuild a direct child sub-agent: re-applies the current hyperhive flake + agent.nix and restarts it. Direct children only — server enforces topology. No approval required. Idempotent.
- `mcp__hyperhive__list_containers()`*(requires `lifecycle` tool group)* list all containers that are topological descendants of this agent (children + their subtrees). Returns each name with running/stopped status, ordered parents-first. Useful before kill/update/restart to check what's under you.
- `mcp__hyperhive__request_init_config(name, description?)`*(requires `approvals` tool group)* initialise a brand-new direct child agent's proposed config repo. Queues an `InitConfig` approval; on approval hive-c0re seeds `/agents/<name>/config/agent.nix`. `name` must be a direct child in the topology tree — server enforces. Fails if the config repo already exists (use `request_apply_commit` instead).
- `mcp__hyperhive__request_apply_commit(agent, commit_ref, description?)`*(requires `approvals` tool group)* submit a config commit for a direct child agent, queued for operator approval. `agent` must be a direct child in the topology tree — server enforces. `commit_ref` must be a 7-40 char hex sha (not a branch/tag name). On approval hive-c0re rebuilds the container with the pinned commit.

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