Documentation
¶
Overview ¶
Package goal implements the autonomous-system runtime above the durable goal persistence (pkg/agently/goal) and the system/goal model tool. It composes three deliberately separate concerns:
- Domain model — the runtime-owned Goal, Status, and ControllerSpec types.
- Store boundary — maps the Datly read/write types to and from the domain model so no generated type leaks upward.
- Controller — a pure, deterministic policy that decides whether and how an active goal continues.
It never infers state from transcript text and never substitutes a guessed default for missing configuration: a goal without a controller spec is simply not autonomous.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ContinuationFingerprint ¶
func ContinuationFingerprint(h *ContinuationHint) string
Types ¶
type Action ¶
type Action struct {
Kind ActionKind
Reason string
// Status is the target status for a lifecycle-transition decision. It is
// empty for ActionNone and ActionQueueTurn.
Status Status
// PauseReason accompanies ActionPauseGoal.
PauseReason PauseReason
// Continuation is set only for ActionQueueTurn and carries the hint that
// justified continuation.
Continuation *ContinuationHint
// WakeDelaySeconds is set only for ActionScheduleWakeup.
WakeDelaySeconds int
}
Action is the controller's single explicit decision.
type ActionKind ¶
type ActionKind string
ActionKind enumerates the single decisions the controller can emit.
const ( ActionNone ActionKind = "none" ActionQueueTurn ActionKind = "queue_turn" ActionPauseGoal ActionKind = "pause_goal" ActionBlockGoal ActionKind = "block_goal" ActionCompleteGoal ActionKind = "complete_goal" ActionBudgetLimited ActionKind = "budget_limited" ActionUsageLimited ActionKind = "usage_limited" ActionScheduleWakeup ActionKind = "schedule_wakeup" )
type AfterTurnInput ¶
type AfterTurnInput struct {
ConversationID string
TurnStatus string
RequestTime time.Time
Usage *usage.Aggregator
TurnRunning bool
QueuedUserTurns int
PendingElicitation bool
PendingApproval bool
PendingAsync bool
UsageLimited bool
ConsecutiveNoProgress int
AutonomousTurnsUsed int
Continuation *ContinuationHint
ProgressFingerprint string
}
type AsyncPolicy ¶
type AsyncPolicy string
AsyncPolicy controls what happens after an async operation completes.
const ( AsyncPolicyEvaluate AsyncPolicy = "evaluate" AsyncPolicyWait AsyncPolicy = "wait" )
type ContinuationHint ¶
type ContinuationHint struct {
// Reason is the human-readable justification for continuing, surfaced to
// the user (e.g. on the queued turn).
Reason string
// Preview is the visible queue preview text for the scheduled turn.
Preview string
// Payload is the hidden controller context handed to the continuation
// turn as internal input. It is not rendered as a user message.
Payload string
}
ContinuationHint is an explicit, runtime-supplied next-step signal. The controller continues an active goal only when such a hint is present; it never infers a next action from free-text transcript output.
type ContinueMode ¶
type ContinueMode string
ContinueMode selects how an active goal is allowed to continue.
const ( // ContinueModeIdleOnly permits the controller to enqueue a continuation // only when the conversation is idle. ContinueModeIdleOnly ContinueMode = "idle_only" // ContinueModeManualOnly disables autonomous continuation; the goal still // exists and accounts usage, but only user/runtime action advances it. ContinueModeManualOnly ContinueMode = "manual_only" )
type Controller ¶
type Controller struct{}
Controller is the autonomy policy engine. It is stateless; all inputs arrive through the Snapshot.
func (*Controller) Evaluate ¶
func (c *Controller) Evaluate(s *Snapshot) Action
Evaluate maps a snapshot to exactly one decision. It is pure and deterministic: the same snapshot always yields the same action.
Order of reasoning:
- no goal or non-active goal → no action;
- system-owned hard limits (budget, usage) → terminal transition;
- conversation not idle, or user work pending → wait;
- goal not configured for idle continuation → no action;
- configured stall / autonomous-turn guards → block or pause;
- no explicit continuation signal, or turn policy is wait → no action;
- otherwise → queue one controller-owned continuation turn.
type ControllerSpec ¶
type ControllerSpec struct {
ContinueMode ContinueMode `json:"continueMode"`
OnTurnFinished TurnPolicy `json:"onTurnFinished"`
OnAsyncCompleted AsyncPolicy `json:"onAsyncCompleted"`
WakeDelaySeconds *int `json:"wakeDelaySeconds,omitempty"`
MaxAutonomousTurns *int `json:"maxAutonomousTurns,omitempty"`
MaxConsecutiveNoProgress *int `json:"maxConsecutiveNoProgress,omitempty"`
}
ControllerSpec is the persisted, runtime-owned policy block for a goal. It is stored as JSON in the goal.controller_spec column. A nil spec means the goal is not autonomous.
func DecodeControllerSpec ¶
func DecodeControllerSpec(raw string) (*ControllerSpec, error)
DecodeControllerSpec parses the controller_spec column value. An empty value yields a nil spec (the goal is not autonomous). A malformed or invalid value is an error; the runtime does not fall back to a default policy.
func (*ControllerSpec) Encode ¶
func (s *ControllerSpec) Encode() (string, error)
Encode serialises the spec to the JSON form stored in controller_spec.
func (*ControllerSpec) Validate ¶
func (s *ControllerSpec) Validate() error
Validate rejects unknown enum values. Empty enum values are not permitted: a spec exists only when the goal is explicitly configured.
type Goal ¶
type Goal struct {
ID string
ConversationID string
Objective string
Status Status
StatusReason string
PauseReason PauseReason
Controller *ControllerSpec
TokenBudget *int64
TokensUsed int64
TimeUsedSeconds int64
AutonomousTurnsUsed int64
ConsecutiveNoProgress int64
LastContinuationFingerprint string
CreatedAt time.Time
UpdatedAt *time.Time
}
Goal is the runtime-owned view of a durable conversation objective. It is distinct from the persistence GoalView and from the tool-facing projection; the store boundary translates between them.
func (*Goal) Autonomous ¶
Autonomous reports whether the goal opted into idle-time continuation.
func (*Goal) BudgetExceeded ¶
BudgetExceeded reports whether a token budget is set and has been reached.
type PauseReason ¶
type PauseReason string
PauseReason explains why an otherwise-valid goal stopped continuing. It is persisted in the dedicated pause_reason column, separate from status_reason.
const ( PauseReasonUserRequested PauseReason = "user_requested" PauseReasonUserInterrupt PauseReason = "user_interrupt" PauseReasonUserNewTurn PauseReason = "user_new_turn" PauseReasonHumanReviewCheckpoint PauseReason = "human_review_checkpoint" PauseReasonModeChange PauseReason = "mode_change" PauseReasonSupervisorPolicy PauseReason = "supervisor_policy" )
type Runtime ¶
type Runtime struct {
// contains filtered or unexported fields
}
Runtime bridges the durable goal store and the pure controller policy. It owns the side effects that happen around a completed turn: usage accounting, state transitions, and continuation decisions.
func NewRuntime ¶
type Snapshot ¶
type Snapshot struct {
Goal *Goal
// Conversation activity. Continuation requires a fully idle conversation.
TurnRunning bool
QueuedUserTurns int
PendingElicitation bool
PendingApproval bool
PendingAsync bool
// Externally detected provider/runtime usage limit. The controller reacts
// to it but does not detect it.
UsageLimited bool
// Progress guards, accounted by the runtime across autonomous turns.
ConsecutiveNoProgress int
AutonomousTurnsUsed int
// Continuation is the explicit next-step signal, or nil when none exists.
Continuation *ContinuationHint
}
Snapshot is the complete, side-effect-free input to a controller decision. Everything the policy needs is captured here; Evaluate performs no IO.
type Status ¶
type Status string
Status is the durable lifecycle state of a goal. The string values match the `status` column in the goal table exactly.
func ParseStatus ¶
ParseStatus converts a persisted status string into a typed Status. It returns an error for any unrecognised value rather than guessing a default.
func (Status) IsTerminal ¶
IsTerminal reports whether the goal has reached a state from which the controller must never continue.
type Store ¶
type Store interface {
// Current returns the active goal for a conversation, or nil when none
// exists.
Current(ctx context.Context, conversationID string) (*Goal, error)
// RecordUsage persists absolute usage counters for a goal. The caller is
// responsible for computing the new totals.
RecordUsage(ctx context.Context, goalID string, tokensUsed, timeUsedSeconds int64) error
// Transition persists a status change with an accompanying status reason.
Transition(ctx context.Context, goalID string, status Status, reason string) error
// Pause persists a paused status with a dedicated pause reason.
Pause(ctx context.Context, goalID string, reason PauseReason) error
// UpdateControllerState persists autonomous controller counters and
// the latest continuation fingerprint.
UpdateControllerState(ctx context.Context, goalID string, autonomousTurnsUsed, consecutiveNoProgress int64, fingerprint string) error
}
Store is the persistence boundary for the goal runtime, expressed entirely in domain terms. No Datly read/write type crosses it.
type TurnPolicy ¶
type TurnPolicy string
TurnPolicy controls what happens after a turn finishes for an active goal.
const ( TurnPolicyEvaluate TurnPolicy = "evaluate" TurnPolicyWait TurnPolicy = "wait" )