set_status: consolidate whoami into get_agent_meta with optional name

This commit is contained in:
damocles 2026-05-23 10:57:27 +02:00 committed by Mara
parent 77fdaf0d1e
commit 73871f18c3
10 changed files with 118 additions and 204 deletions

View file

@ -194,7 +194,7 @@ async fn serve(
| AgentResponse::LooseEnds { .. }
| AgentResponse::PendingRemindersCount { .. }
| AgentResponse::ReminderRollup { .. }
| AgentResponse::Whoami { .. },
| AgentResponse::AgentMeta { .. },
) => {
tracing::warn!("recv produced unexpected response kind");
}

View file

@ -160,7 +160,7 @@ async fn serve(
| ManagerResponse::LooseEnds { .. }
| ManagerResponse::PendingRemindersCount { .. }
| ManagerResponse::ReminderRollup { .. }
| ManagerResponse::Whoami { .. },
| ManagerResponse::AgentMeta { .. },
) => {
tracing::warn!("recv produced unexpected response kind");
}

View file

@ -49,18 +49,13 @@ pub enum SocketReply {
LooseEnds(Vec<hive_sh4re::LooseEnd>),
PendingRemindersCount(u64),
ReminderRollup(hive_sh4re::ReminderStats),
Whoami {
AgentMeta {
name: String,
role: String,
hyperhive_rev: Option<String>,
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 {
@ -77,25 +72,16 @@ impl From<hive_sh4re::AgentResponse> for SocketReply {
Self::PendingRemindersCount(count)
}
hive_sh4re::AgentResponse::ReminderRollup(stats) => Self::ReminderRollup(stats),
hive_sh4re::AgentResponse::Whoami {
name,
role,
hyperhive_rev,
status_text,
status_set_at,
} => Self::Whoami {
name,
role,
hyperhive_rev,
status_text,
status_set_at,
},
hive_sh4re::AgentResponse::AgentMeta {
name,
role,
hyperhive_rev,
status_text,
status_set_at,
} => Self::AgentMeta {
name,
role,
hyperhive_rev,
status_text,
status_set_at,
},
@ -118,25 +104,16 @@ impl From<hive_sh4re::ManagerResponse> for SocketReply {
Self::PendingRemindersCount(count)
}
hive_sh4re::ManagerResponse::ReminderRollup(stats) => Self::ReminderRollup(stats),
hive_sh4re::ManagerResponse::Whoami {
name,
role,
hyperhive_rev,
status_text,
status_set_at,
} => Self::Whoami {
name,
role,
hyperhive_rev,
status_text,
status_set_at,
},
hive_sh4re::ManagerResponse::AgentMeta {
name,
role,
hyperhive_rev,
status_text,
status_set_at,
} => Self::AgentMeta {
name,
role,
hyperhive_rev,
status_text,
status_set_at,
},
@ -292,13 +269,14 @@ fn loose_end_kind_label(kind: hive_sh4re::CancelLooseEndKind) -> &'static str {
}
}
/// Format helper for `whoami`: renders the identity block as a short
/// human-readable string. Skips fields that are `None` so the output
/// doesn't carry dead placeholders.
/// Format helper for `get_agent_meta`: renders an agent's identity +
/// current status as a short human-readable block. `name`, `role`, and
/// `hyperhive_rev` are always shown; `status` only appears when one is
/// set, otherwise the line reads `status: <none>`.
#[must_use]
pub fn format_whoami(resp: Result<SocketReply, anyhow::Error>) -> String {
pub fn format_agent_meta(resp: Result<SocketReply, anyhow::Error>) -> String {
match resp {
Ok(SocketReply::Whoami {
Ok(SocketReply::AgentMeta {
name,
role,
hyperhive_rev,
@ -307,38 +285,8 @@ pub fn format_whoami(resp: Result<SocketReply, anyhow::Error>) -> String {
}) => {
let rev = hyperhive_rev.as_deref().unwrap_or("<unknown>");
let mut out = format!("name: {name}\nrole: {role}\nhyperhive_rev: {rev}");
if let Some(s) = status_text {
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))
});
if let Some(a) = age {
out.push_str(&format!("\nstatus: {s} (set {a} ago)"));
} else {
out.push_str(&format!("\nstatus: {s}"));
}
}
out
}
Ok(SocketReply::Err(m)) => format!("whoami failed: {m}"),
Ok(other) => format!("whoami unexpected response: {other:?}"),
Err(e) => format!("whoami transport error: {e:#}"),
}
}
/// 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(),
match status_text {
None => out.push_str("\nstatus: <none>"),
Some(s) => {
let age = status_set_at.and_then(|ts| {
let now = std::time::SystemTime::now()
@ -349,12 +297,12 @@ pub fn format_agent_meta(resp: Result<SocketReply, anyhow::Error>) -> String {
Some(format_age_secs(secs))
});
match age {
Some(a) => format!("{s} (set {a} ago)"),
None => s,
Some(a) => out.push_str(&format!("\nstatus: {s} (set {a} ago)")),
None => out.push_str(&format!("\nstatus: {s}")),
}
}
};
format!("agent: {name}\nstatus: {status}")
}
out
}
Ok(SocketReply::Err(m)) => format!("get_agent_meta failed: {m}"),
Ok(other) => format!("get_agent_meta unexpected response: {other:?}"),
@ -644,23 +592,6 @@ impl AgentServer {
.await
}
#[tool(
description = "Self-introspection: returns your own canonical agent name (the \
socket-identity name, NOT the prompt-substituted label), role (`agent`), and \
the current hyperhive rev hive-c0re is running against. Also returns the \
current `status` text if one has been set via `set_status`. No args. Useful \
when you want a trustworthy identity stamp 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."
)]
async fn whoami(&self) -> String {
run_tool_envelope("whoami", String::new(), async move {
let (resp, retries) = self.dispatch(hive_sh4re::AgentRequest::Whoami).await;
annotate_retries(format_whoami(resp), retries)
})
.await
}
#[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. \
@ -678,18 +609,21 @@ impl AgentServer {
}
#[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."
description = "Fetch identity + status metadata for an agent. Returns canonical \
`name`, `role` (`agent` / `manager`), the current `hyperhive_rev` hive-c0re is \
running against, and the target's self-reported `status` text (set via \
`set_status`) plus how long ago it was set. Pass `name` to query a peer (e.g. \
check whether iris is idle before pinging them); omit `name` to get your own \
identity stamp handy 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. Status reads `<none>` when the \
target 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();
let log = args.name.clone().unwrap_or_else(|| "<self>".to_owned());
run_tool_envelope("get_agent_meta", log, async move {
let (resp, retries) = self
.dispatch(hive_sh4re::AgentRequest::GetAgentMeta { name: args.name })
@ -868,7 +802,10 @@ pub struct SetStatusArgs {
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct GetAgentMetaArgs {
/// Logical name of the agent to query (e.g. `"iris"`, `"manager"`).
pub name: String,
/// Omit to query your own identity + status — replaces the
/// previous `whoami` self-introspection tool.
#[serde(default)]
pub name: Option<String>,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
@ -1391,21 +1328,6 @@ impl ManagerServer {
.await
}
#[tool(
description = "Self-introspection for the manager: returns canonical name \
(`manager`), role (`manager`), and the current hyperhive rev. Also returns \
the current `status` text if one has been set via `set_status`. Same shape as \
the agent flavour; useful for cross-agent attribution / boot announcements / \
state-file headers without trusting prompt substitution."
)]
async fn whoami(&self) -> String {
run_tool_envelope("whoami", String::new(), async move {
let (resp, retries) = self.dispatch(hive_sh4re::ManagerRequest::Whoami).await;
annotate_retries(format_whoami(resp), retries)
})
.await
}
#[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. \
@ -1421,17 +1343,20 @@ impl ManagerServer {
}
#[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."
description = "Fetch identity + status metadata for an agent. Returns canonical \
`name`, `role` (`agent` / `manager`), the current `hyperhive_rev` hive-c0re is \
running against, and the target's self-reported `status` text (set via \
`set_status`) plus how long ago it was set. Pass `name` to query a sub-agent or \
peer manager; omit `name` for the manager's own identity stamp useful for \
boot announcements, state-file headers, or cross-agent attribution that won't \
drift across renames. Status reads `<none>` when the target 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();
let log = args.name.clone().unwrap_or_else(|| "<self>".to_owned());
run_tool_envelope("get_agent_meta", log, async move {
let (resp, retries) = self
.dispatch(hive_sh4re::ManagerRequest::GetAgentMeta { name: args.name })
@ -1516,8 +1441,9 @@ impl ManagerServer {
`answer` (respond to a `question_asked` event directed at you), \
`get_loose_ends` (hive-wide loose ends pending approvals + unanswered \
questions + pending reminders across the swarm), `cancel_loose_end` (cancel any \
question or reminder row by id), `whoami` (self-introspection canonical \
name, role, current hyperhive rev). The manager's own config lives at \
question or reminder row by id), `set_status` / `get_agent_meta` (publish your \
own status text + query identity/status of any agent `get_agent_meta` with \
no arg replaces the old `whoami` self-introspection). The manager's own config lives at \
`/agents/hm1nd/config/agent.nix`."
)]
impl ServerHandler for ManagerServer {}
@ -1559,7 +1485,6 @@ pub fn allowed_mcp_tools(flavor: Flavor) -> Vec<String> {
"answer",
"remind",
"get_loose_ends",
"whoami",
"set_status",
"get_agent_meta",
"cancel_loose_end",
@ -1579,7 +1504,6 @@ pub fn allowed_mcp_tools(flavor: Flavor) -> Vec<String> {
"get_logs",
"get_loose_ends",
"remind",
"whoami",
"set_status",
"get_agent_meta",
"cancel_loose_end",