Skip to content
Tracon

SessionRecord

Namespace Tracon · Assembly Tracon.Abstractions.dll

A stored session.

public sealed record SessionRecord : IEquatable<SessionRecord>

objectSessionRecord

IEquatable<SessionRecord>

object.GetType(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()

public SessionRecord()

The agent the session belongs to.

public required string AgentName { get; init; }

string

The creation time (UTC).

public required DateTimeOffset CreatedAt { get; init; }

DateTimeOffset

The session identifier.

public required string Id { get; init; }

string

The user the session belongs to, or null when the session is unowned.

public string? OwnerId { get; init; }

string?

This is a SECOND, NARROWER boundary drawn UNDER the tenant, not a replacement for it: SessionRecord.TenantId still answers “whose data is this”, and this answers “which user inside that tenant”. Do not confuse it with ISessionStore.GetOwnerTenantIdAsync, whose “owner” is the owning TENANT.

The value is an opaque string with the same meaning IRunAttributionContext.UserId carries, bounded by RunLabels.MaxUserIdLength. Tracon neither resolves nor validates it; the consumer decides what it identifies. It is never read from a request body — a body field naming the owner would let any client write a session under someone else’s name.

null means the session is unowned: every row written before ownership tracking existed, and every row written by an application that leaves TraconSessionOwnershipOptions.Enabled off. An unowned row is never returned by an owner-filtered SessionQuery.OwnerId query; it stays visible to a management listing that applies no owner filter.

Assigned once. A store must not let a later write clear an owner that is already set: the identity that opened a session keeps it, and “set → unset” is never a legitimate transition here. Writing a DIFFERENT owner onto an owned row is equally not a transition Tracon performs — a derived session (a branch, a Responses chain) carries the SOURCE session’s owner, not the caller’s.

The serialized session state. Microsoft Agent Framework’s SerializeSessionAsync output, treated as opaque.

public required JsonElement State { get; init; }

JsonElement

The Microsoft Agent Framework package version that produced State.

public string? StateMafVersion { get; init; }

string?

null means the row was written before this field existed. Tracon does not promise that a session written by one Microsoft Agent Framework version can be restored by a different one; this value lets a failed restore report exactly which version wrote the state instead of guessing.

The Tracon schema generation that wrote State.

public int StateSchemaVersion { get; init; }

int

Every row carries a value; Tracon has stamped this generation on every session since the very first release, so there is no “unstamped” era for this field the way there is for StateMafVersion. It advances only when Tracon changes how it structures the stored row, never when the Microsoft Agent Framework version changes.

A record built to be saved does not need to set this — the store stamps the current generation regardless of what the caller provides.

The tenant identifier.

public string? TenantId { get; init; }

string?

The last-updated time (UTC).

public required DateTimeOffset UpdatedAt { get; init; }

DateTimeOffset

The record’s write generation, used for optimistic concurrency.

public long Version { get; init; }

long

A record read from a store carries the stored value; a record built to be written carries whatever the caller sets, and stores ignore it on ISessionStore.SaveAsync and ISessionStore.TryCreateAsync — only ISessionStore.TryUpdateAsync reads it, through its own expectedVersion parameter.

The first stored version is 1. A row written before this field existed reads back as 1 as well, so a session that survives the upgrade takes part in concurrency control from its next write onward.

public override bool Equals(object? obj)

obj object?

bool

public bool Equals(SessionRecord? other)

other SessionRecord?

bool

public override int GetHashCode()

int

public override string ToString()

string

operator ==(SessionRecord?, SessionRecord?)

Section titled “ operator ==(SessionRecord?, SessionRecord?)”
public static bool operator ==(SessionRecord? left, SessionRecord? right)

left SessionRecord?

right SessionRecord?

bool

operator !=(SessionRecord?, SessionRecord?)

Section titled “ operator !=(SessionRecord?, SessionRecord?)”
public static bool operator !=(SessionRecord? left, SessionRecord? right)

left SessionRecord?

right SessionRecord?

bool