Skip to content

InMemoryRunStore

Namespace AgentPrism · Assembly AgentPrism.Core.dll

A store that keeps run records and their events in process memory.

public sealed class InMemoryRunStore : IRunStore

objectInMemoryRunStore

IRunStore

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

Events are append-only and stored by sequence number. Replay (InMemoryRunStore.ReadEventsAsync) behaves the same as with persistent stores.

Limits: process lifetime, single node, and unbounded memory growth. InMemoryRunStore.MaxRuns automatically drops the oldest runs. Use AgentPrism.PostgreSql in production.

InMemoryRunStore(IRunScoreStore?, ITenantContext?)

Section titled “ InMemoryRunStore(IRunScoreStore?, ITenantContext?)”

Creates a new in-memory run store.

public InMemoryRunStore(IRunScoreStore? scores = null, ITenantContext? tenantContext = null)

scores IRunScoreStore?

The score store used in summary computation (InMemoryRunStore.GetStatisticsAsync). If not given, creates a private instance of its own – this is to avoid breaking tests that use the parameterless new InMemoryRunStore. When resolved through DI, it gets the shared singleton instance registered by AddAgentPrism, so scores written by the HTTP layer appear in the summary.

tenantContext ITenantContext?

The current tenant’s context. If not given, the store behaves as single-tenant.

The upper bound on the number of runs kept in memory. When exceeded, the oldest run and its events are dropped.

public int MaxRuns { get; init; }

int

AppendEventAsync(RunEvent, CancellationToken)

Section titled “ AppendEventAsync(RunEvent, CancellationToken)”

Appends an event to the run stream.

public ValueTask AppendEventAsync(RunEvent runEvent, CancellationToken cancellationToken = default)

runEvent RunEvent

The event to append. The caller assigns its sequence number.

cancellationToken CancellationToken

The cancellation token.

ValueTask

A task that completes when the event is written.

ClaimOrphanedRunsAsync(DateTimeOffset, int, CancellationToken)

Section titled “ ClaimOrphanedRunsAsync(DateTimeOffset, int, CancellationToken)”

Closes Running rows that have not sent a heartbeat for a long time as Failed and records the reason.

public ValueTask<IReadOnlyList<RunRecord>> ClaimOrphanedRunsAsync(DateTimeOffset staleBefore, int max, CancellationToken cancellationToken = default)

staleBefore DateTimeOffset

Running rows whose last heartbeat is older than this — or that never sent one — count as orphaned (UTC).

max int

The maximum number of rows to close in this round.

cancellationToken CancellationToken

The cancellation token.

ValueTask<IReadOnlyList<RunRecord>>

The records of the closed runs.

Closing also writes a RunEventType.RunFailed event to the stream — the process that was writing the run is gone, so this method emits the event itself. The sequence number is one past the current maximum.

Only Running rows are affected; Queued rows are owned by the job queue and this method DOES not TOUCH them.

[TenantAgnostic]: this is maintenance work and scans the orphaned rows of every tenant. Filtering by the ambient tenant would leave the rows of other tenants Running forever.

CompleteRunAsync(RunCompletion, CancellationToken)

Section titled “ CompleteRunAsync(RunCompletion, CancellationToken)”

Closes the run and updates its summary.

public ValueTask CompleteRunAsync(RunCompletion completion, CancellationToken cancellationToken = default)

completion RunCompletion

The completion information.

cancellationToken CancellationToken

The cancellation token.

ValueTask

A task that completes when the record is updated.

GetExperimentResultsAsync(ExperimentResultsQuery, CancellationToken)

Section titled “ GetExperimentResultsAsync(ExperimentResultsQuery, CancellationToken)”

Summarizes an experiment per variant: count, failure rate, tokens, duration.

public ValueTask<IReadOnlyList<ExperimentVariantResult>> GetExperimentResultsAsync(ExperimentResultsQuery query, CancellationToken cancellationToken = default)

query ExperimentResultsQuery

The filter.

cancellationToken CancellationToken

The cancellation token.

ValueTask<IReadOnlyList<ExperimentVariantResult>>

Per-variant results. A variant that took no traffic is absent.

The experiment breakdown is available only through this query; experiment_id is not emitted as a metric tag, for cardinality reasons.

Gets a run record.

public ValueTask<RunRecord?> GetRunAsync(Guid runId, CancellationToken cancellationToken = default)

runId Guid

The run id.

cancellationToken CancellationToken

The cancellation token.

ValueTask<RunRecord?>

The record, or null when it does not exist.

GetStatisticsAsync(RunStatisticsQuery, CancellationToken)

Section titled “ GetStatisticsAsync(RunStatisticsQuery, CancellationToken)”

Summarizes runs.

public ValueTask<RunStatistics> GetStatisticsAsync(RunStatisticsQuery query, CancellationToken cancellationToken = default)

query RunStatisticsQuery

The filter.

cancellationToken CancellationToken

The cancellation token.

ValueTask<RunStatistics>

Counts, token totals and the per-agent breakdown.

The summary is computed inside the store. Fetching records and aggregating them in memory would cover only a paged subset and give the wrong answer.

GetTimeSeriesAsync(RunTimeSeriesQuery, CancellationToken)

Section titled “ GetTimeSeriesAsync(RunTimeSeriesQuery, CancellationToken)”

Produces the per-bucket time series of runs, failures, tokens and cost.

public ValueTask<IReadOnlyList<TimeSeriesPoint>> GetTimeSeriesAsync(RunTimeSeriesQuery query, CancellationToken cancellationToken = default)

query RunTimeSeriesQuery

The filter.

cancellationToken CancellationToken

The cancellation token.

ValueTask<IReadOnlyList<TimeSeriesPoint>>

The ordered bucket list. Empty buckets are returned too, with zero counts.

AgentPrismException

The requested range exceeds RunTimeSeriesBucketing.MaxBuckets.

GetToolUsageAsync(ToolUsageQuery, CancellationToken)

Section titled “ GetToolUsageAsync(ToolUsageQuery, CancellationToken)”

Summarizes usage per tool.

public ValueTask<IReadOnlyList<ToolUsage>> GetToolUsageAsync(ToolUsageQuery query, CancellationToken cancellationToken = default)

query ToolUsageQuery

The filter.

cancellationToken CancellationToken

The cancellation token.

ValueTask<IReadOnlyList<ToolUsage>>

Call counts, failure rates and average durations.

Same reason as IRunStore.GetStatisticsAsync: the summary is computed inside the store.

ListToolInvocationsAsync(Guid, CancellationToken)

Section titled “ ListToolInvocationsAsync(Guid, CancellationToken)”

Lists the tool calls of a run in chronological order.

public ValueTask<IReadOnlyList<ToolInvocationRecord>> ListToolInvocationsAsync(Guid runId, CancellationToken cancellationToken = default)

runId Guid

The run id.

cancellationToken CancellationToken

The cancellation token.

ValueTask<IReadOnlyList<ToolInvocationRecord>>

The call records.

QueryRunsAsync(RunQuery, CancellationToken)

Section titled “ QueryRunsAsync(RunQuery, CancellationToken)”

Lists runs that match a filter, newest first.

public ValueTask<IReadOnlyList<RunRecord>> QueryRunsAsync(RunQuery query, CancellationToken cancellationToken = default)

query RunQuery

The filter.

cancellationToken CancellationToken

The cancellation token.

ValueTask<IReadOnlyList<RunRecord>>

The matching records.

ReadEventsAsync(Guid, long, CancellationToken)

Section titled “ ReadEventsAsync(Guid, long, CancellationToken)”

Reads the events of a run in sequence order. Live streaming and historical replay take the same path.

public IAsyncEnumerable<RunEvent> ReadEventsAsync(Guid runId, long fromSequence = 0, CancellationToken cancellationToken = default)

runId Guid

The run id.

fromSequence long

Reading starts at this sequence number, inclusive.

cancellationToken CancellationToken

The cancellation token.

IAsyncEnumerable<RunEvent>

The ordered event stream.

RecordToolInvocationAsync(ToolInvocationRecord, CancellationToken)

Section titled “ RecordToolInvocationAsync(ToolInvocationRecord, CancellationToken)”

Records a settled tool call.

public ValueTask RecordToolInvocationAsync(ToolInvocationRecord invocation, CancellationToken cancellationToken = default)

invocation ToolInvocationRecord

The call summary.

cancellationToken CancellationToken

The cancellation token.

ValueTask

A task that completes when the record is written.

Kept apart from the event stream because durations and per-tool totals must be queryable without scanning the whole event stream.

StartRunAsync(RunStartInfo, CancellationToken)

Section titled “ StartRunAsync(RunStartInfo, CancellationToken)”

Opens a new run record.

public ValueTask<RunRecord> StartRunAsync(RunStartInfo info, CancellationToken cancellationToken = default)

info RunStartInfo

The start information.

cancellationToken CancellationToken

The cancellation token.

ValueTask<RunRecord>

The created record.

TouchHeartbeatAsync(IReadOnlyCollection<Guid>, DateTimeOffset, CancellationToken)

Section titled “ TouchHeartbeatAsync(IReadOnlyCollection<Guid>, DateTimeOffset, CancellationToken)”

Updates the “still here” mark of in-flight runs in one batch.

public ValueTask TouchHeartbeatAsync(IReadOnlyCollection<Guid> runIds, DateTimeOffset at, CancellationToken cancellationToken = default)

runIds IReadOnlyCollection<Guid>

The ids of the runs to mark.

at DateTimeOffset

The mark time (UTC).

cancellationToken CancellationToken

The cancellation token.

ValueTask

A task that completes when the marks are written.

Only Running rows are affected; an id that does not exist or is in another status is skipped silently — this is a maintenance signal and must not interrupt a run.

[TenantAgnostic]: the ids come from the calling process’s own IRunCancellationRegistry and are therefore already limited to the runs that process actually executes. A tenant filter would also need one query per tenant, which defeats the point of a heartbeat: a cheap signal that stays off the hot path.

UpdateRunCostAsync(Guid, RunCost?, string?, CancellationToken)

Section titled “ UpdateRunCostAsync(Guid, RunCost?, string?, CancellationToken)”

Updates the cost of a run. Used only by the maintenance endpoint (POST /api/stats/recalculate-costs); on the normal path the cost is written once by IRunStore.CompleteRunAsync.

public ValueTask UpdateRunCostAsync(Guid runId, RunCost? cost, string? tenantId = null, CancellationToken cancellationToken = default)

runId Guid

The run id.

cost RunCost?

The new cost. May be null.

tenantId string?

The EXPECTED tenant of the run. Defence in depth; when null no tenant check is made. TenantId.

cancellationToken CancellationToken

The cancellation token.

ValueTask

A task that completes when the record is updated.