Files
hermes-agent/tests/gateway/test_telegram_text_link_expansion.py
teknium1 d7ceee19a8 refactor(telegram): move text_link expansion to telegram_entities sibling
The adapter facade is ~6.6k lines; new behaviour belongs in a topical sibling per the
facade+siblings layout. expand_link_entities() now lives in telegram_entities.py and
reuses the encode/decode UTF-16 slicing the adapter already uses for entity spans.

Also: skip inlining when the anchor text already is the URL (no 'url (url)' duplication),
trim the test file to the invariants and point it at the sibling.
2026-09-13 20:58:39 -07:00

106 lines
3.5 KiB
Python

"""Tests for Telegram ``text_link`` entity expansion in inbound messages.
Telegram delivers a URL attached to a word (e.g. "тут" -> github.com) as a
``text_link`` entity. The visible text carries no URL, so without expansion the
model only ever sees the bare word and cannot fetch the link. ``expand_link_entities``
inlines the real URL right after its anchor for both ``text`` and ``caption``.
"""
import pytest
from plugins.platforms.telegram.telegram_entities import expand_link_entities
class _Entity:
def __init__(self, type, offset, length, url=None):
self.type = type
self.offset = offset
self.length = length
self.url = url
class _Message:
def __init__(self, text=None, caption=None, entities=None, caption_entities=None):
self.text = text
self.caption = caption
self.entities = entities
self.caption_entities = caption_entities
def test_hidden_link_in_word_is_inlined():
msg = _Message(
text="Ссылка: тут\n#tag",
entities=[_Entity("text_link", 8, 3, "https://github.com/Cysharp/R3")],
)
out = expand_link_entities(msg)
assert "https://github.com/Cysharp/R3" in out
assert out.startswith("Ссылка: тут (https://github.com/Cysharp/R3)")
def test_caption_link_on_media_is_inlined():
msg = _Message(
caption="Смотри тут проект",
caption_entities=[_Entity("text_link", 7, 3, "https://example.com/x")],
)
assert expand_link_entities(msg) == "Смотри тут (https://example.com/x) проект"
def test_utf16_offset_is_respected_after_emoji():
# Telegram entity offsets are measured in UTF-16 code units. The emoji is
# two units, so the visible anchor starts at offset 3, not Python index 2.
msg = _Message(
text="🔥 тут",
entities=[_Entity("text_link", 3, 3, "https://example.com/emoji")],
)
assert expand_link_entities(msg) == "🔥 тут (https://example.com/emoji)"
def test_expansion_is_idempotent():
msg = _Message(
text="Ссылка: тут\n#tag",
entities=[_Entity("text_link", 8, 3, "https://github.com/Cysharp/R3")],
)
out = expand_link_entities(msg)
repeat = _Message(text=out, entities=[_Entity("text_link", 8, 3, "https://github.com/Cysharp/R3")])
assert expand_link_entities(repeat) == out
@pytest.mark.parametrize(
"entity",
[
_Entity("text_link", 1, 99, "https://example.com/past-end"),
_Entity("text_link", 0, 1, 123),
_Entity("text_link", "invalid", 1, "https://example.com/bad-offset"),
],
)
def test_malformed_link_entities_are_ignored(entity):
msg = _Message(text="abc", entities=[entity])
assert expand_link_entities(msg) == "abc"
def test_text_does_not_use_caption_entities():
msg = _Message(
text="plain text",
caption="linked caption",
caption_entities=[_Entity("text_link", 0, 6, "https://example.com/caption")],
)
assert expand_link_entities(msg) == "plain text"
def test_offset_inside_utf16_surrogate_pair_is_ignored():
msg = _Message(
text="🔥 link",
entities=[_Entity("text_link", 1, 1, "https://example.com/mid-surrogate")],
)
assert expand_link_entities(msg) == "🔥 link"
def test_anchor_that_is_already_the_url_is_not_duplicated():
url = "https://example.com/self"
msg = _Message(text=f"see {url} now", entities=[_Entity("text_link", 4, len(url), url)])
assert expand_link_entities(msg) == f"see {url} now"