agent

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Sep 7, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package agent defines one agent declaratively: an identity, a capability card, and a step plan, bound into one value. It also holds the envelope-to-events translator, the composition-layer code that turns a delivered Message, an Ack, or a verified thread into one events.Event.

Map: agent.go = Agent, New, Name, Capabilities. events.go = MessageDeliveredEvent, MessageAckedEvent, ThreadVerifiedEvent. translator.go = ErrNoBus, EmitMessageDelivered, EmitMessageAcked, EmitThreadVerified. run.go = AckWait, Run, ErrEscalated, ErrNoWait, ErrNoThread, ErrOverBudget, Run's optional *heartbeat.Monitor beat and forget logic, Run's optional *contextbudget.Limits budget check, and confirmStep's room-stamping of Message.Room before a.id.Sign. The definition is data; it states who the agent is, what it can do, and what it runs. Run drives the bound plan in-process, through flow.Run. Rationale: ../docs/plans/agent.md. Contribution rules: ../AGENTS.md.

Index

Constants

View Source
const MessageAckedEvent events.Name = "agent.message_acked"

MessageAckedEvent is the event kind EmitMessageAcked emits after an Ack validates. See translator.go.

View Source
const MessageDeliveredEvent events.Name = "agent.message_delivered"

MessageDeliveredEvent is the event kind EmitMessageDelivered emits after a delivered Message verifies. See translator.go.

View Source
const ThreadVerifiedEvent events.Name = "agent.thread_verified"

ThreadVerifiedEvent is the event kind EmitThreadVerified emits after a thread verifies. See translator.go.

Variables

View Source
var (
	ErrNoIdentity = errors.New("agent: identity is required")
	ErrNoPlan     = errors.New("agent: plan is required")
)

Sentinel errors for New and Run; test with errors.Is. A card validation failure wraps discovery's own error instead, because discovery exports no sentinel.

View Source
var (
	ErrEscalated  = errors.New("agent: step escalated")
	ErrNoWait     = errors.New("agent: wait is required")
	ErrNoThread   = errors.New("agent: thread id is required")
	ErrOverBudget = errors.New("agent: context budget exceeded")
)

Sentinel errors for Run; test with errors.Is. ErrNoBus, already exported by the phase 20 translator, is reused for a nil bus.

View Source
var ErrNoBus = errors.New("agent: bus is required")

ErrNoBus is the sentinel every EmitX function returns when its bus argument is nil. It replaces a nil-pointer panic inside events.Bus.Emit; panics inside a package violate AGENTS.md.

Functions

func EmitMessageAcked

func EmitMessageAcked(ctx context.Context, bus *events.Bus, a envelope.Ack) error

EmitMessageAcked validates a, then emits one Event named MessageAckedEvent onto bus. It returns ErrNoBus when bus is nil. It returns the Validate error, unwrapped, when a fails to validate; neither failure emits an event. On success it returns the raw error from bus.Emit.

func EmitMessageDelivered

func EmitMessageDelivered(ctx context.Context, bus *events.Bus, m envelope.Message) error

EmitMessageDelivered verifies m's signature, then emits one Event named MessageDeliveredEvent onto bus. It returns ErrNoBus when bus is nil. It returns the VerifySignature error, unwrapped, when m fails to verify; neither failure emits an event. On success it returns the raw error from bus.Emit.

func EmitThreadVerified

func EmitThreadVerified(ctx context.Context, bus *events.Bus, msgs []envelope.Message) error

EmitThreadVerified verifies msgs as one hash-linked thread, then emits one Event named ThreadVerifiedEvent onto bus. It returns ErrNoBus when bus is nil. It returns the VerifyThread error, unwrapped, when the thread fails to verify; neither failure emits an event. On success it returns the raw error from bus.Emit.

Types

type AckWait

type AckWait func(ctx context.Context, msg envelope.Message) (envelope.Ack, error)

AckWait resolves one step's ack. Run calls it once per step flow.Run gates behind Confirm, with the signed step message. It returns the receiver's real envelope.Ack, or an error. An implementation wraps ErrEscalated with %w to route the step to a human instead of resolving an ack.

type Agent

type Agent struct {
	// contains filtered or unexported fields
}

Agent binds one identity, one capability card, and one step plan into a single declarative value. Build it with New; the fields stay unexported.

func New

func New(id *identity.Identity, card discovery.Card, plan *flow.Definition) (*Agent, error)

New builds an Agent from an identity, a capability card, and a step plan. It checks id for nil, calls card.Validate(), then checks plan for nil, in that order, and returns the first error hit. New does not re-run flow's cycle check: a plan built through flow.New already passed it, and a zero-value plan carries no step for the check to reject.

func (*Agent) Capabilities

func (a *Agent) Capabilities() []string

Capabilities returns the card's Capabilities slice: the same backing array Parse or the caller set, with no defensive copy. This matches discovery.Card, which carries the same caller-owned mutability.

func (*Agent) Name

func (a *Agent) Name() string

Name returns the card's Name field, unchanged. It applies no trim; Card.Validate already rejects a name that is blank after TrimSpace, and Name returns the stored value as-is.

func (*Agent) Plan

func (a *Agent) Plan() *flow.Definition

Plan returns the step plan New bound to a. The returned pointer is the same one New stored; read it through flow's accessors and never mutate it.

func (*Agent) Run

func (a *Agent) Run(
	ctx context.Context, threadID string, m *machine.Definition,
	in machine.InOut, wait AckWait, bus *events.Bus, hb *heartbeat.Monitor,
	room string, budget *contextbudget.Limits,
) (machine.Status, machine.InOut, error)

Run drives a's bound plan (the *flow.Definition New bound) through flow.Run, in-process. threadID names the one envelope thread this run's step messages share. m is the status model the plan's steps target. in is the starting record. wait resolves each gated step's ack. bus receives MessageDeliveredEvent, MessageAckedEvent, and, once per successful run with one or more gated steps, ThreadVerifiedEvent.

Run checks a and a.id for nil first, then wait for nil, then bus for nil, then threadID for empty, in that order, before it touches m or a's plan; each check returns machine.Status(""), in unchanged, and its sentinel.

For each step flow.Run gates behind Confirm, Run builds an envelope.Message from the step's ID, threadID, and Payload, with Version, Intent, and Epistemic set to values that pass Validate on their own, signs it with a's identity, and chains it to the previous step message with PrevHash. It calls EmitMessageDelivered, then wait. A wait error returns unchanged, without calling EmitMessageAcked. A nil wait error runs EmitMessageAcked and requires AckConfirmed before the step counts as done.

A step confirmed more than once in one thread keeps the thread's IDs unique: the second message gets "#2" appended to the step ID, the third "#3", and so on. A looped child step and two Sub children sharing one step ID both hit this rule. The suffix never collides with a caller step ID: the scan skips any suffix already in use.

On a successful run with one or more gated steps, Run calls EmitThreadVerified once, over every step message it built, in order.

hb is an optional step-liveness heartbeat. A nil hb skips every heartbeat call; Run's behavior is otherwise unchanged. A non-nil hb beats one id, a.id.Signer()+":"+threadID, right before each gated step's wait call, and forgets that id once, on every return path. A panel step reaches no beat call; see docs/plans/agents/ phase26_agent_heartbeat.md's disclosed scope limit. Run never calls hb.Dead and never aborts a step on staleness; an external caller holding the same hb polls Dead on its own schedule.

An empty room reproduces today's zero-value behavior: Message.Room stays "". A non-empty room makes confirmStep stamp it onto Message.Room before a.id.Sign runs, on every gated step's built message.

budget is an optional context budget. A nil budget skips every budget check; Run's behavior is otherwise unchanged. A non-nil budget runs budget.Validate() once, at the same point Run checks wait, bus, and threadID; an invalid budget returns machine.Status(""), in unchanged, and the wrapped Validate error. A non-nil, valid budget makes confirmStep check budget.Fits, right before each gated step's wait call, against the cumulative byte total of every message built so far plus the step about to run, and the 1-indexed count of steps built so far including that step. A Fits failure returns ErrOverBudget, wrapping the step ID, without calling hb.Beat, wait, or EmitMessageAcked for that step. A panel step reaches no confirmStep wait call, so its payload never adds to the running total and never trips budget; see docs/plans/agents/ phase32_context_budget.md's disclosed scope limit.

func (*Agent) Signer

func (a *Agent) Signer() string

Signer returns the hex signer string of the identity New bound to a. It matches identity.Signer exactly. A nil Agent, or one bound to a nil identity, returns "".

Jump to

Keyboard shortcuts

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