Skip to content

[Feature]: QQ Official adapter passes raw faceType emoji tags into Plain text context #2291

Description

@jry21223

Runtime environment

LangBot v4.10.x / latest, Docker deployment, Community Edition, QQ Official Bot API (qqofficial).

Observed when receiving QQ Official group-at messages containing QQ emoji / face tags in the raw inbound content field.

Deployment version

Community Edition

Exception

QQ Official inbound messages may include QQ emoji / face markup in the raw text content, for example:

@justbot 欢迎我<faceType=1,faceId="300",ext="eyJ0ZXh0Ijoi6IOW5LiJ5pakIn0=">

The ext payload is base64-encoded JSON. Decoding this example gives:

{"text":"胖三斤"}

Expected behavior:

The QQ Official adapter should normalize this platform-specific face tag before the message enters LangBot's generic message chain / model context. For example:

欢迎我[胖三斤]

or, at minimum, remove or replace the raw tag with a safe placeholder such as:

欢迎我[表情]

Actual behavior:

The current legacy QQ Official converter appears to pass the raw inbound text directly into Plain:

yiri_msg_list.append(platform_message.Plain(text=message))

As a result, the model can receive the raw platform tag as ordinary user text:

@HENU_Bot 欢迎我<faceType=1,faceId="300",ext="...">

This can cause the model to interpret or discuss the implementation detail (faceType, faceId, ext, base64 payload) instead of responding naturally to the user message.

Related location:

src/langbot/pkg/platform/sources/qqofficial.py

Relevant path:

  • QQOfficialEventConverter.target2yiri() passes event.content to QQOfficialMessageConverter.target2yiri().
  • QQOfficialMessageConverter.target2yiri() appends the whole message as Plain(text=message).
  • For GROUP_AT_MESSAGE_CREATE / AT_MESSAGE_CREATE, LangBot inserts a synthetic At(target='justbot'), but the original leading textual mention can remain in the raw content.

Suggested fix direction:

Normalize QQ Official inbound text in the adapter-level converter before creating Plain text.

Example approach:

import base64
import json
import re

_QQ_FACE_RE = re.compile(r'<faceType=\d+,faceId="[^"]+",ext="([^"]*)">')
_LEADING_BOT_MENTION_RE = re.compile(r'^\s*@\S+\s*')


def _decode_qq_face_ext(ext: str) -> str:
    try:
        padded = ext + "=" * ((4 - len(ext) % 4) % 4)
        payload = json.loads(base64.b64decode(padded).decode("utf-8"))
        text = str(payload.get("text") or "").strip()
        return f"[{text}]" if text else "[表情]"
    except Exception:
        return "[表情]"


def _normalize_qq_official_text(message: str, strip_leading_mention: bool = False) -> str:
    text = str(message or "")
    text = _QQ_FACE_RE.sub(lambda m: _decode_qq_face_ext(m.group(1)), text)
    if strip_leading_mention:
        text = _LEADING_BOT_MENTION_RE.sub("", text, count=1)
    return text.strip()

Then use the normalized text in QQOfficialMessageConverter.target2yiri() before appending Plain.

For group-at events, it may also be helpful to strip the leading textual bot mention because LangBot already inserts a synthetic At(target='justbot') for those events.

Reproduction steps

  1. Configure a QQ Official bot in LangBot.
  2. Send a group-at message containing a QQ emoji / face tag, such as:
@Bot 欢迎我<faceType=1,faceId="300",ext="eyJ0ZXh0Ijoi6IOW5LiJ5pakIn0=">
  1. Observe the message that enters the model / conversation context.
  2. The raw <faceType=...> tag can appear as plain text instead of a normalized emoji label such as [胖三斤] or [表情].

Enabled plugins

This issue is adapter-level and can be observed before plugin business logic. A plugin-assisted chat made it visible because the model responded to the raw faceType / ext text, but the normalization should happen in the QQ Official adapter rather than in individual plugins.

Activity

  1. added
    bug?Bug或Bug修复相关 / maybe a bug
    eh: Improveenhance: 现有功能的改进 / improve current features
    IM: qqofficialQQ 官方 API Webhook 适配器相关 / QQ API (Webhook) adapter related
    on Jun 27, 2026
  2. self-assigned this
    on Jul 1, 2026
  3. BiFangKNT commented on Jul 1, 2026

    @BiFangKNT
    Member

    Isn't this a feature rather than a bug?

    I'm wondering if it's necessary to standardize this? It would destroy the original information. I think it should be made an option, or perhaps better just give it to the plugin.


    这不是bug而是feature吧?

    我在想有必要做这个规范化吗?这会破坏原始信息。我觉得做成一个选项,或者干脆给插件比较好

  4. added
    eh: Featureenhance: 新功能添加 / add new features
    and removed
    bug?Bug或Bug修复相关 / maybe a bug
    on Jul 1, 2026
  5. changed the title [-][Bug]: QQ Official adapter passes raw faceType emoji tags into Plain text context[/-] [+][Feature]: QQ Official adapter passes raw faceType emoji tags into Plain text context[/+] on Jul 1, 2026
  6. BiFangKNT commented on Jul 1, 2026

    @BiFangKNT
    Member

    And this implementation is inconsistent with other adapters: the SDK includes a built-in face component, which is used in onebot v11.

    Image

    Also, the LLM cannot see it.

    Therefore, the design requires further discussion.


    并且,此实现与其他适配器不一致:sdk中有内置 face 组件,并于 onebot v11 中应用

    Image

    并且 llm 看不到

    因此设计有待进一步讨论

  7. added
    pd: Need designpending: 需要进一步设计的功能 / wait for us to design
    on Jul 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

IM: qqofficialQQ 官方 API Webhook 适配器相关 / QQ API (Webhook) adapter relatedeh: Featureenhance: 新功能添加 / add new featureseh: Improveenhance: 现有功能的改进 / improve current featurespd: Need designpending: 需要进一步设计的功能 / wait for us to design

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions