set_status: consolidate whoami into get_agent_meta with optional name
This commit is contained in:
parent
77fdaf0d1e
commit
73871f18c3
10 changed files with 118 additions and 204 deletions
|
|
@ -214,8 +214,17 @@ it as a stdio child via `--mcp-config`. The hyperhive socket name is
|
|||
short pointer. Each agent's pending-reminder count is capped
|
||||
(default 50, override via `HIVE_REMIND_MAX_PENDING_PER_AGENT`);
|
||||
scheduling a new one fails if the cap is already hit.
|
||||
- `whoami()` — `{ name, role, pronouns, hyperhive_rev }` for
|
||||
self-identification without scraping the system prompt.
|
||||
- `set_status(text)` — set a free-text status string visible on
|
||||
the operator dashboard. Persisted to
|
||||
`{state_dir}/hyperhive-status`; survives harness restarts. Pass
|
||||
an empty string to clear.
|
||||
- `get_agent_meta(name?)` — fetch identity + status metadata for
|
||||
an agent: `{ name, role, hyperhive_rev, status_text,
|
||||
status_set_at }`. Pass `name` to query a peer (e.g. check
|
||||
whether a sub-agent is idle before sending it work). Omit
|
||||
`name` to get your own identity stamp — replaces the previous
|
||||
`whoami` tool. Status fields are `None` when the target has
|
||||
never called `set_status` or has cleared it.
|
||||
- `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
|
||||
|
|
@ -314,10 +323,11 @@ meta's.
|
|||
startup crashes, etc.). Pass the plain logical agent name;
|
||||
hive-c0re resolves the machine name (`h-<name>`, manager
|
||||
`hm1nd`). `lines` defaults to 50, host-capped at 500.
|
||||
- `remind` / `get_loose_ends` / `cancel_loose_end` / `whoami` —
|
||||
same as the sub-agent tools above. `get_loose_ends` scopes to
|
||||
the manager's own items by default; pass `agent: "*"` for a
|
||||
hive-wide view, or `agent: "<name>"` to inspect one agent.
|
||||
- `remind` / `get_loose_ends` / `cancel_loose_end` / `set_status`
|
||||
/ `get_agent_meta` — same as the sub-agent tools above.
|
||||
`get_loose_ends` scopes to the manager's own items by default;
|
||||
pass `agent: "*"` for a hive-wide view, or `agent: "<name>"`
|
||||
to inspect one agent.
|
||||
`cancel_loose_end` may cancel any agent's row.
|
||||
|
||||
The boundary: lifecycle ops on *existing* sub-agents
|
||||
|
|
|
|||
|
|
@ -10,9 +10,8 @@ Tools (hyperhive surface):
|
|||
- `mcp__hyperhive__get_loose_ends()` — list your loose ends: unanswered questions where you're asker (waiting on someone) or target (owing a reply), plus reminders you've scheduled that haven't fired. No args, cheap server-side sweep. Useful at turn start to remember what's outstanding without scanning inbox archaeology.
|
||||
- `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. `"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__get_agent_meta(name?)` — fetch identity + status metadata for an agent: canonical `name`, `role` (`agent` / `manager`), current `hyperhive_rev`, plus self-reported `status` text (set via `set_status`) and 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 trustworthy identity stamp — useful 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.
|
||||
- `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.
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ Tools (hyperhive surface):
|
|||
- `mcp__hyperhive__get_loose_ends(agent?)` — loose ends. Omit `agent` for your own: pending approvals you submitted + unanswered questions where you are asker/target + your own pending reminders. Pass `agent: "*"` for a hive-wide sweep — every pending approval, unanswered question, and reminder across the swarm — to find stalled threads (sub-agent A asked B something three days ago and B never answered) before they rot. Pass `agent: "<name>"` to inspect one agent's threads. Cheap server-side query.
|
||||
- `mcp__hyperhive__cancel_loose_end(kind, id)` — cancel any question or reminder in the swarm (manager bypasses the owner check used on sub-agents). Use for hive-wide cleanup when a sub-agent is offline / can't withdraw its own ask / reminder.
|
||||
- `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). Good for deadline follow-ups — "check whether agent X answered the question I relayed". Large payloads auto-spill to a file under `/state/reminders/`; pass `file_path` to control the destination.
|
||||
- `mcp__hyperhive__whoami()` — self-introspection: canonical name (`manager`), role, current hyperhive rev. No args. Useful for boot announcements and cross-agent attribution that won't drift across config reloads.
|
||||
- `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 doing (e.g. `"reviewing argus's #341 proposal"`, `"approving lifecycle changes"`, `"idle"`). Pass an empty string to clear. Persists across harness restarts.
|
||||
- `mcp__hyperhive__get_agent_meta(name?)` — fetch identity + status metadata for an agent: canonical `name`, `role` (`agent` / `manager`), current `hyperhive_rev`, plus the target's self-reported `status` text (set via `set_status`) and how long ago it was set. Pass `name` to check on a sub-agent (idle? still working on the task you assigned?) without scrolling the dashboard. Omit `name` for your own identity stamp — useful for boot announcements, state-file headers, cross-agent attribution that won't drift across config reloads.
|
||||
|
||||
Approval boundary: lifecycle ops on *existing* sub-agents (`kill`, `start`, `restart`) are at your discretion — no operator approval. *Creating* a new agent (two-step: `request_init_config` + `request_apply_commit`) and *changing* any agent's config (`request_apply_commit`) both go through the approval queue. The operator only signs off on changes; you run the day-to-day.
|
||||
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ async fn serve(
|
|||
| AgentResponse::LooseEnds { .. }
|
||||
| AgentResponse::PendingRemindersCount { .. }
|
||||
| AgentResponse::ReminderRollup { .. }
|
||||
| AgentResponse::Whoami { .. },
|
||||
| AgentResponse::AgentMeta { .. },
|
||||
) => {
|
||||
tracing::warn!("recv produced unexpected response kind");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ async fn serve(
|
|||
| ManagerResponse::LooseEnds { .. }
|
||||
| ManagerResponse::PendingRemindersCount { .. }
|
||||
| ManagerResponse::ReminderRollup { .. }
|
||||
| ManagerResponse::Whoami { .. },
|
||||
| ManagerResponse::AgentMeta { .. },
|
||||
) => {
|
||||
tracing::warn!("recv produced unexpected response kind");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -220,16 +220,6 @@ async fn dispatch(req: &AgentRequest, agent: &str, coord: &Arc<Coordinator>) ->
|
|||
},
|
||||
}
|
||||
}
|
||||
AgentRequest::Whoami => {
|
||||
let (status_text, status_set_at) = crate::container_view::read_agent_status(agent);
|
||||
AgentResponse::Whoami {
|
||||
name: agent.to_owned(),
|
||||
role: "agent".to_owned(),
|
||||
hyperhive_rev: crate::auto_update::current_flake_rev(&coord.hyperhive_flake),
|
||||
status_text,
|
||||
status_set_at,
|
||||
}
|
||||
}
|
||||
AgentRequest::SetStatus { text } => {
|
||||
let path = crate::coordinator::Coordinator::agent_notes_dir(agent)
|
||||
.join("hyperhive-status");
|
||||
|
|
@ -255,10 +245,19 @@ async fn dispatch(req: &AgentRequest, agent: &str, coord: &Arc<Coordinator>) ->
|
|||
}
|
||||
}
|
||||
AgentRequest::GetAgentMeta { name } => {
|
||||
let target = name.as_deref().unwrap_or(agent);
|
||||
let (status_text, status_set_at) =
|
||||
crate::container_view::read_agent_status(name);
|
||||
crate::container_view::read_agent_status(target);
|
||||
let role = if target == hive_sh4re::MANAGER_AGENT {
|
||||
"manager"
|
||||
} else {
|
||||
"agent"
|
||||
}
|
||||
.to_owned();
|
||||
AgentResponse::AgentMeta {
|
||||
name: name.clone(),
|
||||
name: target.to_owned(),
|
||||
role,
|
||||
hyperhive_rev: crate::auto_update::current_flake_rev(&coord.hyperhive_flake),
|
||||
status_text,
|
||||
status_set_at,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ fn is_rate_limited(name: &str) -> bool {
|
|||
|
||||
/// Read the agent's free-text status and the Unix timestamp when it was last set
|
||||
/// (derived from the file's mtime). Returns `(None, None)` when the file is absent
|
||||
/// or empty. `pub` so `agent_server` and `manager_server` can populate `Whoami`.
|
||||
/// or empty. `pub` so `agent_server` and `manager_server` can populate `AgentMeta`.
|
||||
pub fn read_agent_status(name: &str) -> (Option<String>, Option<i64>) {
|
||||
let path = Coordinator::agent_notes_dir(name).join("hyperhive-status");
|
||||
let meta = std::fs::metadata(&path).ok();
|
||||
|
|
|
|||
|
|
@ -480,17 +480,6 @@ async fn dispatch(req: &ManagerRequest, coord: &Arc<Coordinator>) -> ManagerResp
|
|||
},
|
||||
}
|
||||
}
|
||||
ManagerRequest::Whoami => {
|
||||
let (status_text, status_set_at) =
|
||||
crate::container_view::read_agent_status(MANAGER_AGENT);
|
||||
ManagerResponse::Whoami {
|
||||
name: MANAGER_AGENT.to_owned(),
|
||||
role: "manager".to_owned(),
|
||||
hyperhive_rev: crate::auto_update::current_flake_rev(&coord.hyperhive_flake),
|
||||
status_text,
|
||||
status_set_at,
|
||||
}
|
||||
}
|
||||
ManagerRequest::SetStatus { text } => {
|
||||
let path = Coordinator::agent_notes_dir(MANAGER_AGENT).join("hyperhive-status");
|
||||
let result = if text.trim().is_empty() {
|
||||
|
|
@ -513,10 +502,14 @@ async fn dispatch(req: &ManagerRequest, coord: &Arc<Coordinator>) -> ManagerResp
|
|||
}
|
||||
}
|
||||
ManagerRequest::GetAgentMeta { name } => {
|
||||
let target = name.as_deref().unwrap_or(MANAGER_AGENT);
|
||||
let (status_text, status_set_at) =
|
||||
crate::container_view::read_agent_status(name);
|
||||
crate::container_view::read_agent_status(target);
|
||||
let role = if target == MANAGER_AGENT { "manager" } else { "agent" }.to_owned();
|
||||
ManagerResponse::AgentMeta {
|
||||
name: name.clone(),
|
||||
name: target.to_owned(),
|
||||
role,
|
||||
hyperhive_rev: crate::auto_update::current_flake_rev(&coord.hyperhive_flake),
|
||||
status_text,
|
||||
status_set_at,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -437,20 +437,23 @@ pub enum AgentRequest {
|
|||
#[serde(default)]
|
||||
since_secs: u64,
|
||||
},
|
||||
/// Self-introspection: who am I, what role, what rev. All values
|
||||
/// derive from coord state (no env access required); useful for
|
||||
/// agents to stamp notes / commits / messages with a trustworthy
|
||||
/// identity after a rename or session-continue boundary where the
|
||||
/// system-prompt-substituted label is no longer reliable.
|
||||
Whoami,
|
||||
/// Set a free-text status string visible on the dashboard. Persisted
|
||||
/// to `{state_dir}/hyperhive-status` so it survives harness restarts.
|
||||
/// Pass an empty string to clear the status.
|
||||
SetStatus { text: String },
|
||||
/// Fetch the current status of another agent by name. Returns
|
||||
/// `AgentResponse::AgentMeta` with the target's status fields.
|
||||
/// If the agent does not exist or has never set a status, fields are `None`.
|
||||
GetAgentMeta { name: String },
|
||||
/// Fetch metadata for an agent: identity (name + role + hyperhive
|
||||
/// rev) and current status. When `name` is `None` the caller's own
|
||||
/// identity is returned (self-introspection — replaces the old
|
||||
/// `Whoami` request). When `name` is `Some`, the target agent's
|
||||
/// status fields are populated but `role`/`hyperhive_rev` reflect
|
||||
/// the responding daemon's view (`role` is best-effort: `"manager"`
|
||||
/// for the manager agent, `"agent"` for everyone else).
|
||||
/// `status_text` / `status_set_at` are `None` when the target has
|
||||
/// never set a status or the agent name is unknown.
|
||||
GetAgentMeta {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
name: Option<String>,
|
||||
},
|
||||
/// Cancel an open thread the agent owns: a `Question` they asked
|
||||
/// (returns `[cancelled by <self>]` as the answer to the asker)
|
||||
/// or a `Reminder` they scheduled (hard-deletes the row).
|
||||
|
|
@ -511,15 +514,15 @@ pub enum AgentResponse {
|
|||
PendingRemindersCount { count: u64 },
|
||||
/// `ReminderRollup` result: reminder activity stats for the agent.
|
||||
ReminderRollup(ReminderStats),
|
||||
/// `Whoami` result: identity + role + the current hyperhive rev
|
||||
/// hive-c0re is running against. `role` is `"agent"` for
|
||||
/// sub-agents (the only path that reaches this variant of the
|
||||
/// response). `hyperhive_rev` is `None` only when the configured
|
||||
/// flake URL has no canonical path. `status_text` is the last
|
||||
/// value written via `SetStatus`, or `None` if none has been set.
|
||||
/// `status_set_at` is a Unix timestamp (seconds since epoch) of
|
||||
/// when the status was last written; `None` when no status is set.
|
||||
Whoami {
|
||||
/// `GetAgentMeta` result: identity + status metadata for an agent.
|
||||
/// `role` is `"agent"` for sub-agents and `"manager"` for the
|
||||
/// manager. `hyperhive_rev` is `None` only when the configured
|
||||
/// flake URL has no canonical path. `status_text` is the last value
|
||||
/// written via `SetStatus`, or `None` when none has been set or the
|
||||
/// agent name is unknown. `status_set_at` is a Unix timestamp
|
||||
/// (seconds since epoch) of when the status was last written;
|
||||
/// `None` when no status is set.
|
||||
AgentMeta {
|
||||
name: String,
|
||||
role: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
|
|
@ -529,16 +532,6 @@ pub enum AgentResponse {
|
|||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
status_set_at: Option<i64>,
|
||||
},
|
||||
/// `GetAgentMeta` result: status metadata for a named agent.
|
||||
/// `status_text` / `status_set_at` are `None` when the agent has
|
||||
/// not set a status or the agent name is unknown.
|
||||
AgentMeta {
|
||||
name: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
status_text: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
status_set_at: Option<i64>,
|
||||
},
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
@ -865,13 +858,15 @@ pub enum ManagerRequest {
|
|||
#[serde(default)]
|
||||
agent: Option<String>,
|
||||
},
|
||||
/// Manager-flavour self-introspection. Same wire shape as
|
||||
/// `AgentRequest::Whoami`, but `role` is always `"manager"`.
|
||||
Whoami,
|
||||
/// Mirror of `AgentRequest::SetStatus` on the manager surface.
|
||||
SetStatus { text: String },
|
||||
/// Mirror of `AgentRequest::GetAgentMeta` on the manager surface.
|
||||
GetAgentMeta { name: String },
|
||||
/// `None` returns the manager's own identity (replaces the old
|
||||
/// `Whoami` request).
|
||||
GetAgentMeta {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
name: Option<String>,
|
||||
},
|
||||
/// Cancel an open thread (question or reminder). Manager surface
|
||||
/// can cancel any row (no owner check) — same dispatch as
|
||||
/// `AgentRequest::CancelLooseEnd` but with privileged auth.
|
||||
|
|
@ -947,9 +942,10 @@ pub enum ManagerResponse {
|
|||
},
|
||||
/// `ReminderRollup` result: reminder activity stats for the manager.
|
||||
ReminderRollup(ReminderStats),
|
||||
/// `Whoami` result: manager identity. `role` is always
|
||||
/// `"manager"`. Mirror of `AgentResponse::Whoami`.
|
||||
Whoami {
|
||||
/// Mirror of `AgentResponse::AgentMeta` on the manager surface.
|
||||
/// `role` is `"manager"` for the manager and `"agent"` for any
|
||||
/// sub-agent looked up by name.
|
||||
AgentMeta {
|
||||
name: String,
|
||||
role: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
|
|
@ -959,12 +955,4 @@ pub enum ManagerResponse {
|
|||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
status_set_at: Option<i64>,
|
||||
},
|
||||
/// Mirror of `AgentResponse::AgentMeta` on the manager surface.
|
||||
AgentMeta {
|
||||
name: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
status_text: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
status_set_at: Option<i64>,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue