Add block and media support to sendRichMessage - #438
Open
FernandoWerneck-VibX wants to merge 5 commits into
Open
Add block and media support to sendRichMessage#438FernandoWerneck-VibX wants to merge 5 commits into
FernandoWerneck-VibX wants to merge 5 commits into
Conversation
InputRichMessage only exposed html/markdown, so rich messages could not be described as blocks nor carry embedded media. Two lower-level defects blocked adding them: - RichBlock/RichText declare their `type` discriminator as a computed property, which Gson does not serialize, and the registered adapters were deserializers only. Every block sent would have gone out without a type. - SendRichMessage inherits isMultipart() == false from AbstractSendRequest, so a block referencing a freshly uploaded file would serialize an attach:// URL with no matching multipart part. editMessageText, which already accepted an InputRichMessage, had the same defect. Adds the InputRichBlock hierarchy (21 blocks plus InputRichBlockListItem), InputRichMessageMedia and the missing InputMediaVoiceNote; makes the rich text/block adapters serialize their discriminator; and collects uploads lazily at send time, so a rich message populated after the request was built is still uploaded. Also adds Kotlin DSL extensions for sendRichMessage and sendRichMessageDraft. ModelTest needed prefab InputMedia values: EqualsVerifier cannot instantiate InputMedia because of its final self-typed field. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012tbomWzUs3YpXUn61Rwg17
The collect-once guard defeated the point of collecting lazily: anything that read isMultipart() or getParameters() before the mutable InputRichMessage was populated — logging, for instance — froze the request as non-multipart, and re-sending a request after adding media kept sending attach:// references with no file parts. RichMessageAttachments.refresh now rescans on every call and drops the parts left over from the previous scan, so replacing a block also removes its stale part. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012tbomWzUs3YpXUn61Rwg17
sendRichMessageDraft cannot upload new files. Collecting attachments for it made the request multipart and sent attach:// parts that Telegram rejects. There is no legitimate case to collect either: every InputMedia.addAttachment caller takes a File or a byte array, so an already uploaded thumbnail never shows up there. The draft now stays non-multipart and fails fast when its media would need an upload, instead of building a request that cannot succeed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012tbomWzUs3YpXUn61Rwg17
The API states, for the rich_message parameter of editMessageText, that "direct upload of new files isn't supported when an inline message is edited". Collecting attachments unconditionally made those edits multipart, producing a request Telegram rejects. EditMessageText now tracks whether it targets an inline message and fails fast on media that would need an upload, as sendRichMessageDraft already does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012tbomWzUs3YpXUn61Rwg17
Add block and media support to sendRichMessage
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Completes the Bot API 10.1 rich message sending surface.
InputRichMessagenow supportsblocksandmediain addition tohtml/markdown, and rich messages carrying uploaded files work acrosssendRichMessage,sendRichMessageDraftandeditMessageText.Changes
Input block models — new package
model.request.richmessages.inputrichblock: theInputRichBlockinterface, its 21 concrete blocks andInputRichBlockListItem. PlusInputRichMessageMedia, andInputMediaVoiceNote, which was missing and is required byInputRichBlockVoiceNote.Type constants are reused from
RichBlockTyperather than duplicated, and blocks reference the existing received types where the API specifies them (RichText,RichBlockCaption,RichBlockTableCell,Location).Serialization —
RichBlockandRichTextimplementations declare theirtypediscriminator as a computed property, which Gson does not serialize, and the registered adapters wereJsonDeserializeronly.RichTextTypeAdapterandRichBlockTypeAdapternow also implementJsonSerializer, and a newInputRichBlockSerializercovers the input hierarchy. Each delegates to the concrete runtime type and adds the discriminator back:This does not recurse — the adapter is registered against the interface, while
src.javaClassresolves to the concrete class's reflective adapter.RichTextkeeps the two special cases that mirror how it is parsed:RichTextPlainserializes as a bare string,RichTextArrayas an array.Multipart —
SendRichMessageinheritsisMultipart() == falsefromAbstractSendRequest, so blocks holding uploads had no plumbing.RichMessageAttachmentswalksmediaandblocks, descending intolist,blockquote,collage,slideshowanddetails, and collects theattach://mapping from eachInputMedia.It runs from
isMultipart()/getParameters(), both of whichTelegramBotClientreads at send time, and rescans on every call, dropping the parts left over from the previous scan. UnlikeSendMediaGroup, which collects in its constructor, this means a rich message populated after the request was built is still uploaded, replacing a block also removes its stale part, and re-sending a request picks up media added in between.Where the API forbids uploads, the request stays non-multipart and fails fast instead of building a payload Telegram would reject:
sendRichMessageDraft— "Direct upload of new files isn't supported."editMessageTexttargeting an inline message — "Direct upload of new files isn't supported when an inline message is edited."editMessageText — already accepted an
InputRichMessage; it now collects attachments the same way.Kotlin DSL —
sendRichMessageandsendRichMessageDraftextensions, followingSendMessageExtension.kt.ModelTest — added prefab
InputMediavalues. EqualsVerifier cannot instantiateInputMediabecause of its final self-typedthisAsTfield, so every new model holding one failed.Testing
17 unit tests in
RichMessageRequestTestcovering the discriminator of every block type, snake_case field names, rich text serialization, nested blocks, and attachment collection — nested, message-level, post-construction mutation, block replacement, the non-multipart case, and both upload-rejection paths../gradlew clean check -PprTestpasses on JDK 11.