feat(memory): 记忆 P2(项目索引物化 / decay 回写 / 作用域写规则 / 静默吞点 + loop 级只读红线测试)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

This commit is contained in:
AskaEth committed 2026-10-05 11:47:39 +08:00
1 parent 9b903a89bc
commit 509dc412eb
12 files changed
+660 -55

No files matched your search

+28 -9
View File
@@ -91,27 +91,46 @@ func (k *knowledgeTool) Execute(ctx context.Context, args any) (any, error) {
if v, ok := argInt(m, "top_k"); ok && v > 0 {
topK = v
}
results, err := k.retriever.Retrieve(ctx, persona, query, topK)
// 群聊/陌生人(受限环境)是只读的(design/03 §5「能查不能写」):检索
// 时关掉衰减退化的物化回写(memory.WithoutDecayWriteback),并在返回前
// 复用循环注入路径上的同一隔离判据(loop.FilterSharedVisible),绝不另造
// 第二套 —— 否则一旦管理面板把本工具放行给群聊/陌生人,就会返回角色日常
// (ScopePersona,主人私有)与 L4 意图记录(主人逐句原话),触碰 design/03
// §5「不泄露主人敏感信息」(审计 2026-10-05,P0 红线)。
restricted := loop.SessionEnvFrom(ctx).Restricted()
rctx := ctx
if restricted {
rctx = memory.WithoutDecayWriteback(ctx)
}
results, err := k.retriever.Retrieve(rctx, persona, query, topK)
if err != nil {
return nil, fmt.Errorf("io: knowledge: retrieve: %w", err)
}
// 群聊/陌生人(受限环境)只读非敏感的共享域记忆:复用循环注入路径上的
// 同一隔离判据(loop.FilterSharedVisible),绝不另造第二套 —— 否则一旦
// 管理面板把本工具放行给群聊/陌生人,就会返回角色日常(ScopePersona,
// 主人私有)与 L4 意图记录(主人逐句原话),触碰 design/03 §5
// 「不泄露主人敏感信息」(审计 2026-10-05,P0 红线)。
if loop.SessionEnvFrom(ctx).Restricted() {
if restricted {
results = loop.FilterSharedVisible(results)
}
out := make([]map[string]any, 0, len(results))
for _, r := range results {
out = append(out, map[string]any{
entry := map[string]any{
"id": r.Item.ID,
"kind": string(r.Item.Kind),
"scope": string(r.Item.Scope),
"content": r.Item.Content,
"score": r.Score,
})
}
// 项目作用域记忆链接到项目索引层级(design/03 §3:项目索引 →
// 项目描述 → 章节内容)。此前工具丢掉了 Result.Project,模型因此
// 只看得到一条句子,够不着它所属的项目(审计 2026-10-05 §4「模型
// 不可达章节」)。这里把链接的项目条目带出(id/title/desc),使模型
// 能沿「项目索引 → 项目描述」继续深入,而不是盲取一条悬空记忆。
if r.Project != nil {
entry["project"] = map[string]any{
"id": r.Project.ID,
"title": r.Project.Title,
"desc": r.Project.Desc,
}
}
out = append(out, entry)
}
if len(out) == 0 {
return map[string]any{