InMemoryRunStore
AgentPrism.Core.dllA store that keeps run records and their events in process memory.
public sealed class InMemoryRunStore : IRunStoreInheritance
Section titled “Inheritance”Implements
Section titled “Implements”Inherited Members
Section titled “Inherited Members”object.GetType(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()
Remarks
Section titled “Remarks”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.
Constructors
Section titled “Constructors”InMemoryRunStore(IRunScoreStore?, ITenantContext?)
Section titled “ InMemoryRunStore(IRunScoreStore?, ITenantContext?)”Creates a new in-memory run store.
public InMemoryRunStore(IRunScoreStore? scores = null, ITenantContext? tenantContext = null)Parameters
Section titled “Parameters”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.
Properties
Section titled “Properties”MaxRuns
Section titled “ MaxRuns”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; }Property Value
Section titled “Property Value”Methods
Section titled “Methods”AppendEventAsync(RunEvent, CancellationToken)
Section titled “ AppendEventAsync(RunEvent, CancellationToken)”Appends an event to the run stream.
public ValueTask AppendEventAsync(RunEvent runEvent, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”runEvent RunEvent
The event to append. The caller assigns its sequence number.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”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)Parameters
Section titled “Parameters”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.
Returns
Section titled “Returns”ValueTask<IReadOnlyList<RunRecord>>
The records of the closed runs.
Remarks
Section titled “Remarks”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)Parameters
Section titled “Parameters”completion RunCompletion
The completion information.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”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)Parameters
Section titled “Parameters”query ExperimentResultsQuery
The filter.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”ValueTask<IReadOnlyList<ExperimentVariantResult>>
Per-variant results. A variant that took no traffic is absent.
Remarks
Section titled “Remarks”The experiment breakdown is available only through this query;
experiment_id is not emitted as a metric tag, for cardinality reasons.
GetRunAsync(Guid, CancellationToken)
Section titled “ GetRunAsync(Guid, CancellationToken)”Gets a run record.
public ValueTask<RunRecord?> GetRunAsync(Guid runId, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”runId Guid
The run id.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”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)Parameters
Section titled “Parameters”query RunStatisticsQuery
The filter.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”Counts, token totals and the per-agent breakdown.
Remarks
Section titled “Remarks”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)Parameters
Section titled “Parameters”query RunTimeSeriesQuery
The filter.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”ValueTask<IReadOnlyList<TimeSeriesPoint>>
The ordered bucket list. Empty buckets are returned too, with zero counts.
Exceptions
Section titled “Exceptions”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)Parameters
Section titled “Parameters”query ToolUsageQuery
The filter.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”ValueTask<IReadOnlyList<ToolUsage>>
Call counts, failure rates and average durations.
Remarks
Section titled “Remarks”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)Parameters
Section titled “Parameters”runId Guid
The run id.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”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)Parameters
Section titled “Parameters”query RunQuery
The filter.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”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)Parameters
Section titled “Parameters”runId Guid
The run id.
fromSequence long
Reading starts at this sequence number, inclusive.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”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)Parameters
Section titled “Parameters”invocation ToolInvocationRecord
The call summary.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”A task that completes when the record is written.
Remarks
Section titled “Remarks”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)Parameters
Section titled “Parameters”info RunStartInfo
The start information.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”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)Parameters
Section titled “Parameters”runIds IReadOnlyCollection<Guid>
The ids of the runs to mark.
The mark time (UTC).
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”A task that completes when the marks are written.
Remarks
Section titled “Remarks”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)Parameters
Section titled “Parameters”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.
Returns
Section titled “Returns”A task that completes when the record is updated.