Make fallback user mentions support also match against the bot's room-specific username
It seems like Element iOS benefits from this.
This commit is contained in:
@@ -172,6 +172,24 @@ impl Bot {
|
|||||||
self.matrix_link().user_id()
|
self.matrix_link().user_id()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn user_display_name_in_room(&self, room: &Room) -> Option<String> {
|
||||||
|
let bot_display_name = self
|
||||||
|
.room_display_name_fetcher()
|
||||||
|
.own_display_name_in_room(room)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match bot_display_name {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(err) => {
|
||||||
|
tracing::warn!(
|
||||||
|
?err,
|
||||||
|
"Failed to fetch bot display name. Proceeding without it"
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn reacting(&self) -> super::reacting::Reacting {
|
pub(crate) fn reacting(&self) -> super::reacting::Reacting {
|
||||||
super::reacting::Reacting::new(self.clone())
|
super::reacting::Reacting::new(self.clone())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -239,8 +239,11 @@ impl Messaging {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let bot_display_name = self.bot.user_display_name_in_room(&room).await;
|
||||||
|
|
||||||
let interaction_context = determine_interaction_context_for_room_event(
|
let interaction_context = determine_interaction_context_for_room_event(
|
||||||
self.bot.user_id(),
|
self.bot.user_id(),
|
||||||
|
&bot_display_name,
|
||||||
&room,
|
&room,
|
||||||
&event,
|
&event,
|
||||||
&payload,
|
&payload,
|
||||||
@@ -279,7 +282,8 @@ impl Messaging {
|
|||||||
self.bot.admin_pattern_regexes().clone(),
|
self.bot.admin_pattern_regexes().clone(),
|
||||||
trigger_event_info,
|
trigger_event_info,
|
||||||
interaction_context.thread_info.clone(),
|
interaction_context.thread_info.clone(),
|
||||||
);
|
)
|
||||||
|
.with_bot_display_name(bot_display_name);
|
||||||
|
|
||||||
let controller_type = crate::controller::determine_controller(
|
let controller_type = crate::controller::determine_controller(
|
||||||
self.bot.command_prefix(),
|
self.bot.command_prefix(),
|
||||||
|
|||||||
@@ -383,24 +383,10 @@ async fn handle_stage_text_generation(
|
|||||||
_ => vec![],
|
_ => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let bot_display_name = bot
|
let bot_user_prefixes_to_strip = create_list_of_bot_user_prefixes_to_strip(
|
||||||
.room_display_name_fetcher()
|
bot.user_id(),
|
||||||
.own_display_name_in_room(message_context.room())
|
message_context.bot_display_name(),
|
||||||
.await;
|
);
|
||||||
|
|
||||||
let bot_display_name = match bot_display_name {
|
|
||||||
Ok(value) => value,
|
|
||||||
Err(err) => {
|
|
||||||
tracing::warn!(
|
|
||||||
?err,
|
|
||||||
"Failed to fetch bot display name. Proceeding without it"
|
|
||||||
);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let bot_user_prefixes_to_strip =
|
|
||||||
create_list_of_bot_user_prefixes_to_strip(bot.user_id(), &bot_display_name);
|
|
||||||
|
|
||||||
let allowed_users = match controller_type {
|
let allowed_users = match controller_type {
|
||||||
// Regular chat completion only operates on messages from allowed users.
|
// Regular chat completion only operates on messages from allowed users.
|
||||||
|
|||||||
@@ -277,13 +277,14 @@ pub fn convert_matrix_native_event_to_matrix_message(
|
|||||||
#[tracing::instrument(name = "determine_interaction_context_for_room_event", skip_all, fields(room_id = room.room_id().as_str(), event_id = current_event.event_id.as_str()))]
|
#[tracing::instrument(name = "determine_interaction_context_for_room_event", skip_all, fields(room_id = room.room_id().as_str(), event_id = current_event.event_id.as_str()))]
|
||||||
pub async fn determine_interaction_context_for_room_event(
|
pub async fn determine_interaction_context_for_room_event(
|
||||||
bot_user_id: &OwnedUserId,
|
bot_user_id: &OwnedUserId,
|
||||||
|
bot_display_name: &Option<String>,
|
||||||
room: &Room,
|
room: &Room,
|
||||||
current_event: &OriginalSyncRoomMessageEvent,
|
current_event: &OriginalSyncRoomMessageEvent,
|
||||||
current_event_payload: &MessagePayload,
|
current_event_payload: &MessagePayload,
|
||||||
event_fetcher: &Arc<RoomEventFetcher>,
|
event_fetcher: &Arc<RoomEventFetcher>,
|
||||||
) -> anyhow::Result<Option<InteractionContext>> {
|
) -> anyhow::Result<Option<InteractionContext>> {
|
||||||
let current_event_is_mentioning_bot =
|
let current_event_is_mentioning_bot =
|
||||||
is_event_mentioning_bot(¤t_event.content, bot_user_id);
|
is_event_mentioning_bot(¤t_event.content, bot_user_id, bot_display_name);
|
||||||
|
|
||||||
let Some(relation) = ¤t_event.content.relates_to else {
|
let Some(relation) = ¤t_event.content.relates_to else {
|
||||||
// This is a top-level message. We consider it the start of the thread.
|
// This is a top-level message. We consider it the start of the thread.
|
||||||
@@ -305,6 +306,7 @@ pub async fn determine_interaction_context_for_room_event(
|
|||||||
Relation::Thread(thread) => {
|
Relation::Thread(thread) => {
|
||||||
determine_interaction_context_for_room_event_related_to_thread(
|
determine_interaction_context_for_room_event_related_to_thread(
|
||||||
bot_user_id,
|
bot_user_id,
|
||||||
|
bot_display_name,
|
||||||
room,
|
room,
|
||||||
current_event,
|
current_event,
|
||||||
event_fetcher,
|
event_fetcher,
|
||||||
@@ -329,6 +331,7 @@ pub async fn determine_interaction_context_for_room_event(
|
|||||||
|
|
||||||
async fn determine_interaction_context_for_room_event_related_to_thread(
|
async fn determine_interaction_context_for_room_event_related_to_thread(
|
||||||
bot_user_id: &OwnedUserId,
|
bot_user_id: &OwnedUserId,
|
||||||
|
bot_display_name: &Option<String>,
|
||||||
room: &Room,
|
room: &Room,
|
||||||
current_event: &OriginalSyncRoomMessageEvent,
|
current_event: &OriginalSyncRoomMessageEvent,
|
||||||
event_fetcher: &Arc<RoomEventFetcher>,
|
event_fetcher: &Arc<RoomEventFetcher>,
|
||||||
@@ -389,6 +392,7 @@ async fn determine_interaction_context_for_room_event_related_to_thread(
|
|||||||
thread_start_timeline_event,
|
thread_start_timeline_event,
|
||||||
thread_info.clone(),
|
thread_info.clone(),
|
||||||
bot_user_id,
|
bot_user_id,
|
||||||
|
bot_display_name,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let Some(detailed_message_payload) = thread_start_detailed_message_payload else {
|
let Some(detailed_message_payload) = thread_start_detailed_message_payload else {
|
||||||
@@ -431,6 +435,7 @@ async fn determine_interaction_context_for_room_event_related_to_reply(
|
|||||||
fn is_event_mentioning_bot(
|
fn is_event_mentioning_bot(
|
||||||
event_content: &RoomMessageEventContent,
|
event_content: &RoomMessageEventContent,
|
||||||
bot_user_id: &OwnedUserId,
|
bot_user_id: &OwnedUserId,
|
||||||
|
bot_display_name: &Option<String>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Some(mentions) = &event_content.mentions {
|
if let Some(mentions) = &event_content.mentions {
|
||||||
mentions
|
mentions
|
||||||
@@ -445,12 +450,17 @@ fn is_event_mentioning_bot(
|
|||||||
// As of 2024-10-03, at least Element iOS does not support the new Mentions specification
|
// As of 2024-10-03, at least Element iOS does not support the new Mentions specification
|
||||||
// and is still quite widespread.
|
// and is still quite widespread.
|
||||||
//
|
//
|
||||||
// It may be even better to match not only against the MXID, but also against the bot's
|
|
||||||
// room-specific display name.
|
|
||||||
//
|
|
||||||
// We may consider dropping this string-matching behavior altogether in the future,
|
// We may consider dropping this string-matching behavior altogether in the future,
|
||||||
// so improving this compatibility block is not a high priority.
|
// so improving this compatibility block is not a high priority.
|
||||||
event_content.body().contains(bot_user_id.as_str())
|
if event_content.body().contains(bot_user_id.as_str()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(bot_display_name) = bot_display_name {
|
||||||
|
return event_content.body().contains(bot_display_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,6 +469,7 @@ fn timeline_event_to_detailed_message_payload(
|
|||||||
timeline_event: TimelineEvent,
|
timeline_event: TimelineEvent,
|
||||||
thread_info: ThreadInfo,
|
thread_info: ThreadInfo,
|
||||||
bot_user_id: &OwnedUserId,
|
bot_user_id: &OwnedUserId,
|
||||||
|
bot_display_name: &Option<String>,
|
||||||
) -> anyhow::Result<Option<DetailedMessagePayload>> {
|
) -> anyhow::Result<Option<DetailedMessagePayload>> {
|
||||||
let timeline_event_deserialized = match timeline_event.event.deserialize() {
|
let timeline_event_deserialized = match timeline_event.event.deserialize() {
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
@@ -510,8 +521,11 @@ fn timeline_event_to_detailed_message_payload(
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_mentioning_bot =
|
let is_mentioning_bot = is_event_mentioning_bot(
|
||||||
is_event_mentioning_bot(&room_message_original.content, bot_user_id);
|
&room_message_original.content,
|
||||||
|
bot_user_id,
|
||||||
|
bot_display_name,
|
||||||
|
);
|
||||||
|
|
||||||
(is_mentioning_bot, room_message_payload)
|
(is_mentioning_bot, room_message_payload)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ pub struct MessageContext {
|
|||||||
admin_whitelist_regexes: Vec<regex::Regex>,
|
admin_whitelist_regexes: Vec<regex::Regex>,
|
||||||
trigger_event_info: TriggerEventInfo,
|
trigger_event_info: TriggerEventInfo,
|
||||||
thread_info: ThreadInfo,
|
thread_info: ThreadInfo,
|
||||||
|
|
||||||
|
bot_display_name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageContext {
|
impl MessageContext {
|
||||||
@@ -31,9 +33,20 @@ impl MessageContext {
|
|||||||
admin_whitelist_regexes,
|
admin_whitelist_regexes,
|
||||||
trigger_event_info,
|
trigger_event_info,
|
||||||
thread_info,
|
thread_info,
|
||||||
|
|
||||||
|
bot_display_name: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_bot_display_name(mut self, value: Option<String>) -> Self {
|
||||||
|
self.bot_display_name = value;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bot_display_name(&self) -> &Option<String> {
|
||||||
|
&self.bot_display_name
|
||||||
|
}
|
||||||
|
|
||||||
pub fn room(&self) -> &Room {
|
pub fn room(&self) -> &Room {
|
||||||
&self.room
|
&self.room
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user