Skip to content

fix: handle Telegram Voice_messages_forbidden with typed exception and text caption#5204

Merged
Soulter merged 1 commit intoAstrBotDevs:masterfrom
911218sky:refactor/telegram-voice-forbidden-handler
Feb 18, 2026
Merged

fix: handle Telegram Voice_messages_forbidden with typed exception and text caption#5204
Soulter merged 1 commit intoAstrBotDevs:masterfrom
911218sky:refactor/telegram-voice-forbidden-handler

Conversation

@911218sky
Copy link
Contributor

@911218sky 911218sky commented Feb 18, 2026

The duplicated Voice_messages_forbidden handling in send_with_client and send_streaming was fragile (bare Exception + string matching) and hard to maintain. This PR consolidates it into a single helper with proper typed exception handling.

Modifications / 改动点

  • �strbot/core/platform/sources/telegram/tg_event.py: Extracted _send_voice_with_fallback helper to deduplicate voice forbidden fallback logic. Catches elegram.error.BadRequest instead of bare Exception. Added empty chat_id guard in _send_chat_action.

  • �strbot/core/message/components.py: Added optional ext field to Record to preserve TTS source text.

  • �strbot/core/pipeline/result_decorate/stage.py: Store original plain text into Record.text during TTS conversion, so it can be used as document caption on fallback.

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

Tested with a Telegram user whose privacy settings forbid voice messages.
image


Checklist / 检查清单

  • 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 我的更改经过了良好的测试,并已在上方提供了「验证步骤」和「运行截图」。/ My changes have been well-tested, and Verification Steps and Screenshots have been provided above.
  • 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
  • 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

@auto-assign auto-assign bot requested review from Soulter and anka-afk February 18, 2026 12:07
@dosubot dosubot bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Feb 18, 2026
@dosubot
Copy link

dosubot bot commented Feb 18, 2026

Related Documentation

Checked 1 published document(s) in 1 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 1 个问题,并给出了一些整体层面的反馈:

  • _send_voice_with_fallback 中的 "Voice_messages_forbidden" 字面量现在是一个对行为至关重要的判别条件;建议将其(以及可能的错误类型)提取为具名常量或辅助函数,这样可以让与 Telegram API 错误字符串之间的耦合关系更加清晰,也更方便在上游文案变更时进行修改。
  • _send_voice_with_fallback 中对 BadRequest 的处理假定 e.message 始终是包含 API 错误的字符串;你可能需要通过 str(e)getattr(e, "message", "") 进行防御性标准化,以避免在该属性缺失或结构不同的边缘情况下出错。
  • _send_voice_with_fallback 里关于 use_media_action 的分支是重复的(send_voice/send_document 都有带 media-action 和不带 media-action 的分支);可以考虑将公共的调用模式抽取到一个小的内部辅助函数中,以减少重复代码,并降低这些分支随着时间推移产生差异的风险。
面向 AI 代理的提示词
请根据以下代码审查意见进行修改:

## 整体评论
- `_send_voice_with_fallback` 中的 `"Voice_messages_forbidden"` 字面量现在是一个对行为至关重要的判别条件;建议将其(以及可能的错误类型)提取为具名常量或辅助函数,这样可以让与 Telegram API 错误字符串之间的耦合关系更加清晰,也更方便在上游文案变更时进行修改。
- `_send_voice_with_fallback` 中对 `BadRequest` 的处理假定 `e.message` 始终是包含 API 错误的字符串;你可能需要通过 `str(e)``getattr(e, "message", "")` 进行防御性标准化,以避免在该属性缺失或结构不同的边缘情况下出错。
- `_send_voice_with_fallback` 里关于 `use_media_action` 的分支是重复的(`send_voice`/`send_document` 都有带 media-action 和不带 media-action 的分支);可以考虑将公共的调用模式抽取到一个小的内部辅助函数中,以减少重复代码,并降低这些分支随着时间推移产生差异的风险。

## 单条评论

### 评论 1
<location> `astrbot/core/platform/sources/telegram/tg_event.py:178-153` </location>
<code_context>
+                    **cast(Any, payload),
+                )
+            else:
+                await client.send_document(
+                    document=path,
+                    caption=caption,
+                    **cast(Any, payload),
+                )
+
</code_context>

<issue_to_address>
**issue (bug_risk):** 在回退路径中同时传入 `caption``**payload`,存在重复 `caption` 关键字参数的风险。

在回退分支中,你调用的是 `send_document(document=path, caption=caption, **payload)`。如果 `payload` 中包含 `caption` 键,就会因为同一个参数传入多次而抛出 `TypeError`。可以在这个调用前从 `payload` 中移除 `caption`,或者只通过 `payload` 传入 `caption`,并去掉单独的 `caption` 参数。对 `_send_media_with_action` 路径同样需要考虑这一点,因为它也会同时把 `caption``**payload` 传给 `client.send_document`。
</issue_to_address>

Sourcery 对开源项目免费——如果你觉得我们的审查有价值,欢迎帮忙分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据这些反馈改进后续的审查。
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • The "Voice_messages_forbidden" literal in _send_voice_with_fallback is now a behavior-critical discriminator; consider extracting it (and possibly the error type) into a named constant or helper to make the coupling to the Telegram API error string more explicit and easier to change if the upstream wording shifts.
  • The BadRequest handling in _send_voice_with_fallback assumes e.message is always a string containing the API error; you may want to defensively normalize via str(e) or getattr(e, "message", "") to avoid edge cases where the attribute is missing or structured differently.
  • The duplicated branching for use_media_action in _send_voice_with_fallback (send_voice/send_document both having media-action and non-media-action variants) could be simplified by factoring the common call pattern into a small internal helper to reduce repetition and the chance of the branches diverging over time.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `"Voice_messages_forbidden"` literal in `_send_voice_with_fallback` is now a behavior-critical discriminator; consider extracting it (and possibly the error type) into a named constant or helper to make the coupling to the Telegram API error string more explicit and easier to change if the upstream wording shifts.
- The `BadRequest` handling in `_send_voice_with_fallback` assumes `e.message` is always a string containing the API error; you may want to defensively normalize via `str(e)` or `getattr(e, "message", "")` to avoid edge cases where the attribute is missing or structured differently.
- The duplicated branching for `use_media_action` in `_send_voice_with_fallback` (`send_voice`/`send_document` both having media-action and non-media-action variants) could be simplified by factoring the common call pattern into a small internal helper to reduce repetition and the chance of the branches diverging over time.

## Individual Comments

### Comment 1
<location> `astrbot/core/platform/sources/telegram/tg_event.py:178-153` </location>
<code_context>
+                    **cast(Any, payload),
+                )
+            else:
+                await client.send_document(
+                    document=path,
+                    caption=caption,
+                    **cast(Any, payload),
+                )
+
</code_context>

<issue_to_address>
**issue (bug_risk):** Passing both `caption` and `**payload` risks a duplicate `caption` kwarg in the fallback path.

In the fallback branch you call `send_document(document=path, caption=caption, **payload)`. If `payload` ever includes a `caption` key, this will raise a `TypeError` for multiple values. Either remove `caption` from `payload` before this call, or pass `caption` only via `payload` and drop the separate `caption` argument. The same consideration applies to the `_send_media_with_action` path that forwards both `caption` and `**payload` to `client.send_document`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

user_name=user_name,
message_thread_id=message_thread_id,
voice=path,
**cast(Any, payload),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 在回退路径中同时传入 caption**payload,存在重复 caption 关键字参数的风险。

在回退分支中,你调用的是 send_document(document=path, caption=caption, **payload)。如果 payload 中包含 caption 键,就会因为同一个参数传入多次而抛出 TypeError。可以在这个调用前从 payload 中移除 caption,或者只通过 payload 传入 caption,并去掉单独的 caption 参数。对 _send_media_with_action 路径同样需要考虑这一点,因为它也会同时把 caption**payload 传给 client.send_document

Original comment in English

issue (bug_risk): Passing both caption and **payload risks a duplicate caption kwarg in the fallback path.

In the fallback branch you call send_document(document=path, caption=caption, **payload). If payload ever includes a caption key, this will raise a TypeError for multiple values. Either remove caption from payload before this call, or pass caption only via payload and drop the separate caption argument. The same consideration applies to the _send_media_with_action path that forwards both caption and **payload to client.send_document.

@dosubot dosubot bot added the area:platform The bug / feature is about IM platform adapter, such as QQ, Lark, Telegram, WebChat and so on. label Feb 18, 2026
@911218sky 911218sky changed the title refactor: extract Voice_messages_forbidden fallback into shared helper with typed BadRequest exception fix: show tts text as caption when telegram voice message is forbidden Feb 18, 2026
@911218sky 911218sky changed the title fix: show tts text as caption when telegram voice message is forbidden fix: handle Telegram Voice_messages_forbidden with typed exception and text caption Feb 18, 2026
…r with typed BadRequest exception

- Add _send_voice_with_fallback helper to deduplicate voice forbidden handling
- Catch telegram.error.BadRequest instead of bare Exception with string matching
- Add text field to Record component to preserve TTS source text
- Store original text in Record during TTS conversion for use as document caption
- Skip _send_chat_action when chat_id is empty to avoid unnecessary warnings
@911218sky 911218sky force-pushed the refactor/telegram-voice-forbidden-handler branch from bbaaf5c to 7a8f77c Compare February 18, 2026 12:24
@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Feb 18, 2026
@Soulter Soulter merged commit a2b61e2 into AstrBotDevs:master Feb 18, 2026
6 checks passed
united-pooh pushed a commit to united-pooh/AstrBot that referenced this pull request Feb 19, 2026
…r with typed BadRequest exception (AstrBotDevs#5204)

- Add _send_voice_with_fallback helper to deduplicate voice forbidden handling
- Catch telegram.error.BadRequest instead of bare Exception with string matching
- Add text field to Record component to preserve TTS source text
- Store original text in Record during TTS conversion for use as document caption
- Skip _send_chat_action when chat_id is empty to avoid unnecessary warnings
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:platform The bug / feature is about IM platform adapter, such as QQ, Lark, Telegram, WebChat and so on. lgtm This PR has been approved by a maintainer size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments