two-step agent spawn: request_init_config + request_spawn

This commit is contained in:
damocles 2026-05-20 14:32:54 +02:00 committed by Mara
parent 42437f9c6a
commit 80dd5bb69e
7 changed files with 165 additions and 14 deletions

View file

@ -655,6 +655,19 @@ pub async fn serve_manager_stdio(socket: PathBuf) -> Result<()> {
// Manager tool surface
// -----------------------------------------------------------------------------
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct RequestInitConfigArgs {
/// New sub-agent name (≤9 chars). Queues an InitConfig approval; on
/// approval hive-c0re seeds the proposed config repo at
/// `/agents/<name>/config/agent.nix` with the default template.
/// After the approval the manager can edit and commit the config before
/// calling `request_spawn`.
pub name: String,
/// Optional description shown on the dashboard approval card.
#[serde(default)]
pub description: Option<String>,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct RequestSpawnArgs {
/// New sub-agent name (≤9 chars). Queues a Spawn approval; the
@ -842,8 +855,43 @@ impl ManagerServer {
}
#[tool(
description = "Queue a Spawn approval for a brand-new sub-agent. The operator \
approves on the dashboard before the container is actually created."
description = "Step 1 of 2 for creating a new agent: initialise the proposed config \
repo and queue an InitConfig approval. On operator approval hive-c0re seeds \
`/agents/<name>/config/agent.nix` with the default template so the manager can \
customise it before spawning. After the ConfigReady helper event arrives, edit \
agent.nix, commit the changes, then call `request_spawn`. Fails if a config repo \
for this name already exists (use `request_apply_commit` to update an existing agent)."
)]
async fn request_init_config(
&self,
Parameters(args): Parameters<RequestInitConfigArgs>,
) -> String {
let log = format!("{args:?}");
let name = args.name.clone();
run_tool_envelope("request_init_config", log, async move {
let (resp, retries) = self
.dispatch(hive_sh4re::ManagerRequest::RequestInitConfig {
name: args.name,
description: args.description,
})
.await;
annotate_retries(
format_ack(
resp,
"request_init_config",
format!("init_config approval queued for {name}"),
),
retries,
)
})
.await
}
#[tool(
description = "Step 2 of 2 for creating a new agent: queue a Spawn approval after \
the config has been initialised and customised via `request_init_config`. Requires \
a prior approved InitConfig so the manager can review and edit agent.nix first. \
Fails if no proposed config repo exists for the given name."
)]
async fn request_spawn(&self, Parameters(args): Parameters<RequestSpawnArgs>) -> String {
let log = format!("{args:?}");
@ -1177,8 +1225,9 @@ impl ManagerServer {
#[tool_handler(
instructions = "You are the hyperhive manager (hm1nd). You coordinate sub-agents and \
relay between them and the operator. Use `send` to talk to agents/operator, `recv` \
to drain your inbox. Privileged: `request_spawn` (new agent, gated on operator \
approval), `kill` (graceful stop), `request_apply_commit` (config change for \
to drain your inbox. Privileged: `request_init_config` + `request_spawn` (two-step \
new agent creation - init config first, customise agent.nix, then spawn, both \
gated on operator approval), `kill` (graceful stop), `request_apply_commit` (config change for \
any agent including yourself), `ask` (structured question to the operator or a \
sub-agent non-blocking, answer arrives later as a `question_answered` event), \
`answer` (respond to a `question_asked` event directed at you), \
@ -1233,6 +1282,7 @@ pub fn allowed_mcp_tools(flavor: Flavor) -> Vec<String> {
Flavor::Manager => &[
"send",
"recv",
"request_init_config",
"request_spawn",
"kill",
"start",