event

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 14, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

Package event defines the core event types for the LoopKit event-sourced loop kernel. Events are append-only, immutable records of everything that happened in a loop. The chain hash provides tamper evidence and enables strict replay verification.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ComputeHash

func ComputeHash(prev [32]byte, e Envelope) [32]byte

ComputeHash computes the chain hash for an envelope. Formula: SHA-256(prevHash ‖ []byte(LoopID) ‖ Seq_as_8_big_endian_bytes ‖ []byte(Time.RFC3339Nano) ‖ []byte(Kind) ‖ Payload)

func Marshal

func Marshal(v any) ([]byte, error)

Marshal produces canonical JSON: sorted keys at every nesting level, no insignificant whitespace. This is the one encoding function used everywhere; hashing correctness depends on it being deterministic.

Algorithm: marshal v to a generic interface{}, then re-encode with sorted keys.

func Unmarshal

func Unmarshal(data []byte, v any) error

Unmarshal is a thin wrapper around json.Unmarshal for symmetry with Marshal.

Types

type ActionRequestedPayload

type ActionRequestedPayload struct {
	ActionID      string          `json:"action_id"`
	ActionType    string          `json:"action_type"`
	ActionPayload json.RawMessage `json:"action_payload"`
}

ActionRequestedPayload is the intent record appended before an action executes. This implements the durability protocol: intent before effect.

type BudgetChargedPayload

type BudgetChargedPayload struct {
	// Tokens charged in this event.
	Tokens int64 `json:"tokens,omitempty"`
	// USD charged in this event.
	USD float64 `json:"usd,omitempty"`
	// WallClockMs charged in this event (milliseconds).
	WallClockMs int64 `json:"wall_clock_ms,omitempty"`
	// Iterations charged in this event.
	Iterations int `json:"iterations,omitempty"`
	// ActionType is the kind of action that generated this charge ("model" | "tool" | "iteration").
	ActionType string `json:"action_type"`
}

BudgetChargedPayload records an actual spend charge against the budget ledger.

type CompactionAppliedPayload

type CompactionAppliedPayload struct {
	Strategy string `json:"strategy"`
	// PlanJSON is the serialised ctxmgr.Plan. Replay reads this instead of re-deciding.
	PlanJSON json.RawMessage `json:"plan_json"`
	// Legacy fields kept for backward compat with SP3 stub (DroppedFrom/To/SummaryRef).
	DroppedFrom uint64 `json:"dropped_from,omitempty"`
	DroppedTo   uint64 `json:"dropped_to,omitempty"`
	SummaryRef  string `json:"summary_ref,omitempty"`
}

CompactionAppliedPayload records a context-management compaction that occurred before a ModelCall. The Plan is stored verbatim so replay can re-apply it deterministically without re-running the Strategy.

type ConvergenceWarningPayload

type ConvergenceWarningPayload struct {
	// Detector is the name of the detector that fired ("oscillation" | "zero-progress" | "depth").
	Detector string `json:"detector"`
	// Reason is a human-readable explanation.
	Reason string `json:"reason"`
	// Count is how many times the condition has been observed.
	Count int `json:"count"`
}

ConvergenceWarningPayload is injected when the convergence monitor fires in Redirect mode. The transition can inspect this event and change strategy.

type Envelope

type Envelope struct {
	// LoopID identifies which loop this event belongs to.
	LoopID LoopID
	// Seq is 1-based and contiguous within a loop. No gaps are permitted.
	Seq uint64
	// Time is injected by the runtime Clock. Transitions must NOT read the system clock;
	// they must use ctx.Now which comes from the last event's Time field.
	Time time.Time
	// Kind identifies the event type. See Kind constants in kinds.go.
	Kind Kind
	// Payload is canonical JSON (sorted keys, no insignificant whitespace).
	// Always produced via event.Marshal.
	Payload []byte
	// Hash is SHA-256(prevHash ‖ LoopID ‖ Seq ‖ Time(RFC3339Nano) ‖ Kind ‖ Payload).
	// The zero value of prevHash is used for the first event in a loop.
	Hash [32]byte
}

Envelope is the immutable record wrapper for every event stored in the log. The Hash field chains each envelope to its predecessor, enabling tamper detection.

type ForkedFromPayload

type ForkedFromPayload struct {
	// SourceLoopID is the loop ID that was forked from.
	SourceLoopID LoopID `json:"source_loop_id"`
	// AtSeq is the sequence number at which the fork diverged.
	// Events 1..AtSeq are replayed from the source; events after are live.
	AtSeq uint64 `json:"at_seq"`
}

ForkedFromPayload records that a forked loop branched off from a source trajectory. The forked loop's first event is ForkedFrom; the source log is immutable.

type HumanRequestedPayload

type HumanRequestedPayload struct {
	ActionID string `json:"action_id"`
	Prompt   string `json:"prompt"`
}

HumanRequestedPayload records a pause for human input.

type HumanRespondedPayload

type HumanRespondedPayload struct {
	ActionID string `json:"action_id"`
	Response string `json:"response"`
}

HumanRespondedPayload records the human's response.

type InterruptedPayload

type InterruptedPayload struct {
	Reason string `json:"reason"`
}

InterruptedPayload records why a loop was interrupted.

type IterationStartedPayload

type IterationStartedPayload struct {
	Iteration int `json:"iteration"`
}

IterationStartedPayload marks the beginning of iteration n.

type Kind

type Kind string

Kind is the string identifier for an event type.

const (
	KindLoopStarted        Kind = "LoopStarted"
	KindIterationStarted   Kind = "IterationStarted"
	KindActionRequested    Kind = "ActionRequested"
	KindModelCalled        Kind = "ModelCalled"
	KindToolCalled         Kind = "ToolCalled"
	KindHumanRequested     Kind = "HumanRequested"
	KindHumanResponded     Kind = "HumanResponded"
	KindSubAgentSpawned    Kind = "SubAgentSpawned"    // reserved: SP5
	KindSubAgentCompleted  Kind = "SubAgentCompleted"  // reserved: SP5
	KindBudgetCharged      Kind = "BudgetCharged"      // SP3: governance
	KindPolicyDecided      Kind = "PolicyDecided"      // SP3: governance
	KindConvergenceWarning Kind = "ConvergenceWarning" // SP3: convergence monitor
	KindCompactionApplied  Kind = "CompactionApplied"  // SP3: context management
	KindSnapshotTaken      Kind = "SnapshotTaken"
	KindInterrupted        Kind = "Interrupted"
	KindResumed            Kind = "Resumed"
	KindLoopFinished       Kind = "LoopFinished"
	KindForkedFrom         Kind = "ForkedFrom" // SP4: fork replay
)

Event kind constants. All kinds listed here (including reserved ones for future sub-projects).

type LoopFinishedPayload

type LoopFinishedPayload struct {
	OutcomeKind string          `json:"outcome_kind"`
	Result      json.RawMessage `json:"result,omitempty"`
	Error       string          `json:"error,omitempty"`
	TotalSpend  json.RawMessage `json:"total_spend,omitempty"`
}

LoopFinishedPayload records the terminal outcome of a loop.

type LoopID

type LoopID string

LoopID is a ULID string identifying a loop instance. Generated by the runtime and recorded in the LoopStarted event.

type LoopStartedPayload

type LoopStartedPayload struct {
	Name         string          `json:"name"`
	InitialState json.RawMessage `json:"initial_state"`
	Seed         int64           `json:"seed"`
	ConfigHash   string          `json:"config_hash"`
	// SP5: multi-agent fields (zero value = top-level loop)
	ParentID LoopID `json:"parent_id,omitempty"` // empty for root loops
	Depth    int    `json:"depth,omitempty"`     // 0 = root; parent+1 for children
}

LoopStartedPayload carries the initial configuration of a loop.

type ModelCalledPayload

type ModelCalledPayload struct {
	ActionID   string          `json:"action_id"`
	Request    json.RawMessage `json:"request"`
	Response   json.RawMessage `json:"response"`
	Usage      ModelUsage      `json:"usage"`
	Provider   string          `json:"provider"`
	Model      string          `json:"model"`
	DurationMs int64           `json:"duration_ms"`
}

ModelCalledPayload records the result of a model completion call.

type ModelUsage

type ModelUsage struct {
	In      int     `json:"in"`
	Out     int     `json:"out"`
	CostUSD float64 `json:"cost_usd"`
}

ModelUsage tracks token and cost consumption for a single model call.

type PolicyDecidedPayload

type PolicyDecidedPayload struct {
	// ActionID links back to the ActionRequested event.
	ActionID string `json:"action_id"`
	// Decision is "allow" | "deny" | "ask-human".
	Decision string `json:"decision"`
	// Capability is the capability string that was evaluated.
	Capability string `json:"capability"`
	// Tool is the tool name that triggered the check.
	Tool string `json:"tool"`
	// Reason is the human-readable explanation from the policy engine.
	Reason string `json:"reason"`
}

PolicyDecidedPayload records a policy engine decision for a tool call.

type ResumedPayload

type ResumedPayload struct{}

ResumedPayload has no fields — resumption is its own record.

type Snapshot

type Snapshot struct {
	// LoopID identifies the loop this snapshot belongs to.
	LoopID LoopID
	// Seq is the sequence number of the last event included in this snapshot.
	Seq uint64
	// State is the canonical JSON-encoded state at this point.
	State []byte
	// StateHash is SHA-256 of the State bytes, for integrity verification.
	StateHash [32]byte
	// TakenAt is when the snapshot was recorded (wall clock of the runner).
	TakenAt time.Time
}

Snapshot captures a materialized state at a given sequence number. Snapshots are used to bound replay time: instead of replaying from the beginning, resume starts from the latest snapshot and replays only the tail events.

type SnapshotTakenPayload

type SnapshotTakenPayload struct {
	Seq       uint64 `json:"seq"`
	StateHash string `json:"state_hash"` // hex-encoded SHA-256 of state
}

SnapshotTakenPayload records when a snapshot was written.

type StreamChunk

type StreamChunk struct {
	// Delta contains the incremental content update (e.g., a text delta or tool-use chunk).
	// See core/model.Chunk for the wire format definition.
	Delta json.RawMessage `json:"delta"`
	// Usage is set only in the final chunk; nil for intermediate chunks.
	Usage *ModelUsage `json:"usage,omitempty"`
}

StreamChunk represents a chunk of streamed model response data. It is used by StreamReader.Recv() and StreamObserver callbacks.

type SubAgentCompletedPayload

type SubAgentCompletedPayload struct {
	ChildLoopID string `json:"child_loop_id"`
	Definition  string `json:"definition"`
	// OutcomeKind is "Completed" | "BudgetExceeded" | "Stuck" | "Failed" | "Interrupted" | "PolicyDenied".
	OutcomeKind string `json:"outcome_kind"`
	// RespJSON is the marshalled child result (only set when OutcomeKind == "Completed").
	RespJSON json.RawMessage `json:"resp_json,omitempty"`
	// Error is a human-readable error string for non-Completed outcomes.
	Error string `json:"error,omitempty"`
	// ChildSpend is the actual spend charged to the parent ledger for this child.
	ChildSpend json.RawMessage `json:"child_spend,omitempty"`
}

SubAgentCompletedPayload records the result of a child loop. It is delivered to the parent transition after the child reaches a terminal outcome.

type SubAgentSpawnedPayload

type SubAgentSpawnedPayload struct {
	ChildLoopID string          `json:"child_loop_id"`
	Definition  string          `json:"definition"`
	Request     json.RawMessage `json:"request"`
}

SubAgentSpawnedPayload records that a child loop was launched by the parent.

type ToolCalledPayload

type ToolCalledPayload struct {
	ActionID       string          `json:"action_id"`
	Tool           string          `json:"tool"`
	Args           json.RawMessage `json:"args"`
	Result         json.RawMessage `json:"result"`
	IsError        bool            `json:"is_error"`
	DurationMs     int64           `json:"duration_ms"`
	IdempotencyKey string          `json:"idempotency_key"`
}

ToolCalledPayload records the result of a tool execution.

Jump to

Keyboard shortcuts

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