From 8b5a6edba45d13b17e74cb8f64c4e4c820aad0c2 Mon Sep 17 00:00:00 2001 From: DBT Date: Wed, 25 Feb 2026 12:43:15 +0000 Subject: [PATCH] add cron tool for listing and deleting scheduled jobs --- pkg/agent/loop.go | 1 + pkg/tools/cron_tool.go | 83 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 pkg/tools/cron_tool.go diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 10c0352..48e3611 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -127,6 +127,7 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers if cs != nil { toolsRegistry.Register(tools.NewRemindTool(cs)) + toolsRegistry.Register(tools.NewCronTool(cs)) } maxParallelCalls := cfg.Agents.Defaults.RuntimeControl.ToolMaxParallelCalls diff --git a/pkg/tools/cron_tool.go b/pkg/tools/cron_tool.go new file mode 100644 index 0000000..9ce6f56 --- /dev/null +++ b/pkg/tools/cron_tool.go @@ -0,0 +1,83 @@ +package tools + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + "clawgo/pkg/cron" +) + +type CronTool struct { + cs *cron.CronService +} + +func NewCronTool(cs *cron.CronService) *CronTool { + return &CronTool{cs: cs} +} + +func (t *CronTool) Name() string { return "cron" } + +func (t *CronTool) Description() string { + return "Manage scheduled jobs. Actions: list|delete|enable|disable. Use this to inspect and remove your own timers." +} + +func (t *CronTool) Parameters() map[string]interface{} { + return map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "action": map[string]interface{}{"type": "string", "description": "list|delete|enable|disable"}, + "id": map[string]interface{}{"type": "string", "description": "Job ID for delete/enable/disable"}, + }, + } +} + +func (t *CronTool) Execute(ctx context.Context, args map[string]interface{}) (string, error) { + if t.cs == nil { + return "Error: cron service not available", nil + } + action, _ := args["action"].(string) + action = strings.ToLower(strings.TrimSpace(action)) + if action == "" { + action = "list" + } + id, _ := args["id"].(string) + id = strings.TrimSpace(id) + + switch action { + case "list": + jobs := t.cs.ListJobs(true) + b, _ := json.Marshal(jobs) + return string(b), nil + case "delete": + if id == "" { + return "", fmt.Errorf("%w: id for action=delete", ErrMissingField) + } + ok := t.cs.RemoveJob(id) + if !ok { + return fmt.Sprintf("job not found: %s", id), nil + } + return fmt.Sprintf("deleted job: %s", id), nil + case "enable": + if id == "" { + return "", fmt.Errorf("%w: id for action=enable", ErrMissingField) + } + job := t.cs.EnableJob(id, true) + if job == nil { + return fmt.Sprintf("job not found: %s", id), nil + } + return fmt.Sprintf("enabled job: %s", id), nil + case "disable": + if id == "" { + return "", fmt.Errorf("%w: id for action=disable", ErrMissingField) + } + job := t.cs.EnableJob(id, false) + if job == nil { + return fmt.Sprintf("job not found: %s", id), nil + } + return fmt.Sprintf("disabled job: %s", id), nil + default: + return "", fmt.Errorf("%w: %s", ErrUnsupportedAction, action) + } +}