release: v8.0.4 — 会话 SQLite 存储 + 去加载动画 + 展示截断 + 工具调用解析加固

- 会话数据改用 SQLite(chat_history/conversations.db,WAL):sessions / snapshots 两表,
  首次启动自动迁移旧 JSON,/chat 与 /resume 改走 SQLite,memory 搜索兼容数据库
- 去掉流式显示(_typeprint 改整段打印)与常驻加载动画(移除 show_animation 线程及逐帧输出)
- 展示给用户的消息过长自动截断(仅展示层,底层 messages 完整保存)
- 工具调用解析加固:_loads_json 四级兜底修复;新增 _extract_last_action_json 成对错括号扫描;
  续轮也下发 Function Calling 工具,减少长文本格式错误浪费 token
- 版本号统一更新至 8.0.4(README/about.txt/constants/TUI banner/LSP·MCP clientInfo)
- 12 项 session 单测 + 8 项 JSON 提取边界用例全部通过

Co-Authored-By: WorkBuddy <workbuddy@tencent.com>
This commit is contained in:
shuiyu67andWorkBuddy committed 2026-08-08 00:54:18 +08:00
1 parent 66de8eea13
commit 749fb3f91c
15 files changed
+510 -249

No files matched your search

+22 -24
View File
@@ -9,17 +9,17 @@ class HistoryMixin:
"""聊天记录管理相关方法(含 opencode 式会话持久化 /resume)"""
def save_chat_history(self, name):
"""保存当前聊天记录到文件"""
"""保存当前聊天记录(SQLite 快照)"""
try:
chat_data = {
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"conversation": self.shared_conversation_history.copy()
}
file_path = os.path.join(self.chat_history_dir, f"{name}.json")
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(chat_data, f, ensure_ascii=False, indent=2, default=str)
print(f"{Fore.GREEN}聊天记录已保存为: {name}{Style.RESET_ALL}")
return True
if not hasattr(self, 'session_manager'):
self.init_session_manager()
ok = self.session_manager.save_snapshot(
name, self.shared_conversation_history.copy())
if ok:
print(f"{Fore.GREEN}聊天记录已保存为: {name}{Style.RESET_ALL}")
return True
print(f"{Fore.RED}保存聊天记录失败{Style.RESET_ALL}")
return False
except Exception as e:
print(f"{Fore.RED}保存聊天记录失败: {e}{Style.RESET_ALL}")
return False
@@ -27,30 +27,28 @@ class HistoryMixin:
def list_chat_history(self):
"""列出所有已保存的聊天记录"""
try:
chat_files = [f for f in os.listdir(self.chat_history_dir) if f.endswith('.json')]
if not chat_files:
if not hasattr(self, 'session_manager'):
self.init_session_manager()
snaps = self.session_manager.list_snapshots()
if not snaps:
print(f"{Fore.YELLOW}没有已保存的聊天记录{Style.RESET_ALL}")
return
print(f"{Fore.GREEN}已保存的聊天记录:{Style.RESET_ALL}")
for i, file in enumerate(chat_files, 1):
file_path = os.path.join(self.chat_history_dir, file)
mod_time = os.path.getmtime(file_path)
mod_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(mod_time))
chat_name = file[:-5]
print(f"{Fore.GREEN}{i}. {chat_name} (保存时间: {mod_time_str}){Style.RESET_ALL}")
for i, (chat_name, saved_at) in enumerate(snaps, 1):
print(f"{Fore.GREEN}{i}. {chat_name} (保存时间: {saved_at}){Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}列出聊天记录失败: {e}{Style.RESET_ALL}")
def load_chat_history(self, name):
"""加载指定的聊天记录"""
"""加载指定的聊天记录(SQLite 快照)"""
try:
file_path = os.path.join(self.chat_history_dir, f"{name}.json")
if not os.path.exists(file_path):
if not hasattr(self, 'session_manager'):
self.init_session_manager()
msgs = self.session_manager.load_snapshot(name)
if msgs is None:
print(f"{Fore.RED}聊天记录 '{name}' 不存在{Style.RESET_ALL}")
return False
with open(file_path, 'r', encoding='utf-8') as f:
chat_data = json.load(f)
self.shared_conversation_history = chat_data.get("conversation", [])
self.shared_conversation_history = list(msgs)
self._set_shared_conversation_history()
print(f"{Fore.GREEN}已加载聊天记录: {name}{Style.RESET_ALL}")
if self.shared_conversation_history: