-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
fix: stabilize packaged runtime pip/ssl behavior and mac font fallback #5007
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey - 我发现了 3 个问题,并给出了一些整体反馈:
- 新的
_patch_distlib_finder_for_frozen_runtime辅助函数依赖私有属性distlib_resources._finder_registry;建议增加防御性检查(例如使用hasattr/getattr保护或在访问时加上 try/except),以免未来 pip/distlib 的变更破坏冻结运行时的启动路径。 aiohttp.ClientSession的 SSL 配置在get_official_endpoints和update_llm_metadata中重复出现;可以提取一个共享的辅助函数来构造带 certifi 支持的TCPConnector,从而减少重复,并在未来需要调整证书配置时保持一致性。
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new `_patch_distlib_finder_for_frozen_runtime` helper relies on the private `distlib_resources._finder_registry` attribute; consider adding defensive checks (e.g., `hasattr`/`getattr` guards or a try/except around access) so future pip/distlib changes don’t break the frozen runtime boot path.
- The SSL setup for `aiohttp.ClientSession` is duplicated in both `get_official_endpoints` and `update_llm_metadata`; extracting a shared helper to construct the `TCPConnector` with the certifi-backed context would reduce repetition and keep the cert config consistent if it needs to evolve.
## Individual Comments
### Comment 1
<location> `astrbot/core/utils/pip_installer.py:50-59` </location>
<code_context>
handler.close()
+def _patch_distlib_finder_for_frozen_runtime() -> None:
+ if not getattr(sys, "frozen", False):
+ return
+
+ try:
+ from pip._vendor.distlib import resources as distlib_resources
+ except Exception:
+ return
+
+ for package_name in ("pip._vendor.distlib", "pip._vendor"):
+ try:
+ package = importlib.import_module(package_name)
+ except Exception:
+ continue
+
+ loader = getattr(package, "__loader__", None)
+ if loader is None:
+ loader = getattr(getattr(package, "__spec__", None), "loader", None)
+ if loader is None:
+ continue
+
+ loader_type = type(loader)
+ if loader_type in distlib_resources._finder_registry:
+ continue
+
+ distlib_resources.register_finder(loader, distlib_resources.ResourceFinder)
+ logger.info(
+ "Patched pip distlib finder for frozen loader: %s (%s)",
</code_context>
<issue_to_address>
**issue (bug_risk):** Distlib finder is registered with the loader instance but checked against the loader type, which likely breaks the guard and registry semantics.
In `_patch_distlib_finder_for_frozen_runtime`, the guard checks `if loader_type in distlib_resources._finder_registry:` but `register_finder` is then called with the loader instance. Distlib’s registry is keyed by loader classes, so this mismatch means the guard won’t prevent duplicate registrations and lookups expecting class keys may fail.
Please either:
- register using `loader_type`: `distlib_resources.register_finder(loader_type, distlib_resources.ResourceFinder)`, or
- change the membership check to match whatever key `register_finder` actually uses.
This keeps the registry consistent and avoids subtle runtime resolution issues.
</issue_to_address>
### Comment 2
<location> `astrbot/core/utils/t2i/network_strategy.py:42-44` </location>
<code_context>
url = "https://models.dev/api.json"
try:
- async with aiohttp.ClientSession() as session:
+ ssl_context = ssl.create_default_context(cafile=certifi.where())
+ connector = aiohttp.TCPConnector(ssl=ssl_context)
+ async with aiohttp.ClientSession(
+ trust_env=True, connector=connector
+ ) as session:
</code_context>
<issue_to_address>
**🚨 suggestion (security):** Overriding the SSL CA bundle with certifi may break environments that rely on system or custom CAs.
Passing `cafile=certifi.where()` replaces the system trust store with certifi’s bundle, which can break TLS in environments that rely on custom or proxy-injected CAs. Given `trust_env=True`, it’s more compatible to either:
- use `ssl.create_default_context()` and rely on the OS trust store, or
- create the default context and call `context.load_verify_locations(cafile=certifi.where())` to augment, not replace, system CAs.
Suggested implementation:
```python
try:
ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(cafile=certifi.where())
connector = aiohttp.TCPConnector(ssl=ssl_context)
async with aiohttp.ClientSession(
trust_env=True,
connector=connector,
) as session:
```
Ensure that this file imports both `ssl` and `certifi` at the top if they are not already imported:
- `import ssl`
- `import certifi`
</issue_to_address>
### Comment 3
<location> `astrbot/core/utils/llm_metadata.py:37-39` </location>
<code_context>
url = "https://models.dev/api.json"
try:
- async with aiohttp.ClientSession() as session:
+ ssl_context = ssl.create_default_context(cafile=certifi.where())
+ connector = aiohttp.TCPConnector(ssl=ssl_context)
+ async with aiohttp.ClientSession(
+ trust_env=True, connector=connector
+ ) as session:
</code_context>
<issue_to_address>
**🚨 suggestion (security):** Same TLS CA override concern as in t2i network strategy; consider not replacing the system trust store outright.
Using `ssl.create_default_context(cafile=certifi.where())` here fully replaces the system CA store with certifi’s, which can break environments that rely on additional/custom CAs (corporate proxies, internal PKI, etc.). Please align this with the final approach in `network_strategy.py` (e.g., start from the default context and, if needed, add certifi’s CAs instead of overriding the store).
Suggested implementation:
```python
import aiohttp
import certifi
import ssl
from astrbot.core import logger
```
```python
url = "https://models.dev/api.json"
try:
ssl_context = ssl.create_default_context()
try:
# Extend the system trust store with certifi's CA bundle instead of replacing it
ssl_context.load_verify_locations(cafile=certifi.where())
except Exception as exc:
logger.warning(
"Failed to load certifi CA bundle into SSL context; "
"falling back to system trust store only: %s",
exc,
)
connector = aiohttp.TCPConnector(ssl=ssl_context)
```
If `astrbot/core/network_strategy.py` exposes a shared helper for building SSL contexts (e.g., `build_ssl_context()` or similar), consider refactoring this function to call that helper instead of duplicating the logic here, so both places stay aligned if the TLS behavior changes in the future.
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈不断改进代码评审质量。
Original comment in English
Hey - I've found 3 issues, and left some high level feedback:
- The new
_patch_distlib_finder_for_frozen_runtimehelper relies on the privatedistlib_resources._finder_registryattribute; consider adding defensive checks (e.g.,hasattr/getattrguards or a try/except around access) so future pip/distlib changes don’t break the frozen runtime boot path. - The SSL setup for
aiohttp.ClientSessionis duplicated in bothget_official_endpointsandupdate_llm_metadata; extracting a shared helper to construct theTCPConnectorwith the certifi-backed context would reduce repetition and keep the cert config consistent if it needs to evolve.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new `_patch_distlib_finder_for_frozen_runtime` helper relies on the private `distlib_resources._finder_registry` attribute; consider adding defensive checks (e.g., `hasattr`/`getattr` guards or a try/except around access) so future pip/distlib changes don’t break the frozen runtime boot path.
- The SSL setup for `aiohttp.ClientSession` is duplicated in both `get_official_endpoints` and `update_llm_metadata`; extracting a shared helper to construct the `TCPConnector` with the certifi-backed context would reduce repetition and keep the cert config consistent if it needs to evolve.
## Individual Comments
### Comment 1
<location> `astrbot/core/utils/pip_installer.py:50-59` </location>
<code_context>
handler.close()
+def _patch_distlib_finder_for_frozen_runtime() -> None:
+ if not getattr(sys, "frozen", False):
+ return
+
+ try:
+ from pip._vendor.distlib import resources as distlib_resources
+ except Exception:
+ return
+
+ for package_name in ("pip._vendor.distlib", "pip._vendor"):
+ try:
+ package = importlib.import_module(package_name)
+ except Exception:
+ continue
+
+ loader = getattr(package, "__loader__", None)
+ if loader is None:
+ loader = getattr(getattr(package, "__spec__", None), "loader", None)
+ if loader is None:
+ continue
+
+ loader_type = type(loader)
+ if loader_type in distlib_resources._finder_registry:
+ continue
+
+ distlib_resources.register_finder(loader, distlib_resources.ResourceFinder)
+ logger.info(
+ "Patched pip distlib finder for frozen loader: %s (%s)",
</code_context>
<issue_to_address>
**issue (bug_risk):** Distlib finder is registered with the loader instance but checked against the loader type, which likely breaks the guard and registry semantics.
In `_patch_distlib_finder_for_frozen_runtime`, the guard checks `if loader_type in distlib_resources._finder_registry:` but `register_finder` is then called with the loader instance. Distlib’s registry is keyed by loader classes, so this mismatch means the guard won’t prevent duplicate registrations and lookups expecting class keys may fail.
Please either:
- register using `loader_type`: `distlib_resources.register_finder(loader_type, distlib_resources.ResourceFinder)`, or
- change the membership check to match whatever key `register_finder` actually uses.
This keeps the registry consistent and avoids subtle runtime resolution issues.
</issue_to_address>
### Comment 2
<location> `astrbot/core/utils/t2i/network_strategy.py:42-44` </location>
<code_context>
url = "https://models.dev/api.json"
try:
- async with aiohttp.ClientSession() as session:
+ ssl_context = ssl.create_default_context(cafile=certifi.where())
+ connector = aiohttp.TCPConnector(ssl=ssl_context)
+ async with aiohttp.ClientSession(
+ trust_env=True, connector=connector
+ ) as session:
</code_context>
<issue_to_address>
**🚨 suggestion (security):** Overriding the SSL CA bundle with certifi may break environments that rely on system or custom CAs.
Passing `cafile=certifi.where()` replaces the system trust store with certifi’s bundle, which can break TLS in environments that rely on custom or proxy-injected CAs. Given `trust_env=True`, it’s more compatible to either:
- use `ssl.create_default_context()` and rely on the OS trust store, or
- create the default context and call `context.load_verify_locations(cafile=certifi.where())` to augment, not replace, system CAs.
Suggested implementation:
```python
try:
ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(cafile=certifi.where())
connector = aiohttp.TCPConnector(ssl=ssl_context)
async with aiohttp.ClientSession(
trust_env=True,
connector=connector,
) as session:
```
Ensure that this file imports both `ssl` and `certifi` at the top if they are not already imported:
- `import ssl`
- `import certifi`
</issue_to_address>
### Comment 3
<location> `astrbot/core/utils/llm_metadata.py:37-39` </location>
<code_context>
url = "https://models.dev/api.json"
try:
- async with aiohttp.ClientSession() as session:
+ ssl_context = ssl.create_default_context(cafile=certifi.where())
+ connector = aiohttp.TCPConnector(ssl=ssl_context)
+ async with aiohttp.ClientSession(
+ trust_env=True, connector=connector
+ ) as session:
</code_context>
<issue_to_address>
**🚨 suggestion (security):** Same TLS CA override concern as in t2i network strategy; consider not replacing the system trust store outright.
Using `ssl.create_default_context(cafile=certifi.where())` here fully replaces the system CA store with certifi’s, which can break environments that rely on additional/custom CAs (corporate proxies, internal PKI, etc.). Please align this with the final approach in `network_strategy.py` (e.g., start from the default context and, if needed, add certifi’s CAs instead of overriding the store).
Suggested implementation:
```python
import aiohttp
import certifi
import ssl
from astrbot.core import logger
```
```python
url = "https://models.dev/api.json"
try:
ssl_context = ssl.create_default_context()
try:
# Extend the system trust store with certifi's CA bundle instead of replacing it
ssl_context.load_verify_locations(cafile=certifi.where())
except Exception as exc:
logger.warning(
"Failed to load certifi CA bundle into SSL context; "
"falling back to system trust store only: %s",
exc,
)
connector = aiohttp.TCPConnector(ssl=ssl_context)
```
If `astrbot/core/network_strategy.py` exposes a shared helper for building SSL contexts (e.g., `build_ssl_context()` or similar), consider refactoring this function to call that helper instead of duplicating the logic here, so both places stay aligned if the TLS behavior changes in the future.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
|
@sourcery-ai review |
SourceryAI
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey - 我发现了 1 个问题,并且留下了一些高层次的反馈:
- 在
_patch_distlib_finder_for_frozen_runtime中,register_finder使用的是loader而不是loader_type;distlib.resources.register_finder期望的是一个 loader 类型,因此你可能需要在这里传入loader_type,以避免产生一些难以察觉的错误注册。 - 目前中文字体回退栈分别出现在
_variables.scss、_container.scss和ConsoleDisplayer.vue中的内联样式里,存在重复;可以考虑把这些字体栈抽取成一个共享的 SCSS 变量/混入(并使用 CSS class 来设置 font-family 而不是内联样式),以便保持一致性并降低维护成本。
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `_patch_distlib_finder_for_frozen_runtime`, `register_finder` is called with `loader` instead of `loader_type`; `distlib.resources.register_finder` expects a loader type, so you probably want to pass `loader_type` there to avoid subtle misregistration.
- The Chinese font fallback stacks are now duplicated across `_variables.scss`, `_container.scss`, and the inline style in `ConsoleDisplayer.vue`; consider extracting these stacks into a shared SCSS variable/mixin (and using CSS classes instead of inline font-family) to keep them consistent and easier to maintain.
## Individual Comments
### Comment 1
<location> `astrbot/core/utils/pip_installer.py:86-91` </location>
<code_context>
+ if loader is None:
+ continue
+
+ loader_type = type(loader)
+ if loader_type in finder_registry:
+ continue
+
+ try:
+ register_finder(loader, resource_finder)
+ except Exception as exc:
+ logger.warning(
</code_context>
<issue_to_address>
**issue (bug_risk):** Use the loader *type* when registering the distlib finder instead of the loader instance.
`finder_registry` is keyed by `loader_type`, but `register_finder` is called with the `loader` instance. If `register_finder` uses its first argument as the key, the finder will be registered under the instance, so the subsequent `loader_type in finder_registry` check will fail and the warning will incorrectly say the patch did not take effect. Please align these by calling `register_finder(loader_type, resource_finder)` or confirming and matching whatever key `register_finder` expects.
</issue_to_address>Hi @zouyonghe! 👋
感谢你通过评论 @sourcery-ai review 来体验 Sourcery!🚀
安装 sourcery-ai bot 即可在每个 Pull Request 上自动获得代码审核 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈持续改进审查质量。Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- In
_patch_distlib_finder_for_frozen_runtime,register_finderis called withloaderinstead ofloader_type;distlib.resources.register_finderexpects a loader type, so you probably want to passloader_typethere to avoid subtle misregistration. - The Chinese font fallback stacks are now duplicated across
_variables.scss,_container.scss, and the inline style inConsoleDisplayer.vue; consider extracting these stacks into a shared SCSS variable/mixin (and using CSS classes instead of inline font-family) to keep them consistent and easier to maintain.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `_patch_distlib_finder_for_frozen_runtime`, `register_finder` is called with `loader` instead of `loader_type`; `distlib.resources.register_finder` expects a loader type, so you probably want to pass `loader_type` there to avoid subtle misregistration.
- The Chinese font fallback stacks are now duplicated across `_variables.scss`, `_container.scss`, and the inline style in `ConsoleDisplayer.vue`; consider extracting these stacks into a shared SCSS variable/mixin (and using CSS classes instead of inline font-family) to keep them consistent and easier to maintain.
## Individual Comments
### Comment 1
<location> `astrbot/core/utils/pip_installer.py:86-91` </location>
<code_context>
+ if loader is None:
+ continue
+
+ loader_type = type(loader)
+ if loader_type in finder_registry:
+ continue
+
+ try:
+ register_finder(loader, resource_finder)
+ except Exception as exc:
+ logger.warning(
</code_context>
<issue_to_address>
**issue (bug_risk):** Use the loader *type* when registering the distlib finder instead of the loader instance.
`finder_registry` is keyed by `loader_type`, but `register_finder` is called with the `loader` instance. If `register_finder` uses its first argument as the key, the finder will be registered under the instance, so the subsequent `loader_type in finder_registry` check will fail and the warning will incorrectly say the patch did not take effect. Please align these by calling `register_finder(loader_type, resource_finder)` or confirming and matching whatever key `register_finder` expects.
</issue_to_address>Hi @zouyonghe! 👋
Thanks for trying out Sourcery by commenting with @sourcery-ai review! 🚀
Install the sourcery-ai bot to get automatic code reviews on every pull request ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey - 我发现了两个问题,并给出了一些更高层次的反馈:
- 在
_patch_distlib_finder_for_frozen_runtime中,register_finder使用的是 loader 实例而不是loader_type;distlib 的 API 通常期望传入的是 loader 类,因此建议传入loader_type,以避免微妙的不匹配,并与注册表键的类型保持一致。 _patch_distlib_finder_for_frozen_runtime会在每次调用_run_pip_in_process时执行;可以考虑加一个简单的一次性保护(例如模块级别的标志位),以避免在长时间运行的打包运行时中重复工作和产生重复日志。- 为中文更新的字体回退在多个位置进行了硬编码(全局 body、
.Poppins、.Inter、.Outfit、控制台);建议将这些字体栈集中到一个共享的 SCSS 变量或 mixin 中,以便在整个 dashboard 中保持字体配置的一致性并更易于维护。
给 AI Agent 的提示词
Please address the comments from this code review:
## Overall Comments
- In `_patch_distlib_finder_for_frozen_runtime`, `register_finder` is called with the loader instance instead of `loader_type`; distlib’s API typically expects the loader class, so consider passing `loader_type` to avoid subtle mismatches and to align with the registry’s key type.
- `_patch_distlib_finder_for_frozen_runtime` is invoked on every `_run_pip_in_process` call; consider adding a simple one-time guard (e.g., a module-level flag) to avoid repeated work and duplicate logs in long-running packaged runtimes.
- The updated font fallbacks for Chinese are hardcoded in multiple places (global body, `.Poppins`, `.Inter`, `.Outfit`, console); consider centralizing these font stacks in a shared SCSS variable or mixin to keep the font configuration consistent and easier to maintain across the dashboard.
## Individual Comments
### Comment 1
<location> `astrbot/core/utils/pip_installer.py:86-91` </location>
<code_context>
+ if loader is None:
+ continue
+
+ loader_type = type(loader)
+ if loader_type in finder_registry:
+ continue
+
+ try:
+ register_finder(loader, resource_finder)
+ except Exception as exc:
+ logger.warning(
</code_context>
<issue_to_address>
**issue (bug_risk):** 在注册 distlib finder 时,请始终一致地使用 loader 的 *类型*。
你在查询 `_finder_registry` 时使用的是 `loader_type`,但在调用 `register_finder` 时传入的是 `loader` *实例*。在 distlib 中,`register_finder` 期望的是 loader 类,并使用该类作为注册表键。如果使用实例,可能会导致 `loader_type in finder_registry` 的检查结果不准确,或者产生重复条目。请调用 `register_finder(loader_type, resource_finder)`,这样注册时使用的键就能和你进行成员检查时保持一致。
</issue_to_address>
### Comment 2
<location> `dashboard/src/components/shared/ConsoleDisplayer.vue:272` </location>
<code_context>
}
- span.style = style + 'display: block; font-size: 12px; font-family: Consolas, monospace; white-space: pre-wrap; margin-bottom: 2px;'
+ span.style = style + 'display: block; font-size: 12px; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "PingFang SC", "PingFang TC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", monospace; white-space: pre-wrap; margin-bottom: 2px;'
span.classList.add('fade-in')
span.innerText = `${log}`;
</code_context>
<issue_to_address>
**suggestion:** 在等宽字体栈中混入比例 CJK 字体,可能会导致控制台对齐问题。
新增的这些 CJK UI 字体是比例字体,如果浏览器在等宽 CJK 字体之前选择它们,固定宽度的日志格式(缩进、ASCII 表格等)就可能被破坏。如果对齐很重要,可以考虑将该字体栈限制为等宽/准等宽字体,或者把这些比例 CJK 字体放到 `monospace` 之后,以免它们覆盖等宽字体的选择。
```suggestion
span.style = style + 'display: block; font-size: 12px; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace, "PingFang SC", "PingFang TC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei"; white-space: pre-wrap; margin-bottom: 2px;'
```
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的代码审查。
Original comment in English
Hey - I've found 2 issues, and left some high level feedback:
- In
_patch_distlib_finder_for_frozen_runtime,register_finderis called with the loader instance instead ofloader_type; distlib’s API typically expects the loader class, so consider passingloader_typeto avoid subtle mismatches and to align with the registry’s key type. _patch_distlib_finder_for_frozen_runtimeis invoked on every_run_pip_in_processcall; consider adding a simple one-time guard (e.g., a module-level flag) to avoid repeated work and duplicate logs in long-running packaged runtimes.- The updated font fallbacks for Chinese are hardcoded in multiple places (global body,
.Poppins,.Inter,.Outfit, console); consider centralizing these font stacks in a shared SCSS variable or mixin to keep the font configuration consistent and easier to maintain across the dashboard.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `_patch_distlib_finder_for_frozen_runtime`, `register_finder` is called with the loader instance instead of `loader_type`; distlib’s API typically expects the loader class, so consider passing `loader_type` to avoid subtle mismatches and to align with the registry’s key type.
- `_patch_distlib_finder_for_frozen_runtime` is invoked on every `_run_pip_in_process` call; consider adding a simple one-time guard (e.g., a module-level flag) to avoid repeated work and duplicate logs in long-running packaged runtimes.
- The updated font fallbacks for Chinese are hardcoded in multiple places (global body, `.Poppins`, `.Inter`, `.Outfit`, console); consider centralizing these font stacks in a shared SCSS variable or mixin to keep the font configuration consistent and easier to maintain across the dashboard.
## Individual Comments
### Comment 1
<location> `astrbot/core/utils/pip_installer.py:86-91` </location>
<code_context>
+ if loader is None:
+ continue
+
+ loader_type = type(loader)
+ if loader_type in finder_registry:
+ continue
+
+ try:
+ register_finder(loader, resource_finder)
+ except Exception as exc:
+ logger.warning(
</code_context>
<issue_to_address>
**issue (bug_risk):** Use the loader *type* consistently when registering the distlib finder.
You use `loader_type` to query `_finder_registry`, but pass the `loader` *instance* to `register_finder`. In distlib, `register_finder` expects the loader class and uses that as the registry key. Using the instance can make your `loader_type in finder_registry` check inaccurate or create duplicate entries. Call `register_finder(loader_type, resource_finder)` so the key used for registration matches your membership checks.
</issue_to_address>
### Comment 2
<location> `dashboard/src/components/shared/ConsoleDisplayer.vue:272` </location>
<code_context>
}
- span.style = style + 'display: block; font-size: 12px; font-family: Consolas, monospace; white-space: pre-wrap; margin-bottom: 2px;'
+ span.style = style + 'display: block; font-size: 12px; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "PingFang SC", "PingFang TC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", monospace; white-space: pre-wrap; margin-bottom: 2px;'
span.classList.add('fade-in')
span.innerText = `${log}`;
</code_context>
<issue_to_address>
**suggestion:** Mixing proportional CJK fonts into a monospace stack may cause console alignment issues.
These added CJK UI fonts are proportional, so if the browser picks them before a monospace CJK font, fixed-width log formatting (indentation, ASCII tables, etc.) can break. If alignment matters, consider limiting this stack to monospace/quasi-monospace fonts, or move the proportional CJK fonts after `monospace` so they don’t override the monospace choice.
```suggestion
span.style = style + 'display: block; font-size: 12px; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace, "PingFang SC", "PingFang TC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei"; white-space: pre-wrap; margin-bottom: 2px;'
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
@sourcery-ai review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey - 我在这里给出一些高层次的反馈:
- TLS 帮助方法目前在每次调用
build_tls_connector()时都会创建一个新的 SSL 上下文和 TCPConnector;可以考虑在模块级别保留一个共享的 connector(或者至少是共享的 SSLContext),这样长生命周期的服务就可以复用连接,而不是为每个请求重新创建。 _patch_distlib_finder_for_frozen_runtime()会在每次进程内运行 pip 时被调用;你可以添加一个简单的模块级标志,确保补丁逻辑最多只执行一次,从而避免在长时间运行的打包运行时中重复扫描注册表并产生多余日志噪音。
给 AI 代理的提示
Please address the comments from this code review:
## Overall Comments
- TLS 帮助方法目前在每次调用 `build_tls_connector()` 时都会创建一个新的 SSL 上下文和 TCPConnector;可以考虑在模块级别保留一个共享的 connector(或者至少是共享的 SSLContext),这样长生命周期的服务就可以复用连接,而不是为每个请求重新创建。
- `_patch_distlib_finder_for_frozen_runtime()` 会在每次进程内运行 pip 时被调用;你可以添加一个简单的模块级标志,确保补丁逻辑最多只执行一次,从而避免在长时间运行的打包运行时中重复扫描注册表并产生多余日志噪音。帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据这些反馈改进你的评审体验。
Original comment in English
Hey - I've left some high level feedback:
- The TLS helper currently creates a new SSL context and TCPConnector on every
build_tls_connector()call; consider keeping a shared connector (or at least a shared SSLContext) at module level so long‑lived services can reuse connections instead of recreating them for each request. _patch_distlib_finder_for_frozen_runtime()is invoked on every in‑process pip run; you could add a simple module‑level flag to ensure the patching logic executes at most once and avoid repeated registry scans and log noise in long‑running packaged runtimes.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The TLS helper currently creates a new SSL context and TCPConnector on every `build_tls_connector()` call; consider keeping a shared connector (or at least a shared SSLContext) at module level so long‑lived services can reuse connections instead of recreating them for each request.
- `_patch_distlib_finder_for_frozen_runtime()` is invoked on every in‑process pip run; you could add a simple module‑level flag to ensure the patching logic executes at most once and avoid repeated registry scans and log noise in long‑running packaged runtimes.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
@sourcery-ai review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey - 我发现了 1 个问题,并留下了一些高层次的反馈:
- 几个新的运行时补丁(
_patch_distlib_finder_for_frozen_runtime、build_ssl_context_with_certifi、configure_runtime_ca_bundle和askForConfirmation)捕获了Exception,并且要么忽略错误,要么大幅弱化错误的重要性;建议收窄这些except块的范围,或者至少在失败时持续进行日志记录,这样 pip/SSL 设置或确认对话框的问题就不会悄无声息地失败,从而变得难以排查。 - 新增的
runtime_bootstrap.configure_runtime_ca_bundle依赖并修改了私有属性aiohttp.connector._SSL_CONTEXT_VERIFIED;最好将这类行为集中到一个地方并加上清晰的注释(同时可以通过检查aiohttp版本来加保护),以便在这个内部细节发生变化时,让未来升级aiohttp更加安全。
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Several of the new runtime patches (`_patch_distlib_finder_for_frozen_runtime`, `build_ssl_context_with_certifi`, `configure_runtime_ca_bundle`, and `askForConfirmation`) catch `Exception` and either ignore or heavily downplay errors; consider narrowing these except blocks or at least logging failures consistently so that issues with pip/SSL setup or the confirm dialog do not silently fail and become hard to diagnose.
- The new `runtime_bootstrap.configure_runtime_ca_bundle` relies on and mutates the private `aiohttp.connector._SSL_CONTEXT_VERIFIED` attribute; it would be good to centralize and clearly comment this behavior (and perhaps guard it by checking `aiohttp` version) to make future upgrades of `aiohttp` safer if this internal detail changes.
## Individual Comments
### Comment 1
<location> `runtime_bootstrap.py:12-15` </location>
<code_context>
+ ssl_context = ssl.create_default_context()
+ ssl_context.load_verify_locations(cafile=certifi.where())
+
+ if hasattr(aiohttp_connector, "_SSL_CONTEXT_VERIFIED"):
+ aiohttp_connector._SSL_CONTEXT_VERIFIED = ssl_context
+ except Exception:
+ return
+
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Overriding aiohttp's private `_SSL_CONTEXT_VERIFIED` and swallowing all exceptions could cause subtle SSL issues that are hard to debug.
Because this relies on a private attribute and uses `except Exception` with a silent `return`, we’ll miss any breakage if aiohttp changes its internals or type expectations.
Two suggestions:
- Log failures when configuring the runtime CA bundle so SSL issues in frozen builds are debuggable.
- Make the patch more defensive (e.g., check the existing value/type or gate it on known aiohttp versions) to reduce the risk of future aiohttp changes silently breaking this behavior.
</issue_to_address>Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- Several of the new runtime patches (
_patch_distlib_finder_for_frozen_runtime,build_ssl_context_with_certifi,configure_runtime_ca_bundle, andaskForConfirmation) catchExceptionand either ignore or heavily downplay errors; consider narrowing these except blocks or at least logging failures consistently so that issues with pip/SSL setup or the confirm dialog do not silently fail and become hard to diagnose. - The new
runtime_bootstrap.configure_runtime_ca_bundlerelies on and mutates the privateaiohttp.connector._SSL_CONTEXT_VERIFIEDattribute; it would be good to centralize and clearly comment this behavior (and perhaps guard it by checkingaiohttpversion) to make future upgrades ofaiohttpsafer if this internal detail changes.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Several of the new runtime patches (`_patch_distlib_finder_for_frozen_runtime`, `build_ssl_context_with_certifi`, `configure_runtime_ca_bundle`, and `askForConfirmation`) catch `Exception` and either ignore or heavily downplay errors; consider narrowing these except blocks or at least logging failures consistently so that issues with pip/SSL setup or the confirm dialog do not silently fail and become hard to diagnose.
- The new `runtime_bootstrap.configure_runtime_ca_bundle` relies on and mutates the private `aiohttp.connector._SSL_CONTEXT_VERIFIED` attribute; it would be good to centralize and clearly comment this behavior (and perhaps guard it by checking `aiohttp` version) to make future upgrades of `aiohttp` safer if this internal detail changes.
## Individual Comments
### Comment 1
<location> `runtime_bootstrap.py:12-15` </location>
<code_context>
+ ssl_context = ssl.create_default_context()
+ ssl_context.load_verify_locations(cafile=certifi.where())
+
+ if hasattr(aiohttp_connector, "_SSL_CONTEXT_VERIFIED"):
+ aiohttp_connector._SSL_CONTEXT_VERIFIED = ssl_context
+ except Exception:
+ return
+
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Overriding aiohttp's private `_SSL_CONTEXT_VERIFIED` and swallowing all exceptions could cause subtle SSL issues that are hard to debug.
Because this relies on a private attribute and uses `except Exception` with a silent `return`, we’ll miss any breakage if aiohttp changes its internals or type expectations.
Two suggestions:
- Log failures when configuring the runtime CA bundle so SSL issues in frozen builds are debuggable.
- Make the patch more defensive (e.g., check the existing value/type or gate it on known aiohttp versions) to reduce the risk of future aiohttp changes silently breaking this behavior.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
- Add shared confirm helper in dashboard/src/utils/confirmDialog.ts for async dialog usage with safe fallback. - Migrate provider, chat, config, session, platform, persona, MCP, backup, and knowledge-base delete/close confirmations to use the shared helper. - Remove scattered inline confirm handling to keep behavior consistent and avoid native blocking dialog focus/caret issues in Electron.
- Add bootstrap record buffer in runtime_bootstrap for early TLS patch logs before logger is ready. - Flush buffered bootstrap logs to astrbot logger at process startup in main.py. - Include concrete exception details for TLS bootstrap failures to improve diagnosis.
|
|
@sourcery-ai review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey - 我发现了 1 个问题,并留下了一些整体性的反馈:
- 新的
runtime_bootstrap.configure_runtime_ca_bundle依赖aiohttp.connector._SSL_CONTEXT_VERIFIED,这是一个私有/内部属性,在不同 aiohttp 版本之间可能会发生变化;建议增加版本/特性检查,或者提供一个优雅的回退路径,当预期的结构不存在时避免对内部实现进行补丁。 - 启动日志记录只会在
__main__入口点被 flush,因此如果这个包是通过其他入口导入并运行(例如嵌入式运行器或测试),这些早期的 SSL 启动日志可能永远不会被输出;建议提供一个公开的初始化钩子,让调用方在控制启动顺序时可以显式调用来 flush 启动日志记录。 - 确认对话框在各个组件中的集成方式略有不同(有时使用
inject + resolveConfirmDialog,有时直接传入this.$confirm);可以考虑增加一个小的 composable 或 helper,用来统一解析和使用$confirm的方式,从而让这一模式更加一致、易于维护。
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new runtime_bootstrap.configure_runtime_ca_bundle relies on aiohttp.connector._SSL_CONTEXT_VERIFIED, which is a private/internal attribute and may change between aiohttp versions; consider adding a version/feature check or a graceful fallback path that avoids patching internals when the expected structure isn’t present.
- Bootstrap log records are only flushed in the __main__ entrypoint, so if this package is imported and run via another entry (e.g., embedded runner or tests), those early SSL bootstrap logs may never be emitted; consider providing a public init hook that callers can invoke to flush bootstrap records when they control the startup sequence.
- The confirm dialog integration is implemented slightly differently across components (sometimes using inject + resolveConfirmDialog, other times passing this.$confirm directly); it might be worth adding a small composable or helper that standardizes how $confirm is resolved and used to keep this pattern consistent and easier to maintain.
## Individual Comments
### Comment 1
<location> `runtime_bootstrap.py:10` </location>
<code_context>
+import certifi
+
+
+@dataclass
+class BootstrapRecord:
+ level: str
</code_context>
<issue_to_address>
**issue (complexity):** Consider simplifying the logging bootstrap layer by storing plain (level, message) tuples and using getattr with a fallback instead of a custom dataclass and level-to-method mapping.
The logging bootstrap layer can be simplified without changing behavior.
You don’t need a custom `BootstrapRecord` dataclass or an explicit `level_methods` dict; a simple `(level, message)` tuple and `getattr` with a fallback keeps the same semantics with less code.
For example:
```python
_BOOTSTRAP_RECORDS: list[tuple[str, str]] = []
def _record(level: str, message: str) -> None:
_BOOTSTRAP_RECORDS.append((level, message))
def flush_bootstrap_records(log_obj: Any) -> None:
if not _BOOTSTRAP_RECORDS:
return
for level, message in _BOOTSTRAP_RECORDS:
logger_method = getattr(log_obj, level, None) or getattr(log_obj, "info", None)
if callable(logger_method):
logger_method(message)
_BOOTSTRAP_RECORDS.clear()
```
This preserves:
- buffering of log records before a logger is available,
- per-record level selection, and
- fallback to `.info` when the logger doesn’t expose the requested method,
while reducing indirection and custom types.
</issue_to_address>帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- The new runtime_bootstrap.configure_runtime_ca_bundle relies on aiohttp.connector._SSL_CONTEXT_VERIFIED, which is a private/internal attribute and may change between aiohttp versions; consider adding a version/feature check or a graceful fallback path that avoids patching internals when the expected structure isn’t present.
- Bootstrap log records are only flushed in the main entrypoint, so if this package is imported and run via another entry (e.g., embedded runner or tests), those early SSL bootstrap logs may never be emitted; consider providing a public init hook that callers can invoke to flush bootstrap records when they control the startup sequence.
- The confirm dialog integration is implemented slightly differently across components (sometimes using inject + resolveConfirmDialog, other times passing this.$confirm directly); it might be worth adding a small composable or helper that standardizes how $confirm is resolved and used to keep this pattern consistent and easier to maintain.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new runtime_bootstrap.configure_runtime_ca_bundle relies on aiohttp.connector._SSL_CONTEXT_VERIFIED, which is a private/internal attribute and may change between aiohttp versions; consider adding a version/feature check or a graceful fallback path that avoids patching internals when the expected structure isn’t present.
- Bootstrap log records are only flushed in the __main__ entrypoint, so if this package is imported and run via another entry (e.g., embedded runner or tests), those early SSL bootstrap logs may never be emitted; consider providing a public init hook that callers can invoke to flush bootstrap records when they control the startup sequence.
- The confirm dialog integration is implemented slightly differently across components (sometimes using inject + resolveConfirmDialog, other times passing this.$confirm directly); it might be worth adding a small composable or helper that standardizes how $confirm is resolved and used to keep this pattern consistent and easier to maintain.
## Individual Comments
### Comment 1
<location> `runtime_bootstrap.py:10` </location>
<code_context>
+import certifi
+
+
+@dataclass
+class BootstrapRecord:
+ level: str
</code_context>
<issue_to_address>
**issue (complexity):** Consider simplifying the logging bootstrap layer by storing plain (level, message) tuples and using getattr with a fallback instead of a custom dataclass and level-to-method mapping.
The logging bootstrap layer can be simplified without changing behavior.
You don’t need a custom `BootstrapRecord` dataclass or an explicit `level_methods` dict; a simple `(level, message)` tuple and `getattr` with a fallback keeps the same semantics with less code.
For example:
```python
_BOOTSTRAP_RECORDS: list[tuple[str, str]] = []
def _record(level: str, message: str) -> None:
_BOOTSTRAP_RECORDS.append((level, message))
def flush_bootstrap_records(log_obj: Any) -> None:
if not _BOOTSTRAP_RECORDS:
return
for level, message in _BOOTSTRAP_RECORDS:
logger_method = getattr(log_obj, level, None) or getattr(log_obj, "info", None)
if callable(logger_method):
logger_method(message)
_BOOTSTRAP_RECORDS.clear()
```
This preserves:
- buffering of log records before a logger is available,
- per-record level selection, and
- fallback to `.info` when the logger doesn’t expose the requested method,
while reducing indirection and custom types.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
- Simplify bootstrap log buffering and add a public initialize hook for non-main startup paths. - Guard aiohttp TLS patching with feature/type checks and keep graceful fallback when internals are unavailable. - Standardize dashboard confirmation flow via shared confirm helpers across composition and options API components.
|
@sourcery-ai review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey - 我发现了 1 个问题,并且留了一些整体性的反馈:
- 现在有两处不同的代码路径在构造 SSL 上下文(分别在
runtime_bootstrap.py和astrbot/core/utils/http_ssl.py);建议将这部分逻辑集中到一个单独的辅助函数中,以避免 bootstrap 阶段的上下文与每次请求的build_tls_connector之间产生配置偏差。 - 新的确认对话框辅助函数接受一个非常宽松的
unknown类型的candidate,并且useConfirmDialog还可能返回undefined;你可能需要收紧这些类型(例如使用一个能反映你 UI 库$confirm的联合类型),以便在编译期捕获误用,并让调用点更具自说明性。
给 AI Agent 的提示
Please address the comments from this code review:
## Overall Comments
- There are now two separate code paths constructing SSL contexts (in `runtime_bootstrap.py` and `astrbot/core/utils/http_ssl.py`); consider centralizing this logic in a single helper to avoid configuration drift between the bootstrap context and the per-request `build_tls_connector`.
- The new confirmation dialog helper accepts a very loose `unknown` `candidate` and returns `undefined` from `useConfirmDialog`; you might want to tighten these typings (e.g., a union type reflecting your UI library’s `$confirm`) to catch misuses at compile time and keep call sites more self-documenting.
## Individual Comments
### Comment 1
<location> `runtime_bootstrap.py:7` </location>
<code_context>
+import aiohttp.connector as aiohttp_connector
+import certifi
+
+_BOOTSTRAP_RECORDS: list[tuple[str, str]] = []
+_TLS_BOOTSTRAP_DONE = False
+
</code_context>
<issue_to_address>
**issue (complexity):** Consider simplifying this bootstrap module by removing buffered logging and global state in favor of a single stateless helper that takes an optional logger and configures aiohttp with the certifi-backed SSL context directly.
You can keep the same behavior (patching aiohttp + certifi context + optional logger) with less indirection by:
* Removing the buffered log records and logging directly.
* Avoiding the dual-purpose `_TLS_BOOTSTRAP_DONE` flag.
* Making the logger an explicit dependency instead of a separate bootstrap phase.
For example, you can collapse `_record`, `flush_bootstrap_records`, `initialize_runtime_bootstrap`, and the global state into a single, focused helper:
```python
import logging
import ssl
from typing import Any
import aiohttp.connector as aiohttp_connector
import certifi
log = logging.getLogger(__name__)
def _try_patch_aiohttp_ssl_context(ssl_context: ssl.SSLContext, log_obj: Any | None = None) -> bool:
logger = log_obj or log
attr_name = "_SSL_CONTEXT_VERIFIED"
if not hasattr(aiohttp_connector, attr_name):
logger.warning(
"aiohttp connector does not expose _SSL_CONTEXT_VERIFIED; skipped patch.",
)
return False
current_value = getattr(aiohttp_connector, attr_name, None)
if current_value is not None and not isinstance(current_value, ssl.SSLContext):
logger.warning(
"aiohttp connector exposes _SSL_CONTEXT_VERIFIED with unexpected type; skipped patch.",
)
return False
setattr(aiohttp_connector, attr_name, ssl_context)
logger.info("Configured aiohttp verified SSL context with system+certifi trust chain.")
return True
```
Then `configure_runtime_ca_bundle` can be a simple, stateless helper that takes an optional logger and does not need global flags or bootstrapping records:
```python
def configure_runtime_ca_bundle(log_obj: Any | None = None) -> bool:
logger = log_obj or log
try:
logger.info("Bootstrapping runtime CA bundle.")
ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(cafile=certifi.where())
return _try_patch_aiohttp_ssl_context(ssl_context, log_obj=logger)
except Exception as exc:
logger.error("Failed to configure runtime CA bundle for aiohttp: %r", exc)
return False
```
If you still need a convenience entry point mirroring `initialize_runtime_bootstrap`, it can just delegate:
```python
def initialize_runtime_bootstrap(log_obj: Any | None = None) -> bool:
return configure_runtime_ca_bundle(log_obj=log_obj)
```
This preserves:
* The ability to pass in an arbitrary logger.
* The certifi-backed SSL context and aiohttp patching behavior.
But it removes:
* The global `_BOOTSTRAP_RECORDS` buffer.
* The `_TLS_BOOTSTRAP_DONE` guard/success flag coupling.
* Import-time side effects via the bare `configure_runtime_ca_bundle()` call at the bottom (callers can invoke `initialize_runtime_bootstrap` explicitly during startup instead).
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进评审质量。
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- There are now two separate code paths constructing SSL contexts (in
runtime_bootstrap.pyandastrbot/core/utils/http_ssl.py); consider centralizing this logic in a single helper to avoid configuration drift between the bootstrap context and the per-requestbuild_tls_connector. - The new confirmation dialog helper accepts a very loose
unknowncandidateand returnsundefinedfromuseConfirmDialog; you might want to tighten these typings (e.g., a union type reflecting your UI library’s$confirm) to catch misuses at compile time and keep call sites more self-documenting.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- There are now two separate code paths constructing SSL contexts (in `runtime_bootstrap.py` and `astrbot/core/utils/http_ssl.py`); consider centralizing this logic in a single helper to avoid configuration drift between the bootstrap context and the per-request `build_tls_connector`.
- The new confirmation dialog helper accepts a very loose `unknown` `candidate` and returns `undefined` from `useConfirmDialog`; you might want to tighten these typings (e.g., a union type reflecting your UI library’s `$confirm`) to catch misuses at compile time and keep call sites more self-documenting.
## Individual Comments
### Comment 1
<location> `runtime_bootstrap.py:7` </location>
<code_context>
+import aiohttp.connector as aiohttp_connector
+import certifi
+
+_BOOTSTRAP_RECORDS: list[tuple[str, str]] = []
+_TLS_BOOTSTRAP_DONE = False
+
</code_context>
<issue_to_address>
**issue (complexity):** Consider simplifying this bootstrap module by removing buffered logging and global state in favor of a single stateless helper that takes an optional logger and configures aiohttp with the certifi-backed SSL context directly.
You can keep the same behavior (patching aiohttp + certifi context + optional logger) with less indirection by:
* Removing the buffered log records and logging directly.
* Avoiding the dual-purpose `_TLS_BOOTSTRAP_DONE` flag.
* Making the logger an explicit dependency instead of a separate bootstrap phase.
For example, you can collapse `_record`, `flush_bootstrap_records`, `initialize_runtime_bootstrap`, and the global state into a single, focused helper:
```python
import logging
import ssl
from typing import Any
import aiohttp.connector as aiohttp_connector
import certifi
log = logging.getLogger(__name__)
def _try_patch_aiohttp_ssl_context(ssl_context: ssl.SSLContext, log_obj: Any | None = None) -> bool:
logger = log_obj or log
attr_name = "_SSL_CONTEXT_VERIFIED"
if not hasattr(aiohttp_connector, attr_name):
logger.warning(
"aiohttp connector does not expose _SSL_CONTEXT_VERIFIED; skipped patch.",
)
return False
current_value = getattr(aiohttp_connector, attr_name, None)
if current_value is not None and not isinstance(current_value, ssl.SSLContext):
logger.warning(
"aiohttp connector exposes _SSL_CONTEXT_VERIFIED with unexpected type; skipped patch.",
)
return False
setattr(aiohttp_connector, attr_name, ssl_context)
logger.info("Configured aiohttp verified SSL context with system+certifi trust chain.")
return True
```
Then `configure_runtime_ca_bundle` can be a simple, stateless helper that takes an optional logger and does not need global flags or bootstrapping records:
```python
def configure_runtime_ca_bundle(log_obj: Any | None = None) -> bool:
logger = log_obj or log
try:
logger.info("Bootstrapping runtime CA bundle.")
ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(cafile=certifi.where())
return _try_patch_aiohttp_ssl_context(ssl_context, log_obj=logger)
except Exception as exc:
logger.error("Failed to configure runtime CA bundle for aiohttp: %r", exc)
return False
```
If you still need a convenience entry point mirroring `initialize_runtime_bootstrap`, it can just delegate:
```python
def initialize_runtime_bootstrap(log_obj: Any | None = None) -> bool:
return configure_runtime_ca_bundle(log_obj=log_obj)
```
This preserves:
* The ability to pass in an arbitrary logger.
* The certifi-backed SSL context and aiohttp patching behavior.
But it removes:
* The global `_BOOTSTRAP_RECORDS` buffer.
* The `_TLS_BOOTSTRAP_DONE` guard/success flag coupling.
* Import-time side effects via the bare `configure_runtime_ca_bundle()` call at the bottom (callers can invoke `initialize_runtime_bootstrap` explicitly during startup instead).
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
@sourcery-ai review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey,我发现了 1 个问题,并给出了一些整体性的反馈:
- 新增的
http_ssl_common.py被放在了仓库根目录,并通过顶级模块名导入;建议将它移动到现有的astrbot/astrbot.core.utils命名空间下(并相应调整导入),以避免在打包/冻结环境中出现路径或导入问题。 - 现在确认弹窗的使用方式分裂为
useConfirmDialog()和直接注入的this.$confirm(askForConfirmationDialog(message, this.$confirm));建议统一使用 composable(包括在 Options API 组件中),这样使用方就不需要了解$confirm的注入 key 或其存在。
给 AI Agents 的提示
请根据本次代码评审中的评论进行修改:
## 总体评论
- 新增的 `http_ssl_common.py` 被放在了仓库根目录,并通过顶级模块名导入;建议将它移动到现有的 `astrbot`/`astrbot.core.utils` 命名空间下(并相应调整导入),以避免在打包/冻结环境中出现路径或导入问题。
- 现在确认弹窗的使用方式分裂为 `useConfirmDialog()` 和直接注入的 `this.$confirm`(`askForConfirmationDialog(message, this.$confirm)`);建议统一使用 composable(包括在 Options API 组件中),这样使用方就不需要了解 `$confirm` 的注入 key 或其存在。
## 具体评论
### 评论 1
<location> `astrbot/core/utils/pip_installer.py:52` </location>
<code_context>
handler.close()
+def _patch_distlib_finder_for_frozen_runtime() -> None:
+ global _DISTLIB_FINDER_PATCH_ATTEMPTED
+
</code_context>
<issue_to_address>
**issue (complexity):** 建议将 `_patch_distlib_finder_for_frozen_runtime` 中的 loader 查找逻辑以及注册/校验逻辑提取到几个小的辅助函数中,以简化主控制流程。
通过把这些依赖反射的复杂逻辑拆分成小的辅助函数,同时保持行为完全一致,可以降低阅读 `_patch_distlib_finder_for_frozen_runtime` 时的认知负担。
### 1. 抽取 loader 解析
`loader` 查找逻辑目前有重复,并且增加了主循环中的分支。一个很小的辅助函数就能让意图更清晰,也让循环结构更平直:
```python
def _get_loader_for_package(package: object):
loader = getattr(package, "__loader__", None)
if loader is not None:
return loader
spec = getattr(package, "__spec__", None)
return getattr(spec, "loader", None) if spec is not None else None
```
在 `_patch_distlib_finder_for_frozen_runtime` 中使用该函数:
```python
for package_name in ("pip._vendor.distlib", "pip._vendor"):
try:
package = importlib.import_module(package_name)
except Exception:
continue
loader = _get_loader_for_package(package)
if loader is None:
continue
```
### 2. 抽取注册校验逻辑
“注册、重新获取 registry、再次检查成员、如果缺失则打日志” 这套逻辑本身是很防御性的、可以保留,但会给主循环增加噪音。单独封装成一个辅助函数可以让循环保持线性:
```python
def _try_register_distlib_finder(
distlib_resources,
finder_registry: dict,
register_finder,
resource_finder,
loader,
package_name: str,
) -> bool:
loader_type = type(loader)
if loader_type in finder_registry:
return False
try:
register_finder(loader, resource_finder)
except Exception as exc:
logger.warning(
"Failed to patch pip distlib finder for loader %s (%s): %s",
loader_type.__name__,
package_name,
exc,
)
return False
updated_registry = getattr(distlib_resources, "_finder_registry", finder_registry)
if isinstance(updated_registry, dict) and loader_type not in updated_registry:
logger.warning(
"Distlib finder patch did not take effect for loader %s (%s).",
loader_type.__name__,
package_name,
)
return False
logger.info(
"Patched pip distlib finder for frozen loader: %s (%s)",
loader_type.__name__,
package_name,
)
return True
```
这样核心循环就会更简单、更容易浏览:
```python
for package_name in ("pip._vendor.distlib", "pip._vendor"):
try:
package = importlib.import_module(package_name)
except Exception:
continue
loader = _get_loader_for_package(package)
if loader is None:
continue
_try_register_distlib_finder(
distlib_resources,
finder_registry,
register_finder,
resource_finder,
loader,
package_name,
)
```
通过增加这两个辅助函数,可以在完全不改变功能的前提下,大幅压平控制流结构,并把这些依赖反射、带有防御性编程的逻辑与 `_patch_distlib_finder_for_frozen_runtime` 的调度部分分离开来。
</issue_to_address>帮我变得更有用!请对每条评论点 👍 或 👎,我会根据你的反馈改进后续的评审。
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- The new
http_ssl_common.pyis placed at the repository root and imported via a top-level module name; consider moving it under the existingastrbot/astrbot.core.utilsnamespace (and adjusting imports) to avoid path/import issues in packaged/frozen environments. - The confirmation dialog usage is now split between
useConfirmDialog()and directthis.$confirminjection (askForConfirmationDialog(message, this.$confirm)); it would be cleaner to standardize on the composable (including for Options API components) so that consumers don’t have to know about$confirm’s injection key or existence.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new `http_ssl_common.py` is placed at the repository root and imported via a top-level module name; consider moving it under the existing `astrbot`/`astrbot.core.utils` namespace (and adjusting imports) to avoid path/import issues in packaged/frozen environments.
- The confirmation dialog usage is now split between `useConfirmDialog()` and direct `this.$confirm` injection (`askForConfirmationDialog(message, this.$confirm)`); it would be cleaner to standardize on the composable (including for Options API components) so that consumers don’t have to know about `$confirm`’s injection key or existence.
## Individual Comments
### Comment 1
<location> `astrbot/core/utils/pip_installer.py:52` </location>
<code_context>
handler.close()
+def _patch_distlib_finder_for_frozen_runtime() -> None:
+ global _DISTLIB_FINDER_PATCH_ATTEMPTED
+
</code_context>
<issue_to_address>
**issue (complexity):** Consider extracting the loader lookup and registration/verification logic in `_patch_distlib_finder_for_frozen_runtime` into small helper functions to simplify the main control flow.
You can reduce the cognitive load of `_patch_distlib_finder_for_frozen_runtime` by extracting the reflection-heavy bits into small helpers, while keeping behavior identical.
### 1. Extract loader resolution
The `loader` lookup is duplicated and contributes to branching in the main loop. A tiny helper makes intent clearer and the loop flatter:
```python
def _get_loader_for_package(package: object):
loader = getattr(package, "__loader__", None)
if loader is not None:
return loader
spec = getattr(package, "__spec__", None)
return getattr(spec, "loader", None) if spec is not None else None
```
Use it in `_patch_distlib_finder_for_frozen_runtime`:
```python
for package_name in ("pip._vendor.distlib", "pip._vendor"):
try:
package = importlib.import_module(package_name)
except Exception:
continue
loader = _get_loader_for_package(package)
if loader is None:
continue
```
### 2. Extract registration verification
The “register, re-fetch registry, re-check membership, log if missing” sequence is defensive and fine, but it adds noise to the main loop. A dedicated helper keeps the loop linear:
```python
def _try_register_distlib_finder(
distlib_resources,
finder_registry: dict,
register_finder,
resource_finder,
loader,
package_name: str,
) -> bool:
loader_type = type(loader)
if loader_type in finder_registry:
return False
try:
register_finder(loader, resource_finder)
except Exception as exc:
logger.warning(
"Failed to patch pip distlib finder for loader %s (%s): %s",
loader_type.__name__,
package_name,
exc,
)
return False
updated_registry = getattr(distlib_resources, "_finder_registry", finder_registry)
if isinstance(updated_registry, dict) and loader_type not in updated_registry:
logger.warning(
"Distlib finder patch did not take effect for loader %s (%s).",
loader_type.__name__,
package_name,
)
return False
logger.info(
"Patched pip distlib finder for frozen loader: %s (%s)",
loader_type.__name__,
package_name,
)
return True
```
Then the core loop becomes simpler and easier to scan:
```python
for package_name in ("pip._vendor.distlib", "pip._vendor"):
try:
package = importlib.import_module(package_name)
except Exception:
continue
loader = _get_loader_for_package(package)
if loader is None:
continue
_try_register_distlib_finder(
distlib_resources,
finder_registry,
register_finder,
resource_finder,
loader,
package_name,
)
```
These two extra helpers keep all functionality intact, but significantly flatten the control flow and isolate the reflection-heavy, defensive logic from the orchestration in `_patch_distlib_finder_for_frozen_runtime`.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
本 PR 聚焦修复桌面端打包运行时的三类问题:
背景问题
主要修复
1) pip frozen loader 兼容补丁
辑。
2) SSL 证书链统一到 certifi(并修正初始化时机)
3) mac 字体回退增强
验证
Summary by Sourcery
通过修复冻结环境中 pip 依赖的加载方式、统一出站请求的 SSL 证书处理,以及改进 macOS 上中文文本的字体回退机制,稳定打包后的桌面运行时。
Bug Fixes:
Enhancements:
Original summary in English
Summary by Sourcery
Stabilize the packaged desktop runtime by fixing pip dependency loading in frozen environments, unifying SSL certificate handling for outbound requests, and improving font fallbacks for Chinese text on macOS.
Bug Fixes:
Enhancements:
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强功能:
Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug Fixes(错误修复):
Enhancements(功能增强):
Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强功能:
Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强功能:
Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强功能:
Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug Fixes(错误修复):
Enhancements(功能增强):
Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强功能:
Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements:
Bug 修复:
增强优化:
window.confirm。Original summary in English
Summary by Sourcery
通过强化依赖安装、TLS/SSL 处理以及跨平台字体行为来稳定打包后的运行时和桌面应用,同时在仪表板 UI 中统一确认对话框。
New Features:
Bug Fixes:
Enhancements:
window.confirm。Original summary in English
Summary by Sourcery
Stabilize the packaged runtime and desktop app by hardening dependency installation, TLS/SSL handling, and cross-platform font behavior, while unifying confirmation dialogs in the dashboard UI.
New Features:
Bug Fixes:
Enhancements: