Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/hive-core-agent-sock/src/lib.rs
damocles 1c3b5e52cf drop the host side of the agent broker send
Remove the agent-side Send and AckUntil requests, their hive-c0re handlers
(handle_send with its 4 KiB size cap, handle_ack_until) and Broker::ack_until.
Everything that existed only for them goes with them: the OkWarn response
(its sole producer was Send's reserved-name warning), Recv's max parameter
and RECV_BATCH_MAX (the harness never asked for more than one message),
OPERATOR_SEND_REFUSAL, and the MESSAGE_MAX_BYTES / check_size limit (the
reminder timer keeps its own copy of the cap, so its comment is reworded).

Messages.remaining stays on the wire (default on read) because a harness
built before this change still requires it. Update the conventions docs.
2026-11-08 08:56:39 +01:00

139 lines
6.7 KiB
Rust

//! Per-agent socket wire types (`/run/hive/mcp.sock`).
//!
//! The unified `Request` / `Response` protocol spoken between an agent's
//! in-container harness and the `hive-c0re` daemon over the
//! per-agent mcp socket. Re-homed out of `hive-sh4re` so this one socket owns
//! its own protocol crate, mirroring `hive-host-sock` / `hive-priv-sock`. The
//! shared payload types it references (`Message`, `LooseEnd`, …)
//! stay in `hive-sh4re`, which this crate depends on.
use hive_sh4re::container::MatrixIdentity;
use hive_sh4re::inbox::{DeliveredMessage, InboxRow, LooseEnd};
use hive_types::Ident;
use serde::{Deserialize, Serialize};
/// serde `default` helper for `Response::AgentMeta::running` (absent = true).
fn default_true() -> bool {
true
}
/// Unified request enum for the per-agent socket. The agent's
/// identity is the socket it arrived on.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "cmd", rename_all = "snake_case")]
pub enum Request {
/// Pop pending messages from this agent's inbox.
/// Delivery + ack cycle: see
/// `docs/5-project/process/conventions.md::Broker delivery + ack cycle`.
Recv {
#[serde(default)]
wait_seconds: Option<u64>,
},
/// Non-mutating: how many pending messages are addressed to me?
/// Used by the harness to render a status line after each tool call.
Status,
/// Wake-up event injected from inside the container. Recipient is
/// implicit (this agent); `from` is caller-chosen. See
/// `docs/5-project/process/conventions.md::Wake injection` for the trust model and
/// typical callers. The wake is persisted in the sqlite broker
/// like any other message.
Wake { from: String, body: String },
/// Last `limit` messages addressed to this agent, newest-first.
/// Non-mutating — pulls from the broker without delivering. The
/// per-agent web UI uses this to render its own inbox section.
Recent { limit: u64 },
/// Loose-ends view — always the caller's own. See
/// `docs/5-project/process/conventions.md::Loose-ends wire shape`.
GetLooseEnds,
/// Set a free-text status string visible on the dashboard. The harness
/// writes `{state_dir}/hyperhive-status` locally before sending this
/// request; hive-c0re just triggers a dashboard rescan on receipt.
/// Pass an empty string to clear the status.
SetStatus { text: String },
/// Fetch identity + status for an agent. `name = None` =
/// self-introspection; `Some(<agent>)` = target query. See
/// `docs/5-project/process/conventions.md::Agent metadata`.
GetAgentMeta {
#[serde(default, skip_serializing_if = "Option::is_none")]
name: Option<Ident>,
},
/// Mark every message popped since the last `AckTurn` as handled.
/// Harness↔broker pairing fired after `TurnOutcome::Ok`. See
/// `docs/5-project/process/conventions.md::Broker delivery + ack cycle`.
AckTurn,
/// Requeue every popped-but-unacked message back into the inbox.
/// Harness fires this once at boot to recover from
/// crashed-mid-turn sessions. See
/// `docs/5-project/process/conventions.md::Broker delivery + ack cycle`.
RequeueInflight,
/// Harness → c0re: "I saw the `GracefulStop` signal, ran my
/// stop-checkpoint turn (durable `/state` flushed) and am exiting my
/// serve loop now." Lets the `GracefulStop` orchestration stop the
/// container immediately instead of waiting out its timeout fallback.
GracefulStopComplete,
/// Harness → c0re: "the `Pause` marker check I run between turns
/// (never mid-turn) just flipped `false → true`." Lets the pause
/// DAG's drain node resolve immediately instead of waiting out its
/// timeout fallback — same shape as `GracefulStopComplete`.
PauseAcknowledged,
}
/// Unified response enum for the per-agent socket.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum Response {
/// The request succeeded.
Ok,
/// A request failed (`Recv` errored, a store write failed, ...).
Err { message: String },
/// `Recv` result: zero or one message. Empty vec = nothing pending.
/// Per-row `id` + `redelivered` carry the broker's row id (tracked by
/// the harness for `AckTurn`) and the "previously popped, not acked"
/// flag — see `DeliveredMessage` for details. `remaining` is the inbox
/// depth after the pop. No reader uses it any more, but a harness built
/// before it stopped being used still requires the field, so hive-c0re
/// keeps sending it until every agent has rebuilt; `default` lets a new
/// harness read an answer from a c0re that has dropped it.
Messages {
messages: Vec<DeliveredMessage>,
#[serde(default)]
remaining: u64,
},
/// `Status` result: how many pending messages are in this agent's inbox.
Status { unread: u64 },
/// `Recent` result: newest-first inbox rows.
Recent { rows: Vec<InboxRow> },
/// `GetLooseEnds` result: list of loose ends pending against
/// this agent. Ordered newest-first within each kind.
LooseEnds { loose_ends: Vec<LooseEnd> },
/// `GetAgentMeta` result. Per-field semantics + serde defaults
/// live in `docs/5-project/process/conventions.md::Agent metadata`.
AgentMeta {
name: String,
#[serde(default = "default_true")]
running: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
hyperhive_rev: Option<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>,
#[serde(default, skip_serializing_if = "Option::is_none")]
hive_name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
swarm_name: Option<String>,
/// Matrix identities this agent can act as (one per configured +
/// live account). Empty for agents with no matrix provisioning.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
matrix_accounts: Vec<MatrixIdentity>,
},
/// `Recv` result when a graceful stop is pending for this agent
/// (set by hive-c0re's `GracefulStop` orchestration). Returned in
/// place of `Messages` — it doubles as the inbound fence: the harness
/// stops consuming normal inbox messages and instead runs one
/// stop-checkpoint turn (flush durable `/state`), then reports
/// `GracefulStopComplete` and exits its serve loop so the container
/// can be stopped cleanly. New sends keep queueing in the broker for
/// the agent's next start.
GracefulStop,
}