Watch
0
0
Fork
You've already forked hyperhive
0

hive-matrix-mcp: surface the inviter and topic in list_invites

This commit is contained in:
damocles 2026-10-04 20:11:24 +02:00 • committed by mara
commit 8b6b735a20
3 changed files with 30 additions and 12 deletions

View file

@ -66,7 +66,9 @@ room you haven't read yet.
a pending invite if one exists, but prefer `resolve_invite` for a pending invite if one exists, but prefer `resolve_invite` for
invites (it can reject too). invites (it can reject too).
- `list_invites()` — rooms this agent has been invited to but not - `list_invites()` — rooms this agent has been invited to but not
yet joined (`{ id, canonical_alias, name }` per room). yet joined (`{ id, canonical_alias, name, inviter, topic }` per room —
`inviter` and `topic` are there so an agent has enough to judge an
invite before `resolve_invite`ing it, not just a bare room id).
<!-- vale write-good.Passive = YES --> <!-- vale write-good.Passive = YES -->
### Receipts ### Receipts

View file

@ -32,6 +32,16 @@ pub struct InviteInfo {
pub room_id: String, pub room_id: String,
pub canonical_alias: Option<String>, pub canonical_alias: Option<String>,
pub name: Option<String>, pub name: Option<String>,
/// Who sent the invite — the `sender` of the `m.room.member` invite
/// event for this account. `None` only on an SDK-side lookup failure
/// (`invite_details` errors if the room isn't genuinely in the
/// `Invited` state, which shouldn't happen here since we got the room
/// from `invited_rooms()` itself).
pub inviter: Option<String>,
/// The room's topic, where set. Most invites to a freshly created room
/// won't have one; `canonical_alias`/`name` are just as commonly unset,
/// so this is one more thing to judge the invite by, not a guarantee.
pub topic: Option<String>,
} }
/// JSON-shape for `list_rooms`: one row per joined room. /// JSON-shape for `list_rooms`: one row per joined room.
@ -654,18 +664,23 @@ pub async fn list_room_members(client: &Client, room_ref: &str) -> DaemonRespons
DaemonResponse::ok(&list) DaemonResponse::ok(&list)
} }
#[must_use] pub async fn list_invites(client: &Client) -> DaemonResponse {
pub fn list_invites(client: &Client) -> DaemonResponse { let mut pending = Vec::new();
let invites: Vec<InviteInfo> = client for room in client.invited_rooms() {
.invited_rooms() let inviter = room
.into_iter() .invite_details()
.map(|room| InviteInfo { .await
.map(|details| details.inviter_id.to_string())
.ok();
pending.push(InviteInfo {
room_id: room.room_id().to_string(), room_id: room.room_id().to_string(),
canonical_alias: room.canonical_alias().map(|a| a.to_string()), canonical_alias: room.canonical_alias().map(|a| a.to_string()),
name: room.name(), name: room.name(),
}) inviter,
.collect(); topic: room.topic(),
DaemonResponse::ok(&invites) });
}
DaemonResponse::ok(&pending)
} }
pub async fn join_room(client: &Client, room_ref: &str) -> DaemonResponse { pub async fn join_room(client: &Client, room_ref: &str) -> DaemonResponse {

View file

@ -384,7 +384,8 @@ impl MatrixMcp {
#[tool( #[tool(
description = "List rooms this agent has been invited to but not yet joined. \ description = "List rooms this agent has been invited to but not yet joined. \
Each row has the room id, canonical alias (when set), and display name. \ Each row has the room id, canonical alias (when set), display name, inviting \
user id, and topic (when set) — enough to judge an invite before accepting. \
Use `resolve_invite` to accept or reject an invite." Use `resolve_invite` to accept or reject an invite."
)] )]
async fn list_invites(&self, Parameters(args): Parameters<ListInvitesArgs>) -> String { async fn list_invites(&self, Parameters(args): Parameters<ListInvitesArgs>) -> String {
@ -392,7 +393,7 @@ impl MatrixMcp {
Ok(c) => c, Ok(c) => c,
Err(e) => return format!("matrix error: {e}"), Err(e) => return format!("matrix error: {e}"),
}; };
render(handlers::list_invites(client)) render(handlers::list_invites(client).await)
} }
#[tool( #[tool(