Skip to content

Added RichBlock (half) and RichText stuff#2602

Open
coder2020official wants to merge 7 commits into
eternnoir:masterfrom
coder2020official:botapi101
Open

Added RichBlock (half) and RichText stuff#2602
coder2020official wants to merge 7 commits into
eternnoir:masterfrom
coder2020official:botapi101

Conversation

@coder2020official

@coder2020official coder2020official commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Rich Messages

Join Request Queries

Polls

@coder2020official

Copy link
Copy Markdown
Collaborator Author

Added RichText stuff and half of RichBlock classes

This could've been more simplified (e.g. by having text in the init of the base class), but I chose not to display and confuse people for some classes that don't have the text attribute, for example.

Long way to go, I hope I'm on the right way

@coder2020official coder2020official marked this pull request as ready for review June 23, 2026 16:48
@coder2020official

Copy link
Copy Markdown
Collaborator Author

@Badiboy I think I'm done, but I will double-check & test things tomorrow; you can, however, start reviewing the code

@Badiboy

Badiboy commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

@Badiboy I think I'm done, but I will double-check & test things tomorrow; you can, however, start reviewing the code

Thank you for your work!! I do not think I can do it before weekend, but I'll do my best.

@ranjitsingha

ranjitsingha commented Jun 30, 2026

Copy link
Copy Markdown

@coder2020official Tried the botapi101 branch with AsyncTeleBot and hit two issues using send_rich_message. Sharing in case it helps:

1. Async send_rich_message raises TypeError on every call

AsyncTeleBot.send_rich_message forwards message_thread_id to asyncio_helper.send_rich_message:

await asyncio_helper.send_rich_message(
    self.token, chat_id, rich_message,
    business_connection_id=..., message_thread_id=message_thread_id,
    direct_messages_topic_id=..., ...)

but asyncio_helper.send_rich_message(...) has no message_thread_id parameter, so every call fails with:

TypeError: send_rich_message() got an unexpected keyword argument 'message_thread_id'

(The sync apihelper.send_rich_message has the same parameter mismatch.)

2. Parsing the response crashes on plain-string rich text

After working around (1), Message.de_json of the sendRichMessage result throws whenever a rich-text node is a plain string:

File ".../telebot/types.py", in RichText.de_json
    obj = cls.check_json(json_string)
ValueError: json_type should be a json dict or string.

Per the docs, RichText can be a plain str ("either a String for plain text, an Array of RichText, or any of the following types"), but RichText.de_json always calls check_json, which can't handle a bare string. So any successfully-sent rich message containing plain text fails to deserialize. RichText.de_json should pass str (and the array case) through instead of forcing check_json.

Minimal repro (async): await bot.send_rich_message(chat_id, types.InputRichMessage(html="<b>hi</b>")).

@coder2020official

Copy link
Copy Markdown
Collaborator Author

Hi!

Thanks for noting that--I have fixed your issue exactly; however, I am yet to address RichText being an array of RichText. I will have to test and see how it will look like.

And I'm not sure my current implementation is safe. It seems to work, though.

@coder2020official

Copy link
Copy Markdown
Collaborator Author

This should hypothetically work for arrays. Not really having the time to test--would be amazing if you could play around

@ranjitsingha

ranjitsingha commented Jul 1, 2026

Copy link
Copy Markdown

@coder2020official — your fix works. Confirmed on dee734d: send_rich_message no longer TypeErrors, and the plain-string RichText parse is resolved.

One thing worth flagging separately, because I don't think it was obvious from how I first framed it (my original report was only about the send path): the same RichText.de_json bug also hits the receive path, where the blast radius is much larger.

When a rich_message arrives in an update — e.g. a user simply forwards a rich message to the bot, or forwards one of the bot's own rich messages back — it's parsed by Update.de_jsonMessage.de_jsonRichMessage.de_json. On the async poller that runs inside the polling loop, and the exception is raised before the offset is advanced. So a single unparseable rich_message update:

  • crashes on every get_updates cycle on the same update,
  • never advances past it,
  • stalls the whole bot — no updates of any type are processed until the poison update is manually skipped.

In effect it's a remotely-triggerable poller stall: anyone can send/forward rich content to any polling bot and freeze it — even if the bot never sends rich messages itself. That's actually how I hit it: an inbound forward, not a send.

# no server needed to reproduce the crash Update.de_json would hit:
from telebot.types import RichText
RichText.de_json({"type": "bold", "text": "Detail"})   # pre-fix: JSONDecodeError

7b99c65 fixes the specific string-leaf case, so the common trigger is gone. 👍 The reason I'm raising it anyway: you noted RichBlock support is still "half", and that the array handling in dee734d is untested / you're "not sure it's safe". Given the receive-side blast radius above, any rich node type that isn't yet handled will resurface the same full-poller stall — not just a failed send.

So it may be worth making the receive/parse path fail-safe while the block classes are being finished: if RichMessage.de_json can't parse something, drop it to None and keep the rest of the Message intact (bots that don't consume rich_message lose nothing), rather than letting the error propagate up and jam get_updates. That decouples "incomplete rich parser" from "bot stops entirely".

@ranjitsingha

ranjitsingha commented Jul 1, 2026

Copy link
Copy Markdown

@coder2020official — one more of the same family (like the earlier send_rich_message / message_thread_id mismatch you fixed in 7b99c65): send_rich_message_draft raises TypeError on every call.

AsyncTeleBot.send_rich_message_draft forwards business_connection_id to the helper:

return await asyncio_helper.send_rich_message_draft(
    self.token, chat_id, draft_id, rich_message,
    message_thread_id=message_thread_id, business_connection_id=business_connection_id)

but asyncio_helper.send_rich_message_draft has no such parameter:

async def send_rich_message_draft(token, chat_id, draft_id, rich_message, message_thread_id=None):

so every call fails with:

TypeError: send_rich_message_draft() got an unexpected keyword argument 'business_connection_id'

Minimal repro (async):

await bot.send_rich_message_draft(chat_id, 1, types.InputRichMessage(html="<tg-thinking>hi</tg-thinking>"))

The sync apihelper.send_rich_message_draft(token, chat_id, draft_id, rich_message, message_thread_id=None) has the same missing parameter, so the sync TeleBot method hits it too.

Suggested fix: add business_connection_id=None to both the async and sync send_rich_message_draft helpers and include it in the payload when set (mirroring how send_rich_message handles it).

I worked around it by calling the helper directly, and the draft itself streams fine once that's bypassed.

@coder2020official

Copy link
Copy Markdown
Collaborator Author

sendrichmessagedraft shouldn't even have business connection id

@coder2020official

Copy link
Copy Markdown
Collaborator Author

I tried forwarding a rich message to the bot and there were no issues

@ranjitsingha

Copy link
Copy Markdown

I tried forwarding a rich message to the bot and there were no issues

It was fixed in dee734d

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants