fix(cron): publish deliver-false agent replies

This commit is contained in:
Alix-007 2026-03-17 21:38:20 +08:00
parent 5bc4fe4dea
commit bf2ed429b2
2 changed files with 102 additions and 2 deletions

View file

@ -374,7 +374,18 @@ func (t *CronTool) ExecuteJob(ctx context.Context, job *cron.CronJob) string {
return fmt.Sprintf("Error: %v", err)
}
// Response is automatically sent via MessageBus by AgentLoop
_ = response // Will be sent by AgentLoop
// ProcessDirectWithChannel bypasses the normal inbound loop, so publish the
// returned final text here when the agent produced one.
if strings.TrimSpace(response) == "" {
return "ok"
}
pubCtx, pubCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer pubCancel()
t.msgBus.PublishOutbound(pubCtx, bus.OutboundMessage{
Channel: channel,
ChatID: chatID,
Content: response,
})
return "ok"
}

View file

@ -12,6 +12,39 @@ import (
"github.com/sipeed/picoclaw/pkg/cron"
)
type stubJobExecutor struct {
response string
err error
calls []struct {
content string
sessionKey string
channel string
chatID string
}
}
func (s *stubJobExecutor) ProcessDirectWithChannel(
_ context.Context,
content,
sessionKey,
channel,
chatID string,
) (string, error) {
s.calls = append(s.calls, struct {
content string
sessionKey string
channel string
chatID string
}{
content: content,
sessionKey: sessionKey,
channel: channel,
chatID: chatID,
})
return s.response, s.err
}
func newTestCronToolWithConfig(t *testing.T, cfg *config.Config) *CronTool {
t.Helper()
storePath := filepath.Join(t.TempDir(), "cron.json")
@ -234,3 +267,59 @@ func TestCronTool_ExecuteJobPublishesErrorWhenExecDisabled(t *testing.T) {
t.Fatalf("expected exec disabled message, got: %s", msg.Content)
}
}
func TestCronTool_ExecuteJobPublishesAgentReplyWhenDeliverFalse(t *testing.T) {
tool := newTestCronTool(t)
executor := &stubJobExecutor{response: "remember to stretch"}
tool.executor = executor
job := &cron.CronJob{ID: "job-123"}
job.Payload.Channel = "discord"
job.Payload.To = "chat-42"
job.Payload.Message = "stretch reminder"
if got := tool.ExecuteJob(context.Background(), job); got != "ok" {
t.Fatalf("ExecuteJob() = %q, want ok", got)
}
if len(executor.calls) != 1 {
t.Fatalf("executor calls = %d, want 1", len(executor.calls))
}
if executor.calls[0].sessionKey != "cron-job-123" {
t.Fatalf("sessionKey = %q, want %q", executor.calls[0].sessionKey, "cron-job-123")
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
msg, ok := tool.msgBus.SubscribeOutbound(ctx)
if !ok {
t.Fatal("expected outbound message")
}
if msg.Channel != "discord" || msg.ChatID != "chat-42" {
t.Fatalf("message route = %s/%s, want discord/chat-42", msg.Channel, msg.ChatID)
}
if msg.Content != "remember to stretch" {
t.Fatalf("message content = %q, want %q", msg.Content, "remember to stretch")
}
}
func TestCronTool_ExecuteJobSkipsBlankAgentReplyWhenDeliverFalse(t *testing.T) {
tool := newTestCronTool(t)
tool.executor = &stubJobExecutor{response: " \n\t"}
job := &cron.CronJob{ID: "job-blank"}
job.Payload.Channel = "discord"
job.Payload.To = "chat-blank"
job.Payload.Message = "stretch reminder"
if got := tool.ExecuteJob(context.Background(), job); got != "ok" {
t.Fatalf("ExecuteJob() = %q, want ok", got)
}
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()
if _, ok := tool.msgBus.SubscribeOutbound(ctx); ok {
t.Fatal("expected no outbound message for blank agent reply")
}
}