Help us shape the future of Go! Take the 2026 Go Developer Survey

session

package
v0.12.0 Latest Latest
Warning

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

Go to latest
Published: Aug 19, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package session records a run to disk so it can be inspected afterwards and picked up again.

An autonomous run is unattended by definition: nobody watched it, and by the time anyone looks the terminal is gone. A session log is what turns "it failed overnight" into something answerable - what it tried, what the tools returned, and where it stopped.

It is also what makes a run resumable. The conversation is the entire state of an agent, so writing it down and reading it back is enough to continue: no server-side session, no snapshot format, nothing to keep in sync.

The format is JSON Lines. One record per line, appended as the run goes, so a log is readable while the run is still going and a crashed run still leaves everything up to the crash. A truncated final line loses one record rather than the file.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewID

func NewID(now time.Time) string

NewID returns a session identifier that sorts chronologically.

Time-ordered rather than random so `ls` shows runs in the order they happened, which is how anyone actually looks for one.

func Resolve

func Resolve(dir, reference string) (string, error)

Resolve turns a session reference into a path.

A reference is an id, a filename, or a path. "last" picks the most recent, which is what someone reaching for a resume almost always means.

Types

type Activity

type Activity struct {
	Kind      string `json:"kind"`
	ID        string `json:"id,omitempty"`
	Name      string `json:"name,omitempty"`
	Arguments string `json:"arguments,omitempty"`
	Result    any    `json:"result,omitempty"`
	Failure   string `json:"failure,omitempty"`
}

Activity is a tool call recorded in a log.

type Entry

type Entry struct {
	ID      string
	Path    string
	Task    string
	Started time.Time

	// Complete reports whether the run recorded an outcome.
	Complete bool

	// Reason is the recorded stop reason, empty for an unfinished run.
	Reason string
}

Entry is a session listed in a directory.

func List

func List(dir string) ([]Entry, error)

List enumerates the sessions in dir, newest first.

Reads each log rather than just stat-ing it, because the useful columns - the task, whether it finished - live inside. Sessions are small and there are not many; a listing that only showed filenames would send the user to `cat` anyway.

type Event

type Event struct {
	Kind      string `json:"kind"`
	Tool      string `json:"tool,omitempty"`
	Text      string `json:"text,omitempty"`
	Iteration int    `json:"iteration,omitempty"`
}

Event is something that happened during the run.

type Kind

type Kind string

Kind identifies a record.

const (
	// KindMeta opens a log: the task, model and settings the run started with.
	// Exactly one, first.
	KindMeta Kind = "meta"

	// KindMessage is one conversation message. Replaying these in order
	// reconstructs the agent's state.
	KindMessage Kind = "message"

	// KindEvent is something that happened - a tool call, a retry, a nudge.
	// Not needed to resume; kept because it is what explains a run afterwards.
	KindEvent Kind = "event"

	// KindResult closes a log with the outcome. Absent means the run did not
	// finish, which is itself worth knowing.
	KindResult Kind = "result"

	// KindReset discards the messages recorded before it. The engine compacts
	// its own history, and a log that kept both the pre- and post-compaction
	// turns would resume into a conversation that never happened. Events are
	// kept: they are the narrative of the run, not its state.
	KindReset Kind = "reset"
)

type Message

type Message struct {
	Type     string    `json:"type"`
	Text     string    `json:"text"`
	Activity *Activity `json:"activity,omitempty"`
}

Message is one conversation entry.

The activity is stored as its own object rather than a free-form bag, so a log written today still reads back into a run tomorrow: a typed field either decodes or does not, where a map quietly loses whatever it did not expect.

type Meta

type Meta struct {
	// ID identifies the session, and names its file.
	ID string `json:"id"`

	// Task is the brief the run was given.
	Task string `json:"task"`

	Model string `json:"model"`
	// Provider is the selected named connection; Driver is the resolved
	// implementation that handles its endpoint and protocol quirks.
	Provider string `json:"provider"`
	Driver   string `json:"driver"`

	// Workdir is where the agent's tools operated.
	Workdir string `json:"workdir"`

	// ResumedFrom names the session this one continues, if any.
	ResumedFrom string `json:"resumedFrom,omitempty"`
}

Meta describes how a run started.

type Record

type Record struct {
	Kind Kind      `json:"kind"`
	At   time.Time `json:"at"`

	// Meta is set on a KindMeta record.
	Meta *Meta `json:"meta,omitempty"`

	// Message is set on a KindMessage record.
	Message *Message `json:"message,omitempty"`

	// Event is set on a KindEvent record.
	Event *Event `json:"event,omitempty"`

	// Result is set on a KindResult record.
	Result *Result `json:"result,omitempty"`
}

Record is one line of a session log.

type Recorder

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

Recorder adapts a session Writer to the agent's recorder interface.

The engine knows nothing about files; it hands over what happened and this decides where it lands. That is what keeps a session log an operational concern rather than something the loop has to carry.

func NewRecorder

func NewRecorder(writer *Writer) *Recorder

NewRecorder wraps a writer.

func (*Recorder) RecordEvent

func (r *Recorder) RecordEvent(kind, tool, text string, iteration int) error

RecordEvent appends something that happened.

Token-by-token narration is deliberately dropped: it is the same content the finished message already carries, and keeping it would make the log an order of magnitude larger for nothing.

func (*Recorder) RecordMessage

func (r *Recorder) RecordMessage(message agent.Message) error

RecordMessage appends a conversation entry.

func (*Recorder) RecordReset

func (r *Recorder) RecordReset() error

RecordReset discards the messages recorded so far.

func (*Recorder) RecordResult

func (r *Recorder) RecordResult(summary agent.Summary) error

RecordResult appends the outcome and closes the log.

type Result

type Result struct {
	Reason  string `json:"reason"`
	Message string `json:"message,omitempty"`
	Code    int    `json:"code"`

	Iterations    int `json:"iterations"`
	Calls         int `json:"calls"`
	Continuations int `json:"continuations"`
	Cycles        int `json:"cycles"`
	Settles       int `json:"settles"`
}

Result is how a run ended.

type Session

type Session struct {
	Meta     Meta
	Messages []Message
	Events   []Event
	Result   *Result

	// Truncated reports that the log ended mid-record, which is what a crashed
	// or killed run leaves behind. The records before it are still usable.
	Truncated bool
}

Session is a log read back from disk.

func Load

func Load(path string) (*Session, error)

Load reads a session log.

A malformed line is tolerated rather than fatal: a log is written by a process that may be killed at any moment, and refusing to read the ninety-nine good records because the hundredth is half-written would defeat the purpose.

func Read

func Read(r io.Reader) (*Session, error)

Read parses a session log from a reader.

func (*Session) AgentMessages

func (s *Session) AgentMessages() []agent.Message

Messages converts a loaded session back into agent messages, ready to seed a resumed run.

func (*Session) Complete

func (s *Session) Complete() bool

Complete reports whether the run recorded an outcome.

type Writer

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

Writer appends records to a session log.

Safe for concurrent use: the engine emits events from its own goroutine while the caller may be recording messages.

func Create

func Create(dir, id string, meta Meta) (*Writer, error)

Create opens a new session log under dir.

The directory is created if needed. A session whose id already exists is an error rather than an append: two runs sharing a log would interleave into something that resumes as neither.

func Start

func Start(dir string, now time.Time, meta Meta) (*Writer, error)

Start opens a log for a run beginning at now, choosing an unused id.

Two runs started in the same second collide on the time-derived id, and one of them would otherwise lose its log entirely. A suffix is added rather than finer timestamps because precision alone cannot guarantee uniqueness across processes - only claiming the file can.

func (*Writer) Close

func (w *Writer) Close() error

Close releases the file. Safe to call twice.

func (*Writer) Event

func (w *Writer) Event(event Event) error

Event records something that happened.

func (*Writer) ID

func (w *Writer) ID() string

ID returns the session identifier.

func (*Writer) Message

func (w *Writer) Message(message Message) error

Message records a conversation entry.

func (*Writer) Path

func (w *Writer) Path() string

Path returns the log file.

func (*Writer) Reset

func (w *Writer) Reset() error

Reset discards the messages recorded so far.

func (*Writer) Result

func (w *Writer) Result(result Result) error

Result records the outcome and closes the log.

Jump to

Keyboard shortcuts

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