78 lines
3.3 KiB
Rust
78 lines
3.3 KiB
Rust
//! Shared response/DTO shapes for the matrix tool surface.
|
|
//!
|
|
//! `hive-matrix-daemon` serves its MCP tools directly over
|
|
//! streamable-http (see [`crate::mcp`]) — there is no separate bridge
|
|
//! process and no wire protocol between two binaries any more, so this
|
|
//! module carries only the handler-facing result type
|
|
//! ([`DaemonResponse`]) and small DTOs ([`InviteAction`],
|
|
//! [`RoomUnread`]) shared between [`crate::handlers`] and its callers
|
|
//! (the MCP tool router, the wake-signal formatter).
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// Whether to accept or reject a pending invite (`resolve_invite`
|
|
/// tool). Serialises as `"accept"` / `"reject"` on the wire (kept
|
|
/// `Serialize`/`Deserialize` for the JSON DTOs handlers build).
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum InviteAction {
|
|
/// Accept the invite — join the room (same effect as `join_room`).
|
|
Accept,
|
|
/// Reject the invite — decline it and leave the room.
|
|
Reject,
|
|
}
|
|
|
|
/// One entry in the `unread_summary` response payload.
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub struct RoomUnread {
|
|
/// Canonical alias (`#name:server`) or room id (`!id:server`).
|
|
pub label: String,
|
|
/// Always `1` — an exact unread-message count is no longer tracked
|
|
/// (see `handlers::room_unread_state`'s doc comment for why); the
|
|
/// agent reads the room via `read_room` for full context, so only
|
|
/// "there's something new" plus a one-message preview matters here.
|
|
pub count: u32,
|
|
/// Truncated body of the room's latest (unread) event. Present when
|
|
/// that event is a text-like message; absent for a reaction/state
|
|
/// event or when the fetch failed.
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub last_body: Option<String>,
|
|
/// Sender of the last message (`@user:server`). Present when
|
|
/// `last_body` is present.
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub last_sender: Option<String>,
|
|
}
|
|
|
|
/// Result shape every [`crate::handlers`] function returns: `Ok`
|
|
/// carries the payload (any JSON; the MCP tool router renders it as
|
|
/// the tool result string), `Error` carries a human-readable error
|
|
/// string. Kept as a distinct type (rather than each handler
|
|
/// returning a bare `String`) so the tool router can uniformly render
|
|
/// success vs error without every handler duplicating that
|
|
/// formatting.
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
#[serde(tag = "kind", rename_all = "snake_case")]
|
|
pub enum DaemonResponse {
|
|
Ok { payload: serde_json::Value },
|
|
Error { message: String },
|
|
}
|
|
|
|
impl DaemonResponse {
|
|
/// Convenience: build an Ok response from any serializable value.
|
|
/// Serialisation failure (impossible for the small handler structs
|
|
/// we use, but the API is generic) surfaces as a structured
|
|
/// `{"serialise_error": "..."}` payload so callers see WHY the
|
|
/// data is missing instead of a silent `null`.
|
|
pub fn ok<T: Serialize>(payload: &T) -> Self {
|
|
let payload = serde_json::to_value(payload)
|
|
.unwrap_or_else(|e| serde_json::json!({ "serialise_error": e.to_string() }));
|
|
Self::Ok { payload }
|
|
}
|
|
|
|
/// Convenience: build an Error response from any `Display` value.
|
|
pub fn error(msg: impl std::fmt::Display) -> Self {
|
|
Self::Error {
|
|
message: msg.to_string(),
|
|
}
|
|
}
|
|
}
|