Skip to main content

lc_core/runnables/
events.rs

1// lc-core/src/runnables/events.rs
2//! Stream events for fine-grained LCEL pipeline observability.
3//!
4//! `astream_events` produces a stream of `StreamEvent` values that
5//! describe what's happening inside a pipeline at each step. This is
6//! useful for building UIs that show real-time progress.
7//!
8//! v0.9.0 implements 5 core event types. Full v2 event coverage
9//! is planned for v0.10.0.
10
11use serde_json::Value;
12use std::collections::HashMap;
13use uuid::Uuid;
14
15/// Fine-grained event emitted during LCEL pipeline execution.
16///
17/// v0.9.0 supports 5 core event types:
18/// - `OnLlmStart` / `OnLlmStream` / `OnLlmEnd`: LLM lifecycle
19/// - `OnToolEnd`: Tool execution completion
20/// - `OnChainEnd`: Chain execution completion
21///
22/// v0.10.0 will add: OnRetrieverStart/End, OnPromptStart/End,
23/// OnToolStart, OnChainStart, OnToolError, OnChainError, etc.
24///
25/// Note: Named `LcelStreamEvent` to avoid collision with
26/// `lc_langgraph::StreamEvent` (graph execution events).
27#[derive(Debug, Clone)]
28pub enum LcelStreamEvent {
29    /// LLM invocation started.
30    OnLlmStart {
31        /// Unique run identifier.
32        run_id: Uuid,
33        /// Name of the LLM (e.g. "gpt-4o", "claude-3-opus").
34        name: String,
35        /// Additional metadata.
36        metadata: HashMap<String, Value>,
37    },
38
39    /// LLM streaming token.
40    OnLlmStream {
41        /// Unique run identifier.
42        run_id: Uuid,
43        /// Name of the LLM.
44        name: String,
45        /// The token text.
46        token: String,
47    },
48
49    /// LLM invocation completed.
50    OnLlmEnd {
51        /// Unique run identifier.
52        run_id: Uuid,
53        /// Name of the LLM.
54        name: String,
55        /// The full LLM output.
56        output: Value,
57    },
58
59    /// Tool execution completed.
60    OnToolEnd {
61        /// Unique run identifier.
62        run_id: Uuid,
63        /// Name of the tool.
64        name: String,
65        /// The tool output.
66        output: String,
67    },
68
69    /// Chain execution completed.
70    OnChainEnd {
71        /// Unique run identifier.
72        run_id: Uuid,
73        /// Name of the chain.
74        name: String,
75        /// The chain output.
76        output: Value,
77    },
78}
79
80impl LcelStreamEvent {
81    /// Get the run_id for this event.
82    pub fn run_id(&self) -> &Uuid {
83        match self {
84            LcelStreamEvent::OnLlmStart { run_id, .. } => run_id,
85            LcelStreamEvent::OnLlmStream { run_id, .. } => run_id,
86            LcelStreamEvent::OnLlmEnd { run_id, .. } => run_id,
87            LcelStreamEvent::OnToolEnd { run_id, .. } => run_id,
88            LcelStreamEvent::OnChainEnd { run_id, .. } => run_id,
89        }
90    }
91
92    /// Get the name associated with this event.
93    pub fn name(&self) -> &str {
94        match self {
95            LcelStreamEvent::OnLlmStart { name, .. } => name,
96            LcelStreamEvent::OnLlmStream { name, .. } => name,
97            LcelStreamEvent::OnLlmEnd { name, .. } => name,
98            LcelStreamEvent::OnToolEnd { name, .. } => name,
99            LcelStreamEvent::OnChainEnd { name, .. } => name,
100        }
101    }
102
103    /// Get the event kind as a string.
104    pub fn kind(&self) -> &str {
105        match self {
106            LcelStreamEvent::OnLlmStart { .. } => "on_llm_start",
107            LcelStreamEvent::OnLlmStream { .. } => "on_llm_stream",
108            LcelStreamEvent::OnLlmEnd { .. } => "on_llm_end",
109            LcelStreamEvent::OnToolEnd { .. } => "on_tool_end",
110            LcelStreamEvent::OnChainEnd { .. } => "on_chain_end",
111        }
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    #[test]
120    fn stream_event_kind() {
121        let event = LcelStreamEvent::OnLlmStart {
122            run_id: Uuid::new_v4(),
123            name: "gpt-4o".to_string(),
124            metadata: HashMap::new(),
125        };
126        assert_eq!(event.kind(), "on_llm_start");
127        assert_eq!(event.name(), "gpt-4o");
128    }
129
130    #[test]
131    fn stream_event_variants() {
132        let id = Uuid::new_v4();
133        let event = LcelStreamEvent::OnLlmStream {
134            run_id: id,
135            name: "claude".to_string(),
136            token: "Hello".to_string(),
137        };
138        assert_eq!(event.kind(), "on_llm_stream");
139        assert_eq!(*event.run_id(), id);
140    }
141}