fix: 文档与代码清理 (Closes #164, #163) - #169
Conversation
- 新增 FileAttachment dataclass,扩展 MessageContent.files 字段 - QQ适配器接收端解析 OneBot file segment - QQ适配器发送端通过 upload_group_file/upload_private_file API 上传文件 - 新增 _normalize_file() 处理 URL/base64/本地路径 - XML解析支持 <file name= url= path=> 标签 - 文件发送失败时日志记录并通知AI - AdapterManager/AdapterBridge 透传 files 参数 feat: QQ adapter file message support (#77) - Add FileAttachment dataclass, extend MessageContent.files field - QQ adapter: parse OneBot file segment on receive - QQ adapter: upload files via upload_group_file/upload_private_file API - Add _normalize_file() for URL/base64/local path handling - XML parser: support <file name= url= path=> tag - Log and notify AI on file upload failure - Pass files through AdapterManager/AdapterBridge
- FileAttachment 新增 path 字段,支持本地文件路径发送 - _reconstruct_platform_event 补充 files 重建,接收端不再丢失文件 - _store_to_context_buffer 支持纯文件消息入上下文 - respond 路径追加文件信息到 extra_media,LLM 可感知收到的文件 - QQ adapter: 空 message_segments 时跳过消息 API,直接上传文件 - QQ adapter: 上传改用 _call_action 检查 status,避免成功误判为失败 - QQ adapter: 文件发送优先使用 path 字段(file → url → path → name) - manager.py: adapter 解析失败返回 dict 而非裸 False - ProcessedMessage.to_dict() 补充 files 序列化 - QQ adapter: FileAttachment.name 优先取 data.name fix: address 7 CodeRabbit review issues - FileAttachment: add path field for local file support - _reconstruct_platform_event: carry files through reconstruction - _store_to_context_buffer: allow file-only messages - respond path: add file info to extra_media for LLM context - QQ adapter: skip message API when segments empty, upload files directly - QQ adapter: use _call_action + status check for upload success detection - QQ adapter: prefer path field for file source resolution - manager.py: return dict on adapter resolution failure - ProcessedMessage.to_dict(): include files serialization - QQ adapter: FileAttachment.name uses data.name first
- 上传 API 增加 retcode 检查,避免非零 retcode 被误判成功 - _send_reply 返回 failed_files,_send_message_batch 收集后注入 AI 上下文 - _notify_file_upload_failure 将失败信息写入上下文缓冲区供 AI 感知 - manager.py send_message 返回类型签名改为 Dict[str, Any] fix: address CodeRabbit round 2 review - Upload API: add retcode check alongside status check - _send_reply returns failed_files; batch collects and notifies AI via context - _notify_file_upload_failure writes failure info to context buffer - manager.py send_message return type: bool -> Dict[str, Any]
句间停顿的 3 行代码(956-958)在编辑时被错误地留在了 _notify_file_upload_failure 方法定义之后,导致 IndentationError, 整个 bot 无法启动。 Co-Authored-By: Claude Opus 4.8 (1M context)
- 删除 adapter.py 中重复的 is_group 取值(已在 442 行获取) - 修正 _build_context_window 中纯文件消息被误标为 [图片] - 修复 _notify_file_upload_failure 写入 buffer 末尾却被 [:-1] 跳过的问题, 改为插入到当前消息之前 Co-Authored-By: Claude Opus 4.8 (1M context)
当 persistence_enabled=True 时,_store_to_context_buffer 直接返回、 _build_context_window 被跳过,_chat_context_buffer 中的失败通知 不会被 AI 读取。现在通过 SessionManager.append_memory 写入持久化 会话记忆,下次 set_session 时 AI 能感知到。 Co-Authored-By: Claude Opus 4.8 (1M context)
WebSocket 检查前构造的第一份 api_action/params 从未被使用, if message_segments: 分支内会原样重建。fixes #128
WS 未连接/无响应/status!=ok/异常四条失败路径此前都返回 failed_files=[],附带文件从未尝试上传也不报失败, 文件失败通知永远不会触发。fixes #119
此前文件上传循环结束后无条件返回 success=True, 零送达也会被记录为发送成功。fixes #121
- manager.send_message 先解析 files 再解析 adapter, 无可用适配器与异常路径都返回全部待发文件名 - _send_reply 异常路径返回 files 参数中的文件名 此前这些路径返回空列表,文件失败通知永不触发。fixes #122
websocket/wechat_pc 适配器忽略 content.files 只返回 True, 此前 manager 包装为 success=True + failed_files=[], 文件静默丢弃且无任何告警。现在记 warning 并上报失败, 让 AI 能收到文件未送达通知。fixes #120
persistence_enabled 时 use_ctx 恒为 False,_build_context_window 不会被调用,且 100 条截断只在 _store_to_context_buffer 里执行 (持久化时早退)——此前通知条目只写不读、无上限累积。 现与 _store_to_context_buffer 用相同判定跳过缓冲区写入, 并顺带去掉冗余的分支与函数内 import time。fixes #123
此前只在消息无文本时才渲染 [文件: ...],帮我看看这个文件+ 附件这类最常见组合在滑动窗口里完全丢失文件信息; 现改为平铺三分支,文本后追加文件名,与实时路径行为一致。fixes #125
正则从仅匹配自闭合 <file .../> 改为两种形式都接受, 与 _parse_root 行为一致;无 <text> 的最终回退分支 剥离已识别的 file 标记,避免原始标签文本发给用户。fixes #124
ChatLLM/PlanLLM/VLM/GenericLLM/ProviderManager 均已支持热更新, ToolLLM 是最后一个仍需重启才能生效的 Agent。与 ChatLLM 相同的 模式:重读 tool_llm 配置并重建 provider。fixes #56
- 新增 SendResult dataclass(event.py),带 __bool__ 避免非空 dict 真值陷阱 - 所有适配器 send_message 统一返回 SendResult,删除三层 isinstance 嗅探 - websocket/wechat_pc 不支持文件时正确计入 failed_files 并打 warning - QQ _normalize_file/_normalize_image_file 合并为 _normalize_local_path, 使用 asyncio.to_thread 异步读取,新增 50MB 上限防止阻塞事件循环 - 更新 BaseAdapter、Manager、Bridge 签名/注解/docstring,broadcast 返回 Dict[str, SendResult] Fixes #119 #120 #121 #122 #126 #127 #128
Resolved conflicts in core/main.py: - Line 452: Kept _reconstruct_platform_event method from PR #118 (file message support) - Line 766: Merged file attachment formatting - combined PR #118's file message functionality with main's structured formatting style Changes: - Preserved file message features (files field, FileAttachment handling, failed_files notification) - Adopted main branch's structured formatting (list-style with bullet points) - Files now displayed as '- 文件: X 个 (filename1, filename2)' matching main's style - All 23 file message tests passing
- Fix repository links: Tale_ai -> Tale-AI in README.md and docs/README.zh.md - Remove duplicate logger initialization in webui/app.py (lines 38-39) - Update Flask 3.x config: app.config['JSON_AS_ASCII'] -> app.json.ensure_ascii - Fix docs/config-guide.md: type: chat -> type: llm for consistency - Remove Priority 2 hardcoded handlers in core/function_caller.py (dead code) - Add session_sends field to _fallback_extract in core/parse_xml.py Closes #164
- 移除第 18 行使用 __import__ 动态导入 get_registry 的冗余代码 - 直接使用已在文件顶部(第 4 行)静态导入的 get_registry 函数 - 添加 test_available_tools.py 验证 AVAILABLE_TOOLS 功能保持一致 - 所有测试通过,无功能变更
📝 WalkthroughWalkthroughThe PR removes duplicate hardcoded tool handlers, uses the imported tool registry directly, aligns fallback parsing and Flask JSON settings, changes send-failure logging, and updates repository and configuration documentation. ChangesCleanup and consistency alignment
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related issues Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
webui/app.py (1)
37-38: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick winRestore the module-level
loggerbinding.The change removes
get_loggerandlogger = get_logger(__name__), but later code still referenceslogger. Those paths will raiseNameErrorand can fail request handling. Keep one logger initialization and remove only the duplicate initialization.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@webui/app.py` around lines 37 - 38, Restore the module-level logger binding in webui/app.py by importing and calling get_logger once to initialize logger, ensuring all existing logger references remain valid while removing any duplicate initialization.
🧹 Nitpick comments (1)
core/function_caller.py (1)
218-227: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRemove the unreachable Priority 2
_plugin_dispatchbranch.
_plugin_dispatchis only populated byregister_plugin_handler, which also adds the handler to_handler_registry. Since_handler_registryis checked first, the_plugin_dispatchfallback cannot be reached. Remove this branch and its duplicate comment/error handling to complete the migration cleanup.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/function_caller.py` around lines 218 - 227, Remove the unreachable Priority 2 _plugin_dispatch branch from the function dispatch logic, including its comment and exception handling. Preserve the existing _handler_registry path and the final unknown-function fallback in the surrounding function.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@core/parse_xml.py`:
- Line 145: Update parse_xml_msg so every return path, including empty-input
handling and XXE rejection, includes the session_sends field with the same
default value used by _fallback_extract. Preserve the existing result contents
and behavior for all other paths.
---
Outside diff comments:
In `@webui/app.py`:
- Around line 37-38: Restore the module-level logger binding in webui/app.py by
importing and calling get_logger once to initialize logger, ensuring all
existing logger references remain valid while removing any duplicate
initialization.
---
Nitpick comments:
In `@core/function_caller.py`:
- Around line 218-227: Remove the unreachable Priority 2 _plugin_dispatch branch
from the function dispatch logic, including its comment and exception handling.
Preserve the existing _handler_registry path and the final unknown-function
fallback in the surrounding function.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 96383962-6d12-470e-bb61-44531f2ab3f8
📒 Files selected for processing (10)
README.mdcore/adapter/src/qq/adapter.pycore/adapter/src/websocket/adapter.pycore/function_caller.pycore/llm/toolllm.pycore/parse_xml.pydocs/README.zh.mddocs/config-guide.mdtests/test_available_tools.pywebui/app.py
| "plan": None, | ||
| "parse_error": error_msg, | ||
| "skip_reply": False, | ||
| "session_sends": [], |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Add session_sends to every parser return path.
Line 145 fixes _fallback_extract, but parse_xml_msg still omits session_sends for empty input and XXE rejection returns. This leaves inconsistent result shapes. Add the field to those early returns or centralize result construction.
Proposed fix
- return {"messages": [], "action": None, "actions": [], "plan": None}
+ return {
+ "messages": [],
+ "action": None,
+ "actions": [],
+ "plan": None,
+ "session_sends": [],
+ }Apply the same field to the XXE rejection result.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/parse_xml.py` at line 145, Update parse_xml_msg so every return path,
including empty-input handling and XXE rejection, includes the session_sends
field with the same default value used by _fallback_extract. Preserve the
existing result contents and behavior for all other paths.
概述
修复 Issue #164 和 #163 的文档错误与代码冗余问题。
Issue #164 - 文档与代码清理(6个问题)
修复内容
README 仓库链接错误 ✅
README.md:Tale_ai→Tale-AIdocs/README.zh.md:Tale_ai→Tale-AIwebui/app.py 重复 logger 初始化 ✅
Flask 3.x 配置失效 ✅
app.config['JSON_AS_ASCII'] = False→app.json.ensure_ascii = Falsedocs/config-guide.md 文档不一致 ✅
type: chat→type: llmcore/function_caller.py 冗余死代码 ✅
core/parse_xml.py 降级路径结构不一致 ✅
_fallback_extract补充"session_sends": []_parse_root结构对齐Issue #163 - 代码冗余清理
修复内容
__import__动态导入 ✅core/llm/toolllm.py: 使用已导入的get_registry()替代__import__(...)新增测试
tests/test_available_tools.py: 4个单元测试验证 AVAILABLE_TOOLS 功能代码统计
测试状态
✅ 所有测试通过
Closes #164
Closes #163
Summary by CodeRabbit
New Features
Documentation
Bug Fixes