Documentation
¶
Overview ¶
Package loop provides fixed and dynamic activation policies for continuation executions.
A Controller plans one durable wait after each completed Work result. The package never sleeps, polls, starts a timer, or resumes an execution; applications explicitly deliver due-time or signal activations through continuation.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrInvalid = errors.New("loop: invalid value") ErrTooLarge = errors.New("loop: value too large") )
Loop validation errors.
Functions ¶
This section is empty.
Types ¶
type Controller ¶
type Controller struct {
// contains filtered or unexported fields
}
Controller maps activation plans onto durable continuation waits.
func Every ¶
func Every(interval time.Duration, options ...ControllerOption) (*Controller, error)
Every constructs a fixed-interval Loop Controller.
Example ¶
package main
import (
"context"
"fmt"
"time"
"github.com/rsbin1178/pips/agent/continuation"
"github.com/rsbin1178/pips/agent/loop"
"github.com/rsbin1178/pips/ai"
)
type exampleClock struct {
now time.Time
}
func (clock *exampleClock) Now() time.Time { return clock.now }
type exampleWorker func(context.Context, continuation.WorkRequest) (continuation.WorkResult, error)
func (worker exampleWorker) Run(
ctx context.Context,
request continuation.WorkRequest,
) (continuation.WorkResult, error) {
return worker(ctx, request)
}
func main() {
clock := &exampleClock{now: time.Date(2026, time.July, 19, 8, 0, 0, 0, time.UTC)}
controller, _ := loop.Every(5*time.Minute,
loop.WithClock(clock),
)
setup, _ := loop.Prepare(ai.JSON(`{"prompt":"check deployment"}`))
store, _ := continuation.NewMemoryStore()
engine, _ := continuation.New(store, continuation.WithClock(clock))
workerRef := continuation.HandlerRef{Kind: "deployment-check", Version: "v1"}
controllerRef := continuation.HandlerRef{Kind: "fixed-loop", Version: "v1"}
execution, _ := engine.Create(context.Background(), continuation.CreateRequest{
ID: "deployment-loop", Target: continuation.Target{Kind: "session", ID: "deploy-1"},
Worker: workerRef, Controller: controllerRef,
ControllerState: setup.ControllerState, Input: setup.WorkInput,
})
waiting, _ := engine.Advance(context.Background(), execution.ID, execution.Revision, continuation.Handlers{
WorkerRef: workerRef,
Worker: exampleWorker(func(context.Context, continuation.WorkRequest) (continuation.WorkResult, error) {
return continuation.WorkResult{
Value: ai.JSON(`{"status":"running"}`), Progress: continuation.ProgressChanged,
}, nil
}),
ControllerRef: controllerRef, Controller: controller,
})
clock.now = clock.now.Add(5 * time.Minute)
ready, _ := engine.ResumeDue(context.Background(), waiting.ID, waiting.Revision)
fmt.Println(waiting.Status, ready.Status)
}
Output: waiting ready
func NewController ¶
func NewController(planner Planner, options ...ControllerOption) (*Controller, error)
NewController constructs a Loop Controller.
func (*Controller) Decide ¶
func (controller *Controller) Decide( ctx context.Context, request continuation.DecisionRequest, ) (continuation.Decision, error)
Decide implements continuation.Controller.
type ControllerOption ¶
type ControllerOption func(*controllerConfig) error
ControllerOption configures a Loop Controller.
func WithClock ¶
func WithClock(clock continuation.Clock) ControllerOption
WithClock replaces the Decision-time clock.
type ModelPlanner ¶
type ModelPlanner struct {
// contains filtered or unexported fields
}
ModelPlanner chooses bounded dynamic delays with one structured model call and no tools.
func NewModelPlanner ¶
func NewModelPlanner( model ai.LanguageModel, options ...ModelPlannerOption, ) (*ModelPlanner, error)
NewModelPlanner constructs a provider-neutral dynamic Planner.
func (*ModelPlanner) Plan ¶
func (planner *ModelPlanner) Plan(ctx context.Context, request PlanRequest) (Plan, error)
Plan implements Planner.
type ModelPlannerOption ¶
type ModelPlannerOption func(*modelPlannerConfig) error
ModelPlannerOption configures a ModelPlanner.
func WithDelayBounds ¶
func WithDelayBounds(minimum, maximum time.Duration) ModelPlannerOption
WithDelayBounds sets inclusive dynamic delay bounds. Both values must be positive whole seconds.
func WithMaxTokens ¶
func WithMaxTokens(maxTokens int) ModelPlannerOption
WithMaxTokens bounds one planner response.
type Plan ¶
type Plan struct {
Stop bool
After time.Duration
SignalKey string
Reason string
PlannerState ai.JSON
NextWorkInput ai.JSON
Output ai.JSON
Usage ai.Usage
}
Plan selects the next activation or stops the Loop.
type PlanRecord ¶
type PlanRecord struct {
Stop bool `json:"stop"`
After time.Duration `json:"after,omitempty"`
SignalKey string `json:"signal_key,omitempty"`
Reason string `json:"reason"`
}
PlanRecord is the bounded durable projection of one activation plan.
type PlanRequest ¶
type PlanRequest struct {
Iteration int
WorkInput ai.JSON
Evidence ai.JSON
PlannerState ai.JSON
Attempt int
Activation *continuation.Activation
Limits continuation.Limits
Accounting continuation.Accounting
Previous *PlanRecord
}
PlanRequest is the immutable input for planning after one Work iteration.
type Planner ¶
type Planner interface {
Plan(context.Context, PlanRequest) (Plan, error)
}
Planner selects when another Loop iteration should become runnable.
type PlannerFunc ¶
type PlannerFunc func(context.Context, PlanRequest) (Plan, error)
PlannerFunc adapts a function to Planner.
func (PlannerFunc) Plan ¶
func (function PlannerFunc) Plan(ctx context.Context, request PlanRequest) (Plan, error)
Plan implements Planner.
type State ¶
type State struct {
Version int `json:"version"`
Iterations int `json:"iterations"`
WorkInput ai.JSON `json:"input,omitempty"`
PlannerState ai.JSON `json:"planner_state,omitempty"`
Last *PlanRecord `json:"last,omitempty"`
}
State is the versioned Loop projection stored as continuation ControllerState.