feat(telegram): add overflow split mode (#101)

This commit is contained in:
banteg
2026-01-12 18:17:12 +04:00
committed by GitHub
parent 04671593aa
commit 9d5fccab92
9 changed files with 363 additions and 8 deletions
+11 -1
View File
@@ -1,4 +1,4 @@
from takopi.telegram.render import render_markdown
from takopi.telegram.render import render_markdown, split_markdown_body
def test_render_markdown_basic_entities() -> None:
@@ -18,3 +18,13 @@ def test_render_markdown_code_fence_language_is_string() -> None:
assert entities is not None
assert any(e.get("type") == "pre" and e.get("language") == "py" for e in entities)
assert any(e.get("type") == "code" for e in entities)
def test_split_markdown_body_closes_and_reopens_fence() -> None:
body = "```py\n" + ("line\n" * 10) + "```\n\npost"
chunks = split_markdown_body(body, max_chars=40)
assert len(chunks) > 1
assert chunks[0].rstrip().endswith("```")
assert chunks[1].startswith("```py\n")
+69
View File
@@ -32,6 +32,7 @@ from takopi.telegram.bridge import (
send_with_resume,
)
from takopi.telegram.client import BotClient
from takopi.telegram.render import MAX_BODY_CHARS
from takopi.telegram.topic_state import TopicStateStore, resolve_state_path
from takopi.context import RunContext
from takopi.config import ProjectConfig, ProjectsConfig
@@ -486,6 +487,26 @@ def test_telegram_presenter_final_clears_button() -> None:
assert rendered.extra["reply_markup"]["inline_keyboard"] == []
def test_telegram_presenter_split_overflow_adds_followups() -> None:
presenter = TelegramPresenter(message_overflow="split")
state = ProgressTracker(engine="codex").snapshot()
rendered = presenter.render_final(
state,
elapsed_s=0.0,
status="done",
answer="x" * (MAX_BODY_CHARS + 10),
)
followups = rendered.extra.get("followups")
assert followups
assert all(isinstance(item, RenderedMessage) for item in followups)
assert rendered.extra["reply_markup"]["inline_keyboard"] == []
assert all(
item.extra["reply_markup"]["inline_keyboard"] == [] for item in followups
)
@pytest.mark.anyio
async def test_telegram_transport_passes_replace_and_wait() -> None:
bot = _FakeBot()
@@ -532,6 +553,54 @@ async def test_telegram_transport_passes_reply_markup() -> None:
assert bot.edit_calls[0]["reply_markup"] == markup
@pytest.mark.anyio
async def test_telegram_transport_sends_followups() -> None:
bot = _FakeBot()
transport = TelegramTransport(bot)
reply = MessageRef(channel_id=123, message_id=10)
followup = RenderedMessage(text="part 2")
await transport.send(
channel_id=123,
message=RenderedMessage(text="part 1", extra={"followups": [followup]}),
options=SendOptions(reply_to=reply, notify=False, thread_id=7),
)
assert len(bot.send_calls) == 2
assert bot.send_calls[1]["text"] == "part 2"
assert bot.send_calls[1]["reply_to_message_id"] == 10
assert bot.send_calls[1]["message_thread_id"] == 7
assert bot.send_calls[1]["replace_message_id"] is None
assert bot.send_calls[1]["disable_notification"] is True
@pytest.mark.anyio
async def test_telegram_transport_edits_and_sends_followups() -> None:
bot = _FakeBot()
transport = TelegramTransport(bot)
followup = RenderedMessage(text="part 2")
await transport.edit(
ref=MessageRef(channel_id=123, message_id=42),
message=RenderedMessage(
text="part 1",
extra={
"followups": [followup],
"followup_reply_to_message_id": 10,
"followup_thread_id": 7,
"followup_notify": False,
},
),
)
assert len(bot.edit_calls) == 1
assert len(bot.send_calls) == 1
assert bot.send_calls[0]["text"] == "part 2"
assert bot.send_calls[0]["reply_to_message_id"] == 10
assert bot.send_calls[0]["message_thread_id"] == 7
assert bot.send_calls[0]["disable_notification"] is True
@pytest.mark.anyio
async def test_telegram_transport_edit_wait_false_returns_ref() -> None:
class _OutboxBot(BotClient):