codetether_agent/
event_stream.rs1pub mod s3_sink;
6
7use anyhow::Result;
8use serde::{Deserialize, Serialize};
9use tokio::sync::broadcast;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13#[serde(tag = "type", rename_all = "snake_case")]
14pub enum ChatEvent {
15 UserMessage { content: String, timestamp: i64 },
17 AssistantMessage { content: String, timestamp: i64 },
19 ToolCall {
21 tool_name: String,
22 arguments: serde_json::Value,
23 timestamp: i64,
24 },
25 ToolResult {
27 tool_name: String,
28 result: String,
29 success: bool,
30 timestamp: i64,
31 },
32}
33
34impl ChatEvent {
35 pub fn tool_result(
37 workspace: std::path::PathBuf,
38 _session_id: String,
39 tool_name: &str,
40 success: bool,
41 _duration_ms: u64,
42 result: &str,
43 _message_count: u64,
44 ) -> Self {
45 let _ = workspace; Self::ToolResult {
47 tool_name: tool_name.to_string(),
48 result: result.to_string(),
49 success,
50 timestamp: chrono::Utc::now().timestamp(),
51 }
52 }
53
54 pub fn to_json(&self) -> String {
56 serde_json::to_string(self).unwrap_or_default()
57 }
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
62#[serde(tag = "type", rename_all = "snake_case")]
63#[allow(dead_code)]
64pub enum Event {
65 ToolStarted {
67 tool_name: String,
68 request_id: String,
69 },
70 ToolCompleted {
72 tool_name: String,
73 request_id: String,
74 success: bool,
75 },
76 AgentMessage { content: String },
78 Error { message: String },
80 Chat(ChatEvent),
82}
83
84#[allow(dead_code)]
86pub struct EventStream {
87 sender: broadcast::Sender<Event>,
88}
89
90impl EventStream {
91 #[allow(dead_code)]
92 pub fn new() -> Self {
94 let (sender, _) = broadcast::channel(256);
95 Self { sender }
96 }
97
98 #[allow(dead_code)]
99 pub fn subscribe(&self) -> broadcast::Receiver<Event> {
101 self.sender.subscribe()
102 }
103
104 #[allow(dead_code)]
105 pub fn send(&self, event: Event) -> Result<()> {
107 self.sender.send(event)?;
108 Ok(())
109 }
110}
111
112impl Default for EventStream {
113 fn default() -> Self {
114 Self::new()
115 }
116}