//! 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"); }