v0.13.0: 记忆系统重构 — MEMORY.md 文件化 + 路径保护 + 自动提取优化
核心变更: - 删除 SQLite memories 表 + FTS5 + IVF 向量存储引擎 (~1300行) - 4 个记忆工具合并为 1 个 memory 工具 (5 action) - 记忆存储改为工作空间 MEMORY.md 单文件,严格格式校验 - 路径保护: checkPathAllowed 拦截所有工具,仅 memory 专用 IPC 通道可访问 - 应用启动/工作空间切换时自动校验并初始化 MEMORY.md(格式错误自动备份重建) - 自动记忆提取重建: 对话结束时触发,多层质量过滤(内容/泛化/去重/安全/importance门槛) - 工具总数: 42→40,UI 全面更新(帮助面板、工具面板、设置面板、README) - 版本号更新: 0.12.11 → 0.13.0
This commit is contained in:
+1
-137
@@ -3,7 +3,7 @@
|
||||
* v4.0: 桌面端走 IPC → SQLite,Web 端仍用 IndexedDB
|
||||
*/
|
||||
|
||||
import type { ChatSession, MemoryEntry } from '../types.js';
|
||||
import type { ChatSession } from '../types.js';
|
||||
|
||||
/** 检查是否在桌面环境 */
|
||||
function isDesktop(): boolean {
|
||||
@@ -217,89 +217,8 @@ export class ChatDB {
|
||||
return this._idbGetSetting(key, defaultValue);
|
||||
}
|
||||
|
||||
// ── Memories ──
|
||||
|
||||
async saveMemory(entry: MemoryEntry): Promise<string> {
|
||||
if (isDesktop()) {
|
||||
const row = {
|
||||
id: entry.id,
|
||||
type: entry.type,
|
||||
content: entry.content,
|
||||
importance: entry.importance,
|
||||
tags: entry.tags?.length ? JSON.stringify(entry.tags) : null,
|
||||
source: entry.source || null,
|
||||
session_id: entry.sessionId || null,
|
||||
use_count: entry.useCount,
|
||||
embedding: entry.embedding ? JSON.stringify(entry.embedding) : null,
|
||||
created_at: entry.createdAt,
|
||||
updated_at: entry.updatedAt,
|
||||
last_used_at: entry.lastUsedAt
|
||||
};
|
||||
await dbBridge().saveMemory(row);
|
||||
return entry.id;
|
||||
}
|
||||
return this._idbSaveMemory(entry);
|
||||
}
|
||||
|
||||
async getMemory(id: string): Promise<MemoryEntry | null> {
|
||||
if (isDesktop()) {
|
||||
const row = await dbBridge().getMemory(id);
|
||||
return row ? this._rowToMemory(row) : null;
|
||||
}
|
||||
return this._idbGetMemory(id);
|
||||
}
|
||||
|
||||
async getAllMemories(): Promise<MemoryEntry[]> {
|
||||
if (isDesktop()) {
|
||||
const rows = await dbBridge().getAllMemories();
|
||||
return rows.map((r: any) => this._rowToMemory(r));
|
||||
}
|
||||
return this._idbGetAllMemories();
|
||||
}
|
||||
|
||||
async getMemoriesByType(type: string): Promise<MemoryEntry[]> {
|
||||
if (isDesktop()) {
|
||||
const rows = await dbBridge().getMemoriesByType(type);
|
||||
return rows.map((r: any) => this._rowToMemory(r));
|
||||
}
|
||||
return this._idbGetMemoriesByType(type);
|
||||
}
|
||||
|
||||
async deleteMemory(id: string): Promise<void> {
|
||||
if (isDesktop()) {
|
||||
await dbBridge().deleteMemory(id);
|
||||
return;
|
||||
}
|
||||
return this._idbDeleteMemory(id);
|
||||
}
|
||||
|
||||
async clearAllMemories(): Promise<void> {
|
||||
if (isDesktop()) {
|
||||
await dbBridge().clearAllMemories();
|
||||
return;
|
||||
}
|
||||
return this._idbClearAllMemories();
|
||||
}
|
||||
|
||||
// ── Helpers ──
|
||||
|
||||
private _rowToMemory(row: any): MemoryEntry {
|
||||
return {
|
||||
id: row.id,
|
||||
type: row.type,
|
||||
content: row.content,
|
||||
importance: row.importance,
|
||||
tags: row.tags ? JSON.parse(row.tags) : [],
|
||||
source: row.source || undefined,
|
||||
sessionId: row.session_id || undefined,
|
||||
useCount: row.use_count,
|
||||
embedding: row.embedding ? JSON.parse(row.embedding) : undefined,
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at,
|
||||
lastUsedAt: row.last_used_at
|
||||
};
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// IndexedDB fallback methods (Web 端兼容)
|
||||
// ═══════════════════════════════════════════
|
||||
@@ -393,61 +312,6 @@ export class ChatDB {
|
||||
});
|
||||
}
|
||||
|
||||
private async _idbSaveMemory(entry: MemoryEntry): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const store = this._idbTx('memories', 'readwrite');
|
||||
const req = store.put(entry);
|
||||
req.onsuccess = () => resolve(entry.id);
|
||||
req.onerror = () => reject(req.error);
|
||||
});
|
||||
}
|
||||
|
||||
private async _idbGetMemory(id: string): Promise<MemoryEntry | null> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const store = this._idbTx('memories');
|
||||
const req = store.get(id);
|
||||
req.onsuccess = () => resolve(req.result || null);
|
||||
req.onerror = () => reject(req.error);
|
||||
});
|
||||
}
|
||||
|
||||
private async _idbGetAllMemories(): Promise<MemoryEntry[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const store = this._idbTx('memories');
|
||||
const req = store.getAll();
|
||||
req.onsuccess = () => resolve(req.result || []);
|
||||
req.onerror = () => reject(req.error);
|
||||
});
|
||||
}
|
||||
|
||||
private async _idbGetMemoriesByType(type: string): Promise<MemoryEntry[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const store = this._idbTx('memories');
|
||||
const index = store.index('type');
|
||||
const req = index.getAll(type);
|
||||
req.onsuccess = () => resolve(req.result || []);
|
||||
req.onerror = () => reject(req.error);
|
||||
});
|
||||
}
|
||||
|
||||
private async _idbDeleteMemory(id: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const store = this._idbTx('memories', 'readwrite');
|
||||
const req = store.delete(id);
|
||||
req.onsuccess = () => resolve();
|
||||
req.onerror = () => reject(req.error);
|
||||
});
|
||||
}
|
||||
|
||||
private async _idbClearAllMemories(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const store = this._idbTx('memories', 'readwrite');
|
||||
const req = store.clear();
|
||||
req.onsuccess = () => resolve();
|
||||
req.onerror = () => reject(req.error);
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取原始 IndexedDB 实例(用于数据迁移) */
|
||||
getRawIDB(): IDBDatabase | null {
|
||||
return this.idb;
|
||||
|
||||
Reference in New Issue
Block a user