diff --git a/hive-matrix-mcp/src/bin/mcp.rs b/hive-matrix-mcp/src/bin/mcp.rs index e4c8e426..6d5db39f 100644 --- a/hive-matrix-mcp/src/bin/mcp.rs +++ b/hive-matrix-mcp/src/bin/mcp.rs @@ -162,20 +162,6 @@ struct MarkReadArgs { account: Option, } -#[derive(Debug, Deserialize, JsonSchema)] -struct SendRedactArgs { - room: String, - /// Full matrix event id of the message to redact. - event_id: String, - /// Optional human-readable reason recorded on the redaction event. - #[serde(default)] - reason: Option, - /// Matrix account to act as (a `name` from `hyperhive.matrixAccounts`). - /// Omit to use the agent's primary account. - #[serde(default)] - account: Option, -} - #[derive(Debug, Deserialize, JsonSchema)] struct ListRoomsArgs { /// Matrix account to act as (a `name` from `hyperhive.matrixAccounts`). @@ -413,24 +399,6 @@ impl MatrixBridge { ) } - #[tool(description = "Redact (delete) a specific matrix event in a room — \ - asks the homeserver to strip the event's content, optionally with a \ - `reason`. Works on your own events; redacting others' needs moderator \ - power level. Irreversible.")] - async fn send_redact(&self, Parameters(args): Parameters) -> String { - render( - call( - args.account, - DaemonOp::SendRedact { - room: args.room, - event_id: args.event_id, - reason: args.reason, - }, - ) - .await, - ) - } - #[tool( description = "List rooms this agent has joined. Each row has the room \ id, canonical alias (when set), display name, and joined-member count." @@ -555,8 +523,7 @@ impl MatrixBridge { #[tool_handler(instructions = "Matrix client for an agent on a hyperhive swarm. Use \ `send_message` to post in a joined room, `send_dm` to message a \ specific user, `send_reaction` to react with an emoji, `send_reply` \ - to thread a reply, `mark_read` to acknowledge an event, `send_redact` \ - to delete an event. Discover \ + to thread a reply, `mark_read` to acknowledge an event. Discover \ rooms with `list_rooms`, members with `list_room_members`, recent \ timeline with `read_room`. See pending invites with `list_invites`; \ accept or reject an invite with `resolve_invite`; join a public \ diff --git a/hive-matrix-mcp/src/handlers.rs b/hive-matrix-mcp/src/handlers.rs index 4a8a8f05..d7d932c5 100644 --- a/hive-matrix-mcp/src/handlers.rs +++ b/hive-matrix-mcp/src/handlers.rs @@ -6,8 +6,8 @@ //! //! Tool surface mirrors damocles-daemon's v0 set per the operator's call: //! `send_message`, `send_dm`, `send_reaction`, `send_reply`, `mark_read`, -//! `send_redact`, `list_rooms`, `list_room_members`, `read_room`. Plus a -//! `ping` for the MCP bridge's liveness probe. +//! `list_rooms`, `list_room_members`, `read_room`. Plus a `ping` for the +//! MCP bridge's liveness probe. use matrix_sdk::{ Client, @@ -407,36 +407,6 @@ pub async fn mark_read(client: &Client, room_ref: &str, event_id: &str) -> Daemo } } -pub async fn send_redact( - client: &Client, - room_ref: &str, - event_id: &str, - reason: Option<&str>, -) -> DaemonResponse { - let room = match resolve_room(client, room_ref).await { - Ok(r) => r, - Err(e) => return e, - }; - let eid: OwnedEventId = match event_id.parse() { - Ok(e) => e, - Err(e) => return DaemonResponse::error(format!("invalid event_id {event_id}: {e}")), - }; - // Redaction is irreversible: the homeserver drops the event content and - // keeps only the shell + reason. A fresh txn id (None) is fine — this is - // a one-shot operator/agent action, not a retried send. Power level is - // enforced server-side (own events always; others' need a moderator PL), - // so a redact that races a concurrent edit is resolved by the server. - // NOTE(droggelbecher): no client-side pre-check — we let the server be - // the authority on both permission and ordering. - match room.redact(&eid, reason, None).await { - Ok(resp) => DaemonResponse::ok(&serde_json::json!({ - "event_id": resp.event_id.to_string(), - "target": eid.to_string(), - })), - Err(e) => DaemonResponse::error(format!("redact {eid}: {e}")), - } -} - pub async fn list_rooms(client: &Client) -> DaemonResponse { let mut rooms = Vec::new(); for room in client.joined_rooms() { diff --git a/hive-matrix-mcp/src/protocol.rs b/hive-matrix-mcp/src/protocol.rs index 16bbee20..d072c02b 100644 --- a/hive-matrix-mcp/src/protocol.rs +++ b/hive-matrix-mcp/src/protocol.rs @@ -92,18 +92,6 @@ pub enum DaemonOp { #[serde(rename = "mark_read")] MarkRead { room: String, event_id: String }, - /// Redact `event_id` in `room` — ask the homeserver to strip the - /// event's content (matrix-spec `m.room.redaction`), optionally with - /// a human-readable `reason`. The agent must have a high enough power - /// level (its own events, or moderator rights for others'); the - /// server rejects otherwise. - #[serde(rename = "send_redact")] - SendRedact { - room: String, - event_id: String, - reason: Option, - }, - /// List rooms the agent has joined. Returns each room's id + /// canonical alias (when present) + name + member count. #[serde(rename = "list_rooms")] @@ -279,51 +267,6 @@ mod tests { matches!(back.op, DaemonOp::ListRooms); } - #[test] - fn send_redact_round_trips_with_reason() { - let req = DaemonRequest { - account: None, - op: DaemonOp::SendRedact { - room: "!r:s".to_owned(), - event_id: "$e".to_owned(), - reason: Some("spam".to_owned()), - }, - }; - let line = serde_json::to_string(&req).unwrap(); - assert!(line.contains("\"method\":\"send_redact\""), "wire: {line}"); - let back: DaemonRequest = serde_json::from_str(&line).unwrap(); - match back.op { - DaemonOp::SendRedact { - room, - event_id, - reason, - } => { - assert_eq!(room, "!r:s"); - assert_eq!(event_id, "$e"); - assert_eq!(reason.as_deref(), Some("spam")); - } - other => panic!("wrong variant: {other:?}"), - } - } - - #[test] - fn send_redact_round_trips_without_reason() { - let req = DaemonRequest { - account: None, - op: DaemonOp::SendRedact { - room: "!r:s".to_owned(), - event_id: "$e".to_owned(), - reason: None, - }, - }; - let line = serde_json::to_string(&req).unwrap(); - let back: DaemonRequest = serde_json::from_str(&line).unwrap(); - match back.op { - DaemonOp::SendRedact { reason, .. } => assert_eq!(reason, None), - other => panic!("wrong variant: {other:?}"), - } - } - #[test] fn unit_variant_op_parses_inside_envelope() { // A bare op with no fields still parses when wrapped. diff --git a/hive-matrix-mcp/src/socket.rs b/hive-matrix-mcp/src/socket.rs index 40f55dca..91b2d76a 100644 --- a/hive-matrix-mcp/src/socket.rs +++ b/hive-matrix-mcp/src/socket.rs @@ -99,11 +99,6 @@ async fn dispatch_op(op: DaemonOp, client: &Client) -> DaemonResponse { DaemonOp::MarkRead { room, event_id } => { handlers::mark_read(client, &room, &event_id).await } - DaemonOp::SendRedact { - room, - event_id, - reason, - } => handlers::send_redact(client, &room, &event_id, reason.as_deref()).await, DaemonOp::ListRooms => handlers::list_rooms(client).await, DaemonOp::ListInvites => handlers::list_invites(client), DaemonOp::JoinRoom { room } => handlers::join_room(client, &room).await,