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

@ -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",
],
};