- Removed extensive sections on Manager and Executor implementations to focus on high-level concepts and integration points. - Consolidated error handling and global singleton sections for clarity and brevity. - Updated the structure of the document to enhance readability and ensure a more cohesive presentation of the autonomous agent's functionality.
33 KiB
33 KiB
Autonomous Agent - Technical Design
1. Code Structure
yao/agent/autonomous/
├── DESIGN.md # Product design doc
├── TECHNICAL.md # This file
│
├── autonomous.go # Package entry, Init(), Shutdown()
│
├── api/ # All API forms
│ ├── api.go # Go API (facade)
│ ├── process.go # Yao Process: autonomous.*
│ └── jsapi.go # JS API for scripts
│
├── types/ # Types only (no logic, no external deps)
│ ├── enums.go # Phase, ClockMode, TriggerType, etc.
│ ├── config.go # Config, Clock, Identity, Quota, etc.
│ ├── robot.go # Robot, Execution
│ ├── task.go # Goal, Task, TaskResult
│ ├── request.go # InterveneRequest, EventRequest, etc.
│ ├── inspiration.go # ClockContext, InspirationReport
│ ├── interfaces.go # All interfaces (Manager, Trigger, etc.)
│ └── errors.go # Error definitions
│
├── manager/ # Manager package (orchestration)
│ ├── manager.go # Manager struct, Start/Stop, ticker loop
│ └── lifecycle.go # OnRobotCreate/Delete/Update
│
├── pool/ # Worker pool & task dispatch
│ ├── pool.go # Pool struct, Submit
│ ├── queue.go # Priority queue
│ └── worker.go # Worker goroutines
│
├── executor/ # Executor package
│ ├── executor.go # Executor struct, Execute
│ ├── phase.go # RunPhase dispatcher
│ ├── inspiration.go # P0: Inspiration (clock only)
│ ├── goals.go # P1: Goal generation
│ ├── tasks.go # P2: Task planning
│ ├── run.go # P3: Task execution
│ ├── delivery.go # P4: Delivery
│ ├── learning.go # P5: Learning
│ ├── agent.go # Call assistant/agent unified method
│ └── prompt.go # Prompt building helpers
│
├── utils/ # Utility functions
│ ├── convert.go # Type conversions (JSON, map, struct)
│ ├── time.go # Time parsing, formatting, timezone
│ ├── id.go # ID generation (nanoid, uuid)
│ └── validate.go # Validation helpers
│
├── trigger/ # All trigger sources
│ ├── trigger.go # Trigger interface & dispatcher
│ ├── clock.go # Clock trigger (tick, schedule matching)
│ ├── intervene.go # Human intervention trigger
│ ├── event.go # Event trigger (webhook, db change)
│ └── control.go # Pause/Resume/Cancel
│
├── cache/ # Cache package
│ ├── cache.go # Cache struct, Get/List
│ ├── load.go # LoadAll, LoadOne
│ └── refresh.go # Refresh logic
│
├── dedup/ # Deduplication package
│ ├── dedup.go # Dedup struct
│ ├── fast.go # Fast in-memory check
│ └── semantic.go # Semantic check via agent
│
├── store/ # Data store package (KB, FS, DB access)
│ ├── store.go # Store struct, interface
│ ├── kb.go # Knowledge base operations
│ ├── fs.go # File system operations
│ ├── db.go # Database queries
│ └── learning.go # Learning entry save (to KB)
│
├── job/ # Job system integration
│ ├── job.go # Create/Get job for robot
│ ├── execution.go # Create/Update execution
│ └── log.go # Write execution logs
│
└── plan/ # Plan queue (deferred tasks)
├── plan.go # Plan queue struct
└── schedule.go # Schedule for later
Dependency Graph (No Cycles)
┌──────────┐
│ types/ │ (pure types, no deps)
└────┬─────┘
│
┌───────┬───────┬───────┬──────┼──────┬───────┬───────┬───────┐
│ │ │ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
┌───────┐┌───────┐┌───────┐┌──────┐┌────┐┌──────┐┌───────┐
│ cache ││ dedup ││ store ││ pool ││job ││ plan ││ utils │
└───┬───┘└───┬───┘└───┬───┘└──┬───┘└──┬─┘└──────┘└───────┘
│ │ │ │ │
└────────┴────────┴───────┴───────┘
│
┌──────────────┴──────────────┐
│ │
▼ ▼
┌────────────┐ ┌────────────┐
│ trigger/ │ │ executor/ │
└──────┬─────┘ └──────┬─────┘
│ │
└──────────────┬──────────────┘
│
▼
┌────────────┐
│ manager/ │
└──────┬─────┘
│
┌──────────────┴──────────────┐
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│autonomous.go│ │ api/ │
└─────────────┘ └─────────────┘
Package Dependencies
| Package | Imports |
|---|---|
types/ |
stdlib only |
utils/ |
stdlib only |
cache/ |
types/ |
dedup/ |
types/ |
store/ |
types/ |
pool/ |
types/ |
trigger/ |
types/, cache/ |
job/ |
types/, yao/job |
plan/ |
types/ |
executor/ |
types/, cache/, dedup/, store/, pool/, job/ |
manager/ |
types/, cache/, pool/, trigger/, executor/ |
api/ |
types/, manager/, trigger/ |
| root | all packages |
Public API (api/)
三种 API 形态,统一放在 api/ 目录下:
Go API (api/api.go)
package api
// Robot Management
func GetRobot(memberID string) (*types.Robot, error)
func ListRobots(teamID string) ([]*types.Robot, error)
func RefreshRobot(memberID string) error
// Triggers
func Intervene(req *types.InterveneRequest) (*types.ExecutionResult, error)
func HandleEvent(req *types.EventRequest) (*types.ExecutionResult, error)
// Control
func GetStatus(memberID string) (*types.RobotState, error)
func Pause(memberID string) error
func Resume(memberID string) error
func Cancel(memberID, executionID string) error
// Query
func GetExecution(executionID string) (*types.Execution, error)
func ListExecutions(memberID string, limit int) ([]*types.Execution, error)
Yao Process (api/process.go)
// autonomous.GetRobot(memberID) -> Robot
// autonomous.ListRobots(teamID) -> []Robot
// autonomous.Intervene(teamID, memberID, action, description, priority) -> ExecutionResult
// autonomous.HandleEvent(memberID, source, eventType, data) -> ExecutionResult
// autonomous.GetStatus(memberID) -> RobotState
// autonomous.Pause(memberID) -> bool
// autonomous.Resume(memberID) -> bool
// autonomous.Cancel(memberID, executionID) -> bool
// autonomous.GetExecution(executionID) -> Execution
// autonomous.ListExecutions(memberID, limit) -> []Execution
JS API (api/jsapi.go)
// In Yao scripts
const robot = $autonomous.GetRobot("member_123");
const result = $autonomous.Intervene({
member_id: "member_123",
action: "add_task",
description: "Prepare report",
});
const status = $autonomous.GetStatus("member_123");
2. Type Definitions
All types are in
autonomous/types/package. Other files import as:import "github.com/yaoapp/yao/agent/autonomous/types"
2.1 Enums
// types/enums.go
package types
// Phase - execution phase
type Phase string
const (
PhaseInspiration Phase = "inspiration" // P0: Clock only
PhaseGoals Phase = "goals" // P1
PhaseTasks Phase = "tasks" // P2
PhaseRun Phase = "run" // P3
PhaseDelivery Phase = "delivery" // P4
PhaseLearning Phase = "learning" // P5
)
// AllPhases for iteration
var AllPhases = []Phase{
PhaseInspiration, PhaseGoals, PhaseTasks,
PhaseRun, PhaseDelivery, PhaseLearning,
}
// ClockMode - clock trigger mode
type ClockMode string
const (
ClockTimes ClockMode = "times" // run at specific times
ClockInterval ClockMode = "interval" // run every X duration
ClockDaemon ClockMode = "daemon" // run continuously
)
// TriggerType - trigger source
type TriggerType string
const (
TriggerClock TriggerType = "clock"
TriggerHuman TriggerType = "human"
TriggerEvent TriggerType = "event"
)
// ExecStatus - execution status
type ExecStatus string
const (
ExecPending ExecStatus = "pending"
ExecRunning ExecStatus = "running"
ExecCompleted ExecStatus = "completed"
ExecFailed ExecStatus = "failed"
ExecCancelled ExecStatus = "cancelled"
)
// RobotStatus - matches __yao.member.robot_status
type RobotStatus string
const (
RobotIdle RobotStatus = "idle"
RobotWorking RobotStatus = "working"
RobotPaused RobotStatus = "paused"
RobotError RobotStatus = "error"
RobotMaintenance RobotStatus = "maintenance"
)
// DeliveryType - output delivery type
type DeliveryType string
const (
DeliveryEmail DeliveryType = "email"
DeliveryFile DeliveryType = "file"
DeliveryWebhook DeliveryType = "webhook"
DeliveryNotify DeliveryType = "notify"
)
// DedupResult - deduplication result
type DedupResult string
const (
DedupSkip DedupResult = "skip" // skip execution
DedupMerge DedupResult = "merge" // merge with existing
DedupProceed DedupResult = "proceed" // proceed normally
)
// InterventionAction - human intervention actions
type InterventionAction string
const (
ActionAddTask InterventionAction = "add_task"
ActionAdjustGoal InterventionAction = "adjust_goal"
ActionCancelTask InterventionAction = "cancel_task"
ActionPause InterventionAction = "pause"
ActionResume InterventionAction = "resume"
ActionAbort InterventionAction = "abort"
ActionPlan InterventionAction = "plan"
)
// Priority levels
type Priority string
const (
PriorityHigh Priority = "high"
PriorityNormal Priority = "normal"
PriorityLow Priority = "low"
)
2.2 Config Types
// types/config.go
package types
import "time"
// Config - robot_config in __yao.member
type Config struct {
Triggers *Triggers `json:"triggers,omitempty"`
Clock *Clock `json:"clock,omitempty"`
Identity *Identity `json:"identity"`
Quota *Quota `json:"quota,omitempty"`
PrivateKB *KBConfig `json:"private_kb,omitempty"`
SharedKB *KBConfig `json:"shared_kb,omitempty"`
Resources *Resources `json:"resources,omitempty"`
Delivery *Delivery `json:"delivery,omitempty"`
Events []Event `json:"events,omitempty"`
Monitor *Monitor `json:"monitor,omitempty"`
}
// Validate validates the config
func (c *Config) Validate() error {
if c.Identity == nil || c.Identity.Role == "" {
return ErrMissingIdentity
}
if c.Clock != nil {
if err := c.Clock.Validate(); err != nil {
return err
}
}
return nil
}
// Triggers - trigger enable/disable
type Triggers struct {
Clock *TriggerSwitch `json:"clock,omitempty"`
Intervene *TriggerSwitch `json:"intervene,omitempty"`
Event *TriggerSwitch `json:"event,omitempty"`
}
type TriggerSwitch struct {
Enabled bool `json:"enabled"`
Actions []string `json:"actions,omitempty"` // for intervene
}
// IsEnabled checks if trigger is enabled (default: true)
func (t *Triggers) IsEnabled(typ TriggerType) bool {
if t == nil {
return true
}
switch typ {
case TriggerClock:
return t.Clock == nil || t.Clock.Enabled
case TriggerHuman:
return t.Intervene == nil || t.Intervene.Enabled
case TriggerEvent:
return t.Event == nil || t.Event.Enabled
}
return false
}
// Clock - when to wake up
type Clock struct {
Mode ClockMode `json:"mode"` // times | interval | daemon
Times []string `json:"times,omitempty"` // ["09:00", "14:00"]
Days []string `json:"days,omitempty"` // ["Mon", "Tue"] or ["*"]
Every string `json:"every,omitempty"` // "30m", "1h"
TZ string `json:"tz,omitempty"` // "Asia/Shanghai"
Timeout string `json:"timeout,omitempty"` // "30m"
}
// Validate validates clock config
func (c *Clock) Validate() error {
switch c.Mode {
case ClockTimes:
if len(c.Times) == 0 {
return ErrClockTimesEmpty
}
case ClockInterval:
if c.Every == "" {
return ErrClockIntervalEmpty
}
case ClockDaemon:
// no extra validation
default:
return ErrClockModeInvalid
}
return nil
}
// GetTimeout returns parsed timeout duration
func (c *Clock) GetTimeout() time.Duration {
if c.Timeout == "" {
return 30 * time.Minute // default
}
d, err := time.ParseDuration(c.Timeout)
if err != nil {
return 30 * time.Minute
}
return d
}
// GetLocation returns timezone location
func (c *Clock) GetLocation() *time.Location {
if c.TZ == "" {
return time.Local
}
loc, err := time.LoadLocation(c.TZ)
if err != nil {
return time.Local
}
return loc
}
// Identity - who is this robot
type Identity struct {
Role string `json:"role"`
Duties []string `json:"duties,omitempty"`
Rules []string `json:"rules,omitempty"`
}
// Quota - concurrency limits
type Quota struct {
Max int `json:"max"` // max running (default: 2)
Queue int `json:"queue"` // queue size (default: 10)
Priority int `json:"priority"` // 1-10 (default: 5)
}
// GetMax returns max with default
func (q *Quota) GetMax() int {
if q == nil || q.Max <= 0 {
return 2
}
return q.Max
}
// GetQueue returns queue size with default
func (q *Quota) GetQueue() int {
if q == nil || q.Queue <= 0 {
return 10
}
return q.Queue
}
// GetPriority returns priority with default
func (q *Quota) GetPriority() int {
if q == nil || q.Priority <= 0 {
return 5
}
return q.Priority
}
// KBConfig - knowledge base config
type KBConfig struct {
ID string `json:"id,omitempty"`
Refs []string `json:"refs,omitempty"`
Learn *Learn `json:"learn,omitempty"`
}
type Learn struct {
On bool `json:"on"`
Types []string `json:"types,omitempty"` // execution, feedback, insight
Keep int `json:"keep,omitempty"` // days, 0 = forever
}
// Resources - available agents and tools
type Resources struct {
Phases map[Phase]string `json:"phases,omitempty"` // phase -> agent ID
Agents []string `json:"agents,omitempty"`
MCP []MCPConfig `json:"mcp,omitempty"`
}
// GetPhaseAgent returns agent ID for phase (default: __yao.{phase})
func (r *Resources) GetPhaseAgent(phase Phase) string {
if r != nil && r.Phases != nil {
if id, ok := r.Phases[phase]; ok && id != "" {
return id
}
}
return "__yao." + string(phase)
}
type MCPConfig struct {
ID string `json:"id"`
Tools []string `json:"tools,omitempty"` // empty = all
}
// Delivery - output delivery
type Delivery struct {
Type DeliveryType `json:"type"`
Opts map[string]interface{} `json:"opts,omitempty"`
}
// Event - event trigger config
type Event struct {
Type string `json:"type"` // webhook | database
Source string `json:"source"` // path or table
Filter map[string]interface{} `json:"filter,omitempty"`
}
// Monitor - monitoring config
type Monitor struct {
On bool `json:"on"`
Alerts []Alert `json:"alerts,omitempty"`
}
type Alert struct {
Name string `json:"name"`
When string `json:"when"` // failed | timeout | error_rate
Value float64 `json:"value,omitempty"`
Window string `json:"window,omitempty"` // 1h | 24h
Do []Action `json:"do"`
Cooldown string `json:"cooldown,omitempty"`
}
type Action struct {
Type string `json:"type"` // email | webhook | notify
Opts map[string]interface{} `json:"opts,omitempty"`
}
2.3 Core Types
// types/robot.go
package types
import (
"context"
"sync"
"time"
)
// Robot - runtime representation of an autonomous robot
type Robot struct {
// From __yao.member
MemberID string `json:"member_id"`
TeamID string `json:"team_id"`
DisplayName string `json:"display_name"`
SystemPrompt string `json:"system_prompt"`
Status RobotStatus `json:"robot_status"`
AutonomousMode bool `json:"autonomous_mode"`
// Parsed config
Config *Config `json:"-"`
// Runtime state (job.Job stored as interface{} to avoid import cycle)
Job interface{} `json:"-"` // *job.Job, set by manager
JobID string `json:"-"` // job_id for quick access
LastExecution time.Time `json:"-"`
NextExecution time.Time `json:"-"`
// Concurrency control
running int
runningMu sync.Mutex
}
// CanRun checks if robot can accept new execution
func (r *Robot) CanRun() bool {
r.runningMu.Lock()
defer r.runningMu.Unlock()
return r.running < r.Config.Quota.GetMax()
}
// IncrRunning increments running count
func (r *Robot) IncrRunning() {
r.runningMu.Lock()
defer r.runningMu.Unlock()
r.running++
}
// DecrRunning decrements running count
func (r *Robot) DecrRunning() {
r.runningMu.Lock()
defer r.runningMu.Unlock()
if r.running > 0 {
r.running--
}
}
// Execution - single execution context
type Execution struct {
ID string `json:"id"`
MemberID string `json:"member_id"`
TeamID string `json:"team_id"`
TriggerType TriggerType `json:"trigger_type"`
TriggerData interface{} `json:"trigger_data,omitempty"`
StartTime time.Time `json:"start_time"`
EndTime *time.Time `json:"end_time,omitempty"`
Status ExecStatus `json:"status"`
Phase Phase `json:"phase"`
Error string `json:"error,omitempty"`
// Phase outputs
Inspiration *InspirationReport `json:"inspiration,omitempty"`
Goals []Goal `json:"goals,omitempty"`
Tasks []Task `json:"tasks,omitempty"`
Results []TaskResult `json:"results,omitempty"`
Delivery *DeliveryResult `json:"delivery,omitempty"`
Learning []LearningEntry `json:"learning,omitempty"`
// Context
ctx context.Context
cancel context.CancelFunc
robot *Robot
}
// Goal - generated goal
type Goal struct {
ID string `json:"id"`
Description string `json:"description"`
Priority Priority `json:"priority"`
Rationale string `json:"rationale,omitempty"`
Tags []string `json:"tags,omitempty"`
}
// Task - planned task
type Task struct {
ID string `json:"id"`
GoalID string `json:"goal_id"`
Description string `json:"description"`
ExecutorType string `json:"executor_type"` // "assistant" | "mcp"
ExecutorID string `json:"executor_id"`
Args []any `json:"args,omitempty"`
Status ExecStatus `json:"status"`
Order int `json:"order"`
}
// TaskResult - task execution result
type TaskResult struct {
TaskID string `json:"task_id"`
Success bool `json:"success"`
Output interface{} `json:"output,omitempty"`
Error string `json:"error,omitempty"`
Duration int64 `json:"duration_ms"`
Validated bool `json:"validated"`
}
// DeliveryResult - delivery output
type DeliveryResult struct {
Type DeliveryType `json:"type"`
Success bool `json:"success"`
Details interface{} `json:"details,omitempty"`
Error string `json:"error,omitempty"`
}
// LearningEntry - knowledge to save
type LearningEntry struct {
Type string `json:"type"` // execution | feedback | insight
Content string `json:"content"`
Tags []string `json:"tags,omitempty"`
Meta interface{} `json:"meta,omitempty"`
}
2.4 Clock Context
// types/clock.go
package types
import "time"
// ClockContext - time context for P0 inspiration
type ClockContext struct {
Now time.Time `json:"now"`
Hour int `json:"hour"` // 0-23
DayOfWeek string `json:"day_of_week"` // Monday, Tuesday...
DayOfMonth int `json:"day_of_month"` // 1-31
WeekOfYear int `json:"week_of_year"` // 1-52
Month int `json:"month"` // 1-12
Year int `json:"year"`
IsWeekend bool `json:"is_weekend"`
IsMonthStart bool `json:"is_month_start"` // 1st-3rd
IsMonthEnd bool `json:"is_month_end"` // last 3 days
IsQuarterEnd bool `json:"is_quarter_end"`
IsYearEnd bool `json:"is_year_end"`
TZ string `json:"tz"`
}
// NewClockContext creates clock context from time
func NewClockContext(t time.Time, tz string) *ClockContext {
loc := time.Local
if tz != "" {
if l, err := time.LoadLocation(tz); err == nil {
loc = l
}
}
t = t.In(loc)
_, week := t.ISOWeek()
dayOfMonth := t.Day()
lastDay := time.Date(t.Year(), t.Month()+1, 0, 0, 0, 0, 0, loc).Day()
return &ClockContext{
Now: t,
Hour: t.Hour(),
DayOfWeek: t.Weekday().String(),
DayOfMonth: dayOfMonth,
WeekOfYear: week,
Month: int(t.Month()),
Year: t.Year(),
IsWeekend: t.Weekday() == time.Saturday || t.Weekday() == time.Sunday,
IsMonthStart: dayOfMonth <= 3,
IsMonthEnd: dayOfMonth >= lastDay-2,
IsQuarterEnd: (t.Month()%3 == 0) && dayOfMonth >= lastDay-2,
IsYearEnd: t.Month() == 12 && dayOfMonth >= 29,
TZ: loc.String(),
}
}
2.5 Inspiration Report
// types/inspiration.go
package types
// InspirationReport - P0 output
type InspirationReport struct {
Clock *ClockContext `json:"clock"`
Summary string `json:"summary"`
Highlights []Highlight `json:"highlights,omitempty"`
Opportunities []Opportunity `json:"opportunities,omitempty"`
Risks []Risk `json:"risks,omitempty"`
WorldInsights []WorldInsight `json:"world_insights,omitempty"`
Suggestions []string `json:"suggestions,omitempty"`
PendingItems []PendingItem `json:"pending_items,omitempty"`
}
type Highlight struct {
Source string `json:"source"` // data | event | feedback
Priority string `json:"priority"` // high | medium | low
Content string `json:"content"`
Change string `json:"change,omitempty"` // +50%, -20%, etc.
}
type Opportunity struct {
Description string `json:"description"`
Impact string `json:"impact"` // high | medium | low
Urgency string `json:"urgency"`
}
type Risk struct {
Description string `json:"description"`
Severity string `json:"severity"` // high | medium | low
Mitigation string `json:"mitigation,omitempty"`
}
type WorldInsight struct {
Source string `json:"source"` // news | competitor | industry
Title string `json:"title"`
Summary string `json:"summary"`
Impact string `json:"impact,omitempty"`
URL string `json:"url,omitempty"`
}
type PendingItem struct {
Type string `json:"type"` // goal | task | plan
ID string `json:"id"`
Description string `json:"description"`
DueDate string `json:"due_date,omitempty"`
}
2.6 Request/Response Types
// types/request.go
package types
import (
"context"
"time"
)
// InterveneRequest - human intervention request
type InterveneRequest struct {
TeamID string `json:"team_id"`
MemberID string `json:"member_id"`
Action InterventionAction `json:"action"`
Description string `json:"description"`
Priority Priority `json:"priority,omitempty"`
PlanTime *time.Time `json:"plan_time,omitempty"` // for action=plan
}
// EventRequest - event trigger request
type EventRequest struct {
MemberID string `json:"member_id"`
Source string `json:"source"` // webhook path or table name
EventType string `json:"event_type"` // lead.created, etc.
Data map[string]interface{} `json:"data"`
}
// ExecutionResult - trigger result
type ExecutionResult struct {
ExecutionID string `json:"execution_id"`
Status ExecStatus `json:"status"`
Message string `json:"message,omitempty"`
}
// RobotState - robot status query result
type RobotState struct {
MemberID string `json:"member_id"`
TeamID string `json:"team_id"`
DisplayName string `json:"display_name"`
Status RobotStatus `json:"status"`
LastRun *time.Time `json:"last_run,omitempty"`
NextRun *time.Time `json:"next_run,omitempty"`
RunningID string `json:"running_id,omitempty"` // current execution ID
RunningCnt int `json:"running_cnt"` // current running count
}
3. Interfaces
Interfaces are also in
types/package to avoid cycles.
3.1 Manager Interface
// types/interfaces.go
package types
import (
"context"
"time"
)
// Manager - manages all robots
type Manager interface {
// Lifecycle
Start() error
Stop() error
// Cache operations
LoadActiveRobots(ctx context.Context) error
GetRobot(teamID, memberID string) *Robot
ListRobots(teamID string) []*Robot
RefreshRobot(teamID, memberID string) error
// Clock trigger (called by internal ticker)
Tick(ctx context.Context, now time.Time) error
// Robot lifecycle (called when member created/deleted)
OnRobotCreate(ctx context.Context, teamID, memberID string) error
OnRobotDelete(ctx context.Context, teamID, memberID string) error
OnRobotUpdate(ctx context.Context, teamID, memberID string) error
}
3.2 Trigger Interface
// types/interfaces.go (continued)
package types
import "context"
// Trigger - called by openapi layer
type Trigger interface {
// Human intervention
Intervene(ctx context.Context, req *InterveneRequest) (*ExecutionResult, error)
// Event trigger
HandleEvent(ctx context.Context, req *EventRequest) (*ExecutionResult, error)
// Query & control
GetStatus(ctx context.Context, teamID, memberID string) (*RobotState, error)
Pause(ctx context.Context, teamID, memberID string) error
Resume(ctx context.Context, teamID, memberID string) error
Cancel(ctx context.Context, teamID, memberID, executionID string) error
}
3.3 Executor Interface
// types/interfaces.go (continued)
package types
import "context"
// Executor - executes robot phases
type Executor interface {
// Execute runs all phases for a trigger
Execute(ctx context.Context, robot *Robot, triggerType TriggerType, triggerData interface{}) (*Execution, error)
// Individual phase execution (for testing/debugging)
RunPhase(ctx context.Context, exec *Execution, phase Phase) error
}
3.4 Phase Interface
// types/interfaces.go (continued)
package types
// PhaseExecutor - phase executor interface
type PhaseExecutor interface {
// Name returns phase name
Name() Phase
// Execute runs the phase
Execute(ctx context.Context, exec *Execution) error
}
3.5 Cache Interface
// types/interfaces.go (continued)
package types
import "context"
// Cache - robot cache interface
type Cache interface {
// Load all active robots
LoadAll(ctx context.Context) error
// Get robot by ID
Get(teamID, memberID string) *Robot
// List robots by team
List(teamID string) []*Robot
// Add/Update/Remove
Add(robot *Robot)
Update(robot *Robot)
Remove(teamID, memberID string)
// Stats
Count() int
CountByTeam(teamID string) int
}
3.6 Scheduler Interface
// types/interfaces.go (continued)
package types
import "context"
// Scheduler - worker pool and queue
type Scheduler interface {
// Start/Stop
Start() error
Stop() error
// Submit execution
Submit(ctx context.Context, robot *Robot, triggerType TriggerType, triggerData interface{}) error
// Queue status
QueueSize() int
WorkerCount() int
ActiveCount() int
}
// SchedulerConfig - scheduler configuration
type SchedulerConfig struct {
Workers int // global worker count (default: 10)
QueueSize int // global queue size (default: 1000)
MaxPerTeam int // max concurrent per team (default: 20)
}
3.7 Dedup Interface
// types/interfaces.go (continued)
package types
import (
"context"
"time"
)
// Dedup - deduplication service
type Dedup interface {
// CheckExecution - fast check for duplicate execution
CheckExecution(ctx context.Context, memberID string, triggerType TriggerType) (DedupResult, error)
// CheckGoal - semantic check for duplicate goal
CheckGoal(ctx context.Context, memberID string, goal *Goal) (DedupResult, error)
// CheckTask - semantic check for duplicate task
CheckTask(ctx context.Context, memberID string, task *Task) (DedupResult, error)
// MarkExecuted - mark execution as done
MarkExecuted(ctx context.Context, memberID string, triggerType TriggerType, window time.Duration)
}
4. Errors
// types/errors.go
package types
import "errors"
var (
// Config errors
ErrMissingIdentity = errors.New("identity.role is required")
ErrClockTimesEmpty = errors.New("clock.times is required for times mode")
ErrClockIntervalEmpty = errors.New("clock.every is required for interval mode")
ErrClockModeInvalid = errors.New("clock.mode must be times, interval, or daemon")
// Runtime errors
ErrRobotNotFound = errors.New("robot not found")
ErrRobotPaused = errors.New("robot is paused")
ErrRobotBusy = errors.New("robot has reached max concurrent executions")
ErrTriggerDisabled = errors.New("trigger type is disabled for this robot")
ErrExecutionCancelled = errors.New("execution was cancelled")
ErrExecutionTimeout = errors.New("execution timed out")
// Phase errors
ErrPhaseAgentNotFound = errors.New("phase agent not found")
ErrGoalGenFailed = errors.New("goal generation failed")
ErrTaskPlanFailed = errors.New("task planning failed")
ErrDeliveryFailed = errors.New("delivery failed")
)