mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-03 15:53:56 +00:00
sdk: embed non-toolchain SDK in third_party, add NoMemory/Cleaner support
- Embed sdk/, example/, meta/, go.mod from homeagent-sdk (no .git)
- Core .gitignore excludes SDK toolchain: bin/, tools/, package/
- RegisterInputChannel + ChannelDef(NoMemory, Cleaner) in SDK
- IOManager input channel registry with GetInputChannelDef
- eventloop: apply channel Cleaner/NoMemory to interrupt text
- context engine: channelDefLookup applied in textForVector
- document store: ChannelCleaner param for archive functions
- All callers/adapters updated with ChannelDef{} default
This commit is contained in:
@ -15,6 +15,10 @@ import (
|
||||
"gitcode.com/JianFeeeee/HomeAgent/internal/memory/vector"
|
||||
)
|
||||
|
||||
// ChannelCleaner 按事件来源查找输入通道的 Cleaner 函数。
|
||||
// 返回 nil 表示不使用额外清洗。
|
||||
type ChannelCleaner func(source string) func(string) string
|
||||
|
||||
// Doc — 记忆文档:由上下文提炼而来
|
||||
type Doc struct {
|
||||
ID string `json:"id"`
|
||||
@ -128,7 +132,7 @@ func (s *Store) Insert(doc *Doc) error {
|
||||
// toolCleanFn 可选,func(name, output string) string,按工具名对输出进行过滤/清洗:
|
||||
// - 返回 "" → 跳过该工具输出(NoMemory)
|
||||
// - 返回清洗后文本 → 用于计算层(Cleaner),原文不受影响
|
||||
func (s *Store) ContextToDoc(source string, entries []ContextEntry, vec vector.Vectorizer, cleanFn func(string) string, toolCleanFn func(name, output string) string) (*Doc, error) {
|
||||
func (s *Store) ContextToDoc(source string, entries []ContextEntry, vec vector.Vectorizer, cleanFn func(string) string, toolCleanFn func(name, output string) string, channelCleaner ChannelCleaner) (*Doc, error) {
|
||||
if len(entries) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
@ -151,9 +155,9 @@ func (s *Store) ContextToDoc(source string, entries []ContextEntry, vec vector.V
|
||||
content := strings.Join(parts, "\n")
|
||||
contentHash := simpleHash(content)
|
||||
|
||||
summary := summarizeEntries(entries, cleanFn, toolCleanFn)
|
||||
tags := extractTags(entries, cleanFn, toolCleanFn)
|
||||
entities := extractEntities(entries, cleanFn, toolCleanFn)
|
||||
summary := summarizeEntries(entries, cleanFn, toolCleanFn, channelCleaner)
|
||||
tags := extractTags(entries, cleanFn, toolCleanFn, channelCleaner)
|
||||
entities := extractEntities(entries, cleanFn, toolCleanFn, channelCleaner)
|
||||
|
||||
s.mu.Lock()
|
||||
|
||||
@ -441,7 +445,7 @@ type ContextEntry struct {
|
||||
ToolResults []ToolResultItem
|
||||
}
|
||||
|
||||
func summarizeEntries(entries []ContextEntry, cleanText func(string) string, toolCleanFn func(name, output string) string) string {
|
||||
func summarizeEntries(entries []ContextEntry, cleanText func(string) string, toolCleanFn func(name, output string) string, channelCleaner ChannelCleaner) string {
|
||||
if len(entries) == 0 {
|
||||
return ""
|
||||
}
|
||||
@ -449,7 +453,13 @@ func summarizeEntries(entries []ContextEntry, cleanText func(string) string, too
|
||||
var topics []string
|
||||
for _, e := range entries {
|
||||
sources[e.Source]++
|
||||
words := memory.ExtractKeywords(cleanText(e.Content))
|
||||
content := e.Content
|
||||
if channelCleaner != nil {
|
||||
if c := channelCleaner(e.Source); c != nil {
|
||||
content = c(content)
|
||||
}
|
||||
}
|
||||
words := memory.ExtractKeywords(cleanText(content))
|
||||
topics = append(topics, words...)
|
||||
for _, tr := range e.ToolResults {
|
||||
out := tr.Output
|
||||
@ -490,10 +500,16 @@ func summarizeEntries(entries []ContextEntry, cleanText func(string) string, too
|
||||
return summary
|
||||
}
|
||||
|
||||
func extractTags(entries []ContextEntry, cleanText func(string) string, toolCleanFn func(name, output string) string) []string {
|
||||
func extractTags(entries []ContextEntry, cleanText func(string) string, toolCleanFn func(name, output string) string, channelCleaner ChannelCleaner) []string {
|
||||
tagSet := make(map[string]bool)
|
||||
for _, e := range entries {
|
||||
for _, kw := range memory.ExtractKeywords(cleanText(e.Content)) {
|
||||
content := e.Content
|
||||
if channelCleaner != nil {
|
||||
if c := channelCleaner(e.Source); c != nil {
|
||||
content = c(content)
|
||||
}
|
||||
}
|
||||
for _, kw := range memory.ExtractKeywords(cleanText(content)) {
|
||||
tagSet[kw] = true
|
||||
}
|
||||
for _, tr := range e.ToolResults {
|
||||
@ -520,11 +536,17 @@ func extractTags(entries []ContextEntry, cleanText func(string) string, toolClea
|
||||
return tags
|
||||
}
|
||||
|
||||
func extractEntities(entries []ContextEntry, cleanText func(string) string, toolCleanFn func(name, output string) string) []string {
|
||||
func extractEntities(entries []ContextEntry, cleanText func(string) string, toolCleanFn func(name, output string) string, channelCleaner ChannelCleaner) []string {
|
||||
var entities []string
|
||||
seen := make(map[string]bool)
|
||||
for _, e := range entries {
|
||||
for _, kw := range memory.ExtractKeywords(cleanText(e.Content)) {
|
||||
content := e.Content
|
||||
if channelCleaner != nil {
|
||||
if c := channelCleaner(e.Source); c != nil {
|
||||
content = c(content)
|
||||
}
|
||||
}
|
||||
for _, kw := range memory.ExtractKeywords(cleanText(content)) {
|
||||
if len(kw) >= 2 && !seen[kw] {
|
||||
seen[kw] = true
|
||||
entities = append(entities, kw)
|
||||
|
||||
@ -82,7 +82,7 @@ func TestContextToDoc(t *testing.T) {
|
||||
{Timestamp: time.Now(), Source: "user", Content: "特别是Go语言", Response: "Go很棒"},
|
||||
}
|
||||
|
||||
doc, err := s.ContextToDoc("test", entries, nil, nil, nil)
|
||||
doc, err := s.ContextToDoc("test", entries, nil, nil, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -178,7 +178,7 @@ func TestSummarizeEntries(t *testing.T) {
|
||||
{Source: "user", Content: "今天天气如何"},
|
||||
{Source: "user", Content: "明天会下雨吗"},
|
||||
}
|
||||
summary := summarizeEntries(entries, func(s string) string { return s }, nil)
|
||||
summary := summarizeEntries(entries, func(s string) string { return s }, nil, nil)
|
||||
if summary == "" {
|
||||
t.Error("summary should not be empty")
|
||||
}
|
||||
@ -198,7 +198,7 @@ func TestExtractTags(t *testing.T) {
|
||||
entries := []ContextEntry{
|
||||
{Content: "我喜欢喝咖啡和编程"},
|
||||
}
|
||||
tags := extractTags(entries, func(s string) string { return s }, nil)
|
||||
tags := extractTags(entries, func(s string) string { return s }, nil, nil)
|
||||
if len(tags) == 0 {
|
||||
t.Error("should extract tags")
|
||||
}
|
||||
@ -384,7 +384,7 @@ func TestSummarizeEntriesWithToolCleanFn(t *testing.T) {
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
summary := summarizeEntries([]ContextEntry{entry}, func(s string) string { return s }, tc.toolCleanFn)
|
||||
summary := summarizeEntries([]ContextEntry{entry}, func(s string) string { return s }, tc.toolCleanFn, nil)
|
||||
for _, w := range tc.wantTopics {
|
||||
if !contains(summary, w) {
|
||||
t.Errorf("summary should contain %q, got: %s", w, summary)
|
||||
@ -410,7 +410,7 @@ func TestExtractTagsWithToolCleanFn(t *testing.T) {
|
||||
}
|
||||
|
||||
// toolCleanFn 返回 "" → NoMemory,工具输出被跳过
|
||||
tagsSkip := extractTags(entries, func(s string) string { return s }, func(name, output string) string { return "" })
|
||||
tagsSkip := extractTags(entries, func(s string) string { return s }, func(name, output string) string { return "" }, nil)
|
||||
for _, tag := range tagsSkip {
|
||||
if tag == "编程" || tag == "咖啡" {
|
||||
t.Errorf("NoMemory tool should not contribute keywords, got tag: %s", tag)
|
||||
@ -418,7 +418,7 @@ func TestExtractTagsWithToolCleanFn(t *testing.T) {
|
||||
}
|
||||
|
||||
// toolCleanFn 返回清洗文本 → 用清洗后内容提取关键词
|
||||
tagsClean := extractTags(entries, func(s string) string { return s }, func(name, output string) string { return "咖啡 编程" })
|
||||
tagsClean := extractTags(entries, func(s string) string { return s }, func(name, output string) string { return "咖啡 编程" }, nil)
|
||||
found := false
|
||||
for _, tag := range tagsClean {
|
||||
if tag == "编程" {
|
||||
@ -456,7 +456,7 @@ func TestContextToDocContentPreservesRawToolOutput(t *testing.T) {
|
||||
cleaner := func(name, output string) string {
|
||||
return "天气 温度"
|
||||
}
|
||||
doc, err := s.ContextToDoc("test", entries, nil, nil, cleaner)
|
||||
doc, err := s.ContextToDoc("test", entries, nil, nil, cleaner, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user