add send_reply and get_room_history mcp tools, show reply targets in prompt
This commit is contained in:
parent
41da93a71f
commit
3f5208cab1
5 changed files with 190 additions and 3 deletions
110
src/socket.rs
110
src/socket.rs
|
|
@ -2,6 +2,7 @@ use std::path::Path;
|
|||
|
||||
use matrix_sdk::{
|
||||
Client,
|
||||
room::reply::{EnforceThread, Reply},
|
||||
ruma::{
|
||||
OwnedRoomId, OwnedUserId,
|
||||
events::{
|
||||
|
|
@ -66,8 +67,16 @@ async fn handle_request(request: DaemonRequest, client: &Client) -> DaemonRespon
|
|||
event_id,
|
||||
key,
|
||||
} => send_reaction(client, &room_id, &event_id, &key).await,
|
||||
DaemonRequest::SendReply {
|
||||
room_id,
|
||||
event_id,
|
||||
body,
|
||||
} => send_reply(client, &room_id, &event_id, &body).await,
|
||||
DaemonRequest::ListRooms {} => list_rooms(client).await,
|
||||
DaemonRequest::ListRoomMembers { room_id } => list_room_members(client, &room_id).await,
|
||||
DaemonRequest::GetRoomHistory { room_id, limit } => {
|
||||
get_room_history(client, &room_id, limit).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -183,3 +192,104 @@ async fn list_room_members(client: &Client, room_id: &str) -> DaemonResponse {
|
|||
.collect();
|
||||
DaemonResponse::ok(list)
|
||||
}
|
||||
|
||||
async fn send_reply(client: &Client, room_id: &str, event_id: &str, body: &str) -> DaemonResponse {
|
||||
let rid = match room_id.parse::<OwnedRoomId>() {
|
||||
Ok(r) => r,
|
||||
Err(e) => return DaemonResponse::err(format!("invalid room_id: {e}")),
|
||||
};
|
||||
let Some(room) = client.get_room(&rid) else {
|
||||
return DaemonResponse::err(format!("room {rid} not found"));
|
||||
};
|
||||
let own_user = match client.user_id() {
|
||||
Some(u) => u.to_owned(),
|
||||
None => return DaemonResponse::err("not logged in".to_owned()),
|
||||
};
|
||||
|
||||
// Resolve possibly-shortened event id against recent timeline
|
||||
let tl = match timeline::load_timeline(&room, 50, &own_user).await {
|
||||
Ok(t) => t,
|
||||
Err(e) => return DaemonResponse::err(format!("failed to load timeline: {e}")),
|
||||
};
|
||||
let Some(full_eid) = timeline::resolve_event_id(&tl, event_id) else {
|
||||
return DaemonResponse::err(format!("event {event_id} not found in timeline"));
|
||||
};
|
||||
|
||||
let content = RoomMessageEventContent::text_plain(body).into();
|
||||
let reply = Reply {
|
||||
event_id: full_eid.clone(),
|
||||
enforce_thread: EnforceThread::MaybeThreaded,
|
||||
};
|
||||
let reply_content = match room.make_reply_event(content, reply).await {
|
||||
Ok(c) => c,
|
||||
Err(e) => return DaemonResponse::err(format!("make_reply_event failed: {e}")),
|
||||
};
|
||||
match room.send(reply_content).await {
|
||||
Ok(_) => {
|
||||
tracing::info!(target = %full_eid, "mcp: sent reply");
|
||||
DaemonResponse::ok(format!("replied to {full_eid}"))
|
||||
}
|
||||
Err(e) => DaemonResponse::err(format!("send reply failed: {e}")),
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_room_history(
|
||||
client: &Client,
|
||||
room_id: &str,
|
||||
limit: Option<usize>,
|
||||
) -> DaemonResponse {
|
||||
let rid = match room_id.parse::<OwnedRoomId>() {
|
||||
Ok(r) => r,
|
||||
Err(e) => return DaemonResponse::err(format!("invalid room_id: {e}")),
|
||||
};
|
||||
let Some(room) = client.get_room(&rid) else {
|
||||
return DaemonResponse::err(format!("room {rid} not found"));
|
||||
};
|
||||
let own_user = match client.user_id() {
|
||||
Some(u) => u.to_owned(),
|
||||
None => return DaemonResponse::err("not logged in".to_owned()),
|
||||
};
|
||||
let limit = limit.unwrap_or(20).min(100);
|
||||
|
||||
let tl = match timeline::load_timeline(&room, limit, &own_user).await {
|
||||
Ok(t) => t,
|
||||
Err(e) => return DaemonResponse::err(format!("failed to load timeline: {e}")),
|
||||
};
|
||||
|
||||
let items: Vec<_> = tl
|
||||
.iter()
|
||||
.map(|item| match item {
|
||||
crate::types::TimelineItem::Message {
|
||||
event_id,
|
||||
sender,
|
||||
body,
|
||||
is_self,
|
||||
ts,
|
||||
in_reply_to,
|
||||
} => json!({
|
||||
"kind": "message",
|
||||
"event_id": event_id.as_str(),
|
||||
"sender": sender.as_str(),
|
||||
"body": body,
|
||||
"is_self": is_self,
|
||||
"ts": ts,
|
||||
"in_reply_to": in_reply_to.as_ref().map(|e| e.as_str()),
|
||||
}),
|
||||
crate::types::TimelineItem::Reaction {
|
||||
sender,
|
||||
target_event_id,
|
||||
key,
|
||||
is_self,
|
||||
ts,
|
||||
} => json!({
|
||||
"kind": "reaction",
|
||||
"sender": sender.as_str(),
|
||||
"target_event_id": target_event_id.as_str(),
|
||||
"key": key,
|
||||
"is_self": is_self,
|
||||
"ts": ts,
|
||||
}),
|
||||
})
|
||||
.collect();
|
||||
DaemonResponse::ok(items)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue