#[non_exhaustive]pub enum AgentEvent<S> {
Started {
run_id: String,
tenant_id: TenantId,
parent_run_id: Option<String>,
agent: String,
},
ToolStart {
run_id: String,
tenant_id: TenantId,
tool_use_id: String,
tool: String,
tool_version: Option<String>,
input: Value,
},
ToolComplete {
run_id: String,
tenant_id: TenantId,
tool_use_id: String,
tool: String,
tool_version: Option<String>,
duration_ms: u64,
output: Value,
},
ToolError {
run_id: String,
tenant_id: TenantId,
tool_use_id: String,
tool: String,
tool_version: Option<String>,
error: String,
error_for_llm: RenderedForLlm<String>,
envelope: ErrorEnvelope,
duration_ms: u64,
},
Failed {
run_id: String,
tenant_id: TenantId,
error: String,
envelope: ErrorEnvelope,
},
Complete {
run_id: String,
tenant_id: TenantId,
state: S,
usage: Option<UsageSnapshot>,
},
ToolCallApproved {
run_id: String,
tenant_id: TenantId,
tool_use_id: String,
tool: String,
},
ToolCallDenied {
run_id: String,
tenant_id: TenantId,
tool_use_id: String,
tool: String,
reason: String,
},
}Expand description
Runtime events emitted by the agent during a single
execute / execute_stream call.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Started
Run opened. Sinks use this to mark span beginnings, allocate per-run state, and emit “session opened” telemetry.
Fields
run_id: StringPer-run correlation id (UUID v7). Stable for the duration of the run; matches the id on every subsequent event for this same call.
tenant_id: TenantIdTenant scope this event belongs to (invariant 11 —
every emit site stamps ctx.tenant_id().clone()). Audit /
billing / replay consumers key off this field directly
instead of correlating through a separate run_id →
tenant_id lookup.
ToolStart
One tool dispatch began. Emitted by
crate::agent::tool_event_layer::ToolEventLayer when wired
into the tool registry. Absent when the layer is not wired
(the agent runtime itself does not generate tool events).
Fields
ToolComplete
One tool dispatch finished successfully.
Fields
ToolError
One tool dispatch failed.
Fields
tool_version: Option<String>Tool version echoed from the matching ToolStart so sinks
see the same provenance on the failure path as on success.
error: StringOperator-facing error message (Display form, includes
vendor status, source chain). Sinks, OTel, and log
destinations consume this.
error_for_llm: RenderedForLlm<String>LLM-facing error message wrapped in a sealed
RenderedForLlm carrier. The carrier’s constructor is
pub(crate) to entelix-core, so the only path from a
raw String to this field is
entelix_core::LlmRenderable::for_llm — emit sites
cannot fabricate model-facing content. The audit-log
projection (Self::to_graph_event) extracts the inner
rendering into GraphEvent::ToolResult so replay
reconstructs the model’s view without re-leaking
operator content (invariant #16).
envelope: ErrorEnvelopeTyped wire shape produced by
entelix_core::Error::envelope. Bundles wire_code
(i18n key / metric label), wire_class (responsibility
split), retry_after_secs (vendor Retry-After hint),
and provider_status (raw HTTP status) so sinks, audit
replay, SSE adapters, and FE rate-limit timers all read
one Copy value instead of pattern-matching the inner
error variant. Patch-version-stable.
Failed
Run terminated with the inner runnable’s error. The matching
Started{run_id} is always present in the same stream.
Caller-facing streams additionally surface the typed error
via Result::Err; sinks see only this event.
Fields
envelope: ErrorEnvelopeTyped wire shape produced by
entelix_core::Error::envelope — see ToolError for
the field roster. Replay / audit / metric / SSE consumers
route off this field instead of parsing error prose.
Complete
Run terminated successfully with the agent’s terminal state.
Fields
state: SFinal state returned by the inner runnable.
usage: Option<UsageSnapshot>Frozen UsageSnapshot of the entelix_core::RunBudget
counters at the moment the inner runnable returned.
None when no budget was attached to the
entelix_core::ExecutionContext. Mirrors the
usage field on
crate::AgentRunResult so streaming and one-shot
surfaces observe the same terminal artifact.
ToolCallApproved
HITL approver decided to permit one tool dispatch. Emitted by
crate::agent::ApprovalLayer before the matching ToolStart
fires. Only present when an Approver is wired (default
agents skip approval and never emit this variant).
Fields
ToolCallDenied
HITL approver decided to reject one tool dispatch. The
matching ToolStart does NOT fire — denial short-circuits
the dispatch path. The agent observes the rejection as
Error::InvalidRequest carrying the same reason.
Implementations§
Source§impl<S> AgentEvent<S>
impl<S> AgentEvent<S>
Sourcepub fn to_graph_event(&self, timestamp: DateTime<Utc>) -> Option<GraphEvent>
pub fn to_graph_event(&self, timestamp: DateTime<Utc>) -> Option<GraphEvent>
Project this runtime event onto the durable audit-log shape
GraphEvent. Returns None when the variant has no audit
projection — Started, Complete, Failed are runtime-only
lifecycle markers that do not belong in the per-thread audit
trail.
The timestamp argument is supplied by the caller (typically
Utc::now() at emit time) so this method stays pure: a single
runtime event projected at two different points in time
produces two distinct (but otherwise equal) GraphEvents.
Lossy projection notes — run_id, tool_version, and
duration_ms are dropped because the audit log keys
correlation by tool_use_id + timestamp and is not the
home for runtime metrics. Operators who need run-level
correlation in audit do it at the sink layer (e.g. by
stamping a thread tag prior to append).
ToolError is mapped onto a GraphEvent::ToolResult with
is_error: true and the error message carried as text
content — preserving the same correlation key
(tool_use_id) so a session replay can pair the failed
dispatch back with the originating ToolCall.
Sourcepub fn erase_state(self) -> AgentEvent<()>
pub fn erase_state(self) -> AgentEvent<()>
Erase the agent-state type parameter, replacing
Self::Complete::state with the unit value. Every other
variant rebuilds with identical field values — they carry no
state. Enables a single audit / SSE / OTel sink (typed
AgentEventSink<()>) to fan
in from heterogeneous agents (Agent<ReActState>,
Agent<SupervisorState>, …) through the
StateErasureSink adapter.
Operators consuming the post-erasure event tree retain access
to every header field (run_id, tenant_id, parent_run_id)
and every per-variant payload (tool inputs / outputs, error
envelope, usage snapshot) — only the agent’s terminal state
is dropped, which is the field a state-agnostic sink could
not type-erase anyway.
§Examples
use entelix_agents::AgentEvent;
use entelix_core::TenantId;
let typed: AgentEvent<u32> = AgentEvent::Complete {
run_id: "r1".into(),
tenant_id: TenantId::new("t1"),
state: 42_u32,
usage: None,
};
let erased: AgentEvent<()> = typed.erase_state();
match erased {
AgentEvent::Complete { state, .. } => assert_eq!(state, ()),
_ => unreachable!(),
}Trait Implementations§
Source§impl<S> Clone for AgentEvent<S>where
S: Clone,
impl<S> Clone for AgentEvent<S>where
S: Clone,
Source§fn clone(&self) -> AgentEvent<S>
fn clone(&self) -> AgentEvent<S>
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl<S> Debug for AgentEvent<S>where
S: Debug,
impl<S> Debug for AgentEvent<S>where
S: Debug,
Source§impl<S> PartialEq for AgentEvent<S>where
S: PartialEq,
impl<S> PartialEq for AgentEvent<S>where
S: PartialEq,
Source§fn eq(&self, other: &AgentEvent<S>) -> bool
fn eq(&self, other: &AgentEvent<S>) -> bool
self and other values to be equal, and is used by ==.impl<S> Eq for AgentEvent<S>where
S: Eq,
impl<S> StructuralPartialEq for AgentEvent<S>
Auto Trait Implementations§
impl<S> Freeze for AgentEvent<S>where
S: Freeze,
impl<S> RefUnwindSafe for AgentEvent<S>where
S: RefUnwindSafe,
impl<S> Send for AgentEvent<S>where
S: Send,
impl<S> Sync for AgentEvent<S>where
S: Sync,
impl<S> Unpin for AgentEvent<S>where
S: Unpin,
impl<S> UnsafeUnpin for AgentEvent<S>where
S: UnsafeUnpin,
impl<S> UnwindSafe for AgentEvent<S>where
S: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
Source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request