refactor(#2581): carve per-agent mcp.sock protocol into hive-agent-sock crate
This commit is contained in:
parent
f64ab47de0
commit
d0beec8a40
26 changed files with 603 additions and 542 deletions
|
|
@ -123,9 +123,9 @@ impl AgentServer {
|
|||
/// (hive-sh4re type aliases), so this single method covers both sockets.
|
||||
async fn dispatch(
|
||||
&self,
|
||||
req: hive_sh4re::Request,
|
||||
) -> (Result<hive_sh4re::Response, anyhow::Error>, u32) {
|
||||
match client::request_retried::<_, hive_sh4re::Response>(&self.socket, &req).await {
|
||||
req: hive_agent_sock::Request,
|
||||
) -> (Result<hive_agent_sock::Response, anyhow::Error>, u32) {
|
||||
match client::request_retried::<_, hive_agent_sock::Response>(&self.socket, &req).await {
|
||||
Ok((r, n)) => (Ok(r), n),
|
||||
Err(e) => (Err(e), 0),
|
||||
}
|
||||
|
|
@ -152,7 +152,7 @@ impl AgentServer {
|
|||
}
|
||||
run_tool_envelope("send", log, async move {
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::Send {
|
||||
.dispatch(hive_agent_sock::Request::Send {
|
||||
to: args.to,
|
||||
body: args.body,
|
||||
in_reply_to: args.in_reply_to,
|
||||
|
|
@ -183,7 +183,7 @@ impl AgentServer {
|
|||
let log = format!("{args:?}");
|
||||
run_tool_envelope("ask", log, async move {
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::Ask {
|
||||
.dispatch(hive_agent_sock::Request::Ask {
|
||||
question: args.question,
|
||||
options: args.options,
|
||||
multi: args.multi,
|
||||
|
|
@ -192,7 +192,7 @@ impl AgentServer {
|
|||
})
|
||||
.await;
|
||||
let s = match resp {
|
||||
Ok(hive_sh4re::Response::QuestionQueued { id }) => format!(
|
||||
Ok(hive_agent_sock::Response::QuestionQueued { id }) => format!(
|
||||
"question queued (id={id}); answer will arrive as a system \
|
||||
`question_answered` event in your inbox"
|
||||
),
|
||||
|
|
@ -217,7 +217,7 @@ impl AgentServer {
|
|||
let id = args.id;
|
||||
run_tool_envelope("answer", log, async move {
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::Answer {
|
||||
.dispatch(hive_agent_sock::Request::Answer {
|
||||
id,
|
||||
answer: args.answer,
|
||||
})
|
||||
|
|
@ -255,7 +255,7 @@ impl AgentServer {
|
|||
run_tool_envelope("recv", log, async move {
|
||||
let waited = args.wait_seconds.is_some_and(|w| w > 0);
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::Recv {
|
||||
.dispatch(hive_agent_sock::Request::Recv {
|
||||
wait_seconds: args.wait_seconds,
|
||||
max: args.max,
|
||||
})
|
||||
|
|
@ -280,10 +280,10 @@ impl AgentServer {
|
|||
let log = format!("{args:?}");
|
||||
run_tool_envelope("ack_until", log, async move {
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::AckUntil { up_to: args.up_to })
|
||||
.dispatch(hive_agent_sock::Request::AckUntil { up_to: args.up_to })
|
||||
.await;
|
||||
let rendered = match resp {
|
||||
Ok(hive_sh4re::Response::Acked { count }) => {
|
||||
Ok(hive_agent_sock::Response::Acked { count }) => {
|
||||
format!("acked {count} message(s) up to id {}", args.up_to)
|
||||
}
|
||||
other => reply_err(other, "ack_until"),
|
||||
|
|
@ -312,11 +312,11 @@ impl AgentServer {
|
|||
run_tool_envelope("get_loose_ends", String::new(), async move {
|
||||
let is_self_query = args.agent.is_none();
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::GetLooseEnds { agent: args.agent })
|
||||
.dispatch(hive_agent_sock::Request::GetLooseEnds { agent: args.agent })
|
||||
.await;
|
||||
// Extract the vec so we can augment before rendering.
|
||||
let mut loose_ends = match resp {
|
||||
Ok(hive_sh4re::Response::LooseEnds { loose_ends }) => loose_ends,
|
||||
Ok(hive_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
|
||||
|
|
@ -365,7 +365,7 @@ impl AgentServer {
|
|||
return e;
|
||||
}
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::SetStatus { text: args.text })
|
||||
.dispatch(hive_agent_sock::Request::SetStatus { text: args.text })
|
||||
.await;
|
||||
annotate_retries(
|
||||
format_ack(resp, "set_status", "status updated".to_owned()),
|
||||
|
|
@ -397,7 +397,7 @@ impl AgentServer {
|
|||
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::Request::GetAgentMeta { name: args.name })
|
||||
.dispatch(hive_agent_sock::Request::GetAgentMeta { name: args.name })
|
||||
.await;
|
||||
annotate_retries(format_agent_meta(resp), retries)
|
||||
})
|
||||
|
|
@ -425,7 +425,7 @@ impl AgentServer {
|
|||
};
|
||||
let kind_label = loose_end_kind_label(kind);
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::CancelLooseEnd { kind, id })
|
||||
.dispatch(hive_agent_sock::Request::CancelLooseEnd { kind, id })
|
||||
.await;
|
||||
annotate_retries(
|
||||
format_ack(
|
||||
|
|
@ -452,10 +452,10 @@ impl AgentServer {
|
|||
let log = format!("{args:?}");
|
||||
run_tool_envelope("create_repo", log, async move {
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::CreateRepo { repo: args.repo })
|
||||
.dispatch(hive_agent_sock::Request::CreateRepo { repo: args.repo })
|
||||
.await;
|
||||
let s = match resp {
|
||||
Ok(hive_sh4re::Response::RepoCreated {
|
||||
Ok(hive_agent_sock::Response::RepoCreated {
|
||||
full_name,
|
||||
clone_url,
|
||||
}) => format!("created repo {full_name} — clone: {clone_url}"),
|
||||
|
|
@ -495,7 +495,7 @@ impl AgentServer {
|
|||
(None, Some(t)) => hive_sh4re::ReminderTiming::At { unix_timestamp: t },
|
||||
};
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::Remind {
|
||||
.dispatch(hive_agent_sock::Request::Remind {
|
||||
message: args.message,
|
||||
timing,
|
||||
file_path: args.file_path,
|
||||
|
|
@ -549,7 +549,7 @@ impl AgentServer {
|
|||
let name = args.name.clone();
|
||||
run_tool_envelope("restart", log, async move {
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::Restart { name: args.name })
|
||||
.dispatch(hive_agent_sock::Request::Restart { name: args.name })
|
||||
.await;
|
||||
annotate_retries(
|
||||
format_ack(resp, "restart", format!("restarted {name}")),
|
||||
|
|
@ -571,7 +571,7 @@ impl AgentServer {
|
|||
let name = args.name.clone();
|
||||
run_tool_envelope("kill", log, async move {
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::Kill { name: args.name })
|
||||
.dispatch(hive_agent_sock::Request::Kill { name: args.name })
|
||||
.await;
|
||||
annotate_retries(format_ack(resp, "kill", format!("killed {name}")), retries)
|
||||
})
|
||||
|
|
@ -592,7 +592,7 @@ impl AgentServer {
|
|||
let name = args.name.clone();
|
||||
run_tool_envelope("update", log, async move {
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::Update { name: args.name })
|
||||
.dispatch(hive_agent_sock::Request::Update { name: args.name })
|
||||
.await;
|
||||
annotate_retries(
|
||||
format_ack(resp, "update", format!("updated {name}")),
|
||||
|
|
@ -614,9 +614,11 @@ impl AgentServer {
|
|||
)]
|
||||
async fn list_containers(&self) -> String {
|
||||
run_tool_envelope("list_containers", String::new(), async move {
|
||||
let (resp, retries) = self.dispatch(hive_sh4re::Request::ListDescendants).await;
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_agent_sock::Request::ListDescendants)
|
||||
.await;
|
||||
let body = match resp {
|
||||
Ok(hive_sh4re::Response::Containers { containers }) => {
|
||||
Ok(hive_agent_sock::Response::Containers { containers }) => {
|
||||
if containers.is_empty() {
|
||||
"no descendant containers".to_owned()
|
||||
} else {
|
||||
|
|
@ -659,7 +661,7 @@ impl AgentServer {
|
|||
let log = format!("{args:?}");
|
||||
run_tool_envelope("get_host_journal", log, async move {
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::GetHostJournal {
|
||||
.dispatch(hive_agent_sock::Request::GetHostJournal {
|
||||
unit: args.unit,
|
||||
container: args.container,
|
||||
lines: args.lines,
|
||||
|
|
@ -670,7 +672,7 @@ impl AgentServer {
|
|||
})
|
||||
.await;
|
||||
let result = match resp {
|
||||
Ok(hive_sh4re::Response::HostJournal { content }) => content,
|
||||
Ok(hive_agent_sock::Response::HostJournal { content }) => content,
|
||||
other => reply_err(other, "get_host_journal"),
|
||||
};
|
||||
annotate_retries(result, retries)
|
||||
|
|
@ -699,7 +701,7 @@ impl AgentServer {
|
|||
let name = args.name.clone();
|
||||
run_tool_envelope("request_init_config", log, async move {
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::RequestInitConfig {
|
||||
.dispatch(hive_agent_sock::Request::RequestInitConfig {
|
||||
name: args.name,
|
||||
description: args.description,
|
||||
})
|
||||
|
|
@ -727,7 +729,7 @@ impl AgentServer {
|
|||
let name = args.name.clone();
|
||||
run_tool_envelope("start", log, async move {
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::Start { name: args.name })
|
||||
.dispatch(hive_agent_sock::Request::Start { name: args.name })
|
||||
.await;
|
||||
annotate_retries(
|
||||
format_ack(resp, "start", format!("started {name}")),
|
||||
|
|
@ -750,13 +752,13 @@ impl AgentServer {
|
|||
run_tool_envelope("get_logs", log, async move {
|
||||
let lines = args.lines.map(|n| n.min(500));
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::GetLogs {
|
||||
.dispatch(hive_agent_sock::Request::GetLogs {
|
||||
agent: agent.clone(),
|
||||
lines,
|
||||
})
|
||||
.await;
|
||||
let s = match resp {
|
||||
Ok(hive_sh4re::Response::Logs { content }) => {
|
||||
Ok(hive_agent_sock::Response::Logs { content }) => {
|
||||
if content.is_empty() {
|
||||
format!("(no journal output for {agent})")
|
||||
} else {
|
||||
|
|
@ -790,7 +792,7 @@ impl AgentServer {
|
|||
args.inputs.join(", ")
|
||||
};
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::RequestUpdateMetaInputs {
|
||||
.dispatch(hive_agent_sock::Request::RequestUpdateMetaInputs {
|
||||
inputs: args.inputs,
|
||||
description: args.description,
|
||||
})
|
||||
|
|
@ -829,7 +831,7 @@ impl AgentServer {
|
|||
run_tool_envelope("request_schedule_prompt", log, async move {
|
||||
let target_count = args.targets.len();
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::RequestSchedulePrompt(
|
||||
.dispatch(hive_agent_sock::Request::RequestSchedulePrompt(
|
||||
hive_sh4re::SchedulePromptPayload {
|
||||
targets: args.targets,
|
||||
body: args.body,
|
||||
|
|
@ -865,7 +867,7 @@ impl AgentServer {
|
|||
run_tool_envelope("fire_schedule_now", log, async move {
|
||||
let id = args.id;
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::FireScheduleNow { id })
|
||||
.dispatch(hive_agent_sock::Request::FireScheduleNow { id })
|
||||
.await;
|
||||
annotate_retries(
|
||||
format_ack(resp, "fire_schedule_now", format!("fired #{id} now")),
|
||||
|
|
@ -888,7 +890,7 @@ impl AgentServer {
|
|||
run_tool_envelope("cancel_schedule", log, async move {
|
||||
let id = args.id;
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::CancelSchedule {
|
||||
.dispatch(hive_agent_sock::Request::CancelSchedule {
|
||||
id: args.id,
|
||||
targets: args.targets,
|
||||
})
|
||||
|
|
@ -920,7 +922,7 @@ impl AgentServer {
|
|||
run_tool_envelope("edit_schedule", log, async move {
|
||||
let id = args.id;
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::EditSchedule {
|
||||
.dispatch(hive_agent_sock::Request::EditSchedule {
|
||||
id: args.id,
|
||||
body: args.body,
|
||||
description: args.description.map(Some),
|
||||
|
|
@ -947,9 +949,9 @@ impl AgentServer {
|
|||
)]
|
||||
async fn list_schedules(&self) -> String {
|
||||
run_tool_envelope("list_schedules", String::new(), async move {
|
||||
let (resp, retries) = self.dispatch(hive_sh4re::Request::ListSchedules).await;
|
||||
let (resp, retries) = self.dispatch(hive_agent_sock::Request::ListSchedules).await;
|
||||
let body = match resp {
|
||||
Ok(hive_sh4re::Response::Schedules { schedules }) => {
|
||||
Ok(hive_agent_sock::Response::Schedules { schedules }) => {
|
||||
serde_json::to_string(&schedules)
|
||||
.unwrap_or_else(|e| format!("list_schedules: serialise: {e:#}"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,12 @@
|
|||
/// 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.
|
||||
pub(super) fn reply_err(resp: Result<hive_sh4re::Response, anyhow::Error>, tool: &str) -> String {
|
||||
pub(super) fn reply_err(
|
||||
resp: Result<hive_agent_sock::Response, anyhow::Error>,
|
||||
tool: &str,
|
||||
) -> String {
|
||||
match resp {
|
||||
Ok(hive_sh4re::Response::Err { message }) => format!("{tool} failed: {message}"),
|
||||
Ok(hive_agent_sock::Response::Err { message }) => format!("{tool} failed: {message}"),
|
||||
Ok(other) => format!("{tool} unexpected response: {other:?}"),
|
||||
Err(e) => format!("{tool} transport error: {e:#}"),
|
||||
}
|
||||
|
|
@ -23,12 +26,12 @@ pub(super) fn reply_err(resp: Result<hive_sh4re::Response, anyhow::Error>, tool:
|
|||
/// behavior.
|
||||
#[must_use]
|
||||
pub fn format_ack(
|
||||
resp: Result<hive_sh4re::Response, anyhow::Error>,
|
||||
resp: Result<hive_agent_sock::Response, anyhow::Error>,
|
||||
tool: &str,
|
||||
ok_msg: String,
|
||||
) -> String {
|
||||
match resp {
|
||||
Ok(hive_sh4re::Response::Ok) => ok_msg,
|
||||
Ok(hive_agent_sock::Response::Ok) => ok_msg,
|
||||
other => reply_err(other, tool),
|
||||
}
|
||||
}
|
||||
|
|
@ -44,9 +47,9 @@ pub fn format_ack(
|
|||
/// so the model can tell where one ends and the next begins;
|
||||
/// per-message redelivery banners included.
|
||||
#[must_use]
|
||||
pub fn format_recv(resp: Result<hive_sh4re::Response, anyhow::Error>, waited: bool) -> String {
|
||||
pub fn format_recv(resp: Result<hive_agent_sock::Response, anyhow::Error>, waited: bool) -> String {
|
||||
match resp {
|
||||
Ok(hive_sh4re::Response::Messages {
|
||||
Ok(hive_agent_sock::Response::Messages {
|
||||
messages,
|
||||
remaining,
|
||||
}) => render_recv_messages(&messages, remaining, waited),
|
||||
|
|
@ -57,7 +60,7 @@ pub fn format_recv(resp: Result<hive_sh4re::Response, anyhow::Error>, waited: bo
|
|||
// stop unmissably tells claude to flush + end. `remaining` is forced
|
||||
// to 0 — the inbox is fenced, so a "N more pending" hint would be
|
||||
// misleading.
|
||||
Ok(hive_sh4re::Response::GracefulStop) => {
|
||||
Ok(hive_agent_sock::Response::GracefulStop) => {
|
||||
render_recv_messages(&[graceful_stop_message()], 0, waited)
|
||||
}
|
||||
other => reply_err(other, "recv"),
|
||||
|
|
@ -354,9 +357,9 @@ pub(super) fn loose_end_kind_label(kind: hive_sh4re::CancelLooseEndKind) -> &'st
|
|||
/// `running: no` line tells the caller WHY. See
|
||||
/// `docs/turn-loop/mcp.md::Core tools` (`get_agent_meta`).
|
||||
#[must_use]
|
||||
pub fn format_agent_meta(resp: Result<hive_sh4re::Response, anyhow::Error>) -> String {
|
||||
pub fn format_agent_meta(resp: Result<hive_agent_sock::Response, anyhow::Error>) -> String {
|
||||
match resp {
|
||||
Ok(hive_sh4re::Response::AgentMeta {
|
||||
Ok(hive_agent_sock::Response::AgentMeta {
|
||||
name,
|
||||
running,
|
||||
hyperhive_rev,
|
||||
|
|
@ -477,7 +480,7 @@ mod tests {
|
|||
#[test]
|
||||
fn empty_recv_after_wait_appends_idle_hint() {
|
||||
let out = format_recv(
|
||||
Ok(hive_sh4re::Response::Messages {
|
||||
Ok(hive_agent_sock::Response::Messages {
|
||||
messages: vec![],
|
||||
remaining: 0,
|
||||
}),
|
||||
|
|
@ -490,7 +493,7 @@ mod tests {
|
|||
#[test]
|
||||
fn empty_recv_without_wait_has_no_hint() {
|
||||
let out = format_recv(
|
||||
Ok(hive_sh4re::Response::Messages {
|
||||
Ok(hive_agent_sock::Response::Messages {
|
||||
messages: vec![],
|
||||
remaining: 0,
|
||||
}),
|
||||
|
|
@ -502,7 +505,7 @@ mod tests {
|
|||
#[test]
|
||||
fn single_recv_with_remaining_appends_pending_hint() {
|
||||
let out = format_recv(
|
||||
Ok(hive_sh4re::Response::Messages {
|
||||
Ok(hive_agent_sock::Response::Messages {
|
||||
messages: vec![msg(7, "alice", "hi")],
|
||||
remaining: 3,
|
||||
}),
|
||||
|
|
@ -516,7 +519,7 @@ mod tests {
|
|||
#[test]
|
||||
fn single_recv_no_remaining_has_no_pending_hint() {
|
||||
let out = format_recv(
|
||||
Ok(hive_sh4re::Response::Messages {
|
||||
Ok(hive_agent_sock::Response::Messages {
|
||||
messages: vec![msg(7, "alice", "hi")],
|
||||
remaining: 0,
|
||||
}),
|
||||
|
|
@ -528,7 +531,7 @@ mod tests {
|
|||
#[test]
|
||||
fn batch_recv_with_remaining_appends_pending_hint_once() {
|
||||
let out = format_recv(
|
||||
Ok(hive_sh4re::Response::Messages {
|
||||
Ok(hive_agent_sock::Response::Messages {
|
||||
messages: vec![msg(7, "alice", "hi"), msg(8, "bob", "yo")],
|
||||
remaining: 9,
|
||||
}),
|
||||
|
|
|
|||
Loading…
Reference in a new issue