set_status: add get_agent_meta tool for inter-agent status queries

This commit is contained in:
damocles 2026-05-23 01:25:34 +02:00 committed by Mara
parent 8e8e8a771f
commit 77fdaf0d1e
5 changed files with 153 additions and 2 deletions

View file

@ -11,7 +11,8 @@ Tools (hyperhive surface):
- `mcp__hyperhive__cancel_loose_end(kind, id)` — cancel one of your own open threads. `kind` is `"question"` (the asker — you, in this case — gets a `[cancelled by <you>]` answer so the waiter unblocks) or `"reminder"` (hard-deleted before it fires). `id` from the matching `get_loose_ends` row or the original submission reply.
- `mcp__hyperhive__remind(message, delay_seconds? | at_unix_timestamp?, file_path?)` — schedule a message to land in your *own* inbox at a future time (sender shows as `reminder`). Set exactly one of `delay_seconds` (relative) or `at_unix_timestamp` (absolute). Use for self-paced follow-ups instead of blocking a whole turn on a long `recv` wait. A large `message` auto-spills to a file under `/agents/{label}/state/reminders/`; pass `file_path` to point at one yourself. Each agent's pending-reminder count is capped (default 50) — the tool will error if the cap is already reached.
- `mcp__hyperhive__whoami()` — self-introspection: returns your canonical agent name (from socket identity, not the prompt-substituted label), role, and current hyperhive rev. No args. Use it when you want a trustworthy identity stamp for state files, commit messages, or cross-agent attribution that won't drift across renames or session-continue boundaries where the system-prompt label could be stale.
- `mcp__hyperhive__set_status(text)` — set a free-text status visible on the operator dashboard. **Call this at the start of every task** to say what you're working on (e.g. `"reviewing PR #42"`, `"fixing #319 model priority"`, `"idle"`). Pass an empty string to clear. Persists across harness restarts.
- `mcp__hyperhive__set_status(text)` — set a free-text status visible on the operator dashboard. **Call this at the start of every task** to say what you're working on (e.g. `"processing matrix messages"`, `"fixing #319 model priority"`, `"idle"`). Pass an empty string to clear. Persists across harness restarts.
- `mcp__hyperhive__get_agent_meta(name)` — fetch another agent's current status (set via `set_status`). Returns their status text and how long ago it was set. Useful for checking whether a peer is idle before sending a request.
- `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.
Need new packages, env vars, or other NixOS config for yourself? You can't edit your own config directly — message the manager (recipient `manager`) 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.

View file

@ -56,6 +56,11 @@ pub enum SocketReply {
status_text: Option<String>,
status_set_at: Option<i64>,
},
AgentMeta {
name: String,
status_text: Option<String>,
status_set_at: Option<i64>,
},
}
impl From<hive_sh4re::AgentResponse> for SocketReply {
@ -85,6 +90,15 @@ impl From<hive_sh4re::AgentResponse> for SocketReply {
status_text,
status_set_at,
},
hive_sh4re::AgentResponse::AgentMeta {
name,
status_text,
status_set_at,
} => Self::AgentMeta {
name,
status_text,
status_set_at,
},
}
}
}
@ -117,6 +131,15 @@ impl From<hive_sh4re::ManagerResponse> for SocketReply {
status_text,
status_set_at,
},
hive_sh4re::ManagerResponse::AgentMeta {
name,
status_text,
status_set_at,
} => Self::AgentMeta {
name,
status_text,
status_set_at,
},
}
}
}
@ -305,6 +328,40 @@ pub fn format_whoami(resp: Result<SocketReply, anyhow::Error>) -> String {
}
}
/// Format the result of a `get_agent_meta` call.
#[must_use]
pub fn format_agent_meta(resp: Result<SocketReply, anyhow::Error>) -> String {
match resp {
Ok(SocketReply::AgentMeta {
name,
status_text,
status_set_at,
}) => {
let status = match status_text {
None => "no status set".to_owned(),
Some(s) => {
let age = status_set_at.and_then(|ts| {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.ok()?
.as_secs();
let secs = now.saturating_sub(ts as u64);
Some(format_age_secs(secs))
});
match age {
Some(a) => format!("{s} (set {a} ago)"),
None => s,
}
}
};
format!("agent: {name}\nstatus: {status}")
}
Ok(SocketReply::Err(m)) => format!("get_agent_meta failed: {m}"),
Ok(other) => format!("get_agent_meta unexpected response: {other:?}"),
Err(e) => format!("get_agent_meta transport error: {e:#}"),
}
}
/// Format a duration in seconds as a human-readable age string.
fn format_age_secs(secs: u64) -> String {
if secs < 60 {
@ -607,7 +664,7 @@ impl AgentServer {
#[tool(
description = "Set a free-text status string visible on the operator dashboard. \
Call this at the START of every task to describe what you're working on (e.g. \
`\"reviewing PR #42\"`, `\"fixing bitburner crash\"`, `\"idle\"`). Pass an empty \
`\"processing matrix messages\"`, `\"fixing bitburner crash\"`, `\"idle\"`). Pass an empty \
string to clear. The status is shown on your dashboard card and persists across \
harness restarts."
)]
@ -620,6 +677,28 @@ impl AgentServer {
.await
}
#[tool(
description = "Fetch the current status of another agent by name. Returns the \
agent's self-reported status text (set via `set_status`) and how long ago it \
was set. Useful for checking whether a peer is idle before sending a request, \
or for the manager to get a quick overview of what each agent is doing. \
Returns `no status set` when the agent has never called `set_status` or has \
cleared it."
)]
async fn get_agent_meta(
&self,
Parameters(args): Parameters<GetAgentMetaArgs>,
) -> String {
let log = args.name.clone();
run_tool_envelope("get_agent_meta", log, async move {
let (resp, retries) = self
.dispatch(hive_sh4re::AgentRequest::GetAgentMeta { name: args.name })
.await;
annotate_retries(format_agent_meta(resp), retries)
})
.await
}
#[tool(
description = "Cancel an open thread you own — a `question` you asked (the \
asker gets `[cancelled by <you>]` as the answer and unblocks) or a `reminder` \
@ -786,6 +865,12 @@ pub struct SetStatusArgs {
pub text: String,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct GetAgentMetaArgs {
/// Logical name of the agent to query (e.g. `"iris"`, `"manager"`).
pub name: String,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct StartArgs {
/// Sub-agent name (without the `h-` container prefix).
@ -1335,6 +1420,27 @@ impl ManagerServer {
.await
}
#[tool(
description = "Fetch the current status of another agent by name. Returns the \
agent's self-reported status text (set via `set_status`) and how long ago it \
was set. Useful for the manager to get a quick overview of what each agent is \
doing without querying the dashboard. Returns `no status set` when the agent \
has never called `set_status` or has cleared it."
)]
async fn get_agent_meta(
&self,
Parameters(args): Parameters<GetAgentMetaArgs>,
) -> String {
let log = args.name.clone();
run_tool_envelope("get_agent_meta", log, async move {
let (resp, retries) = self
.dispatch(hive_sh4re::ManagerRequest::GetAgentMeta { name: args.name })
.await;
annotate_retries(format_agent_meta(resp), retries)
})
.await
}
#[tool(
description = "Cancel any open thread in the swarm — a `question` (cancels \
with the operator-override sentinel so the asker unblocks) or a `reminder` \
@ -1455,6 +1561,7 @@ pub fn allowed_mcp_tools(flavor: Flavor) -> Vec<String> {
"get_loose_ends",
"whoami",
"set_status",
"get_agent_meta",
"cancel_loose_end",
],
Flavor::Manager => &[
@ -1474,6 +1581,7 @@ pub fn allowed_mcp_tools(flavor: Flavor) -> Vec<String> {
"remind",
"whoami",
"set_status",
"get_agent_meta",
"cancel_loose_end",
],
};