Skip to content

feat: split oversized forwarded message nodes#8798

Open
Sisyphbaous-DT-Project wants to merge 2 commits into
AstrBotDevs:masterfrom
Sisyphbaous-DT-Project:codex/fix-forward-node-splitting
Open

feat: split oversized forwarded message nodes#8798
Sisyphbaous-DT-Project wants to merge 2 commits into
AstrBotDevs:masterfrom
Sisyphbaous-DT-Project:codex/fix-forward-node-splitting

Conversation

@Sisyphbaous-DT-Project

@Sisyphbaous-DT-Project Sisyphbaous-DT-Project commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

修改了当前的合并转发的功能,加上了合并消息内按照设置分段的功能,用来防止单条消息字数过多导致的超过qq单消息字数上限的限制而报错,具体更改请看 PR 内容:

QQ/NapCat 在发送合并转发消息时,如果单个转发 Node 里包含过长的纯文本,可能会在 aiocqhttp 调用 send_private_forward_msg 时失败,出现类似 retcode=1200 的错误。

本 PR 保留现有 platform_settings.forward_threshold 的含义,只在触发自动合并转发后,把长文本拆成多个较短的转发节点,避免单个节点过长。

Modifications / 改动点

  • 新增两个平台配置项:

    • platform_settings.forward_node_max_length:单个转发节点的目标文本长度。
    • platform_settings.forward_node_hard_limit:单个转发节点的文本硬上限。
  • 兼容旧配置:旧配置缺少新字段时自动使用默认值,不要求用户手动迁移配置文件。

  • 配置值非法时自动回退到默认值。

  • 如果 forward_node_max_length 大于 forward_node_hard_limit,自动收敛到硬上限并记录 warning。

  • 合并转发节点分段时复用 segmented_reply.split_words,并额外支持换行作为自然断点。

  • aiocqhttp 自动合并转发时,生成 Nodes([...]),内部包含多个 Node,不再把整段长文本塞进一个 Node

  • 分段规则优先在目标长度之后、硬上限以内寻找自然断点;找不到再向目标长度之前回退;仍找不到则按硬上限强制切分。

  • 保留非纯文本消息组件的原始顺序,避免图片、表情、At、Reply 等组件因分段而重复或丢失。

  • 如果消息链里已经包含 NodeNodes,跳过自动转换,避免二次包装。

  • WebUI 配置元数据和中/英/俄三份 i18n 文案同步补充新配置项说明。

  • 新增单元测试,覆盖切分点选择、节点构建、装饰阶段转换、配置规整和混合组件处理。

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

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

87fe2da65f69cad3a3c004090db1a5b6

本地验证命令:

pytest -s tests/unit/test_result_decorate_forward.py

结果:

26 passed, 1 warning
ruff check astrbot/core/pipeline/result_decorate/stage.py tests/unit/test_result_decorate_forward.py

结果:

All checks passed!
python -m compileall astrbot/core/pipeline/result_decorate/stage.py astrbot/core/config/default.py tests/unit/test_result_decorate_forward.py

结果:通过。

git diff --check

结果:通过。

WebUI 构建验证:

cd dashboard
npm install --no-package-lock --no-audit --no-fund
npm run build

结果:

✓ built in 1m 14s

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

Split long QQ/NapCat auto-forward messages into multiple shorter forward nodes to avoid single-node length limits while preserving existing behavior for other platforms and message types.

New Features:

  • Add configurable limits for the target and hard maximum length of a single forward node when auto-merging long replies.
  • Support natural breakpoint-based splitting (including punctuation and newlines) when constructing forward nodes for QQ/NapCat.

Enhancements:

  • Reuse segmented-reply splitting logic for forward node segmentation and ensure non-text components (images, mentions, replies) keep their original order without duplication.
  • Skip auto-conversion when the message chain already contains forward nodes to avoid double-wrapping.
  • Ensure invalid or missing forward node config values are sanitized and fall back to safe defaults, with warnings when needed.
  • Update default config and WebUI metadata/i18n entries to expose the new forward node settings.

Tests:

  • Add comprehensive unit tests covering forward node splitting behavior, configuration sanitization, and process-stage integration for auto-forward conversion.

@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 Jun 15, 2026
@Sisyphbaous-DT-Project Sisyphbaous-DT-Project changed the title feat: 拆分过长合并转发节点 feat: split oversized forwarded message nodes Jun 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 left some high level feedback:

  • The default values for forward_node_max_length/forward_node_hard_limit are hard-coded in both default.py and ResultDecorateStage.initialize; consider centralizing these defaults (e.g., module-level constants or reading from config) to avoid future drift.
  • The logic for constructing forward_split_pattern largely duplicates the segmented reply splitting setup; consider extracting a shared helper to build the regex pattern so the two code paths stay consistent when split-word rules evolve.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The default values for `forward_node_max_length`/`forward_node_hard_limit` are hard-coded in both `default.py` and `ResultDecorateStage.initialize`; consider centralizing these defaults (e.g., module-level constants or reading from config) to avoid future drift.
- The logic for constructing `forward_split_pattern` largely duplicates the segmented reply splitting setup; consider extracting a shared helper to build the regex pattern so the two code paths stay consistent when split-word rules evolve.

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 introduces auto-forward node splitting for long replies, allowing messages to be split into multiple forward nodes based on target and hard length limits while preferring natural breakpoints (like punctuation and newlines). It updates the default configuration, localization files, and pipeline processing logic, and adds comprehensive unit tests. The reviewer identified a potential boundary bug in the _find_forward_split_pos method where a breakpoint crossing the target length boundary could be missed, and suggested a simplified, single-pass regex matching approach to resolve it.

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 thread astrbot/core/pipeline/result_decorate/stage.py
@Sisyphbaous-DT-Project

Copy link
Copy Markdown
Contributor Author

Thanks @sourcery-ai. I addressed the default-value drift risk in adea231 by centralizing the forward node defaults in astrbot.core.config.default and reusing those constants from ResultDecorateStage and the tests.

For the split-pattern construction, I kept the regex construction inline for now because the repository contribution guide explicitly prefers avoiding extra helpers unless the reuse or complexity clearly warrants it. The forward splitter still reuses the configured segmented_reply.split_words and applies the same escaping/sorting behavior, plus newline as an extra breakpoint for forward nodes.

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