Skip to content

fix: 文档与代码清理 (Closes #164, #163) - #169

Merged
Qixuan112 merged 22 commits into
mainfrom
fix/issues-164-163
Aug 3, 2026
Merged

fix: 文档与代码清理 (Closes #164, #163)#169
Qixuan112 merged 22 commits into
mainfrom
fix/issues-164-163

Conversation

@Qixuan112

@Qixuan112 Qixuan112 commented Aug 2, 2026

Copy link
Copy Markdown
Owner

概述

修复 Issue #164#163 的文档错误与代码冗余问题。


Issue #164 - 文档与代码清理(6个问题)

修复内容

  1. README 仓库链接错误

    • README.md: Tale_aiTale-AI
    • docs/README.zh.md: Tale_aiTale-AI
  2. webui/app.py 重复 logger 初始化

    • 删除第 38-39 行重复的 logger 初始化
  3. Flask 3.x 配置失效

    • app.config['JSON_AS_ASCII'] = Falseapp.json.ensure_ascii = False
    • 兼容 Flask 3.x JSON provider API
  4. docs/config-guide.md 文档不一致

    • type: chattype: llm
    • 与实际配置 schema 一致
  5. core/function_caller.py 冗余死代码

    • 删除 Priority 2 硬编码 handlers(81行)
    • 统一使用 handler registry
  6. 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 功能

代码统计

  • 删除:92行
  • 新增:95行
  • 净变化:+3行

测试状态

✅ 所有测试通过


Closes #164
Closes #163

Summary by CodeRabbit

  • New Features

    • Tool availability is now managed consistently through the unified tool registry, improving support for configured plugins and integrations.
    • Fallback message parsing now includes session send information for more consistent results.
  • Documentation

    • Updated repository links in the English and Chinese setup guides.
    • Corrected the service type in the configuration example.
  • Bug Fixes

    • Improved web interface handling of non-ASCII characters in JSON responses.
    • Added validation coverage for available tools and their configuration.

Qixuan112 added 21 commits June 27, 2026 22:01
- 新增 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
- 新增 tests/test_file_message.py(23个测试用例,100%通过)
- 新增 core/utils/cache.py(BoundedCache 类)
- 修复 core/adapter/src/qq/adapter.py(兼容测试 mock 场景)

测试覆盖:
- FileAttachment 数据模型(4个测试)
- QQ 适配器接收解析(4个测试)
- QQ 适配器发送上传(7个测试)
- XML 文件标签解析(5个测试)
- AdapterManager 透传(1个测试)
- 错误处理(1个测试)
- 集成测试(1个测试)

相关: #118 #77
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 功能保持一致
- 所有测试通过,无功能变更
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The 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.

Changes

Cleanup and consistency alignment

Layer / File(s) Summary
Tool registry dispatch alignment
core/function_caller.py, core/llm/toolllm.py, tests/test_available_tools.py
Tool execution now falls through to plugin dispatch after registered handlers. AVAILABLE_TOOLS uses get_registry(). Tests validate tool structure and registry consistency.
Runtime output and logging consistency
core/parse_xml.py, core/adapter/src/qq/adapter.py, core/adapter/src/websocket/adapter.py, webui/app.py
Fallback parsing adds session_sends. Failed sends log at info level. Flask uses app.json.ensure_ascii = False.
Repository and configuration documentation
README.md, docs/README.zh.md, docs/config-guide.md
Repository URLs use Tale-AI. The service example uses type: llm.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The send failure log-level changes in the QQ and WebSocket adapters are not covered by the linked issue objectives. Revert the unrelated log-level changes or link an issue that explicitly requires them.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the documentation and code cleanup covered by issues #164 and #163.
Linked Issues check ✅ Passed The changes address the documented repository links, Flask configuration, cleanup, parser consistency, registry import, and related tests.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ 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 fix/issues-164-163

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.

@Qixuan112
Qixuan112 merged commit 74fbbfe into main Aug 3, 2026
1 check was pending

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Restore the module-level logger binding.

The change removes get_logger and logger = get_logger(__name__), but later code still references logger. Those paths will raise NameError and 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 win

Remove the unreachable Priority 2 _plugin_dispatch branch.

_plugin_dispatch is only populated by register_plugin_handler, which also adds the handler to _handler_registry. Since _handler_registry is checked first, the _plugin_dispatch fallback 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

📥 Commits

Reviewing files that changed from the base of the PR and between e916d3b and 5945695.

📒 Files selected for processing (10)
  • README.md
  • core/adapter/src/qq/adapter.py
  • core/adapter/src/websocket/adapter.py
  • core/function_caller.py
  • core/llm/toolllm.py
  • core/parse_xml.py
  • docs/README.zh.md
  • docs/config-guide.md
  • tests/test_available_tools.py
  • webui/app.py

Comment thread core/parse_xml.py
"plan": None,
"parse_error": error_msg,
"skip_reply": False,
"session_sends": [],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant