hermes-agent/gateway/platforms/qqbot
WideLee 5b121c6e35 feat(qqbot): process attachments in quoted (reply) messages
When a user replies while quoting another message, QQ sets
'message_type = 103' and pushes the referenced message's content +
attachments inside 'msg_elements[0]'. The old adapter ignored
msg_elements entirely, so:

- Bare quote-replies (no user text) surfaced nothing to the LLM.
- Quoted images/files/voice were never downloaded or described.
- Quoted voice messages specifically produced no transcript — the model
  had no way to see what the user was referring to when saying 'about
  this voice note…'.

This commit adds _process_quoted_context(d) which extracts msg_elements,
unions their attachments, and runs them through the SAME
_process_attachments pipeline as the main message body. Quoted voice
gets an STT transcript (tried via QQ's asr_refer_text first, then the
configured STT provider); quoted images get cached just like main-body
images; quoted files surface with their original filename intact (not
the CDN URL hash).

The quoted content is prepended to the user's text as a '[Quoted message]:'
block so the LLM sees the full referential context on one turn.
Images-only quotes surface a '[Quoted message]: (image)' marker so the
model knows an image was referenced even if no text came with it.

All four inbound handlers (_handle_c2c_message, _handle_group_message,
_handle_guild_message, _handle_dm_message) now call the helper uniformly
— one merge pattern, not four divergent implementations.

Filename preservation is carried by _process_attachments' existing
'[Attachment: {filename or ct}]' line; nothing else needed for that.

12 new tests under TestProcessQuotedContext and TestMergeQuoteInto cover:

- Non-quote messages short-circuit to empty
- message_type=103 with no msg_elements is harmless
- Text-only quotes render with '[Quoted message]:' prefix
- Voice attachments in the quote flow through STT
- File attachments in the quote preserve the original filename
- Image attachments surface cached paths + media types
- Images-only quote still emits a marker
- Multiple msg_elements are concatenated
- Malformed message_type values return empty
- _merge_quote_into prepends with a blank-line separator

Full qqbot suite: 130 passed (72 existing + 19 chunked + 27 keyboards
+ 12 quoted).

Co-authored-by: WideLee <limkuan24@gmail.com>
2026-05-07 07:36:30 -07:00
..
__init__.py feat(qqbot): add inline-keyboard approvals and update prompts 2026-05-07 07:36:30 -07:00
adapter.py feat(qqbot): process attachments in quoted (reply) messages 2026-05-07 07:36:30 -07:00
chunked_upload.py feat(qqbot): add chunked upload with structured error types 2026-05-07 07:36:30 -07:00
constants.py refactor(qqbot): split qqbot.py into package & add QR scan-to-configure onboard flow 2026-04-17 15:31:14 -07:00
crypto.py refactor(qqbot): split qqbot.py into package & add QR scan-to-configure onboard flow 2026-04-17 15:31:14 -07:00
keyboards.py feat(qqbot): add inline-keyboard approvals and update prompts 2026-05-07 07:36:30 -07:00
onboard.py refactor(qqbot): migrate qr onboard flow to sync + consolidate into onboard.py 2026-04-22 05:50:21 -07:00
utils.py refactor(qqbot): split qqbot.py into package & add QR scan-to-configure onboard flow 2026-04-17 15:31:14 -07:00