Behaviour for channel-specific mention detection and parsing.
Mention detection varies significantly across platforms. This behaviour defines how channels can implement platform-specific mention parsing while providing normalized output for the messaging pipeline.
Mention Structure
Parsed mentions follow a consistent structure:
%{
user_id: "123456789", # Platform's user ID
username: "johndoe", # Username (may be nil)
offset: 0, # Byte offset in the message body
length: 8 # Length of the mention text
}Implementation
Channels should implement this behaviour to enable mention detection:
defmodule MyApp.Channels.Telegram.Mentions do
@behaviour Jido.Chat.Adapters.Mentions
@impl true
def parse_mentions(body, raw) do
entities = raw["entities"] || []
entities
|> Enum.filter(&(&1["type"] == "mention" or &1["type"] == "text_mention"))
|> Enum.map(fn entity ->
%{
user_id: to_string(entity["user"]["id"]),
username: entity["user"]["username"],
offset: entity["offset"],
length: entity["length"]
}
end)
end
@impl true
def was_mentioned?(raw, bot_id) do
entities = raw["entities"] || []
Enum.any?(entities, fn e ->
e["type"] == "text_mention" and to_string(e["user"]["id"]) == bot_id
end)
end
endIntegration with MsgContext
The MsgContext struct includes fields populated by mention adapters:
was_mentioned- Boolean indicating if the bot was mentionedmentions- List of parsed mention maps
Default Implementations
All callbacks are optional:
parse_mentions/2- Returns[]if not implementedstrip_mentions/2- Returns the original body if not implementedwas_mentioned?/2- Returnsfalseif not implemented
Summary
Callbacks
Parses mentions from a message body and raw payload.
Strips mentions from a message body.
Checks if the bot was mentioned in the message.
Functions
Default implementation for stripping mentions from text.
Checks if a module implements the Mentions behaviour.
Normalizes mention maps into canonical format.
Safely parses mentions for a module.
Safely strips mentions for a module.
Safely checks if the bot was mentioned for a module.
Types
@type mention() :: %{ user_id: String.t(), username: String.t() | nil, offset: non_neg_integer(), length: non_neg_integer() }
Callbacks
Parses mentions from a message body and raw payload.
Parameters
body- The text content of the messageraw- The raw platform-specific message payload
Returns
A list of mention maps with :user_id, :username, :offset, and :length.
Strips mentions from a message body.
Useful for getting clean text content without mention markers.
Parameters
body- The text content of the messagementions- List of parsed mentions fromparse_mentions/2
Returns
The message body with mention text removed or replaced.
Checks if the bot was mentioned in the message.
Parameters
raw- The raw platform-specific message payloadbot_id- The bot's user ID on the platform
Returns
true if the bot was mentioned, false otherwise.
Functions
Default implementation for stripping mentions from text.
Removes mention text by offset/length, processing from end to start to preserve offsets.
Examples
mentions = [%{offset: 0, length: 5, user_id: "1", username: nil}]
Mentions.default_strip_mentions("@john hello", mentions)
# => " hello"
Checks if a module implements the Mentions behaviour.
Normalizes mention maps into canonical format.
Invalid entries are ignored. Output is sorted by offset/length and de-duplicated.
Safely parses mentions for a module.
Returns an empty list if the module doesn't implement the callback.
Safely strips mentions for a module.
Returns the original body if the module doesn't implement the callback.
Safely checks if the bot was mentioned for a module.
Returns false if the module doesn't implement the callback.