Skip to content

feat: handle bot_offline notice event in OneBot adapter#623

Merged
sj817 merged 3 commits intomainfrom
copilot/feat-adapter-offline-notification
Mar 24, 2026
Merged

feat: handle bot_offline notice event in OneBot adapter#623
sj817 merged 3 commits intomainfrom
copilot/feat-adapter-offline-notification

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 23, 2026

The OneBot adapter was logging [AdapterOneBot] 收到未知事件 whenever it received a bot_offline notice (e.g., account forcibly logged out). This adds full first-class support for the event across the type system, event pipeline, and adapter.

Changes

packages/onebot

  • NoticeType.BotOffline = 'bot_offline' enum entry + BotOfflineNoticeEvent interface added to OneBotNoticeEvent union

packages/core — types

  • BotOfflineType content interface (tag, message)
  • 'botOffline' added to NoticeEventSub union; BotOfflineOptions type added (uses Contact<'friend'> / Sender<'friend'> — no group context exists for this event)
  • BotOfflineNotice added to FriendNoticeEventMap as 'notice.botOffline' and to the Notice union

packages/core — event pipeline

  • BotOfflineNotice class extending NoticeBase
  • createBotOfflineNotice factory routing through friendNoticeHandler
  • initTips case: Bot下线: <tag>

packages/core — adapter handler

  • NoticeType.BotOffline branch in createNotice using bot.selfId as contact/sender

Plugins can now subscribe to 'notice.botOffline' events:

karin.notice('notice.botOffline', async (ctx) => {
  logger.warn(`Bot ${ctx.selfId} went offline: ${ctx.content.tag}`)
})

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • registry.npmmirror.com
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/.npm/_npx/4876f32048baf8ac/node_modules/.bin/prebuild-install -r node --pkg_version=0.13.1 --pkg_name=node-pty-prebuilt-multiarch ame git (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>Feat: 适配协议端下线事件</issue_title>
<issue_description>### 描述功能

[Karin][05:59:13.712][WARN] [AdapterOneBot] 收到未知事件: {"tag":"你的帐号当前登录已失效,请重新登录。","message":"下线通知","notice_type":"bot_offline","time":1757109553,"self_id":3936555804,"post_type":"notice"}

动机

/

实现方法

No response

替代方案

No response

附加信息

No response</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Summary by Sourcery

在整个类型系统和事件管道中,为 OneBot 机器人离线通知事件添加一等支持。

新功能:

  • 在 OneBot 适配器和核心事件/内容类型定义中引入 BotOffline 通知事件类型,使机器人离线事件得到显式建模。
  • 新增 BotOfflineNotice 事件类和工厂方法,将机器人离线事件通过好友通知管道进行路由。
  • 允许插件订阅和处理带有标准化内容(标签和消息)的 notice.botOffline 事件。

改进:

  • 扩展 initTips 处理逻辑,为机器人离线事件提供可读性良好的人类提示信息。
  • 更新 OneBot 通知事件联合类型和适配器通知创建逻辑,避免将 bot_offline 事件视为未知事件。
Original summary in English

Summary by Sourcery

Add first-class support for OneBot bot offline notice events across the type system and event pipeline.

New Features:

  • Introduce a BotOffline notice event type in the OneBot adapter and core event/content typings so bot offline events are modeled explicitly.
  • Add a BotOfflineNotice event class and factory that routes bot offline events through the friend notice pipeline.
  • Allow plugins to subscribe to and handle 'notice.botOffline' events with standardized content (tag and message).

Enhancements:

  • Extend initTips handling to provide a human-readable hint for bot offline events.
  • Update the OneBot notice event union and adapter notice creation logic to avoid treating bot_offline events as unknown.

Copilot AI changed the title [WIP] Add support for adapter offline event notification feat: handle bot_offline notice event in OneBot adapter Mar 23, 2026
Copilot AI requested a review from sj817 March 23, 2026 23:46
@sj817 sj817 marked this pull request as ready for review March 24, 2026 04:47
Copilot AI review requested due to automatic review settings March 24, 2026 04:47
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Mar 24, 2026

审阅者指南(Reviewer's Guide)

为 OneBot 适配器、核心事件类型和事件流水线增加对 OneBot bot_offline 通知事件的一等支持,使 Bot 下线事件具备类型标注、按好友通知路径路由,并能作为 notice.botOffline 提供给插件使用。

处理 OneBot bot_offline 通知的时序图

sequenceDiagram
  actor OneBotServer
  participant AdapterOneBot
  participant createNotice
  participant createBotOfflineNotice
  participant friendNoticeHandler
  participant PluginSystem

  OneBotServer->>AdapterOneBot: BotOfflineNoticeEvent (notice_type = bot_offline)
  AdapterOneBot->>createNotice: createNotice(event, bot)
  createNotice->>createNotice: time = new Date(event.time * 1000)
  createNotice->>createBotOfflineNotice: BotOfflineOptions
  activate createBotOfflineNotice
  createBotOfflineNotice->>createBotOfflineNotice: new BotOfflineNotice(options)
  createBotOfflineNotice->>friendNoticeHandler: friendNoticeHandler(BotOfflineNotice)
  deactivate createBotOfflineNotice
  friendNoticeHandler->>PluginSystem: emit notice.botOffline
  PluginSystem->>PluginSystem: invoke handlers(ctx)
  PluginSystem-->>PluginSystem: ctx.tips = Bot下线: ctx.content.tag
  PluginSystem-->>PluginSystem: logger.warn(Bot offline info)
Loading

BotOffline 通知流水线的更新类图

classDiagram
  class NoticeBase {
    <<abstract>>
  }

  class BotOfflineNotice {
    - "botOffline" #subEvent
    - Contact_friend_ #contact
    - Sender_friend_ #sender
    + BotOfflineType content
    + BotOfflineNotice(options BotOfflineOptions)
    + get subEvent() string
    + get contact() Contact_friend_
    + get sender() Sender_friend_
    + get isPrivate() boolean
    + get isFriend() boolean
    + get isGroup() boolean
    + get isGuild() boolean
    + get isDirect() boolean
    + get isGroupTemp() boolean
  }

  class BotOfflineType {
    + string tag
    + string message
  }

  class BotOfflineOptions {
    + Contact_friend_ contact
    + Sender_friend_ sender
    + BotOfflineType content
  }

  class FriendNoticeEventMap {
    + BotOfflineNotice notice_botOffline
  }

  class Notice {
    + BotOfflineNotice botOfflineVariant
  }

  NoticeBase <|-- BotOfflineNotice
  BotOfflineOptions o--> BotOfflineType
  BotOfflineNotice o--> BotOfflineOptions
  FriendNoticeEventMap --> BotOfflineNotice
  Notice --> BotOfflineNotice
Loading

文件级改动

Change Details Files
引入类型化的 OneBot bot_offline 通知事件,并将其加入 OneBot 通知事件联合类型。
  • NoticeType 枚举中新增带文档注释的 BotOffline = 'bot_offline'
  • 定义 BotOfflineNoticeEvent 接口,包含 post_typenotice_typetagmessage
  • 扩展 OneBotNoticeEvent 联合类型以包含 BotOfflineNoticeEvent
packages/onebot/src/event/notice.ts
为 Bot 下线通知定义核心事件 content / options 类型,并接入现有通知类型联合/映射中。
  • 在通知内容类型中新增 BotOfflineType 接口(tag, message)。
  • 扩展 NoticeEventSub 联合类型及其文档,加入 'botOffline'
  • 新增 BotOfflineOptions,使用 Contact<'friend'>Sender<'friend'> 创建事件。
  • FriendNoticeEventMap 中将 BotOfflineNotice 注册为 'notice.botOffline',并将其纳入 Notice 联合类型。
packages/core/src/types/event/content.ts
packages/core/src/types/event/options.ts
packages/core/src/types/event/event.ts
实现 BotOfflineNotice 事件类和创建工厂,并集成到好友通知处理器及 tips 初始化逻辑中。
  • 创建继承 NoticeBaseBotOfflineNotice 类,带好友/私聊标记以及 content 字段。
  • 新增 createBotOfflineNotice 工厂方法,用于构造 BotOfflineNotice 并通过 friendNoticeHandler 路由。
  • 更新 initTips 处理器,在 'botOffline' 子事件中将 ctx.tips 设置为 Bot下线: <tag>
packages/core/src/event/notice.ts
packages/core/src/event/create/index.ts
packages/core/src/event/handler/other/other.ts
在 OneBot 适配器中处理 OneBot bot_offline 通知,并发送类型化的 BotOfflineNotice,而不是将其视为未知事件。
  • createNotice 中增加 NoticeType.BotOffline 分支,通过 createBotOfflineNotice 构造 BotOfflineNotice
  • 通过 contactFriend / senderFriend 使用 bot.selfId 同时作为 contact 和 sender,并设置 srcReply 以通过 bot.sendMsg 回复。
  • bot_offline 从记录未知通知事件的兜底路径中移除。
packages/core/src/adapter/onebot/create/notice.ts

与关联 issue 的对照评估

Issue Objective Addressed Explanation
#523 在 OneBot 适配器中支持 OneBot bot_offline 通知事件,使其被识别而不是被当作未知事件记录日志。
#523 bot_offline 通知集成进核心事件/类型系统,使其成为插件可订阅的一等通知事件。

可能关联的 issues


Tips and commands

与 Sourcery 交互

  • 触发新的审查: 在 pull request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub issue: 在审查评论下回复,要求 Sourcery 从该评论创建 issue。也可以直接回复 @sourcery-ai issue,从该评论创建 issue。
  • 生成 pull request 标题: 在 PR 标题的任意位置写上 @sourcery-ai 即可随时生成标题。也可以在 PR 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 pull request 摘要: 在 PR 正文任意位置写上 @sourcery-ai summary,即可在该位置生成 PR 摘要。也可以在 PR 中评论 @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 来触发新的审查!

自定义你的体验

前往你的 dashboard 可以:

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

获取帮助

Original review guide in English

Reviewer's Guide

Adds first-class support for OneBot bot_offline notice events across the OneBot adapter, core event types, and event pipeline so that bot offline events are typed, routed as friend notices, and available to plugins as notice.botOffline.

Sequence diagram for handling OneBot bot_offline notice

sequenceDiagram
  actor OneBotServer
  participant AdapterOneBot
  participant createNotice
  participant createBotOfflineNotice
  participant friendNoticeHandler
  participant PluginSystem

  OneBotServer->>AdapterOneBot: BotOfflineNoticeEvent (notice_type = bot_offline)
  AdapterOneBot->>createNotice: createNotice(event, bot)
  createNotice->>createNotice: time = new Date(event.time * 1000)
  createNotice->>createBotOfflineNotice: BotOfflineOptions
  activate createBotOfflineNotice
  createBotOfflineNotice->>createBotOfflineNotice: new BotOfflineNotice(options)
  createBotOfflineNotice->>friendNoticeHandler: friendNoticeHandler(BotOfflineNotice)
  deactivate createBotOfflineNotice
  friendNoticeHandler->>PluginSystem: emit notice.botOffline
  PluginSystem->>PluginSystem: invoke handlers(ctx)
  PluginSystem-->>PluginSystem: ctx.tips = Bot下线: ctx.content.tag
  PluginSystem-->>PluginSystem: logger.warn(Bot offline info)
Loading

Updated class diagram for BotOffline notice pipeline

classDiagram
  class NoticeBase {
    <<abstract>>
  }

  class BotOfflineNotice {
    - "botOffline" #subEvent
    - Contact_friend_ #contact
    - Sender_friend_ #sender
    + BotOfflineType content
    + BotOfflineNotice(options BotOfflineOptions)
    + get subEvent() string
    + get contact() Contact_friend_
    + get sender() Sender_friend_
    + get isPrivate() boolean
    + get isFriend() boolean
    + get isGroup() boolean
    + get isGuild() boolean
    + get isDirect() boolean
    + get isGroupTemp() boolean
  }

  class BotOfflineType {
    + string tag
    + string message
  }

  class BotOfflineOptions {
    + Contact_friend_ contact
    + Sender_friend_ sender
    + BotOfflineType content
  }

  class FriendNoticeEventMap {
    + BotOfflineNotice notice_botOffline
  }

  class Notice {
    + BotOfflineNotice botOfflineVariant
  }

  NoticeBase <|-- BotOfflineNotice
  BotOfflineOptions o--> BotOfflineType
  BotOfflineNotice o--> BotOfflineOptions
  FriendNoticeEventMap --> BotOfflineNotice
  Notice --> BotOfflineNotice
Loading

File-Level Changes

Change Details Files
Introduce typed OneBot bot_offline notice event and include it in the OneBot notice event union.
  • Add BotOffline = 'bot_offline' to NoticeType enum with documentation comment.
  • Define BotOfflineNoticeEvent interface including post_type, notice_type, tag, and message.
  • Extend OneBotNoticeEvent union to include BotOfflineNoticeEvent.
packages/onebot/src/event/notice.ts
Define core event content and options types for bot offline notices and wire them into existing notice type unions/maps.
  • Add BotOfflineType interface (tag, message) to notice content types.
  • Extend NoticeEventSub union and its documentation with 'botOffline'.
  • Add BotOfflineOptions using Contact<'friend'> and Sender<'friend'> for event creation.
  • Register BotOfflineNotice in FriendNoticeEventMap as 'notice.botOffline' and include it in the Notice union.
packages/core/src/types/event/content.ts
packages/core/src/types/event/options.ts
packages/core/src/types/event/event.ts
Implement BotOfflineNotice event class and creation factory, and integrate with the friend notice handler and tips initialization.
  • Create BotOfflineNotice class extending NoticeBase with friend/private flags and content field.
  • Add createBotOfflineNotice factory that constructs BotOfflineNotice and routes it through friendNoticeHandler.
  • Update initTips handler to set ctx.tips to Bot下线: <tag> for 'botOffline' sub-events.
packages/core/src/event/notice.ts
packages/core/src/event/create/index.ts
packages/core/src/event/handler/other/other.ts
Handle OneBot bot_offline notice in the OneBot adapter and emit a typed BotOfflineNotice instead of treating it as unknown.
  • Add NoticeType.BotOffline branch in createNotice to build a BotOfflineNotice via createBotOfflineNotice.
  • Use bot.selfId as both contact and sender via contactFriend/senderFriend, and set srcReply to reply via bot.sendMsg.
  • Remove bot_offline from the fallback path that logs unknown notice events.
packages/core/src/adapter/onebot/create/notice.ts

Assessment against linked issues

Issue Objective Addressed Explanation
#523 Support the OneBot bot_offline notice event in the OneBot adapter so it is recognized instead of logged as an unknown event.
#523 Integrate the bot_offline notice into the core event/type system so it becomes a first-class notice event that plugins can subscribe to.

Possibly linked issues


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

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - 我发现了 1 个问题

给 AI 代理的提示
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="packages/core/src/event/notice.ts" line_range="1278-1279" />
<code_context>
+  #sender: BotOfflineOptions['sender']
+  content: BotOfflineOptions['content']
+
+  constructor (options: BotOfflineOptions) {
+    super(Object.assign(options, { subEvent: 'botOffline' as const }))
+
+    this.#subEvent = 'botOffline'
</code_context>
<issue_to_address>
**issue (bug_risk):** 在调用 `super` 之前设置 `subEvent` 时,应避免对 `options` 对象进行修改。

`Object.assign(options, { subEvent: 'botOffline' as const })` 会改变原始的 `options` 对象,如果该实例在其他地方被复用或检查,可能会导致一些隐蔽的 bug。应改为向 `super` 传入一个新对象,例如 `super({ ...options, subEvent: 'botOffline' as const })``super(Object.assign({}, options, { subEvent: 'botOffline' as const }))`,从而保证调用方传入的 `options` 保持不变。
</issue_to_address>

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

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="packages/core/src/event/notice.ts" line_range="1278-1279" />
<code_context>
+  #sender: BotOfflineOptions['sender']
+  content: BotOfflineOptions['content']
+
+  constructor (options: BotOfflineOptions) {
+    super(Object.assign(options, { subEvent: 'botOffline' as const }))
+
+    this.#subEvent = 'botOffline'
</code_context>
<issue_to_address>
**issue (bug_risk):** Avoid mutating the `options` object when setting `subEvent` before calling `super`.

`Object.assign(options, { subEvent: 'botOffline' as const })` mutates the original `options` object, which can cause subtle bugs if that instance is reused or inspected elsewhere. Instead, pass a new object to `super`, e.g. `super({ ...options, subEvent: 'botOffline' as const })` or `super(Object.assign({}, options, { subEvent: 'botOffline' as const }))`, so the caller’s `options` remains unchanged.
</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 thread packages/core/src/event/notice.ts
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds first-class handling for OneBot bot_offline notice events end-to-end (OneBot adapter typings → core event types → event creation/dispatch → adapter routing), eliminating the “unknown event” warning and enabling plugins to subscribe to notice.botOffline.

Changes:

  • Added NoticeType.BotOffline = 'bot_offline' and BotOfflineNoticeEvent to the OneBot notice event union.
  • Added BotOfflineType, botOffline sub-event typing, BotOfflineOptions, and wired notice.botOffline into the core notice event map/union.
  • Implemented BotOfflineNotice + factory + handler routing, plus tips initialization and OneBot adapter branch to create the event.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/onebot/src/event/notice.ts Adds OneBot notice enum + event interface for bot_offline.
packages/core/src/types/event/content.ts Introduces BotOfflineType payload (tag, message).
packages/core/src/types/event/options.ts Adds botOffline to NoticeEventSub and defines BotOfflineOptions.
packages/core/src/types/event/event.ts Wires notice.botOffline into the event map and Notice union.
packages/core/src/event/notice.ts Implements BotOfflineNotice event class.
packages/core/src/event/create/index.ts Adds createBotOfflineNotice factory routed via friendNoticeHandler.
packages/core/src/event/handler/other/other.ts Adds initTips formatting for botOffline.
packages/core/src/adapter/onebot/create/notice.ts Routes OneBot bot_offline to createBotOfflineNotice.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/core/src/adapter/onebot/create/notice.ts Outdated
…in bot_offline handler

Co-authored-by: sj817 <74231782+sj817@users.noreply.github.com>
Agent-Logs-Url: https://github.com/KarinJS/Karin/sessions/34c587bf-3892-4a64-8b9f-60637af418ec
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 24, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • registry.npmmirror.com
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/.npm/_npx/4876f32048baf8ac/node_modules/.bin/prebuild-install -r node --pkg_version=0.13.1 --pkg_name=node-pty-prebuilt-multiarch (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@github-actions
Copy link
Copy Markdown
Contributor

你可以通过以下命令安装该版本:

pnpm add https://pkg.pr.new/node-karin@da737eb -w

@sj817 sj817 merged commit 61b5a7d into main Mar 24, 2026
5 checks passed
@sj817 sj817 deleted the copilot/feat-adapter-offline-notification branch March 24, 2026 05:09
@github-actions github-actions Bot mentioned this pull request Mar 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: 适配协议端下线事件

3 participants