Skip to content

Commit 6bc18c4

Browse files
committed
fix(telegram): include reply context in prompts
1 parent e82c725 commit 6bc18c4

3 files changed

Lines changed: 38 additions & 3 deletions

File tree

ductor_bot/messenger/telegram/app.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
handle_command,
4747
handle_interrupt,
4848
handle_new_session,
49+
merge_reply_context,
4950
strip_mention,
5051
)
5152
from ductor_bot.messenger.telegram.media import (
@@ -1407,7 +1408,10 @@ async def _resolve_text(self, message: Message) -> str | None:
14071408
)
14081409
if not message.text:
14091410
return None
1410-
return strip_mention(message.text, self._bot_username)
1411+
text = strip_mention(message.text, self._bot_username)
1412+
reply = message.reply_to_message
1413+
reply_text = None if reply is None else (reply.text or reply.caption)
1414+
return merge_reply_context(text, reply_text)
14111415

14121416
async def _handle_streaming(
14131417
self, message: Message, key: SessionKey, text: str, *, thread_id: int | None = None

ductor_bot/messenger/telegram/handlers.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,12 @@ def strip_mention(text: str, bot_username: str | None) -> str:
203203
stripped = (text[:idx] + text[idx + len(tag) :]).strip()
204204
return stripped or text
205205
return text
206+
207+
208+
def merge_reply_context(text: str, reply_text: str | None) -> str:
209+
"""Combine the user's message with replied-to text when present."""
210+
message_text = text.strip()
211+
quoted = (reply_text or "").strip()
212+
if not quoted:
213+
return message_text
214+
return f"[REPLY TO]\n{quoted}\n\n[USER MESSAGE]\n{message_text}"

tests/messenger/telegram/test_app.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ def _make_message(
100100
type(msg).message_id = PropertyMock(return_value=message_id)
101101
msg.text = text
102102
msg.answer = AsyncMock(return_value=msg)
103+
msg.reply_to_message = None
104+
msg.entities = None
105+
msg.caption = None
106+
msg.caption_entities = None
103107

104108
user = MagicMock(spec=User)
105109
user.id = user_id
@@ -501,7 +505,7 @@ async def test_returns_early_for_none_text(self) -> None:
501505
@patch("ductor_bot.messenger.telegram.app.strip_mention", return_value="clean text")
502506
async def test_strips_mention_from_text(self, mock_strip: MagicMock) -> None:
503507
tg_bot, _ = _make_tg_bot()
504-
tg_bot.bot_instance_username = "testbot"
508+
tg_bot._bot_username = "testbot"
505509
orch = _make_orchestrator()
506510
tg_bot._orchestrator = orch
507511

@@ -525,12 +529,30 @@ async def test_strips_mention_from_text(self, mock_strip: MagicMock) -> None:
525529
class TestResolveText:
526530
async def test_plain_text_message(self) -> None:
527531
tg_bot, _ = _make_tg_bot()
528-
tg_bot.bot_instance_username = "mybot"
532+
tg_bot._bot_username = "mybot"
529533
tg_bot._orchestrator = _make_orchestrator()
530534
msg = _make_message(text="Hello")
531535
result = await tg_bot._resolve_text(msg)
532536
assert result == "Hello"
533537

538+
async def test_reply_includes_replied_message_text(self) -> None:
539+
tg_bot, _ = _make_tg_bot()
540+
tg_bot._bot_username = "mybot"
541+
tg_bot._orchestrator = _make_orchestrator()
542+
543+
msg = _make_message(text="@mybot what do you think?", chat_type="group")
544+
reply = MagicMock(spec=Message)
545+
reply.text = "Original message text"
546+
reply.caption = None
547+
msg.reply_to_message = reply
548+
549+
result = await tg_bot._resolve_text(msg)
550+
551+
assert result == (
552+
"[REPLY TO]\nOriginal message text\n\n"
553+
"[USER MESSAGE]\nwhat do you think?"
554+
)
555+
534556
async def test_none_when_no_text_and_no_media(self) -> None:
535557
tg_bot, _ = _make_tg_bot()
536558
tg_bot._orchestrator = _make_orchestrator()

0 commit comments

Comments
 (0)