Skip to content

fix: convert telegram audio files into a Record component - #9702

Open
Trainingcqy wants to merge 1 commit into
AstrBotDevs:masterfrom
Trainingcqy:fix/telegram-audio
Open

fix: convert telegram audio files into a Record component#9702
Trainingcqy wants to merge 1 commit into
AstrBotDevs:masterfrom
Trainingcqy:fix/telegram-audio

Conversation

@Trainingcqy

@Trainingcqy Trainingcqy commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

When a music or audio file, that is audio, is sent to the Bot on Telegram, the message is silently dropped and the Bot gives no response. The cause is that convert_message() in tg_adapter.py only handles types such as text in turn, and audio is not among them. As a result the message chain and message_str are both empty, and the flow stops at skip llm request in agent_sub_stages/internal.py. The Bot does not react; if the audio content is then asked about, the model gives an unrelated answer.

Modifications / 改动点

astrbot/core/platform/sources/telegram/tg_adapter.py:

  • Add an audio branch in convert_message() that produces a Comp.Record and calls _apply_caption().

tests/fixtures/helpers.py:

  • Add an audio parameter to create_mock_update().

tests/test_telegram_adapter.py:

  • Add a test case covering the creation of the Record component and the handling of the caption.

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

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

Observation point Before After
tg_adapter.py message dump audio=Audio(...) audio=Audio(...)
event_bus.py message outline empty [ComponentType.Record]
agent_sub_stages/internal.py skip llm request ready to request llm provider
MediaModality.AUDIO on the provider side absent token_count=2000

The message dump on the Telegram side contains the complete audio=Audio(...) both before and after the change, which shows that the audio data itself arrives intact and is dropped inside the adapter. After the change an AUDIO modality appears in the usage statistics returned by the provider, confirming that the audio entered the model through the multimodal channel.

修复前截图
Log before

The audio message is dropped after it arrives, and no request is produced:

[15:32:21.722] [Core] [DBUG] [telegram.tg_adapter:427]: Telegram message: Message(audio=Audio(_duration=datetime.timedelta(seconds=80), api_kwargs={'thumb': {'file_id': 'AAMCBAADGQEAA3JqgAd7XPnA7G9LhiWk13GsceHScAACkyEAAq_KAVAAAR_elEBjKlYBAAdtAAM9BA', 'file_unique_id': 'AQADkyEAAq_KAVBy', 'file_size': 4289, 'width': 132, 'height': 132}}, file_id='CQACAgQAAxkBAANyaoAHe1z5wOxvS4YlpNdxrHHh0nAAApMhAAKvygFQAAEf3pRAYypWPQQ', file_name='Ennio Morricone - Toto and Alfredo.mp3', file_size=3235600, file_unique_id='AgADkyEAAq_KAVA', mime_type='audio/mpeg', performer='Ennio Morricone', thumbnail=PhotoSize(file_id='AAMCBAADGQEAA3JqgAd7XPnA7G9LhiWk13GsceHScAACkyEAAq_KAVAAAR_elEBjKlYBAAdtAAM9BA', file_size=4289, file_unique_id='AQADkyEAAq_KAVBy', height=132, width=132), title='Toto and Alfredo'), channel_chat_created=False, chat=Chat(first_name='testuser', id=100000000, type=<ChatType.PRIVATE>), date=datetime.datetime(2026, 8, 15, 6, 32, 20, tzinfo=datetime.timezone.utc), delete_chat_photo=False, from_user=User(first_name='testuser', id=100000000, is_bot=False, language_code='zh-hans'), group_chat_created=False, message_id=121, supergroup_chat_created=False)
[15:32:21.723] [Core] [INFO] [core.event_bus:74]: [default] [telegram(telegram)] Unknown/100000000:
[15:32:21.723] [Core] [DBUG] [waking_check.stage:165]: enabled_plugins_name: ['*']
[15:32:21.723] [Core] [DBUG] [method.star_request:46]: plugin -> astrbot - handle_session_control_agent
[15:32:21.723] [Core] [DBUG] [method.star_request:46]: plugin -> astrbot - handle_empty_mention
[15:32:21.723] [Core] [DBUG] [method.star_request:46]: plugin -> astrbot - persist_group_message
[15:32:21.723] [Core] [DBUG] [method.star_request:46]: plugin -> astrbot - on_message
[15:32:21.723] [Core] [DBUG] [agent_sub_stages.internal:190]: skip llm request: empty message and no provider_request
[15:32:21.723] [Core] [DBUG] [pipeline.scheduler:97]: pipeline execution completed.

The audio content is then asked about, and that request is sent normally:

[15:32:27.843] [Core] [DBUG] [telegram.tg_adapter:427]: Telegram message: Message(channel_chat_created=False, chat=Chat(first_name='testuser', id=100000000, type=<ChatType.PRIVATE>), date=datetime.datetime(2026, 8, 15, 6, 32, 26, tzinfo=datetime.timezone.utc), delete_chat_photo=False, from_user=User(first_name='testuser', id=100000000, is_bot=False, language_code='zh-hans'), group_chat_created=False, message_id=122, supergroup_chat_created=False, text='描述音频内容')
[15:32:27.844] [Core] [INFO] [core.event_bus:74]: [default] [telegram(telegram)] Unknown/100000000: 描述音频内容
[15:32:27.844] [Core] [DBUG] [waking_check.stage:165]: enabled_plugins_name: ['*']
[15:32:27.844] [Core] [DBUG] [method.star_request:46]: plugin -> astrbot - handle_session_control_agent
[15:32:27.844] [Core] [DBUG] [method.star_request:46]: plugin -> astrbot - handle_empty_mention
[15:32:27.845] [Core] [DBUG] [method.star_request:46]: plugin -> astrbot - persist_group_message
[15:32:27.845] [Core] [DBUG] [method.star_request:46]: plugin -> astrbot - on_message
[15:32:27.845] [Core] [DBUG] [agent_sub_stages.internal:193]: ready to request llm provider
[15:32:29.170] [Core] [DBUG] [agent_sub_stages.internal:221]: acquired session lock for llm request

Request construction and response body are omitted here; below are the usage statistics of that response

)] create_time=None model_version='gemini-3.6-flash' prompt_feedback=None response_id='_QeAasqwD6K12roPyqm6iQ4' usage_metadata=GenerateContentResponseUsageMetadata(
  candidates_token_count=36,
  prompt_token_count=3286,
  prompt_tokens_details=[
    ModalityTokenCount(
      modality=<MediaModality.TEXT: 'TEXT'>,
      token_count=3286
    ),
  ],
  thoughts_token_count=142,
  total_token_count=3464
) model_status=None automatic_function_calling_history=None parsed=None

prompt_tokens_details contains only TEXT, so the audio is not in the context of that request.

修复后截图
Log after

The same audio file is converted into a Comp.Record and triggers the request directly:

[15:38:49.831] [Core] [DBUG] [telegram.tg_adapter:427]: Telegram message: Message(audio=Audio(_duration=datetime.timedelta(seconds=80), api_kwargs={'thumb': {'file_id': 'AAMCBAADGQEAA3JqgAd7XPnA7G9LhiWk13GsceHScAACkyEAAq_KAVAAAR_elEBjKlYBAAdtAAM9BA', 'file_unique_id': 'AQADkyEAAq_KAVBy', 'file_size': 4289, 'width': 132, 'height': 132}}, file_id='CQACAgQAAxkBAANyaoAHe1z5wOxvS4YlpNdxrHHh0nAAApMhAAKvygFQAAEf3pRAYypWPQQ', file_name='Ennio Morricone - Toto and Alfredo.mp3', file_size=3235600, file_unique_id='AgADkyEAAq_KAVA', mime_type='audio/mpeg', performer='Ennio Morricone', thumbnail=PhotoSize(file_id='AAMCBAADGQEAA3JqgAd7XPnA7G9LhiWk13GsceHScAACkyEAAq_KAVAAAR_elEBjKlYBAAdtAAM9BA', file_size=4289, file_unique_id='AQADkyEAAq_KAVBy', height=132, width=132), title='Toto and Alfredo'), channel_chat_created=False, chat=Chat(first_name='testuser', id=100000000, type=<ChatType.PRIVATE>), date=datetime.datetime(2026, 8, 15, 6, 38, 48, tzinfo=datetime.timezone.utc), delete_chat_photo=False, from_user=User(first_name='testuser', id=100000000, is_bot=False, language_code='zh-hans'), group_chat_created=False, message_id=126, supergroup_chat_created=False)
[15:38:57.451] [Core] [DBUG] [utils.media_utils:1187]: Audio converted successfully: C:\Users\user\Desktop\AstrBot-repro\data\temp\file_17.mp3 -> C:\Users\user\Desktop\AstrBot-repro\data\temp\media_audio_20260815153856913_bc9a.wav
[15:38:57.452] [Core] [INFO] [core.event_bus:74]: [default] [telegram(telegram)] Unknown/100000000: [ComponentType.Record]
[15:38:57.453] [Core] [DBUG] [waking_check.stage:165]: enabled_plugins_name: ['*']
[15:38:57.464] [Core] [DBUG] [method.star_request:46]: plugin -> astrbot - handle_session_control_agent
[15:38:57.465] [Core] [DBUG] [method.star_request:46]: plugin -> astrbot - handle_empty_mention
[15:38:57.465] [Core] [DBUG] [method.star_request:46]: plugin -> astrbot - persist_group_message
[15:38:57.465] [Core] [DBUG] [method.star_request:46]: plugin -> astrbot - on_message
[15:38:57.465] [Core] [DBUG] [agent_sub_stages.internal:193]: ready to request llm provider
[15:38:58.801] [Core] [DBUG] [agent_sub_stages.internal:221]: acquired session lock for llm request

Request construction and response body are omitted here; below are the usage statistics of that response

)] create_time=None model_version='gemini-3.6-flash' prompt_feedback=None response_id='iAmAav6YLsP_2roPvZ2xiQI' usage_metadata=GenerateContentResponseUsageMetadata(
  candidates_token_count=203,
  prompt_token_count=5341,
  prompt_tokens_details=[
    ModalityTokenCount(
      modality=<MediaModality.TEXT: 'TEXT'>,
      token_count=3341
    ),
    ModalityTokenCount(
      modality=<MediaModality.AUDIO: 'AUDIO'>,
      token_count=2000
    ),
  ],
  thoughts_token_count=387,
  total_token_count=5931
) model_status=None automatic_function_calling_history=None parsed=None

An AUDIO modality appears in prompt_tokens_details, so the audio has entered the context of that request.


Checklist / 检查清单

  • 😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
    / 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。

  • 👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
    / 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”

  • 🤓 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.
    / 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到 requirements.txtpyproject.toml 文件相应位置。

  • 😮 My changes do not introduce malicious code.
    / 我的更改没有引入恶意代码。

Summary by Sourcery

Handle Telegram Bot audio messages by converting them into Record components so they participate in LLM requests.

New Features:

  • Support Telegram audio messages as Record components in the platform adapter so audio can be sent to the LLM along with captions.

Bug Fixes:

  • Fix dropped Telegram audio messages where no provider request was previously created.
  • Ensure captions on Telegram audio messages populate both the aggregated message string and a Plain text component.

Tests:

  • Add helper fixture support for Telegram audio messages.
  • Add tests verifying conversion of Telegram audio messages into Record components and proper handling of captions.

@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. area:platform The bug / feature is about IM platform adapter, such as QQ, Lark, Telegram, WebChat and so on. labels Aug 15, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="astrbot/core/platform/sources/telegram/tg_adapter.py" line_range="595-597" />
<code_context>
+            # Audio files use their own Bot API field and do not fall back to document.
+            file = await update.message.audio.get_file()
+
+            file_basename = os.path.basename(cast(str, file.file_path))
+            temp_dir = get_astrbot_temp_path()
+            temp_path = os.path.join(temp_dir, file_basename)
+            await download_file(cast(str, file.file_path), path=temp_path)
+            path_wav = await MediaResolver(
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Using `file_basename` directly in the temp path can cause collisions between different audio files.

Because `temp_path` is derived only from `temp_dir` and `file_basename`, two messages with identically named audio files (or the same file processed concurrently) will overwrite each other in the same temp location. This risks race conditions and incorrect audio being processed when handling messages in parallel. Please include a unique component in the filename (e.g., message/update ID or a UUID) to guarantee per-message isolation.

```suggestion
            file_basename = os.path.basename(cast(str, file.file_path))
            temp_dir = get_astrbot_temp_path()
            # Include chat and message identifiers to avoid filename collisions between different messages/chats.
            temp_path = os.path.join(
                temp_dir,
                f"{update.effective_chat.id}_{update.message.message_id}_{file_basename}",
            )
```
</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.

Comment on lines +595 to +597
file_basename = os.path.basename(cast(str, file.file_path))
temp_dir = get_astrbot_temp_path()
temp_path = os.path.join(temp_dir, file_basename)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion (bug_risk): Using file_basename directly in the temp path can cause collisions between different audio files.

Because temp_path is derived only from temp_dir and file_basename, two messages with identically named audio files (or the same file processed concurrently) will overwrite each other in the same temp location. This risks race conditions and incorrect audio being processed when handling messages in parallel. Please include a unique component in the filename (e.g., message/update ID or a UUID) to guarantee per-message isolation.

Suggested change
file_basename = os.path.basename(cast(str, file.file_path))
temp_dir = get_astrbot_temp_path()
temp_path = os.path.join(temp_dir, file_basename)
file_basename = os.path.basename(cast(str, file.file_path))
temp_dir = get_astrbot_temp_path()
# Include chat and message identifiers to avoid filename collisions between different messages/chats.
temp_path = os.path.join(
temp_dir,
f"{update.effective_chat.id}_{update.message.message_id}_{file_basename}",
)

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. size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant