hyperhive/hive-agent-sock/src/lib.rs

76 lines
3.3 KiB
Rust

//! Wire types for the *in-agent* socket, served by the hive-agent harness
//! to the in-container producers (matrix / bash MCP daemons) and
//! `forge_notify`. Currently carries the loose-ends-v2 *todo* op family;
//! more in-agent request families may be added over time (the socket is
//! deliberately named for the agent, not the todos).
//!
//! Distinct from `hive-core-agent-sock`, the *host*-served core↔agent
//! protocol on `/run/hive/mcp.sock`: this socket never leaves the
//! container. The harness owns the todo store locally and signals its own
//! turn loop directly, so hive-c0re is not in the todo path — no broker
//! round-trip, no long-poll, no marker files.
use serde::{Deserialize, Serialize};
use hive_sh4re::LooseEnd;
/// In-container path of the harness-served in-agent socket. The harness
/// binds it on boot; the in-container producers dial it for todo ops.
/// (Placeholder default — the harness + producers resolve the real path
/// from config; kept here so a producer with no override has a sane one.)
pub const DEFAULT_AGENT_SOCKET: &str = "/run/hive/agent.sock";
/// A request on the in-agent socket. Serialised with a `cmd` tag so the
/// in-container producers can emit a plain JSON line without linking a
/// typed client (matrix/bash build the JSON by hand).
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "cmd", rename_all = "snake_case")]
pub enum Request {
/// Upsert a todo from an in-container subsystem (matrix / bash /
/// forge). `subsystem` is the producer marker; `key` the optional
/// subsystem-specific dedup key (a matrix room id, a bash task id).
/// A new-or-changed row signals the turn loop; an identical keyed
/// re-push is a silent no-op. Keyless todos always insert as one-offs.
UpsertTodo {
subsystem: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
key: Option<String>,
summary: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
source: Option<String>,
},
/// Clear producer-resolved todo(s). `key = Some(k)` clears the one
/// keyed row; `key = None` clears the subsystem's keyless rows; `all
/// = true` wipes the producer's whole set (cancel-and-recreate on
/// daemon restart).
ClearTodo {
subsystem: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
key: Option<String>,
#[serde(default)]
all: bool,
},
/// List todos, optionally filtered to one `subsystem` (a producer
/// reconciling its own set). `None` = all.
ListTodos {
#[serde(default, skip_serializing_if = "Option::is_none")]
subsystem: Option<String>,
},
/// The agent marks one of its own todos done, by id.
MarkTodoDone { id: i64 },
}
/// A response on the in-agent socket. Serialised with a `kind` tag,
/// mirroring the core↔agent protocol's response shape.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum Response {
/// Op succeeded, no payload.
Ok,
/// Op succeeded and touched `count` rows (clear / mark-done).
Acked { count: u64 },
/// `ListTodos` result.
LooseEnds { loose_ends: Vec<LooseEnd> },
/// Op failed; `message` is operator-facing.
Err { message: String },
}