json input format + required room_id on all room-scoped tools

This commit is contained in:
Damocles 2026-05-01 12:46:15 +02:00
parent ef461797ad
commit cc3451eef3
5 changed files with 260 additions and 241 deletions

View file

@ -1,5 +1,4 @@
use std::collections::HashMap;
use std::fmt::Write as _;
use matrix_sdk::{
Room,
@ -51,17 +50,6 @@ pub fn ts_secs_from(ts: matrix_sdk::ruma::UInt) -> i64 {
i64::try_from(ms).unwrap_or(0) / 1000
}
/// Shorten an event id for prompt display: `$abc123def456...` -> `$abc123de`.
pub fn short_event_id(id: &OwnedEventId) -> String {
let s = id.as_str();
let prefix: String = s.chars().take(9).collect();
if s.len() > 9 {
format!("{prefix}")
} else {
prefix
}
}
/// Resolve a (possibly shortened/ellipsized) event id to a full one by
/// looking up against the timeline. Returns the matching message's full
/// event id if found.
@ -80,64 +68,6 @@ pub fn resolve_event_id(timeline: &[TimelineItem], arg: &str) -> Option<OwnedEve
None
}
/// Render one timeline item into the prompt.
/// Messages: `[ts] $eid... [(you) ]@user: body [read by: ...]`
/// Reactions: `[ts] [(you) ]@user reacted to $eid... with KEY`
pub fn render_timeline_item(
prompt: &mut String,
item: &TimelineItem,
read_markers: &HashMap<OwnedEventId, Vec<OwnedUserId>>,
) {
match item {
TimelineItem::Message {
event_id,
sender,
body,
is_self,
ts,
in_reply_to,
} => {
let ts_str = format_ts(*ts);
let id = short_event_id(event_id);
let prefix = if *is_self { "(you) " } else { "" };
let reply_str = match in_reply_to {
Some(target) => format!(" [reply to {}]", short_event_id(target)),
None => String::new(),
};
let readers_str = match read_markers.get(event_id) {
Some(rs) if !rs.is_empty() => {
let mut sorted = rs.clone();
sorted.sort();
let names: Vec<String> = sorted.iter().map(|u| u.to_string()).collect();
format!(" [read by: {}]", names.join(", "))
}
_ => String::new(),
};
writeln!(
prompt,
"[{ts_str}] {id} {prefix}{sender}:{reply_str} {body}{readers_str}"
)
.unwrap();
}
TimelineItem::Reaction {
sender,
target_event_id,
key,
is_self,
ts,
} => {
let ts_str = format_ts(*ts);
let id = short_event_id(target_event_id);
let prefix = if *is_self { "(you) " } else { "" };
writeln!(
prompt,
"[{ts_str}] {prefix}{sender} reacted to {id} with {key}"
)
.unwrap();
}
}
}
/// Load the last N timeline items (messages + reactions) from the room's
/// persistent event cache. Returns oldest-first.
///