Skip to content

RunEventWriter

Namespace AgentPrism · Assembly AgentPrism.Core.dll

Writes the events of a single run into IRunStore and produces the sequence number.

public sealed class RunEventWriter

objectRunEventWriter

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

The sequence number is produced by a single writer. This keeps the event order deterministic and guarantees that live streaming and replay produce the same result.

Store failures do not interrupt the run. Observability must not break functionality. Every write failure is logged and swallowed; once the writer hits a failure, it moves into the RunEventWriter.IsDisabled state and attempts no further writes for that run.

RunEventWriter(IRunStore, AgentPrismRunRecordingOptions, ILogger, Guid, IReadOnlyList<IRunEventSink>?)

Section titled “ RunEventWriter(IRunStore, AgentPrismRunRecordingOptions, ILogger, Guid, IReadOnlyList<IRunEventSink>?)”

Creates a new writer.

public RunEventWriter(IRunStore store, AgentPrismRunRecordingOptions options, ILogger logger, Guid runId, IReadOnlyList<IRunEventSink>? sinks = null)

store IRunStore

The store the events are written to.

options AgentPrismRunRecordingOptions

The recording detail settings.

logger ILogger

The logger write failures are reported to.

runId Guid

The run identity.

sinks IReadOnlyList<IRunEventSink>?

The observers to fan every event out to, in addition to store. null or empty runs the identical hot path as before this extension point existed — no allocation, no branching difference.

ArgumentNullException

One of the required dependencies is null.

Gets the number of events written.

public long EventCount { get; }

long

Gets whether the writer was disabled because it hit a store failure. A disabled writer silently does nothing.

public bool IsDisabled { get; }

bool

Gets the identity of the run this writer writes to.

public Guid RunId { get; }

Guid

Gets the tenant of the run this writer writes to. Stamped onto every sub-write as defense in depth.

public string? TenantId { get; }

string?

The value is taken from the RunStartInfo.TenantId field in RunEventWriter.StartAsync — not from the ambient tenant. This is the run’s own tenant; it can deliberately override the ambient tenant (this is how workflows and job queues work). A writer used without calling RunEventWriter.StartAsync stays null and no tenant check is performed.

AppendAsync(RunEventDraft, CancellationToken)

Section titled “ AppendAsync(RunEventDraft, CancellationToken)”

Appends an event to the stream and assigns its sequence number.

public ValueTask<RunEvent> AppendAsync(RunEventDraft draft, CancellationToken cancellationToken = default)

draft RunEventDraft

The event draft.

cancellationToken CancellationToken

The cancellation token.

ValueTask<RunEvent>

The event with its sequence number and timestamp assigned. The event is produced even if the store fails or the writer is disabled.

Returning the event is for workflow execution: the streaming endpoint must both write the same event to the store and send it to the client, and building it a second time would split the sequence number in two. Returning a value from a disabled writer is also deliberate — closing observability must not interrupt the response streaming to the client.

CompleteAsync(RunStatus, RunUsage?, RunError?, RunCost?, string?, CancellationToken)

Section titled “ CompleteAsync(RunStatus, RunUsage?, RunError?, RunCost?, string?, CancellationToken)”

Terminates the run.

public ValueTask CompleteAsync(RunStatus status, RunUsage? usage = null, RunError? error = null, RunCost? cost = null, string? modelId = null, CancellationToken cancellationToken = default)

status RunStatus

The final status.

usage RunUsage?

The token usage.

error RunError?

The error information.

cost RunCost?

The computed cost. null if the model is unknown.

modelId string?

The model that actually answered, overriding runs.model_id when a ModelBinding.Fallbacks link stood in for the primary binding. null leaves the value RunEventWriter.StartAsync already wrote unchanged — the overwhelmingly common case.

cancellationToken CancellationToken

The cancellation token.

ValueTask

The completion task.

RecordToolInvocationAsync(ToolInvocationRecord, CancellationToken)

Section titled “ RecordToolInvocationAsync(ToolInvocationRecord, CancellationToken)”

Records a completed tool invocation.

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

invocation ToolInvocationRecord

The invocation summary.

cancellationToken CancellationToken

The cancellation token.

ValueTask

The completion task.

Separate from the event stream: events narrate the invocation, this record measures it. Its failure is swallowed the same way as an event write.

StartAsync(RunStartInfo, string?, CancellationToken)

Section titled “ StartAsync(RunStartInfo, string?, CancellationToken)”

Opens the run record and writes the first event.

public ValueTask StartAsync(RunStartInfo info, string? query, CancellationToken cancellationToken = default)

info RunStartInfo

The start information.

query string?

The text of the first user message that triggered this run. It is the only source for production-to-eval case promotion: outside run_events the input text is not persisted anywhere, and the session is recorded only at the end of a SUCCESSFUL run (see AgentEndpoints.AgentRunStream) — so the query of a failed run can ONLY be read from here.

cancellationToken CancellationToken

The cancellation token.

ValueTask

The completion task.