diff --git a/hive-matrix-mcp/src/bin/mcp.rs b/hive-matrix-mcp/src/bin/mcp.rs index 778e5eec..8be34203 100644 --- a/hive-matrix-mcp/src/bin/mcp.rs +++ b/hive-matrix-mcp/src/bin/mcp.rs @@ -93,16 +93,10 @@ struct SendFileArgs { } #[derive(Debug, Deserialize, JsonSchema)] -struct SendFileDmArgs { - /// Matrix user id of the recipient (`@user:server`). DM room is +struct OpenDmArgs { + /// Matrix user id (`@user:server`) to open a DM with. The DM room is /// created if one doesn't already exist. user_id: String, - /// Absolute path to a local file readable by the agent. MIME type is - /// inferred from the extension. 50 MiB cap. - path: String, - /// Optional caption, sent as a follow-up text message in the DM. - #[serde(default)] - caption: Option, } #[derive(Debug, Deserialize, JsonSchema)] @@ -240,19 +234,14 @@ impl MatrixBridge { ) } - #[tool( - description = "Open (or reuse) a DM with `user_id` (@user:server) and upload \ - a local file as an attachment. `path` is an absolute local file path (MIME \ - inferred, 50 MiB cap); optional `caption` is sent as a follow-up message. \ - If the DM room already exists with unread messages, the send is rejected \ - — read_room then mark_read first." - )] - async fn send_file_dm(&self, Parameters(args): Parameters) -> String { + #[tool(description = "Resolve (find-or-create) the DM room with `user_id` \ + (@user:server) and return its room id, without sending anything. Use the \ + returned room id with the room-based tools (`send_file`, `send_message`, \ + …) to deliver into the DM — there is no per-tool DM variant.")] + async fn open_dm(&self, Parameters(args): Parameters) -> String { render( - round_trip(DaemonRequest::SendFileDm { + round_trip(DaemonRequest::OpenDm { user_id: args.user_id, - path: args.path, - caption: args.caption, }) .await, ) diff --git a/hive-matrix-mcp/src/handlers.rs b/hive-matrix-mcp/src/handlers.rs index 03d2b720..c07ba78f 100644 --- a/hive-matrix-mcp/src/handlers.rs +++ b/hive-matrix-mcp/src/handlers.rs @@ -185,7 +185,7 @@ pub async fn send_message(client: &Client, room_ref: &str, body: &str) -> Daemon } /// Find the existing DM room with `user_id` or create one. Shared by -/// `send_dm` and `send_file_dm`. `direct_targets()` (cached state) is +/// `send_dm` and `open_dm`. `direct_targets()` (cached state) is /// used rather than the async `is_direct()`. async fn resolve_or_create_dm( client: &Client, @@ -304,20 +304,19 @@ pub async fn send_file( upload_attachment(&room, path, caption).await } -pub async fn send_file_dm( - client: &Client, - user_id: &str, - path: &str, - caption: Option<&str>, -) -> DaemonResponse { +/// Resolve (find-or-create) the DM room with `user_id` and return its +/// room id without sending anything. The caller then uses the room-based +/// tools (`send_file`, `send_message`, …) against that id — so there is +/// no per-tool `_dm` variant. +pub async fn open_dm(client: &Client, user_id: &str) -> DaemonResponse { let room = match resolve_or_create_dm(client, user_id).await { Ok(r) => r, Err(e) => return e, }; - if let Some(reject) = unread_guard(&room) { - return reject; - } - upload_attachment(&room, path, caption).await + DaemonResponse::ok(&serde_json::json!({ + "room_id": room.room_id().to_string(), + "user_id": user_id, + })) } pub async fn send_reaction( diff --git a/hive-matrix-mcp/src/protocol.rs b/hive-matrix-mcp/src/protocol.rs index 64c4392e..58a3b231 100644 --- a/hive-matrix-mcp/src/protocol.rs +++ b/hive-matrix-mcp/src/protocol.rs @@ -37,15 +37,13 @@ pub enum DaemonRequest { caption: Option, }, - /// Open (or reuse) a DM with `user_id` and post a local file as an - /// attachment. `caption`, when set, is sent as a follow-up text - /// message in the DM. - #[serde(rename = "send_file_dm")] - SendFileDm { - user_id: String, - path: String, - caption: Option, - }, + /// Resolve (find-or-create) the DM room with `user_id` and return + /// its room id, without sending anything. Lets a caller obtain the + /// DM room id and then use the room-based tools (`send_file`, + /// `send_message`, …) against it — so there is no per-tool `_dm` + /// variant. + #[serde(rename = "open_dm")] + OpenDm { user_id: String }, /// React to a specific event with an emoji `key`. Matrix-spec /// `m.reaction` annotation. diff --git a/hive-matrix-mcp/src/socket.rs b/hive-matrix-mcp/src/socket.rs index 8ba5a5e2..2a8a588f 100644 --- a/hive-matrix-mcp/src/socket.rs +++ b/hive-matrix-mcp/src/socket.rs @@ -70,11 +70,7 @@ async fn dispatch(req: DaemonRequest, client: &Client) -> DaemonResponse { path, caption, } => handlers::send_file(client, &room, &path, caption.as_deref()).await, - DaemonRequest::SendFileDm { - user_id, - path, - caption, - } => handlers::send_file_dm(client, &user_id, &path, caption.as_deref()).await, + DaemonRequest::OpenDm { user_id } => handlers::open_dm(client, &user_id).await, DaemonRequest::SendReaction { room, event_id,