From e8d101d663019217422db0123a8d37a38985ff0e Mon Sep 17 00:00:00 2001 From: damocles Date: Wed, 22 Jul 2026 21:05:15 +0200 Subject: [PATCH] repoint remind/cancel_loose_end/get_loose_ends to the local reminder socket (#2635 inc 1) --- hive-agent-mcp/src/mcp/mod.rs | 58 +++++++++++++++++++++++++------- hive-agent-mcp/src/mcp/render.rs | 16 +++++++-- 2 files changed, 59 insertions(+), 15 deletions(-) diff --git a/hive-agent-mcp/src/mcp/mod.rs b/hive-agent-mcp/src/mcp/mod.rs index 0ca18172..3a4616c0 100644 --- a/hive-agent-mcp/src/mcp/mod.rs +++ b/hive-agent-mcp/src/mcp/mod.rs @@ -35,8 +35,9 @@ pub use args::{ pub use render::{annotate_retries, format_ack, format_agent_meta, format_recv}; use render::{ - format_matrix_summary, local_todos, loose_end_kind_label, mark_local_todo_done, - matrix_unread_summary, parse_loose_end_kind, render_loose_ends, reply_err, + dial_agent_socket, format_matrix_summary, local_reminders, local_todos, loose_end_kind_label, + mark_local_todo_done, matrix_unread_summary, parse_loose_end_kind, render_loose_ends, + reply_err, }; /// Write (or remove) the status file in the agent's own `state/` directory. @@ -343,6 +344,12 @@ impl AgentServer { if is_self_query && let Some(todos) = local_todos().await { loose_ends.extend(todos); } + // Merge local pending reminders (#2635 inc 1 — 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 { + loose_ends.extend(reminders); + } annotate_retries(render_loose_ends(&loose_ends), retries) }) .await @@ -446,6 +453,26 @@ impl AgentServer { Err(e) => return e, }; let kind_label = loose_end_kind_label(kind); + // Reminders are harness-local (#2635 inc 1) — dial the in-agent + // socket directly instead of the broker; every other kind + // (question/approval) still lives in c0re. + if kind == hive_sh4re::CancelLooseEndKind::Reminder { + return match dial_agent_socket(&hive_agent_sock::Request::CancelReminder { id }) + .await + { + Some(hive_agent_sock::Response::Acked { count }) if count > 0 => { + format!("cancelled {kind_label} {id}") + } + Some(hive_agent_sock::Response::Acked { .. }) => { + format!("cancel_loose_end failed: no pending {kind_label} {id}") + } + Some(hive_agent_sock::Response::Err { message }) => { + format!("cancel_loose_end failed: {message}") + } + Some(other) => format!("cancel_loose_end unexpected response: {other:?}"), + None => "cancel_loose_end failed: in-agent socket unavailable".to_owned(), + }; + } let (resp, retries) = self .dispatch(hive_core_agent_sock::Request::CancelLooseEnd { kind, id }) .await; @@ -516,17 +543,22 @@ impl AgentServer { (Some(s), None) => hive_sh4re::ReminderTiming::InSeconds { seconds: s }, (None, Some(t)) => hive_sh4re::ReminderTiming::At { unix_timestamp: t }, }; - let (resp, retries) = self - .dispatch(hive_core_agent_sock::Request::Remind { - message: args.message, - timing, - file_path: args.file_path, - }) - .await; - annotate_retries( - format_ack(resp, "remind", "reminder scheduled".to_string()), - retries, - ) + // Reminders are harness-local (#2635 inc 1) — dial the in-agent + // socket directly instead of the broker. + match dial_agent_socket(&hive_agent_sock::Request::StoreReminder { + message: args.message, + timing, + file_path: args.file_path, + }) + .await + { + Some(hive_agent_sock::Response::Ok) => "reminder scheduled".to_owned(), + Some(hive_agent_sock::Response::Err { message }) => { + format!("remind failed: {message}") + } + Some(other) => format!("remind unexpected response: {other:?}"), + None => "remind failed: in-agent socket unavailable".to_owned(), + } }) .await } diff --git a/hive-agent-mcp/src/mcp/render.rs b/hive-agent-mcp/src/mcp/render.rs index 8402c995..7217b873 100644 --- a/hive-agent-mcp/src/mcp/render.rs +++ b/hive-agent-mcp/src/mcp/render.rs @@ -304,8 +304,10 @@ pub(super) async fn matrix_unread_summary() -> Option> { /// best-effort, single-shot (no retry, unlike the broker's /// `client::request_retried`): this socket lives in the SAME container, so /// a connect failure means the harness itself isn't up, which a retry -/// won't fix within a tool call's budget. Shared by [`local_todos`] and -/// [`mark_local_todo_done`]. +/// won't fix within a tool call's budget. Shared by [`local_todos`], +/// [`mark_local_todo_done`], and [`local_reminders`]; `remind`/ +/// `cancel_loose_end`(reminder) in `mod.rs` dial it directly since their +/// happy path is a plain `Ok`/`Err`, not a `Vec` to merge. pub(super) async fn dial_agent_socket( req: &hive_agent_sock::Request, ) -> Option { @@ -335,6 +337,16 @@ pub(super) async fn local_todos() -> Option> { } } +/// Query the harness's in-agent socket for this agent's local pending +/// reminders (#2635 inc 1 — was a broker query before reminders moved +/// in-container). Same best-effort contract as [`local_todos`]. +pub(super) async fn local_reminders() -> Option> { + match dial_agent_socket(&hive_agent_sock::Request::ListReminders).await? { + hive_agent_sock::Response::LooseEnds { loose_ends } => Some(loose_ends), + _ => None, + } +} + /// Mark one of this agent's local todos (loose-ends v2) done by id, via /// the harness's in-agent socket — reachable through `cancel_loose_end` /// kind `"todo"` so clearing a todo never has to shell out through a