Skip to content

feat(session_waiter): allow session_waiter handler to return MessageEventResult - #9551

Open
Hiraeth-Wave wants to merge 2 commits into
AstrBotDevs:masterfrom
Hiraeth-Wave:feat/session-wainer-return-result
Open

feat(session_waiter): allow session_waiter handler to return MessageEventResult#9551
Hiraeth-Wave wants to merge 2 commits into
AstrBotDevs:masterfrom
Hiraeth-Wave:feat/session-wainer-return-result

Conversation

@Hiraeth-Wave

@Hiraeth-Wave Hiraeth-Wave commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

fix #9548

Modifications / 改动点

  • 这不是一个破坏性变更。

核心改动(2 文件,约 10 行)

  • astrbot/core/utils/session_waiter.pySessionWaiter.trigger 返回 handler 的返回值(原为丢弃),返回类型 NoneAny
  • astrbot/builtin_stars/astrbot/main.pyhandle_session_control_agent 改为 async generator——当 trigger 返回 MessageEventResultyield 它,借助 scheduler 的洋葱模型自动执行 ResultDecorateStageRespondStage(发送);否则保持原 stop_event 行为。

测试(2 文件,7 个用例)

  • tests/unit/test_session_waiter.py:覆盖 trigger 在 handler 返回 MessageEventResult / None / 抛异常 / 无对应 session 四种情况下的返回值。
  • tests/unit/test_session_control_agent.py:覆盖 handle_session_control_agent 在 trigger 返回 MessageEventResult(yield + stop)/ None(无 yield + stop)/ 无匹配 session(无操作)三种分支。

工作机制call_handler 检测到 handler 是 async generator 且 yieldMessageEventResult 时,会自动 event.set_result(ret) 再向上 yield,触发 scheduler 递归执行后续 stage。因此 waiter handler 只需 return event.plain_result(...),回复即走完整装饰流程。

向后兼容:老插件在 waiter 内用 event.send() 且不 return 的,handler 返回 None,走原 stop_event 路径,行为完全不变。新插件改为 return event.plain_result(...) 即可享受完整装饰流程。

文档更新:更新会话控制文档,使用新调用方法,增加相关提示。此外顺带更新了过时的 import

插件侧用法示例

改前(装饰功能失效):

@session_waiter(timeout=60)
async def idiom_waiter(controller: SessionController, event: AstrMessageEvent):
    ...
    await event.send(event.plain_result("先见之明"))  # 不走 @回复 / 引用 / 分段
    controller.keep(timeout=60, reset_timeout=True)

改后(装饰功能生效):

@session_waiter(timeout=60)
async def idiom_waiter(controller: SessionController, event: AstrMessageEvent):
    ...
    controller.keep(timeout=60, reset_timeout=True)
    return event.plain_result("先见之明")  # 自动走 @回复 / 引用 / 分段 / TTS / 转图

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

$ uv run pytest tests/unit/test_session_control_agent.py -q
3 passed, 1 warning in 4.52s
$ uv run pytest tests/unit/test_session_waiter.py -q
4 passed, 1 warning in 4.43s

warning 为已有的弃用依赖警告,与本次 PR 无关。


Checklist / 检查清单

  • 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。
  • 👀 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到 requirements.txtpyproject.toml 文件相应位置。
  • 😮 我的更改没有引入恶意代码。

Summary by Sourcery

Propagate session waiter handler return values so session-controlled replies can go through the normal message decoration and sending pipeline, while preserving existing behavior when handlers return None.

New Features:

  • Allow session_waiter handlers to return a MessageEventResult that is forwarded by SessionWaiter.trigger and emitted by the session control agent for standard decorated replies.

Enhancements:

  • Update the session control agent to act as an async generator that yields MessageEventResult values from session_waiter handlers before stopping the event.
  • Simplify session control imports by using astrbot.api.utils for SessionController and session_waiter in examples.

Documentation:

  • Revise Chinese and English session control guides to show returning MessageEventResult from session_waiter handlers instead of calling event.send, and document the decoration-pipeline behavior and the restriction on using yield in handlers.

Tests:

  • Add unit tests for SessionWaiter.trigger covering MessageEventResult return, None return, missing sessions, and handler exceptions.
  • Add unit tests for the session control agent covering yielding MessageEventResult, no-yield when None is returned, and no-op when no session matches.

Let session_waiter handlers return a MessageEventResult instead of forcing them to call event.send(). The returned result is yielded back into the pipeline by handle_session_control_agent, so it goes through the full ResultDecorateStage (reply-with-mention, reply-with-quote, segmented reply, TTS, text-to-image, etc.) and RespondStage like any normal reply.

Backward compatible: handlers that return None keep the original stop_event behavior.
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. area:core The bug / feature is about astrbot's core, backend labels Aug 4, 2026
@dosubot

dosubot Bot commented Aug 4, 2026

Copy link
Copy Markdown

📄 Knowledge review

Dosu skipped reviewing this PR because your organization has used its 200 included credits for the month. Your usage will reset on 2026-09-01. To have Dosu review this PR before then, ask your organization admin to upgrade to a pro account.


Leave Feedback Ask Dosu about AstrBot Add Dosu to your team

@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 reviewed your changes and they look great!


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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core The bug / feature is about astrbot's core, backend size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] session_waiter 支持返回 MessageEventResult 以走完整消息装饰流程

1 participant