Skip to main content

agui_rs_server/
handler.rs

1use agui_rs_core::{Event, Result, RunAgentInput};
2use futures::stream::BoxStream;
3
4/// Run-scoped metadata extracted from [`RunAgentInput`].
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct RunContext {
7    pub thread_id: String,
8    pub run_id: String,
9    pub parent_run_id: Option<String>,
10}
11
12impl RunContext {
13    pub fn new(
14        thread_id: impl Into<String>,
15        run_id: impl Into<String>,
16        parent_run_id: Option<String>,
17    ) -> Self {
18        Self {
19            thread_id: thread_id.into(),
20            run_id: run_id.into(),
21            parent_run_id,
22        }
23    }
24}
25
26impl From<&RunAgentInput> for RunContext {
27    fn from(input: &RunAgentInput) -> Self {
28        Self::new(
29            input.thread_id.clone(),
30            input.run_id.clone(),
31            input.parent_run_id.clone(),
32        )
33    }
34}
35
36#[async_trait::async_trait]
37pub trait RunHandler: Send + Sync + 'static {
38    /// Process the input and return a stream of AG-UI events.
39    async fn handle(&self, input: RunAgentInput) -> Result<BoxStream<'static, Result<Event>>>;
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45
46    #[test]
47    fn run_context_copies_ids_from_input() {
48        let mut input = RunAgentInput::new("thread-1", "run-1");
49        input.parent_run_id = Some("parent-1".into());
50
51        let context = RunContext::from(&input);
52
53        assert_eq!(context.thread_id, "thread-1");
54        assert_eq!(context.run_id, "run-1");
55        assert_eq!(context.parent_run_id.as_deref(), Some("parent-1"));
56    }
57}