hyperhive/hive-matrix-mcp/src/timeline.rs

66 lines
2.9 KiB
Rust

//! Matrix event handlers: incoming room messages fire a hyperhive
//! wake signal so the agent's harness drives a new claude turn.
//!
//! Per mara on #548: wake body is a SHORT TEASER, not the full message
//! (msg stays unread server-side; agent fetches via `read_room`). The
//! `wake::format_wake_body` truncates to ~100 chars.
//!
//! Self-events (events sent by this agent) are filtered out so an
//! agent posting a message doesn't wake itself.
use std::path::PathBuf;
use std::sync::Arc;
use matrix_sdk::{
Client, Room, RoomState,
ruma::events::room::message::{MessageType, OriginalSyncRoomMessageEvent},
};
use crate::wake;
/// Install the room-message handler on `client`. Fires on every
/// `m.room.message` event in a joined room; non-self text messages
/// trigger a wake signal to the hyperhive harness via the unix socket
/// at `hyperhive_socket`.
pub fn install_message_handler(client: &Client, hyperhive_socket: PathBuf) {
let socket = Arc::new(hyperhive_socket);
let own_user = client.user_id().map(std::borrow::ToOwned::to_owned);
client.add_event_handler({
let socket = socket.clone();
move |event: OriginalSyncRoomMessageEvent, room: Room, _client: Client| {
let socket = socket.clone();
let own_user = own_user.clone();
async move {
if room.state() != RoomState::Joined {
return;
}
// Self-event filter so the agent's own outgoing messages
// don't wake it. matches forge_notify's self-skip pattern.
if own_user.as_ref().is_some_and(|u| u == &event.sender) {
return;
}
let text = match &event.content.msgtype {
MessageType::Text(t) => t.body.clone(),
MessageType::Notice(n) => n.body.clone(),
MessageType::Emote(e) => format!("* {}", e.body),
_ => {
// Non-text content (image / file / location / etc.) —
// still wake, but with a placeholder body so the
// agent knows something landed and can read_room.
format!("[{}]", event.content.msgtype())
}
};
let room_label = room
.canonical_alias()
.map_or_else(|| room.room_id().to_string(), |a| a.to_string());
let body = wake::format_wake_body(event.sender.as_str(), &room_label, &text);
if let Err(e) = wake::send_wake(&socket, &body).await {
tracing::warn!(error = %e, "failed to deliver matrix wake to hyperhive");
} else {
tracing::debug!(room = %room.room_id(), "matrix wake delivered");
}
}
}
});
tracing::info!("matrix message handler installed");
}