automation

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 14, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AgentConfig

type AgentConfig struct {
	// Slug references a named agent definition in seshat-ai (e.g. "accounting-agent").
	// When set, the daemon fetches the agent's model, tools, system_prompt, and
	// max_turns from seshat-ai and merges them with any inline overrides below.
	Slug string
	// BaseType is the built-in agent type to use as a starting point.
	// Empty defaults to "general-purpose".
	BaseType string
	// Tools is the list of tool name patterns the agent is allowed to use
	// (e.g. "read", "web_search", "bash"). Empty = all tools (or inherits from agent).
	Tools []string
	// Skills is the list of skill names to load for this agent.
	Skills []string
	// Model overrides the agent/server default (format "provider:model").
	Model string
	// MaxTurns caps autonomous execution. 0 = inherit from agent or single turn.
	MaxTurns int
	// SystemPrompt overrides the default system prompt when non-empty.
	SystemPrompt string
}

AgentConfig defines the agent that executes a job. When Slug is set the daemon resolves the full agent definition from seshat-ai and uses it as the base configuration; all other fields act as overrides.

type CronSchedule

type CronSchedule struct {
	// contains filtered or unexported fields
}

CronSchedule fires according to a standard 5-field cron expression:

┌───────────── minute  (0–59)
│ ┌─────────── hour    (0–23)
│ │ ┌───────── dom     (1–31)
│ │ │ ┌─────── month   (1–12)
│ │ │ │ ┌───── weekday (0–6, 0=Sun)
│ │ │ │ │
* * * * *

Supports: *, N, N-M, */N, N,M,…, and combinations thereof.

func Cron

func Cron(expr string) (*CronSchedule, error)

Cron parses a 5-field cron expression. Returns an error on invalid syntax.

func MustCron

func MustCron(expr string) *CronSchedule

MustCron parses expr and panics on error.

func (*CronSchedule) Next

func (c *CronSchedule) Next(from time.Time) time.Time

func (*CronSchedule) String

func (c *CronSchedule) String() string

type DBJobStore

type DBJobStore struct {
	// contains filtered or unexported fields
}

DBJobStore implements JobStore backed by a seshat DB instance.

func NewDBJobStore

func NewDBJobStore(database *db.DB) *DBJobStore

NewDBJobStore wraps a DB instance as a JobStore.

func (*DBJobStore) CreateJob

func (s *DBJobStore) CreateJob(ctx context.Context, job *Job) error

func (*DBJobStore) CreateRun

func (s *DBJobStore) CreateRun(ctx context.Context, run *JobRun) error

func (*DBJobStore) DeleteJob

func (s *DBJobStore) DeleteJob(ctx context.Context, id, ownerID string) error

func (*DBJobStore) GetJob

func (s *DBJobStore) GetJob(ctx context.Context, id string) (*Job, error)

func (*DBJobStore) GetRun

func (s *DBJobStore) GetRun(ctx context.Context, id string) (*JobRun, error)

func (*DBJobStore) ListJobs

func (s *DBJobStore) ListJobs(ctx context.Context, ownerID string) ([]*Job, error)

func (*DBJobStore) ListRuns

func (s *DBJobStore) ListRuns(ctx context.Context, jobID string, limit int) ([]*JobRun, error)

func (*DBJobStore) UpdateJob

func (s *DBJobStore) UpdateJob(ctx context.Context, job *Job) error

func (*DBJobStore) UpdateRun

func (s *DBJobStore) UpdateRun(ctx context.Context, run *JobRun) error

type DiscardSink

type DiscardSink struct{}

DiscardSink silently drops every result. Useful in tests.

func (DiscardSink) Write

func (DiscardSink) Write(_ context.Context, _ Result) error

type ExecuteConfig

type ExecuteConfig struct {
	// StreamFn receives each text delta in real time. May be nil.
	StreamFn func(string)
	// ModelOverride specifies a different model for this execution only.
	// Format: "provider:model". Empty means use RunnerConfig.Model.
	ModelOverride string
	// SystemPrompt replaces the entire Seshat default system prompt.
	// Empty means use the default.
	SystemPrompt string
}

ExecuteConfig holds per-execution overrides applied on top of RunnerConfig.

type ExecuteFunc

type ExecuteFunc func(ctx context.Context, w Workflow, opts Options) (Result, error)

ExecuteFunc is the core execution signature threaded through the middleware chain.

type ExecutionState

type ExecutionState struct {
	WorkflowName string    `json:"workflow_name"`
	LastRunAt    time.Time `json:"last_run_at"`
	NextRunAt    time.Time `json:"next_run_at,omitempty"`
	LastStatus   string    `json:"last_status"` // "success" | "error" | "running"
	LastError    string    `json:"last_error,omitempty"`
	RunCount     int64     `json:"run_count"`
	SuccessCount int64     `json:"success_count"`
	FailureCount int64     `json:"failure_count"`
	ConsecErrors int       `json:"consec_errors"`
}

ExecutionState tracks the persistent history of a workflow across runs.

type Executor

type Executor struct {
	// contains filtered or unexported fields
}

Executor orchestrates workflow execution: it combines the Runner with middleware, output sinks, and state management.

func NewExecutor

func NewExecutor(cfg ExecutorConfig) (*Executor, error)

NewExecutor builds an Executor from cfg. WithRecovery() is always prepended so panics never escape.

func (*Executor) Close

func (e *Executor) Close()

Close releases the underlying Runner and all its resources.

func (*Executor) Run

func (e *Executor) Run(ctx context.Context, w Workflow, opts Options) (Result, error)

Run executes w with opts, runs all middleware, feeds sinks, and updates state.

type ExecutorConfig

type ExecutorConfig struct {
	RunnerConfig RunnerConfig
	// Middleware is applied in order (first = outermost wrapper).
	Middleware []Middleware
	// Sinks receive the completed Result after each execution.
	Sinks []Sink
	// State persists execution history. May be nil (no persistence).
	State StateStore
}

ExecutorConfig configures the Executor.

type FileSink

type FileSink struct {
	// Dir is the directory where output files are written. Created if absent.
	Dir string
	// Format is "text" (default) or "json".
	Format string
}

FileSink writes the result to a file. The filename is derived from the workflow name and the run timestamp.

func (*FileSink) Write

func (s *FileSink) Write(ctx context.Context, r Result) error

type FileStateStore

type FileStateStore struct {
	Dir string
	// contains filtered or unexported fields
}

FileStateStore persists one JSON file per workflow in a directory. It is safe for use by a single process (no cross-process locking).

func NewFileStateStore

func NewFileStateStore(dir string) (*FileStateStore, error)

func (*FileStateStore) Delete

func (f *FileStateStore) Delete(_ context.Context, name string) error

func (*FileStateStore) List

func (*FileStateStore) Load

func (*FileStateStore) Save

type IntervalSchedule

type IntervalSchedule struct {
	Interval time.Duration
}

IntervalSchedule fires every fixed Interval starting from first use.

func Every

func Every(d time.Duration) *IntervalSchedule

func (*IntervalSchedule) Next

func (s *IntervalSchedule) Next(from time.Time) time.Time

func (*IntervalSchedule) String

func (s *IntervalSchedule) String() string

type Job

type Job struct {
	ID            string
	OwnerID       string // user ID from the calling app — empty means unowned (system job)
	Name          string
	Description   string
	Trigger       Trigger
	Agent         AgentConfig
	Task          string
	Status        JobStatus
	LastRunAt     *time.Time
	NextRunAt     *time.Time
	LastRunStatus string // "success" | "error" | ""
	CreatedAt     time.Time
	UpdatedAt     time.Time
}

Job is a persisted automation task: trigger + agent config + task description.

type JobRun

type JobRun struct {
	ID        string
	JobID     string
	StartedAt time.Time
	EndedAt   *time.Time
	Status    RunStatus
	Output    string
	Error     string
}

JobRun records a single execution of a Job.

type JobScheduler

type JobScheduler struct {
	// contains filtered or unexported fields
}

JobScheduler manages the lifecycle of persisted automation jobs. It ticks every 10 seconds, checks due jobs, and fires them as goroutines. All job state is persisted via JobStore so the scheduler survives restarts.

func NewJobScheduler

func NewJobScheduler(store JobStore, runner *Runner) *JobScheduler

NewJobScheduler builds a JobScheduler backed by store and runner.

func (*JobScheduler) AddJob

func (s *JobScheduler) AddJob(ctx context.Context, job *Job) error

AddJob persists a new job and computes its initial NextRunAt.

func (*JobScheduler) GetJob

func (s *JobScheduler) GetJob(ctx context.Context, id string) (*Job, error)

GetJob returns a single job by ID.

func (*JobScheduler) GetRun

func (s *JobScheduler) GetRun(ctx context.Context, id string) (*JobRun, error)

GetRun returns a single run by ID.

func (*JobScheduler) ListJobs

func (s *JobScheduler) ListJobs(ctx context.Context, ownerID string) ([]*Job, error)

ListJobs returns jobs for ownerID; "" returns all (admin/scheduler use).

func (*JobScheduler) ListRuns

func (s *JobScheduler) ListRuns(ctx context.Context, jobID string, limit int) ([]*JobRun, error)

ListRuns returns the most recent runs for a job (newest first).

func (*JobScheduler) PauseJob

func (s *JobScheduler) PauseJob(ctx context.Context, id string) error

PauseJob marks a job as paused so the scheduler skips it.

func (*JobScheduler) RemoveJob

func (s *JobScheduler) RemoveJob(ctx context.Context, id, ownerID string) error

RemoveJob deletes a job and cancels any in-flight execution. ownerID="" bypasses ownership check (admin/system use).

func (*JobScheduler) ResumeJob

func (s *JobScheduler) ResumeJob(ctx context.Context, id string) error

ResumeJob re-activates a paused job and recomputes its next run time.

func (*JobScheduler) Run

func (s *JobScheduler) Run(ctx context.Context) error

Run blocks and ticks the scheduler until ctx is cancelled.

func (*JobScheduler) RunNow

func (s *JobScheduler) RunNow(ctx context.Context, id string) (*JobRun, error)

RunNow immediately fires a job outside of its schedule. Returns the JobRun created for this execution.

func (*JobScheduler) SetLogger

func (s *JobScheduler) SetLogger(l *log.Logger)

SetLogger replaces the default logger.

func (*JobScheduler) SetRunnerResolver

func (s *JobScheduler) SetRunnerResolver(resolver RunnerResolver)

SetRunnerResolver installs a dynamic runner resolver that fetches per-user LLM credentials at execution time. When set, it overrides the static runner.

func (*JobScheduler) UpdateJob

func (s *JobScheduler) UpdateJob(ctx context.Context, job *Job) error

UpdateJob re-persists a job and recomputes its next run time.

type JobStatus

type JobStatus string
const (
	JobStatusActive   JobStatus = "active"
	JobStatusPaused   JobStatus = "paused"
	JobStatusInactive JobStatus = "inactive" // once-trigger that already fired
)

type JobStore

type JobStore interface {
	CreateJob(ctx context.Context, job *Job) error
	// GetJob returns a job by ID regardless of owner (for internal scheduler use).
	GetJob(ctx context.Context, id string) (*Job, error)
	// ListJobs returns all jobs for ownerID; pass "" to list all (scheduler/admin).
	ListJobs(ctx context.Context, ownerID string) ([]*Job, error)
	UpdateJob(ctx context.Context, job *Job) error
	// DeleteJob deletes a job by ID; ownerID="" bypasses ownership check (admin).
	DeleteJob(ctx context.Context, id, ownerID string) error

	CreateRun(ctx context.Context, run *JobRun) error
	UpdateRun(ctx context.Context, run *JobRun) error
	ListRuns(ctx context.Context, jobID string, limit int) ([]*JobRun, error)
	GetRun(ctx context.Context, id string) (*JobRun, error)
}

JobStore is the persistence interface for automation jobs and their runs.

type MemoryStateStore

type MemoryStateStore struct {
	// contains filtered or unexported fields
}

MemoryStateStore is an in-process store with no persistence. Suitable for testing or ephemeral single-run scenarios.

func NewMemoryStateStore

func NewMemoryStateStore() *MemoryStateStore

func (*MemoryStateStore) Delete

func (m *MemoryStateStore) Delete(_ context.Context, name string) error

func (*MemoryStateStore) List

func (*MemoryStateStore) Load

func (*MemoryStateStore) Save

type Middleware

type Middleware func(next ExecuteFunc) ExecuteFunc

Middleware wraps an ExecuteFunc to add cross-cutting behaviour. Middlewares are applied innermost-first: Chain(A, B, C) produces A(B(C(core))).

func Chain

func Chain(middlewares ...Middleware) Middleware

Chain composes a slice of middlewares into a single middleware. The first middleware is the outermost (runs first on entry, last on exit).

func WithLogging

func WithLogging(logger *log.Logger) Middleware

WithLogging logs workflow start, completion, and errors to logger. Pass nil to use the default log package.

func WithMetrics

func WithMetrics(onResult func(Result)) Middleware

WithMetrics calls onResult after every execution (success or failure). Use this to feed Prometheus counters, Datadog metrics, or custom logging.

func WithRecovery

func WithRecovery() Middleware

WithRecovery catches panics from the workflow, converts them to errors, and ensures the Result is always populated.

func WithRetry

func WithRetry(maxAttempts int, backoff time.Duration) Middleware

WithRetry retries a failed workflow up to maxAttempts additional times, waiting backoff (doubled each attempt) between attempts. Overrides opts.MaxRetries and opts.RetryBackoff when both are non-zero.

func WithTimeout

func WithTimeout(d time.Duration) Middleware

WithTimeout cancels the workflow if it exceeds d. Opts.Timeout takes precedence when non-zero.

type MultiSink

type MultiSink struct {
	Sinks []Sink
}

MultiSink fans a Result out to multiple sinks. All sinks are called even if one errors; errors are joined.

func NewMultiSink

func NewMultiSink(sinks ...Sink) *MultiSink

func (*MultiSink) Write

func (m *MultiSink) Write(ctx context.Context, r Result) error

type OnceSchedule

type OnceSchedule struct {
	At time.Time
}

OnceSchedule fires exactly once at At.

func Once

func Once(at time.Time) *OnceSchedule

func (*OnceSchedule) Next

func (s *OnceSchedule) Next(from time.Time) time.Time

func (*OnceSchedule) String

func (s *OnceSchedule) String() string

type Options

type Options struct {
	// Model overrides the Runner's default model for this execution only.
	// Format: "provider:model" (e.g. "anthropic:claude-sonnet-4-6").
	Model string

	// DryRun skips actual LLM execution and returns an empty Result.
	// Useful for validating scheduler configuration without incurring cost.
	DryRun bool

	// Timeout caps the total wall-clock time for the workflow.
	// Zero means no per-execution timeout (context deadline still applies).
	Timeout time.Duration

	// MaxRetries is the number of additional attempts after a failure.
	// Zero means no retry. Used by WithRetry middleware.
	MaxRetries int

	// RetryBackoff is the initial wait between retries (doubles each attempt).
	// Defaults to 5s when zero and MaxRetries > 0.
	RetryBackoff time.Duration

	// Extra holds workflow-specific key-value options that are not part of
	// the standard contract. Workflows may inspect this map for opt-in features.
	Extra map[string]any
}

Options configure a single workflow execution. Workflow-specific parameters (e.g. topics, target path) belong in the workflow struct itself; Options covers cross-cutting execution concerns.

func DefaultOptions

func DefaultOptions() Options

DefaultOptions returns sensible defaults for interactive or scheduled runs.

func (Options) Get

func (o Options) Get(key string) any

Get retrieves a value from Extra. Returns nil if the key is absent.

func (*Options) Set

func (o *Options) Set(key string, value any)

Set stores a key-value pair in Extra, initialising the map if needed.

func (Options) WithDryRun

func (o Options) WithDryRun() Options

WithDryRun returns a copy of o with DryRun enabled.

func (Options) WithModel

func (o Options) WithModel(model string) Options

WithModel returns a copy of o with the model overridden.

func (Options) WithRetry

func (o Options) WithRetry(maxRetries int, backoff time.Duration) Options

WithRetry returns a copy of o with retry configured.

func (Options) WithTimeout

func (o Options) WithTimeout(d time.Duration) Options

WithTimeout returns a copy of o with the timeout set.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry is a thread-safe catalog of named workflows. Workflows are registered once at startup and looked up by name at runtime.

func NewRegistry

func NewRegistry() *Registry

NewRegistry returns an empty Registry.

func (*Registry) Get

func (r *Registry) Get(name string) (Workflow, bool)

Get returns the workflow registered under name, or (nil, false) if absent.

func (*Registry) Len

func (r *Registry) Len() int

Len returns the number of registered workflows.

func (*Registry) List

func (r *Registry) List() []Workflow

List returns all registered workflows sorted by name.

func (*Registry) MustRegister

func (r *Registry) MustRegister(w Workflow)

MustRegister calls Register and panics on error. Intended for package-level init blocks where duplicate registration is a programming error.

func (*Registry) Names

func (r *Registry) Names() []string

Names returns all registered workflow names sorted alphabetically.

func (*Registry) Register

func (r *Registry) Register(w Workflow) error

Register adds w to the registry. Returns an error if a workflow with the same name is already registered.

func (*Registry) Unregister

func (r *Registry) Unregister(name string)

Unregister removes w from the registry. No-op if the name is not present.

type Result

type Result struct {
	WorkflowName string
	StartedAt    time.Time
	FinishedAt   time.Time
	Duration     time.Duration
	Output       string // accumulated text streamed by the agent
	Error        error
	Metadata     map[string]any // arbitrary key-value pairs set by middleware or workflow
}

Result holds the complete outcome of a single workflow execution.

func (Result) Success

func (r Result) Success() bool

Success reports whether the workflow completed without error.

type RunStatus

type RunStatus string
const (
	RunStatusRunning RunStatus = "running"
	RunStatusSuccess RunStatus = "success"
	RunStatusError   RunStatus = "error"
)

type Runner

type Runner struct {
	// contains filtered or unexported fields
}

Runner creates a fresh SDK client for each workflow execution. It holds no mutable state, making it safe for concurrent use.

func NewRunner

func NewRunner(cfg RunnerConfig) (*Runner, error)

NewRunner builds a Runner from cfg.

func (*Runner) Close

func (r *Runner) Close()

Close is a no-op — Runner holds no long-lived resources.

func (*Runner) Execute

func (r *Runner) Execute(ctx context.Context, w Workflow, ec ExecuteConfig) error

Execute runs w against a fresh SDK client and session. A new client is created for every call, which ensures ExecuteConfig overrides (model, system prompt) are fully isolated between executions.

type RunnerConfig

type RunnerConfig struct {
	Model          sdk.ModelIdentifier
	ProviderConfig *providers.Config
	MaxTokens      int
	// WebSearchKeys provides per-owner web search provider keys.
	// When set, the web_search tool uses these keys instead of reading from the
	// process environment — required for safe multi-tenant execution.
	WebSearchKeys map[string]string
	// RAGService enables the rag_search/rag_ingest tools for this
	// execution when set. Callers embedding automation in a multi-tenant
	// host (e.g. seshat-ai/seshat-server) are expected to build one scoped
	// to the right organization/corpus namespace per execution, the same
	// way WebSearchKeys is resolved per owner rather than read from a
	// single process-wide config.
	RAGService *rag.Service
	// DoclingURL enables the read_document_url tool when set — fetches
	// and converts a remote document (PDF, webpage, ...) to markdown via a
	// running docling-serve instance. Unlike WebSearchKeys/RAGService this
	// isn't a secret or per-tenant value, so it's fine to read straight
	// from RunnerConfig rather than resolved per execution.
	DoclingURL string
}

RunnerConfig is the base template used to build an SDK client for each workflow execution.

type RunnerResolver

type RunnerResolver func(ctx context.Context, ownerID string, agentSlug string, modelOverride string) (*Runner, AgentConfig, error)

RunnerResolver resolves a per-owner Runner at execution time. agentSlug is the named agent to resolve (empty = no named agent). modelOverride is the job-level model override (may be empty). The second return value carries the resolved base AgentConfig from the named agent definition; the scheduler merges it with the job's inline AgentConfig (inline fields take precedence over the resolved base).

type Schedule

type Schedule interface {
	// Next returns the next time the schedule fires after from.
	// Returns the zero Time if the schedule never fires again.
	Next(from time.Time) time.Time
	// String returns a human-readable description of the schedule.
	String() string
}

Schedule computes the next trigger time after a given reference point.

type ScheduledRun

type ScheduledRun struct {
	WorkflowName string
	Schedule     string
	NextRun      time.Time
}

ScheduledRun is a read-only view of a single job's next execution.

type Scheduler

type Scheduler struct {
	// contains filtered or unexported fields
}

Scheduler runs registered workflows according to their schedules. It uses a single goroutine and a timer-based loop; it does not spawn a goroutine per job. Concurrent job execution is not supported by design — use multiple Schedulers if you need parallel pipelines.

func NewScheduler

func NewScheduler(executor *Executor) *Scheduler

NewScheduler creates a Scheduler backed by executor.

func (*Scheduler) Add

func (s *Scheduler) Add(w Workflow, schedule Schedule, opts Options) *Scheduler

Add registers a workflow with its schedule and options. Returns the Scheduler to allow method chaining.

func (*Scheduler) Next

func (s *Scheduler) Next() []ScheduledRun

Next returns a snapshot of the upcoming scheduled runs, sorted by time.

func (*Scheduler) Run

func (s *Scheduler) Run(ctx context.Context) error

Run blocks and runs scheduled jobs until ctx is cancelled. It ticks at most once per second to avoid busy-wait.

func (*Scheduler) RunNow

func (s *Scheduler) RunNow(ctx context.Context, name string, opts Options) (Result, error)

RunNow immediately executes the workflow registered under name, bypassing the schedule. Returns ErrNotFound if the name is not registered.

type Sink

type Sink interface {
	Write(ctx context.Context, r Result) error
}

Sink receives a completed Result after a workflow finishes. Sinks are called sequentially by the Executor; use MultiSink for fan-out.

type StateStore

type StateStore interface {
	Load(ctx context.Context, workflowName string) (*ExecutionState, error)
	Save(ctx context.Context, state ExecutionState) error
	List(ctx context.Context) ([]ExecutionState, error)
	Delete(ctx context.Context, workflowName string) error
}

StateStore persists and retrieves execution state across process restarts.

type StdoutSink

type StdoutSink struct {
	// Quiet suppresses the footer when true.
	Quiet bool
}

StdoutSink prints a human-readable summary of the result to stdout. The workflow's streaming output is already printed in real time via StreamFn; StdoutSink adds a completion footer (duration, status).

func (*StdoutSink) Write

func (s *StdoutSink) Write(_ context.Context, r Result) error

type SystemPrompter

type SystemPrompter interface {
	SystemPrompt() string
}

SystemPrompter is an optional interface a Workflow can implement to provide a fully custom system prompt that replaces the Seshat default. When satisfied, the Executor builds a dedicated SDK client for that execution.

type Trigger

type Trigger struct {
	Type     TriggerType
	Cron     string        // valid when Type == TriggerTypeCron
	Interval time.Duration // valid when Type == TriggerTypeInterval
	RunAt    *time.Time    // valid when Type == TriggerTypeOnce
}

Trigger defines when an automation job fires.

func (Trigger) String

func (t Trigger) String() string

func (Trigger) ToSchedule

func (t Trigger) ToSchedule() (Schedule, error)

ToSchedule converts a Trigger to the Schedule interface used by the engine.

type TriggerType

type TriggerType string
const (
	TriggerTypeCron     TriggerType = "cron"
	TriggerTypeInterval TriggerType = "interval"
	TriggerTypeOnce     TriggerType = "once"
)

type WebhookSink

type WebhookSink struct {
	URL     string
	Headers map[string]string
	// Timeout for the HTTP request. Defaults to 15s.
	Timeout time.Duration
	// contains filtered or unexported fields
}

WebhookSink sends the result as a JSON POST to a URL.

func NewWebhookSink

func NewWebhookSink(url string) *WebhookSink

func (*WebhookSink) Write

func (s *WebhookSink) Write(ctx context.Context, r Result) error

type Workflow

type Workflow interface {
	Name() string
	Description() string
	Run(ctx context.Context, session *sdk.Session) error
}

Workflow is the interface every automation workflow must implement.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL