package task import ( "time" ) type State string const ( StatePending State = "PENDING" StateQueued State = "QUEUED" StateRunning State = "RUNNING" StateReady State = "READY" StateCompleted State = "COMPLETED" StateFailed State = "FAILED" StateTimedOut State = "TIMED_OUT" StateCancelled State = "CANCELLED" StateBudgetExceeded State = "BUDGET_EXCEEDED" StateBlocked State = "BLOCKED" ) type Priority string const ( PriorityHigh Priority = "high" PriorityNormal Priority = "normal" PriorityLow Priority = "low" ) type AgentConfig struct { Type string `yaml:"type" json:"type"` Model string `yaml:"model" json:"model"` ContextFiles []string `yaml:"context_files" json:"context_files"` Instructions string `yaml:"instructions" json:"instructions"` RepositoryURL string `yaml:"repository_url" json:"repository_url"` ContainerImage string `yaml:"container_image" json:"container_image"` ProjectDir string `yaml:"project_dir" json:"project_dir"` // Deprecated: use Task.RepositoryURL MaxBudgetUSD float64 `yaml:"max_budget_usd" json:"max_budget_usd"` PermissionMode string `yaml:"permission_mode" json:"permission_mode"` AllowedTools []string `yaml:"allowed_tools" json:"allowed_tools"` DisallowedTools []string `yaml:"disallowed_tools" json:"disallowed_tools"` SystemPromptAppend string `yaml:"system_prompt_append" json:"system_prompt_append"` AdditionalArgs []string `yaml:"additional_args" json:"additional_args"` SkipPlanning bool `yaml:"skip_planning" json:"skip_planning"` } type RetryConfig struct { MaxAttempts int `yaml:"max_attempts" json:"max_attempts"` Backoff string `yaml:"backoff" json:"backoff"` // "linear", "exponential" } // GitCommit represents a single git commit created during a task execution. type GitCommit struct { Hash string `json:"hash"` Message string `json:"message"` } // Changestats records file/line change metrics from an agent execution. type Changestats struct { FilesChanged int `json:"files_changed"` LinesAdded int `json:"lines_added"` LinesRemoved int `json:"lines_removed"` } // Interaction records a single question/answer exchange between an agent and the user. type Interaction struct { QuestionText string `json:"question_text"` Options []string `json:"options,omitempty"` Answer string `json:"answer,omitempty"` AskedAt time.Time `json:"asked_at"` } type Task struct { ID string `yaml:"id" json:"id"` ParentTaskID string `yaml:"parent_task_id" json:"parent_task_id"` Name string `yaml:"name" json:"name"` Description string `yaml:"description" json:"description"` Project string `yaml:"project" json:"project"` // Human-readable project name RepositoryURL string `yaml:"repository_url" json:"repository_url"` Agent AgentConfig `yaml:"agent" json:"agent"` Timeout Duration `yaml:"timeout" json:"timeout"` Retry RetryConfig `yaml:"retry" json:"retry"` Priority Priority `yaml:"priority" json:"priority"` Tags []string `yaml:"tags" json:"tags"` DependsOn []string `yaml:"depends_on" json:"depends_on"` State State `yaml:"-" json:"state"` RejectionComment string `yaml:"-" json:"rejection_comment,omitempty"` QuestionJSON string `yaml:"-" json:"question,omitempty"` ElaborationInput string `yaml:"-" json:"elaboration_input,omitempty"` Summary string `yaml:"-" json:"summary,omitempty"` Interactions []Interaction `yaml:"-" json:"interactions,omitempty"` CreatedAt time.Time `yaml:"-" json:"created_at"` UpdatedAt time.Time `yaml:"-" json:"updated_at"` } // Duration wraps time.Duration for YAML unmarshaling from strings like "30m". type Duration struct { time.Duration } func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error { var s string if err := unmarshal(&s); err != nil { return err } dur, err := time.ParseDuration(s) if err != nil { return err } d.Duration = dur return nil } func (d Duration) MarshalYAML() (interface{}, error) { return d.Duration.String(), nil } // BatchFile represents a YAML file containing multiple tasks. type BatchFile struct { Tasks []Task `yaml:"tasks"` } // validTransitions maps each state to the set of states it may transition into. // COMPLETED is the only true terminal state (no outgoing edges). // CANCELLED, FAILED, TIMED_OUT, and BUDGET_EXCEEDED all allow re-entry at QUEUED // (restart or retry). // READY may go back to PENDING on user rejection. // BLOCKED may advance to READY when all subtasks complete, or back to QUEUED on user answer. var validTransitions = map[State]map[State]bool{ StatePending: {StateQueued: true, StateCancelled: true}, StateQueued: {StateRunning: true, StateCancelled: true}, StateRunning: {StateReady: true, StateCompleted: true, StateFailed: true, StateTimedOut: true, StateCancelled: true, StateBudgetExceeded: true, StateBlocked: true}, StateReady: {StateCompleted: true, StatePending: true}, StateFailed: {StateQueued: true}, // retry StateTimedOut: {StateQueued: true}, // retry or resume StateCancelled: {StateQueued: true}, // restart StateBudgetExceeded: {StateQueued: true}, // retry StateBlocked: {StateQueued: true, StateReady: true, StateCancelled: true}, } // ValidTransition returns true if moving from the current state to next is allowed. func ValidTransition(from, to State) bool { return validTransitions[from][to] }