Files
clawgo/pkg/agent/loop_system_notify_test.go
2026-03-15 23:46:06 +08:00

160 lines
5.0 KiB
Go

package agent
import (
"context"
"strings"
"testing"
"time"
"github.com/YspCoder/clawgo/pkg/bus"
)
func TestPrepareOutboundAgentNoReplyFallback(t *testing.T) {
al := &AgentLoop{}
msg := bus.InboundMessage{
Channel: "system",
SenderID: "agent:agent-1",
ChatID: "telegram:9527",
Content: "Task 'coder' completed.\n\nResult:\nOK",
Metadata: map[string]string{
"trigger": "agent",
},
}
outbound, ok := al.prepareOutbound(msg, "NO_REPLY")
if !ok {
t.Fatalf("expected outbound notification for agent NO_REPLY fallback")
}
if outbound.Channel != "telegram" || outbound.ChatID != "9527" {
t.Fatalf("unexpected outbound target: %s:%s", outbound.Channel, outbound.ChatID)
}
if strings.TrimSpace(outbound.Content) != strings.TrimSpace(msg.Content) {
t.Fatalf("expected fallback content from system message, got: %q", outbound.Content)
}
}
func TestPrepareOutboundNoReplySuppressedForNonAgent(t *testing.T) {
al := &AgentLoop{}
msg := bus.InboundMessage{
Channel: "cli",
ChatID: "direct",
Content: "hello",
}
if _, ok := al.prepareOutbound(msg, "NO_REPLY"); ok {
t.Fatalf("expected NO_REPLY to be suppressed for non-agent messages")
}
}
func TestPrepareOutboundAgentNoReplyFallbackWithMissingOrigin(t *testing.T) {
al := &AgentLoop{}
msg := bus.InboundMessage{
Channel: "system",
SenderID: "agent:agent-9",
ChatID: ":",
Metadata: map[string]string{
"trigger": "agent",
},
}
outbound, ok := al.prepareOutbound(msg, "NO_REPLY")
if !ok {
t.Fatalf("expected outbound notification for malformed system origin")
}
if outbound.Channel != "cli" || outbound.ChatID != "direct" {
t.Fatalf("expected fallback origin cli:direct, got %s:%s", outbound.Channel, outbound.ChatID)
}
if outbound.Content != "Agent agent-9 completed." {
t.Fatalf("unexpected fallback content: %q", outbound.Content)
}
}
func TestProcessSystemMessageAgentBlockedQueuedIntoDigest(t *testing.T) {
msgBus := bus.NewMessageBus()
al := &AgentLoop{
bus: msgBus,
agentDigestDelay: 10 * time.Millisecond,
agentDigests: map[string]*agentDigestState{},
}
out, err := al.processSystemMessage(context.Background(), bus.InboundMessage{
Channel: "system",
SenderID: "agent:agent-3",
ChatID: "telegram:9527",
Content: "Agent update\nagent: coder\nrun: agent-3\nstatus: blocked\nreason: blocked\ntask: 修复登录\nsummary: rate limit",
Metadata: map[string]string{
"trigger": "agent",
"agent_id": "coder",
"status": "failed",
"notify_reason": "blocked",
},
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if out != "" {
t.Fatalf("expected queued digest with no immediate output, got %q", out)
}
al.flushDueAgentDigests(time.Now().Add(20 * time.Millisecond))
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
outbound, ok := msgBus.SubscribeOutbound(ctx)
if !ok {
t.Fatalf("expected outbound digest")
}
if !strings.Contains(outbound.Content, "阶段总结") || !strings.Contains(outbound.Content, "coder") || !strings.Contains(outbound.Content, "受阻") {
t.Fatalf("unexpected digest content: %q", outbound.Content)
}
}
func TestProcessSystemMessageAgentDigestMergesMultipleUpdates(t *testing.T) {
msgBus := bus.NewMessageBus()
al := &AgentLoop{
bus: msgBus,
agentDigestDelay: 10 * time.Millisecond,
agentDigests: map[string]*agentDigestState{},
}
first := bus.InboundMessage{
Channel: "system",
SenderID: "agent:agent-7",
ChatID: "telegram:9527",
Content: "Agent update\nagent: tester\nrun: agent-7\nstatus: completed\nreason: final\ntask: 回归测试\nsummary: 所有测试通过",
Metadata: map[string]string{
"trigger": "agent",
"agent_id": "tester",
"status": "completed",
"notify_reason": "final",
},
}
second := bus.InboundMessage{
Channel: "system",
SenderID: "agent:agent-8",
ChatID: "telegram:9527",
Content: "Agent update\nagent: coder\nrun: agent-8\nstatus: completed\nreason: final\ntask: 修复登录\nsummary: 接口已联调",
Metadata: map[string]string{
"trigger": "agent",
"agent_id": "coder",
"status": "completed",
"notify_reason": "final",
},
}
if out, err := al.processSystemMessage(context.Background(), first); err != nil || out != "" {
t.Fatalf("unexpected first result out=%q err=%v", out, err)
}
if out, err := al.processSystemMessage(context.Background(), second); err != nil || out != "" {
t.Fatalf("unexpected second result out=%q err=%v", out, err)
}
al.flushDueAgentDigests(time.Now().Add(20 * time.Millisecond))
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
outbound, ok := msgBus.SubscribeOutbound(ctx)
if !ok {
t.Fatalf("expected merged outbound digest")
}
if strings.Count(outbound.Content, "\n- ") != 2 {
t.Fatalf("expected two digest lines, got: %q", outbound.Content)
}
if !strings.Contains(outbound.Content, "完成 2") {
t.Fatalf("expected aggregate completion count, got: %q", outbound.Content)
}
}