Documentation
¶
Overview ¶
Package scheduler implements the task scheduling system for DevClaw. Uses robfig/cron for cron expression parsing and execution, with SQLite-based persistence for surviving restarts.
Package scheduler – sqlite_storage.go implements JobStorage backed by the central devclaw.db SQLite database. It is a drop-in replacement for FileJobStorage: same interface, no changes needed in scheduler.go.
Package scheduler – storage.go provides a JSON file-based JobStorage implementation that persists scheduler jobs to disk.
Index ¶
- type AnnounceHandler
- type FileJobStorage
- type Job
- type JobHandler
- type JobResult
- type JobStorage
- type JobUsage
- type SQLiteJobStorage
- type Scheduler
- func (s *Scheduler) Add(job *Job) error
- func (s *Scheduler) Get(jobID string) (*Job, bool)
- func (s *Scheduler) List() []*Job
- func (s *Scheduler) Remove(jobID string) error
- func (s *Scheduler) SetAnnounceHandler(h AnnounceHandler)
- func (s *Scheduler) Start(ctx context.Context) error
- func (s *Scheduler) Stop()
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AnnounceHandler ¶
AnnounceHandler is called when a job with Announce=true completes. Receives the channel, chatID, and formatted message to send.
type FileJobStorage ¶
type FileJobStorage struct {
// contains filtered or unexported fields
}
FileJobStorage persists jobs as a JSON file on disk.
func NewFileJobStorage ¶
func NewFileJobStorage(path string) (*FileJobStorage, error)
NewFileJobStorage creates a file-based job storage at the given path. Creates the parent directory if it doesn't exist.
func (*FileJobStorage) Delete ¶
func (s *FileJobStorage) Delete(id string) error
Delete removes a job from the storage file.
func (*FileJobStorage) LoadAll ¶
func (s *FileJobStorage) LoadAll() ([]*Job, error)
LoadAll reads all persisted jobs from the storage file.
func (*FileJobStorage) Save ¶
func (s *FileJobStorage) Save(job *Job) error
Save persists a job to the storage file.
type Job ¶
type Job struct {
// ID is the unique job identifier.
ID string `json:"id" yaml:"id"`
// Schedule is the cron expression or shorthand.
// Supports: standard 5-field cron, @daily, @hourly, @every 5m, etc.
Schedule string `json:"schedule" yaml:"schedule"`
// Type is the schedule type: "cron" (recurring), "at" (one-shot), "every" (interval).
Type string `json:"type" yaml:"type"`
// Command is the prompt/command executed by the agent.
Command string `json:"command" yaml:"command"`
// Channel is the target channel (e.g., "whatsapp").
Channel string `json:"channel" yaml:"channel"`
// ChatID is the target chat/group.
ChatID string `json:"chat_id" yaml:"chat_id"`
// Enabled indicates if the job is active.
Enabled bool `json:"enabled" yaml:"enabled"`
// CreatedBy is the user who created the job.
CreatedBy string `json:"created_by,omitempty" yaml:"created_by,omitempty"`
// CreatedAt is the creation timestamp.
CreatedAt time.Time `json:"created_at" yaml:"created_at"`
// LastRunAt is the last execution timestamp.
LastRunAt *time.Time `json:"last_run_at,omitempty" yaml:"last_run_at,omitempty"`
// LastError contains the error from the last run, if any.
LastError string `json:"last_error,omitempty" yaml:"last_error,omitempty"`
// RunCount tracks how many times the job has executed.
RunCount int `json:"run_count" yaml:"run_count"`
// IsolateSession runs each job execution in its own isolated session
// instead of sharing the channel's main session. This prevents cron
// output from polluting the main conversation history.
IsolateSession bool `json:"isolate_session,omitempty" yaml:"isolate_session,omitempty"`
// Announce sends the job result to the target channel/chat after completion.
// When false, the job runs silently (result is only logged).
Announce bool `json:"announce,omitempty" yaml:"announce,omitempty"`
// AsSubagent runs the job as a subagent instead of in the main agent loop.
// This provides better isolation and prevents cron jobs from blocking
// user-initiated agent runs.
AsSubagent bool `json:"as_subagent,omitempty" yaml:"as_subagent,omitempty"`
// Model overrides the LLM model for this specific job (empty = default).
Model string `json:"model,omitempty" yaml:"model,omitempty"`
// TimeoutSeconds overrides the global job timeout for this job.
TimeoutSeconds int `json:"timeout_seconds,omitempty" yaml:"timeout_seconds,omitempty"`
// Labels are arbitrary tags for filtering and organization.
Labels []string `json:"labels,omitempty" yaml:"labels,omitempty"`
// StaggerMs is a deterministic delay (in ms) applied before execution to
// prevent thundering herd when multiple jobs share the same schedule.
// Computed from job ID hash if zero and the schedule is top-of-hour.
StaggerMs int `json:"stagger_ms,omitempty" yaml:"stagger_ms,omitempty"`
// Exact disables stagger for this job (fire at exact schedule time).
Exact bool `json:"exact,omitempty" yaml:"exact,omitempty"`
// LastRunDuration is how long the last execution took.
LastRunDuration time.Duration `json:"last_run_duration,omitempty" yaml:"last_run_duration,omitempty"`
// LastUsage holds token usage from the last execution.
LastUsage *JobUsage `json:"last_usage,omitempty" yaml:"last_usage,omitempty"`
}
Job represents a scheduled task.
type JobHandler ¶
JobHandler is called when a job fires. Returns the agent response or error. For backward compatibility, the handler may return just a string via the legacy signature, or a JobResult with usage telemetry.
type JobStorage ¶
type JobStorage interface {
Save(job *Job) error
Delete(id string) error
LoadAll() ([]*Job, error)
}
JobStorage defines the persistence interface for jobs.
type JobUsage ¶
type JobUsage struct {
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
TotalTokens int `json:"total_tokens"`
CacheReadTokens int `json:"cache_read_tokens,omitempty"`
CacheWriteTokens int `json:"cache_write_tokens,omitempty"`
}
JobUsage tracks token usage from the LLM during a cron job execution.
type SQLiteJobStorage ¶
type SQLiteJobStorage struct {
// contains filtered or unexported fields
}
SQLiteJobStorage persists jobs in the central devclaw.db "jobs" table.
func NewSQLiteJobStorage ¶
func NewSQLiteJobStorage(db *sql.DB) *SQLiteJobStorage
NewSQLiteJobStorage creates a SQLite-backed job storage using the shared DB. The "jobs" table must already exist (created by copilot.OpenDatabase).
func (*SQLiteJobStorage) Delete ¶
func (s *SQLiteJobStorage) Delete(id string) error
Delete removes a job by ID.
func (*SQLiteJobStorage) LoadAll ¶
func (s *SQLiteJobStorage) LoadAll() ([]*Job, error)
LoadAll reads all persisted jobs.
func (*SQLiteJobStorage) Save ¶
func (s *SQLiteJobStorage) Save(job *Job) error
Save persists a job (insert or update).
type Scheduler ¶
type Scheduler struct {
// contains filtered or unexported fields
}
Scheduler manages scheduled tasks using cron expressions.
func New ¶
func New(storage JobStorage, handler JobHandler, logger *slog.Logger) *Scheduler
New creates a new Scheduler with the given storage and handler.
func (*Scheduler) SetAnnounceHandler ¶
func (s *Scheduler) SetAnnounceHandler(h AnnounceHandler)
SetAnnounceHandler registers a callback for announce-enabled jobs.