feat(desktop): merge desktop_sessions.json on memory import
Import now also merges the source's temp/desktop_sessions.json into the current session list (dedup by id), updating both memory and the on-disk file so past desktop chats reappear in the sidebar immediately. - manager.import_sessions(): id-dedup merge, in-memory + persist - import handler returns sessionsAdded/sessionsSkipped - frontend shows session count in toast and reloads the sidebar
This commit is contained in:
1 parent
ec44d69bfe
commit
aff6560440
3 files changed
+51
-1
No files matched your search
@@ -461,6 +461,7 @@ const I18N = {
|
||||
'sys.memoryImported': '记忆已导入',
|
||||
'err.memoryImport': '导入记忆失败',
|
||||
'sys.memoryImportBackup': '原记忆已备份至',
|
||||
'sys.memorySessions': '会话',
|
||||
'sys.memoryPickTitle': '选择 GenericAgent 根目录(包含 memory 与 temp 的目录)',
|
||||
'sys.memoryImportPrompt': '请输入 GenericAgent 根目录的完整路径(包含 memory 与 temp 的目录,而非 memory 文件夹本身):',
|
||||
'sys.mykeyExported': '模型配置已导出',
|
||||
@@ -639,6 +640,7 @@ const I18N = {
|
||||
'sys.memoryImported': 'Memory imported',
|
||||
'err.memoryImport': 'Failed to import memory',
|
||||
'sys.memoryImportBackup': 'Previous memory backed up to',
|
||||
'sys.memorySessions': 'sessions',
|
||||
'sys.memoryPickTitle': 'Select the GenericAgent root directory (the folder containing memory and temp)',
|
||||
'sys.memoryImportPrompt': 'Enter the full path of the GenericAgent root directory (the folder containing memory and temp, not the memory folder itself):',
|
||||
'sys.mykeyExported': 'Model config exported',
|
||||
@@ -1030,7 +1032,11 @@ async function importMemoryFromDir() {
|
||||
if (!res || res.ok === false) throw new Error((res && res.error) || 'import failed');
|
||||
const detail = `memory: ${res.memoryCopied}, model_responses: ${res.responsesCopied}`
|
||||
+ (res.responsesSkipped ? ` (skip ${res.responsesSkipped})` : '')
|
||||
+ `, ${t('sys.memorySessions')}: ${res.sessionsAdded || 0}`
|
||||
+ (res.backupDir ? `\n${t('sys.memoryImportBackup')}: ${res.backupDir}` : '');
|
||||
if (res.sessionsAdded) {
|
||||
try { await loadSessions(); } catch (_) {}
|
||||
}
|
||||
showChanToast(t('sys.memoryImported'), detail, 'ok');
|
||||
}
|
||||
bindClick('import-memory-btn', async (e) => {
|
||||
|
||||
@@ -678,6 +678,6 @@
|
||||
<!-- highlight.js -->
|
||||
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/highlight.min.js" crossorigin="anonymous"></script>
|
||||
<script src="phosphor-icons.js?v=2"></script>
|
||||
<script src="app.js?v=210"></script>
|
||||
<script src="app.js?v=211"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -188,6 +188,49 @@ class AgentManager:
|
||||
except Exception as e:
|
||||
print(f"[bridge] load sessions failed: {e}", file=sys.stderr)
|
||||
|
||||
def import_sessions(self, source_dir: str) -> dict:
|
||||
"""把 source_dir/temp/desktop_sessions.json 合并进当前会话列表(按 id 去重)。
|
||||
|
||||
既更新内存(立即在侧边栏可见)又落盘。返回新增/跳过计数。
|
||||
"""
|
||||
src = Path(source_dir).expanduser().resolve()
|
||||
src_file = src / "temp" / "desktop_sessions.json"
|
||||
if not src_file.is_file():
|
||||
return {"sessionsAdded": 0, "sessionsSkipped": 0, "sessionsFileFound": False}
|
||||
try:
|
||||
arr = json.loads(src_file.read_text(encoding="utf-8"))
|
||||
if not isinstance(arr, list):
|
||||
raise ValueError("desktop_sessions.json is not a list")
|
||||
except Exception as e:
|
||||
raise ValueError(f"cannot read desktop_sessions.json: {e}")
|
||||
added = 0
|
||||
skipped = 0
|
||||
with self.lock:
|
||||
for item in arr:
|
||||
sid = item.get("id")
|
||||
if not sid or sid in self.sessions:
|
||||
skipped += 1
|
||||
continue
|
||||
msgs = item.get("messages", [])
|
||||
sess = Session(id=sid, title=item.get("title", "New chat"),
|
||||
cwd=item.get("cwd", self.ga_root),
|
||||
created_at=item.get("created_at", time.time()),
|
||||
updated_at=item.get("updated_at", time.time()),
|
||||
messages=msgs,
|
||||
msg_seq=item.get("msg_seq", 0),
|
||||
pinned=item.get("pinned", False),
|
||||
untitled=item.get("untitled", True),
|
||||
plan_scan_baseline=_load_plan_baseline(item, msgs),
|
||||
plan_path=_sanitize_desktop_plan_path(sid, item.get("plan_path") or ""),
|
||||
status="idle", agent=None,
|
||||
llm_history=item.get("llm_history"),
|
||||
llm_no=item.get("llm_no"))
|
||||
self.sessions[sid] = sess
|
||||
added += 1
|
||||
if added:
|
||||
self._persist()
|
||||
return {"sessionsAdded": added, "sessionsSkipped": skipped, "sessionsFileFound": True}
|
||||
|
||||
def _mykey_file(self) -> Path:
|
||||
p = Path(self.ga_root) / "mykey.py"
|
||||
if not p.exists():
|
||||
@@ -1812,6 +1855,7 @@ async def memory_import_handler(request):
|
||||
return json_ok({"ok": False, "error": "missing_sourceDir"}, status=400)
|
||||
try:
|
||||
result = _import_memory_from(source_dir, manager.ga_root)
|
||||
result.update(manager.import_sessions(source_dir))
|
||||
except Exception as e:
|
||||
return json_ok({"ok": False, "error": str(e)}, status=400)
|
||||
return json_ok(result)
|
||||
|
||||
Reference in new issue
Block a user