/// Per-message response context, threading the sender's identity from Matrix /// through the tool loop and memory system. #[derive(Debug, Clone)] pub struct ResponseContext { /// Full Matrix user ID, e.g. `@sienna:sunbeam.pt` pub matrix_user_id: String, /// Derived portable ID, e.g. `sienna@sunbeam.pt` pub user_id: String, /// Display name if available pub display_name: Option, /// Whether this message was sent in a DM pub is_dm: bool, /// Whether this message is a reply to Sol pub is_reply: bool, /// The room this message was sent in pub room_id: String, } /// Extract the localpart from a Matrix user ID. /// /// `@sienna:sunbeam.pt` → `sienna` pub fn localpart(matrix_user_id: &str) -> &str { let stripped = matrix_user_id.strip_prefix('@').unwrap_or(matrix_user_id); stripped.split(':').next().unwrap_or(stripped) } /// Derive a portable user ID from a Matrix user ID. /// /// `@sienna:sunbeam.pt` → `sienna@sunbeam.pt` pub fn derive_user_id(matrix_user_id: &str) -> String { let stripped = matrix_user_id.strip_prefix('@').unwrap_or(matrix_user_id); stripped.replacen(':', "@", 1) } #[cfg(test)] mod tests { use super::*; #[test] fn test_derive_user_id_standard() { assert_eq!(derive_user_id("@sienna:sunbeam.pt"), "sienna@sunbeam.pt"); } #[test] fn test_derive_user_id_no_at_prefix() { assert_eq!(derive_user_id("sienna:sunbeam.pt"), "sienna@sunbeam.pt"); } #[test] fn test_derive_user_id_complex() { assert_eq!( derive_user_id("@user.name:matrix.org"), "user.name@matrix.org" ); } #[test] fn test_derive_user_id_only_first_colon() { assert_eq!( derive_user_id("@user:server:8448"), "user@server:8448" ); } #[test] fn test_localpart_standard() { assert_eq!(localpart("@sienna:sunbeam.pt"), "sienna"); } #[test] fn test_localpart_no_at_prefix() { assert_eq!(localpart("sienna:sunbeam.pt"), "sienna"); } #[test] fn test_localpart_no_colon() { assert_eq!(localpart("@sienna"), "sienna"); } #[test] fn test_localpart_complex() { assert_eq!(localpart("@user.name:matrix.org"), "user.name"); } }