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 ¶
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.
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 (*Recorder) RecordEvent ¶
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 ¶
RecordMessage appends a conversation entry.
func (*Recorder) RecordReset ¶
RecordReset discards the messages recorded so far.
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 ¶
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 (*Session) AgentMessages ¶
Messages converts a loaded session back into agent messages, ready to seed a resumed run.
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 ¶
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 ¶
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.