- 04.4.2/1.9 读侧:Retrieve 候选集并集 = 本人 persona 域 ∪ user 共享域 ∪ project 共享域(他角色 persona 域仍排除),群聊/陌生人取受限收窄
- 写侧:群聊/陌生人整段跳过记忆提取(可查不可写),persona 域仅属主可写
- 04.4.3:source_conversation 不再由 LLM 自由生成(prompt 不索要、候选结构不含该键),落库时无条件盖真实 {session_id,message_id},编解码集中在 memory/source.go
- 新增跨角色种子用例(原用例即使关掉并集也会通过)+ 成对用例「同群聊上下文:读得到共享域、写不进 store」
- 同步 store.go/retrieve.go 文档注释,与 design/03 §3/§4 口径一致
61 lines
2.1 KiB
Go
61 lines
2.1 KiB
Go
package memory
|
||
|
||
import (
|
||
"encoding/json"
|
||
"strings"
|
||
)
|
||
|
||
// SourceRef 是 source_conversation 落库值的结构化形状(裁决
|
||
// 04.4.3,design/03 §2 溯源):一条记忆由哪次会话的哪条消息
|
||
// 提取而来。两个 id 都由持久化层(提取调用点)从运行上下文
|
||
// 盖真实值,绝不由模型生成,因此「可回溯到哪次对话」是
|
||
// 机器可验证的,而不是 LLM 自由文本。
|
||
type SourceRef struct {
|
||
// SessionID 是提取发生时的会话 id(Run 的 sessionID:Web
|
||
// 主/次级会话或渠道会话)。
|
||
SessionID string `json:"session_id"`
|
||
// MessageID 是触发提取的消息标识:gateway 在 Run 前挂载的
|
||
// turn id;调用方未挂载时为空,此时溯源只到会话粒度。
|
||
MessageID string `json:"message_id"`
|
||
}
|
||
|
||
// FormatSourceConversation 把真实 session/message id 编码为
|
||
// source_conversation 的落库值:固定键序的紧凑 JSON,可被
|
||
// ParseSourceConversation 解回。两个 id 都为空时返回 ""(无
|
||
// 溯源)。纯字符串字段结构的 Marshal 不会失败;防御性兜底
|
||
// 返回 ""。
|
||
func FormatSourceConversation(sessionID, messageID string) string {
|
||
ref := SourceRef{
|
||
SessionID: strings.TrimSpace(sessionID),
|
||
MessageID: strings.TrimSpace(messageID),
|
||
}
|
||
if ref.SessionID == "" && ref.MessageID == "" {
|
||
return ""
|
||
}
|
||
b, err := json.Marshal(ref)
|
||
if err != nil {
|
||
return ""
|
||
}
|
||
return string(b)
|
||
}
|
||
|
||
// ParseSourceConversation 解码落库的 source_conversation。ok 为
|
||
// false 表示该值不是结构化溯源 —— 裁决前由 LLM 自由文本填写
|
||
// 的遗留行会落在这里 —— 调用方据此区分可机器回溯的行与
|
||
// 遗留行,而不是把自由文本误当真实 id。解出的两个字段都为
|
||
// 空同样返回 false:没有真实 id 的行不构成溯源。
|
||
func ParseSourceConversation(s string) (SourceRef, bool) {
|
||
s = strings.TrimSpace(s)
|
||
if !strings.HasPrefix(s, "{") {
|
||
return SourceRef{}, false
|
||
}
|
||
var ref SourceRef
|
||
if err := json.Unmarshal([]byte(s), &ref); err != nil {
|
||
return SourceRef{}, false
|
||
}
|
||
if ref.SessionID == "" && ref.MessageID == "" {
|
||
return SourceRef{}, false
|
||
}
|
||
return ref, true
|
||
}
|