feat(#792): agent restart tool — topology-checked restart of direct children
This commit is contained in:
parent
7767493428
commit
5a9ede10df
3 changed files with 50 additions and 0 deletions
|
|
@ -42,6 +42,7 @@ Tools (hyperhive surface):
|
||||||
- `mcp__hyperhive__get_agent_meta(name?)` — fetch identity + status metadata for an agent: canonical `name`, `role` (`agent` / `manager`), current `hyperhive_rev`, plus self-reported `status` text (set via `set_status`) and how long ago it was set. Also returns the hive + swarm display names (`hive_name`, `swarm_name`) when the operator has configured `services.hyperhive.{hiveName, swarmName}`; both lines omitted when unset. Pass `name` to query a peer (e.g. check whether iris is idle before pinging them). Omit `name` to get your own trustworthy identity stamp — useful for state files, commit messages, cross-agent attribution that won't drift across renames or session-continue boundaries where the system-prompt label could be stale.
|
- `mcp__hyperhive__get_agent_meta(name?)` — fetch identity + status metadata for an agent: canonical `name`, `role` (`agent` / `manager`), current `hyperhive_rev`, plus self-reported `status` text (set via `set_status`) and how long ago it was set. Also returns the hive + swarm display names (`hive_name`, `swarm_name`) when the operator has configured `services.hyperhive.{hiveName, swarmName}`; both lines omitted when unset. Pass `name` to query a peer (e.g. check whether iris is idle before pinging them). Omit `name` to get your own trustworthy identity stamp — useful for state files, commit messages, cross-agent attribution that won't drift across renames or session-continue boundaries where the system-prompt label could be stale.
|
||||||
<!-- role:agent -->
|
<!-- role:agent -->
|
||||||
- `mcp__hyperhive__request_next_turn()` — ask the harness to start another turn immediately after this one ends, even if the inbox is empty. Use for multi-turn tasks (long builds, sequential steps) where you want to continue without waiting for an external message. The next turn starts with `from: "self"` and `body: "continue"`. No-op if new inbox messages arrive before this turn ends (the harness already loops immediately on pending messages). No args.
|
- `mcp__hyperhive__request_next_turn()` — ask the harness to start another turn immediately after this one ends, even if the inbox is empty. Use for multi-turn tasks (long builds, sequential steps) where you want to continue without waiting for an external message. The next turn starts with `from: "self"` and `body: "continue"`. No-op if new inbox messages arrive before this turn ends (the harness already loops immediately on pending messages). No args.
|
||||||
|
- `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.
|
||||||
|
|
||||||
Need new packages, env vars, or other NixOS config for yourself? You can't edit your own config directly — message the manager (recipient `root`) describing what you need + why. The manager evaluates the request (it doesn't rubber-stamp), edits `/agents/{label}/config/agent.nix` on your behalf, commits, and submits an approval that the operator can accept on the dashboard; on approve hive-c0re rebuilds your container with the new config.
|
Need new packages, env vars, or other NixOS config for yourself? You can't edit your own config directly — message the manager (recipient `root`) describing what you need + why. The manager evaluates the request (it doesn't rubber-stamp), edits `/agents/{label}/config/agent.nix` on your behalf, commits, and submits an approval that the operator can accept on the dashboard; on approve hive-c0re rebuilds your container with the new config.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -895,6 +895,29 @@ impl AgentServer {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IMPORTANT: this tool is only available when the `lifecycle` tool group
|
||||||
|
// is granted to this agent. hive-c0re enforces the topology check
|
||||||
|
// server-side: the call is rejected unless `name` is a direct child.
|
||||||
|
#[tool(
|
||||||
|
description = "Restart a direct child sub-agent container (stop + start). \
|
||||||
|
Only succeeds if `name` is a direct child of this agent in the topology \
|
||||||
|
tree — the server enforces this. No approval required."
|
||||||
|
)]
|
||||||
|
async fn restart(&self, Parameters(args): Parameters<RestartArgs>) -> String {
|
||||||
|
let log = format!("{args:?}");
|
||||||
|
let name = args.name.clone();
|
||||||
|
run_tool_envelope("restart", log, async move {
|
||||||
|
let (resp, retries) = self
|
||||||
|
.dispatch(hive_sh4re::AgentRequest::Restart { name: args.name })
|
||||||
|
.await;
|
||||||
|
annotate_retries(
|
||||||
|
format_ack(resp, "restart", format!("restarted {name}")),
|
||||||
|
retries,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
// IMPORTANT: this tool is capability-gated (`read_host_journal`).
|
// IMPORTANT: this tool is capability-gated (`read_host_journal`).
|
||||||
// It is added to `--allowedTools` by `allowed_capability_tools` only
|
// It is added to `--allowedTools` by `allowed_capability_tools` only
|
||||||
// when `HIVE_CAPABILITIES` contains `read_host_journal`. hive-c0re
|
// when `HIVE_CAPABILITIES` contains `read_host_journal`. hive-c0re
|
||||||
|
|
|
||||||
|
|
@ -361,6 +361,32 @@ async fn dispatch(req: &AgentRequest, agent: &str, coord: &Arc<Coordinator>) ->
|
||||||
Err(message) => AgentResponse::Err { message },
|
Err(message) => AgentResponse::Err { message },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AgentRequest::Restart { name } => {
|
||||||
|
// Topology check: the caller must be the direct parent of the
|
||||||
|
// target. This is the only authorisation criterion — no
|
||||||
|
// capability flag needed; parenthood is sufficient privilege.
|
||||||
|
if !crate::topology::children_of(agent)
|
||||||
|
.iter()
|
||||||
|
.any(|c| c == name)
|
||||||
|
{
|
||||||
|
return AgentResponse::Err {
|
||||||
|
message: format!(
|
||||||
|
"agent `{agent}` cannot restart `{name}`: \
|
||||||
|
not a direct child in the topology tree"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
tracing::info!(%agent, %name, "agent: enqueue restart for child");
|
||||||
|
coord.rebuild_queue.enqueue(
|
||||||
|
crate::rebuild_queue::QueueKind::Restart,
|
||||||
|
name.to_owned(),
|
||||||
|
crate::rebuild_queue::QueueSource::Manual,
|
||||||
|
format!("agent `{agent}` restart tool"),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
coord.emit_rebuild_queue_snapshot();
|
||||||
|
AgentResponse::Ok
|
||||||
|
}
|
||||||
// Manager-only variants are not valid on the agent socket.
|
// Manager-only variants are not valid on the agent socket.
|
||||||
_ => AgentResponse::Err {
|
_ => AgentResponse::Err {
|
||||||
message: "request not supported on agent socket".to_owned(),
|
message: "request not supported on agent socket".to_owned(),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue