Skip to content

Commit bad34e3

Browse files
ernadoclaude
andcommitted
feat(rich): support Bot API 10.1 rich messages
Add SendRichMessage / SendRichHTML / SendRichMarkdown, sending structured page-block content via gotd/td's message/rich package and the sender's RichMessage builder. Demonstrate in the advanced example (/rich, /richhtml), document in the guide, note in the changelog. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent c19ca43 commit bad34e3

4 files changed

Lines changed: 115 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ messages follow [Conventional Commits](https://www.conventionalcommits.org/).
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- **Rich messages** (Bot API 10.1) — `SendRichMessage`/`SendRichHTML`/
13+
`SendRichMarkdown` send structured page-block content built with
14+
`github.com/gotd/td/telegram/message/rich`.
15+
1016
## [0.1.0] - 2026-06-14
1117

1218
`botapi` was rebuilt from a codegen-first OpenAPI/ogen project into a

docs/guide.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,31 @@ bot.SendMessage(ctx, chat, "*bold* _italic_ ||spoiler||",
101101
botapi.WithParseMode(botapi.ParseModeMarkdownV2))
102102
```
103103

104+
## Rich messages
105+
106+
Beyond formatted text, Telegram supports **rich messages** (Bot API 10.1):
107+
structured content — headings, paragraphs, lists, tables, block quotes, media,
108+
math — as a tree of page blocks rather than a flat string with entity ranges.
109+
Build the content with `github.com/gotd/td/telegram/message/rich` and send it
110+
with `SendRichMessage`:
111+
112+
```go
113+
import "github.com/gotd/td/telegram/message/rich"
114+
115+
msg := rich.New(
116+
rich.Heading1(rich.Plain("Title")),
117+
rich.Paragraph(rich.Bold(rich.Plain("Hello"))),
118+
).Input()
119+
bot.SendRichMessage(ctx, chat, msg)
120+
```
121+
122+
For a whole HTML or Markdown document (parsed server-side), use the shortcuts:
123+
124+
```go
125+
bot.SendRichHTML(ctx, chat, "<h1>Title</h1><p>Body</p>")
126+
bot.SendRichMarkdown(ctx, chat, "# Title\n\nBody")
127+
```
128+
104129
## Keyboards
105130

106131
`ReplyMarkup` is a sealed union: `*InlineKeyboardMarkup`,

examples/advanced/main.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121

2222
"go.uber.org/zap"
2323

24+
"github.com/gotd/td/telegram/message/rich"
25+
2426
"github.com/gotd/botapi"
2527
)
2628

@@ -88,6 +90,31 @@ func registerCommands(bot *botapi.Bot) {
8890
return err
8991
})
9092

93+
// A rich message (Bot API 10.1): structured page-block content built with
94+
// the gotd/td rich package.
95+
bot.OnCommand("rich", "Send a structured rich message", func(c *botapi.Context) error {
96+
chat, _ := c.Chat()
97+
msg := rich.New(
98+
rich.Heading1(rich.Plain("Rich messages")),
99+
rich.Paragraph(rich.Concat(
100+
rich.Plain("They carry "),
101+
rich.Bold(rich.Plain("headings")),
102+
rich.Plain(", "),
103+
rich.Italic(rich.Plain("paragraphs")),
104+
rich.Plain(" and more — a tree of blocks, not a flat string."),
105+
)),
106+
rich.Preformatted(rich.Plain("bot.SendRichMessage(ctx, chat, msg)"), "go"),
107+
).Input()
108+
_, err := c.Bot.SendRichMessage(c, chat, msg)
109+
return err
110+
})
111+
112+
bot.OnCommand("richhtml", "Send a rich message from HTML", func(c *botapi.Context) error {
113+
chat, _ := c.Chat()
114+
_, err := c.Bot.SendRichHTML(c, chat, "<h1>From HTML</h1><p>Parsed by Telegram into a <b>rich</b> message.</p>")
115+
return err
116+
})
117+
91118
bot.OnCommand("keyboard", "Show an inline keyboard with callbacks", func(c *botapi.Context) error {
92119
_, err := c.Reply("Pick one:", botapi.WithReplyMarkup(demoInlineKeyboard()))
93120
return err
@@ -370,6 +397,8 @@ const helpText = `<b>Advanced demo bot</b>
370397
Commands:
371398
/html — HTML formatting
372399
/md — MarkdownV2 formatting
400+
/rich — structured rich message (page blocks)
401+
/richhtml — rich message from HTML
373402
/keyboard — inline keyboard + callbacks
374403
/removekbd — remove the reply keyboard
375404
/photo — send a photo by URL

rich.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package botapi
2+
3+
import (
4+
"context"
5+
6+
"github.com/gotd/td/telegram/message/rich"
7+
"github.com/gotd/td/tg"
8+
)
9+
10+
// SendRichMessage sends a rich message (Bot API 10.1): structured content —
11+
// headings, paragraphs, lists, tables, block quotes, media, math and more — as
12+
// a tree of page blocks rather than a flat string with entity ranges.
13+
//
14+
// Build the content with github.com/gotd/td/telegram/message/rich, for example:
15+
//
16+
// msg := rich.New(
17+
// rich.Heading1(rich.Plain("Title")),
18+
// rich.Paragraph(rich.Bold(rich.Plain("Hello"))),
19+
// ).Input()
20+
// bot.SendRichMessage(ctx, chat, msg)
21+
//
22+
// For whole-document HTML or Markdown, prefer SendRichHTML / SendRichMarkdown.
23+
// The usual SendOptions (reply, silent, protect, reply markup) apply.
24+
func (b *Bot) SendRichMessage(ctx context.Context, chat ChatID, msg tg.InputRichMessageClass, opts ...SendOption) (*Message, error) {
25+
var cfg sendConfig
26+
for _, o := range opts {
27+
o(&cfg)
28+
}
29+
30+
peer, err := b.resolveInputPeer(ctx, chat)
31+
if err != nil {
32+
return nil, err
33+
}
34+
35+
builder := &b.sender.To(peer).Builder
36+
builder, err = b.applySendConfig(builder, cfg)
37+
if err != nil {
38+
return nil, err
39+
}
40+
41+
resp, err := builder.RichMessage(ctx, msg)
42+
return b.sentMessage(ctx, peer, resp, err)
43+
}
44+
45+
// SendRichHTML sends a rich message whose content is the given HTML document,
46+
// parsed by Telegram's servers.
47+
func (b *Bot) SendRichHTML(ctx context.Context, chat ChatID, html string, opts ...SendOption) (*Message, error) {
48+
return b.SendRichMessage(ctx, chat, rich.HTML(html), opts...)
49+
}
50+
51+
// SendRichMarkdown sends a rich message whose content is the given Markdown
52+
// document, parsed by Telegram's servers.
53+
func (b *Bot) SendRichMarkdown(ctx context.Context, chat ChatID, markdown string, opts ...SendOption) (*Message, error) {
54+
return b.SendRichMessage(ctx, chat, rich.Markdown(markdown), opts...)
55+
}

0 commit comments

Comments
 (0)