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.
139 lines
6.7 KiB
Rust
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,
|
|
}
|