mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-04 00:03:59 +00:00
refactor: pluginize text cleaning and tool NoMemory control
- SDK: ToolDef.NoMemory field, PluginSDK.RegisterTextCleaner/TextCleaners - Registry: aggregate text cleaners from plugins, expose CleanText() - Memory: replace hardcoded QQ regex CleanTemplateText with dynamic CleanText/SetTextCleaner - StageHost: add ToolDef(name) lookup - eventloop: check ToolDef.NoMemory before emitMemoryCandidate - context/Prune: replace hardcoded agentcli/terminal source filter with ToolsUsed NoMemory check - agentcli/cmd: mark tools with NoMemory: true - main.go: wire memory.SetTextCleaner(pluginReg.CleanText)
This commit is contained in:
229
_sdk_local/sdk/plugin_test.go
Normal file
229
_sdk_local/sdk/plugin_test.go
Normal file
@ -0,0 +1,229 @@
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRegisterStageGlobalDefault(t *testing.T) {
|
||||
called := false
|
||||
regStage := func(stage Stage, handler StageHandler) {
|
||||
called = true
|
||||
}
|
||||
s := &PluginSDK{regStage: regStage, name: "test"}
|
||||
s.RegisterStage(StageBeforeToolcall, func(ctx *StageContext) error { return nil })
|
||||
|
||||
if !called {
|
||||
t.Error("global scope: handler not registered")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterStageGlobalExplicit(t *testing.T) {
|
||||
called := false
|
||||
regStage := func(stage Stage, handler StageHandler) {
|
||||
called = true
|
||||
}
|
||||
s := &PluginSDK{regStage: regStage, name: "test"}
|
||||
s.RegisterStage(StageBeforeToolcall, func(ctx *StageContext) error { return nil }, StageScopeGlobal)
|
||||
|
||||
if !called {
|
||||
t.Error("global scope: handler not registered")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterStageOwnToolsMatch(t *testing.T) {
|
||||
var registered StageHandler
|
||||
regStage := func(stage Stage, handler StageHandler) {
|
||||
registered = handler
|
||||
}
|
||||
s := &PluginSDK{regStage: regStage, name: "myplugin"}
|
||||
s.RegisterStage(StageBeforeToolcall, func(ctx *StageContext) error { return nil }, StageScopeOwnTools)
|
||||
|
||||
if registered == nil {
|
||||
t.Fatal("handler not registered")
|
||||
}
|
||||
|
||||
ctx := &StageContext{}
|
||||
ctx.ToolCalls = []ToolCall{{Plugin: "myplugin", Name: "my_tool"}}
|
||||
ctx.ToolResults = nil
|
||||
|
||||
err := registered(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("expected nil, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterStageOwnToolsSkipOtherPlugin(t *testing.T) {
|
||||
var registered StageHandler
|
||||
regStage := func(stage Stage, handler StageHandler) {
|
||||
registered = handler
|
||||
}
|
||||
s := &PluginSDK{regStage: regStage, name: "myplugin"}
|
||||
|
||||
callCount := 0
|
||||
s.RegisterStage(StageBeforeToolcall, func(ctx *StageContext) error {
|
||||
callCount++
|
||||
return nil
|
||||
}, StageScopeOwnTools)
|
||||
|
||||
if registered == nil {
|
||||
t.Fatal("handler not registered")
|
||||
}
|
||||
|
||||
ctx := &StageContext{}
|
||||
ctx.ToolCalls = []ToolCall{{Plugin: "other", Name: "other_tool"}}
|
||||
|
||||
err := registered(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("expected nil, got %v", err)
|
||||
}
|
||||
if callCount != 0 {
|
||||
t.Error("handler should not be called for other plugin's tool")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterStageOwnToolsNonToolcallDegrades(t *testing.T) {
|
||||
regStage := func(stage Stage, handler StageHandler) {
|
||||
if stage != StagePreAction {
|
||||
t.Errorf("expected StagePreAction, got %s", stage)
|
||||
}
|
||||
}
|
||||
s := &PluginSDK{regStage: regStage, name: "test"}
|
||||
s.RegisterStage(StagePreAction, func(ctx *StageContext) error { return nil }, StageScopeOwnTools)
|
||||
}
|
||||
|
||||
func TestRegisterStageOwnToolsStageBeforeToolcallNoToolCalls(t *testing.T) {
|
||||
var registered StageHandler
|
||||
regStage := func(stage Stage, handler StageHandler) {
|
||||
registered = handler
|
||||
}
|
||||
s := &PluginSDK{regStage: regStage, name: "myplugin"}
|
||||
|
||||
callCount := 0
|
||||
s.RegisterStage(StageBeforeToolcall, func(ctx *StageContext) error {
|
||||
callCount++
|
||||
return nil
|
||||
}, StageScopeOwnTools)
|
||||
|
||||
if registered == nil {
|
||||
t.Fatal("handler not registered")
|
||||
}
|
||||
|
||||
ctx := &StageContext{}
|
||||
|
||||
err := registered(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("expected nil, got %v", err)
|
||||
}
|
||||
if callCount != 0 {
|
||||
t.Error("handler should not be called when ToolCalls is empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterStageOwnToolsStageAfterToolcallMatch(t *testing.T) {
|
||||
var registered StageHandler
|
||||
regStage := func(stage Stage, handler StageHandler) {
|
||||
registered = handler
|
||||
}
|
||||
s := &PluginSDK{regStage: regStage, name: "myplugin"}
|
||||
|
||||
callCount := 0
|
||||
s.RegisterStage(StageAfterToolcall, func(ctx *StageContext) error {
|
||||
callCount++
|
||||
return nil
|
||||
}, StageScopeOwnTools)
|
||||
|
||||
if registered == nil {
|
||||
t.Fatal("handler not registered")
|
||||
}
|
||||
|
||||
ctx := &StageContext{}
|
||||
ctx.ToolResults = []ToolResult{{Plugin: "myplugin", Name: "my_tool"}}
|
||||
|
||||
err := registered(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("expected nil, got %v", err)
|
||||
}
|
||||
if callCount != 1 {
|
||||
t.Error("handler should be called for own plugin's tool result")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterStageOwnToolsStageAfterToolcallSkip(t *testing.T) {
|
||||
var registered StageHandler
|
||||
regStage := func(stage Stage, handler StageHandler) {
|
||||
registered = handler
|
||||
}
|
||||
s := &PluginSDK{regStage: regStage, name: "myplugin"}
|
||||
|
||||
callCount := 0
|
||||
s.RegisterStage(StageAfterToolcall, func(ctx *StageContext) error {
|
||||
callCount++
|
||||
return nil
|
||||
}, StageScopeOwnTools)
|
||||
|
||||
ctx := &StageContext{}
|
||||
ctx.ToolResults = []ToolResult{{Plugin: "other", Name: "other_tool"}}
|
||||
|
||||
err := registered(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("expected nil, got %v", err)
|
||||
}
|
||||
if callCount != 0 {
|
||||
t.Error("handler should not be called for other plugin's tool result")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterStageOwnToolsNilRegStage(t *testing.T) {
|
||||
s := &PluginSDK{name: "test"}
|
||||
s.RegisterStage(StageBeforeToolcall, func(ctx *StageContext) error { return nil }, StageScopeOwnTools)
|
||||
}
|
||||
|
||||
func TestToolDefNoMemory(t *testing.T) {
|
||||
def := ToolDef{
|
||||
Name: "test_tool",
|
||||
NoMemory: true,
|
||||
}
|
||||
if !def.NoMemory {
|
||||
t.Error("NoMemory should be true")
|
||||
}
|
||||
def2 := ToolDef{Name: "normal_tool"}
|
||||
if def2.NoMemory {
|
||||
t.Error("default NoMemory should be false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterTextCleaner(t *testing.T) {
|
||||
s := &PluginSDK{name: "test"}
|
||||
|
||||
c1 := func(text string) string { return text + "_c1" }
|
||||
c2 := func(text string) string { return text + "_c2" }
|
||||
|
||||
s.RegisterTextCleaner(c1)
|
||||
s.RegisterTextCleaner(c2)
|
||||
|
||||
cleaners := s.TextCleaners()
|
||||
if len(cleaners) != 2 {
|
||||
t.Fatalf("expected 2 cleaners, got %d", len(cleaners))
|
||||
}
|
||||
|
||||
got := cleaners[0]("hello")
|
||||
if got != "hello_c1" {
|
||||
t.Errorf("expected hello_c1, got %s", got)
|
||||
}
|
||||
|
||||
got = cleaners[1]("hello")
|
||||
if got != "hello_c2" {
|
||||
t.Errorf("expected hello_c2, got %s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTextCleanersEmpty(t *testing.T) {
|
||||
s := New("test", nil, nil, nil, nil, nil)
|
||||
cleaners := s.TextCleaners()
|
||||
if cleaners == nil {
|
||||
t.Error("TextCleaners should return empty slice, not nil")
|
||||
}
|
||||
if len(cleaners) != 0 {
|
||||
t.Errorf("expected 0 cleaners, got %d", len(cleaners))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user