mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-06 17:27:31 +00:00
feat: 段页式记忆流转、coldcontext 重命名与安全治理
记忆层: - MemoryBlock 承载 FrameTS/PageSeq/PageKind/BlockRole/CallID - coldcontext 归档与回填按完整页传递,工具调用参数和配对键不丢失 - 召回先估算总 token,超预算时按全局页相似度标记 inactive - inactive 仅是 context 渲染期状态,不落盘、不进入 coldcontext,Prune 后重置 - Peek/确认/Remove 两阶段召回,失败保留冷上下文副本 - stablemem 记录 last_recalled_at,删块连带清理边 命名: - internal/memory/document → internal/memory/coldcontext - Doc/DocEvent/DocHit → ColdDoc/ColdEvent/ColdHit - ContextToColdContext/RecentColdContexts/FindColdContexts - 保留既有 JSON 标签、doc_ 文件前缀与 doc_count 状态键,兼容存量数据 安全治理: - 工具策略门禁、安全配置、事件总线发布者身份与入站脱敏 - 声明式 SecurityAPI 与 QQ owner/guest profile - 日志保留策略与相关 e2e/回归判据 验证:go build ./...、go vet ./...、go test ./...(62 包); 生产副本 e2e:7013 块迁移后 ID/向量/指纹 0 变化、0 缺失。
This commit is contained in:
@ -9,7 +9,7 @@ import (
|
||||
"unicode"
|
||||
|
||||
"github.com/JianFeeeee/HologramAgent/internal/memory"
|
||||
"github.com/JianFeeeee/HologramAgent/internal/memory/document"
|
||||
"github.com/JianFeeeee/HologramAgent/internal/memory/coldcontext"
|
||||
)
|
||||
|
||||
// CrossModalHit 是跨模态检索融合后的一条候选。
|
||||
@ -21,11 +21,11 @@ import (
|
||||
// memory.RecallBlocks(读块自己的向量),因此不存在「召回已无处可归的
|
||||
// 内容」这回事——能召回的必然是被某层持有的块。
|
||||
type CrossModalHit struct {
|
||||
Doc *document.Doc // 文本路命中的文档;视觉路命中时为 nil
|
||||
Media *memory.MemoryBlock // 视觉路命中的媒体块;文本路命中时也可能带关联块
|
||||
MediaScore float64 // 视觉路原始 cosine(无则 0)
|
||||
DocScore float64 // 文本路原始 cosine(无则 0)
|
||||
Fused float64 // 归一化加权融合分,供最终排序
|
||||
Doc *coldcontext.ColdDoc // 文本路命中的文档;视觉路命中时为 nil
|
||||
Media *memory.MemoryBlock // 视觉路命中的媒体块;文本路命中时也可能带关联块
|
||||
MediaScore float64 // 视觉路原始 cosine(无则 0)
|
||||
DocScore float64 // 文本路原始 cosine(无则 0)
|
||||
Fused float64 // 归一化加权融合分,供最终排序
|
||||
// 该媒体同时被两路命中时 DoubleHit=true —— 双信号确认,应排在只被
|
||||
// 一路命中的候选之前。
|
||||
DoubleHit bool
|
||||
@ -88,8 +88,8 @@ func (a *Agent) retrieveCrossModal(query string, topK int, cfg CrossModalFusionC
|
||||
|
||||
// ---- 文本路 ----
|
||||
var textHits []CrossModalHit
|
||||
if a.docStore != nil {
|
||||
for _, dh := range a.docStore.QueryScored(query, per) {
|
||||
if a.coldcontextStore != nil {
|
||||
for _, dh := range a.coldcontextStore.QueryScored(query, per) {
|
||||
hit := CrossModalHit{Doc: dh.Doc, DocScore: dh.Score}
|
||||
// 命中文档若持有一等记忆块,把首个媒体块一并带上(用于双命中标记)。
|
||||
for i := range dh.Doc.Blocks {
|
||||
@ -322,7 +322,7 @@ func (a *Agent) crossModalMarkdown(hits []CrossModalHit) string {
|
||||
// firstRealSource 取事件里第一个非内部标记的来源。
|
||||
//
|
||||
// `context_archived` 是内核归档动作的标记,不是"谁说的",对模型无意义。
|
||||
func firstRealSource(events []document.DocEvent) string {
|
||||
func firstRealSource(events []coldcontext.ColdEvent) string {
|
||||
for _, ev := range events {
|
||||
if ev.Source != "" && ev.Source != "context_archived" && ev.Source != "cold_storage" {
|
||||
return ev.Source
|
||||
@ -342,7 +342,7 @@ func firstRealSource(events []document.DocEvent) string {
|
||||
// 顺序:事件正文(块里的文本)→ 工具回执 → 文档 Content。
|
||||
// 摘要行("已回复…")不在这里出现——它由 docHeadlineForPrompt 负责,
|
||||
// 两者互补:一个说"发生了什么",一个说"内容是什么"。
|
||||
func docBodyExcerptForPrompt(d *document.Doc, n int) string {
|
||||
func docBodyExcerptForPrompt(d *coldcontext.ColdDoc, n int) string {
|
||||
if d == nil {
|
||||
return ""
|
||||
}
|
||||
@ -438,7 +438,7 @@ func collectJSONStrings(v interface{}, depth int) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
func docHeadlineForPrompt(d *document.Doc) string {
|
||||
func docHeadlineForPrompt(d *coldcontext.ColdDoc) string {
|
||||
if d == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user