Skip to content

Conversation

@Soulter
Copy link
Member

@Soulter Soulter commented Sep 16, 2025


Motivation / 动机

减少 unexpected behavior

Modifications / 改动点

主要都集中于 pyright type checking 的报错

Verification Steps / 验证步骤

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

Compatibility & Breaking Changes / 兼容性与破坏性变更

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

Checklist / 检查清单

  • 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 👀 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
  • 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

Sourcery 总结

优化类型注解并添加运行时检查,以消除核心 star、provider、agent 和 tool 模块中的 Pyright 类型检查错误。

改进:

  • 将泛型 Awaitable 类型替换为 Callable[..., Awaitable[Any]],并对可选参数使用联合管道语法。
  • register_commandregister_command_group 装饰器中,针对缺失的参数添加日志警告。
  • 在提供者管理器和 star 上下文中,引入运行时类型守卫并在检索提供者时引发 ValueError
  • 调整函数工具模式转换和工具管理器签名,以符合静态类型要求。
  • 在卸载和更新操作期间,包含空值检查和错误处理以确保插件数据完整性。
Original summary in English

Summary by Sourcery

Refine type annotations and add runtime checks to eliminate Pyright type checking errors across core star, provider, agent, and tool modules.

Enhancements:

  • Replace generic Awaitable types with Callable[..., Awaitable[Any]] and use union pipe syntax for optional parameters.
  • Add logger warnings for missing parameters in register_command and register_command_group decorators.
  • Introduce runtime type guards and ValueError on provider retrieval in provider manager and star context.
  • Adjust function tool schema conversion and tool manager signatures to align with static typing requirements.
  • Include null checks and error handling for plugin data completeness during uninstall and update operations.

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.

你好 - 我已审阅了你的更改 - 以下是一些反馈:

  • register_commandregister_command_group 中,缺少必需参数目前只会记录警告,但仍然返回一个不起作用的装饰器;考虑抛出错误或明确返回一个无操作装饰器以实现快速失败并避免静默的错误配置。
  • 你正在对插件和 MCP 客户端错误使用通用的 Exception/ValueError——引入更具体的自定义异常类型将使错误处理更清晰、更容易捕获。
  • 宽泛的 Callable[..., Awaitable[Any]] 注释涵盖了所有异步签名;考虑定义一个 ProtocolTypeVar 来缩小预期的处理程序签名并提高类型安全性。
Prompt for AI Agents
请处理此代码审查中的评论:

## 总体评论
-`register_command``register_command_group` 中,缺少必需参数目前只会记录警告,但仍然返回一个不起作用的装饰器;考虑抛出错误或明确返回一个无操作装饰器以实现快速失败并避免静默的错误配置。
- 你正在对插件和 MCP 客户端错误使用通用的 `Exception`/`ValueError`——引入更具体的自定义异常类型将使错误处理更清晰、更容易捕获。
- 宽泛的 `Callable[..., Awaitable[Any]]` 注释涵盖了所有异步签名;考虑定义一个 `Protocol``TypeVar` 来缩小预期的处理程序签名并提高类型安全性。

## 独立评论

### 评论 1
<location> `astrbot/core/star/session_plugin_manager.py:143-141` </location>
<code_context>
                 filtered_handlers.append(handler)
                 continue

+            if plugin.name is None:
+                continue
+
             # 检查插件是否在当前会话中启用
</code_context>

<issue_to_address>
**suggestion (bug_risk):** 插件名称为 None 时跳过可能会隐藏注册问题。

在跳过没有名称的插件时记录警告或错误,以帮助诊断潜在的注册问题。

建议实现:

```python
                filtered_handlers.append(handler)
                continue

            if plugin.name is None:
                import logging
                logging.warning(f"Skipping plugin with no name: {plugin!r}")
                continue

            # 检查插件是否在当前会话中启用

```

如果文件中其他地方已经导入了 logging,你可以从这个块中删除 `import logging` 行。
你可能还需要在应用程序的其他地方配置日志级别和格式(如果尚未完成)。
</issue_to_address>

### 评论 2
<location> `astrbot/core/provider/manager.py:91` </location>
<code_context>
-        self.curr_provider_inst = self.inst_map[provider_id]
-        if provider_type == ProviderType.TEXT_TO_SPEECH:
+
+        prov = self.inst_map[provider_id]
+        if provider_type == ProviderType.TEXT_TO_SPEECH and isinstance(
+            prov, TTSProvider
</code_context>

<issue_to_address>
**issue (complexity):** 考虑将重复的按类型分支重构为简洁的查找表和循环,以进行提供者管理。

你可以在 `get_using_provider``terminate_provider` 中将所有这些按类型分支折叠成一个小的查找表 + 单个循环。例如:

```python
# at class‐level
_PROVIDER_CONFIG = {
    ProviderType.TEXT_TO_SPEECH:  ("curr_tts_provider_inst",  TTSProvider, "curr_provider_tts"),
    ProviderType.SPEECH_TO_TEXT:  ("curr_stt_provider_inst",  STTProvider, "curr_provider_stt"),
    ProviderType.CHAT_COMPLETION: ("curr_provider_inst",      Provider,    "curr_provider"),
}
```

然后在 `get_using_provider` 中:

```python
prov = self.inst_map[provider_id]
attr, cls, sp_key = self._PROVIDER_CONFIG[provider_type]
if isinstance(prov, cls):
    setattr(self, attr, prov)
    sp.put(sp_key, provider_id, scope="global", scope_id="global")
````terminate_provider` 中,你可以通过迭代列表和 `curr_*` 属性来删除所有 `isinstance` 检查/remove 调用:

```python
inst = self.inst_map[provider_id]

# remove from any list it lives in
for lst in (
    self.provider_insts,
    self.stt_provider_insts,
    self.tts_provider_insts,
    self.embedding_provider_insts,
):
    if inst in lst:
        lst.remove(inst)

# clear any curr_* pointer
for attr, _, _ in self._PROVIDER_CONFIG.values():
    if getattr(self, attr) is inst:
        setattr(self, attr, None)

if getattr(inst, "terminate", None):
    await inst.terminate()
```

这保留了完全相同的行为,但将所有重复的 `if isinstance(...)` / `remove(...)` / `setattr(...)` / `sp.put(...)` 代码折叠成了两个非常简洁的循环。
</issue_to_address>

### 评论 3
<location> `astrbot/core/agent/mcp_client.py:202` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** 抛出特定错误而非通用的 `Exception``BaseException` ([`raise-specific-error`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/raise-specific-error))

<details><summary>Explanation</summary>如果一段代码抛出特定异常类型
而不是通用的
[`BaseException`](https://docs.python.org/3/library/exceptions.html#BaseException)[`Exception`](https://docs.python.org/3/library/exceptions.html#Exception),
则调用代码可以:

- 获取有关错误类型的更多信息
- 为其定义特定的异常处理

这样,代码的调用者可以适当地处理错误。

如何解决这个问题?

- 使用标准库中的 [内置异常](https://docs.python.org/3/library/exceptions.html)- [定义自己的错误类](https://docs.python.org/3/tutorial/errors.html#tut-userexceptions),该类继承自 `Exception`。

因此,与其让代码抛出 `Exception``BaseException`,例如

```python
if incorrect_input(value):
    raise Exception("The input is incorrect")
```

你可以让代码抛出特定错误,例如

```python
if incorrect_input(value):
    raise ValueError("The input is incorrect")
```

或者

```python
class IncorrectInputError(Exception):
    pass


if incorrect_input(value):
    raise IncorrectInputError("The input is incorrect")
```
</details>
</issue_to_address>

### 评论 4
<location> `astrbot/core/star/star_manager.py:691` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** 抛出特定错误而非通用的 `Exception``BaseException` ([`raise-specific-error`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/raise-specific-error))

<details><summary>Explanation</summary>如果一段代码抛出特定异常类型
而不是通用的
[`BaseException`](https://docs.python.org/3/library/exceptions.html#BaseException)[`Exception`](https://docs.python.org/3/library/exceptions.html#Exception),
则调用代码可以:

- 获取有关错误类型的更多信息
- 为其定义特定的异常处理

这样,代码的调用者可以适当地处理错误。

如何解决这个问题?

- 使用标准库中的 [内置异常](https://docs.python.org/3/library/exceptions.html)- [定义自己的错误类](https://docs.python.org/3/tutorial/errors.html#tut-userexceptions),该类继承自 `Exception`。

因此,与其让代码抛出 `Exception``BaseException`,例如

```python
if incorrect_input(value):
    raise Exception("The input is incorrect")
```

你可以让代码抛出特定错误,例如

```python
if incorrect_input(value):
    raise ValueError("The input is incorrect")
```

或者

```python
class IncorrectInputError(Exception):
    pass


if incorrect_input(value):
    raise IncorrectInputError("The input is incorrect")
```
</details>
</issue_to_address>

### 评论 5
<location> `astrbot/core/star/star_manager.py:808` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** 抛出特定错误而非通用的 `Exception``BaseException` ([`raise-specific-error`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/raise-specific-error))

<details><summary>Explanation</summary>如果一段代码抛出特定异常类型
而不是通用的
[`BaseException`](https://docs.python.org/3/library/exceptions.html#BaseException)[`Exception`](https://docs.python.org/3/library/exceptions.html#Exception),
则调用代码可以:

- 获取有关错误类型的更多信息
- 为其定义特定的异常处理

这样,代码的调用者可以适当地处理错误。

如何解决这个问题?

- 使用标准库中的 [内置异常](https://docs.python.org/3/library/exceptions.html)- [定义自己的错误类](https://docs.python.org/3/tutorial/errors.html#tut-userexceptions),该类继承自 `Exception`。

因此,与其让代码抛出 `Exception``BaseException`,例如

```python
if incorrect_input(value):
    raise Exception("The input is incorrect")
```

你可以让代码抛出特定错误,例如

```python
if incorrect_input(value):
    raise ValueError("The input is incorrect")
```

或者

```python
class IncorrectInputError(Exception):
    pass


if incorrect_input(value):
    raise IncorrectInputError("The input is incorrect")
```
</details>
</issue_to_address>

### 评论 6
<location> `astrbot/core/star/updator.py:36` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** 抛出特定错误而非通用的 `Exception``BaseException` ([`raise-specific-error`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/raise-specific-error))

<details><summary>Explanation</summary>如果一段代码抛出特定异常类型
而不是通用的
[`BaseException`](https://docs.python.org/3/library/exceptions.html#BaseException)[`Exception`](https://docs.python.org/3/library/exceptions.html#Exception),
则调用代码可以:

- 获取有关错误类型的更多信息
- 为其定义特定的异常处理

这样,代码的调用者可以适当地处理错误。

如何解决这个问题?

- 使用标准库中的 [内置异常](https://docs.python.org/3/library/exceptions.html)- [定义自己的错误类](https://docs.python.org/3/tutorial/errors.html#tut-userexceptions),该类继承自 `Exception`。

因此,与其让代码抛出 `Exception``BaseException`,例如

```python
if incorrect_input(value):
    raise Exception("The input is incorrect")
```

你可以让代码抛出特定错误,例如

```python
if incorrect_input(value):
    raise ValueError("The input is incorrect")
```

或者

```python
class IncorrectInputError(Exception):
    pass


if incorrect_input(value):
    raise IncorrectInputError("The input is incorrect")
```
</details>
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
帮助我更有用!请点击每个评论上的 👍 或 👎,我将使用反馈来改进你的评论。
Original comment in English

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

  • In register_command and register_command_group, missing required parameters currently only log warnings but still return a decorator that does nothing; consider raising errors or explicitly returning a no-op decorator to fail fast and avoid silent misconfigurations.
  • You’re using generic Exception/ValueError for plugin and MCP client errors—introducing more specific custom exception types would make error handling clearer and easier to catch.
  • The broad Callable[..., Awaitable[Any]] annotations cover all async signatures; consider defining a Protocol or TypeVar to narrow the expected handler signature and improve type safety.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In register_command and register_command_group, missing required parameters currently only log warnings but still return a decorator that does nothing; consider raising errors or explicitly returning a no-op decorator to fail fast and avoid silent misconfigurations.
- You’re using generic Exception/ValueError for plugin and MCP client errors—introducing more specific custom exception types would make error handling clearer and easier to catch.
- The broad Callable[..., Awaitable[Any]] annotations cover all async signatures; consider defining a Protocol or TypeVar to narrow the expected handler signature and improve type safety.

## Individual Comments

### Comment 1
<location> `astrbot/core/star/session_plugin_manager.py:143-141` </location>
<code_context>
                 filtered_handlers.append(handler)
                 continue

+            if plugin.name is None:
+                continue
+
             # 检查插件是否在当前会话中启用
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Skipping plugins with None name may hide registry issues.

Log a warning or error when skipping plugins with no name to aid in diagnosing potential registry problems.

Suggested implementation:

```python
                filtered_handlers.append(handler)
                continue

            if plugin.name is None:
                import logging
                logging.warning(f"Skipping plugin with no name: {plugin!r}")
                continue

            # 检查插件是否在当前会话中启用

```

If logging is already imported elsewhere in the file, you can remove the `import logging` line from this block.
You may also want to configure the logging level and format elsewhere in your application if not already done.
</issue_to_address>

### Comment 2
<location> `astrbot/core/provider/manager.py:91` </location>
<code_context>
-        self.curr_provider_inst = self.inst_map[provider_id]
-        if provider_type == ProviderType.TEXT_TO_SPEECH:
+
+        prov = self.inst_map[provider_id]
+        if provider_type == ProviderType.TEXT_TO_SPEECH and isinstance(
+            prov, TTSProvider
</code_context>

<issue_to_address>
**issue (complexity):** Consider refactoring repetitive per-type branches into concise lookup tables and loops for provider management.

You can collapse all of those per-type branches into a small lookup table + single loop in both `get_using_provider` and `terminate_provider`. For example:

```python
# at class‐level
_PROVIDER_CONFIG = {
    ProviderType.TEXT_TO_SPEECH:  ("curr_tts_provider_inst",  TTSProvider, "curr_provider_tts"),
    ProviderType.SPEECH_TO_TEXT:  ("curr_stt_provider_inst",  STTProvider, "curr_provider_stt"),
    ProviderType.CHAT_COMPLETION: ("curr_provider_inst",      Provider,    "curr_provider"),
}
```

Then in `get_using_provider`:

```python
prov = self.inst_map[provider_id]
attr, cls, sp_key = self._PROVIDER_CONFIG[provider_type]
if isinstance(prov, cls):
    setattr(self, attr, prov)
    sp.put(sp_key, provider_id, scope="global", scope_id="global")
```

And in `terminate_provider` you can drop all of the `isinstance` checks/remove calls by iterating your lists and  `curr_*` attrs:

```python
inst = self.inst_map[provider_id]

# remove from any list it lives in
for lst in (
    self.provider_insts,
    self.stt_provider_insts,
    self.tts_provider_insts,
    self.embedding_provider_insts,
):
    if inst in lst:
        lst.remove(inst)

# clear any curr_* pointer
for attr, _, _ in self._PROVIDER_CONFIG.values():
    if getattr(self, attr) is inst:
        setattr(self, attr, None)

if getattr(inst, "terminate", None):
    await inst.terminate()
```

This preserves exactly the same behavior but collapses all of your repetitive `if isinstance(...)` / `remove(...)` / `setattr(...)` / `sp.put(...)` code into two very concise loops.
</issue_to_address>

### Comment 3
<location> `astrbot/core/agent/mcp_client.py:202` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Raise a specific error instead of the general `Exception` or `BaseException` ([`raise-specific-error`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/raise-specific-error))

<details><summary>Explanation</summary>If a piece of code raises a specific exception type
rather than the generic
[`BaseException`](https://docs.python.org/3/library/exceptions.html#BaseException)
or [`Exception`](https://docs.python.org/3/library/exceptions.html#Exception),
the calling code can:

- get more information about what type of error it is
- define specific exception handling for it

This way, callers of the code can handle the error appropriately.

How can you solve this?

- Use one of the [built-in exceptions](https://docs.python.org/3/library/exceptions.html) of the standard library.
- [Define your own error class](https://docs.python.org/3/tutorial/errors.html#tut-userexceptions) that subclasses `Exception`.

So instead of having code raising `Exception` or `BaseException` like

```python
if incorrect_input(value):
    raise Exception("The input is incorrect")
```

you can have code raising a specific error like

```python
if incorrect_input(value):
    raise ValueError("The input is incorrect")
```

or

```python
class IncorrectInputError(Exception):
    pass


if incorrect_input(value):
    raise IncorrectInputError("The input is incorrect")
```
</details>
</issue_to_address>

### Comment 4
<location> `astrbot/core/star/star_manager.py:691` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Raise a specific error instead of the general `Exception` or `BaseException` ([`raise-specific-error`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/raise-specific-error))

<details><summary>Explanation</summary>If a piece of code raises a specific exception type
rather than the generic
[`BaseException`](https://docs.python.org/3/library/exceptions.html#BaseException)
or [`Exception`](https://docs.python.org/3/library/exceptions.html#Exception),
the calling code can:

- get more information about what type of error it is
- define specific exception handling for it

This way, callers of the code can handle the error appropriately.

How can you solve this?

- Use one of the [built-in exceptions](https://docs.python.org/3/library/exceptions.html) of the standard library.
- [Define your own error class](https://docs.python.org/3/tutorial/errors.html#tut-userexceptions) that subclasses `Exception`.

So instead of having code raising `Exception` or `BaseException` like

```python
if incorrect_input(value):
    raise Exception("The input is incorrect")
```

you can have code raising a specific error like

```python
if incorrect_input(value):
    raise ValueError("The input is incorrect")
```

or

```python
class IncorrectInputError(Exception):
    pass


if incorrect_input(value):
    raise IncorrectInputError("The input is incorrect")
```
</details>
</issue_to_address>

### Comment 5
<location> `astrbot/core/star/star_manager.py:808` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Raise a specific error instead of the general `Exception` or `BaseException` ([`raise-specific-error`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/raise-specific-error))

<details><summary>Explanation</summary>If a piece of code raises a specific exception type
rather than the generic
[`BaseException`](https://docs.python.org/3/library/exceptions.html#BaseException)
or [`Exception`](https://docs.python.org/3/library/exceptions.html#Exception),
the calling code can:

- get more information about what type of error it is
- define specific exception handling for it

This way, callers of the code can handle the error appropriately.

How can you solve this?

- Use one of the [built-in exceptions](https://docs.python.org/3/library/exceptions.html) of the standard library.
- [Define your own error class](https://docs.python.org/3/tutorial/errors.html#tut-userexceptions) that subclasses `Exception`.

So instead of having code raising `Exception` or `BaseException` like

```python
if incorrect_input(value):
    raise Exception("The input is incorrect")
```

you can have code raising a specific error like

```python
if incorrect_input(value):
    raise ValueError("The input is incorrect")
```

or

```python
class IncorrectInputError(Exception):
    pass


if incorrect_input(value):
    raise IncorrectInputError("The input is incorrect")
```
</details>
</issue_to_address>

### Comment 6
<location> `astrbot/core/star/updator.py:36` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Raise a specific error instead of the general `Exception` or `BaseException` ([`raise-specific-error`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/Python/Default-Rules/raise-specific-error))

<details><summary>Explanation</summary>If a piece of code raises a specific exception type
rather than the generic
[`BaseException`](https://docs.python.org/3/library/exceptions.html#BaseException)
or [`Exception`](https://docs.python.org/3/library/exceptions.html#Exception),
the calling code can:

- get more information about what type of error it is
- define specific exception handling for it

This way, callers of the code can handle the error appropriately.

How can you solve this?

- Use one of the [built-in exceptions](https://docs.python.org/3/library/exceptions.html) of the standard library.
- [Define your own error class](https://docs.python.org/3/tutorial/errors.html#tut-userexceptions) that subclasses `Exception`.

So instead of having code raising `Exception` or `BaseException` like

```python
if incorrect_input(value):
    raise Exception("The input is incorrect")
```

you can have code raising a specific error like

```python
if incorrect_input(value):
    raise ValueError("The input is incorrect")
```

or

```python
class IncorrectInputError(Exception):
    pass


if incorrect_input(value):
    raise IncorrectInputError("The input is incorrect")
```
</details>
</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.

@Soulter Soulter merged commit 80a86f5 into master Sep 21, 2025
5 checks passed
@Soulter Soulter deleted the refactor/type-checking branch October 18, 2025 01:54
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.

2 participants