diff --git a/hive-ag3nt/src/mcp.rs b/hive-ag3nt/src/mcp.rs index f9afd86f..21435b21 100644 --- a/hive-ag3nt/src/mcp.rs +++ b/hive-ag3nt/src/mcp.rs @@ -180,6 +180,20 @@ fn write_status_file(text: &str) -> Result<(), String> { result.map_err(|e| format!("set_status write failed: {e}")) } +/// Render the three identical failure arms every data-returning tool handler +/// repeats: a broker `Err` → `"{tool} failed: {m}"`, an unexpected `Ok` variant +/// → `"{tool} unexpected response: …"`, and a transport error → `"{tool} +/// transport error: …"`. Handlers match their own happy-path variant and route +/// everything else here via a catch-all arm (`other => reply_err(other, tool)`), +/// so the triplet lives in exactly one place. +fn reply_err(resp: Result, tool: &str) -> String { + match resp { + Ok(SocketReply::Err(m)) => format!("{tool} failed: {m}"), + Ok(other) => format!("{tool} unexpected response: {other:?}"), + Err(e) => format!("{tool} transport error: {e:#}"), + } +} + /// Format helper for "send-like" tools (anything that expects an `Ok`). /// `tool` and `ok_msg` only appear in the result string; they don't change /// behavior. @@ -187,9 +201,7 @@ fn write_status_file(text: &str) -> Result<(), String> { pub fn format_ack(resp: Result, tool: &str, ok_msg: String) -> String { match resp { Ok(SocketReply::Ok) => ok_msg, - Ok(SocketReply::Err(m)) => format!("{tool} failed: {m}"), - Ok(other) => format!("{tool} unexpected response: {other:?}"), - Err(e) => format!("{tool} transport error: {e:#}"), + other => reply_err(other, tool), } } @@ -205,13 +217,16 @@ pub fn format_ack(resp: Result, tool: &str, ok_msg: /// per-message redelivery banners included. #[must_use] pub fn format_recv(resp: Result, waited: bool) -> String { + match resp { + Ok(SocketReply::Messages(m)) => render_recv_messages(&m, waited), + other => reply_err(other, "recv"), + } +} + +/// Render the popped-message payload of a successful `recv` (see `format_recv` +/// for the empty/single/batch shapes). +fn render_recv_messages(messages: &[hive_sh4re::DeliveredMessage], waited: bool) -> String { use std::fmt::Write as _; - let messages = match resp { - Ok(SocketReply::Messages(m)) => m, - Ok(SocketReply::Err(m)) => return format!("recv failed: {m}"), - Ok(other) => return format!("recv unexpected response: {other:?}"), - Err(e) => return format!("recv transport error: {e:#}"), - }; if messages.is_empty() { return if waited { format!("(empty){IDLE_WAIT_HINT}") @@ -536,9 +551,7 @@ pub fn format_agent_meta(resp: Result) -> String { } out } - 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:#}"), + other => reply_err(other, "get_agent_meta"), } } @@ -761,9 +774,7 @@ impl AgentServer { "question queued (id={id}); answer will arrive as a system \ `question_answered` event in your inbox" ), - Ok(SocketReply::Err(m)) => format!("ask failed: {m}"), - Ok(other) => format!("ask unexpected response: {other:?}"), - Err(e) => format!("ask transport error: {e:#}"), + other => reply_err(other, "ask"), }; annotate_retries(s, retries) }) @@ -850,9 +861,7 @@ impl AgentServer { Ok(SocketReply::Acked(count)) => { format!("acked {count} message(s) up to id {}", args.up_to) } - Ok(SocketReply::Err(m)) => format!("ack_until failed: {m}"), - Ok(other) => format!("ack_until unexpected response: {other:?}"), - Err(e) => format!("ack_until transport error: {e:#}"), + other => reply_err(other, "ack_until"), }; annotate_retries(rendered, retries) }) @@ -883,21 +892,7 @@ impl AgentServer { // Extract the vec so we can augment before rendering. let mut loose_ends = match resp { Ok(SocketReply::LooseEnds(t)) => t, - Ok(SocketReply::Err(m)) => { - return annotate_retries(format!("get_loose_ends failed: {m}"), retries); - } - Ok(other) => { - return annotate_retries( - format!("get_loose_ends unexpected response: {other:?}"), - retries, - ); - } - Err(e) => { - return annotate_retries( - format!("get_loose_ends transport error: {e:#}"), - retries, - ); - } + 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). @@ -1039,9 +1034,7 @@ impl AgentServer { full_name, clone_url, }) => format!("created repo {full_name} — clone: {clone_url}"), - Ok(SocketReply::Err(m)) => format!("create_repo failed: {m}"), - Ok(other) => format!("create_repo unexpected response: {other:?}"), - Err(e) => format!("create_repo transport error: {e:#}"), + other => reply_err(other, "create_repo"), }; annotate_retries(s, retries) }) @@ -1212,9 +1205,7 @@ impl AgentServer { .join("\n") } } - Ok(SocketReply::Err(m)) => format!("list_containers failed: {m}"), - Ok(other) => format!("list_containers unexpected response: {other:?}"), - Err(e) => format!("list_containers transport error: {e:#}"), + other => reply_err(other, "list_containers"), }; annotate_retries(body, retries) }) @@ -1255,9 +1246,7 @@ impl AgentServer { .await; let result = match resp { Ok(SocketReply::HostJournal(content)) => content, - Ok(SocketReply::Err(m)) => format!("get_host_journal failed: {m}"), - Ok(other) => format!("get_host_journal unexpected response: {other:?}"), - Err(e) => format!("get_host_journal transport error: {e:#}"), + other => reply_err(other, "get_host_journal"), }; annotate_retries(result, retries) }) @@ -1388,9 +1377,7 @@ impl AgentServer { content } } - Ok(SocketReply::Err(m)) => format!("get_logs failed: {m}"), - Ok(other) => format!("get_logs unexpected response: {other:?}"), - Err(e) => format!("get_logs transport error: {e:#}"), + other => reply_err(other, "get_logs"), }; annotate_retries(s, retries) }) @@ -1578,9 +1565,7 @@ impl AgentServer { let body = match resp { Ok(SocketReply::Schedules(schedules)) => serde_json::to_string(&schedules) .unwrap_or_else(|e| format!("list_schedules: serialise: {e:#}")), - Ok(SocketReply::Err(m)) => format!("list_schedules: {m}"), - Ok(other) => format!("list_schedules unexpected response: {other:?}"), - Err(e) => format!("list_schedules transport error: {e:#}"), + other => reply_err(other, "list_schedules"), }; annotate_retries(body, retries) })