Skip to content

fix(onebot): 合并转发节点传入 bot self_id 作为 uin,修复 retcode=1200 - #93

Merged
FlanChanXwO merged 2 commits into
AstrBot-Elementary-School:devfrom
Github-2333-top:fix/onebot-forward-node-uin
Jul 23, 2026
Merged

fix(onebot): 合并转发节点传入 bot self_id 作为 uin,修复 retcode=1200#93
FlanChanXwO merged 2 commits into
AstrBot-Elementary-School:devfrom
Github-2333-top:fix/onebot-forward-node-uin

Conversation

@Github-2333-top

@Github-2333-top Github-2333-top commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

问题

RSS 推送到 QQ 群(aiocqhttp / OneBot)失败,推送历史报错:

platform_send: <ActionFailed status='failed', retcode=1200, data=None,
wording='forward node user_id/uin is required', echo={'seq': 1696}>

根因

OneBotMessageSender.send_to_user 构建合并转发 Node 时只传了 contentname未传 uin

nodes.append(Node(content=node_content, name=nickname))  # 缺少 uin

AstrBot 的 Node 组件 uin 默认为 "0"Node.to_dict() 序列化后变成 user_id: "0"新版 NapCat / Lagrange 对合并转发节点做了严格校验,拒绝 user_id 为 0 或空的转发节点,返回 retcode=1200"forward node user_id/uin is required")。旧版 go-cqhttp / 早期 NapCat 较为宽容,所以此前未暴露。

此外 aiocqhttp 在收到 retcode=1200 时抛出 ActionFailed 异常而非返回失败结果,异常直接被外层 except 捕获,try 块内的纯文本回退逻辑被跳过;即便回退执行,回退的 Node 同样不带 uin,仍会失败。

修复

1. src/infrastructure/messaging/senders/onebot_sender.py

  • 新增 _resolve_bot_self_id,按以下顺序解析 bot 的 self_id(QQ 号):
    1. 命令响应场景:从 event.message_obj.self_id 读取(最可靠);
    2. 主动推送场景:通过全局 provider get_bot_self_id(platform_name) 解析;
    3. 兜底:返回非零占位 "10000",避免 user_id 为空或 0 再次触发 retcode=1200
  • 构建节点与三处回退 Node(主循环、空消息兜底、纯文本回退)均传入 uin=bot_self_id
  • bot_client 解析上移到节点构建之前,使 uin 在构建节点时即可用。

2. bootstrap.py

  • types.py 已预留 set_bot_self_id_provider / get_bot_self_id hook,但 bootstrap.py 此前只注册了 set_bot_client_provider漏注册了 set_bot_self_id_provider,导致 get_bot_self_id() 永远返回默认 "10000"
  • 本次在 _register_bot_client_provider 中新增 _resolve_bot_self_id 闭包:复用已有的 _resolve_bot_client 解析出 CQHttp 实例后,从其 _wsr_api_clients(以 self_id 为键保存已连接的反向 WS API 客户端,AstrBot core 的 terminate 也读取该属性)取第一个非零键作为真实 bot QQ 号;并注册到 set_bot_self_id_provider

验证

  • python -m py_compile 两个文件均通过。
  • uin 解析在事件场景下读 message_obj.self_id(AstrBot aiocqhttp 适配器在 _convert_handle_message_event 中设置 abm.self_id = str(event.self_id)),主动推送场景下读 _wsr_api_clients,两者均与现有代码路径一致。

兼容性

  • 不改变现有发送流程与回退策略,仅补齐 uin 字段。
  • 对旧版 go-cqhttp / 早期 NapCat 无影响(它们本就接受任意 user_id)。
  • _wsr_api_clients 属性访问使用 getattr + isinstance 防御,不存在时返回空串由调用方兜底,不会抛错。

Summary by Sourcery

确保 OneBot 合并转发消息包含有效的机器人 self_id/uin,以满足更严格的 NapCat/Lagrange 校验要求,并防止在 QQ 群消息投递时出现 retcode=1200 错误。

Bug Fixes:

  • 在所有 OneBot 发送与回退路径中,将合并转发节点(merged forward Node)的 uin 填充为机器人 self_id,以避免由于 user_id 缺失或为 0 而导致的 ActionFailed retcode=1200
  • 在启动流程(bootstrap)中注册并使用机器人 self_id 提供器,以便在主动推送场景中能够解析真实的 QQ 号,而不是总是退回到默认占位值。

Enhancements:

  • 引入辅助逻辑,从当前事件或全局提供器中解析机器人 self_id,并带有非零回退值,在不同运行时上下文中提升 OneBot 消息发送的健壮性。
Original summary in English

Summary by Sourcery

Ensure OneBot merged forward messages include a valid bot self_id/uin to satisfy stricter NapCat/Lagrange validation and prevent retcode=1200 failures in QQ group deliveries.

Bug Fixes:

  • Populate merged forward Node uin with the bot self_id for all OneBot sending and fallback paths to avoid ActionFailed retcode=1200 from missing or zero user_id.
  • Register and use a bot self_id provider in bootstrap so proactive push scenarios can resolve the actual QQ number instead of always falling back to a default placeholder.

Enhancements:

  • Introduce helper logic to resolve the bot self_id from either the current event or the global provider with a non-zero fallback, improving robustness of OneBot messaging in varying runtime contexts.

Summary by CodeRabbit

  • 新功能
    • 发送合并转发消息时,系统现在会自动带上发送方标识,提升转发消息的兼容性与可用性。
  • 问题修复
    • 优化了在不同场景下的发送方标识获取逻辑,减少合并转发失败后回退消息的异常情况。
    • 当无法获取标识时,增加了默认值处理,提升消息发送稳定性。

@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8ac06831-cb5e-4698-a18a-d4e85d73ffab

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

bootstrap 注册 bot client 与 bot self_id provider;OneBot sender 解析 bot_self_id,并在合并转发和兜底节点中写入 Node.uin

Changes

bot self_id 解析与写入

Layer / File(s) Summary
bootstrap.py 的 provider 注册
bootstrap.py
_register_bot_client_provider 现在同时注册 set_bot_client_providerset_bot_self_id_provider,并补充了从底层 bot client 解析 self_id 的说明。
OneBot sender 的 self_id 解析与 Node 赋值
src/infrastructure/messaging/senders/onebot_sender.py
OneBotMessageSender 新增 _resolve_bot_self_idsend_to_user 解析 bot_self_id 后,将其写入合并转发、纯文本回退和失败兜底节点的 uin

Sequence Diagram(s)

初始化注册

sequenceDiagram
  participant Bootstrap as "bootstrap.py:_register_bot_client_provider"
  participant ClientProvider as "set_bot_client_provider"
  participant SelfIdProvider as "set_bot_self_id_provider"

  Bootstrap->>ClientProvider: register _resolve_bot_client
  Bootstrap->>SelfIdProvider: register _resolve_bot_self_id
Loading

发送时解析 self_id

sequenceDiagram
  participant Sender as "OneBotMessageSender.send_to_user"
  participant Context as "MessageContext.message_obj.self_id"
  participant Tool as "get_bot_self_id(platform_name)"
  participant Node as "Node(..., uin=bot_self_id)"

  Sender->>Context: read message_obj.self_id
  alt message_obj.self_id exists
    Context-->>Sender: self_id
  else message_obj.self_id missing
    Sender->>Tool: resolve bot_self_id by platform_name
    Tool-->>Sender: bot_self_id or "10000"
  end
  Sender->>Node: build merged-forward and fallback nodes
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 兔耳轻点启动台,
self_id 亮进夜色来。
合并转发排好队,
节点尾巴都带牌。
啵唧一声消息去,
轻轻落到远方怀。

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了核心修改:为合并转发节点传入 bot self_id 作为 uin 以修复 retcode=1200。
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Jun 27, 2026

Copy link
Copy Markdown

审阅者指南

添加了正确的 bot self_id(uin)的解析和在 OneBot 转发节点中的传递,以修复 retcode=1200,并从 bootstrap 中接好全局 self_id provider,使得主动发送可以获取 QQ 号。

文件级变更

变更 详情 文件
在所有构造出的 OneBot 转发节点中解析并注入 bot self_id,以满足 NapCat/Lagrange 的校验要求。
  • 在 onebot_sender 中引入 get_bot_self_id,以便在非事件上下文中获取 self_id。
  • 新增 _resolve_bot_self_id,优先使用 event.message_obj.self_id,其次使用全局 provider,最后回退到非零占位值 '10000'
  • 重构 send_to_user,更早解析 bot_client,并在构造节点前派生出 bot_self_id
  • 更新所有 Node 构造(主循环、空消息回退、文本回退),确保包含 uin=bot_self_id
  • 确保 NapCat 流式上传路径使用带有已填充 uin 的更新后 Nodes。
src/infrastructure/messaging/senders/onebot_sender.py
为主动推送场景提供基于底层 aiocqhttp CQHttp 客户端的 bot self_id provider。
  • 扩展 _register_bot_client_provider 的 docstring 和职责范围,使其涵盖 bot self_id 的解析。
  • 新增 _resolve_bot_self_id,检查 CQHttp._wsr_api_clients 并返回第一个非零的 self_id(字符串形式),失败时返回空字符串。
  • 通过 set_bot_self_id_provider 注册 _resolve_bot_self_id,与现有的 bot client provider 一同使用。
bootstrap.py

技巧与命令

与 Sourcery 交互

  • 触发新的审阅: 在 pull request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审阅评论。
  • 从审阅评论生成 GitHub issue: 通过回复某条审阅评论,让 Sourcery 从该评论创建一个 issue。你也可以回复审阅评论 @sourcery-ai issue 来从中创建 issue。
  • 生成 pull request 标题: 在 pull request 标题任意位置写上 @sourcery-ai 即可随时生成标题。你也可以在 pull request 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 pull request 摘要: 在 pull request 正文任意位置写上 @sourcery-ai summary,即可在你想要的位置生成 PR 摘要。你也可以在 pull request 中评论 @sourcery-ai summary 来在任意时间(重新)生成摘要。
  • 生成审阅者指南: 在 pull request 中评论 @sourcery-ai guide,即可在任意时间(重新)生成审阅者指南。
  • 解决所有 Sourcery 评论: 在 pull request 中评论 @sourcery-ai resolve,以解决所有 Sourcery 评论。如果你已经处理了所有评论并且不想再看到它们,这会很有用。
  • 关闭所有 Sourcery 审阅: 在 pull request 中评论 @sourcery-ai dismiss,以关闭所有现有的 Sourcery 审阅。如果你想从头开始一次新的审阅,这特别有用——别忘了评论 @sourcery-ai review 来触发新的审阅!

自定义你的体验

访问你的 控制面板 来:

  • 启用或禁用审阅功能,比如 Sourcery 生成的 pull request 摘要、审阅者指南等。
  • 更改审阅语言。
  • 添加、移除或编辑自定义审阅指令。
  • 调整其他审阅设置。

获取帮助

Original review guide in English

Reviewer's Guide

Adds proper bot self_id (uin) resolution and propagation into OneBot forward nodes to fix retcode=1200, and wires a global self_id provider from bootstrap so proactive sends can obtain the QQ number.

File-Level Changes

Change Details Files
Resolve and inject bot self_id into all constructed OneBot forward Nodes to satisfy NapCat/Lagrange validation.
  • Imported get_bot_self_id into onebot_sender to obtain self_id in non-event contexts.
  • Introduced _resolve_bot_self_id, preferring event.message_obj.self_id, then global provider, finally a non-zero placeholder '10000'.
  • Refactored send_to_user to resolve bot_client earlier and derive bot_self_id before node construction.
  • Updated all Node constructions (main loop, empty-message fallback, text fallback) to include uin=bot_self_id.
  • Ensured NapCat stream upload path uses the updated Nodes with uin populated.
src/infrastructure/messaging/senders/onebot_sender.py
Provide a bot self_id provider based on the underlying aiocqhttp CQHttp client for proactive push scenarios.
  • Extended _register_bot_client_provider docstring and responsibility to cover bot self_id resolution.
  • Added _resolve_bot_self_id that inspects CQHttp._wsr_api_clients and returns the first non-zero self_id as string, or empty on failure.
  • Registered _resolve_bot_self_id via set_bot_self_id_provider alongside the existing bot client provider.
bootstrap.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - 我发现了 1 个问题,并给出了一些整体性的反馈:

  • _resolve_bot_self_id 中,bot_client 参数从未被使用;请考虑要么将其从函数签名中移除,要么复用已经解析好的 client,而不是通过 get_bot_self_id 重新推导 self_id,以避免混淆和重复逻辑。
  • 硬编码的兜底 self_id 值 "10000" 在多处出现,且蕴含业务逻辑;建议将其提取为一个语义清晰的模块级常量,以便更容易理解其意图与用途,并在后续需要调整时集中修改。
面向 AI Agents 的提示词
Please address the comments from this code review:

## Overall Comments
- In `_resolve_bot_self_id`, the `bot_client` parameter is never used; either remove it from the signature or reuse the already-resolved client instead of re-deriving self_id via `get_bot_self_id` to avoid confusion and duplication.
- The hardcoded fallback self_id value "10000" appears in multiple places and encodes business logic; consider extracting it into a clearly named module-level constant to make the intent and usage easier to track and adjust.

## Individual Comments

### Comment 1
<location path="src/infrastructure/messaging/senders/onebot_sender.py" line_range="86-87" />
<code_context>
         return get_bot_client(platform_name or "")

+    @classmethod
+    def _resolve_bot_self_id(
+        cls, context: MessageContext | None, bot_client: Any | None
+    ) -> str:
+        """解析 bot 的 self_id(QQ 号),用于合并转发节点的 user_id。
</code_context>
<issue_to_address>
**suggestion:** Remove or leverage the unused `bot_client` parameter in `_resolve_bot_self_id`.

Since `bot_client` is always passed from `send_to_user` but never used here, it currently adds complexity without value. Consider either removing it from both the method and call site, or deriving `self_id` directly from the provided client (mirroring the bootstrap provider) to avoid the extra `get_bot_self_id` lookup.

Suggested implementation:

```python
from typing import Any
from .types import MessageContext, SendRequest, SendResult, get_bot_self_id

```

```python
    @classmethod
    def _resolve_bot_self_id(
        cls, context: MessageContext | None, bot_client: Any | None
    ) -> str:
        """解析 bot 的 self_id(QQ 号),用于合并转发节点的 user_id。

        解析顺序:
        1. 命令响应场景:从事件消息对象的 ``self_id`` 读取(最可靠)。
        2. 若有显式传入的 ``bot_client``,优先从 client 上解析 ``self_id``,
           避免额外的 get_bot_self_id 查找。
        3. 主动推送场景:通过全局 provider 按 platform_name 解析(由
           bootstrap 注册,读取 CQHttp 的 ``_wsr_api_clients``)。
        4. 兜底:返回非零占位 ``"10000"``,避免新版 NapCat / Lagrange
           因 user_id 为空或 0 报 retcode=1200。
        """
        # 1. 从事件对象中直接读取(命令响应场景)
        if context is not None:
            event = getattr(context, "event", None)
            if event is not None:
                self_id = getattr(event, "self_id", None)
                if self_id:
                    return str(self_id)

        # 2. 从显式传入的 bot_client 上解析(如果可用)
        if bot_client is not None:
            self_id = getattr(bot_client, "self_id", None)
            if self_id:
                return str(self_id)

        # 3. 通过全局 provider + platform_name 解析
        platform_name = getattr(context, "platform_name", "") if context is not None else ""
        self_id = get_bot_self_id(platform_name or "")
        if self_id:
            return str(self_id)

        # 4. 兜底占位,避免 retcode=1200
        return "10000"

```
</issue_to_address>

Sourcery 对开源项目是免费的——如果你觉得我们的代码审查有帮助,请考虑分享它 ✨
帮我变得更有用!请对每条评论点击 👍 或 👎,我会根据你的反馈改进后续的代码审查。
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • In _resolve_bot_self_id, the bot_client parameter is never used; either remove it from the signature or reuse the already-resolved client instead of re-deriving self_id via get_bot_self_id to avoid confusion and duplication.
  • The hardcoded fallback self_id value "10000" appears in multiple places and encodes business logic; consider extracting it into a clearly named module-level constant to make the intent and usage easier to track and adjust.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `_resolve_bot_self_id`, the `bot_client` parameter is never used; either remove it from the signature or reuse the already-resolved client instead of re-deriving self_id via `get_bot_self_id` to avoid confusion and duplication.
- The hardcoded fallback self_id value "10000" appears in multiple places and encodes business logic; consider extracting it into a clearly named module-level constant to make the intent and usage easier to track and adjust.

## Individual Comments

### Comment 1
<location path="src/infrastructure/messaging/senders/onebot_sender.py" line_range="86-87" />
<code_context>
         return get_bot_client(platform_name or "")

+    @classmethod
+    def _resolve_bot_self_id(
+        cls, context: MessageContext | None, bot_client: Any | None
+    ) -> str:
+        """解析 bot 的 self_id(QQ 号),用于合并转发节点的 user_id。
</code_context>
<issue_to_address>
**suggestion:** Remove or leverage the unused `bot_client` parameter in `_resolve_bot_self_id`.

Since `bot_client` is always passed from `send_to_user` but never used here, it currently adds complexity without value. Consider either removing it from both the method and call site, or deriving `self_id` directly from the provided client (mirroring the bootstrap provider) to avoid the extra `get_bot_self_id` lookup.

Suggested implementation:

```python
from typing import Any
from .types import MessageContext, SendRequest, SendResult, get_bot_self_id

```

```python
    @classmethod
    def _resolve_bot_self_id(
        cls, context: MessageContext | None, bot_client: Any | None
    ) -> str:
        """解析 bot 的 self_id(QQ 号),用于合并转发节点的 user_id。

        解析顺序:
        1. 命令响应场景:从事件消息对象的 ``self_id`` 读取(最可靠)。
        2. 若有显式传入的 ``bot_client``,优先从 client 上解析 ``self_id``,
           避免额外的 get_bot_self_id 查找。
        3. 主动推送场景:通过全局 provider 按 platform_name 解析(由
           bootstrap 注册,读取 CQHttp 的 ``_wsr_api_clients``)。
        4. 兜底:返回非零占位 ``"10000"``,避免新版 NapCat / Lagrange
           因 user_id 为空或 0 报 retcode=1200。
        """
        # 1. 从事件对象中直接读取(命令响应场景)
        if context is not None:
            event = getattr(context, "event", None)
            if event is not None:
                self_id = getattr(event, "self_id", None)
                if self_id:
                    return str(self_id)

        # 2. 从显式传入的 bot_client 上解析(如果可用)
        if bot_client is not None:
            self_id = getattr(bot_client, "self_id", None)
            if self_id:
                return str(self_id)

        # 3. 通过全局 provider + platform_name 解析
        platform_name = getattr(context, "platform_name", "") if context is not None else ""
        self_id = get_bot_self_id(platform_name or "")
        if self_id:
            return str(self_id)

        # 4. 兜底占位,避免 retcode=1200
        return "10000"

```
</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 +86 to +87
def _resolve_bot_self_id(
cls, context: MessageContext | None, bot_client: Any | None

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion: 移除或利用 _resolve_bot_self_id 中未使用的 bot_client 参数。

由于 bot_client 始终由 send_to_user 传入,但在这里从未使用,目前只是在增加无意义的复杂度。建议要么在该方法及其调用处同时移除该参数,要么直接从传入的 client 上推导 self_id(与 bootstrap provider 的行为保持一致),以避免额外的 get_bot_self_id 查找。

建议实现如下:

from typing import Any
from .types import MessageContext, SendRequest, SendResult, get_bot_self_id
    @classmethod
    def _resolve_bot_self_id(
        cls, context: MessageContext | None, bot_client: Any | None
    ) -> str:
        """解析 bot 的 self_id(QQ 号),用于合并转发节点的 user_id。

        解析顺序:
        1. 命令响应场景:从事件消息对象的 ``self_id`` 读取(最可靠)。
        2. 若有显式传入的 ``bot_client``,优先从 client 上解析 ``self_id``,
           避免额外的 get_bot_self_id 查找。
        3. 主动推送场景:通过全局 provider 按 platform_name 解析(由
           bootstrap 注册,读取 CQHttp 的 ``_wsr_api_clients``)。
        4. 兜底:返回非零占位 ``"10000"``,避免新版 NapCat / Lagrange
           因 user_id 为空或 0 报 retcode=1200。
        """
        # 1. 从事件对象中直接读取(命令响应场景)
        if context is not None:
            event = getattr(context, "event", None)
            if event is not None:
                self_id = getattr(event, "self_id", None)
                if self_id:
                    return str(self_id)

        # 2. 从显式传入的 bot_client 上解析(如果可用)
        if bot_client is not None:
            self_id = getattr(bot_client, "self_id", None)
            if self_id:
                return str(self_id)

        # 3. 通过全局 provider + platform_name 解析
        platform_name = getattr(context, "platform_name", "") if context is not None else ""
        self_id = get_bot_self_id(platform_name or "")
        if self_id:
            return str(self_id)

        # 4. 兜底占位,避免 retcode=1200
        return "10000"
Original comment in English

suggestion: Remove or leverage the unused bot_client parameter in _resolve_bot_self_id.

Since bot_client is always passed from send_to_user but never used here, it currently adds complexity without value. Consider either removing it from both the method and call site, or deriving self_id directly from the provided client (mirroring the bootstrap provider) to avoid the extra get_bot_self_id lookup.

Suggested implementation:

from typing import Any
from .types import MessageContext, SendRequest, SendResult, get_bot_self_id
    @classmethod
    def _resolve_bot_self_id(
        cls, context: MessageContext | None, bot_client: Any | None
    ) -> str:
        """解析 bot 的 self_id(QQ 号),用于合并转发节点的 user_id。

        解析顺序:
        1. 命令响应场景:从事件消息对象的 ``self_id`` 读取(最可靠)。
        2. 若有显式传入的 ``bot_client``,优先从 client 上解析 ``self_id``,
           避免额外的 get_bot_self_id 查找。
        3. 主动推送场景:通过全局 provider 按 platform_name 解析(由
           bootstrap 注册,读取 CQHttp 的 ``_wsr_api_clients``)。
        4. 兜底:返回非零占位 ``"10000"``,避免新版 NapCat / Lagrange
           因 user_id 为空或 0 报 retcode=1200。
        """
        # 1. 从事件对象中直接读取(命令响应场景)
        if context is not None:
            event = getattr(context, "event", None)
            if event is not None:
                self_id = getattr(event, "self_id", None)
                if self_id:
                    return str(self_id)

        # 2. 从显式传入的 bot_client 上解析(如果可用)
        if bot_client is not None:
            self_id = getattr(bot_client, "self_id", None)
            if self_id:
                return str(self_id)

        # 3. 通过全局 provider + platform_name 解析
        platform_name = getattr(context, "platform_name", "") if context is not None else ""
        self_id = get_bot_self_id(platform_name or "")
        if self_id:
            return str(self_id)

        # 4. 兜底占位,避免 retcode=1200
        return "10000"

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/infrastructure/messaging/senders/onebot_sender.py (1)

87-110: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

让 self_id 解析真正使用传入的 bot_client

Line 87 接收 bot_client,但当前只查 event.message_obj.self_id 和全局 provider;若命令响应场景有 event.bot、但 message_obj.self_id 缺失,会落到占位值。请补充从 bot_client.self_id / _wsr_api_clients 解析的分支,或移除该参数并验证所有事件都稳定携带 message_obj.self_id

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/infrastructure/messaging/senders/onebot_sender.py` around lines 87 - 110,
The self_id resolution in the onebot sender is ignoring the passed bot_client,
so command-response flows can fall back to the placeholder when
message_obj.self_id is missing. Update the self_id resolver in the onebot_sender
logic to first use bot_client.self_id (or derive from the CQHttp
_wsr_api_clients when available) before falling back to
event.message_obj.self_id and get_bot_self_id(platform_name), or remove the
unused bot_client parameter if all callers guarantee message_obj.self_id is
always present.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bootstrap.py`:
- Around line 242-247: The new docstrings in bootstrap.py trigger Ruff RUF002
because they contain full-width Chinese punctuation, so the lint step may fail.
Update the affected docstring text around the bot client/self_id provider
documentation to use ASCII punctuation only, or adjust the Ruff configuration to
allow Chinese punctuation if that is the intended project policy. Use the
existing docstring block in the bootstrap logic as the target location.
- Around line 281-285: The self_id lookup in the client helper that reads
_wsr_api_clients should avoid iterating the live dict directly because it can
change during WebSocket activity and raise a RuntimeError. Update the logic in
the self_id resolution path to take a snapshot of api_clients keys first, then
iterate that snapshot and return the first non-empty, non-"0" id. Keep the fix
localized to the getattr(client, "_wsr_api_clients", None) / self_id selection
block so the lookup remains stable under concurrent connection changes.

In `@src/infrastructure/messaging/senders/onebot_sender.py`:
- Around line 89-96: The new docstring in OneBot sender is triggering Ruff
RUF002 because it contains full-width punctuation. Update the documentation text
in the affected helper around the self_id parsing logic in onebot_sender.py to
use ASCII punctuation consistently, or adjust the Ruff configuration to allow
Chinese punctuation if that is the intended project standard. Make sure the fix
targets the docstring associated with the self_id resolution flow used for
merged-forward user_id handling.

---

Nitpick comments:
In `@src/infrastructure/messaging/senders/onebot_sender.py`:
- Around line 87-110: The self_id resolution in the onebot sender is ignoring
the passed bot_client, so command-response flows can fall back to the
placeholder when message_obj.self_id is missing. Update the self_id resolver in
the onebot_sender logic to first use bot_client.self_id (or derive from the
CQHttp _wsr_api_clients when available) before falling back to
event.message_obj.self_id and get_bot_self_id(platform_name), or remove the
unused bot_client parameter if all callers guarantee message_obj.self_id is
always present.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b89cd41c-38fd-46d0-9672-3e069f78eb37

📥 Commits

Reviewing files that changed from the base of the PR and between ca02892 and 176520c.

📒 Files selected for processing (2)
  • bootstrap.py
  • src/infrastructure/messaging/senders/onebot_sender.py

Comment thread bootstrap.py
Comment on lines +242 to +247
"""注册 bot client / bot self_id provider,供主动推送场景使用

主动推送没有消息事件,sender 无法从 event 取 bot 客户端。
这里通过 AstrBot platform_manager 按平台名解析出底层 bot 客户端
(如 aiocqhttp 的 CQHttp 实例),用于调用 NapCat stream action。
(如 aiocqhttp 的 CQHttp 实例),用于调用 NapCat stream action,
并从中解析出 bot 的 self_id(QQ 号)供合并转发节点使用。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

处理 Ruff RUF002 告警,避免 lint 阶段失败。

这些新增 docstring 含全角标点,Ruff 已在这些行报告 RUF002。若该规则在 CI 中阻断,请改为 ASCII 标点,或在 Ruff 配置中明确允许中文标点。

Also applies to: 271-276

🧰 Tools
🪛 Ruff (0.15.18)

[warning] 242-242: Docstring contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF002)


[warning] 244-244: Docstring contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF002)


[warning] 246-246: Docstring contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF002)


[warning] 246-246: Docstring contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF002)


[warning] 246-246: Docstring contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF002)


[warning] 246-246: Docstring contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF002)


[warning] 247-247: Docstring contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF002)


[warning] 247-247: Docstring contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF002)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bootstrap.py` around lines 242 - 247, The new docstrings in bootstrap.py
trigger Ruff RUF002 because they contain full-width Chinese punctuation, so the
lint step may fail. Update the affected docstring text around the bot
client/self_id provider documentation to use ASCII punctuation only, or adjust
the Ruff configuration to allow Chinese punctuation if that is the intended
project policy. Use the existing docstring block in the bootstrap logic as the
target location.

Source: Linters/SAST tools

Comment thread bootstrap.py Outdated
Comment on lines +281 to +285
api_clients = getattr(client, "_wsr_api_clients", None)
if isinstance(api_clients, dict):
for self_id in api_clients.keys():
if self_id and str(self_id) != "0":
return str(self_id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

遍历前先快照 _wsr_api_clients

该 dict 由反向 WebSocket 连接维护,发送期间连接增删时直接遍历 keys 可能抛 RuntimeError: dictionary changed size during iteration,导致 self_id 解析失败。

建议修复
-            for self_id in api_clients.keys():
+            for self_id in list(api_clients):
                 if self_id and str(self_id) != "0":
                     return str(self_id)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
api_clients = getattr(client, "_wsr_api_clients", None)
if isinstance(api_clients, dict):
for self_id in api_clients.keys():
if self_id and str(self_id) != "0":
return str(self_id)
api_clients = getattr(client, "_wsr_api_clients", None)
if isinstance(api_clients, dict):
for self_id in list(api_clients):
if self_id and str(self_id) != "0":
return str(self_id)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bootstrap.py` around lines 281 - 285, The self_id lookup in the client helper
that reads _wsr_api_clients should avoid iterating the live dict directly
because it can change during WebSocket activity and raise a RuntimeError. Update
the logic in the self_id resolution path to take a snapshot of api_clients keys
first, then iterate that snapshot and return the first non-empty, non-"0" id.
Keep the fix localized to the getattr(client, "_wsr_api_clients", None) /
self_id selection block so the lookup remains stable under concurrent connection
changes.

Comment on lines +89 to +96
"""解析 bot 的 self_id(QQ 号),用于合并转发节点的 user_id。

解析顺序:
1. 命令响应场景:从事件消息对象的 ``self_id`` 读取(最可靠)。
2. 主动推送场景:通过全局 provider 按 platform_name 解析(由
bootstrap 注册,读取 CQHttp 的 ``_wsr_api_clients``)。
3. 兜底:返回非零占位 ``"10000"``,避免新版 NapCat / Lagrange
因 user_id 为空或 0 报 retcode=1200。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

处理 Ruff RUF002 告警,避免 lint 阶段失败。

这些新增 docstring 含全角标点,Ruff 已在这些行报告 RUF002。若该规则在 CI 中阻断,请改为 ASCII 标点,或在 Ruff 配置中明确允许中文标点。

🧰 Tools
🪛 Ruff (0.15.18)

[warning] 89-89: Docstring contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF002)


[warning] 89-89: Docstring contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF002)


[warning] 89-89: Docstring contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF002)


[warning] 91-91: Docstring contains ambiguous (FULLWIDTH COLON). Did you mean : (COLON)?

(RUF002)


[warning] 92-92: Docstring contains ambiguous (FULLWIDTH COLON). Did you mean : (COLON)?

(RUF002)


[warning] 92-92: Docstring contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF002)


[warning] 92-92: Docstring contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF002)


[warning] 93-93: Docstring contains ambiguous (FULLWIDTH COLON). Did you mean : (COLON)?

(RUF002)


[warning] 93-93: Docstring contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF002)


[warning] 94-94: Docstring contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF002)


[warning] 94-94: Docstring contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF002)


[warning] 95-95: Docstring contains ambiguous (FULLWIDTH COLON). Did you mean : (COLON)?

(RUF002)


[warning] 95-95: Docstring contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF002)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/infrastructure/messaging/senders/onebot_sender.py` around lines 89 - 96,
The new docstring in OneBot sender is triggering Ruff RUF002 because it contains
full-width punctuation. Update the documentation text in the affected helper
around the self_id parsing logic in onebot_sender.py to use ASCII punctuation
consistently, or adjust the Ruff configuration to allow Chinese punctuation if
that is the intended project standard. Make sure the fix targets the docstring
associated with the self_id resolution flow used for merged-forward user_id
handling.

Source: Linters/SAST tools

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 176520cc79

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if node_content:
nodes.append(Node(content=node_content, name=nickname))
nodes.append(
Node(content=node_content, name=nickname, uin=bot_self_id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 同步更新 OneBot Node 测试替身

在运行现有 tests/unit/infrastructure/test_onebot_sender.py 时,这个新增关键字会调用被 monkeypatch 的 _Node(content, name) 测试替身;该替身没有 uin 参数,因此覆盖合并转发路径的单元测试会在发送前以 TypeError: __init__() got an unexpected keyword argument 'uin' 失败。请同步更新测试替身(最好同时断言 uin),否则 OneBot sender 的回归测试无法执行。

Useful? React with 👍 / 👎.

Comment on lines +95 to +96
3. 兜底:返回非零占位 ``"10000"``,避免新版 NapCat / Lagrange
因 user_id 为空或 0 报 retcode=1200。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 补充 OneBot uin 兜底文档

这里新增了 OneBot 合并转发节点 user_id/uin 的解析顺序和 "10000" 兜底语义,属于 sender / 平台行为变化;仓库的 AGENTS.mddocs/dev/maintenance.md 要求这类变化同步更新对应 docs/。当前提交没有更新 docs/project/platforms.md 或兼容性文档,后续维护者无法从文档得知主动推送时 self_id 的来源和兜底行为。

Useful? React with 👍 / 👎.

@FlanChanXwO

Copy link
Copy Markdown
Member

感谢这个修复,方向是对的。我们当前 dev 分支的 OneBot merged-forward 确实没有给 Node 显式设置 uin,所以在新版 NapCat / Lagrange 严格校验 forward node user_id/uin 时,会存在你描述的 retcode=1200 风险。

我建议这个 PR 再收敛一下实现,主要是避免用固定 QQ 号兜底,以及补上回归测试。下面是具体定位和建议改法。

1. 不要用 "10000" 作为 self_id 兜底

当前 PR 新增逻辑里这段会在解析失败时伪造一个固定 bot uin:

# src/infrastructure/messaging/senders/onebot_sender.py
return "10000"

这个兜底风险比较大:

  • 如果平台仍然校验真实 bot 身份,10000 可能继续失败。
  • 如果能发出去,节点显示身份也不是当前 bot。
  • 更重要的是,它会把 provider 注册失败、平台结构变化、多 bot 解析失败这些真实问题隐藏起来。

建议改成:只返回真实解析到的非零 self_id;解析不到就返回空串,由发送路径明确失败并记录日志。

可以参考这个结构:

def _normalize_self_id(value: Any) -> str:
    text = str(value or "").strip()
    if not text or text == "0":
        return ""
    return text
@classmethod
def _resolve_bot_self_id(
    cls,
    context: MessageContext | None,
    bot_client: Any | None,
) -> str:
    """解析真实 bot self_id,用于 OneBot 合并转发 node.uin。"""
    event = getattr(context, "event", None) if context else None
    if event is not None:
        msg_obj = getattr(event, "message_obj", None)
        self_id = cls._normalize_self_id(getattr(msg_obj, "self_id", None))
        if self_id:
            return self_id

        get_self_id = getattr(event, "get_self_id", None)
        if callable(get_self_id):
            self_id = cls._normalize_self_id(get_self_id())
            if self_id:
                return self_id

    for attr in ("self_id", "uin", "qq"):
        self_id = cls._normalize_self_id(getattr(bot_client, attr, None))
        if self_id:
            return self_id

    platform_name = getattr(context, "platform_name", "") if context else ""
    if platform_name:
        self_id = cls._normalize_self_id(get_bot_self_id(platform_name))
        if self_id:
            return self_id

    return ""

然后在构建 nodes 之前显式处理失败:

bot_client = self._resolve_bot_client(context)
bot_self_id = self._resolve_bot_self_id(context, bot_client)
if not bot_self_id:
    logger.warning(
        "OneBot merged-forward missing bot self_id: session=%s, platform=%s",
        request.session_id,
        getattr(context, "platform_name", "") if context else "",
    )
    return SendResult(ok=False, detail="missing_bot_self_id")

这样严格平台不会继续撞 uin=0,也不会伪造成固定 QQ 号;如果运行环境解析链路变了,日志和 detail 都能直接暴露问题。

2. 主动推送 provider 不建议无条件取 _wsr_api_clients 第一个 key

当前新增 provider 大致是这个逻辑:

api_clients = getattr(client, "_wsr_api_clients", None)
if isinstance(api_clients, dict):
    for self_id in api_clients.keys():
        if self_id and str(self_id) != "0":
            return str(self_id)
return ""

如果同一个 CQHttp client 后面存在多个 bot 连接,取第一个 key 不是稳定映射,可能把 A bot 的 self_id 写到 B bot 的 forward node 上。

建议先做保守处理:只在唯一候选时返回;多个候选时记录 warning 并返回空串,让 sender 暴露 missing_bot_self_id

api_clients = getattr(client, "_wsr_api_clients", None)
if isinstance(api_clients, dict):
    candidates = [
        str(self_id).strip()
        for self_id in api_clients.keys()
        if str(self_id or "").strip() and str(self_id).strip() != "0"
    ]
    if len(candidates) == 1:
        return candidates[0]
    if len(candidates) > 1:
        logger.warning(
            "解析 bot self_id 失败:platform=%s 存在多个候选 self_id=%s",
            platform_name,
            ",".join(candidates),
        )
return ""

后续如果要完整支持多 bot,最好把真实 self_id 在订阅绑定 / MessageContext / target_session 这条链路里传下来,而不是只靠 platform_name 推断。

3. types.get_bot_self_id() 也不要默认返回 "10000"

仓库里已有这个函数:

# src/infrastructure/messaging/senders/types.py
if _bot_self_id_provider:
    return _bot_self_id_provider(platform_id)
return "10000"

建议一起改成空串:

if _bot_self_id_provider:
    return _bot_self_id_provider(platform_id)
return ""

否则即使 sender 侧去掉了硬编码,provider 未注册时仍会重新得到固定兜底值。

4. 建议补的回归测试

这个 PR 改的是发送协议字段,最好补 OneBot sender 的定向测试。现有 tests/unit/infrastructure/test_onebot_sender.py 里的 fake _Node 也需要同步支持 uin

class _Node:
    def __init__(self, content: list, name: str, uin: str = "0") -> None:
        self.content = content
        self.name = name
        self.uin = uin

建议至少覆盖这几条:

async def test_onebot_merged_forward_uses_event_self_id(monkeypatch):
    ...
    context = MessageContext(
        platform_name="aiocqhttp",
        event=SimpleNamespace(
            message_obj=SimpleNamespace(self_id="123456"),
        ),
    )
    result = await sender.send_to_user(request, context=context)
    assert result.ok is True
    assert all(node.uin == "123456" for node in calls[0][1][0].nodes)
async def test_onebot_merged_forward_uses_provider_self_id_for_push(monkeypatch):
    monkeypatch.setattr(
        "astrbot_plugin_rsshub.src.infrastructure.messaging.senders.onebot_sender.get_bot_self_id",
        lambda platform_name: "654321",
    )
    ...
    context = MessageContext(platform_name="aiocqhttp")
    result = await sender.send_to_user(request, context=context)
    assert result.ok is True
    assert all(node.uin == "654321" for node in calls[0][1][0].nodes)
async def test_onebot_merged_forward_fails_when_self_id_missing(monkeypatch):
    monkeypatch.setattr(
        "astrbot_plugin_rsshub.src.infrastructure.messaging.senders.onebot_sender.get_bot_self_id",
        lambda platform_name: "",
    )
    ...
    result = await sender.send_to_user(request, context=MessageContext(platform_name="aiocqhttp"))
    assert result.ok is False
    assert result.detail == "missing_bot_self_id"
    assert calls == []

还建议补一条 stream 场景,确保 _stream_upload_nodes() 重建节点后仍保留 uin

streamed = await sender._stream_upload_nodes(bot_client, [node])
assert streamed[0].uin == node.uin

总结

这个 PR 要解决的问题是真实存在的:当前 dev 创建 OneBot merged-forward node 时没有显式传 uin。建议继续推进,但请避免固定 "10000" 兜底,改成“只使用真实 self_id,解析不到就显式失败并记录日志”,同时补上上述回归测试。

@FFFold

FFFold commented Jul 18, 2026

Copy link
Copy Markdown

napcat、snowluma现均已支持宽松的uin="0"作为缺省值,会自动fallback到Bot自身账号

Github-2333-top and others added 2 commits July 23, 2026 22:15
OneBotMessageSender 构建合并转发 Node 时未传 uin,导致 Node.uin 默认
为 "0",序列化后 user_id="0"。新版 NapCat / Lagrange 会拒绝 user_id
为 0 或空的转发节点,返回 retcode=1200 ("forward node user_id/uin is
required"),使 RSS 推送到 QQ 群失败。

修复:
- onebot_sender: 新增 _resolve_bot_self_id,优先从 event.message_obj.self_id
  读取(命令响应场景),其次通过 get_bot_self_id provider 解析(主动推送
  场景),最后兜底非零占位 "10000";构建与回退 Node 时均传入 uin。
- bootstrap: 注册 set_bot_self_id_provider,从 CQHttp 的 _wsr_api_clients
  解析已连接 bot 的 self_id(types.py 已预留 hook 但未注册)。

同时将 bot_client 解析上移到节点构建之前,使 uin 在构建节点时即可用。
@FlanChanXwO
FlanChanXwO force-pushed the fix/onebot-forward-node-uin branch from 176520c to 62ce5ee Compare July 23, 2026 14:26
@FlanChanXwO
FlanChanXwO changed the base branch from master to dev July 23, 2026 14:26
@github-actions github-actions Bot added area: docs Documentation changes area: tests Test changes labels Jul 23, 2026
@FlanChanXwO
FlanChanXwO merged commit f1ff679 into AstrBot-Elementary-School:dev Jul 23, 2026
4 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in astrbot_plugin_rsshub Jul 23, 2026
@FlanChanXwO FlanChanXwO mentioned this pull request Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: backend Backend or core runtime changes area: docs Documentation changes area: tests Test changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants