Files
picoclaw/pkg/routing/agent_id_test.go
T
Leandro Barbosa 272536a11a feat: add multi-agent routing with declarative bindings
Implement per-agent workspace/model/session isolation with 7-level
priority routing cascade (peer > parent_peer > guild > team > account >
channel > default). Backward compatible - empty agents.list creates
implicit "main" agent from defaults.

Core components:
- routing/agent_id.go: ID normalization with pre-compiled regex
- routing/session_key.go: 4 DM scope modes with identity links
- routing/route.go: RouteResolver with priority-based binding matcher
- agent/instance.go: Per-agent state (workspace, sessions, tools, model)
- agent/registry.go: Agent lifecycle, route resolution, subagent ACL

Integration:
- config.go: AgentModelConfig (flexible JSON), bindings, session config
- loop.go: Complete rewrite for multi-agent dispatch
- Channel adapters: peer_kind/peer_id metadata (telegram, discord, slack)
- spawn.go: Subagent allowlist enforcement per agent

Validated end-to-end with Discord channel-based bindings, default
fallback routing, and per-agent session persistence.
2026-02-13 12:12:33 -03:00

87 lines
2.2 KiB
Go

package routing
import "testing"
func TestNormalizeAgentID_Empty(t *testing.T) {
if got := NormalizeAgentID(""); got != DefaultAgentID {
t.Errorf("NormalizeAgentID('') = %q, want %q", got, DefaultAgentID)
}
}
func TestNormalizeAgentID_Whitespace(t *testing.T) {
if got := NormalizeAgentID(" "); got != DefaultAgentID {
t.Errorf("NormalizeAgentID(' ') = %q, want %q", got, DefaultAgentID)
}
}
func TestNormalizeAgentID_Valid(t *testing.T) {
tests := []struct {
input, want string
}{
{"main", "main"},
{"Main", "main"},
{"SALES", "sales"},
{"support-bot", "support-bot"},
{"agent_1", "agent_1"},
{"a", "a"},
{"0test", "0test"},
}
for _, tt := range tests {
if got := NormalizeAgentID(tt.input); got != tt.want {
t.Errorf("NormalizeAgentID(%q) = %q, want %q", tt.input, got, tt.want)
}
}
}
func TestNormalizeAgentID_InvalidChars(t *testing.T) {
tests := []struct {
input, want string
}{
{"Hello World", "hello-world"},
{"agent@123", "agent-123"},
{"foo.bar.baz", "foo-bar-baz"},
{"--leading", "leading"},
{"--both--", "both"},
}
for _, tt := range tests {
if got := NormalizeAgentID(tt.input); got != tt.want {
t.Errorf("NormalizeAgentID(%q) = %q, want %q", tt.input, got, tt.want)
}
}
}
func TestNormalizeAgentID_AllInvalid(t *testing.T) {
if got := NormalizeAgentID("@@@"); got != DefaultAgentID {
t.Errorf("NormalizeAgentID('@@@') = %q, want %q", got, DefaultAgentID)
}
}
func TestNormalizeAgentID_TruncatesAt64(t *testing.T) {
long := ""
for i := 0; i < 100; i++ {
long += "a"
}
got := NormalizeAgentID(long)
if len(got) > MaxAgentIDLength {
t.Errorf("length = %d, want <= %d", len(got), MaxAgentIDLength)
}
}
func TestNormalizeAccountID_Empty(t *testing.T) {
if got := NormalizeAccountID(""); got != DefaultAccountID {
t.Errorf("NormalizeAccountID('') = %q, want %q", got, DefaultAccountID)
}
}
func TestNormalizeAccountID_Valid(t *testing.T) {
if got := NormalizeAccountID("MyBot"); got != "mybot" {
t.Errorf("NormalizeAccountID('MyBot') = %q, want 'mybot'", got)
}
}
func TestNormalizeAccountID_InvalidChars(t *testing.T) {
if got := NormalizeAccountID("bot@home"); got != "bot-home" {
t.Errorf("NormalizeAccountID('bot@home') = %q, want 'bot-home'", got)
}
}