mcp: remove the restart/kill/start/update/get_logs agent verbs
Container lifecycle from inside an agent goes away: an agent no longer starts, stops, restarts or rebuilds a container in its subtree, and no longer reads another container's journal. Those are operator actions — the dashboard and hivectl keep their own paths to the same job-queue and hive-priv plumbing, which is why none of that machinery is removed here, only the five MCP verbs and what they alone reached. What went with them: the `Request` variants and `Response::Logs` on the agent socket, the five tool definitions and their arg structs, the four lifecycle handlers plus `handle_get_logs`, and `require_descendant` — the topology guard those five were the only remaining callers of. `ToolGroup::Diagnostics` goes too: `get_logs` was its only tool, so it would otherwise be a grantable group that grants nothing. `lifecycle` stays, now carrying `list_containers` alone. An agent that gets a `needs_update` or `container_crash` helper event has no remedy of its own left, so the system prompt and the docs now send it to the operator instead of to a tool that no longer exists. Refs #4480
This commit is contained in:
parent
c5f60fd58f
commit
87970a8c93
17 changed files with 48 additions and 450 deletions
|
|
@ -94,15 +94,9 @@ pub struct CompactArgs {
|
|||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Privileged tool arg types (lifecycle, approvals, scheduling, diagnostics)
|
||||
// Privileged tool arg types (lifecycle, approvals, scheduling)
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
|
||||
pub struct KillArgs {
|
||||
/// Sub-agent name (without the `h-` container prefix).
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
|
||||
pub struct SetStatusArgs {
|
||||
/// Status text to display on the dashboard card. Pass an empty string to clear.
|
||||
|
|
@ -125,24 +119,6 @@ pub struct GetAgentMetaArgs {
|
|||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
|
||||
pub struct StartArgs {
|
||||
/// Sub-agent name (without the `h-` container prefix).
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
|
||||
pub struct RestartArgs {
|
||||
/// Sub-agent name (without the `h-` container prefix).
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
|
||||
pub struct UpdateArgs {
|
||||
/// Sub-agent name (without the `h-` container prefix).
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
|
||||
pub struct CancelLooseEndArgs {
|
||||
/// Which kind of thread to cancel — `"reminder"` for a scheduled
|
||||
|
|
@ -265,17 +241,6 @@ pub struct EditScheduleArgs {
|
|||
pub targets_remove: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
|
||||
pub struct GetLogsArgs {
|
||||
/// Logical agent name to fetch logs for (e.g. `gui`, `iris`).
|
||||
/// hive-c0re maps it to the underlying machine name (`h-gui`)
|
||||
/// itself — pass the plain agent name, not the `h-` form.
|
||||
pub agent: String,
|
||||
/// How many journal lines to return (default: 50, max: 500).
|
||||
#[serde(default)]
|
||||
pub lines: Option<u32>,
|
||||
}
|
||||
|
||||
/// Arguments for `get_host_journal` (capability-gated: `read_host_journal`).
|
||||
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
|
||||
pub struct GetHostJournalArgs {
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ mod render;
|
|||
pub use args::{
|
||||
AckUntilArgs, AgentGetLooseEndsArgs, CancelLooseEndArgs, CancelScheduleArgs, CompactArgs,
|
||||
CreateRepoArgs, EditScheduleArgs, FireScheduleNowArgs, GetAgentMetaArgs, GetHostJournalArgs,
|
||||
GetLogsArgs, KillArgs, MarkTodosDoneArgs, RecvArgs, RemindArgs, RequestSchedulePromptArgs,
|
||||
RestartArgs, SendArgs, SetStatusArgs, StartArgs, UpdateArgs, UpdateMetaInputsArgs,
|
||||
MarkTodosDoneArgs, RecvArgs, RemindArgs, RequestSchedulePromptArgs, SendArgs, SetStatusArgs,
|
||||
UpdateMetaInputsArgs,
|
||||
};
|
||||
pub use render::{annotate_retries, format_ack, format_agent_meta, format_recv};
|
||||
|
||||
|
|
@ -557,78 +557,6 @@ impl AgentServer {
|
|||
.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 in the caller's
|
||||
// subtree.
|
||||
#[tool(
|
||||
description = "Restart a sub-agent container (stop + start). Only succeeds if `name` \
|
||||
is somewhere in this agent's subtree — a child, a child's child, and so on down \
|
||||
the topology tree — which the server enforces. 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_core_agent_sock::Request::Restart { name: args.name })
|
||||
.await;
|
||||
annotate_retries(
|
||||
format_ack(resp, "restart", format!("restarted {name}")),
|
||||
retries,
|
||||
)
|
||||
})
|
||||
.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 in the caller's
|
||||
// subtree.
|
||||
#[tool(
|
||||
description = "Stop a sub-agent container (graceful). Only succeeds if `name` \
|
||||
is somewhere in this agent's subtree — a child, a child's child, and so on down \
|
||||
the topology tree — which the server enforces. No approval required. \
|
||||
State dir is kept; recreating the agent reuses prior config + credentials."
|
||||
)]
|
||||
async fn kill(&self, Parameters(args): Parameters<KillArgs>) -> String {
|
||||
let log = format!("{args:?}");
|
||||
let name = args.name.clone();
|
||||
run_tool_envelope("kill", log, async move {
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_core_agent_sock::Request::Kill { name: args.name })
|
||||
.await;
|
||||
annotate_retries(format_ack(resp, "kill", format!("killed {name}")), retries)
|
||||
})
|
||||
.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 in the caller's
|
||||
// subtree.
|
||||
#[tool(
|
||||
description = "Rebuild a sub-agent: re-applies the current hyperhive flake + agent.nix \
|
||||
and restarts the container. Only succeeds if `name` is somewhere in this agent's \
|
||||
subtree — a child, a child's child, and so on down the topology tree — which the \
|
||||
server enforces. No approval required. Idempotent — use when an agent needs its \
|
||||
config reapplied."
|
||||
)]
|
||||
async fn update(&self, Parameters(args): Parameters<UpdateArgs>) -> String {
|
||||
let log = format!("{args:?}");
|
||||
let name = args.name.clone();
|
||||
run_tool_envelope("update", log, async move {
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_core_agent_sock::Request::Update { name: args.name })
|
||||
.await;
|
||||
annotate_retries(
|
||||
format_ack(resp, "update", format!("updated {name}")),
|
||||
retries,
|
||||
)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
// IMPORTANT: this tool is only available when the `lifecycle` tool group
|
||||
// is granted to this agent. Returns the calling agent's whole subtree,
|
||||
// itself included, with running status.
|
||||
|
|
@ -709,70 +637,13 @@ impl AgentServer {
|
|||
.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 in the caller's
|
||||
// subtree.
|
||||
#[tool(
|
||||
description = "Start a stopped sub-agent container. Only succeeds if `name` \
|
||||
is somewhere in this agent's subtree — a child, a child's child, and so on down \
|
||||
the topology tree — which the server enforces. No approval required."
|
||||
)]
|
||||
async fn start(&self, Parameters(args): Parameters<StartArgs>) -> String {
|
||||
let log = format!("{args:?}");
|
||||
let name = args.name.clone();
|
||||
run_tool_envelope("start", log, async move {
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_core_agent_sock::Request::Start { name: args.name })
|
||||
.await;
|
||||
annotate_retries(
|
||||
format_ack(resp, "start", format!("started {name}")),
|
||||
retries,
|
||||
)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
#[tool(
|
||||
description = "Fetch recent journal log lines for a sub-agent container. Useful \
|
||||
for diagnosing MCP server registration failures, startup crashes, plugin install \
|
||||
errors, or any harness issue you can't see from inside the container. Pass the \
|
||||
plain logical agent name (e.g. `gui`) — hive-c0re resolves the machine name. \
|
||||
`lines` defaults to 50 (max capped at 500 on the host side)."
|
||||
)]
|
||||
async fn get_logs(&self, Parameters(args): Parameters<GetLogsArgs>) -> String {
|
||||
let log = format!("{args:?}");
|
||||
let agent = args.agent.clone();
|
||||
run_tool_envelope("get_logs", log, async move {
|
||||
let lines = args.lines.map(|n| n.min(500));
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_core_agent_sock::Request::GetLogs {
|
||||
agent: agent.clone(),
|
||||
lines,
|
||||
})
|
||||
.await;
|
||||
let s = match resp {
|
||||
Ok(hive_core_agent_sock::Response::Logs { content }) => {
|
||||
if content.is_empty() {
|
||||
format!("(no journal output for {agent})")
|
||||
} else {
|
||||
content
|
||||
}
|
||||
}
|
||||
other => reply_err(other, "get_logs"),
|
||||
};
|
||||
annotate_retries(s, retries)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
#[tool(
|
||||
description = "Queue an approval for the operator to run `nix flake update` on the \
|
||||
meta flake and commit the resulting lock changes. Pass specific input names to update \
|
||||
only those inputs (e.g. `[\"bitburner-agent\"]`), or pass an empty list to update ALL \
|
||||
inputs. Returns immediately — the lock update runs when the operator approves. \
|
||||
Does NOT trigger container rebuilds — call `update` on each affected agent \
|
||||
separately after the approval resolves."
|
||||
Does NOT trigger container rebuilds — the operator rebuilds affected agents \
|
||||
after the approval resolves."
|
||||
)]
|
||||
async fn request_update_meta_inputs(
|
||||
&self,
|
||||
|
|
|
|||
Loading…
Reference in a new issue