goal

package
v0.1.21 Latest Latest
Warning

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

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

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:

  1. Domain model — the runtime-owned Goal, Status, and ControllerSpec types.
  2. Store boundary — maps the Datly read/write types to and from the domain model so no generated type leaks upward.
  3. 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 NewController

func NewController() *Controller

NewController returns a controller.

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:

  1. no goal or non-active goal → no action;
  2. system-owned hard limits (budget, usage) → terminal transition;
  3. conversation not idle, or user work pending → wait;
  4. goal not configured for idle continuation → no action;
  5. configured stall / autonomous-turn guards → block or pause;
  6. no explicit continuation signal, or turn policy is wait → no action;
  7. 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

func (g *Goal) Autonomous() bool

Autonomous reports whether the goal opted into idle-time continuation.

func (*Goal) BudgetExceeded

func (g *Goal) BudgetExceeded() bool

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

func NewRuntime(store Store) *Runtime

func (*Runtime) AfterTurn

func (r *Runtime) AfterTurn(ctx context.Context, in *AfterTurnInput) (Action, *Goal, error)

func (*Runtime) SetDeactivateHook

func (r *Runtime) SetDeactivateHook(fn func(ctx context.Context, conversationID, goalID string))

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.

const (
	StatusActive        Status = "active"
	StatusPaused        Status = "paused"
	StatusBlocked       Status = "blocked"
	StatusComplete      Status = "complete"
	StatusBudgetLimited Status = "budget_limited"
	StatusUsageLimited  Status = "usage_limited"
)

func ParseStatus

func ParseStatus(value string) (Status, error)

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) IsActive

func (s Status) IsActive() bool

IsActive reports whether the goal is eligible for autonomous continuation.

func (Status) IsTerminal

func (s Status) IsTerminal() bool

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.

func NewStore

func NewStore(access dataAccess) Store

NewStore returns a Store backed by the application data service.

type TurnPolicy

type TurnPolicy string

TurnPolicy controls what happens after a turn finishes for an active goal.

const (
	TurnPolicyEvaluate TurnPolicy = "evaluate"
	TurnPolicyWait     TurnPolicy = "wait"
)

Jump to

Keyboard shortcuts

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