feat: 修复了一些 issues 中的 bug,新增了待总结聊天内容的相关命令,新增了聊天中断一段时间后的自动总结功能,新增了给记忆注入附带时间信息的选项,新增了对于图片转述内容的支持#73
Conversation
There was a problem hiding this comment.
Pull request overview
该 PR 主要围绕“会话级隔离 + 待总结/自动总结能力增强 + 图片转述支持 + 配置与冗余清理”展开,目标是修复 /new//reset 后跨会话串扰(Issue #70),并补齐对图片轮次与空闲场景的总结/记忆流程支持。
Changes:
- 引入 conversation_id 参与 session key 构建,实现同一聊天源下的“对话窗口级”隔离,并增加总结任务防丢失/重跑机制
- 新增
/lmem pending、/lmem pending-del管理待总结窗口;新增空闲自动总结巡检;支持图片转述内容的召回/落库/总结 - 清理冗余模块与配置项(移除 sparse_retriever、ConversationManager 缓存/TTL 等),并同步更新配置校验与 schema(但文档示例仍需补齐)
Reviewed changes
Copilot reviewed 21 out of 22 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| storage/conversation_store.py | get_recent_sessions() 支持 limit=None,为全量会话扫描提供接口 |
| main.py | 初始化绑定幂等化;WebUI 句柄同步;启动空闲自动总结后台巡检;新增 pending 命令入口 |
| docs/ARCHITECTURE.md | 更新架构文件树,移除已删除的 sparse_retriever 记录 |
| docs/API.md | 更新配置示例中的 session_manager 字段(但未覆盖本 PR 新增配置项) |
| core/utils/init.py | 记忆注入格式支持可选显示“发生时间”(中文年月日时分格式) |
| core/retrieval/vector_retriever.py | 移除查询预处理逻辑与相关配置依赖 |
| core/retrieval/sparse_retriever.py | 删除冗余稀疏检索器实现文件 |
| core/plugin_initializer.py | ConversationManager 初始化参数精简(移除未使用的缓存/窗口/TTL 配置) |
| core/managers/conversation_manager.py | 移除 LRU 缓存与过期清理;支持外部传入更细粒度 session_id;默认上下文窗口固定为 50 |
| core/event_handler.py | conversation_id 会话隔离;图片转述提取/补写;严格从当前 req 提取本轮输入;空闲自动总结扫描;总结并发防丢失与重跑 |
| core/command_handler.py | WebUI 地址展示改为多地址;reset 支持对话窗口隔离;新增 pending/pending-del;新增会话键解析 helper |
| core/base/config_validator.py | 配置项增删:新增 capture_image_caption / include_memory_time / idle auto summary;移除 sparse/dense retriever 配置 |
| _conf_schema.json | 同步配置 schema:新增图片描述写库、注入带时间、空闲自动总结等字段;移除稀疏/稠密检索器配置 |
| .gitignore | 忽略本地 issue 跟踪文件 LOCAL_ISSUES.md |
| .github/workflows/* | 删除多个自动化工作流文件 |
| .github/ISSUE_TEMPLATE/* | 删除 issue 模板相关文件 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "session_manager": { | ||
| "max_sessions": 100, | ||
| "session_ttl": 3600, | ||
| "context_window_size": 50 | ||
| "enable_full_group_capture": true, | ||
| "max_messages_per_session": 1000 | ||
| }, |
There was a problem hiding this comment.
配置示例里没有包含本 PR 新增/调整的配置项(例如 session_manager.capture_image_caption、recall_engine.include_memory_time、reflection_engine.enable_idle_auto_summary / idle_summary_timeout_seconds),容易让读者按文档配置后发现功能不生效。建议同步更新此处的“完整配置示例”以覆盖新增字段,并说明已移除的旧字段(max_sessions/session_ttl/context_window_size)。
| triggered = 0 | ||
|
|
||
| try: | ||
| sessions = await self.conversation_manager.get_recent_sessions(limit=None) |
There was a problem hiding this comment.
这里使用 limit=None 拉取所有 sessions 并逐个做多次 DB 查询(message_count/metadata/messages_range),会在会话数量较大时造成明显的周期性 IO 开销。建议在 store 层用 SQL 直接按 last_active_at < now-timeout 过滤并分页/限制数量,或按 last_active_at 升序扫描并在遇到未超时的会话时提前结束。
| sessions = await self.conversation_manager.get_recent_sessions(limit=None) | |
| max_sessions = int( | |
| self.config_manager.get( | |
| "reflection_engine.idle_summary_max_sessions", 200 | |
| ) | |
| ) | |
| sessions = await self.conversation_manager.get_recent_sessions( | |
| limit=max_sessions | |
| ) |
| logger.info( | ||
| f"[{session_id}] [RecallShape] prompt_has={has_prompt}, prompt_len={prompt_len}, " | ||
| f"contexts_count={contexts_count}, event_text_len={event_text_len}, " | ||
| f"event_components={component_types}, image_hints={image_hints}, " |
There was a problem hiding this comment.
RecallShape 诊断日志使用 logger.info,并包含 extra_preview / tail_text_preview 等用户消息内容预览,可能在生产日志中泄露隐私数据。建议将这类包含用户内容的日志降级为 debug(或加显式开关/脱敏),并确保预览长度在任何 level 都可控。
| async def _resolve_conversation_session_id(self, event: AstrMessageEvent) -> str: | ||
| """ | ||
| 解析插件内部会话ID:unified_msg_origin + conversation_id。 | ||
| 回退策略:无法获取conversation_id时返回unified_msg_origin。 | ||
| """ | ||
| base_session_id = event.unified_msg_origin | ||
| if not self.context or not hasattr(self.context, "conversation_manager"): |
There was a problem hiding this comment.
conversation_id 解析逻辑在 EventHandler._build_conversation_session_id 与 CommandHandler._resolve_conversation_session_id 中重复实现,后续若拼接格式/回退策略调整容易出现行为不一致。建议抽到共享 helper(或集中定义拼接常量)并在两处复用。
| def _get_webui_urls(self) -> list[str]: | ||
| """获取 WebUI 可访问地址列表(优先可直连地址)""" | ||
| webui_config = self.config_manager.webui_settings | ||
| if not webui_config.get("enabled") or not self.webui_server: | ||
| return None | ||
| return [] |
There was a problem hiding this comment.
_get_webui_url 被替换为 _get_webui_urls 后,仓库内仍有调用点依赖旧方法(例如 tests/test_command_handler.py 里直接调用 _get_webui_url),会导致测试/CI 失败。建议保留一个 _get_webui_url() 薄封装(返回第一个可用地址或 None)或同步更新所有调用点。
📋 变更概览
✨ 新增功能
1. 会话级隔离(conversation_id 集成)
_build_conversation_session_id()方法,将unified_msg_origin与 AstrBot 的conversation_id组合/new命令切换对话时自动隔离待总结窗口2. Pending 管理命令
新增两个管理员命令,方便用户管理待总结内容:
/lmem pending [数量]/lmem pending-del <序号>3. 图片转述内容的召回与总结支持
新增了对于图片转述内容的记忆召回支持和记忆总结支持
_extract_image_caption()提取图片描述标签_patch_recent_group_image_message()为群聊图片消息补写描述_resolve_current_turn_input_from_request()严格模式提取当前轮输入_build_image_turn_recall_query()构建图片轮次召回查询session_manager.capture_image_caption控制是否启用4. 空闲自动总结
新增了当会话在指定时间内无新消息时,自动归纳当前未总结的对话内容的功能
run_idle_summary_check()空闲会话扫描功能reflection_engine.enable_idle_auto_summary- 是否启用(默认关闭)reflection_engine.idle_summary_timeout_seconds- 超时时间(默认 1800 秒)5. 记忆注入带时间
recall_engine.include_memory_time6. 总结任务防丢失机制
_sessions_summarizing和_sessions_summary_rerun_requested集合🐛 Bug 修复
1. 初始化流程改进
_bind_runtime_handlers()幂等绑定处理器2. WebUI 句柄同步
/lmem webui误判未启用的问题🗑️ 精简内容
1. 删除冗余的 sparse_retriever.py
core/retrieval/sparse_retriever.py(514 行)bm25_retriever.py功能重复,且未被任何模块引用sparse_retriever和dense_retriever2. 精简 ConversationManager 无用代码
移除以下从未被调用的冗余代码:
_cache,_cache_lock)_update_cache,_get_from_cache,invalidate_cache,_evict_cache)cleanup_expired_sessions()方法max_cache_size,context_window_size,session_ttl)3. 精简废弃配置项
移除以下不再使用的配置:
session_manager.max_sessionssession_manager.session_ttlsession_manager.context_window_size🧪 测试建议
我在私聊场景下测试了很多条聊天,没有出现什么 bug,但是没有做群聊场景下的测试,所以没法保证群聊场景下正常