main
py 152 lines 4.63 KB
Raw
1 import asyncio
2
3 from plugins._telegram_integration.helpers import draft_stream
4 from plugins._telegram_integration.helpers.constants import (
5 CTX_TG_BOT,
6 CTX_TG_CHAT_ID,
7 CTX_TG_PROGRESS_LINES,
8 CTX_TG_PROGRESS_MESSAGE_ID,
9 CTX_TG_REPLY_TO,
10 CTX_TG_RESPONSE_MESSAGE_ID,
11 )
12
13
14 class FakeBot:
15 class Bot:
16 token = "token"
17
18 bot = Bot()
19
20
21 class FakeContext:
22 def __init__(self):
23 self.data = {
24 CTX_TG_BOT: "main",
25 CTX_TG_CHAT_ID: 123,
26 CTX_TG_REPLY_TO: 456,
27 }
28
29 def get_data(self, key):
30 return self.data.get(key)
31
32
33 def test_intermediate_response_sends_separate_non_reply_message(monkeypatch):
34 calls = []
35
36 async def fake_send(token, chat_id, text, reply_to_message_id=None, parse_mode="HTML", reply_markup=None):
37 calls.append(
38 {
39 "token": token,
40 "chat_id": chat_id,
41 "text": text,
42 "reply_to_message_id": reply_to_message_id,
43 "parse_mode": parse_mode,
44 "reply_markup": reply_markup,
45 }
46 )
47 return 789
48
49 context = FakeContext()
50 monkeypatch.setattr(draft_stream, "_bot_instance", lambda ctx: FakeBot())
51 monkeypatch.setattr(draft_stream.tc, "raw_send_text", fake_send)
52
53 sent = asyncio.run(
54 draft_stream.send_intermediate_response(
55 context,
56 "**Working** on the brief.",
57 keyboard=[[{"text": "Open", "callback_data": "open"}]],
58 )
59 )
60
61 assert sent is True
62 assert calls == [
63 {
64 "token": "token",
65 "chat_id": 123,
66 "text": "<b>Working</b> on the brief.",
67 "reply_to_message_id": None,
68 "parse_mode": "HTML",
69 "reply_markup": {"inline_keyboard": [[{"text": "Open", "callback_data": "open"}]]},
70 }
71 ]
72 assert CTX_TG_RESPONSE_MESSAGE_ID not in context.data
73
74
75 def test_intermediate_response_finalizes_active_stream_and_starts_next_tool_group(monkeypatch):
76 calls = []
77 next_message_id = 100
78
79 async def fake_send(token, chat_id, text, reply_to_message_id=None, parse_mode="HTML", reply_markup=None):
80 nonlocal next_message_id
81 calls.append(
82 {
83 "method": "send",
84 "text": text,
85 "reply_to_message_id": reply_to_message_id,
86 "parse_mode": parse_mode,
87 "reply_markup": reply_markup,
88 "message_id": next_message_id,
89 }
90 )
91 next_message_id += 1
92 return next_message_id - 1
93
94 async def fake_edit(token, chat_id, message_id, text, parse_mode="HTML", reply_markup=None):
95 calls.append(
96 {
97 "method": "edit",
98 "message_id": message_id,
99 "text": text,
100 "parse_mode": parse_mode,
101 "reply_markup": reply_markup,
102 }
103 )
104 return True
105
106 context = FakeContext()
107 monkeypatch.setattr(draft_stream, "_bot_instance", lambda ctx: FakeBot())
108 monkeypatch.setattr(draft_stream.tc, "raw_send_text", fake_send)
109 monkeypatch.setattr(draft_stream.tc, "raw_edit_text", fake_edit)
110
111 asyncio.run(draft_stream.add_tool_start(context, "search_engine", {"query": "telegram bot api"}))
112 asyncio.run(draft_stream.update_response(context, "Found the docs."))
113 sent = asyncio.run(draft_stream.send_intermediate_response(context, "Found the docs."))
114 asyncio.run(draft_stream.add_tool_start(context, "read_file", {"path": "notes.md"}))
115
116 assert sent is True
117 assert calls == [
118 {
119 "method": "send",
120 "text": "🔎 search engine: telegram bot api",
121 "reply_to_message_id": None,
122 "parse_mode": None,
123 "reply_markup": None,
124 "message_id": 100,
125 },
126 {
127 "method": "send",
128 "text": "Found the docs.",
129 "reply_to_message_id": 456,
130 "parse_mode": "HTML",
131 "reply_markup": None,
132 "message_id": 101,
133 },
134 {
135 "method": "edit",
136 "message_id": 101,
137 "text": "Found the docs.",
138 "parse_mode": "HTML",
139 "reply_markup": None,
140 },
141 {
142 "method": "send",
143 "text": "📖 read file: notes.md",
144 "reply_to_message_id": None,
145 "parse_mode": None,
146 "reply_markup": None,
147 "message_id": 102,
148 },
149 ]
150 assert context.data[CTX_TG_PROGRESS_MESSAGE_ID] == 102
151 assert context.data[CTX_TG_PROGRESS_LINES] == ["📖 read file: notes.md"]
152 assert CTX_TG_RESPONSE_MESSAGE_ID not in context.data