replace send_file_dm with open_dm resolver (per review)

This commit is contained in:
damocles 2026-06-15 17:21:23 +02:00 committed by mara
commit 07941421c1
4 changed files with 26 additions and 44 deletions

View file

@ -93,16 +93,10 @@ struct SendFileArgs {
} }
#[derive(Debug, Deserialize, JsonSchema)] #[derive(Debug, Deserialize, JsonSchema)]
struct SendFileDmArgs { struct OpenDmArgs {
/// Matrix user id of the recipient (`@user:server`). DM room is /// Matrix user id (`@user:server`) to open a DM with. The DM room is
/// created if one doesn't already exist. /// created if one doesn't already exist.
user_id: String, 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<String>,
} }
#[derive(Debug, Deserialize, JsonSchema)] #[derive(Debug, Deserialize, JsonSchema)]
@ -240,19 +234,14 @@ impl MatrixBridge {
) )
} }
#[tool( #[tool(description = "Resolve (find-or-create) the DM room with `user_id` \
description = "Open (or reuse) a DM with `user_id` (@user:server) and upload \ (@user:server) and return its room id, without sending anything. Use the \
a local file as an attachment. `path` is an absolute local file path (MIME \ returned room id with the room-based tools (`send_file`, `send_message`, \
inferred, 50 MiB cap); optional `caption` is sent as a follow-up message. \ ) to deliver into the DM there is no per-tool DM variant.")]
If the DM room already exists with unread messages, the send is rejected \ async fn open_dm(&self, Parameters(args): Parameters<OpenDmArgs>) -> String {
read_room then mark_read first."
)]
async fn send_file_dm(&self, Parameters(args): Parameters<SendFileDmArgs>) -> String {
render( render(
round_trip(DaemonRequest::SendFileDm { round_trip(DaemonRequest::OpenDm {
user_id: args.user_id, user_id: args.user_id,
path: args.path,
caption: args.caption,
}) })
.await, .await,
) )

View file

@ -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 /// 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()`. /// used rather than the async `is_direct()`.
async fn resolve_or_create_dm( async fn resolve_or_create_dm(
client: &Client, client: &Client,
@ -304,20 +304,19 @@ pub async fn send_file(
upload_attachment(&room, path, caption).await upload_attachment(&room, path, caption).await
} }
pub async fn send_file_dm( /// Resolve (find-or-create) the DM room with `user_id` and return its
client: &Client, /// room id without sending anything. The caller then uses the room-based
user_id: &str, /// tools (`send_file`, `send_message`, …) against that id — so there is
path: &str, /// no per-tool `_dm` variant.
caption: Option<&str>, pub async fn open_dm(client: &Client, user_id: &str) -> DaemonResponse {
) -> DaemonResponse {
let room = match resolve_or_create_dm(client, user_id).await { let room = match resolve_or_create_dm(client, user_id).await {
Ok(r) => r, Ok(r) => r,
Err(e) => return e, Err(e) => return e,
}; };
if let Some(reject) = unread_guard(&room) { DaemonResponse::ok(&serde_json::json!({
return reject; "room_id": room.room_id().to_string(),
} "user_id": user_id,
upload_attachment(&room, path, caption).await }))
} }
pub async fn send_reaction( pub async fn send_reaction(

View file

@ -37,15 +37,13 @@ pub enum DaemonRequest {
caption: Option<String>, caption: Option<String>,
}, },
/// Open (or reuse) a DM with `user_id` and post a local file as an /// Resolve (find-or-create) the DM room with `user_id` and return
/// attachment. `caption`, when set, is sent as a follow-up text /// its room id, without sending anything. Lets a caller obtain the
/// message in the DM. /// DM room id and then use the room-based tools (`send_file`,
#[serde(rename = "send_file_dm")] /// `send_message`, …) against it — so there is no per-tool `_dm`
SendFileDm { /// variant.
user_id: String, #[serde(rename = "open_dm")]
path: String, OpenDm { user_id: String },
caption: Option<String>,
},
/// React to a specific event with an emoji `key`. Matrix-spec /// React to a specific event with an emoji `key`. Matrix-spec
/// `m.reaction` annotation. /// `m.reaction` annotation.

View file

@ -70,11 +70,7 @@ async fn dispatch(req: DaemonRequest, client: &Client) -> DaemonResponse {
path, path,
caption, caption,
} => handlers::send_file(client, &room, &path, caption.as_deref()).await, } => handlers::send_file(client, &room, &path, caption.as_deref()).await,
DaemonRequest::SendFileDm { DaemonRequest::OpenDm { user_id } => handlers::open_dm(client, &user_id).await,
user_id,
path,
caption,
} => handlers::send_file_dm(client, &user_id, &path, caption.as_deref()).await,
DaemonRequest::SendReaction { DaemonRequest::SendReaction {
room, room,
event_id, event_id,