# SessionRecord

> Tracon documentation. Tracon is a .NET package family that adds a control
> plane on Microsoft Agent Framework, published as NuGet packages that run
> inside your own ASP.NET Core application.
>
> Page: https://tracon.dev/api/tracon.sessionrecord/
> Summary: SessionRecord: A stored session.

<div class="api-provenance">Namespace Tracon · Assembly <code>Tracon.Abstractions.dll</code></div>

A stored session.

```csharp
public sealed record SessionRecord : IEquatable<SessionRecord>
```

<dl class="api-relations"><dt>Inheritance</dt><dd><a href="https://learn.microsoft.com/dotnet/api/system.object">object</a> ← <a href="/api/tracon.sessionrecord/">SessionRecord</a></dd><dt>Implements</dt><dd><a href="https://learn.microsoft.com/dotnet/api/system.iequatable-1">IEquatable&lt;SessionRecord&gt;</a></dd><dt>Inherited Members</dt><dd><a href="https://learn.microsoft.com/dotnet/api/system.object.gettype">object.GetType()</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.tostring">object.ToString()</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)">object.Equals(object?)</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)">object.Equals(object?, object?)</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.referenceequals">object.ReferenceEquals(object?, object?)</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.gethashcode">object.GetHashCode()</a></dd></dl>

## Constructors

### <a id="Tracon_SessionRecord__ctor"></a> SessionRecord\(\)

```csharp
public SessionRecord()
```

## Properties

### <a id="Tracon_SessionRecord_AgentName"></a> AgentName

The agent the session belongs to.

```csharp
public required string AgentName { get; init; }
```

#### Property Value

 [string](https://learn.microsoft.com/dotnet/api/system.string)

### <a id="Tracon_SessionRecord_CreatedAt"></a> CreatedAt

The creation time (UTC).

```csharp
public required DateTimeOffset CreatedAt { get; init; }
```

#### Property Value

 [DateTimeOffset](https://learn.microsoft.com/dotnet/api/system.datetimeoffset)

### <a id="Tracon_SessionRecord_Id"></a> Id

The session identifier.

```csharp
public required string Id { get; init; }
```

#### Property Value

 [string](https://learn.microsoft.com/dotnet/api/system.string)

### <a id="Tracon_SessionRecord_OwnerId"></a> OwnerId

The user the session belongs to, or [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null) when the
session is unowned.

```csharp
public string? OwnerId { get; init; }
```

#### Property Value

 [string](https://learn.microsoft.com/dotnet/api/system.string)?

#### Remarks

This is a SECOND, NARROWER boundary drawn UNDER the tenant, not a
replacement for it: [SessionRecord.TenantId](/api/tracon.sessionrecord/#Tracon_SessionRecord_TenantId) still answers "whose data is
this", and this answers "which user inside that tenant". Do not confuse
it with [ISessionStore.GetOwnerTenantIdAsync](/api/tracon.isessionstore/#Tracon_ISessionStore_GetOwnerTenantIdAsync_System_String_System_Threading_CancellationToken_), whose "owner"
is the owning TENANT.

The value is an **opaque string** with the same meaning
[IRunAttributionContext.UserId](/api/tracon.irunattributioncontext/#Tracon_IRunAttributionContext_UserId) carries, bounded by
[RunLabels.MaxUserIdLength](/api/tracon.runlabels/#Tracon_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](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null) means the session is unowned: every row written
before ownership tracking existed, and every row written by an
application that leaves
[TraconSessionOwnershipOptions.Enabled](/api/tracon.traconsessionownershipoptions/#Tracon_TraconSessionOwnershipOptions_Enabled) off. An unowned
row is never returned by an owner-filtered
[SessionQuery.OwnerId](/api/tracon.sessionquery/#Tracon_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.

### <a id="Tracon_SessionRecord_State"></a> State

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

```csharp
public required JsonElement State { get; init; }
```

#### Property Value

 [JsonElement](https://learn.microsoft.com/dotnet/api/system.text.json.jsonelement)

### <a id="Tracon_SessionRecord_StateMafVersion"></a> StateMafVersion

The Microsoft Agent Framework package version that produced
`State`.

```csharp
public string? StateMafVersion { get; init; }
```

#### Property Value

 [string](https://learn.microsoft.com/dotnet/api/system.string)?

#### Remarks

[null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/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.

### <a id="Tracon_SessionRecord_StateSchemaVersion"></a> StateSchemaVersion

The Tracon schema generation that wrote `State`.

```csharp
public int StateSchemaVersion { get; init; }
```

#### Property Value

 [int](https://learn.microsoft.com/dotnet/api/system.int32)

#### Remarks

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.

### <a id="Tracon_SessionRecord_TenantId"></a> TenantId

The tenant identifier.

```csharp
public string? TenantId { get; init; }
```

#### Property Value

 [string](https://learn.microsoft.com/dotnet/api/system.string)?

### <a id="Tracon_SessionRecord_UpdatedAt"></a> UpdatedAt

The last-updated time (UTC).

```csharp
public required DateTimeOffset UpdatedAt { get; init; }
```

#### Property Value

 [DateTimeOffset](https://learn.microsoft.com/dotnet/api/system.datetimeoffset)

### <a id="Tracon_SessionRecord_Version"></a> Version

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

```csharp
public long Version { get; init; }
```

#### Property Value

 [long](https://learn.microsoft.com/dotnet/api/system.int64)

#### Remarks

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](/api/tracon.isessionstore/#Tracon_ISessionStore_SaveAsync_Tracon_SessionRecord_System_Threading_CancellationToken_) and
[ISessionStore.TryCreateAsync](/api/tracon.isessionstore/#Tracon_ISessionStore_TryCreateAsync_Tracon_SessionRecord_System_Threading_CancellationToken_) — only
[ISessionStore.TryUpdateAsync](/api/tracon.isessionstore/#Tracon_ISessionStore_TryUpdateAsync_Tracon_SessionRecord_System_Int64_System_Threading_CancellationToken_) 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.

## Methods

### <a id="Tracon_SessionRecord_Equals_System_Object_"></a> Equals\(object?\)

```csharp
public override bool Equals(object? obj)
```

#### Parameters

`obj` [object](https://learn.microsoft.com/dotnet/api/system.object)?

#### Returns

 [bool](https://learn.microsoft.com/dotnet/api/system.boolean)

### <a id="Tracon_SessionRecord_Equals_Tracon_SessionRecord_"></a> Equals\(SessionRecord?\)

```csharp
public bool Equals(SessionRecord? other)
```

#### Parameters

`other` [SessionRecord](/api/tracon.sessionrecord/)?

#### Returns

 [bool](https://learn.microsoft.com/dotnet/api/system.boolean)

### <a id="Tracon_SessionRecord_GetHashCode"></a> GetHashCode\(\)

```csharp
public override int GetHashCode()
```

#### Returns

 [int](https://learn.microsoft.com/dotnet/api/system.int32)

### <a id="Tracon_SessionRecord_ToString"></a> ToString\(\)

```csharp
public override string ToString()
```

#### Returns

 [string](https://learn.microsoft.com/dotnet/api/system.string)

## Operators

### <a id="Tracon_SessionRecord_op_Equality_Tracon_SessionRecord_Tracon_SessionRecord_"></a> operator ==\(SessionRecord?, SessionRecord?\)

```csharp
public static bool operator ==(SessionRecord? left, SessionRecord? right)
```

#### Parameters

`left` [SessionRecord](/api/tracon.sessionrecord/)?

`right` [SessionRecord](/api/tracon.sessionrecord/)?

#### Returns

 [bool](https://learn.microsoft.com/dotnet/api/system.boolean)

### <a id="Tracon_SessionRecord_op_Inequality_Tracon_SessionRecord_Tracon_SessionRecord_"></a> operator \!=\(SessionRecord?, SessionRecord?\)

```csharp
public static bool operator !=(SessionRecord? left, SessionRecord? right)
```

#### Parameters

`left` [SessionRecord](/api/tracon.sessionrecord/)?

`right` [SessionRecord](/api/tracon.sessionrecord/)?

#### Returns

 [bool](https://learn.microsoft.com/dotnet/api/system.boolean)
