Skip to content

fix: preserve qq official quoted message context#9164

Merged
Soulter merged 3 commits into
masterfrom
codex/qqofficial-quoted-messages
Jul 6, 2026
Merged

fix: preserve qq official quoted message context#9164
Soulter merged 3 commits into
masterfrom
codex/qqofficial-quoted-messages

Conversation

@Soulter

@Soulter Soulter commented Jul 6, 2026

Copy link
Copy Markdown
Member

Summary

  • Preserve QQ Official raw quote fields that qq-botpy drops during message parsing.
  • Convert QQ quoted message payloads into AstrBot Reply components with embedded text and attachments.
  • Add coverage for quoted group messages with quoted image attachments.

Tests

  • uv run ruff format .
  • uv run ruff check .
  • uv run pytest tests/test_qqofficial_group_message_create.py tests/test_quoted_message_parser.py

Summary by Sourcery

Preserve QQOfficial quoted message context by patching message parsers to retain raw payload fields, converting quoted content and attachments into Reply components, and extending tests to cover quoted group messages with image attachments.

New Features:

  • Map QQ quoted message payloads into AstrBot Reply components that embed quoted text and attachments.

Bug Fixes:

  • Preserve raw QQOfficial quote-related fields that qq-botpy drops during parsing so quoted context is retained in AstrBot messages.
  • Handle QQ attachment payloads provided as raw dicts as well as botpy objects to ensure images and files are correctly converted.

Enhancements:

  • Generalize and register patched parsers for multiple QQOfficial message create events to consistently retain raw payload metadata.

Tests:

  • Add group message parsing test that verifies quoted message context, including quoted image attachments, is surfaced as a Reply component.

@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. area:platform The bug / feature is about IM platform adapter, such as QQ, Lark, Telegram, WebChat and so on. labels Jul 6, 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 left some high level feedback:

  • The patched message classes (PatchedMessage, PatchedDirectMessage, PatchedC2CMessage, PatchedGroupMessage) duplicate the same slots and init logic; consider introducing a shared base/mixin to reduce repetition and keep future changes to raw field handling in one place.
  • The quoted message detection relies on the hard-coded message_type == 103 value; it would be clearer and safer to centralize this as a named constant or helper function so its meaning is explicit and easy to adjust if QQ changes the type codes.
  • In _append_attachments, the dict/object branching and repeated content-type/URL/filename extraction logic could be simplified via a small normalization helper, and the sets of file extensions could be moved to module-level constants to avoid reallocation on each call.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The patched message classes (PatchedMessage, PatchedDirectMessage, PatchedC2CMessage, PatchedGroupMessage) duplicate the same __slots__ and __init__ logic; consider introducing a shared base/mixin to reduce repetition and keep future changes to raw field handling in one place.
- The quoted message detection relies on the hard-coded `message_type == 103` value; it would be clearer and safer to centralize this as a named constant or helper function so its meaning is explicit and easy to adjust if QQ changes the type codes.
- In `_append_attachments`, the dict/object branching and repeated content-type/URL/filename extraction logic could be simplified via a small normalization helper, and the sets of file extensions could be moved to module-level constants to avoid reallocation on each call.

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.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request adds support for parsing quoted messages (replies) and retaining raw message fields from the official QQ platform. It introduces patched message classes, registers multiple message parsers dynamically, and updates attachment parsing to handle dictionary payloads. The review feedback suggests defensive programming improvements, specifically ensuring that the message payload and data dictionaries are safely guarded against None or invalid types before accessing their keys, as well as adding debug logging for received message events.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +135 to +141
def parse_message(self, payload: dict[str, Any]) -> None:
qq_message = message_cls(
self.api,
payload.get("id", None),
payload.get("d", {}),
)
self._dispatch(event_name, qq_message)

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.

medium

Defensive programming & logging: If "d" is explicitly set to None in the payload, payload.get("d", {}) will return None, which can cause downstream issues. Using payload.get("d") or {} is safer. Additionally, adding generic debug logging for received message events helps significantly with troubleshooting.

Suggested change
def parse_message(self, payload: dict[str, Any]) -> None:
qq_message = message_cls(
self.api,
payload.get("id", None),
payload.get("d", {}),
)
self._dispatch(event_name, qq_message)
def parse_message(self, payload: dict[str, Any]) -> None:
payload = payload or {}
qq_message = message_cls(
self.api,
payload.get("id", None),
payload.get("d") or {},
)
logger.debug("[QQOfficial] Received message event %s: %s", event_name, qq_message)
self._dispatch(event_name, qq_message)

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 6, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
astrbot-docs 8f6d393 Commit Preview URL

Branch Preview URL
Jul 06 2026, 03:01 PM

Soulter and others added 2 commits July 6, 2026 22:54
…dapter.py

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@Soulter Soulter merged commit 4166d9a into master Jul 6, 2026
20 checks passed
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:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant