hive-agent-mcp, hive-c0re, hive-sh4re: drop agent param from get_loose_ends

get_loose_ends now always returns the caller's own loose ends, for every
caller including the manager (ruth) — there is no separate manager
surface, ruth is a normal agent with different default capabilities.

- AgentGetLooseEndsArgs removed; get_loose_ends takes no args.
- Wire Request::GetLooseEnds collapses from an Option<String> target to
  a unit variant.
- hive-c0re's handle_get_loose_ends drops the "*" hive-wide branch and
  the subtree/capability resolver (resolve_agent_state_target); both
  are gone since there is no longer a target to resolve.
- loose_ends::hive_wide and Capability::QueryAgentState removed as
  dead code — their only callers were the two functions above.
- is_descendant_of is untouched (still used by lifecycle_handlers.rs
  and schedules.rs independently of this change).
- Docs updated: docs/turn-loop/mcp.md, docs/web-ui/dashboard.md,
  docs/process/conventions.md (Loose-ends wire shape + capabilities
  table), plus the doc comments in hive-core-agent-sock, mcp_config.rs
  and capabilities.rs that described the old shape.

Refs #4480
This commit is contained in:
atlas 2026-09-19 20:08:08 +02:00 committed by mara
commit 729c5b4f42
12 changed files with 41 additions and 178 deletions

View file

@ -131,19 +131,6 @@ pub struct CancelLooseEndArgs {
pub id: i64,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct AgentGetLooseEndsArgs {
/// Whose loose ends to list. Omit (or `null`) for your own. You may
/// also pass the name of any agent in your subtree — a child, a child's
/// child, and so on down — without any extra capability.
/// Pass any other agent name to inspect their threads — requires the
/// `query_agent_state` capability; without it the request is rejected
/// with an error. The `"*"` hive-wide value is not available on the
/// agent socket.
#[serde(default)]
pub agent: Option<String>,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct UpdateMetaInputsArgs {
/// Flake input names to update (e.g. `["bitburner-agent", "nixpkgs"]`).

View file

@ -24,7 +24,7 @@ mod args;
mod render;
pub use args::{
AckUntilArgs, AgentGetLooseEndsArgs, CancelLooseEndArgs, CancelScheduleArgs, CompactArgs,
AckUntilArgs, CancelLooseEndArgs, CancelScheduleArgs, CompactArgs,
CreateRepoArgs, EditScheduleArgs, FireScheduleNowArgs, GetAgentMetaArgs, GetHostJournalArgs,
MarkTodosDoneArgs, RecvArgs, RemindArgs, RequestSchedulePromptArgs, SendArgs, SetStatusArgs,
UpdateMetaInputsArgs,
@ -248,25 +248,20 @@ impl AgentServer {
the same row on its own regardless of whether you marked it done while it was \
still running, so doing that buys nothing and just costs a redundant call later. \
Todos cap at 40 rows; a trailer line says how many more are pending mark the \
reviewed ones done with `mark_todos_done`, then call again for the rest.\n\
Pass `agent: \"<name>\"` to inspect a specific peer agent's threads. Direct \
child agents are always accessible. For non-children, the `query_agent_state` \
capability is required without it the request is rejected with an error."
reviewed ones done with `mark_todos_done`, then call again for the rest."
)]
async fn get_loose_ends(&self, Parameters(args): Parameters<AgentGetLooseEndsArgs>) -> String {
async fn get_loose_ends(&self) -> String {
run_tool_envelope("get_loose_ends", String::new(), async move {
let is_self_query = args.agent.is_none();
let (resp, retries) = self
.dispatch(hive_core_agent_sock::Request::GetLooseEnds { agent: args.agent })
.dispatch(hive_core_agent_sock::Request::GetLooseEnds)
.await;
// Extract the vec so we can augment before rendering.
let mut loose_ends = match resp {
Ok(hive_core_agent_sock::Response::LooseEnds { loose_ends }) => loose_ends,
other => return annotate_retries(reply_err(other, "get_loose_ends"), retries),
};
// Prepend matrix unread entry for self-queries only (can't
// reach another agent's matrix daemon from here).
if is_self_query && let Some(unread_rooms) = matrix_unread_summary().await {
// Prepend matrix unread entry.
if let Some(unread_rooms) = matrix_unread_summary().await {
let total = u32::try_from(unread_rooms.len()).unwrap_or(u32::MAX);
if total > 0 {
let summary = format_matrix_summary(&unread_rooms);
@ -279,16 +274,12 @@ impl AgentServer {
);
}
}
// Merge the harness's local todos (loose-ends v2) for self-queries.
// The harness owns the todo store in-container; another agent's
// todos aren't reachable from here (same as matrix above).
if is_self_query && let Some(todos) = local_todos().await {
// Merge the harness's local todos (loose-ends v2).
if let Some(todos) = local_todos().await {
loose_ends.extend(todos);
}
// Merge local pending reminders — same self-query-only
// restriction: a manager asking for a child's loose-ends no longer
// sees the child's reminders, matching the todos precedent above).
if is_self_query && let Some(reminders) = local_reminders().await {
// Merge local pending reminders.
if let Some(reminders) = local_reminders().await {
loose_ends.extend(reminders);
}
annotate_retries(render_loose_ends(&loose_ends), retries)