Skip to content

Dev#1714

Merged
SengokuCola merged 37 commits into
mainfrom
dev
May 18, 2026
Merged

Dev#1714
SengokuCola merged 37 commits into
mainfrom
dev

Conversation

@SengokuCola
Copy link
Copy Markdown
Collaborator

@SengokuCola SengokuCola commented May 18, 2026

  • ✅ 接受:与main直接相关的Bug修复:提交到dev分支
  • 新增功能类pr需要经过issue提前讨论,否则不会被合并
  • 🌐 i18n 提醒:除 bootstrap 或紧急修复外,请不要把非 zh-CN 目标翻译作为常规 GitHub 编辑面;常规翻译以 Crowdin -> l10n_* PR 回流为准,详见 docs/i18n.md

请填写以下内容

(删除掉中括号内的空格,并替换为小写的x

    • main 分支 禁止修改,请确认本次提交的分支 不是 main 分支
    • 我确认我阅读了贡献指南
    • 本次更新类型为:BUG修复
    • 本次更新类型为:功能新增
    • 本次更新是否经过测试
    • 如果本次修改涉及 src/A_memorix,我确认已阅读 src/A_memorix/MODIFICATION_POLICY.md,不涉及则无需勾选
  1. 请填写破坏性更新的具体内容(如有):
  2. 请简要说明本次更新的内容和目的:

其他信息

  • 关联 Issue:Close #
  • 截图/GIF
  • 附加信息:

Summary by CodeRabbit

发布说明 - 版本 1.0.0-pre.22

  • 新功能

    • 新增"启用思考"开关,支持为规划器和回复器独立控制思考模式
    • 扩展插件配置国际化支持
    • 任务级超时设置支持
  • 改进

    • 将 DeepSeek 设为默认 API Provider
    • 优化插件卸载流程,自动清理残留文件
    • 性能优化:消息存储异步化,提升高并发场景稳定性
  • 修复

    • 修复表达选择和回复效果判断中的视觉上下文问题

Review Change Stack

SengokuCola and others added 30 commits May 16, 2026 18:35
- TaskConfig 新增 hard_timeout 字段(默认 180s);LLMOrchestrator 5 个公开入口统一套 asyncio.wait_for,超时抛 LLMTaskTimeoutError(继承 ModelAttemptFailed)复用切模型链路
- DEFAULT_TASK_CONFIG_TEMPLATES 9 个任务块种子化 hard_timeout:planner=120、utils/learner/emoji/voice=60、embedding=30、其余 180
- MessageUtils 新增 store_message_to_db_async(asyncio.to_thread 包装);message_gateway / heartflow_message_processor / bot / send_service 4 个调用点改为 await,消除主事件循环里同步 SQLAlchemy session 的阻塞

修复 LLM 单次调用被上游代理 TPM 静默排队卡死、叠加同步落库阻塞导致主循环饥饿、plugin.health 30s 超时连锁杀 napcat 的故障
PR review 反馈两处问题修正:

- hard_timeout 原先包在 _execute_request 整体外面,超时会取消整个 for 循环导致内部 except ModelAttemptFailed 进不去,"切下一个模型" fallback 失效且 usage_penalty -1 清理被绕过造成负载均衡计数器泄露。改为在 _execute_request 循环内对单次 _attempt_request_on_model 套 asyncio.wait_for,TimeoutError 转 LLMTaskTimeoutError(继承 ModelAttemptFailed)由现有 except 分支自动接住,复用切模型链路与计数器清理
- DEFAULT_TASK_CONFIG_TEMPLATES 新增的 5 个最小条目(learner/emoji/vlm/voice/embedding)只写了 hard_timeout,但 build_default_model_templates 用 task_template["model_list"] 直接索引,会让 create_default_model_config 在新部署时 KeyError。补 model_list=[]
PR review 第二轮反馈两处问题修正:

- build_single_model_task / summary_importer 重建 TaskConfig 时漏传 hard_timeout,导致 A_Memorix 单模型路由从 planner 模板派生时 120s 被静默退回 180s 默认值;同步带上字段
- _build_task_config_signature 未把 hard_timeout 纳入签名,热重载只改超时时签名不变会被误判为旧配置;签名元组追加 hard_timeout
- _attempt_request_on_model_with_timeout 内层 warning 与 _execute_request 的 except ModelAttemptFailed 分支日志重复(LLMTaskTimeoutError.message 已含 task/model/timeout 信息),删除内层日志
PR review 第三轮反馈:to_thread 默认线程池有多个 worker,突发消息流量下多个 worker
会并发拿 SQLAlchemy session 写入;底层 SQLite WAL 仅允许单写、busy_timeout 1s
不足以缓冲所有突发,会触发 `database is locked`。

新增 module-level `_DB_WRITE_LOCK = asyncio.Lock()`,store_message_to_db_async 在
持有 lock 后再 to_thread,把写入串行化;仍保持同步 SQLAlchemy session 在线程池里
执行,事件循环不阻塞。
PR review 第四轮反馈两处问题修正:

- await_task_with_interrupt 只在 interrupt_flag set 时 cancel child task;外层
  asyncio.wait_for 触发 hard_timeout 时仅 CancelledError 从 sleep 抛出,child task
  不被取消导致上游 httpx 请求继续在后台跑、占用连接 / token。加 try/finally 在所有
  退出路径上 cancel 未完成的 child task
- LLMTaskTimeoutError 构造里写死 original_exception=None 丢失了原始 asyncio.TimeoutError
  上下文。__init__ 接收 original_exception 并向 ModelAttemptFailed 透传;调用点传 e
PR review 第五轮反馈两处问题修正:

- _execute_request 内 `last_exception = e.original_exception or e` 会展开 original_exception,
  上一轮加的 `original_exception=e` 让所有模型都超时时上层最终收到 raw asyncio.TimeoutError
  而非承诺的 LLMTaskTimeoutError。撤回 original_exception 传递,原始 TimeoutError 仍通过
  `raise ... from e` 的 __cause__ 链保留供 traceback / 调试使用
- update_message_id 是同步 DB 写入,在 echo_message_process(async)里被裸调,违反本次
  消息落库异步化目标。新增 update_message_id_async 走同一把 _DB_WRITE_LOCK + to_thread;
  bot.py:473 调用点改为 await
PR review 第六轮反馈:module-level `asyncio.Lock()` 在测试场景(pytest-asyncio
每用例独立 loop)会绑定到第一个使用它的 loop,后续切换 loop 时跨 loop 复用。
改为 `_get_db_write_lock()` 懒初始化,首次需要时再构造,避免 import 期触发;
也与项目内其他 lock 全为函数/实例级的风格保持一致。
PR review 第七轮反馈:finally 里只 cancel 不 await,子任务在后台延迟清理,
若 cancel 后子任务清理过程中再抛异常会变成「Task exception was never retrieved」
警告污染日志。cancel 后用 contextlib.suppress 抑制 CancelledError 与清理异常
再 await,让子任务生命周期完全收敛在本函数内。
PR review 第八轮反馈两处问题合并修正:

- gemini 建议改用 functools.lru_cache(maxsize=None) 简化 lazy init,比手写
  `if None then create` 更 Pythonic
- sourcery 指出手写 lazy init 存在理论 race(两个协程同时见 None 各自建 Lock),
  lru_cache 内部用 thread lock 自动消除该 race
- 多 loop 场景下 Lock 仍绑定首次使用所在 loop(lru_cache 也一样),但 MaiBot
  单进程单 event loop 不会触发;在 docstring 显式注明该假设供后续维护参考
PR review 第九轮反馈实事求是修正:之前我注释里写「假设 MaiBot 是单进程单 event loop」
但实际上 bot.py 主 loop、WebUI 在另一个线程的独立 loop、asyncio.run 临时 loop 等
都同时存在;asyncio.Lock 只能互斥同一个 loop 内的协程,对跨 loop / 跨线程并发写
完全形同虚设。

改成 module-level threading.Lock:
- 在 to_thread worker 线程内同步持有,不依赖 event loop
- 进程级互斥,任何 loop / 任何线程发起的 SQLite 写都被串行
- 不再需要 lru_cache / lazy init 兜底跨 loop 风险,代码更直白
fix: tool search解析失败
PR review 第十轮反馈两处问题修正:

- _DB_WRITE_THREAD_LOCK 之前只在 async wrapper 里持有,sync store_message_to_db /
  update_message_id 的直接调用方(如 pytests/test_message_image_persistence.py、
  迁移脚本)会绕过锁形成竞争。把 with _DB_WRITE_THREAD_LOCK 移入两个 sync 方法
  本体,所有写入路径共享同一套串行化;async wrapper 简化为 to_thread 直透传
- await_task_with_interrupt finally 里的 contextlib.suppress(Exception) 太宽,
  会静默掉子任务清理代码里的 AttributeError / TypeError 等编程错误。改成
  try/except CancelledError + Exception (debug 日志),CancelledError 静默,
  其他异常以 debug 记录避免完全淹没。同步移除文件顶部不再需要的 contextlib 导入
…db-store

fix: LLM任务级 hard_timeout 与消息落库异步化
fix(A_memorix):为人物画像添加可调节的最大token数量限制
fix(A_memorix):调整episode重建逻辑
fix: LLM 任务硬超时 + 消息落库异步化,避免主循环饥饿
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b2e0a2d4-ae19-49e3-9f70-46f4e13ac574

📥 Commits

Reviewing files that changed from the base of the PR and between 40f1c60 and 7df378c.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (41)
  • README.md
  • changelogs/changelog.md
  • dashboard/package.json
  • dashboard/src/i18n/locales/zh.json
  • dashboard/src/lib/plugin-api/types.ts
  • dashboard/src/lib/version.ts
  • dashboard/src/routes/config/model.tsx
  • dashboard/src/routes/plugin-config.tsx
  • dashboard/src/routes/plugins/UpdatesTab.tsx
  • dashboard/src/routes/plugins/index.tsx
  • dashboard/src/routes/setup/StepForms.tsx
  • dashboard/src/routes/setup/api.ts
  • dashboard/src/routes/setup/index.tsx
  • dashboard/src/routes/setup/types.ts
  • pyproject.toml
  • pytests/test_maisaka_chat_loop_visual_mode.py
  • pytests/webui/test_plugin_management_routes.py
  • src/A_memorix/CONFIG_REFERENCE.md
  • src/A_memorix/QUICK_START.md
  • src/A_memorix/config_schema.json
  • src/A_memorix/core/runtime/sdk_memory_kernel.py
  • src/A_memorix/core/utils/model_routing.py
  • src/A_memorix/core/utils/person_profile_service.py
  • src/A_memorix/core/utils/summary_importer.py
  • src/chat/heart_flow/heartflow_message_processor.py
  • src/chat/message_receive/bot.py
  • src/common/utils/utils_message.py
  • src/config/config.py
  • src/config/default_model_config.py
  • src/config/model_configs.py
  • src/config/official_configs.py
  • src/llm_models/exceptions.py
  • src/llm_models/model_client/adapter_base.py
  • src/llm_models/utils_model.py
  • src/maisaka/chat_loop_service.py
  • src/maisaka/runtime.py
  • src/plugin_runtime/component_query.py
  • src/plugin_runtime/host/message_gateway.py
  • src/services/send_service.py
  • src/webui/routers/plugin/management.py
  • src/webui/routers/plugin/support.py

Walkthrough

本 PR 是 v1.0.0-pre.22 版本的综合发布,跨越应用层、运行时、存储、插件系统多个功能模块的统一迭代。主要包括:WebUI 模型配置思考开关与 DeepSeek 默认提供商、插件配置多语言映射支持、LLM 任务级硬超时管理机制、消息落库的异步化与跨线程串行化、A_memorix 证据分类可配化与摘要导入重构、Maisaka 视觉消息与工具搜索修复、插件管理安装卸载流程优化。

Changes

v1.0.0-pre.22 多模块联合发布

Layer / File(s) Summary
版本号统一更新
pyproject.toml, dashboard/package.json, dashboard/src/lib/version.ts, src/config/config.py
跨应用与配置层统一版本号从 pre.21 升级至 pre.22,包括项目版本、dashboard 包版本、应用常量与内层配置版本。
WebUI 模型配置与思考开关
dashboard/src/routes/setup/types.ts, dashboard/src/routes/setup/index.tsx, dashboard/src/routes/setup/StepForms.tsx, dashboard/src/routes/setup/api.ts
在 ModelSetupConfig 类型新增 planner_thinking/replyer_thinking 布尔字段,StepForms 实现基于模型标识符(包含 deepseek-v4-pro)的思考推断与手动开关 UI,api.ts 在保存时通过 buildThinkingExtraParams 生成新的 extra_params 结构(thinking.type + reasoning_effort),完整支持模型思考启用/禁用的配置化。
插件配置多语言支持体系
dashboard/src/lib/plugin-api/types.ts, dashboard/src/routes/plugin-config.tsx
五个插件配置接口新增可选 i18n 字段(Record<string, Record<string, string>>),plugin-config.tsx 实现 getLocaleCandidates/resolveLocalizedText/localizeItemFields 等多语言解析函数,在 FieldRenderer/SectionRenderer/PluginConfigEditor 中统一应用本地化文本解析,为字段标签、占位符、提示、分组标题、标签页与插件名称提供多语言映射。
插件生命周期与流程优化
src/webui/routers/plugin/support.py, src/webui/routers/plugin/management.py, pytests/webui/test_plugin_management_routes.py
新增 is_plugin_install_residue 函数识别卸载残留(仅含 config.toml),安装前清理残留目录;卸载流程调整为先禁用插件、触发运行时全局重载再删除目录,配套新增两项测试验证残留清理与运行时卸载顺序。
LLM 任务级 hard_timeout 管理体系
src/config/model_configs.py, src/llm_models/exceptions.py, src/llm_models/model_client/adapter_base.py, src/llm_models/utils_model.py, src/config/default_model_config.py
TaskConfig 新增 hard_timeout 字段(默认 240s),新建 LLMTaskTimeoutError 异常类,adapter_base 增强异步任务清理机制确保 CancelledError 完整处理,LLMOrchestrator 实现 _attempt_request_on_model_with_timeout 包装进行 asyncio.wait_for 超时控制,LLMRequest 签名计算纳入 hard_timeout,默认模板补齐超时值。
消息持久化异步化与串行化
src/common/utils/utils_message.py, src/chat/heart_flow/heartflow_message_processor.py, src/chat/message_receive/bot.py, src/plugin_runtime/host/message_gateway.py, src/services/send_service.py
utils_message.py 新增 threading.Lock 进行进程级数据库写入串行化,新增 store_message_to_db_async/update_message_id_async 异步包装,在五个调用点改用异步调用 with await,并对相关代码格式进行优化。
A_memorix 证据分类可配化
src/A_memorix/config_schema.json, src/config/official_configs.py, src/A_memorix/CONFIG_REFERENCE.md, src/A_memorix/QUICK_START.md, src/A_memorix/core/utils/person_profile_service.py
新增 evidence_classification_max_tokens 配置项(默认 1200,范围 128~32768)跨 schema/配置类/文档,person_profile_service 实现 _profile_classification_max_tokens 方法从配置读取并做范围裁剪,替换证据分类 LLM 调用的固定 max_tokens。
A_memorix 摘要导入与增量 episode 处理
src/A_memorix/core/utils/summary_importer.py, src/A_memorix/core/runtime/sdk_memory_kernel.py, src/A_memorix/core/utils/model_routing.py
summary_importer 重构返回结构为 SummaryImportResult 数据类,在所有分支统一返回并在成功时捕获段落 hash,_execute_import 改为返回 str(段落 hash);SDKMemoryKernel.summarize_chat_stream 改用 enqueue_episode_pending 进行增量入队而非全量 rebuild;model_routing 补齐 TaskConfig hard_timeout 继承。
Maisaka 与插件运行时修复
src/maisaka/chat_loop_service.py, src/maisaka/runtime.py, src/plugin_runtime/component_query.py, pytests/test_maisaka_chat_loop_visual_mode.py
chat_loop_service 禁用 expression_selector/reply_effect_judge 请求的视觉消息,runtime 按中文括号截断工具名避免附加说明干扰,component_query 将消息序列化后注入 invoke_args["message"],新增视觉模式与卸载流程测试。
UI 文案与插件更新标签页
dashboard/src/i18n/locales/zh.json, dashboard/src/routes/config/model.tsx, dashboard/src/routes/plugins/UpdatesTab.tsx, dashboard/src/routes/plugins/index.tsx
更新 zh.json 中 setup 与重启文案,模型管理标签页改为"模型列表",新增 UpdatesTab 组件独立渲染可更新插件列表,统一标签页计数为 getFilteredPluginCount 函数。
文档与测试扩展
README.md, changelogs/changelog.md, pytests/test_maisaka_chat_loop_visual_mode.py, pytests/webui/test_plugin_management_routes.py
README 更新社区群组信息,changelog 记录 v1.0.0-pre.22 各模块变更,新增 Maisaka 视觉模式与插件管理路由单元测试。

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • Mai-with-u/MaiBot#1709: 同样重构 A_memorix 的 SummaryImportResult 返回结构与 SDKMemoryKernel.summarize_chat_stream 的 episode 增量入队逻辑。
  • Mai-with-u/MaiBot#1707: 同样实现 LLM 任务级 hard_timeout/LLMTaskTimeoutError 与消息落库的 store_message_to_db_async 异步调用和跨线程 SQLite 锁。
  • Mai-with-u/MaiBot#1713: 同样新增与集成 UpdatesTab 组件用于插件更新标签页的渲染与过滤逻辑。
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@SengokuCola SengokuCola merged commit 78c3536 into main May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants