Documentation
¶
Overview ¶
Package agentloop implements the decision layer of an agent DAG: the catalog of actions offered to the LLM, the goal state it works against, and the planner that turns a conversation into the next action.
Index ¶
- Constants
- func MergeParams(stepParams string, args map[string]any, pinned map[string]struct{}) string
- func ParamString(args map[string]any) string
- func PinnedParams(step ir.Step) map[string]struct{}
- func ValidTaskStatus(value string) bool
- type Catalog
- type Decision
- type DecisionKind
- type Event
- type MaskFunc
- type PendingAction
- type Planner
- type State
- func (s *State) Append(msgs ...ir.LLMMessage)
- func (s *State) ClearPendingBatch()
- func (s *State) CompactAllObservations(maxBytes int) int
- func (s *State) CompactObservations(keepRecent, maxBytes int) int
- func (s *State) EnableObservationAging()
- func (s *State) FailedTasks() []TaskState
- func (s *State) FinalizeEvent(toolCallID, step, status, finishedAt, reason string)
- func (s *State) LatestPromptTokens() int
- func (s *State) Marshal() (json.RawMessage, error)
- func (s *State) Messages() []ir.LLMMessage
- func (s *State) OpenTaskNames() []string
- func (s *State) PendingBatch() []PendingAction
- func (s *State) PriorAnswer(question string) (string, bool)
- func (s *State) QuestionCount() int
- func (s *State) RecordAnswer(question, answer string)
- func (s *State) RecordEvent(e Event)
- func (s *State) RecordStepRun(step string) int
- func (s *State) SetPendingBatch(actions []PendingAction)
- func (s *State) SetTaskStatus(name string, status TaskStatus, reason string) error
- func (s *State) Settled() bool
- func (s *State) StepRunCount(step string) int
- type TaskState
- type TaskStatus
Constants ¶
const ( // SetTaskStatusTool is the name of the tool the agent calls to record // where a task stands. It is reserved and cannot name a step. SetTaskStatusTool = "set_task_status" // AskUserTool is the name of the tool the agent calls to put a question // to a person. It is reserved and cannot name a step. AskUserTool = "ask_user" )
const ( // EventAction is one run of a declared step. EventAction = "action" // EventTaskStatus records the agent settling, or reopening, a task. // The new status is carried on the event. EventTaskStatus = "task_status" // EventAskUser is a question the agent put to a person. EventAskUser = "ask_user" // EventRejected is a tool call the agent could not carry out. EventRejected = "rejected" // EventStalled is a turn where the model declined to act. EventStalled = "stalled" )
Event kinds recorded on the agent's decision timeline.
Variables ¶
This section is empty.
Functions ¶
func MergeParams ¶
MergeParams combines the parameters a step supplies itself with the arguments the agent chose, rendering both as the "key=value" string a child DAG run expects. A pinned parameter is passed through exactly as the step wrote it, and an argument naming one is dropped: it was never offered, so a model that invented it does not get to override the author.
func ParamString ¶
ParamString renders tool-call arguments as the "key=value" parameter string a child DAG run expects. Keys are sorted so the same arguments always produce the same child run ID.
func PinnedParams ¶
PinnedParams lists the parameter names a step supplies itself.
func ValidTaskStatus ¶
ValidTaskStatus reports whether a value names a task status the agent may set. "open" is included: settling a task can be undone.
Types ¶
type Catalog ¶
type Catalog struct {
// contains filtered or unexported fields
}
Catalog is the set of actions an agent may choose from, expressed as LLM function-calling tools.
func NewCatalog ¶
NewCatalog builds the tool catalog from an agent DAG's declared steps. A step that runs a child DAG advertises that DAG's parameters, so the agent can pass arguments through.
func (*Catalog) Definitions ¶
func (c *Catalog) Definitions() []ir.ToolDefinition
Definitions returns the catalog in the form persisted for UI visibility.
func (*Catalog) StepFor ¶
StepFor resolves a tool name back to the step it runs. It returns false for CompleteTaskTool and for unknown names.
type Decision ¶
type Decision struct {
Kind DecisionKind
ToolCallID string
ToolName string
// Step is the declared step to run, set when Kind is DecideRunStep.
Step string
// Args are the child DAG parameters, set when Kind is DecideRunStep.
Args map[string]any
// Task, TaskStatus and Reason are set when Kind is DecideSetTaskStatus.
Task string
TaskStatus TaskStatus
Reason string
// Question is set when Kind is DecideAskUser.
Question string
// Content is the model's prose, set when Kind is DecideStop.
Content string
// Problem describes why the decision was rejected, set when Kind is DecideInvalid.
Problem string
}
Decision is one tool call the agent chose for this turn.
type DecisionKind ¶
type DecisionKind int
DecisionKind classifies what the agent chose to do this turn.
const ( // DecideRunStep runs one declared step. DecideRunStep DecisionKind = iota // DecideSetTaskStatus records where a task stands. DecideSetTaskStatus // DecideAskUser puts a question to a person and waits for the answer. DecideAskUser // DecideStop is returned when the model answers without calling a tool. DecideStop // DecideInvalid is returned when the model calls a tool that does not exist // or passes arguments that cannot be decoded. The caller reports the problem // back to the model and continues. DecideInvalid )
type Event ¶
type Event struct {
Turn int `json:"turn"`
Kind string `json:"kind"`
// ToolCallID ties this event to its observation when a turn contains
// multiple action calls.
ToolCallID string `json:"toolCallId,omitempty"`
// Name is the step or task the event concerns.
Name string `json:"name,omitempty"`
// Status is the resulting node status, for action events.
Status string `json:"status,omitempty"`
// Attempt counts this run of the step, starting at 1.
Attempt int `json:"attempt,omitempty"`
// Reason carries the agent's justification, or why a call was rejected.
Reason string `json:"reason,omitempty"`
StartedAt string `json:"startedAt,omitempty"`
FinishedAt string `json:"finishedAt,omitempty"`
// ChildDAGRunID identifies the child run this action produced, so the
// timeline can link straight to it. Empty for steps that run no child DAG.
ChildDAGRunID string `json:"childDagRunId,omitempty"`
// ChildDAGName is the child DAG that ran.
ChildDAGName string `json:"childDagName,omitempty"`
}
Event is one entry on the agent's decision timeline. The timeline is what makes an agent run legible: it records what ran, in what order, and when each task was satisfied, none of which a dependency graph can express.
func EventsFromState ¶
func EventsFromState(raw json.RawMessage) []Event
EventsFromState decodes the decision timeline persisted on an agent node. Unreadable or absent state yields no events rather than an error.
type MaskFunc ¶
type MaskFunc func([]ir.LLMMessage) []ir.LLMMessage
Planner asks the model which action to take next. MaskFunc hides secret values in the copy of a conversation that leaves for an external model.
type PendingAction ¶
type PendingAction struct {
ToolCallID string `json:"toolCallId"`
ToolName string `json:"toolName"`
Step string `json:"step"`
// Question is the text put to a person, set when the pending action is a
// question the agent asked.
Question string `json:"question,omitempty"`
}
PendingAction records the tool call whose observation has not been reported back to the LLM yet. It is set while a chosen step runs so that a run which suspends mid-action can report the outcome after it resumes.
type Planner ¶
type Planner struct {
// contains filtered or unexported fields
}
func NewPlanner ¶
func NewPlanner( provider llmpkg.Provider, cfg *ir.LLMConfig, catalog *Catalog, system string, mask MaskFunc, ) *Planner
NewPlanner builds a planner over a provider and an action catalog. The system prompt is prepended to the agent's own framing; callers pass it already resolved, so a workflow can parameterise its instructions.
type State ¶
type State struct {
Tasks []TaskState `json:"tasks"`
// Events is the decision timeline, in the order decisions were made.
Events []Event `json:"events,omitempty"`
// StepRuns counts how many times each step has been started.
StepRuns map[string]int `json:"stepRuns,omitempty"`
// Turns counts LLM decisions made so far.
Turns int `json:"turns,omitempty"`
// Pending is the legacy single action awaiting an observation. It is retained
// for runs persisted before action batches were supported.
Pending *PendingAction `json:"pending,omitempty"`
// PendingActions is the ordered action batch whose observations have not
// been reported to the model yet.
PendingActions []PendingAction `json:"pendingActions,omitempty"`
// Nudges counts consecutive turns where the LLM declined to act while tasks
// were still open.
Nudges int `json:"nudges,omitempty"`
// Answers records what a person replied to each question, so the agent
// is held to an answer it already has.
Answers map[string]string `json:"answers,omitempty"`
// ObservationAging records that old tool results must remain compacted for
// the rest of this run.
ObservationAging bool `json:"observationAging,omitempty"`
// contains filtered or unexported fields
}
State is the agent's durable memory. It survives suspension because it is persisted on the agent node and carried into the resumed run.
func LoadState ¶
func LoadState(raw json.RawMessage, messages []ir.LLMMessage, dag *ir.DAG) (*State, error)
LoadState restores state persisted by an earlier attempt of the same run and reconciles it with the DAG, so that editing the task list between attempts neither drops progress nor resurrects removed tasks.
func (*State) Append ¶
func (s *State) Append(msgs ...ir.LLMMessage)
Append adds a message to the conversation.
func (*State) ClearPendingBatch ¶ added in v2.15.0
func (s *State) ClearPendingBatch()
ClearPendingBatch removes every pending-action representation.
func (*State) CompactAllObservations ¶
CompactAllObservations replaces each tool result whose deterministic summary is smaller. It returns the number replaced so callers can avoid retrying an unchanged request.
func (*State) CompactObservations ¶
CompactObservations replaces all but the newest keepRecent tool results with deterministic one-line summaries. Positive maxBytes values also bound each summary. Assistant tool calls and result IDs remain unchanged so the conversation continues to satisfy provider tool protocols. Zero keepRecent disables compaction.
func (*State) EnableObservationAging ¶
func (s *State) EnableObservationAging()
EnableObservationAging keeps old observations compacted for subsequent decisions and across suspension or retry.
func (*State) FailedTasks ¶
FailedTasks lists the tasks the agent declared unachievable, with the reason it gave. A run with any of these has failed.
func (*State) FinalizeEvent ¶
FinalizeEvent updates the event for a suspended tool call with the outcome it reached. The step name supports state written before tool-call IDs were kept.
func (*State) LatestPromptTokens ¶
LatestPromptTokens returns the most recent prompt size reported by the provider. Zero means no decision reported usage.
func (*State) Marshal ¶
func (s *State) Marshal() (json.RawMessage, error)
Marshal serializes the state for persistence on the agent node.
func (*State) Messages ¶
func (s *State) Messages() []ir.LLMMessage
Messages returns the conversation so far.
func (*State) OpenTaskNames ¶
OpenTaskNames lists the tasks the agent has yet to settle.
func (*State) PendingBatch ¶ added in v2.15.0
func (s *State) PendingBatch() []PendingAction
PendingBatch returns the ordered tool calls awaiting observations.
func (*State) PriorAnswer ¶
PriorAnswer returns what a person already said to this exact question.
func (*State) QuestionCount ¶
QuestionCount reports how many questions have been answered so far.
func (*State) RecordAnswer ¶
RecordAnswer stores a reply so the same question is not put to a person twice.
func (*State) RecordEvent ¶
RecordEvent appends an entry to the decision timeline, stamping it with the turn it belongs to.
func (*State) RecordStepRun ¶
RecordStepRun counts a step start and returns the new total.
func (*State) SetPendingBatch ¶ added in v2.15.0
func (s *State) SetPendingBatch(actions []PendingAction)
SetPendingBatch records an ordered batch awaiting observations.
func (*State) SetTaskStatus ¶
func (s *State) SetTaskStatus(name string, status TaskStatus, reason string) error
SetTaskStatus records where a task now stands. Naming an unknown task, or restating the status a task already has, is reported back to the agent as a tool error rather than failing the run.
func (*State) StepRunCount ¶
StepRunCount reports how many times a step has been started in this run.
type TaskState ¶
type TaskState struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Status TaskStatus `json:"status,omitempty"`
// Reason is the justification the agent gave for the current status.
Reason string `json:"reason,omitempty"`
}
TaskState tracks one goal across the lifetime of an agent run.
func TasksFromState ¶
func TasksFromState(raw json.RawMessage) []TaskState
TasksFromState decodes the task progress persisted on an agent node. Unreadable or absent state yields no tasks rather than an error, so a display surface never fails on it.
type TaskStatus ¶
type TaskStatus string
TaskStatus is where a goal stands. A run ends once no task is open.
const ( // TaskOpen is a goal still to be settled. Tasks start here. TaskOpen TaskStatus = "open" // TaskCompleted is a goal that was achieved. TaskCompleted TaskStatus = "completed" // TaskSkipped is a goal the agent judged unnecessary. It does not fail // the run: nothing went wrong, there was simply nothing to do. TaskSkipped TaskStatus = "skipped" // TaskFailed is a goal that cannot be achieved. It fails the run, because // the goal was neither met nor waived. TaskFailed TaskStatus = "failed" )