Skip to main content

conversation_api/execution/
event.rs

1//! Durable Agent events and their delivery boundary.
2
3use async_trait::async_trait;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7use crate::execution::{
8    EventId, ExternalError, InvocationContext, MessageId, PreparedAction, RuntimeSnapshot,
9    UsageSummary,
10};
11
12/// Event emitted by the Runtime.
13#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
14#[serde(tag = "type", rename_all = "snake_case")]
15pub enum AgentEvent {
16    /// A run has started or resumed.
17    Started,
18    /// The run requires user input before it can continue.
19    InteractionRequired {
20        /// Batch identifier answered by `SubmitInteraction`.
21        batch_id: MessageId,
22        /// Prepared actions awaiting one decision each.
23        actions: Vec<PreparedAction>,
24        /// Usage accumulated before Runtime suspended the run.
25        usage: UsageSummary,
26    },
27    /// The run completed successfully.
28    Completed {
29        /// Final structured result.
30        result: Value,
31        /// Aggregated usage for the completed run.
32        usage: UsageSummary,
33    },
34    /// The run failed definitively.
35    Failed {
36        /// Stable machine-readable failure code.
37        code: String,
38        /// Safe user-facing or diagnostic message.
39        message: String,
40        /// Usage settled before the failure, cancellation, or interruption.
41        usage: UsageSummary,
42    },
43}
44
45/// Best-effort, request-scoped observation that is not part of the durable outbox.
46#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
47#[serde(tag = "type", rename_all = "snake_case")]
48pub enum AgentObservation {
49    /// Coarse progress for live presentation.
50    Progress {
51        /// Stable progress label.
52        status: String,
53    },
54    /// Temporary assistant text emitted before a tool batch.
55    CompanionText {
56        /// Text shown while work continues.
57        content: String,
58        /// Whether a client should append rather than replace.
59        append: bool,
60    },
61    /// A tool attempt is starting.
62    ToolStarted {
63        /// Model tool-call identifier.
64        call_id: String,
65        /// Stable tool name.
66        tool_name: String,
67    },
68    /// A tool attempt produced a result.
69    ToolResult {
70        /// Model tool-call identifier.
71        call_id: String,
72        /// Stable tool name.
73        tool_name: String,
74        /// Structured result.
75        result: Value,
76        /// Whether execution failed.
77        is_error: bool,
78    },
79    /// A validated model tool-call batch has been checkpointed for execution.
80    ToolCallsScheduled {
81        /// Tool names in model order.
82        tool_names: Vec<String>,
83    },
84    /// A tool batch completed and its results are available to the next model step.
85    ToolCallsCompleted {
86        /// Number of completed tool calls.
87        count: u32,
88    },
89    /// Optional diagnostic payload requested by the caller.
90    DebugData {
91        /// Diagnostic namespace.
92        scope: String,
93        /// Structured diagnostic value.
94        payload: Value,
95    },
96}
97
98/// Sequenced event persisted as part of a thread transition.
99#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
100pub struct DurableEvent {
101    /// Globally unique event identifier used for deduplication.
102    pub id: EventId,
103    /// Monotonic sequence within a thread.
104    pub sequence: u64,
105    /// Frozen routing, ownership, and run identity for this event.
106    pub context: InvocationContext,
107    /// Event payload.
108    pub event: AgentEvent,
109}
110
111/// Delivery boundary for events that have already been durably committed.
112#[async_trait]
113pub trait EventPublisher: Send + Sync {
114    /// Publishes one committed stable-boundary event with at-least-once delivery semantics.
115    ///
116    /// `snapshot` is the exact Runtime generation committed with `event`. Implementations must
117    /// never reload a newer snapshot while encoding the event.
118    async fn publish(
119        &self,
120        snapshot: &RuntimeSnapshot,
121        event: &DurableEvent,
122    ) -> Result<(), ExternalError>;
123}
124
125/// Best-effort observer for non-durable UI progress.
126#[async_trait]
127pub trait Observer: Send + Sync {
128    /// Delivers one request-scoped observation.
129    async fn observe(&self, context: &InvocationContext, observation: &AgentObservation);
130}