events

package
v0.4.10 Latest Latest
Warning

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

Go to latest
Published: Aug 8, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package events is the append-only event log: the single write path for the record of everything (session lifecycle, memory write/read/supersede, injection, task transition, gardener action). Telemetry, retrieval stats, and the console feed all derive from this log. SSE fan-out is added in a later phase.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Truncate

func Truncate(s string, maxRunes int) string

Truncate caps s to maxRunes runes, appending truncationMarker when it trims. A non-positive maxRunes disables truncation (returns s unchanged) -- the default for captured Interactions content, where retention pruning rather than truncation is the growth control. Rune-safe: never splits a multibyte rune.

Types

type KindTick

type KindTick struct {
	ID   string
	TS   time.Time
	Kind string
}

KindTick is one event's id, timestamp, and kind -- the minimal projection the console buckets into the interaction-volume histogram. ID lets an interactive bucket identify its newest represented row without fetching wide event payloads for the chart.

type Recorder

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

Recorder appends events to the log, reads them back, and fans successfully recorded events out to live subscribers (the console SSE feed).

func NewRecorder

func NewRecorder(db *sql.DB) *Recorder

NewRecorder returns a Recorder backed by db.

func (*Recorder) ByID

func (r *Recorder) ByID(ctx context.Context, id string) (core.Event, bool, error)

ByID returns a single event by its id. ok is false (with a nil error) when no event has that id.

func (*Recorder) ByKinds

func (r *Recorder) ByKinds(ctx context.Context, kinds []core.EventKind, beforeTS, beforeID string, limit int) ([]core.Event, error)

ByKinds returns events of any of the given kinds, newest first, strictly older than the compound (beforeTS, beforeID) cursor when it is set -- so a caller can page backwards through the Interactions feed without missing or repeating rows across a ts tie (ids are ULIDs, lexically ordered like ts). An empty kinds slice returns nil; a non-positive limit defaults to 200.

func (*Recorder) ByKindsAfter added in v0.4.4

func (r *Recorder) ByKindsAfter(ctx context.Context, kinds []core.EventKind, afterTS, beforeTS, beforeID string, limit int) ([]core.Event, error)

ByKindsAfter returns events of any of the given kinds at or after afterTS, newest first. The optional compound (beforeTS, beforeID) cursor pages farther back without crossing the lower bound. It is the bounded-history query behind the Interactions screen's explicit "add recent" action; keeping the bound in SQL avoids reading an unbounded tail only to discard it in the console layer. An empty kinds slice returns nil; a non-positive limit defaults to 200.

func (*Recorder) ByKindsSince

func (r *Recorder) ByKindsSince(ctx context.Context, kinds []core.EventKind, sinceTS, sinceID string, limit int) ([]core.Event, error)

ByKindsSince returns events of any of the given kinds strictly newer than the (sinceTS, sinceID) cursor, oldest first -- the gap-fill query an SSE client runs after a reconnect to recover rows it missed. An empty kinds slice returns nil; a non-positive limit defaults to 200.

func (*Recorder) BySession

func (r *Recorder) BySession(ctx context.Context, sessionID string, limit int) ([]core.Event, error)

BySession returns a session's events in chronological order (oldest first), so a caller can render the session's timeline. A non-positive limit defaults to 500.

func (*Recorder) KindTimeline

func (r *Recorder) KindTimeline(ctx context.Context, kinds []core.EventKind, project, sinceTS string, limit int) ([]KindTick, error)

KindTimeline returns the (id, ts, kind) of every event of the given kinds at or after sinceTS, newest first and capped at limit. project scopes to one project slug when non-empty. Only three narrow columns are read, so a wide window stays cheap. An empty sinceTS spans all history (bounded by limit); an empty kinds slice or non-positive limit returns nil.

func (*Recorder) LatestBySession added in v0.4.10

func (r *Recorder) LatestBySession(ctx context.Context, sessionID string, kinds []core.EventKind, limit int) ([]core.Event, error)

LatestBySession returns a session's most recent events of the given kinds, newest first, capped at limit (default 50). Unlike BySession -- whose limit truncates from the oldest side, for timelines -- this reads from the newest side, for "what did this agent just do" trails. An empty kinds slice spans all kinds.

func (*Recorder) PruneKinds

func (r *Recorder) PruneKinds(ctx context.Context, kinds []core.EventKind, before time.Time) (int64, error)

PruneKinds deletes events of the given kinds recorded strictly before cutoff, returning the number removed. It is the retention path for transport-level Interactions events (tool.call, hook.prompt); domain events are never passed in. An empty kinds slice or zero cutoff deletes nothing.

func (*Recorder) RecentExcluding

func (r *Recorder) RecentExcluding(ctx context.Context, limit int, exclude ...core.EventKind) ([]core.Event, error)

RecentExcluding returns the most recent events, newest first, omitting the given kinds -- the overview's business-level feed, which hides transport-level tool.call / hook.prompt noise. A non-positive limit defaults to 50.

func (*Recorder) Record

func (r *Recorder) Record(ctx context.Context, e core.Event) (string, error)

Record appends an event, stamping a ULID id and UTC timestamp when absent and serializing Payload to JSON. It returns the stored event's id. A non-fatal logging call site may ignore the id but should not ignore the error.

func (*Recorder) RecordOnce added in v0.4.10

func (r *Recorder) RecordOnce(ctx context.Context, e core.Event) (id string, recorded bool, err error)

RecordOnce appends an event only if no event of its kind exists for its item -- the once-per-item latch behind moments like the momentum first-reuse mark. The guard and the insert are a single statement, so two concurrent recorders cannot both mint the moment; recorded is false when the latch had already been set, and subscribers see the event only when it actually landed.

func (*Recorder) SetFeatures added in v0.4.10

func (r *Recorder) SetFeatures(base config.Features)

SetFeatures arms the momentum milestone layer with the file/env features base. From then on every successfully recorded event runs store.CheckMilestones, which resolves the effective features live (base overlaid with the console's stored override) and does nothing while momentum is off -- so the console toggle applies immediately, with no daemon restart. Call it once at wiring time, before serving.

func (*Recorder) Subscribe

func (r *Recorder) Subscribe() (<-chan core.Event, func())

Subscribe registers a live-event channel and returns it with an unsubscribe func the caller must invoke when done (idempotent). Events are delivered best-effort: a full channel drops rather than blocks.

func (*Recorder) TimestampsSince added in v0.4.10

func (r *Recorder) TimestampsSince(ctx context.Context, since time.Time, limit int) ([]time.Time, error)

TimestampsSince returns the timestamps of every event at or after since, oldest first, capped at limit (default 2000) -- the minimal projection behind the Now screen's activity pulse, which buckets them client-blind into a per-interval histogram. All kinds count: the pulse measures how hard the fleet is running, and a tool call is exactly that.

Jump to

Keyboard shortcuts

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