feat(memory): 记忆 P2(项目索引物化 / decay 回写 / 作用域写规则 / 静默吞点 + loop 级只读红线测试)
This commit is contained in:
1 parent
9b903a89bc
commit
509dc412eb
12 files changed
+660
-55
No files matched your search
@@ -42,6 +42,7 @@ import (
|
||||
"time"
|
||||
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/logger"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/memory/projectindex"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/memory/vector"
|
||||
)
|
||||
|
||||
@@ -153,6 +154,13 @@ type Store struct {
|
||||
// nil 表示没有配置持久索引,检索据此回退到内存余弦。
|
||||
vecMu sync.RWMutex
|
||||
vec vector.Index
|
||||
|
||||
// projMu 保护 proj,使项目索引存储能在装配后并发接入,而写入路径
|
||||
// 每写一条项目作用域记忆就确保它链接的项目索引条目存在(见
|
||||
// ensureProjectIndex)。proj 为 nil 表示未接入项目索引,此时写入
|
||||
// 不触碰项目索引(design §3 项目记忆链接项目索引)。
|
||||
projMu sync.RWMutex
|
||||
proj *projectindex.Store
|
||||
}
|
||||
|
||||
// rowScanner 同时被 *sql.Row 与 *sql.Rows 满足,因此单个 scanItem
|
||||
@@ -230,6 +238,7 @@ func (s *Store) Add(ctx context.Context, item MemoryItem) (MemoryItem, error) {
|
||||
return MemoryItem{}, fmt.Errorf("memory: insert item: %w", err)
|
||||
}
|
||||
s.indexItem(ctx, item)
|
||||
s.ensureProjectIndex(ctx, item)
|
||||
return item, nil
|
||||
}
|
||||
|
||||
@@ -459,39 +468,4 @@ func discardLogger(log *slog.Logger) *slog.Logger {
|
||||
return slog.New(slog.NewTextHandler(io.Discard, nil))
|
||||
}
|
||||
|
||||
// schema DDL。internal/db 中的迁移框架是领域表的权威
|
||||
// 机制,但这里刻意不用它:db 包的迁移测试断言精确的
|
||||
// 迁移数量,而记忆存储必须自包含、
|
||||
// 可在任意 *sql.DB 上使用。表与索引因此
|
||||
// 由 NewStore 幂等创建。
|
||||
const createMemoryItemsTable = `
|
||||
CREATE TABLE IF NOT EXISTS memory_items (
|
||||
id TEXT PRIMARY KEY,
|
||||
persona_id TEXT NOT NULL,
|
||||
role_id TEXT NOT NULL DEFAULT '',
|
||||
project_id TEXT NOT NULL DEFAULT '',
|
||||
scope TEXT NOT NULL,
|
||||
kind TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
tags TEXT NOT NULL DEFAULT '[]',
|
||||
confidence REAL NOT NULL DEFAULT 1.0,
|
||||
source_conversation TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL,
|
||||
decay_weight REAL NOT NULL DEFAULT 1.0,
|
||||
status TEXT NOT NULL DEFAULT 'active',
|
||||
merged_into TEXT NOT NULL DEFAULT '',
|
||||
merged_from TEXT NOT NULL DEFAULT '[]',
|
||||
merge_count INTEGER NOT NULL DEFAULT 1,
|
||||
occurred_at TEXT NOT NULL DEFAULT '',
|
||||
valid_to TEXT NOT NULL DEFAULT '',
|
||||
expires_at TEXT NOT NULL DEFAULT ''
|
||||
)`
|
||||
|
||||
const createMemoryItemsPersonaIndex = `
|
||||
CREATE INDEX IF NOT EXISTS idx_memory_items_persona_id
|
||||
ON memory_items (persona_id)`
|
||||
|
||||
const createMemoryItemsPersonaCreatedIndex = `
|
||||
CREATE INDEX IF NOT EXISTS idx_memory_items_persona_id_created_at
|
||||
ON memory_items (persona_id, created_at)`
|
||||
Reference in new issue
Block a user