Skip to content

feat:发送消息前的At和Reply改用概率添加,同时过滤掉不支持的组件 #1818

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

Zhalslar
Copy link
Contributor

@Zhalslar Zhalslar commented Jun 15, 2025

Motivation

  • 目前在发送消息前给消息附加的At组件或Reply组件只能设置为True/False,一些用户希望改成按概率附加,从而达到更拟人的效果
  • At、Reply组件不能和Record、Video、File等组件放在一个消息链里,否则会导致语音、视频、文件等组件发不出来,要增加一个过滤机制

Modifications

  • 概率控制:将 reply_with_mention 和 reply_with_quote 从布尔值改为支持 0.0~1.0 的概率值,允许控制回复行为触发概率。
  • 兼容处理:若旧配置仍为布尔值,将自动转换为对应的概率值(True → 1.0,False → 0.0)。
  • 优化触发条件:避免私聊触发 @,防止重复 @bot,仅在消息链存在Plain、Face、Image、At时考虑插入At、Reply组件。

Check

  • 😊 我的 Commit Message 符合良好的规范
  • 👀 我的更改经过良好的测试
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。
  • 😮 我的更改没有引入恶意代码

Sourcery 总结

启用概率性插入提及(At)和引用回复组件,并针对不支持的消息链进行过滤,以及向后兼容布尔配置。

新特性:

  • 支持基于概率的提及和引用回复触发器,而不是布尔标志

增强功能:

  • 自动将旧的布尔回复设置转换为等效的浮点概率
  • 过滤 At/Reply 注入到仅包含受支持组件的消息,并防止重复或私聊提及
Original summary in English

Sourcery 总结

启用概率性插入提及和引用回复组件,过滤不支持的消息链,并保持与布尔配置的向后兼容性

新特性:

  • 支持基于概率的 'reply_with_mention' 和 'reply_with_quote' 触发器

Bug 修复:

  • 阻止提及/引用注入阻止语音、视频和文件组件,并避免私有或重复的机器人提及

增强功能:

  • 自动将旧的布尔回复配置转换为等效的概率值
  • 限制提及/引用插入到包含支持的组件类型的消息链

文档:

  • 更新默认配置模式和提示,以使用浮点概率进行提及和引用设置
Original summary in English

Summary by Sourcery

Enable probabilistic insertion of mention and quote reply components, filter unsupported message chains, and maintain backward compatibility with boolean configs

New Features:

  • Support probability-based 'reply_with_mention' and 'reply_with_quote' triggers

Bug Fixes:

  • Prevent mention/quote injections from blocking voice, video, and file components and avoid private or duplicate bot mentions

Enhancements:

  • Auto-convert legacy boolean reply configs to equivalent probability values
  • Restrict mention/quote insertion to message chains containing supported component types

Documentation:

  • Update default config schema and hints to use float probabilities for mention and quote settings

Copy link
Contributor

sourcery-ai bot commented Jun 15, 2025

## 审查者指南

此 PR 重构了 At 和 Reply 组件的注入,以使用可配置的概率值,添加了过滤以避免不支持或重复的注入,更新了默认配置和模式条目,将布尔值更改为浮点数,并提供了旧版布尔设置到概率的向后兼容转换。

#### 类图:概率回复的配置和逻辑

```mermaid
classDiagram
    class PlatformSettingsConfig {
        <<Configuration>>
        reply_with_mention: float
        reply_with_quote: float
        %% 为了清晰起见,省略了其他设置,如 path_mapping, segmented_reply
    }

    class AstrBotConfig {
        <<Configuration Handler>>
        +check_config_integrity(refer_conf: dict, conf: dict, path: str) : bool
        %% 方法已更新,用于转换 'platform_settings' 中
        %% reply_with_mention 和 reply_with_quote 的旧版布尔值
        %% 路径到浮点概率 (True->1.0, False->0.0)。
    }

    class ResultDecorateStage {
        <<Pipeline Stage>>
        reply_with_mention: float // 从 PlatformSettingsConfig 初始化
        reply_with_quote: float   // 从 PlatformSettingsConfig 初始化
        +process(event: Event, result: Result) : void
        %% 方法逻辑已更新,以使用浮点概率进行 At/Reply 注入
        %% 以及基于消息内容和类型的新过滤条件。
    }

    ResultDecorateStage ..> PlatformSettingsConfig : uses
    AstrBotConfig ..> PlatformSettingsConfig : manages/validates

文件级别更改

Change Details Files
将 mention 和 quote 标志从布尔值转换为基于概率的触发器
  • 用 random.random() < 配置的概率替换布尔值检查
  • 对 At 和 Reply 插入应用概率条件
astrbot/core/pipeline/result_decorate/stage.py
过滤注入到支持的消息链并防止重复/私有提及
  • 仅当链包含 Plain、Face、Image 或 At 组件时才考虑插入
  • 防止在私聊中 @-提及,并避免重新提及机器人
  • 如果链包含 File 组件,则跳过引用回复
astrbot/core/pipeline/result_decorate/stage.py
将默认配置值和模式类型更新为浮点数
  • 将默认的 reply_with_mention 和 reply_with_quote 从 False 更改为 0.0
  • 修改模式条目,将类型从 bool 更改为 float
  • 修改提示以指定概率范围 0.0–1.0
astrbot/core/config/default.py
添加布尔配置到概率的向后兼容转换
  • 检测 platform_settings 中回复设置的布尔值
  • 转换 True→1.0 和 False→0.0 并记录转换
astrbot/core/config/astrbot_config.py

可能相关的 issue

  • 无法运行 #123: PR 实现了概率和条件引用/提及逻辑,解决了 issue 的灵活性请求。

提示和命令

与 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

This PR refactors the injection of At and Reply components to use configurable probability values, adds filtering to avoid unsupported or duplicate injections, updates default configuration and schema entries from booleans to floats, and provides backward-compatible conversion of legacy boolean settings to probabilities.

Class Diagram: Configuration and Logic for Probabilistic Replies

classDiagram
    class PlatformSettingsConfig {
        <<Configuration>>
        reply_with_mention: float
        reply_with_quote: float
        %% Other settings like path_mapping, segmented_reply omitted for clarity
    }

    class AstrBotConfig {
        <<Configuration Handler>>
        +check_config_integrity(refer_conf: dict, conf: dict, path: str) : bool
        %% Method updated to convert legacy boolean values for
        %% reply_with_mention and reply_with_quote in 'platform_settings'
        %% path to float probabilities (True->1.0, False->0.0).
    }

    class ResultDecorateStage {
        <<Pipeline Stage>>
        reply_with_mention: float // Initialized from PlatformSettingsConfig
        reply_with_quote: float   // Initialized from PlatformSettingsConfig
        +process(event: Event, result: Result) : void
        %% Method logic updated to use float probabilities for At/Reply injection
        %% and new filtering conditions based on message content and type.
    }

    ResultDecorateStage ..> PlatformSettingsConfig : uses
    AstrBotConfig ..> PlatformSettingsConfig : manages/validates
Loading

File-Level Changes

Change Details Files
Convert mention and quote flags from boolean to probability-based triggers
  • Replace boolean checks with random.random() < configured probability
  • Apply probabilistic conditions for both At and Reply insertion
astrbot/core/pipeline/result_decorate/stage.py
Filter injections to supported message chains and prevent duplicates/private mentions
  • Only consider insertion when chain contains Plain, Face, Image, or At components
  • Prevent @-mentions in private chats and avoid re-mentioning the bot
  • Skip quote replies if the chain contains File components
astrbot/core/pipeline/result_decorate/stage.py
Update default configuration values and schema types to floats
  • Change default reply_with_mention and reply_with_quote from False to 0.0
  • Modify schema entries from type bool to float
  • Revise hints to specify probability range 0.0–1.0
astrbot/core/config/default.py
Add backward-compatible conversion of boolean configs to probabilities
  • Detect boolean values for reply settings in platform_settings
  • Convert True→1.0 and False→0.0 and log the conversion
astrbot/core/config/astrbot_config.py

Possibly linked issues

  • 无法运行 #123: PR implements probabilistic and conditional quote/mention logic, addressing the issue's flexibility request.

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
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.

@Zhalslar - 我已经查看了你的更改 - 这里有一些反馈:

  • 引用插入过滤器仅检查文件组件,但你的描述还提到了记录和视频 - 考虑扩展过滤器以排除这些类型。
  • 验证或限制加载时的 reply_with_mentionreply_with_quote 会更安全,以确保它们保持在 [0.0, 1.0] 范围内,并避免因配置错误而导致的意外行为。
AI 代理的提示
请解决此代码审查中的评论:
## 总体评论
- 引用插入过滤器仅检查文件组件,但你的描述还提到了记录和视频 - 考虑扩展过滤器以排除这些类型。
- 验证或限制加载时的 `reply_with_mention``reply_with_quote` 会更安全,以确保它们保持在 [0.0, 1.0] 范围内,并避免因配置错误而导致的意外行为。

## 单独评论

### 评论 1
<location> `astrbot/core/pipeline/result_decorate/stage.py:282` </location>
<code_context>
                 # at 回复
                 if (
-                    self.reply_with_mention
+                    random.random() < self.reply_with_mention
                     and event.get_message_type() != MessageType.FRIEND_MESSAGE
+                    and not (
</code_context>

<issue_to_address>
考虑强制执行有效的概率范围

这些概率的无效浮点数值可能会导致意外行为。在加载时限制它们,或者验证配置以确保它们保持在 0.0–1.0 之间。

建议的实施方案:

```python
    def __init__(self, ..., reply_with_mention, ...):
        # Clamp reply_with_mention to [0.0, 1.0]
        self.reply_with_mention = min(max(reply_with_mention, 0.0), 1.0)
        ...

```

如果在其他地方设置了 `self.reply_with_mention`(例如,通过配置加载器或 setter),则应在每次赋值时应用相同的限制逻辑。如果想在任何地方都强制执行此操作,请考虑将其设为具有 setter 的属性,该 setter 会限制该值。
</issue_to_address>

### 评论 2
<location> `astrbot/core/config/default.py:28` </location>
<code_context>
         "wl_ignore_admin_on_friend": True,
-        "reply_with_mention": False,
-        "reply_with_quote": False,
+        "reply_with_mention": 0.0,
+        "reply_with_quote": 0.0,
         "path_mapping": [],
         "segmented_reply": {
</code_context>

<issue_to_address>
为浮点概率添加 JSON 模式范围约束

请将 `minimum: 0.0``maximum: 1.0` 添加到这些模式字段,以强制执行有效的概率值。

建议的实施方案:

```python
                    "reply_with_mention": {
                        "description": "回复时 @ 发送者",
                        "type": "float",
                        "minimum": 0.0,
                        "maximum": 1.0,
                        "hint": "启用后,机器人回复消息时会 @ 发送者。0.0-1.0 之间的概率值,0.0 表示从不,1.0 表示总是。实际效果以具体的平台适配器为准。",
                    },
                    "reply_with_quote": {

```

```python
                    "reply_with_quote": {
                        "description": "回复时引用消息",
                        "type": "float",
                        "minimum": 0.0,
                        "maximum": 1.0,
                        "hint": "启用后,机器人回复消息时会引用原消息。0.0-1.0 之间的概率值,0.0 表示从不,1.0 表示总是。实际效果以具体的平台适配器为准。",
                    },

```
</issue_to_address>

Sourcery 对开源是免费的 - 如果你喜欢我们的评论,请考虑分享它们 ✨
帮助我更有用!请点击每个评论上的 👍 或 👎,我将使用反馈来改进你的评论。
Original comment in English

Hey @Zhalslar - I've reviewed your changes - here's some feedback:

  • The quote‐insertion filter only checks for File components, but your description mentions also Record and Video—consider extending the filter to exclude those types too.
  • It would be safer to validate or clamp reply_with_mention and reply_with_quote on load to ensure they stay within [0.0, 1.0] and avoid unexpected behavior if misconfigured.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The quote‐insertion filter only checks for File components, but your description mentions also Record and Video—consider extending the filter to exclude those types too.
- It would be safer to validate or clamp `reply_with_mention` and `reply_with_quote` on load to ensure they stay within [0.0, 1.0] and avoid unexpected behavior if misconfigured.

## Individual Comments

### Comment 1
<location> `astrbot/core/pipeline/result_decorate/stage.py:282` </location>
<code_context>
                 # at 回复
                 if (
-                    self.reply_with_mention
+                    random.random() < self.reply_with_mention
                     and event.get_message_type() != MessageType.FRIEND_MESSAGE
+                    and not (
</code_context>

<issue_to_address>
Consider enforcing valid probability range

Invalid float values for these probabilities could cause unintended behavior. Clamp them at load time or validate the config to ensure they stay within 0.0–1.0.

Suggested implementation:

```python
    def __init__(self, ..., reply_with_mention, ...):
        # Clamp reply_with_mention to [0.0, 1.0]
        self.reply_with_mention = min(max(reply_with_mention, 0.0), 1.0)
        ...

```

If `self.reply_with_mention` is set elsewhere (e.g., via a config loader or setter), you should apply the same clamping logic at every assignment. If you want to enforce this everywhere, consider making it a property with a setter that clamps the value.
</issue_to_address>

### Comment 2
<location> `astrbot/core/config/default.py:28` </location>
<code_context>
         "wl_ignore_admin_on_friend": True,
-        "reply_with_mention": False,
-        "reply_with_quote": False,
+        "reply_with_mention": 0.0,
+        "reply_with_quote": 0.0,
         "path_mapping": [],
         "segmented_reply": {
</code_context>

<issue_to_address>
Add JSON schema range constraints for float probabilities

Please add `minimum: 0.0` and `maximum: 1.0` to these schema fields to enforce valid probability values.

Suggested implementation:

```python
                    "reply_with_mention": {
                        "description": "回复时 @ 发送者",
                        "type": "float",
                        "minimum": 0.0,
                        "maximum": 1.0,
                        "hint": "启用后,机器人回复消息时会 @ 发送者。0.0-1.0 之间的概率值,0.0 表示从不,1.0 表示总是。实际效果以具体的平台适配器为准。",
                    },
                    "reply_with_quote": {

```

```python
                    "reply_with_quote": {
                        "description": "回复时引用消息",
                        "type": "float",
                        "minimum": 0.0,
                        "maximum": 1.0,
                        "hint": "启用后,机器人回复消息时会引用原消息。0.0-1.0 之间的概率值,0.0 表示从不,1.0 表示总是。实际效果以具体的平台适配器为准。",
                    },

```
</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.

# at 回复
if (
self.reply_with_mention
random.random() < self.reply_with_mention
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (bug_risk): 考虑强制执行有效的概率范围

这些概率的无效浮点数值可能会导致意外行为。在加载时限制它们,或者验证配置以确保它们保持在 0.0-1.0 之间。

建议的实施方案:

    def __init__(self, ..., reply_with_mention, ...):
        # Clamp reply_with_mention to [0.0, 1.0]
        self.reply_with_mention = min(max(reply_with_mention, 0.0), 1.0)
        ...

如果在其他地方设置了 self.reply_with_mention(例如,通过配置加载器或 setter),则应在每次赋值时应用相同的限制逻辑。如果想在任何地方都强制执行此操作,请考虑将其设为具有 setter 的属性,该 setter 会限制该值。

Original comment in English

suggestion (bug_risk): Consider enforcing valid probability range

Invalid float values for these probabilities could cause unintended behavior. Clamp them at load time or validate the config to ensure they stay within 0.0–1.0.

Suggested implementation:

    def __init__(self, ..., reply_with_mention, ...):
        # Clamp reply_with_mention to [0.0, 1.0]
        self.reply_with_mention = min(max(reply_with_mention, 0.0), 1.0)
        ...

If self.reply_with_mention is set elsewhere (e.g., via a config loader or setter), you should apply the same clamping logic at every assignment. If you want to enforce this everywhere, consider making it a property with a setter that clamps the value.

Comment on lines +28 to +29
"reply_with_mention": 0.0,
"reply_with_quote": 0.0,
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: 为浮点概率添加 JSON 模式范围约束

请将 minimum: 0.0maximum: 1.0 添加到这些模式字段,以强制执行有效的概率值。

建议的实施方案:

                    "reply_with_mention": {
                        "description": "回复时 @ 发送者",
                        "type": "float",
                        "minimum": 0.0,
                        "maximum": 1.0,
                        "hint": "启用后,机器人回复消息时会 @ 发送者。0.0-1.0 之间的概率值,0.0 表示从不,1.0 表示总是。实际效果以具体的平台适配器为准。",
                    },
                    "reply_with_quote": {
                    "reply_with_quote": {
                        "description": "回复时引用消息",
                        "type": "float",
                        "minimum": 0.0,
                        "maximum": 1.0,
                        "hint": "启用后,机器人回复消息时会引用原消息。0.0-1.0 之间的概率值,0.0 表示从不,1.0 表示总是。实际效果以具体的平台适配器为准。",
                    },
Original comment in English

suggestion: Add JSON schema range constraints for float probabilities

Please add minimum: 0.0 and maximum: 1.0 to these schema fields to enforce valid probability values.

Suggested implementation:

                    "reply_with_mention": {
                        "description": "回复时 @ 发送者",
                        "type": "float",
                        "minimum": 0.0,
                        "maximum": 1.0,
                        "hint": "启用后,机器人回复消息时会 @ 发送者。0.0-1.0 之间的概率值,0.0 表示从不,1.0 表示总是。实际效果以具体的平台适配器为准。",
                    },
                    "reply_with_quote": {
                    "reply_with_quote": {
                        "description": "回复时引用消息",
                        "type": "float",
                        "minimum": 0.0,
                        "maximum": 1.0,
                        "hint": "启用后,机器人回复消息时会引用原消息。0.0-1.0 之间的概率值,0.0 表示从不,1.0 表示总是。实际效果以具体的平台适配器为准。",
                    },

Comment on lines 296 to 298
if random.random() < self.reply_with_quote:
if not any(isinstance(item, File) for item in result.chain):
result.chain.insert(0, Reply(id=event.message_obj.message_id))
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (code-quality): 合并嵌套的 if 条件 (merge-nested-ifs)

Suggested change
if random.random() < self.reply_with_quote:
if not any(isinstance(item, File) for item in result.chain):
result.chain.insert(0, Reply(id=event.message_obj.message_id))
if random.random() < self.reply_with_quote and not any(isinstance(item, File) for item in result.chain):
result.chain.insert(0, Reply(id=event.message_obj.message_id))


Explanation过多的嵌套会使代码难以理解,这在 Python 中尤其如此,因为没有括号来帮助区分不同的嵌套级别。

阅读深度嵌套的代码令人困惑,因为您必须跟踪哪些条件与哪些级别相关。因此,我们努力尽可能减少嵌套,并且可以使用 and 组合两个 if 条件的情况很容易实现。

Original comment in English

suggestion (code-quality): Merge nested if conditions (merge-nested-ifs)

Suggested change
if random.random() < self.reply_with_quote:
if not any(isinstance(item, File) for item in result.chain):
result.chain.insert(0, Reply(id=event.message_obj.message_id))
if random.random() < self.reply_with_quote and not any(isinstance(item, File) for item in result.chain):
result.chain.insert(0, Reply(id=event.message_obj.message_id))


ExplanationToo much nesting can make code difficult to understand, and this is especially
true in Python, where there are no brackets to help out with the delineation of
different nesting levels.

Reading deeply nested code is confusing, since you have to keep track of which
conditions relate to which levels. We therefore strive to reduce nesting where
possible, and the situation where two if conditions can be combined using
and is an easy win.

@Zhalslar
Copy link
Contributor Author

关于AI提到的为浮点概率添加 JSON 模式范围约束,这个可以统一为所有这类浮点配置添加约束,考虑到保持一致性这里就不加约束了,实际上超出约束照样能达到预期效果。另外一删除多余的File组件判断

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.

1 participant