platforms.emoji_resolver module
Resolve custom emojis from Discord and Matrix into image Attachments.
Custom emojis are platform-specific rich content that arrives as text
tokens (Discord <:name:id>) or HTML <img> tags (Matrix). This
module extracts them from message text, downloads the images, and
returns Attachment objects so the LLM can
see the emojis as inline PNG images.
Both Discord and Matrix adapters call into these shared utilities from
their on_message handlers.
- class platforms.emoji_resolver.DiscordEmojiMatch(name, emoji_id, animated, full_match)[source]
Bases:
objectAn immutable record of one custom emoji parsed from Discord text.
Captures everything needed to both download a custom emoji’s image and rewrite the original
<:name:id>(or animated<a:name:id>) token in the message body. Instances are produced byextract_discord_emojis()(which deduplicates by id) and consumed byrewrite_discord_emoji_text()and_download_one_discord_emoji(); being frozen, they are safe to share across the parallel download fan-out.
- platforms.emoji_resolver.extract_discord_emojis(text)[source]
Find the unique custom emojis in a message, in first-seen order.
Scans the text for Discord custom-emoji tokens (
<:name:id>and the animated<a:name:id>form) usingDISCORD_EMOJI_REand returns oneDiscordEmojiMatchper distinct emoji id, so a repeated emoji is downloaded and rewritten only once. This is the entry point of the resolve-emojis-as-images flow, telling the caller both what to fetch and what to rewrite. Pure string processing with no I/O.Called by the Discord bot adapter (
platforms/discord.py) and the selfbot adapter (platforms/discord_self.py) in theiron_messagepaths whenresolve_emojis_as_imagesis enabled; also exercised bytests/test_emoji_resolver.py.- Parameters:
text (
str) – The raw message body to scan for custom-emoji tokens.- Returns:
One match per unique emoji id, ordered by first appearance; empty when the text contains no custom emojis.
- Return type:
- platforms.emoji_resolver.rewrite_discord_emoji_text(text, matches)[source]
Swap raw custom-emoji tokens for readable
[emoji: name]placeholders.Rewrites the message body so that the opaque
<:name:id>tokens become human- and LLM-legible[emoji: name]markers, which is paired with attaching the emoji images: the model reads the name in context while also seeing the actual picture as an inline attachment. Replaces by exact token text (full_match) so only the emojis the caller chose to resolve are touched. Pure string processing with no I/O.Called by the Discord bot adapter (
platforms/discord.py) and the selfbot adapter (platforms/discord_self.py) right after their emoji images are downloaded; also covered bytests/test_emoji_resolver.py.- Parameters:
text (
str) – The message body to rewrite.matches (
list[DiscordEmojiMatch]) – The emojis to replace (typically the subset that was actually downloaded as images).
- Returns:
The text with each matched token replaced by
[emoji: name].- Return type:
- async platforms.emoji_resolver.download_discord_emojis(matches, *, max_emojis=5, media_cache=None)[source]
Download up to
max_emojisDiscord custom emojis concurrently.Caps the work at
max_emojis(to bound how many images a single message can pull) and fetches the chosen emojis in parallel, returning only the ones that succeeded so a few bad emojis never sink the batch. This is the download half of the resolve-emojis-as-images flow whose matches come fromextract_discord_emojis().Fans out one
_download_one_discord_emoji()task per emoji viaasyncio.gather()(withreturn_exceptions=Trueso a failure is isolated, not raised), threading the optionalmedia_cachethrough to each so cached emoji bytes are reused. Called by the Discord bot adapter (platforms/discord.py) and the selfbot adapter (platforms/discord_self.py) whenresolve_emojis_as_imagesis enabled; no internal callers.- Parameters:
matches (
list[DiscordEmojiMatch]) – Candidate emojis to download (usually fromextract_discord_emojis()).max_emojis (
int) – Maximum number of emojis to fetch from the front ofmatches(default5).media_cache (
Any|None) – Optional cache exposingget_or_downloadto dedupe repeated downloads.
- Returns:
The successfully downloaded emoji attachments; failures and the over-the-limit tail are omitted.
- Return type:
- class platforms.emoji_resolver.MatrixEmojiMatch(alt_text, mxc_url, full_tag)[source]
Bases:
objectAn immutable record of one custom emoji parsed from Matrix HTML.
Captures what is needed to both download a Matrix custom emoji and rewrite its shortcode in the plain-text body. Instances are produced by
extract_matrix_emojis()(deduplicated bymxc://URL) and consumed byrewrite_matrix_emoji_text()anddownload_matrix_emojis(); being frozen, they are safe to share across the parallel download fan-out.
- platforms.emoji_resolver.extract_matrix_emojis(formatted_body)[source]
Find the unique custom emojis embedded in a Matrix HTML body.
Scans a Matrix message’s
formatted_bodyfor inline emoji<img>tags whosesrcis anmxc://URI (using_MATRIX_EMOJI_IMG_RE), pulling thealttext from each (falling back to"emoji") and deduplicating by URI so each emoji is fetched and rewritten once. This is the Matrix-side entry point of the resolve-emojis-as-images flow. Pure string processing with no I/O.Called by the Matrix adapter (
platforms/matrix.py) in its message path when emoji resolution is enabled; also exercised bytests/test_emoji_resolver.py.- Parameters:
formatted_body (
str) – The Matrix HTMLformatted_bodyto scan.- Returns:
One match per unique
mxc://URL, ordered by first appearance; empty when no emoji images are present.- Return type:
- platforms.emoji_resolver.rewrite_matrix_emoji_text(body, matches)[source]
Swap Matrix emoji shortcodes in the body for
[emoji: name]markers.Rewrites the plain-text body so the legible emoji name survives next to the inline image attachment shown to the LLM. Matrix clients typically put the shortcode (e.g.
:wave:) in the plain-text body, so this strips the surrounding colons from each emoji’salttext and wraps it in descriptive bracket notation, replacing only the first occurrence of each shortcode. Pure string processing with no I/O.Called by the Matrix adapter (
platforms/matrix.py) after its emoji images are downloaded; also covered bytests/test_emoji_resolver.py.- Parameters:
body (
str) – The plain-text message body to rewrite.matches (
list[MatrixEmojiMatch]) – The emojis whose shortcodes should be replaced.
- Returns:
The body with each matched shortcode replaced by
[emoji: name]; unchanged when no shortcode is present.- Return type:
- async platforms.emoji_resolver.download_matrix_emojis(matches, matrix_client, *, max_emojis=5, media_cache=None)[source]
Download up to
max_emojisMatrix custom emojis concurrently.Caps the work at
max_emojisand fetches the chosen emojis in parallel from the Matrix homeserver, returning only those that succeeded so a few failures never sink the batch. This is the download half of the Matrix resolve-emojis-as-images flow whose matches come fromextract_matrix_emojis().Fans out the inner
_download_onecoroutine per emoji viaasyncio.gather()(withreturn_exceptions=True), where each task fetches media through the matrix-nioAsyncClient.download()method against the homeserver’smxc://URIs and wraps the bytes in anAttachment. The optionalmedia_cacheis threaded through so previously fetched emoji bytes are reused on a hit. Importsnio.responses.DownloadErrorto detect download failures. Called by the Matrix adapter (platforms/matrix.py) when emoji resolution is enabled; no internal callers.- Parameters:
matches (
list[MatrixEmojiMatch]) – Candidate emojis to download (usually fromextract_matrix_emojis()).matrix_client (
Any) – The matrix-nioAsyncClientused to fetch media from the homeserver.max_emojis (
int) – Maximum number of emojis to fetch from the front ofmatches(default5).media_cache (
Any|None) – Optional cache exposingget_or_downloadto dedupe repeated downloads.
- Returns:
The successfully downloaded emoji attachments; failures and the over-the-limit tail are omitted.
- Return type: