Files
Cyrene_v2/internal/runtime/memory/extract.go
T
AskaEth 61cf80d5ee
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
docs(comments): 注释中文化 · internal/runtime/memory(31 文件,纯替换)
- 只翻注释/文档字符串:820 增 / 820 删 严格 1:1;剥掉整行注释与行尾注释尾巴后,
  逐文件与 HEAD 比对「代码部分差异 = 0」;裁决/design 编号计数逐项与 HEAD 一致
- 保留可执行 SQL 样例、SQLite 报错原文、pgvector/HNSW/ANN/BLOB 等技术词原文
- 复核:go build 绿 + memory/projectindex/vector 三包测试绿;gofmt 仅剩 2 个既有未格式化文件(改动前即如此,未顺手修)
2026-10-04 13:32:54 +08:00

95 lines
3.0 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"
"errors"
"strings"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
)
var (
// ErrNilAdapter 在构建或使用 LLMExtractor 却未提供
// 驱动提取的 model.Adapter 时返回。
ErrNilAdapter = errors.New("memory: nil model adapter")
)
// Extractor 从一次对话中推导候选记忆条目(design §1)。
//
// 有两个实现:
//
// - LLMExtractor:让 model.Adapter 对每轮对话去噪去重,
// 同步运行(Extract)或在后台 goroutine 上运行
// (ExtractAsync)。
// - ManualExtractor:确定性、规则式 —— 只记录用户
// 显式要求记住的内容(「记住 X」)。
type Extractor interface {
// Extract 返回对话中值得持久化的记忆条目。ctx
// 控制取消;ctx 被取消时返回错误。
Extract(ctx context.Context, conversation []model.Message) ([]MemoryItem, error)
}
// ManualExtractor 实现不经 LLM 的手动「记住 X」提取路径。
// 它扫描用户轮次中领起的记住指令,为每条产出一个记忆
// 条目,普通对话则不产出。它是 M4 LLM 提取器的
// 确定性对照实现。
type ManualExtractor struct {
personaID string
roleID string
}
// NewManualExtractor 构建 ManualExtractor,其提取出的条目以
// personaID/roleID 为作者。与 LLM 提取器一样,角色是
// 默认值而非权威:多角色调用方以空
// 角色构建它,并在持久化时用该轮的角色给条目盖章
// (design/22 §4.2),因此要构建与角色无关的提取器就传 ""。
func NewManualExtractor(personaID, roleID string) *ManualExtractor {
return &ManualExtractor{personaID: personaID, roleID: roleID}
}
// Extract 为每个要求代理记住点什么的用户
// 轮次返回一条记忆条目(kind 为 relationship、作用域为 persona)。领起的
// 「记住」/「请记住」指令会从落库内容中剥离;没有该指令的轮次跳过。
func (e *ManualExtractor) Extract(ctx context.Context, conversation []model.Message) ([]MemoryItem, error) {
if err := ctx.Err(); err != nil {
return nil, err
}
items := make([]MemoryItem, 0)
for _, msg := range conversation {
if msg.Role != model.RoleUser {
continue
}
text := strings.TrimSpace(messageText(msg))
content, ok := rememberDirective(text)
if !ok {
continue
}
items = append(items, MemoryItem{
PersonaID: e.personaID,
RoleID: e.roleID,
Scope: ScopePersona,
Kind: KindRelationship,
Content: content,
Confidence: 1.0,
DecayWeight: 1.0,
})
}
return items, nil
}
// rememberDirective 在 text 是记住指令时剥离「记住」/「请记住」前缀。
// 它返回被记住的内容与 true;text 不是显式记住请求时
// ok=false。
func rememberDirective(text string) (string, bool) {
for _, prefix := range []string{"请记住", "记住"} {
if strings.HasPrefix(text, prefix) {
content := strings.TrimSpace(strings.TrimPrefix(text, prefix))
if content == "" {
return "", false
}
return content, true
}
}
return "", false
}