From 64109338770169c34aa527fd4d9af2a0ebc00455 Mon Sep 17 00:00:00 2001 From: DBT Date: Mon, 23 Feb 2026 12:24:00 +0000 Subject: [PATCH] refine openclaw-style background triggers and status visibility --- cmd/clawgo/cmd_gateway.go | 62 +++++++++++++++++++++++++++------------ cmd/clawgo/cmd_status.go | 23 ++++++++++++++- 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/cmd/clawgo/cmd_gateway.go b/cmd/clawgo/cmd_gateway.go index 7446046..72ea5c4 100644 --- a/cmd/clawgo/cmd_gateway.go +++ b/cmd/clawgo/cmd_gateway.go @@ -61,11 +61,26 @@ func gatewayCmd() { msgBus := bus.NewMessageBus() cronStorePath := filepath.Join(filepath.Dir(getConfigPath()), "cron", "jobs.json") cronService := cron.NewCronService(cronStorePath, func(job *cron.CronJob) (string, error) { - if job == nil || strings.TrimSpace(job.Payload.Message) == "" { + if job == nil { return "", nil } + targetChannel := strings.TrimSpace(job.Payload.Channel) targetChatID := strings.TrimSpace(job.Payload.To) + message := strings.TrimSpace(job.Payload.Message) + + if job.Payload.Deliver && targetChannel != "" && targetChatID != "" && message != "" { + msgBus.PublishOutbound(bus.OutboundMessage{ + Channel: targetChannel, + ChatID: targetChatID, + Content: message, + }) + return "delivered", nil + } + + if message == "" { + return "", nil + } if targetChannel == "" || targetChatID == "" { targetChannel = "internal" targetChatID = "cron" @@ -74,7 +89,7 @@ func gatewayCmd() { Channel: "system", SenderID: "cron", ChatID: fmt.Sprintf("%s:%s", targetChannel, targetChatID), - Content: job.Payload.Message, + Content: message, SessionKey: fmt.Sprintf("cron:%s", job.ID), Metadata: map[string]string{ "trigger": "cron", @@ -84,23 +99,7 @@ func gatewayCmd() { return "scheduled", nil }) configureCronServiceRuntime(cronService, cfg) - hbInterval := cfg.Agents.Defaults.Heartbeat.EverySec - if hbInterval <= 0 { - hbInterval = 30 * 60 - } - heartbeatService := heartbeat.NewHeartbeatService(cfg.WorkspacePath(), func(prompt string) (string, error) { - msgBus.PublishInbound(bus.InboundMessage{ - Channel: "system", - SenderID: "heartbeat", - ChatID: "internal:heartbeat", - Content: prompt, - SessionKey: "heartbeat:default", - Metadata: map[string]string{ - "trigger": "heartbeat", - }, - }) - return "queued", nil - }, hbInterval, cfg.Agents.Defaults.Heartbeat.Enabled) + heartbeatService := buildHeartbeatService(cfg, msgBus) sentinelService := sentinel.NewService( getConfigPath(), cfg.WorkspacePath(), @@ -181,6 +180,11 @@ func gatewayCmd() { applyMaximumPermissionPolicy(newCfg) } configureCronServiceRuntime(cronService, newCfg) + heartbeatService.Stop() + heartbeatService = buildHeartbeatService(newCfg, msgBus) + if err := heartbeatService.Start(); err != nil { + fmt.Printf("Error starting heartbeat service: %v\n", err) + } if reflect.DeepEqual(cfg, newCfg) { fmt.Println("✓ Config unchanged, skip reload") @@ -565,3 +569,23 @@ func configureCronServiceRuntime(cs *cron.CronService, cfg *config.Config) { MaxWorkers: cfg.Cron.MaxWorkers, }) } + +func buildHeartbeatService(cfg *config.Config, msgBus *bus.MessageBus) *heartbeat.HeartbeatService { + hbInterval := cfg.Agents.Defaults.Heartbeat.EverySec + if hbInterval <= 0 { + hbInterval = 30 * 60 + } + return heartbeat.NewHeartbeatService(cfg.WorkspacePath(), func(prompt string) (string, error) { + msgBus.PublishInbound(bus.InboundMessage{ + Channel: "system", + SenderID: "heartbeat", + ChatID: "internal:heartbeat", + Content: prompt, + SessionKey: "heartbeat:default", + Metadata: map[string]string{ + "trigger": "heartbeat", + }, + }) + return "queued", nil + }, hbInterval, cfg.Agents.Defaults.Heartbeat.Enabled) +} diff --git a/cmd/clawgo/cmd_status.go b/cmd/clawgo/cmd_status.go index 45d1ee4..75206e8 100644 --- a/cmd/clawgo/cmd_status.go +++ b/cmd/clawgo/cmd_status.go @@ -3,11 +3,11 @@ package main import ( "fmt" "os" + "path/filepath" "strings" "clawgo/pkg/providers" ) - func statusCmd() { cfg, err := loadConfig() if err != nil { @@ -64,5 +64,26 @@ func statusCmd() { fmt.Printf("Log Max Size: %d MB\n", cfg.Logging.MaxSizeMB) fmt.Printf("Log Retention: %d days\n", cfg.Logging.RetentionDays) } + + fmt.Printf("Heartbeat: enabled=%v interval=%ds ackMaxChars=%d\n", + cfg.Agents.Defaults.Heartbeat.Enabled, + cfg.Agents.Defaults.Heartbeat.EverySec, + cfg.Agents.Defaults.Heartbeat.AckMaxChars, + ) + fmt.Printf("Cron Runtime: workers=%d sleep=%d-%ds\n", + cfg.Cron.MaxWorkers, + cfg.Cron.MinSleepSec, + cfg.Cron.MaxSleepSec, + ) + + heartbeatLog := filepath.Join(workspace, "memory", "heartbeat.log") + if data, err := os.ReadFile(heartbeatLog); err == nil { + trimmed := strings.TrimSpace(string(data)) + if trimmed != "" { + lines := strings.Split(trimmed, "\n") + fmt.Printf("Heartbeat Runs Logged: %d\n", len(lines)) + fmt.Printf("Heartbeat Last Log: %s\n", lines[len(lines)-1]) + } + } } }