Files
picoclaw/pkg/routing/route_test.go
T
2026-04-01 22:13:04 +08:00

234 lines
5.6 KiB
Go

package routing
import (
"testing"
"github.com/sipeed/picoclaw/pkg/bus"
"github.com/sipeed/picoclaw/pkg/config"
)
func testConfig(agents []config.AgentConfig) *config.Config {
return &config.Config{
Agents: config.AgentsConfig{
Defaults: config.AgentDefaults{
Workspace: "/tmp/picoclaw-test",
ModelName: "gpt-4",
},
List: agents,
},
Session: config.SessionConfig{
Dimensions: []string{"sender"},
},
}
}
func TestResolveRoute_DefaultAgent_NoBindings(t *testing.T) {
cfg := testConfig(nil)
r := NewRouteResolver(cfg)
route := r.ResolveRoute(bus.InboundContext{
Channel: "telegram",
ChatType: "direct",
SenderID: "user1",
})
if route.AgentID != DefaultAgentID {
t.Errorf("AgentID = %q, want %q", route.AgentID, DefaultAgentID)
}
if route.MatchedBy != "default" {
t.Errorf("MatchedBy = %q, want 'default'", route.MatchedBy)
}
if len(route.SessionPolicy.Dimensions) != 1 || route.SessionPolicy.Dimensions[0] != "sender" {
t.Errorf("SessionPolicy.Dimensions = %v, want [sender]", route.SessionPolicy.Dimensions)
}
if route.SessionPolicy.IdentityLinks != nil {
t.Errorf("SessionPolicy.IdentityLinks = %v, want nil", route.SessionPolicy.IdentityLinks)
}
}
func TestResolveRoute_UsesNormalizedInboundContextFields(t *testing.T) {
cfg := testConfig([]config.AgentConfig{{ID: "sales", Default: true}})
r := NewRouteResolver(cfg)
route := r.ResolveRoute(bus.InboundContext{
Channel: "Telegram",
Account: "Bot2",
ChatType: "direct",
SenderID: "user123",
})
if route.AgentID != "sales" {
t.Errorf("AgentID = %q, want 'sales'", route.AgentID)
}
if route.Channel != "telegram" {
t.Errorf("Channel = %q, want 'telegram'", route.Channel)
}
if route.AccountID != "bot2" {
t.Errorf("AccountID = %q, want 'bot2'", route.AccountID)
}
if route.MatchedBy != "default" {
t.Errorf("MatchedBy = %q, want 'default'", route.MatchedBy)
}
}
func TestResolveRoute_DispatchFirstMatchWins(t *testing.T) {
cfg := testConfig([]config.AgentConfig{
{ID: "main", Default: true},
{ID: "support"},
{ID: "sales"},
})
cfg.Agents.Dispatch = &config.DispatchConfig{
Rules: []config.DispatchRule{
{
Name: "support-group",
Agent: "support",
When: config.DispatchSelector{
Channel: "telegram",
Chat: "group:-100123",
},
},
{
Name: "vip-in-group",
Agent: "sales",
When: config.DispatchSelector{
Channel: "telegram",
Chat: "group:-100123",
Sender: "12345",
},
},
},
}
r := NewRouteResolver(cfg)
route := r.ResolveRoute(bus.InboundContext{
Channel: "telegram",
ChatID: "-100123",
ChatType: "group",
SenderID: "12345",
})
if route.AgentID != "support" {
t.Fatalf("AgentID = %q, want support", route.AgentID)
}
if route.MatchedBy != "dispatch.rule:support-group" {
t.Fatalf("MatchedBy = %q, want dispatch.rule:support-group", route.MatchedBy)
}
}
func TestResolveRoute_DispatchOverridesSessionDimensions(t *testing.T) {
cfg := testConfig([]config.AgentConfig{
{ID: "main", Default: true},
{ID: "support"},
})
cfg.Session.Dimensions = []string{"chat"}
cfg.Agents.Dispatch = &config.DispatchConfig{
Rules: []config.DispatchRule{
{
Name: "support-dm",
Agent: "support",
When: config.DispatchSelector{
Channel: "telegram",
Chat: "direct:user-1",
},
SessionDimensions: []string{"chat", "sender"},
},
},
}
r := NewRouteResolver(cfg)
route := r.ResolveRoute(bus.InboundContext{
Channel: "telegram",
ChatID: "user-1",
ChatType: "direct",
SenderID: "user-1",
})
if route.AgentID != "support" {
t.Fatalf("AgentID = %q, want support", route.AgentID)
}
if got := route.SessionPolicy.Dimensions; len(got) != 2 || got[0] != "chat" || got[1] != "sender" {
t.Fatalf("SessionPolicy.Dimensions = %v, want [chat sender]", got)
}
}
func TestResolveRoute_DispatchMentionedRule(t *testing.T) {
cfg := testConfig([]config.AgentConfig{
{ID: "main", Default: true},
{ID: "support"},
})
mentioned := true
cfg.Agents.Dispatch = &config.DispatchConfig{
Rules: []config.DispatchRule{
{
Name: "slack-mentions",
Agent: "support",
When: config.DispatchSelector{
Channel: "slack",
Space: "workspace:t001",
Mentioned: &mentioned,
},
},
},
}
r := NewRouteResolver(cfg)
route := r.ResolveRoute(bus.InboundContext{
Channel: "slack",
ChatID: "C123",
ChatType: "channel",
SpaceID: "T001",
SpaceType: "workspace",
SenderID: "U123",
Mentioned: true,
})
if route.AgentID != "support" {
t.Fatalf("AgentID = %q, want support", route.AgentID)
}
}
func TestResolveRoute_InvalidAgentFallsToDefault(t *testing.T) {
agents := []config.AgentConfig{
{ID: "main", Default: true},
}
cfg := testConfig(agents)
r := NewRouteResolver(cfg)
route := r.ResolveRoute(bus.InboundContext{Channel: "telegram"})
if route.AgentID != "main" {
t.Errorf("AgentID = %q, want 'main' (invalid agent should fall to default)", route.AgentID)
}
}
func TestResolveRoute_DefaultAgentSelection(t *testing.T) {
agents := []config.AgentConfig{
{ID: "alpha"},
{ID: "beta", Default: true},
{ID: "gamma"},
}
cfg := testConfig(agents)
r := NewRouteResolver(cfg)
route := r.ResolveRoute(bus.InboundContext{Channel: "cli"})
if route.AgentID != "beta" {
t.Errorf("AgentID = %q, want 'beta' (marked as default)", route.AgentID)
}
}
func TestResolveRoute_NoDefaultUsesFirst(t *testing.T) {
agents := []config.AgentConfig{
{ID: "alpha"},
{ID: "beta"},
}
cfg := testConfig(agents)
r := NewRouteResolver(cfg)
route := r.ResolveRoute(bus.InboundContext{Channel: "cli"})
if route.AgentID != "alpha" {
t.Errorf("AgentID = %q, want 'alpha' (first in list)", route.AgentID)
}
}