Skip to content

Rulvar API reference


Rulvar API reference / @rulvar/core / AgentEvents

Type Alias: AgentEvents

ts
type AgentEvents = 
  | {
  agentType: string;
  label?: string;
  type: "agent:queued";
}
  | {
  agentType: string;
  label?: string;
  model: string;
  role: string;
  type: "agent:start";
}
  | {
  agentType: string;
  invocation: number;
  label?: string;
  model: string;
  role: string;
  type: "agent:phase:start";
}
  | {
  agentType: string;
  costBasis?: CostBasis;
  costUsd: number;
  durationMs: number;
  invocation: number;
  label?: string;
  model: string;
  outcome: "ok" | "error";
  retries?: number;
  role: string;
  type: "agent:phase:end";
  usage: Usage;
}
  | {
  agentType: string;
  costBasis?: CostBasis;
  costUsd: number;
  entryRef: number;
  error?: WireError;
  exploration?: ExplorationSummary;
  hostRejected?: boolean;
  label?: string;
  retryCount?: number;
  status: string;
  toolBudget?: ToolBudgetSummary;
  type: "agent:end";
  usage: Usage;
  usageApprox?: boolean;
}
  | {
  agentType: string;
  error: WireError;
  label?: string;
  type: "agent:error";
  willRetry: boolean;
}
  | {
  agentType: string;
  label?: string;
  model?: string;
  reason?: string;
  retryAfterMs?: number;
  type: "quota:denied";
  willRetry: true;
}
  | {
  agentType: string;
  capUsd?: number;
  estimateUsd?: number;
  inFlightUsd?: number;
  label?: string;
  model?: string;
  scope?: "root" | "child";
  spentUsd?: number;
  type: "budget:exposure-wait";
  willWait: boolean;
}
  | {
  agentType: string;
  attempt: number;
  maxAttempts: number;
  type: "agent:schema-retry";
}
  | {
  controlKind: "countTokens";
  inputTokens?: number;
  model: string;
  outcome: "ok" | "failed" | "denied";
  type: "control:wire";
}
  | {
  delta: string;
  type: "agent:stream";
};

Defined in: packages/core/src/l0/events.ts:327

Agent lifecycle. One logical agent dispatch emits EXACTLY ONE agent:start/agent:end pair on its span (the start carries the primary role), and each model invocation phase inside the span (loop, then possibly summarize activations, finalize, extract) emits its own agent:phase:start/agent:phase:end pair, so durations, per-phase usage, and attempts are derivable without heuristics (the RV-207 event-model contract; before it, every phase emitted an unpaired extra agent:start and consumers pairing starts with the single end computed the LAST phase's duration as the agent's). reduceInvocationTable is the official reducer over this vocabulary.

Union Members

Type Literal

ts
{
  agentType: string;
  label?: string;
  type: "agent:queued";
}

Type Literal

ts
{
  agentType: string;
  label?: string;
  model: string;
  role: string;
  type: "agent:start";
}

Type Literal

ts
{
  agentType: string;
  invocation: number;
  label?: string;
  model: string;
  role: string;
  type: "agent:phase:start";
}
NameTypeDescriptionDefined in
agentTypestring-packages/core/src/l0/events.ts:332
invocationnumber1-based activation ordinal within the span, unique per activation (a summarize that fires three times gets three pairs). Key phases by (spanId, invocation).packages/core/src/l0/events.ts:343
label?string-packages/core/src/l0/events.ts:333
modelstringThe model the activation resolved to (fallbacks may serve another; the end event reports the server).packages/core/src/l0/events.ts:337
rolestringThe invocation role this phase activation runs as.packages/core/src/l0/events.ts:335
type"agent:phase:start"-packages/core/src/l0/events.ts:331

Type Literal

ts
{
  agentType: string;
  costBasis?: CostBasis;
  costUsd: number;
  durationMs: number;
  invocation: number;
  label?: string;
  model: string;
  outcome: "ok" | "error";
  retries?: number;
  role: string;
  type: "agent:phase:end";
  usage: Usage;
}
NameTypeDescriptionDefined in
agentTypestring-packages/core/src/l0/events.ts:347
costBasis?CostBasisThe fold behind costUsd (RV702). Live phase deltas are always per-call (every slice a live activation adds is backed by a recorded provider call); a replayed pair says 'aggregate-estimate' exactly when its model's records do not cover its usage. Absent on streams recorded before RV702, which priced the aggregate.packages/core/src/l0/events.ts:370
costUsdnumberThat usage priced at each serving model's own rate.packages/core/src/l0/events.ts:362
durationMsnumberWall-clock activation duration. Live telemetry only: replayed phase pairs (reconstructed from the terminal entry's usage slices) carry 0.packages/core/src/l0/events.ts:358
invocationnumber-packages/core/src/l0/events.ts:352
label?string-packages/core/src/l0/events.ts:348
modelstringThe model that actually served the activation's last attempt.packages/core/src/l0/events.ts:351
outcome"ok" | "error"-packages/core/src/l0/events.ts:371
retries?numberTransport retries inside this activation. Present only when greater than zero; live telemetry only (absent on replay).packages/core/src/l0/events.ts:376
rolestring-packages/core/src/l0/events.ts:349
type"agent:phase:end"-packages/core/src/l0/events.ts:346
usageUsageThe usage this activation added to its (role, model) slices.packages/core/src/l0/events.ts:360

Type Literal

ts
{
  agentType: string;
  costBasis?: CostBasis;
  costUsd: number;
  entryRef: number;
  error?: WireError;
  exploration?: ExplorationSummary;
  hostRejected?: boolean;
  label?: string;
  retryCount?: number;
  status: string;
  toolBudget?: ToolBudgetSummary;
  type: "agent:end";
  usage: Usage;
  usageApprox?: boolean;
}
NameTypeDescriptionDefined in
agentTypestring-packages/core/src/l0/events.ts:380
costBasis?CostBasisThe fold behind costUsd (RV702): 'per-call' when every usage slice of the invocation (restored included) is covered by per-request records priced individually, the settled fold's own basis; 'aggregate-estimate' when it is not (the aggregate number is kept so restored spend is never silently dropped, and labeled so it is never mistaken for the per-request fold). Absent on streams recorded before RV702, which priced the aggregate.packages/core/src/l0/events.ts:394
costUsdnumber-packages/core/src/l0/events.ts:384
entryRefnumber-packages/core/src/l0/events.ts:395
error?WireErrorThe terminal's typed error (RV4703), verbatim from the journaled agent entry, so live and replayed streams carry the same value. The eighth comparison experiment's first run lost its child's death to exactly this absence: the child died on a budget-refused finalize dispatch, the terminal entry named it, and the event said status 'error' and nothing else. Absent when the agent settled without an error.packages/core/src/l0/events.ts:442
exploration?ExplorationSummaryThe exploration guard counters (RV-210). Present live whenever any exploration guard limit was configured for the invocation; on replay present only when the guard abort journaled it in the terminal error payload.packages/core/src/l0/events.ts:426
hostRejected?booleanPresent and true when the invocation was aborted by the host's finish rejection (RV3702): the declared finish contract rejected the candidate past its repair bound. Journaled on the terminal agent entry (unlike retryCount), so a replayed agent:end carries it too and both surfaces of the RV3404 cut read the same count.packages/core/src/l0/events.ts:419
label?string-packages/core/src/l0/events.ts:381
retryCount?numberTotal transport retries across the span's activations. Present only when greater than zero; live telemetry only, never journaled, so a replayed agent:end omits it (absent means "zero or unknown").packages/core/src/l0/events.ts:410
statusstring-packages/core/src/l0/events.ts:382
toolBudget?ToolBudgetSummaryThe tool budget pressure snapshot (RV304). Present live whenever a tool budget limiter or the extension was configured; live telemetry only, absent on replay.packages/core/src/l0/events.ts:432
type"agent:end"-packages/core/src/l0/events.ts:379
usageUsage-packages/core/src/l0/events.ts:383
usageApprox?booleanPresent and true when this agent's usage is approximate rather than reported by the provider (the turn was cut by a transport failure, a ceiling that severed the stream, or an abort). Absent means the provider reported the usage exactly. Mirrors the terminal journal entry's usageApprox.packages/core/src/l0/events.ts:403

Type Literal

ts
{
  agentType: string;
  error: WireError;
  label?: string;
  type: "agent:error";
  willRetry: boolean;
}

Type Literal

ts
{
  agentType: string;
  label?: string;
  model?: string;
  reason?: string;
  retryAfterMs?: number;
  type: "quota:denied";
  willRetry: true;
}

A recoverable pre-wire quota wait (RV1810): the shared limiter denied a window and the dispatch will retry after the wait. This is healthy throttling, not failure: it produces no provider attempt, no ledger row, and no transport retry, and it used to ride agent:error (data.source 'quota-limiter'), where naive alerting on the event TYPE read a failing run out of a clean one. Terminal denial exhaustion still ends in a real agent:error; createEngine({ telemetry: { quotaDeniedAgentError: true } }) restores the legacy twin for consumers keyed to the old type.

NameTypeDescriptionDefined in
agentTypestring-packages/core/src/l0/events.ts:458
label?string-packages/core/src/l0/events.ts:459
model?stringThe denied model ref.packages/core/src/l0/events.ts:461
reason?stringThe limiter's reason ('tokensPerMinute 1800000 exhausted').packages/core/src/l0/events.ts:463
retryAfterMs?number-packages/core/src/l0/events.ts:464
type"quota:denied"-packages/core/src/l0/events.ts:457
willRetrytrue-packages/core/src/l0/events.ts:465

Type Literal

ts
{
  agentType: string;
  capUsd?: number;
  estimateUsd?: number;
  inFlightUsd?: number;
  label?: string;
  model?: string;
  scope?: "root" | "child";
  spentUsd?: number;
  type: "budget:exposure-wait";
  willWait: boolean;
}

A transient in-flight exposure refusal on a waiting dispatch: the turn's worst-case estimate did not fit maxInFlightExposureUsd beside the live dispatches, so the invocation parks until a hold releases and then retries, exactly the transient semantics the budgets guide promises. Healthy backpressure, not failure: no provider attempt, no ledger row, no journal entry. scope names the waiting party: 'root' is the orchestrate-owned root dispatch (RV1902), 'child' an orchestrator-spawned child (RV2002; the third parity rerun terminally killed three mid-research workers where this event now fires). willWait: false names the drained arm: nothing is left to wait out (no live hold), so the refusal is terminal for the turn; the root settles its documented forced-finish partial, a child dies as the typed cheap 'exposure-drained' refusal the orchestrator can re-spawn. Plain agents outside the orchestration never emit this: they keep the documented settle-as-budget-error behavior.

NameTypeDescriptionDefined in
agentTypestring-packages/core/src/l0/events.ts:487
capUsd?numberThe refusal arithmetic, verbatim from the typed refusal.packages/core/src/l0/events.ts:494
estimateUsd?number-packages/core/src/l0/events.ts:497
inFlightUsd?number-packages/core/src/l0/events.ts:496
label?string-packages/core/src/l0/events.ts:488
model?stringThe refused model ref.packages/core/src/l0/events.ts:492
scope?"root" | "child"The waiting party: the orchestrate root or a spawned child.packages/core/src/l0/events.ts:490
spentUsd?number-packages/core/src/l0/events.ts:495
type"budget:exposure-wait"-packages/core/src/l0/events.ts:486
willWaitboolean-packages/core/src/l0/events.ts:498

Type Literal

ts
{
  agentType: string;
  attempt: number;
  maxAttempts: number;
  type: "agent:schema-retry";
}

Type Literal

ts
{
  controlKind: "countTokens";
  inputTokens?: number;
  model: string;
  outcome: "ok" | "failed" | "denied";
  type: "control:wire";
}

Non-billable control egress (RV1804): a provider request that is not a model dispatch and lands in no invoice row, today exactly the admission countTokens probe (which carries the FULL child prompt). 'ok' names a counted probe, 'failed' a probe the provider refused (the flat reserve admits instead), 'denied' a probe the configured countTokens policy stopped before it left the process. Live telemetry only, never journaled.


Type Literal

ts
{
  delta: string;
  type: "agent:stream";
}

Emitted only when the call opts into streaming; never journaled, never re-emitted.