mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-21 01:18:08 +00:00
feat(lightkernel): N2c —— 轻量内核 profile(窄接口 GraphMemory + nil 即禁用整理面)
按用户指出的关键点(a.memory 多数使用点属"主 agent 整理记忆"与"记忆整理流水线", 子不该有那些路径)实现,方案见设计 §16.0。 ## 窄接口:只有 Recall + Commit 新增 `GraphMemory` 接口(memoryface.go)—— 按调用方实测分类后,真正"根与子都要"的只有这两个: - `Recall`:上下文检索 / memory_recall - `Commit`:自动写入路径的图部分 / memory_commit 新增 `Agent.graph`(共同面)与 `Agent.graphMem()` 访问器: - `graph` 显式为 nil 时**回落**到 `memory` ⇒ 既有"只用 Agent 字面量设 memory"的测试无需改动 (原本会出现"必须同时设两个字段"的脚坑,实测踩到后去掉了) - 轻量内核:`graph = *memory.LightMemory`,`memory = nil` ## nil 即禁用:整理面自动消失,不需要受限包装 子的 `a.memory == nil` ⇒ 既有的 22 处 `if a.memory != nil` 关卡自动禁掉全部整理面: - 记忆整理流水线(distill.go 的 archive/review/merge 循环) - 记忆块 + 媒体桥(graphmedia.go / medialoop.go) - 记忆整理工具(memory_merge / memory_delete_entity / memory_block_merge / memory_purge / memory_edit / memory_introspect)—— 它们本就在 `if a.memory != nil` 块内 唯一拆开的一处是自动写入 `commitTriplesWithMedia`: 图部分走 `graphMem().Commit`(父落 main、子落 temp),块/媒体部分仍由 `a.memory != nil` 守卫。 `executeMemoryTool` 的读路径改走 `graphMem().Recall`;整理类 case 加 `requireFull()` 闸门, 被直调时明确报"本 agent 是轻量内核:记忆整理不可用",不静默降级。 ## 验收(3 项新测试) - `TestLightProfile_MemoryFaceWiring`:整理面为 nil、写入只落 temp(主库无子痕迹)、 读是并集(主库实体 + temp 实体都看得到) - `TestLightProfile_OrganizeToolsAbsentAndRefused`:整理类工具**不进工具表**; 即便被直调也明确报"轻量内核不支持" - `TestFullProfile_KeepsOrganizeFace`:对照,根 agent 仍保留整理面与整理工具 全仓 go test ./... 37 包 ok / 0 FAIL;-race(agent/memory)干净;gofmt 干净。
This commit is contained in:
@ -545,11 +545,11 @@ type GraphMemory interface {
|
||||
| **N0** | **无状态化**:删 `Agent.currentOutputChannel`、删提示词里的通道预设 | S18;既有全部测试通过(这是纯收敛,不含新能力) |
|
||||
| **N1a** | **通道登记层**:inputch 一等化(归属插件 / 归属 agent / 容量 / 共享登记表)+ **单工具多视图总览** | S21–S23 |
|
||||
| **N1b** | 输出通道授权过滤 + 目标解析(outputch → 目标 agent 的 inputch) | S1–S3 |
|
||||
| **N2a** | **作用域对象 + 图记忆 space 维度**:`memory.Scope{Write string; Read []string}`;`entities/sentences/relations` 加 `space` 列(默认 `main`,老数据迁移视为 main);写落 `Write`、查询过滤 `space IN Read` | 同 space 可见、跨 space 不可见 |
|
||||
| **N2b** | **图记忆的向量检索**接入同一 space 过滤(子能按 space 语义检索) | 检索不跨 space 越界 |
|
||||
| **N2a** | ~~作用域对象 + 图记忆 space 维度~~ **已完成(改为独立存储实例)**:`OpenGraphDBReadOnly`(query_only 受限句柄)+ `LightMemory`(temp 可写 / 主库只读 / 并集查询 + 应用层合并) | S13–S15 ✅ |
|
||||
| **N2b** | 图记忆的向量检索在并集下的排序/去重(当前按实体名/三元组合并,检索排序沿用单库语义) | 待做(非阻塞) |
|
||||
| — | 其余记忆面(doc 记忆 / 动态上下文 / 知识库 / 文本 / 媒体 / 社交):**v1 不加 space**(子不可达) | 由 S13/S14 隐含 |
|
||||
| **N2c** | **Agent 级 profile(轻量内核接线)**:见下方施工方案 | S13–S15 |
|
||||
| **N2d** | **晋升与丢弃**:`Promote(space, records)`(回收时父把选中的 temp 记录写进 main)+ `DropSpace(space)`(回收/销毁时丢弃 temp) | S11 的数据面 |
|
||||
| **N2c** | ~~Agent 级 profile~~ **已完成**:`GraphMemory` 窄接口(Recall/Commit)+ `a.graph` 共同面;子 `a.memory = nil` ⇒ 22 处既有关卡自动禁用整理面 | S13–S15 ✅ |
|
||||
| **N2d** | ~~晋升与丢弃~~ **数据面已完成**:`GraphDB.ExportTriples` + 复用 `Commit` 合入(父选哪几条);`LightMemory.Close()` 丢弃 temp | S11 数据面 ✅ |
|
||||
| **N3** | **驻留子生命周期**:创建 / 销毁 / 登记表 / 父退出清理 | S12、S16 |
|
||||
| **N4** | **跨 agent 投递**:子→父 L3、父→子 L4(+ `isKernelLevelSource` 分层) | S4、S6、S17 |
|
||||
| **N5** | **inputch 处理表**:主动写入工具 + 自动写兜底 + 生命周期 | S8、S9 |
|
||||
|
||||
@ -37,12 +37,15 @@ type Agent struct {
|
||||
providerManager *agentAPI.ProviderManager
|
||||
io *agentIO.IOManager
|
||||
memory *memory.GraphDB
|
||||
indexer *memory.Indexer
|
||||
tracker *tracker.Tracker
|
||||
context *RelevanceContext
|
||||
systemPrompt string
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
// graph 是本 agent 的**图记忆共同面**(根 = 同一个 GraphDB;驻留子 = LightMemory)。
|
||||
// 整理面仍走 memory 字段(子为 nil ⇒ 既有的 nil 关卡自动禁用整理面)。
|
||||
graph GraphMemory
|
||||
indexer *memory.Indexer
|
||||
tracker *tracker.Tracker
|
||||
context *RelevanceContext
|
||||
systemPrompt string
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
|
||||
// 文档记忆(第二层)
|
||||
docStore *document.Store
|
||||
@ -192,8 +195,13 @@ type AgentConfig struct {
|
||||
ProviderManager *agentAPI.ProviderManager
|
||||
IO *agentIO.IOManager
|
||||
Memory *memory.GraphDB
|
||||
Indexer *memory.Indexer
|
||||
Tracker *tracker.Tracker
|
||||
// LightMemory 是**轻量内核**的图记忆装配(驻留子用;读 temp∪main,只写 temp)。
|
||||
//
|
||||
// 给了它就意味着这是轻量内核:`Memory` 必须为 nil,
|
||||
// 于是记忆整理面(块/媒体/流水线/整理工具)全部不可达(见 memoryface.go)。
|
||||
LightMemory *memory.LightMemory
|
||||
Indexer *memory.Indexer
|
||||
Tracker *tracker.Tracker
|
||||
|
||||
DocStore *document.Store
|
||||
Knowledge *knowledge.Store
|
||||
@ -291,6 +299,7 @@ func New(cfg AgentConfig) *Agent {
|
||||
providerManager: cfg.ProviderManager,
|
||||
io: cfg.IO,
|
||||
memory: cfg.Memory,
|
||||
graph: graphMemoryOf(cfg),
|
||||
indexer: cfg.Indexer,
|
||||
tracker: cfg.Tracker,
|
||||
context: rc,
|
||||
@ -351,6 +360,36 @@ func (a *Agent) Stop() {
|
||||
a.cancel()
|
||||
}
|
||||
|
||||
// graphMemoryOf 决定本 agent 的图记忆共同面实现。
|
||||
//
|
||||
// - 轻量内核(给了 LightMemory):用 LightMemory,**整理面保持 nil**;
|
||||
// - 完整内核:直接用主图库(*memory.GraphDB 天然满足 GraphMemory)。
|
||||
func graphMemoryOf(cfg AgentConfig) GraphMemory {
|
||||
if cfg.LightMemory != nil {
|
||||
return cfg.LightMemory
|
||||
}
|
||||
if cfg.Memory == nil {
|
||||
return nil
|
||||
}
|
||||
return cfg.Memory
|
||||
}
|
||||
|
||||
// graphMem 返回本 agent 的图记忆**共同面**。
|
||||
//
|
||||
// `graph` 显式为 nil 时回落到 `memory` —— 这样"只设 memory 的构造"
|
||||
// (大量既有测试直接用 Agent 字面量)照常工作,不需要同时维护两个字段。
|
||||
// 轻量内核则显式设 graph=LightMemory 且 memory=nil:共同面走 LightMemory,
|
||||
// 整理面因 memory==nil 而全部不可达。
|
||||
func (a *Agent) graphMem() GraphMemory {
|
||||
if a.graph != nil {
|
||||
return a.graph
|
||||
}
|
||||
if a.memory == nil {
|
||||
return nil
|
||||
}
|
||||
return a.memory
|
||||
}
|
||||
|
||||
func (a *Agent) ID() types.AgentID { return a.id }
|
||||
|
||||
// IsOutputAllowed 报告某个输出通道是否被授权给本 agent。
|
||||
|
||||
@ -107,11 +107,14 @@ func (a *Agent) linkBlocksToDocument(docID string, blocks []memory.MemoryBlock)
|
||||
// seed 是调用方已持有的一等块(如 L2 文档的 Blocks),用于保持块身份;
|
||||
// 普通对话路径传 nil。blocks 是本次写入 L3 的块数。
|
||||
func (a *Agent) commitTriplesWithMedia(triples []memory.Triple, sessionID string, turnID int, seed []memory.MemoryBlock) (entities, relations, blocks int, err error) {
|
||||
if a.memory == nil {
|
||||
g := a.graphMem()
|
||||
if g == nil {
|
||||
return 0, 0, 0, fmt.Errorf("graph memory 未启用")
|
||||
}
|
||||
if a.mediaStore == nil {
|
||||
ec, rc, cErr := a.memory.Commit(triples, sessionID, turnID)
|
||||
// 轻量内核(memory == nil,子只有图记忆)或没有媒体库时:只写图记忆。
|
||||
// 写目标由 a.graph 决定 —— 根落 main,子落自己的 temp。
|
||||
if a.memory == nil || a.mediaStore == nil {
|
||||
ec, rc, cErr := g.Commit(triples, sessionID, turnID)
|
||||
return ec, rc, 0, cErr
|
||||
}
|
||||
sentenceIDs, ec, rc, err := a.memory.CommitWithMedia(triples, sessionID, turnID)
|
||||
|
||||
169
internal/agent/core/lightprofile_test.go
Normal file
169
internal/agent/core/lightprofile_test.go
Normal file
@ -0,0 +1,169 @@
|
||||
package core
|
||||
|
||||
// N2c 验收:**轻量内核 profile**。
|
||||
//
|
||||
// 设计 docs/zh/resident-subagent-design.md §16.0(窄接口 + nil 即禁用)与 §5.5。
|
||||
//
|
||||
// 轻量内核(驻留子)的记忆装配:
|
||||
// - graph = *memory.LightMemory(读 temp∪main,只写 temp)
|
||||
// - memory = nil ⇒ 既有的 `if a.memory != nil` 关卡自动禁掉**全部**整理面:
|
||||
// 记忆整理流水线(distill.go 的 archive/review/merge 循环)、记忆块与媒体桥
|
||||
// (graphmedia.go / medialoop.go)、记忆整理工具(merge/delete/purge/edit/block_merge)
|
||||
//
|
||||
// 因此这里要钉住四件事:
|
||||
// ① 子的写入只落 temp,主库不受影响;
|
||||
// ② 子的读是并集(看得到主库 + 自己的 temp);
|
||||
// ③ 整理类工具**不进子的工具表**;
|
||||
// ④ 即便被直调,整理类操作也明确报"轻量内核不支持"(纵深防御,不静默降级)。
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
agentAPI "gitcode.com/JianFeeeee/HomeAgent/internal/agent/api"
|
||||
agentIO "gitcode.com/JianFeeeee/HomeAgent/internal/agent/io"
|
||||
"gitcode.com/JianFeeeee/HomeAgent/internal/memory"
|
||||
)
|
||||
|
||||
// newLightAgent 构造一个轻量内核 agent(驻留子形态):有 LightMemory,没有整理面。
|
||||
func newLightAgent(t *testing.T, main *memory.GraphDB, tempPath string) *Agent {
|
||||
t.Helper()
|
||||
light, err := memory.NewLightMemory(main, tempPath, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
a := New(AgentConfig{
|
||||
ID: "sub-1",
|
||||
Provider: &scriptProvider{},
|
||||
ProviderManager: agentAPI.NewProviderManager(),
|
||||
IO: agentIO.NewIOManager(),
|
||||
StageHost: NewStageHost(),
|
||||
LightMemory: light, // 轻量内核:只给图记忆共同面
|
||||
})
|
||||
t.Cleanup(func() { light.Close() })
|
||||
return a
|
||||
}
|
||||
|
||||
func TestLightProfile_MemoryFaceWiring(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
main, err := memory.NewGraphDB(filepath.Join(dir, "main.db"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer main.Close()
|
||||
if _, _, err := main.Commit([]memory.Triple{
|
||||
{Subject: "主记忆实体", Relation: "属于", Object: "主库"},
|
||||
}, "sess", 1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a := newLightAgent(t, main, filepath.Join(dir, "sub.db"))
|
||||
|
||||
// ① 整理面必须为 nil —— 这正是"nil 即禁用"的开关。
|
||||
if a.memory != nil {
|
||||
t.Fatal("轻量内核不该有整理面(a.memory 必须为 nil)")
|
||||
}
|
||||
if a.graphMem() == nil {
|
||||
t.Fatal("轻量内核必须有图记忆共同面")
|
||||
}
|
||||
|
||||
// ② 写入只落 temp:主库不得出现子才知道的实体。
|
||||
if _, _, _, err := a.commitTriplesWithMedia([]memory.Triple{
|
||||
{Subject: "子独有实体", Relation: "来自", Object: "子的temp"},
|
||||
}, "sess", 1, nil); err != nil {
|
||||
t.Fatalf("子的写入应成功(落 temp): %v", err)
|
||||
}
|
||||
mainRes, err := main.Recall([]string{"子独有实体"}, nil, 1, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, e := range mainRes.Entities {
|
||||
if e.Name == "子独有实体" {
|
||||
t.Fatalf("子的写入不该进主库:%v", e.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// ③ 读是并集:主库的实体与 temp 的实体都要看得到。
|
||||
got := a.executeMemoryTool(agentAPI.ToolCall{
|
||||
ID: "c1", Name: "memory_recall",
|
||||
Arguments: map[string]interface{}{"query_intent": "主记忆实体,子独有实体"},
|
||||
})
|
||||
if !strings.Contains(got, "主记忆实体") {
|
||||
t.Fatalf("子应看得到主记忆:%s", got)
|
||||
}
|
||||
if !strings.Contains(got, "子独有实体") {
|
||||
t.Fatalf("子应看得到自己的 temp:%s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLightProfile_OrganizeToolsAbsentAndRefused(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
main, err := memory.NewGraphDB(filepath.Join(dir, "main.db"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer main.Close()
|
||||
|
||||
a := newLightAgent(t, main, filepath.Join(dir, "sub.db"))
|
||||
|
||||
// ① 整理类工具不进子的工具表(不是进去再报不可用)。
|
||||
names := toolNames(a)
|
||||
for _, banned := range []string{
|
||||
"memory_merge", "memory_delete_entity", "memory_block_merge",
|
||||
"memory_purge", "memory_edit",
|
||||
} {
|
||||
if hasTool(names, banned) {
|
||||
t.Fatalf("轻量内核不该声明整理类工具 %s:%v", banned, names)
|
||||
}
|
||||
}
|
||||
// 对照:共同面/无关能力照常在。
|
||||
if !hasTool(names, "input_channels") {
|
||||
t.Fatalf("轻量内核仍应有共同面工具:%v", names)
|
||||
}
|
||||
|
||||
// ② 纵深防御:即便被直调,整理类操作也必须明确报"轻量内核不支持"。
|
||||
for _, tool := range []string{
|
||||
"memory_merge", "memory_delete_entity", "memory_block_merge",
|
||||
"memory_purge", "memory_edit", "memory_introspect",
|
||||
} {
|
||||
got := a.executeMemoryTool(agentAPI.ToolCall{
|
||||
ID: "x", Name: tool,
|
||||
Arguments: map[string]interface{}{
|
||||
"name": "任意", "source": "a", "target": "b", "criteria": map[string]interface{}{},
|
||||
},
|
||||
})
|
||||
if !strings.Contains(got, "轻量内核") {
|
||||
t.Fatalf("%s 在轻量内核里必须明确报不支持,实际 %q", tool, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 对照:完整内核(根 agent)仍有整理面与整理工具。
|
||||
func TestFullProfile_KeepsOrganizeFace(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
main, err := memory.NewGraphDB(filepath.Join(dir, "main.db"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer main.Close()
|
||||
|
||||
a := New(AgentConfig{
|
||||
ID: "root",
|
||||
Provider: &scriptProvider{},
|
||||
ProviderManager: agentAPI.NewProviderManager(),
|
||||
IO: agentIO.NewIOManager(),
|
||||
StageHost: NewStageHost(),
|
||||
Memory: main,
|
||||
})
|
||||
if a.memory == nil {
|
||||
t.Fatal("根 agent 必须有整理面")
|
||||
}
|
||||
if a.graphMem() == nil {
|
||||
t.Fatal("根 agent 必须有图记忆共同面")
|
||||
}
|
||||
names := toolNames(a)
|
||||
if !hasTool(names, "memory_merge") {
|
||||
t.Fatalf("根 agent 应保留整理类工具:%v", names)
|
||||
}
|
||||
}
|
||||
33
internal/agent/core/memoryface.go
Normal file
33
internal/agent/core/memoryface.go
Normal file
@ -0,0 +1,33 @@
|
||||
package core
|
||||
|
||||
// 图记忆的**共同面**(设计 docs/zh/resident-subagent-design.md §16.0)。
|
||||
//
|
||||
// 只有两个方法 —— 因为按调用方实测分类后,`Agent.memory` 的 42 处使用里,
|
||||
// 真正"根与子都要"的只有:
|
||||
//
|
||||
// Recall 读(上下文检索 / memory_recall)
|
||||
// Commit 写(自动写入路径的图部分 / memory_commit)
|
||||
//
|
||||
// 其余 40 处全是**主 agent 整理记忆**与**记忆整理流水线**:
|
||||
// - 记忆整理流水线:distill.go 的 archive/review/merge 循环
|
||||
// - 记忆块 + 媒体桥:graphmedia.go / medialoop.go
|
||||
// - 记忆整理工具:memory_merge / memory_delete_entity / memory_block_merge /
|
||||
// memory_purge / memory_edit / memory_introspect
|
||||
//
|
||||
// 所以驻留子的轻量内核**不该有那些代码路径**:它用 `*memory.LightMemory` 接上 `graph`,
|
||||
// 而 `a.memory`(整理面)保持 nil —— 既有的 22 处 `if a.memory != nil` 关卡
|
||||
// 会自动把整理面全部禁掉,不需要写"每个方法都返回错误"的受限包装。
|
||||
|
||||
import "gitcode.com/JianFeeeee/HomeAgent/internal/memory"
|
||||
|
||||
// GraphMemory 是任意 agent 都能用的图记忆面。
|
||||
//
|
||||
// 实现者:
|
||||
// - 根 agent:直接就是 *memory.GraphDB
|
||||
// - 驻留子:*memory.LightMemory(读 temp∪main,只写 temp)
|
||||
type GraphMemory interface {
|
||||
// Recall 按关键词/种子实体召回(子的实现是两空间并集)。
|
||||
Recall(keywords []string, seedEntities []string, depth int, sessionFilter string) (*memory.RecallResult, error)
|
||||
// Commit 写入三元组(子的实现只落自己的 temp 空间)。
|
||||
Commit(triples []memory.Triple, sessionID string, turnID int) (int, int, error)
|
||||
}
|
||||
@ -106,12 +106,21 @@ func (a *Agent) executeToolCallInner(tc agentAPI.ToolCall, channel string) strin
|
||||
}
|
||||
|
||||
func (a *Agent) executeMemoryTool(tc agentAPI.ToolCall) string {
|
||||
if a.memory == nil {
|
||||
g := a.graphMem()
|
||||
if g == nil {
|
||||
if tc.Name == "memory_document_query" {
|
||||
return a.executeDocTool(tc)
|
||||
}
|
||||
return "图记忆系统不可用"
|
||||
}
|
||||
// 整理类工具需要**完整内核**的记忆整理面(块/媒体/结构操作)。
|
||||
// 轻量内核(驻留子)只有图记忆共同面 ⇒ 这些操作明确不可用,不静默降级。
|
||||
requireFull := func() string {
|
||||
if a.memory == nil {
|
||||
return "本 agent 是轻量内核:只能读写图记忆,记忆整理(合并/删除/清理/编辑/统计)不可用"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
switch tc.Name {
|
||||
case "memory_recall":
|
||||
query, _ := tc.Arguments["query_intent"].(string)
|
||||
@ -127,7 +136,7 @@ func (a *Agent) executeMemoryTool(tc agentAPI.ToolCall) string {
|
||||
if len(keywords) == 1 {
|
||||
keywords = memory.ExtractKeywords(query)
|
||||
}
|
||||
result, err := a.memory.Recall(keywords, nil, int(depth), "")
|
||||
result, err := g.Recall(keywords, nil, int(depth), "")
|
||||
if err != nil {
|
||||
return fmt.Sprintf("记忆检索失败: %v", err)
|
||||
}
|
||||
@ -165,6 +174,9 @@ func (a *Agent) executeMemoryTool(tc agentAPI.ToolCall) string {
|
||||
return strings.Join(parts, "\n")
|
||||
|
||||
case "memory_block_merge":
|
||||
if msg := requireFull(); msg != "" {
|
||||
return msg
|
||||
}
|
||||
entityA, _ := tc.Arguments["entity_a"].(string)
|
||||
entityB, _ := tc.Arguments["entity_b"].(string)
|
||||
rounds, _ := tc.Arguments["rounds"].(float64)
|
||||
@ -225,6 +237,9 @@ func (a *Agent) executeMemoryTool(tc agentAPI.ToolCall) string {
|
||||
return fmt.Sprintf("已写入 %d 个实体和 %d 条关系", ec, rc)
|
||||
|
||||
case "memory_introspect":
|
||||
if msg := requireFull(); msg != "" {
|
||||
return msg
|
||||
}
|
||||
stats, err := a.memory.Introspect()
|
||||
if err != nil {
|
||||
return fmt.Sprintf("查询失败: %v", err)
|
||||
@ -235,6 +250,9 @@ func (a *Agent) executeMemoryTool(tc agentAPI.ToolCall) string {
|
||||
return a.executeDocTool(tc)
|
||||
|
||||
case "memory_merge":
|
||||
if msg := requireFull(); msg != "" {
|
||||
return msg
|
||||
}
|
||||
source, _ := tc.Arguments["source"].(string)
|
||||
target, _ := tc.Arguments["target"].(string)
|
||||
if source == "" || target == "" {
|
||||
@ -247,6 +265,9 @@ func (a *Agent) executeMemoryTool(tc agentAPI.ToolCall) string {
|
||||
return fmt.Sprintf("已将「%s」合并到「%s」,source 已彻底删除,%d 条关系已重定向", source, target, count)
|
||||
|
||||
case "memory_delete_entity":
|
||||
if msg := requireFull(); msg != "" {
|
||||
return msg
|
||||
}
|
||||
name, _ := tc.Arguments["name"].(string)
|
||||
if name == "" {
|
||||
return "name 不能为空"
|
||||
@ -257,6 +278,9 @@ func (a *Agent) executeMemoryTool(tc agentAPI.ToolCall) string {
|
||||
return fmt.Sprintf("已彻底删除实体「%s」及其所有关联关系", name)
|
||||
|
||||
case "memory_purge":
|
||||
if msg := requireFull(); msg != "" {
|
||||
return msg
|
||||
}
|
||||
criteria := make(map[string]string)
|
||||
if v, ok := tc.Arguments["subject_contains"].(string); ok && v != "" {
|
||||
criteria["subject_contains"] = v
|
||||
@ -291,6 +315,9 @@ func (a *Agent) executeMemoryTool(tc agentAPI.ToolCall) string {
|
||||
return strings.Join(parts, ",")
|
||||
|
||||
case "memory_edit":
|
||||
if msg := requireFull(); msg != "" {
|
||||
return msg
|
||||
}
|
||||
oldSubject, _ := tc.Arguments["old_subject"].(string)
|
||||
oldRelation, _ := tc.Arguments["old_relation"].(string)
|
||||
oldObject, _ := tc.Arguments["old_object"].(string)
|
||||
|
||||
Reference in New Issue
Block a user