更新bug

This commit is contained in:
Your Name
2026-07-31 11:48:16 +08:00
parent f913a57529
commit f22cc1a70d
109 changed files with 37586 additions and 927 deletions
+110
View File
@@ -14,6 +14,7 @@ import json
import os
import time
import threading
import copy
# 每个会话最多留存的消息条数(防止档案无限膨胀;AI 实际使用条数由 AI_CONTEXT_MAX_ROUNDS 决定)
MAX_MESSAGES_PER_SESSION = 200
@@ -95,6 +96,47 @@ class ConversationStore:
e["history"] = e["history"][-MAX_MESSAGES_PER_SESSION:]
e["updated"] = time.time()
def append_exchange_once(
self,
fp_hex: str,
user_text: str,
assistant_text: str,
exchange_id: str,
) -> bool:
"""Atomically append one user/assistant pair once across crash recovery."""
key = str(fp_hex or "")
txid = str(exchange_id or "")
if not key or not txid:
return False
self._maybe_reload()
appended = False
with self._lock:
entry = self._data.setdefault(key, {
"history": [],
"last_lines": [],
"updated": 0,
})
committed = entry.setdefault("exchange_ids", [])
if txid not in committed:
now = time.time()
entry["history"].extend([
{"role": "user", "content": str(user_text or ""), "ts": now},
{
"role": "assistant",
"content": str(assistant_text or ""),
"ts": now,
},
])
if len(entry["history"]) > MAX_MESSAGES_PER_SESSION:
entry["history"] = entry["history"][-MAX_MESSAGES_PER_SESSION:]
committed.append(txid)
entry["exchange_ids"] = committed[-MAX_MESSAGES_PER_SESSION:]
entry["updated"] = now
appended = True
if appended:
self.save()
return appended
def last_lines(self, fp_hex: str) -> list:
return self._entry(fp_hex)["last_lines"]
@@ -103,6 +145,34 @@ class ConversationStore:
e["last_lines"] = list(lines)[-MAX_SNAPSHOT_LINES:]
e["updated"] = time.time()
def outgoing_speakers(self, fp_hex: str) -> list[str]:
"""Return sender labels previously proven by right-side bubble geometry."""
entry = self._entry(fp_hex)
return [
str(value).strip()
for value in entry.get("outgoing_speakers") or []
if str(value).strip()
]
def add_outgoing_speaker(self, fp_hex: str, speaker: str) -> bool:
"""Persist one visually proven local sender label for this conversation."""
name = str(speaker or "").strip()
if not name:
return False
entry = self._entry(fp_hex)
known = {
str(value).strip()
for value in entry.get("outgoing_speakers") or []
if str(value).strip()
}
if name in known:
return False
known.add(name)
entry["outgoing_speakers"] = sorted(known)
entry["updated"] = time.time()
self.save()
return True
def list_sessions(self, limit: int = 200) -> list:
"""按最近更新排序,返回会话摘要列表。"""
self._maybe_reload()
@@ -139,6 +209,46 @@ class ConversationStore:
self.save()
return True
def migrate_key(self, old_fp_hex: str, new_fp_hex: str) -> bool:
"""Atomically move one legacy session entry to a stronger identity key."""
old_key = str(old_fp_hex or "")
new_key = str(new_fp_hex or "")
if not old_key or not new_key or old_key == new_key:
return False
self._maybe_reload()
migrated = False
with self._lock:
current = self._data.get(new_key)
current_is_empty_shell = bool(
isinstance(current, dict)
and not current.get("history")
and not current.get("last_lines")
and not current.get("exchange_ids")
)
if old_key in self._data and (
new_key not in self._data or current_is_empty_shell
):
if current_is_empty_shell:
self._data.pop(new_key, None)
self._data[new_key] = self._data.pop(old_key)
migrated = True
if migrated:
self.save()
return migrated
def entry_snapshot(self, fp_hex: str) -> dict | None:
"""Return a detached legacy entry for identity checks without creating it."""
self._maybe_reload()
entry = self._data.get(str(fp_hex or ""))
if not isinstance(entry, dict):
return None
return copy.deepcopy(entry)
def keys(self) -> list[str]:
"""Return a detached list of stored session keys without exposing live data."""
self._maybe_reload()
return [str(key) for key in (self._data or {}).keys()]
def clear_all(self) -> int:
"""清空全部会话档案,返回删除条数。"""
self._maybe_reload()