Documentation
¶
Overview ¶
Package planning provides goal-directed state planning as an Agent execution strategy. Goal, Condition, WorldState, Action, and Plan belong exclusively to this package; the Agent kernel sees only opaque Execution state and Effects.
Planning separates predicted Action semantics from external execution. A Planner is a pure, deterministic search over a Problem. A managed Planning Execution observes the real world and executes selected Actions outside its Step through a Deployment-bound dispatcher or a child Process, then observes again before accepting that the prediction became true.
Index ¶
- Variables
- func NewActionSettlement(effectID agent.EffectID, result ActionResult) (agent.Settlement, error)
- type Action
- func (a Action) Applicable(state WorldState) bool
- func (a Action) Apply(source WorldState) (WorldState, error)
- func (a Action) Cost(source WorldState) (cost float64, err error)
- func (a Action) Description() string
- func (a Action) Effects() []Condition
- func (a Action) Name() string
- func (a Action) Preconditions() []Condition
- func (a Action) Valid() bool
- type ActionBinding
- type ActionConfig
- type ActionExecutor
- type ActionExecutorFunc
- type ActionRequest
- type ActionResult
- type Attempt
- type AttemptStatus
- type ChildBindingConfig
- type ChildInputFunc
- type Condition
- type CostFunc
- type Definition
- type DefinitionConfig
- type Dispatcher
- type DispatcherBindingConfig
- type DispatcherConfig
- type Goal
- type GoalConfig
- type ObservationRequest
- type Observer
- type ObserverFunc
- type Outcome
- type Output
- type Plan
- type PlannedAction
- type Planner
- type PlannerFunc
- type Problem
- type Truth
- type WorldState
- func (w WorldState) Apply(effects ...Condition) (WorldState, error)
- func (w WorldState) Conditions() []Condition
- func (WorldState) JSONSchemaModel() any
- func (w WorldState) Key() string
- func (w WorldState) MarshalJSON() ([]byte, error)
- func (w WorldState) Satisfies(requirements ...Condition) bool
- func (w WorldState) Truth(key string) Truth
- func (w *WorldState) UnmarshalJSON(data []byte) error
- func (w WorldState) Valid() bool
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrInvalidCondition = errors.New("planning: invalid condition") ErrInvalidWorldState = errors.New("planning: invalid world state") ErrInvalidGoal = errors.New("planning: invalid goal") ErrInvalidAction = errors.New("planning: invalid action") ErrInvalidActionCost = errors.New("planning: invalid action cost") ErrInvalidPlan = errors.New("planning: invalid plan") ErrInvalidProblem = errors.New("planning: invalid problem") ErrInvalidDefinitionConfig = errors.New("planning: invalid definition configuration") ErrInvalidDispatcherConfig = errors.New("planning: invalid dispatcher configuration") ErrInvalidExecutionState = errors.New("planning: invalid execution state") ErrInvalidProtocol = errors.New("planning: invalid protocol payload") )
Functions ¶
func NewActionSettlement ¶
func NewActionSettlement(effectID agent.EffectID, result ActionResult) (agent.Settlement, error)
NewActionSettlement converts an executor result into the kernel settlement that closes the effect. Going through this constructor is what keeps an executor from encoding planning vocabulary into a payload the kernel would then have to understand.
Types ¶
type Action ¶
type Action struct {
// contains filtered or unexported fields
}
Action is an immutable predictive operation used only by Planners. It does not execute I/O and is not a model Tool.
func NewAction ¶
func NewAction(config ActionConfig) (Action, error)
NewAction builds the predictive half of an action — preconditions, effects, and cost — with no executable body. Keeping execution out means the planner can search over actions without the risk of running one, and the same action can be bound to different executors.
func (Action) Applicable ¶
func (a Action) Applicable(state WorldState) bool
Applicable reports whether state establishes every Action precondition.
func (Action) Apply ¶
func (a Action) Apply(source WorldState) (WorldState, error)
Apply returns the Action's predicted successor state. It does not assert that external execution actually produced the prediction.
func (Action) Cost ¶
func (a Action) Cost(source WorldState) (cost float64, err error)
Cost evaluates the Action's predicted edge cost against source. Panics, errors, negative values, and non-finite values are returned as ErrInvalidActionCost.
func (Action) Description ¶
Description returns the human-readable predicted behavior.
func (Action) Preconditions ¶
Preconditions returns an independently owned, key-sorted requirement set.
type ActionBinding ¶
type ActionBinding struct {
// contains filtered or unexported fields
}
ActionBinding is an immutable association between predictive Action semantics and exactly one external execution mechanism.
func NewChildBinding ¶
func NewChildBinding(config ChildBindingConfig) (ActionBinding, error)
NewChildBinding attaches an action to a child Deployment, so a plan step becomes a real Process with its own identity, budget, and recovery instead of an opaque call inside the parent.
func NewDispatcherBinding ¶
func NewDispatcherBinding(config DispatcherBindingConfig) (ActionBinding, error)
NewDispatcherBinding attaches an action to an external executor. Binding is separate from the action itself so the same predictive model can be planned against in tests without an executor present.
func (ActionBinding) Action ¶
func (a ActionBinding) Action() Action
Action returns the immutable predictive Action owned by the binding.
func (ActionBinding) Valid ¶
func (a ActionBinding) Valid() bool
type ActionConfig ¶
type ActionConfig struct {
// Name is the stable lower-case qualified Action identity.
Name string
// Description explains what the Action is expected to accomplish.
Description string
// Preconditions are truths required in the source WorldState.
Preconditions []Condition
// Effects are truths predicted in the successor WorldState after success.
Effects []Condition
// Cost computes the non-negative search edge cost. Nil defaults to 1.
Cost CostFunc
}
ActionConfig contains one Action's complete predictive planning semantics. External execution is deliberately absent and is bound separately by a managed Planning Definition.
type ActionExecutor ¶
type ActionExecutor interface {
// Execute attempts one selected Action against the observed WorldState. A
// valid ActionResult is definite; a non-nil error means the external outcome
// is unknown and must not be translated into an ordinary failed Action or
// implicitly retried under a new identity.
Execute(ctx context.Context, request ActionRequest) (ActionResult, error)
}
ActionExecutor performs one dispatcher-bound Action. A valid ActionResult is a definite success or failure. A non-nil error means the external outcome is unknown, so Dispatcher returns an unknown Effect settlement and never retries it implicitly.
type ActionExecutorFunc ¶
type ActionExecutorFunc func(ctx context.Context, request ActionRequest) (ActionResult, error)
ActionExecutorFunc adapts a plain function to the executor interface, so a single action does not require a named type to be made runnable.
func (ActionExecutorFunc) Execute ¶
func (a ActionExecutorFunc) Execute( ctx context.Context, request ActionRequest, ) (ActionResult, error)
type ActionRequest ¶
type ActionRequest struct {
// EffectID is the stable identity of the prepared Action attempt.
EffectID agent.EffectID
// Input is the original immutable Planning Process input.
Input agent.Input
// ActionName is the exact frozen Action identity.
ActionName string
// ActionDescription is the exact frozen model-facing Action description.
ActionDescription string
// WorldState is the complete observation against which the Action was selected.
WorldState WorldState
}
ActionRequest is one external dispatcher Action invocation selected against an observed WorldState. Input and WorldState are immutable values.
type ActionResult ¶
type ActionResult struct {
// contains filtered or unexported fields
}
ActionResult is the definite external result reported by an ActionExecutor. Its zero value is invalid.
func ActionFailed ¶
func ActionFailed(diagnostic string) (ActionResult, error)
ActionFailed constructs a definite failed Action result with a bounded diagnostic suitable for a portable Planning attempt record.
func ActionSucceeded ¶
func ActionSucceeded() ActionResult
ActionSucceeded returns a definite successful Action result.
func (ActionResult) Diagnostic ¶
func (a ActionResult) Diagnostic() string
Diagnostic returns the definite failure explanation, or an empty string on success.
func (ActionResult) Succeeded ¶
func (a ActionResult) Succeeded() bool
Succeeded reports whether the definite Action result succeeded.
func (ActionResult) Valid ¶
func (a ActionResult) Valid() bool
type Attempt ¶
type Attempt struct {
// ActionName is the exact Action identity selected for this attempt.
ActionName string `json:"action_name" jsonschema:"pattern=^[a-z][a-z0-9._-]{0\\,127}$"`
// Status is the observed semantic outcome of this attempt.
Status AttemptStatus `json:"status" jsonschema:"enum=succeeded,enum=failed,enum=unconfirmed"`
// Diagnostic explains failed or unconfirmed attempts and is empty on success.
Diagnostic string `json:"diagnostic,omitempty" jsonschema:"minLength=1,maxLength=4096"`
}
Attempt is one final, portable Action-attempt fact. Diagnostic is empty only for a succeeded attempt.
type AttemptStatus ¶
type AttemptStatus string
AttemptStatus records the observed result of one selected Action attempt.
const ( // AttemptSucceeded means execution succeeded and reobservation established // every predicted effect. AttemptSucceeded AttemptStatus = "succeeded" // AttemptFailed means the dispatcher or child Process definitely failed. AttemptFailed AttemptStatus = "failed" // AttemptUnconfirmed means execution reported success but reobservation did // not establish every predicted effect. AttemptUnconfirmed AttemptStatus = "unconfirmed" )
func (AttemptStatus) Valid ¶
func (a AttemptStatus) Valid() bool
type ChildBindingConfig ¶
type ChildBindingConfig struct {
// Action is the immutable predictive behavior delegated to a child Process.
Action Action
// DeploymentRef identifies the exact child behavior binding.
DeploymentRef agent.DeploymentRef
// Input deterministically derives child input; nil reuses Process input.
Input ChildInputFunc
// Budget is permanently allocated to each child attempt.
Budget agent.Budget
// Capabilities is the attenuated authority granted to each child attempt.
Capabilities agent.CapabilitySet
}
ChildBindingConfig binds a predictive Action to one exact child Deployment. Every attempt starts a new child Process with a stable Engine-derived identity, explicit budget, and attenuated capabilities.
type ChildInputFunc ¶
ChildInputFunc derives a child Process input from the parent input and the current world state, so a plan step can be parameterized by facts discovered during execution rather than only by what the plan was started with.
type Condition ¶
type Condition struct {
// contains filtered or unexported fields
}
Condition is one immutable known truth requirement or prediction. Unknown is represented by absence from a WorldState and therefore cannot be stored in a Condition.
func NewCondition ¶
NewCondition names one fact the planner reasons over. Conditions are keys with a truth value rather than arbitrary predicates, because the planner has to compare and combine them without executing anything.
func (Condition) JSONSchemaModel ¶
JSONSchemaModel returns the typed JSON wire model owned by Condition.
func (Condition) MarshalJSON ¶
func (*Condition) UnmarshalJSON ¶
type CostFunc ¶
type CostFunc func(source WorldState) (float64, error)
CostFunc lets an action's cost depend on the world state it would run in, which is what allows a planner to prefer a cheap path under current facts rather than a fixed ordering. Returning an error keeps an uncomputable cost from being silently treated as zero, which would make that action always win.
type Definition ¶
type Definition struct {
// contains filtered or unexported fields
}
Definition is an immutable Planning Strategy definition. It contains no Observer or ActionExecutor; those I/O capabilities belong to its Deployment-bound Dispatcher.
func NewDefinition ¶
func NewDefinition(config DefinitionConfig) (*Definition, error)
NewDefinition freezes the goal, actions, and planner into one immutable behavior. The planner is chosen here rather than at run time so that a restored Execution searches with the same algorithm that produced the plan it is resuming.
func (*Definition) Descriptor ¶
func (d *Definition) Descriptor() agent.Descriptor
Descriptor returns the immutable managed Planning contract.
func (*Definition) Restore ¶
func (d *Definition) Restore(state agent.ExecutionState) (agent.Execution, error)
Restore recreates a Planning Execution solely from its opaque state and this exact Definition.
type DefinitionConfig ¶
type DefinitionConfig struct {
// Name is the stable qualified Definition name.
Name string
// Description states the managed goal-directed behavior for discovery.
Description string
// InputSchema is the authoritative schema for opaque task input passed to
// Observer, ActionExecutor, and child input functions.
InputSchema agent.Schema
// Goal is the immutable target state.
Goal Goal
// Actions binds every predictive Action to exactly one execution mechanism.
Actions []ActionBinding
// Planner selects Actions from each newly observed WorldState.
Planner Planner
// MaxActionAttempts bounds external Action attempts. It must be positive.
MaxActionAttempts uint32
}
DefinitionConfig contains one immutable managed Planning behavior. Goal, Planner, and Action bindings are fixed for the exact Deployment; only Input varies per Process.
type Dispatcher ¶
type Dispatcher struct {
// contains filtered or unexported fields
}
Dispatcher executes observation and dispatcher Action Effects emitted by one Planning Definition. It is immutable after construction and may serve Processes concurrently when Observer and ActionExecutors are concurrent-safe.
func NewDispatcher ¶
func NewDispatcher(definition *Definition, config DispatcherConfig) (*Dispatcher, error)
NewDispatcher binds a definition to the executors that carry out its effects. It is constructed against an exact definition so an effect cannot be routed to an executor the planner never planned against.
func (*Dispatcher) Dispatch ¶
func (d *Dispatcher) Dispatch( ctx context.Context, request agent.EffectRequest, _ agent.DeltaEmitter, ) (agent.Settlement, error)
Dispatch executes one validated Planning protocol operation. Observer errors and valid ActionResult failures are definite failed settlements; an ActionExecutor error leaves the Effect outcome unknown.
func (*Dispatcher) ReplayPolicy ¶
func (*Dispatcher) ReplayPolicy(effect agent.Effect) agent.ReplayPolicy
ReplayPolicy permits same-identity replay only for side-effect-free observation. Action Effects may have irreversible external consequences and always require explicit resolution after an unknown attempt.
type DispatcherBindingConfig ¶
type DispatcherBindingConfig struct {
// Action is the immutable predictive behavior bound to a dispatcher target.
Action Action
// RequiredCapabilities is the authority required before dispatch.
RequiredCapabilities []agent.Capability
}
DispatcherBindingConfig binds a predictive Action to the Planning Dispatcher. RequiredCapabilities are enforced by Engine before dispatch.
type DispatcherConfig ¶
type DispatcherConfig struct {
// Observer supplies each complete WorldState observation.
Observer Observer
// ActionExecutors maps dispatcher-bound Action names to exact executors.
ActionExecutors map[string]ActionExecutor
}
DispatcherConfig binds side-effect-free observation and the exact set of dispatcher-targeted Action executors required by a Definition. Child-bound Actions must not appear in ActionExecutors.
type Goal ¶
type Goal struct {
// contains filtered or unexported fields
}
Goal is an immutable set of desired condition truths.
func NewGoal ¶
func NewGoal(config GoalConfig) (Goal, error)
NewGoal states the target as conditions rather than as a procedure, which is what lets the planner decide the route and re-plan when observed facts change.
func (Goal) Conditions ¶
Conditions returns an independently owned, key-sorted requirement set.
func (Goal) Description ¶
Description returns the human-readable desired state.
func (Goal) SatisfiedBy ¶
func (g Goal) SatisfiedBy(state WorldState) bool
SatisfiedBy reports whether state establishes every goal condition.
type GoalConfig ¶
type GoalConfig struct {
// Name is the stable lower-case qualified goal identity.
Name string
// Description explains the desired state to a human consumer.
Description string
// Conditions are the known truths the final WorldState must establish.
Conditions []Condition
}
GoalConfig contains the complete immutable description of a Planning goal.
type ObservationRequest ¶
type ObservationRequest struct {
// EffectID is the stable identity of the prepared observation attempt.
EffectID agent.EffectID
// Input is the original immutable Planning Process input.
Input agent.Input
}
ObservationRequest is one side-effect-free request for the current complete WorldState. Input is the original Planning Process input; EffectID is stable for the prepared attempt.
type Observer ¶
type Observer interface {
// Observe obtains one complete immutable WorldState for the original Process
// input. It must honor ctx and must not cause externally visible side effects,
// because the same EffectID may be replayed after an unknown observation.
Observe(ctx context.Context, request ObservationRequest) (WorldState, error)
}
Observer produces one complete WorldState without externally visible side effects. A returned error is a definite observation failure and terminates Planning; an Observer must not use error to report an unknown side effect.
type ObserverFunc ¶
type ObserverFunc func(ctx context.Context, request ObservationRequest) (WorldState, error)
ObserverFunc adapts a plain function to the observer interface. Observation is an Effect rather than part of a Step, because reading the world is external I/O and its result must arrive as a settlement the Execution can be resumed from.
func (ObserverFunc) Observe ¶
func (o ObserverFunc) Observe( ctx context.Context, request ObservationRequest, ) (WorldState, error)
type Outcome ¶
type Outcome string
Outcome is the Planning-owned semantic reason a Goal-directed execution completed. It does not add states to the common Process lifecycle.
const ( // OutcomeAchieved means the latest observed WorldState satisfies the Goal. OutcomeAchieved Outcome = "achieved" // OutcomeUnreachable means the initial complete planning search found no plan. OutcomeUnreachable Outcome = "unreachable" // OutcomeStuck means attempts or the Action limit were exhausted without // reaching the Goal. OutcomeStuck Outcome = "stuck" )
type Output ¶
type Output struct {
// Outcome is the Planning-owned semantic completion reason.
Outcome Outcome `json:"outcome" jsonschema:"enum=achieved,enum=unreachable,enum=stuck"`
// WorldState is the final complete observation.
WorldState WorldState `json:"world_state"`
// Attempts preserves Action-attempt order.
Attempts []Attempt `json:"attempts"`
// PlanningPasses counts calls to Planner.
PlanningPasses uint32 `json:"planning_passes" jsonschema:"maximum=4294967295"`
}
Output is the final semantic Planning result. WorldState is the last complete observation, Attempts preserve selection order, and PlanningPasses counts calls to Planner. No field is derived from Event or Delta history.
type Plan ¶
type Plan struct {
// contains filtered or unexported fields
}
Plan is an immutable ordered Action sequence and its predicted total cost. An empty Plan with zero cost is valid and represents an already-satisfied Goal; Planner's separate found result distinguishes it from no solution.
func NewPlan ¶
func NewPlan(actions []PlannedAction, totalCost float64) (Plan, error)
NewPlan carries the total cost alongside the steps so an operator can compare two plans without re-running the search that produced them.
func (Plan) Actions ¶
func (p Plan) Actions() []PlannedAction
Actions returns independently owned Action references in execution order.
func (Plan) MarshalJSON ¶
func (*Plan) UnmarshalJSON ¶
type PlannedAction ¶
type PlannedAction struct {
// contains filtered or unexported fields
}
PlannedAction is one immutable Action reference in Planner-selected order. It contains no executable capability or copied Action metadata.
func NewPlannedAction ¶
func NewPlannedAction(name string) (PlannedAction, error)
NewPlannedAction names a step by action name only. A plan holds names rather than action values so it stays serializable in the Execution snapshot, and so resuming resolves the action from the Definition instead of trusting a stored copy.
func (PlannedAction) MarshalJSON ¶
func (p PlannedAction) MarshalJSON() ([]byte, error)
func (PlannedAction) Name ¶
func (p PlannedAction) Name() string
Name returns the referenced Action identity.
func (*PlannedAction) UnmarshalJSON ¶
func (p *PlannedAction) UnmarshalJSON(data []byte) error
func (PlannedAction) Valid ¶
func (p PlannedAction) Valid() bool
type Planner ¶
type Planner interface {
// Plan searches one immutable Problem without mutating it or performing I/O.
// found=false with nil error is reserved for an exhausted complete search;
// cancellation, resource limits, invalid costs, and internal failure return
// errors. Equivalent Problems must produce an equivalent ordered Plan.
Plan(ctx context.Context, problem Problem) (plan Plan, found bool, err error)
}
Planner finds an ordered Action sequence for one immutable Problem. It must be deterministic and side-effect-free for the same Problem, safe for concurrent calls, and honor context cancellation. found=false with nil error means the search proved no plan within its algorithm's complete search space; resource exhaustion must be returned as an error instead.
type PlannerFunc ¶
PlannerFunc adapts a plain function to the planner interface. The separate found result distinguishes a completed search that proved no path exists from a search that failed, because the first is a legitimate planning answer and the second is an error.
type Problem ¶
type Problem struct {
// contains filtered or unexported fields
}
Problem is one immutable Planner input: a current observation, one Goal, and the available predictive Actions. It contains no dispatcher, Process, or application dependency.
func NewProblem ¶
func NewProblem(initial WorldState, goal Goal, actions ...Action) (Problem, error)
NewProblem binds the initial state, the goal, and the actions available to reach it into one value, so a planner cannot be handed a goal without the vocabulary it is expected to search over.
func (Problem) InitialState ¶
func (p Problem) InitialState() WorldState
InitialState returns the immutable starting observation.
func (Problem) ValidatePlan ¶
ValidatePlan verifies that every referenced Action exists and is applicable in sequence, the reported cost equals the evaluated path cost, and the predicted final state satisfies the Goal.
type Truth ¶
type Truth string
Truth is the three-valued truth of one observed condition. Unknown is not a synonym for False: it means the current WorldState does not establish either known value. The zero value is invalid; callers must choose explicitly.
const ( // Unknown means the current observation does not establish the condition. Unknown Truth = "unknown" // False means the current observation establishes that the condition is false. False Truth = "false" // True means the current observation establishes that the condition is true. True Truth = "true" )
func (Truth) MarshalJSON ¶
func (*Truth) UnmarshalJSON ¶
type WorldState ¶
type WorldState struct {
// contains filtered or unexported fields
}
WorldState is an immutable, canonical observation of known condition truths. Missing conditions read as Unknown. Its zero value is the valid empty state.
func NewWorldState ¶
func NewWorldState(conditions ...Condition) (WorldState, error)
NewWorldState collects the facts a plan is evaluated against. It is a validated set rather than a free-form map because the planner compares states for equality while searching, and duplicate or conflicting conditions would make that comparison meaningless.
Example ¶
package main
import (
"fmt"
"github.com/Tangerg/scope/agent/planning"
)
func main() {
ready, err := planning.NewCondition("service.ready", planning.True)
if err != nil {
panic(err)
}
state, err := planning.NewWorldState(ready)
if err != nil {
panic(err)
}
fmt.Println(state.Truth("service.ready"), state.Truth("service.cached"), state.Satisfies(ready))
}
Output: true unknown true
func (WorldState) Apply ¶
func (w WorldState) Apply(effects ...Condition) (WorldState, error)
Apply returns a new state with predicted effects layered over this state. The receiver is never mutated.
func (WorldState) Conditions ¶
func (w WorldState) Conditions() []Condition
Conditions returns an independently owned, key-sorted snapshot.
func (WorldState) JSONSchemaModel ¶
func (WorldState) JSONSchemaModel() any
JSONSchemaModel returns the typed JSON wire model owned by WorldState.
func (WorldState) Key ¶
func (w WorldState) Key() string
Key returns a stable identity derived only from canonical known truths.
func (WorldState) MarshalJSON ¶
func (w WorldState) MarshalJSON() ([]byte, error)
func (WorldState) Satisfies ¶
func (w WorldState) Satisfies(requirements ...Condition) bool
Satisfies reports whether w establishes every required condition.
func (WorldState) Truth ¶
func (w WorldState) Truth(key string) Truth
Truth returns the observed truth for key, or Unknown when key is absent.
func (*WorldState) UnmarshalJSON ¶
func (w *WorldState) UnmarshalJSON(data []byte) error
func (WorldState) Valid ¶
func (w WorldState) Valid() bool