Yokami
0ffdf54407
feat(context): improve default LLM compression prompt for better continuity ( #8424 )
2026-05-30 13:46:41 +08:00
NayukiChiba
8353fe1608
fix(anthropic): Anthropic API tool_choice schema conversion ( #8328 )
...
* fix(anthropic): 修复 Anthropic API tool_choice 格式转换及参数支持
- 将 tool_choice 从简单的 auto/required 逻辑改为遵循 Anthropic API 规范,支持 auto/any/none/tool 四种原生值
- 兼容 OpenAI 风格的 tool_choice="required",自动映射为 {"type": "any"}
- 允许直接传入 dict 类型的 tool_choice 以实现指定工具调用
- 更新 text_chat 和 stream_chat 入口的参数类型标注,扩大可接收的 tool_choice 类型
- 新增 tool_choice 格式转换的单元测试,覆盖各类输入场景
Closes #8319
* Clean up test cases and remove unused mocks
Removed unused mock classes and tests for tool_choice conversion.
* fix(anthropic): 修复 Anthropic API tool_choice="tool" 参数处理及重构格式转换逻辑
- 提取静态方法 _normalize_tool_choice 统一处理 tool_choice 格式转换,消除重复代码
- 处理字符串 "tool" 值时,因无法指定具体工具名而回退为 auto 并记录警告,避免无效请求
- 在 _query 和 _stream_query 中采用默认值 auto 并应用规范化逻辑,确保一致性
* test(anthropic): 添加空工具集时跳过工具参数设置的测试
- 新增 _EmptyToolSet 模拟类,模拟无工具场景
- 新增测试用例 test_tool_choice_empty_tool_list_skips_tool_choice
- 验证当 ToolSet 存在但工具列表为空时,请求不包含 tools 和 tool_choice 参数
- 完善边缘情况测试覆盖,确保与现有逻辑一致
* style: ruff 格式化一下
---------
Co-authored-by: Weilong Liao <37870767+Soulter@users.noreply.github.com >
2026-05-30 13:44:45 +08:00
時壹
01a47b8360
feat: pass through qq webhook extra fields ( #6274 )
2026-05-29 21:06:04 +08:00
千岚之夏
d16e6a869e
fix: Dashboard list config item cannot input spaces ( #8403 )
...
* fix: Dashboard list config item cannot input spaces (#8393 )
* docs: add comment clarifying pure-space filtering in watch is expected behavior
2026-05-29 13:03:56 +08:00
M1LKT
cea37707a5
feat: 为已配置的模型增加能力图标 ( #8405 )
2026-05-29 13:02:46 +08:00
elecvoid243
adae1f3598
fix(command-suggestion): support custom wake-up words & hover information ( #8353 )
...
* feature: add command suggestion for ChatUI
* feat(chat): add focus functionality to chat input after sending messages
* feat(llm): add error handling for LLM provider selection failures
* feat(command-suggestion): enhance command filtering and sorting logic
* fix(command-suggestion): support custom wake-up words & hover information
* ruff
---------
Co-authored-by: Soulter <905617992@qq.com >
2026-05-29 01:17:32 +08:00
Waterwzy
e087b9def3
fix(plugin): plugin name in the marketplace does not match the local plugin ( #8276 )
...
* fix: plugin name in the marketplace does not match the local plugin
* chore: update test
* Update astrbot/dashboard/routes/plugin.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
* Update astrbot/dashboard/routes/plugin.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
* Update astrbot/dashboard/routes/plugin.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
* chore: reformat code
* Clean up unused variables in useExtensionPage.js
Removed unused sets for installed repositories and names.
* fix: 统一repo匹配逻辑,移除fallback
---------
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-05-29 01:02:51 +08:00
千岚之夏
9bd38cad57
fix: strip segment text to remove extra blank lines in segmented reply ( #8304 )
...
* fix: strip segment text to remove extra blank lines in segmented reply
Fixes #8300
* refactor: optimize seg.strip() per PR review suggestion
2026-05-29 00:54:47 +08:00
千岚之夏
022a5dd9f8
fix: prevent duplicate processing of quoted images by multimodal main providers when no dedicated image caption provider is configured ( #8401 )
...
Co-authored-by: C₂₂H₂₅NO₆ <Sisyphbaous-DT-Project@users.noreply.github.com >
Co-authored-by: Soulter <905617992@qq.com >
2026-05-29 00:54:36 +08:00
Dt8333
e960c1495e
fix(dashboard): fix plugin displayed dup ( #8389 )
...
Fixed the issue of duplicate plugin cards introduced in #8369
2026-05-28 10:39:56 +08:00
Yufeng He
9688a64cd5
fix(dashboard): add sub-command count label ( #8388 )
2026-05-28 10:12:00 +08:00
liuwanwan
8b16e4d6c9
fix: sanitize file name in file component ( #8318 )
...
* fix: sanitize remote file component names
* fix: handle windows-invalid file names
* test: cover windows-invalid file names
---------
Co-authored-by: liuwanwan1 <243261597+liuwanwan1@users.noreply.github.com >
2026-05-28 08:20:11 +08:00
Yufeng He
26e867cc6d
fix(core): route image requests to vision fallback ( #8089 )
2026-05-27 22:21:55 +08:00
lingyun14
a221c74b74
Fix/plugin metadata repo type guard ( #8207 )
...
* fix: 修复插件 repo 字段类型导致前端报错
* fix: 修复插件 repo 字段类型导致前端报错
* fix: 使用 normalizeInstallUrl 统一 repo 字段处理
* fix:优化 installedRepos 构建方式
2026-05-27 22:00:42 +08:00
Weilong Liao
7f94bce360
feat(qqofficial): split message chain by media and update sending logic ( #8376 )
...
* feat(qqofficial): split message chain by media and update sending logic
* Delete tests/test_qqofficial_adapter.py
2026-05-27 21:59:47 +08:00
NayukiChiba
85f9c4dff8
fix(mimo): 修复voice design模型请求中包含无效voice参数的问题 ( #8326 )
...
* fix(mimo): 修复voice design模型请求中包含无效voice参数的问题
- voice design模型不支持audio.voice参数,之前统一添加导致请求可能出错
- 在构建请求payload时根据模型名称动态决定是否包含voice字段
- 增加单元测试覆盖voicedesign模型和普通模型的参数构建逻辑
close #8283
* style: 使用snake case命名法
2026-05-27 21:36:22 +08:00
lingyun14
465a685b66
feat: add EULA hint for first notification ( #7955 )
...
* docs: add FIRST_NOTICE.ru-RU.md
* docs: add metrics notice to FIRST_NOTICE files
* docs: add metrics notice to FIRST_NOTICE
* docs: update FIRST_NOTICE to reference system config
* docs: update FIRST_NOTICE to reference system config
* docs: update FIRST_NOTICE to reference system config
* Update FIRST_NOTICE.md
* Update FIRST_NOTICE.en-US.md
* Update FIRST_NOTICE.ru-RU.md
2026-05-27 21:33:41 +08:00
NayukiChiba
89153fdf80
fix: 8267 mimo reasoning content ( #8327 )
...
* feat(openai): 为MiMo推理模型自动补充reasoning_content字段
- 消息过滤时增加reasoning_content判断,保留仅含思考内容的assistant消息
- 自动为MiMo推理模型的assistant历史消息注入空reasoning_content,满足API要求
- 通过模型名称集合和xiaomimimo.com端点双重判断是否为MiMo推理模型
- 添加单元测试覆盖不同模型识别、字段注入、端点检测和已有内容保留等场景
* fix(openai): 移除MiMo推理模型检测中的端点主机名判断
- 回退通过xiaomimimo.com主机名自动识别MiMo推理模型的逻辑
- 仅保留基于模型名称集合的判断方式,避免误判非MiMo模型
- 删除对应主机名检测的单元测试用例
* test(openai): 补充MiMo推理模型仅含reasoning_content消息不过滤的单元测试
- 添加test_mimo_filter_preserves_reasoning_only_assistant_message参数化测试
- 验证仅有reasoning_content的assistant消息不会被_sanitize过滤
- 确保包含reasoning_content的空content消息仍保留在对话历史中
* Update test_openai_source.py
---------
Co-authored-by: Weilong Liao <37870767+Soulter@users.noreply.github.com >
2026-05-27 21:13:40 +08:00
星空凌
538772c305
feat: add Xiaomi 和 Xiaomi Token Plan LLM provider ( #7744 )
...
* feat: 新增 Xiaomi 和 Xiaomi Token Plan LLM 提供商
- 新增 Xiaomi provider(OpenAI 兼容)
- 新增 Xiaomi Token Plan provider(Anthropic 兼容)
- 支持全模态(图片理解)
- 内置 MiMo v2.5 系列模型
* Update astrbot/core/provider/sources/xiaomi_token_plan_source.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
* Remove default config from Xiaomi provider adapter
Removed default configuration template for Xiaomi provider adapter.
* Remove default config from Xiaomi Token Plan adapter
Removed default configuration template for Xiaomi Token Plan provider adapter.
* chore: rf
---------
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Weilong Liao <37870767+Soulter@users.noreply.github.com >
Co-authored-by: Soulter <905617992@qq.com >
2026-05-27 21:11:00 +08:00
lxfight
23d70dbdbd
feat(webui): add direct access button on plugin cards and improve embedded page height ( #8369 )
...
* feat(plugin): add pages field to plugin list API response
Include discovered page names for each plugin in the /api/plugin/get
response, so the frontend can determine whether a plugin has a WebUI
without an extra detail request.
* feat(webui): add direct WebUI access button on plugin cards
- Add "open-webui" button on plugin cards when plugin has pages
- Navigate to plugin's first page directly from the card
- Adjust PluginPagePage iframe height for better UX
- Add i18n labels (zh-CN/en-US/ru-RU)
* perf(plugin): use asyncio.gather for concurrent page discovery
Replace sequential await loop with concurrent processing to avoid
blocking on disk I/O when discovering plugin pages.
* fix(webui): disable open plugin UI button when plugin is deactivated
Prevent navigation to a disabled plugin's WebUI page which would
result in an error.
* test: update plugin API tests to match pages field in list response
- test_plugin_get_excludes_scanned_pages: expect pages field now present
- test_plugins: use name-based lookup instead of exact count assertion
---------
Co-authored-by: lxfight <lxfight@192.168 .5.50>
2026-05-27 20:33:10 +08:00
Simon He
ae44163bb3
feat: enable smooth markdown streaming ( #8371 )
2026-05-27 20:30:16 +08:00
dependabot[bot]
284c4082f3
chore(deps): bump the github-actions group with 3 updates ( #8335 )
...
Bumps the github-actions group with 3 updates: [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action ), [docker/login-action](https://github.com/docker/login-action ) and [docker/build-push-action](https://github.com/docker/build-push-action ).
Updates `docker/setup-buildx-action` from 4.0.0 to 4.1.0
- [Release notes](https://github.com/docker/setup-buildx-action/releases )
- [Commits](https://github.com/docker/setup-buildx-action/compare/v4.0.0...v4.1.0 )
Updates `docker/login-action` from 4.1.0 to 4.2.0
- [Release notes](https://github.com/docker/login-action/releases )
- [Commits](https://github.com/docker/login-action/compare/v4.1.0...v4.2.0 )
Updates `docker/build-push-action` from 7.1.0 to 7.2.0
- [Release notes](https://github.com/docker/build-push-action/releases )
- [Commits](https://github.com/docker/build-push-action/compare/v7.1.0...v7.2.0 )
---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
dependency-version: 4.1.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: github-actions
- dependency-name: docker/login-action
dependency-version: 4.2.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: github-actions
- dependency-name: docker/build-push-action
dependency-version: 7.2.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: github-actions
...
Signed-off-by: dependabot[bot] <support@github.com >
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-27 12:00:42 +08:00
letr
bc35daa110
fix(webui): restore mobile provider source deletion ( #8321 )
...
* fix(webui): restore mobile provider source deletion
* fix(webui): improve provider source delete accessibility
2026-05-27 11:59:06 +08:00
F. Abyssalis
000d638c1b
fixed typo in the Chinese documentation for the QQ official WebSocket bot setup. ( #8351 )
2026-05-27 11:56:28 +08:00
香草味的纳西妲喵
7ff58f2938
fix(docs): Update FAQ, add description of hard refresh (force reload) of the page. ( #8359 )
2026-05-27 08:44:23 +08:00
hibiki233i
2d78626840
fix SQLAlchemy compatibility issues on macOS ( #7724 )
...
* Stabilize packaged SQLite knowledge base initialization
* Apply suggestion from @sourcery-ai[bot]
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
* Apply suggestion from @gemini-code-assist[bot]
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
* fix: updating database URL handling and ensuring unique document IDs
* fix: preserve sqlite pragmas with null pool
---------
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: 邹永赫 <1259085392@qq.com >
2026-05-26 09:37:01 +09:00
NayukiChiba
ff28eca9ca
fix(openai): 修复流式响应末尾usage信息丢失问题 ( #8306 )
...
- 修复在流式处理过程中,因跳过 delta=None 且 choices=[] 的 usage chunk 导致最终 completion 丢失 usage 数据的问题
- 在 handle_chunk 调用条件中增加 chunk.usage 判断,确保末尾 usage chunk 能被正常传递给 state 处理
- 更新相关注释,说明 usage chunk 的例外情况,保障流式响应的 usage 信息完整性
2026-05-23 23:17:44 +08:00
elecvoid243
dcc99e6b9b
feat: 为ChatUI添加指令候选功能 ( #8279 )
...
* feature: add command suggestion for ChatUI
* feat(chat): add focus functionality to chat input after sending messages
* feat(llm): add error handling for LLM provider selection failures
* feat(command-suggestion): enhance command filtering and sorting logic
---------
Co-authored-by: Soulter <905617992@qq.com >
2026-05-22 20:57:19 +08:00
lingyun14
fd4fe84310
fix: docs ( #8229 )
...
* Update listen-message-event.md
* Update other.md
* Update send-message.md
* Update ai.md
* Update ai.md
* Update send-message.md
* Update listen-message-event.md
* Delete docs/zh/dev/star/guides/env.md
* Delete docs/en/dev/star/guides/env.md
* Update simple.md
* Update discord.md
* Update discord.md
* Update matrix.md
* Update matrix.md
* Update index.md
* Update index.md
* Update openapi.md
* Update ppio.md
* Update ppio.md
* Update function-calling.md
* Update function-calling.md
* Update config.mjs
* docs: add EN desktop deployment page
* Update plugin.md
* Update ai.md
* Update ai.md
* Update ai.md
* Update desktop.md
2026-05-22 20:35:29 +08:00
EmilyCheoh
f5bd4f30e5
fix: preserve original completion_text in skills_like tool re-query ( #8240 )
...
Only overwrite tool-call-related fields from the re-query response, preserving the original completion_text and reasoning_content that were already sent to the user.
2026-05-22 20:32:29 +08:00
x1051445024
1e48bab514
fix: handle delta=None chunks in streaming to prevent SDK to_dict() error ( #8244 )
...
* fix: handle delta=None chunks in streaming to prevent SDK to_dict() error
When certain OpenAI-compatible providers (Gemini, DeepSeek, some proxies)
return chunks with choice.delta=None (e.g. ContentBlockDeltaEvent),
ChatCompletionStreamState._convert_initial_chunk_into_snapshot internally
calls choice.delta.to_dict() at line 747, causing:
'NoneType' object has no attribute 'to_dict'
Fix:
1. Skip handle_chunk when delta is None (delta=None chunks have no
content contribution anyway)
2. Wrap get_final_completion in try/except to gracefully fall back to
empty ChatCompletion if SDK state is corrupted
Refs: openai-python#5069, openai-python#5047
* fix: resolve bugs found by Sourcery and gemini-code-assist review
- Remove orphan logger.error that caused NameError on every chunk
- Replace broken empty ChatCompletion fallback with clean return;
streamed content already yielded, no data loss
Co-authored-by: sourcery-ai[bot] <sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <gemini-code-assist[bot]@users.noreply.github.com>
* fix: properly replace get_final_completion fallback in _query_stream
Previous fix_pr_v3 wrongly injected code into terminate() instead.
Now correctly:
1. Replace empty ChatCompletion fallback with clean return in _query_stream
2. Revert terminate() to original (await self.client.close() only)
* fix: revert corrupted terminate() to original
Previous fix_pr_v3 injected wrong-indentation code into terminate().
---------
Co-authored-by: sourcery-ai[bot] <sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <gemini-code-assist[bot]@users.noreply.github.com>
2026-05-22 20:28:03 +08:00
lingyun14
3f20bbdf23
fix: t2i shiki issue ( #8013 )
...
* fix(t2i): run Shiki runtime injection in executor to avoid blocking event loop
* Update network_strategy.py
* ruff
2026-05-22 19:11:38 +08:00
lingyun14
0711172fa7
Fix/stale command hints ( #8245 )
...
* Update stage.py
* fix: remove stale slash command hints
* fix: remove stale slash command hints
* fix: remove stale slash command hints
* Update openai_source.py
2026-05-21 21:45:57 +08:00
Weilong Liao
d15606d202
feat(password): add command to change AstrBot dashboard password ( #8272 )
...
closes : #8268
2026-05-21 21:37:10 +08:00
M1LKT
165933545d
feat: Automate generation of the MDI icon font subset during dashboard dev and build workflows ( #8264 )
...
* feat: ignore字体集的生成文件,并在编译时自动生成
* 移除preview的前置运行
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
---------
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-05-21 08:48:12 +08:00
Yufeng He
c4693fa68e
fix: support rst and adoc knowledge uploads ( #8255 )
2026-05-20 14:38:16 +08:00
Jianyu Li
7a9fb33dd9
docs: fix typo of the count in FAQ deletion instructions ( #8235 )
...
Correct the number of fields to be deleted from five to six in the instructions.
2026-05-19 14:41:58 +08:00
dependabot[bot]
de0a7afdcf
chore(deps): bump pnpm/action-setup in the github-actions group ( #8233 )
...
Bumps the github-actions group with 1 update: [pnpm/action-setup](https://github.com/pnpm/action-setup ).
Updates `pnpm/action-setup` from 6.0.7 to 6.0.8
- [Release notes](https://github.com/pnpm/action-setup/releases )
- [Commits](https://github.com/pnpm/action-setup/compare/v6.0.7...v6.0.8 )
---
updated-dependencies:
- dependency-name: pnpm/action-setup
dependency-version: 6.0.8
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: github-actions
...
Signed-off-by: dependabot[bot] <support@github.com >
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-19 13:21:03 +09:00
Yufeng He
5bbcdced0f
fix: skip empty llm summaries ( #8195 )
2026-05-19 09:38:55 +08:00
Soulter
dceacd5a87
docs: update release version instructions in AGENTS.md
2026-05-17 15:07:39 +08:00
Soulter
d609f23b71
chore: bump version to 4.25.1
v4.25.1
2026-05-17 15:01:59 +08:00
Soulter
a1e95081be
feat: add random suffix for weixin and dingtalk id
2026-05-17 14:56:15 +08:00
Midwich
b3381c6448
fix(webui): add Noto Sans to global font-family stack for Cyrillic text ( #8205 )
...
PR #8015 added 'Noto Sans' to the Google Fonts link and CJK fallback list,
but the font was placed at the end of $cjk-sans-fallback where browsers
never reach it for Cyrillic text. The global $body-font-family also lacked
'Outfit' entirely, causing Vuetify to use CJK fonts as the primary face.
Changes:
- Remove 'Noto Sans' from the end of $cjk-sans-fallback (it is not a CJK font)
- Add 'Outfit' and 'Noto Sans' to $body-font-family before CJK fallbacks
- Update .Outfit class in _container.scss to match the new stack
This ensures:
- Latin text → Outfit
- Cyrillic text → Noto Sans (loaded by vite-plugin-webfont-dl)
- CJK text → Noto Sans SC / PingFang SC etc.
Fixes follow-up to #8015 .
2026-05-16 22:03:13 +08:00
Soulter
02291a3217
chore: bump version to 4.25.0
v4.25.0
2026-05-16 01:39:04 +08:00
Yufeng He
1d69626421
fix: pass image inputs through active replies ( #8119 )
...
* fix(core): pass images through active replies
* fix: harden active reply image collection
* test: avoid logger coupling in active reply test
* Delete tests/unit/test_builtin_astrbot_main.py
---------
Co-authored-by: Weilong Liao <37870767+Soulter@users.noreply.github.com >
2026-05-16 01:34:03 +08:00
Tom8266
871b932785
fix: detect Tencent SILK (\x02 prefix) in audio magic bytes to avoid ffmpeg failure ( #8009 )
...
* fix: detect Tencent SILK (\x02 prefix) in audio magic bytes to avoid ffmpeg failure
QQ official bot sends voice in Tencent SILK format (leading \x02 byte before
#!SILK_V3 magic). _get_audio_magic_type() had two off-by-one slice errors:
1. Standard SILK: header[:8] vs b'#!SILK_V3' (8 != 9 bytes) — never matched
2. Tencent SILK: not detected at all
Fixes:
- Standard SILK: header[:9] == b'#!SILK_V3' (correct 9-byte slice)
- Tencent SILK: header[:1] == b"\x02" and header[1:10] == b'#!SILK_V3'
- ensure_wav() routes detected silk to tencent_silk_to_wav()
Before: QQ voice → ffmpeg → 'Invalid data found'
After: QQ voice → magic detects silk → tencent_silk_to_wav → WAV OK
* refactor: use startswith() for SILK magic byte detection
Replace manual slice comparisons with startswith() — cleaner, less
error-prone, and immune to off-by-one slice errors.
Suggested by: sourcery-ai
2026-05-16 01:20:52 +08:00
Weilong Liao
c88025c2a3
feat(dingtalk): implement one-click QR registration and polling mechanism ( #8198 )
2026-05-15 18:43:21 +08:00
lingyun14
094aef6241
fix: drop **kwargs bug in two register funcs ( #8141 )
2026-05-15 17:00:03 +08:00
Weilong Liao
6982ef7d94
feat(weixin_oc): handle session timeout and clear login state ( #8196 )
2026-05-15 15:30:56 +08:00
Midwich
1a0306343a
fix(webui): add Noto Sans font support for Cyrillic text ( #8015 )
...
The WebUI only loaded Noto Sans SC (Simplified Chinese), which lacks
Cyrillic glyphs. Russian text fell back to system sans-serif, causing
poor rendering depending on the OS.
Changes:
- Load Noto Sans (regular) from Google Fonts alongside Noto Sans SC
- Add 'Noto Sans' at the END of $cjk-sans-fallback (after CJK fonts)
so Chinese text still renders with system CJK fonts first,
while Cyrillic text falls through to Noto Sans.
This ensures both Chinese and Cyrillic text render correctly.
2026-05-15 13:36:37 +08:00