Files
Cyrene_v2/internal/runtime/memory/store_project.go
T
AskaEth 509dc412eb
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
feat(memory): 记忆 P2(项目索引物化 / decay 回写 / 作用域写规则 / 静默吞点 + loop 级只读红线测试)
2026-10-05 11:47:39 +08:00

63 lines
2.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package memory
import (
"context"
"strings"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/memory/projectindex"
)
// 本文件是「项目记忆 → 项目索引」链接的写入侧:把项目作用域记忆携带的
// ProjectID 落成一条真实的项目索引条目,使 design/03 §3 的
// 「项目索引 → 项目描述 → 章节内容」三层在第一层就有数据可解析。
//
// 背景(审计 2026-10-05 §4/§7):project / project_chapter 两表数据为零,
// 而实库里 project 域记忆的 project_id 大量悬空 —— Retriever.projectFor
// 对这些条目恒返回 nil,模型够不着项目/章节。项目索引的权威写入源是
// 知识库导入(admin RAG,PutProject + AddChapter);但一条**先写下来**的
// 项目记忆(LLM 提取或手动添加)若引用一个尚未导入的项目 id,链接即断。
// 这里在记忆写入时确保该索引条目存在(只补不覆盖),把悬空链接就地接通,
// 而不新建知识内容(记忆 ≠ 资料,design §3)。
// attachProjectIndex 把项目索引存储接到该 store 的写入路径:此后每条经
// Add 落库的项目作用域记忆都会确保其 ProjectID 对应的索引条目存在。nil
// 索引是空操作。可并发调用,last-writer-wins。
func (s *Store) attachProjectIndex(idx *projectindex.Store) {
if s == nil || idx == nil {
return
}
s.projMu.Lock()
defer s.projMu.Unlock()
s.proj = idx
}
// projectIndex 返回当前接入的项目索引存储,未接入时为 nil。
func (s *Store) projectIndex() *projectindex.Store {
if s == nil {
return nil
}
s.projMu.RLock()
defer s.projMu.RUnlock()
return s.proj
}
// ensureProjectIndex 为项目作用域且带 ProjectID 的条目确保项目索引条目
// 存在。其它作用域、空 ProjectID、未接入项目索引时都是空操作。
//
// 失败只记日志:项目链接是元数据,接通失败绝不使记忆写入失败(与
// indexItem 的语义一致);条目的关系行已经在库里,Retriever.projectFor
// 仍有日志可循(见 retrieve.go 的静默吞点修复)。
func (s *Store) ensureProjectIndex(ctx context.Context, item MemoryItem) {
if item.Scope != ScopeProject || strings.TrimSpace(item.ProjectID) == "" {
return
}
idx := s.projectIndex()
if idx == nil {
return
}
if err := idx.EnsureProject(ctx, item.ProjectID, item.ProjectID); err != nil {
s.log.Warn("memory: ensure project index entry failed, link left dangling",
"project_id", item.ProjectID, "id", item.ID, "error", err)
}
}