schedule

package
v0.22.0 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2026 License: AGPL-3.0 Imports: 26 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// RunTargetNewSession creates a fresh user-visible session per fire.
	RunTargetNewSession = "new_session"
	// RunTargetExistingSession reuses one stored session for every fire.
	// The target session pins runtime and workdir; only model and
	// reasoning effort stay overridable per schedule.
	RunTargetExistingSession = "existing_session"
)

Run targets: where one fire of a schedule executes.

View Source
const (
	RuntimeModel    = string(runtimekind.Model)
	RuntimeACPAgent = string(runtimekind.ACPAgent)
)

Runtime types are the bot_sessions vocabulary, pinned to the shared runtimekind table (the schedule domain cannot import the chat packages).

View Source
const (
	RunStatusRunning = "running"
	RunStatusOK      = "ok"
	RunStatusError   = "error"
)

Run statuses a RunSession reports. RunStatusRunning is derived from a log row with no completed_at; the other two are the stored outcome.

Variables

View Source
var (
	// ErrScheduleNotFound marks a schedule ID that matches no row.
	ErrScheduleNotFound      = errors.New("schedule not found")
	ErrTargetSessionRequired = requiredField("target_session_id", "target_session_id is required for existing_session run target")
	ErrTargetSessionNotFound = invalidField("target_session_id", "target session not found")
	// ErrTargetSessionGone marks a fire whose stored target session no
	// longer exists; the trigger path reports it and disables the schedule.
	ErrTargetSessionGone = errors.New("target session was deleted")
	ErrExecutionTimeout  = errors.New("schedule execution budget expired")
	// ErrModelRequired marks a schedule that would open a fresh session with
	// no model to run it: the bot has no default and none was given.
	ErrModelRequired = ruleViolation(RuleModelRequired, "model_id", "this bot has no default model, so a scheduled run needs an explicit model")
)
View Source
var ErrSessionBusy = errors.New("session busy")

ErrSessionBusy is returned by a Triggerer when the target session already has an active run. The fire is dropped, not retried.

Functions

This section is empty.

Types

type CreateRequest

type CreateRequest struct {
	Name        string      `json:"name"`
	Description string      `json:"description"`
	Pattern     string      `json:"pattern"`
	MaxCalls    NullableInt `json:"max_calls,omitempty"`
	Command     string      `json:"command"`
	Enabled     *bool       `json:"enabled,omitempty"`
	ExecutionConfig
}

type ExecutionConfig

type ExecutionConfig struct {
	// MaxRunSeconds is the execution budget (300-86400 seconds); zero uses one hour.
	MaxRunSeconds int `json:"max_run_seconds,omitempty"`
	// RunTarget is new_session (default) or existing_session.
	RunTarget string `json:"run_target,omitempty"`
	// TargetSessionID names the session reused by existing_session mode.
	TargetSessionID string `json:"target_session_id,omitempty"`
	// RuntimeType selects the runtime for new sessions: "" or "model" for
	// the native model runtime, "acp_agent" for an ACP agent. Must be empty
	// in existing_session mode (inherited from the target session).
	RuntimeType string `json:"runtime_type,omitempty"`
	// BotAgentID selects one persisted BotAgent for a new session. Empty means
	// the built-in Native runtime (or the legacy ACP fields below).
	BotAgentID string `json:"bot_agent_id,omitempty"`
	// ACPAgentID names the ACP agent when RuntimeType is acp_agent.
	ACPAgentID string `json:"acp_agent_id,omitempty"`
	// ModelID is a native model UUID override (models.id).
	ModelID string `json:"model_id,omitempty"`
	// ACPModelID is an agent-reported model identifier override for External
	// Agent runs. Mutually exclusive with ModelID.
	ACPModelID string `json:"acp_model_id,omitempty"`
	// ReasoningEffort overrides the reasoning effort for this schedule.
	ReasoningEffort string `json:"reasoning_effort,omitempty"`
	// WorkdirID binds new sessions to a bot workdir. Must be empty in
	// existing_session mode (inherited from the target session).
	WorkdirID string `json:"workdir_id,omitempty"`
}

ExecutionConfig is the per-schedule execution parameter block: where a fire runs and with which runtime/model/effort/workdir. The zero value means "new session with all bot defaults" — exactly the pre-parameter behavior.

type InvalidRequestError

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

InvalidRequestError marks user-correctable validation failures so the API layer can answer 400 instead of 500. msg is the sentence callers such as the agent tool show to a model; field is the request field the user has to fix, written as the request spells it.

func (InvalidRequestError) Error

func (e InvalidRequestError) Error() string

func (InvalidRequestError) Field added in v0.22.0

func (e InvalidRequestError) Field() string

Field is the request field the failure is about.

func (InvalidRequestError) Required added in v0.22.0

func (e InvalidRequestError) Required() bool

Required reports that the field is missing rather than holding a bad value.

func (InvalidRequestError) Rule added in v0.22.0

func (e InvalidRequestError) Rule() Rule

Rule is the broken validation rule, empty for a plain field problem.

type ListLogsResponse

type ListLogsResponse struct {
	Items      []Log `json:"items"`
	TotalCount int64 `json:"total_count"`
}

type ListResponse

type ListResponse struct {
	Items []Schedule `json:"items"`
}

type ListRunSessionsResponse added in v0.22.0

type ListRunSessionsResponse struct {
	Items      []RunSession `json:"items"`
	NextCursor string       `json:"next_cursor"`
}

ListRunSessionsResponse carries one page of a schedule's runs, newest first. NextCursor is empty exactly when there are no older runs.

type Log

type Log struct {
	ID         string `json:"id"`
	ScheduleID string `json:"schedule_id"`
	BotID      string `json:"bot_id"`
	SessionID  string `json:"session_id,omitempty"`
	Status     string `json:"status"`
	ResultText string `json:"result_text"`
	// ErrorMessage is the text an earlier server stored; new failures set
	// ErrorCode and leave it empty.
	ErrorMessage string     `json:"error_message"`
	ErrorCode    string     `json:"error_code,omitempty"`
	Usage        any        `json:"usage,omitempty"`
	StartedAt    time.Time  `json:"started_at"`
	CompletedAt  *time.Time `json:"completed_at,omitempty"`
}

type NullableInt

type NullableInt struct {
	Value *int
	Set   bool
}

func (NullableInt) IsZero

func (n NullableInt) IsZero() bool

func (NullableInt) MarshalJSON

func (n NullableInt) MarshalJSON() ([]byte, error)

func (*NullableInt) UnmarshalJSON

func (n *NullableInt) UnmarshalJSON(data []byte) error

type Rule added in v0.22.0

type Rule string

Rule names the validation rule a request broke when the fix needs more than the field's name. The API layer gives each rule its own public error.

const (
	// RuleRunTargetConflict: run target, runtime, agent and session settings
	// that cannot be combined.
	RuleRunTargetConflict Rule = "run_target_conflict"
	// RuleModelConflict: a model setting that does not fit the runtime or
	// collides with another model setting.
	RuleModelConflict Rule = "model_conflict"
	// RuleModelUnusable: the model exists but a schedule cannot run on it.
	RuleModelUnusable Rule = "model_unusable"
	// RuleSessionModeUnsupported: the target session is of a mode that cannot
	// host scheduled runs.
	RuleSessionModeUnsupported Rule = "session_mode_unsupported"
	// RuleModelRequired: a fresh session would have no model to run on.
	RuleModelRequired Rule = "model_required"
)

type RunSession added in v0.22.0

type RunSession struct {
	// LogID identifies the fire (schedule_logs.id).
	LogID string `json:"log_id"`
	// SessionID is empty when the fire failed before any session existed.
	SessionID string `json:"session_id"`
	// Title is the session title, empty when there is no session.
	Title string `json:"title"`
	// Status is running while the fire has not completed, then ok or error.
	Status    string    `json:"status" enums:"running,ok,error"`
	ErrorCode string    `json:"error_code"`
	StartedAt time.Time `json:"started_at"`
	// CompletedAt is null while the fire is still running.
	CompletedAt *time.Time `json:"completed_at" extensions:"x-nullable"`
}

RunSession is one fire of a schedule together with the session it ran in.

type Schedule

type Schedule struct {
	ID           string    `json:"id"`
	Name         string    `json:"name"`
	Description  string    `json:"description"`
	Pattern      string    `json:"pattern"`
	MaxCalls     *int      `json:"max_calls,omitempty"`
	CurrentCalls int       `json:"current_calls"`
	CreatedAt    time.Time `json:"created_at"`
	UpdatedAt    time.Time `json:"updated_at"`
	Enabled      bool      `json:"enabled"`
	Command      string    `json:"command"`
	BotID        string    `json:"bot_id"`
	ExecutionConfig
}

type Service

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

func NewService

func NewService(log *slog.Logger, queries dbstore.Queries, triggerer Triggerer, sessionCreator SessionCreator, workdirService *workdir.Service, runtimeConfig *boot.RuntimeConfig) *Service

func (*Service) Bootstrap

func (s *Service) Bootstrap(ctx context.Context) error

func (*Service) Create

func (s *Service) Create(ctx context.Context, botID string, req CreateRequest) (Schedule, error)

func (*Service) Delete

func (s *Service) Delete(ctx context.Context, id string) error

func (*Service) DeleteLogs

func (s *Service) DeleteLogs(ctx context.Context, botID string) error

func (*Service) Get

func (s *Service) Get(ctx context.Context, id string) (Schedule, error)

func (*Service) List

func (s *Service) List(ctx context.Context, botID string) ([]Schedule, error)

func (*Service) ListLogs

func (s *Service) ListLogs(ctx context.Context, botID string, limit, offset int) ([]Log, int64, error)

func (*Service) ListLogsBySchedule

func (s *Service) ListLogsBySchedule(ctx context.Context, scheduleID string, limit, offset int) ([]Log, int64, error)

func (*Service) ListRunSessions added in v0.22.0

func (s *Service) ListRunSessions(ctx context.Context, botID, scheduleID string, limit int, cursor string) (ListRunSessionsResponse, error)

ListRunSessions returns one page of a schedule's fires, newest first, each with the session it ran in. A fire whose session was deleted is left out; a fire that failed before it had a session is kept. A schedule that belongs to another bot answers ErrScheduleNotFound, exactly like an unknown one, so schedule ids cannot be probed across bots. limit outside 1..100 falls back to 20 or is capped at 100. cursor is the NextCursor of the previous page, or empty for the first page; a malformed cursor is an invalid "cursor" field.

func (*Service) SetBotAgents

func (s *Service) SetBotAgents(service *botagents.Service)

func (*Service) SetEventPublisher added in v0.21.0

func (s *Service) SetEventPublisher(publisher messageevent.Publisher)

SetEventPublisher wires bot-scoped schedule snapshot invalidations.

func (*Service) Shutdown added in v0.21.0

func (s *Service) Shutdown(ctx context.Context) error

Shutdown cancels owned fires before waiting for cron workers to unwind.

func (*Service) Trigger

func (s *Service) Trigger(ctx context.Context, scheduleID string) error

func (*Service) Update

func (s *Service) Update(ctx context.Context, id string, req UpdateRequest) (Schedule, error)

type SessionCreator

type SessionCreator interface {
	CreateSession(ctx context.Context, botID, sessionType string) (string, error)
	// CreateScheduleSession creates the user-visible session one fire of a
	// schedule runs in, honoring the schedule's runtime and workdir.
	CreateScheduleSession(ctx context.Context, spec SessionSpec) (string, error)
}

SessionCreator creates sessions for schedule runs.

type SessionSpec

type SessionSpec struct {
	BotID string
	// BotAgentID is empty for Native and set for a persisted Agent selection.
	BotAgentID string
	// Title labels the session in user-facing lists (the schedule name).
	Title string
	// RuntimeType selects the Native or External Agent runtime.
	RuntimeType string
	// ACPAgentID names the agent when RuntimeType is RuntimeACPAgent.
	ACPAgentID string
	// WorkdirID optionally binds the session to a bot workdir.
	WorkdirID string
	// OwnerUserID becomes the session creator and, for External Agent sessions, the
	// runtime owner account.
	OwnerUserID string
}

SessionSpec describes the session one schedule fire runs in. The creator (wired in the composition root) resolves the workdir path and assembles ACP runtime metadata; the schedule domain only states intent.

type TriggerPayload

type TriggerPayload struct {
	FireID      string
	ID          string
	Name        string
	Description string
	Pattern     string
	MaxCalls    *int
	Command     string
	OwnerUserID string
	SessionID   string
	// ModelID / RuntimeModelID / ReasoningEffort are the schedule's per-run
	// overrides. Which runtime executes the run is decided by the session
	// itself (its runtime_type and metadata), never by the payload.
	ModelID         string
	RuntimeModelID  string
	ReasoningEffort string
}

TriggerPayload describes the parameters passed to the chat side when a schedule triggers.

type TriggerResult

type TriggerResult struct {
	Status     string
	Text       string
	UsageBytes []byte
	ModelID    string
}

TriggerResult carries execution metadata back from the resolver.

type Triggerer

type Triggerer interface {
	TriggerSchedule(ctx context.Context, botID string, payload TriggerPayload, token string) (TriggerResult, error)
}

Triggerer triggers schedule execution for chat-related jobs.

type UpdateRequest

type UpdateRequest struct {
	Name        *string     `json:"name,omitempty"`
	Description *string     `json:"description,omitempty"`
	Pattern     *string     `json:"pattern,omitempty"`
	MaxCalls    NullableInt `json:"max_calls,omitempty"`
	Command     *string     `json:"command,omitempty"`
	Enabled     *bool       `json:"enabled,omitempty"`
	// Execution replaces the whole execution parameter block when present.
	// Field-level patching is deliberately not offered: the block carries
	// cross-field constraints (run target vs runtime vs workdir), so
	// callers send the full desired state and the service validates it as
	// one unit.
	Execution *ExecutionConfig `json:"execution,omitempty"`
}

type WorkdirValidator

type WorkdirValidator interface {
	RequireActive(ctx context.Context, botID, workdirID string) (workdir.Workdir, error)
}

WorkdirValidator is the slice of the workdir domain the schedule service needs to validate a workdir binding at create/update time.

Jump to

Keyboard shortcuts

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