Session

A named container grouping all LoopRecords for one agent session. A Session represents a task the agent performs. It has identity, formation history, configuration, and contains an ordered sequence of Loops (iterations).

Sessions are created automatically by SessionRecorder when a new session_id first appears in an AgentStart event, or explicitly by the caller.

Concept Overview

Session [EXISTS]
├── HEADER
│   ├── session_id, agent_id [EXISTS]
│   ├── formation [EXISTS] — Explicit / FirstLoop / InactivityTimeout
│   ├── scope [EXISTS] — Ephemeral / Persistent (SessionScope enum)
│   ├── created_at, last_active_at [EXISTS]
│   ├── parent_spawn_ref [EXISTS] — cross-session link
│   ├── Task Name, Task Status [CONCEPTUAL]
│   └── Callbacks: before_task / after_task [EXISTS]
├── LINE ITEMS: Loops [EXISTS]
├── LINE ITEMS: Input Filters [EXISTS]
└── SUMMARY: total_usage(), loop_chain_to() [EXISTS]

FieldTypeStatusDescription
session_idString[EXISTS]Stable identifier. Matches AgentStart.session_id. Generated as UUID v4 at BasicAgent::new().
agent_idString[EXISTS]The agent that owns this session. Taken from the first AgentStart event.
formationSessionFormation[EXISTS]How the session was created. See Formation section below.
scopeSessionScope[EXISTS]Ephemeral (default, in-memory only) or Persistent (session logs retained). Declared via config [session] scope = "persistent".
created_atDateTime<Utc>[EXISTS]Timestamp of the first AgentStart event for this session.
last_active_atDateTime<Utc>[EXISTS]Updated each time a new loop opens (on AgentStart). Reflects when the last loop started, not when it last had activity.
parent_spawn_refOption<SpawnRef>[EXISTS]Cross-session link when this session was spawned as a sub-agent. Points back to parent session, loop, tool call. Inverse of LoopRecord.child_loop_refs.
Task NameString[CONCEPTUAL]Human-readable label for the task this session represents.
Task Statusenum[CONCEPTUAL]Status of the task (e.g., Pending, Running, Completed, Failed). Derived from loop statuses but would be a first-class field.

Formation [EXISTS]

How the session was initially created. Enum SessionFormation:

VariantStatusDescription
Explicit { timestamp }[EXISTS]Created by direct construction (tests, tooling). SessionRecorder never sets this.
FirstLoop { timestamp }[EXISTS]Created automatically when a new session_id first appeared in an AgentStart event.
InactivityTimeout { threshold_secs, previous_session_id, timestamp }[EXISTS]New session opened because the agent was idle longer than the threshold. Requires prior session_id rotation via BasicAgent::check_and_rotate.

Callbacks [EXISTS]

Callbacks are configured on SessionRecorderConfig, not on the Session struct directly.

CallbackTypeStatusDescription
before_taskOption<BeforeTaskFn>[EXISTS]Fires on the first AgentStart event with a new session_id. Blank by default.
after_taskOption<AfterTaskFn>[EXISTS]Fires on flush(). Blank by default.

LINE ITEMS: Loops (Iterations) [EXISTS]

Ordered list of all LoopRecords in this session, sorted by started_at.

FieldTypeStatusDescription
loopsVec<LoopRecord>[EXISTS]All completed and in-progress loop records. See loop.md.

Loop Tree Structure

The tree is implicit via parent_loop_id / children_loop_ids links:

  • Root loops -- parent_loop_id is None (or points to a loop in a different session for sub-agent roots).
  • Continuation chains -- parent_loop_id -> loop_id within the same session.
  • Parallel branches -- siblings sharing the same parent_loop_id, each with parallel_group set.
  • Sub-agent children -- in child_loop_refs on the parent loop (cross-session, not in loops vec).

LINE ITEMS: Input Filters [EXISTS]

Input filters validate user messages before the LLM is called. Stored on AgentLoopConfig.input_filters, conceptually a Session-level concern.

FieldTypeStatusDescription
input_filtersVec<Arc<dyn InputFilter>>[EXISTS]Each filter returns Pass, Warn, or Reject for a given message. Reject aborts the loop before any LLM call and emits InputRejected.

SUMMARY Methods [EXISTS]

Methods on the Session struct for querying and aggregating.

MethodStatusDescription
total_usage()[EXISTS]Cumulative Usage across all loops. Sums input, output, reasoning, cache_read, cache_write, total_tokens.
loop_chain_to(target_loop_id)[EXISTS]Builds the linear chain of loop IDs from root to target by walking parent_loop_id links backward. Returns chronological order (root first). Handles parallel branches (only selected path) and reruns (only active ancestor chain).
root_loops()[EXISTS]Returns loops whose parent_loop_id is None or belongs to a different session.
children_of(loop_id)[EXISTS]Returns direct same-session children of a loop.
parallel_siblings(loop_id)[EXISTS]Returns all loops in the same parallel group.
get_loop(loop_id)[EXISTS]Look up a loop by ID.

Code Reference

FileWhat it contains
src/session/model.rsSession struct, SessionFormation enum, SpawnRef struct, SessionError enum. All methods (total_usage, loop_chain_to, root_loops, children_of, parallel_siblings, get_loop).

Conceptual Notes

  • Session scope (Ephemeral vs Persistent) does not exist in code. All sessions are currently ephemeral by default. Adding scope would gate whether Introspection is required.
  • Model/thinking/temperature per-loop -- These settings are no longer on Session. They are tracked per-loop via LoopConfigSnapshot on each LoopRecord (see loop.md). The fallback hierarchy is Loop -> Agent default.
  • Task Name and Task Status would give sessions first-class task identity, enabling task dashboards and workflow tracking.
  • before_task / after_task callbacks now exist on SessionRecorderConfig. before_task fires on the first AgentStart with a new session_id; after_task fires on flush(). This mirrors the existing before_loop/after_loop and before_turn/after_turn callback pattern at the Session level.