mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-03 15:53:56 +00:00
refactor(memory): 移除 media_refs/引用计数,媒体成为一等记忆块
媒体此前是"文本块 + digest 引用 + owner 账本 + 独立 GC":ContextEvent.Media
记 digest,media_refs 表用 owner_kind/owner_id 保活,ref_count 决定 GC 能否清。
这与文本记忆块的管理方式不一致,也是本次一并纠正的核心偏差。
改为与文本块完全一致的生命周期:
1. 一等记忆块直接由所在层持有
- ContextEvent.Blocks / Doc.Blocks / GraphDB memory_blocks
- 块带 modality/digest/MIME/size/vector/fingerprint,文本、图片、视频同构
- Context→Document→Graph 迁移的是块本身(ID 不变),迁移后清空源容器,
同一块不同时存在于两层
2. 删除平行生命周期账本
- media.Store 去掉 media_refs 表、OwnerKind 常量、RefCount 字段、
AddRef/DropRef/DropOwner/Refs、ref_count 列与索引
- 删除 mediaGCLoop、GC(keep,minAge)、容量上限与 media.gc_* / media.max_mb 配置
- 媒体内容在块被永久删除时一并删除(media.Store.Delete + forgetPayloads),
与"删除文本块即删除内容"同一语义
3. L3 原生结构
- memory_blocks / memory_block_edges(contains/depicts/derived_from)
- 边端点必须是真实图节点,不再用 owner 字符串伪装关系
- BlocksForNode 支持 sentence --contains--> block 反查
4. SDK 与检索同步
- 插件附件/标记直接变成块,不再 AddRef
- 跨模态检索改用 QueryMediaScored(CAS 内不再有孤儿缓存需要过滤)
测试全部改写为块语义:删除 refcount/media_refs/GC 断言,新增块迁移、
单层不变量、Delete 语义与并发删除回归。
注:cmd/homed/main.go 同时携带工作区中既有的 CLIP→Qwen 模型目录接线改动。
This commit is contained in:
@ -217,3 +217,40 @@ func (g *GraphDB) MemoryBlockEdges() ([]MemoryBlockEdge, error) {
|
||||
}
|
||||
return edges, rows.Err()
|
||||
}
|
||||
|
||||
// BlocksForNode 返回与某个图节点通过任意边相连的一等记忆块。
|
||||
// 例:sentence --contains--> block;entity --depicts--> block。
|
||||
func (g *GraphDB) BlocksForNode(nodeKind, nodeID string) ([]MemoryBlock, error) {
|
||||
g.mu.RLock()
|
||||
defer g.mu.RUnlock()
|
||||
rows, err := g.db.Query(`SELECT b.id, b.modality, b.text_content, b.payload_digest,
|
||||
b.mime, b.size, b.width, b.height, b.vector, b.fingerprint, b.source, b.tool,
|
||||
b.created_at, b.updated_at
|
||||
FROM memory_block_edges e
|
||||
JOIN memory_blocks b ON (
|
||||
(e.source_kind = 'block' AND e.source_id = b.id AND e.target_kind = ? AND e.target_id = ?)
|
||||
OR (e.target_kind = 'block' AND e.target_id = b.id AND e.source_kind = ? AND e.source_id = ?))
|
||||
ORDER BY b.created_at, b.id`, nodeKind, nodeID, nodeKind, nodeID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var blocks []MemoryBlock
|
||||
for rows.Next() {
|
||||
var block MemoryBlock
|
||||
var vectorJSON string
|
||||
if err := rows.Scan(&block.ID, &block.Modality, &block.Text, &block.PayloadDigest,
|
||||
&block.MIME, &block.Size, &block.Width, &block.Height, &vectorJSON,
|
||||
&block.Fingerprint, &block.Source, &block.Tool, &block.CreatedAt,
|
||||
&block.UpdatedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if vectorJSON != "" && vectorJSON != "null" {
|
||||
if err := json.Unmarshal([]byte(vectorJSON), &block.Vector); err != nil {
|
||||
return nil, fmt.Errorf("decode memory block %s vector: %w", block.ID, err)
|
||||
}
|
||||
}
|
||||
blocks = append(blocks, block)
|
||||
}
|
||||
return blocks, rows.Err()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user