1#[derive(Debug, Clone)]
6pub enum HyphaEvent {
7 Progress {
9 current: u32,
10 total: u32,
11 message: String,
12 },
13 DownloadProgress {
15 downloaded_bytes: u64,
16 total_bytes: Option<u64>,
17 },
18 Log { message: String },
20 Warn { message: String },
22}
23
24pub trait EventSink: Send + Sync {
26 fn emit(&self, event: HyphaEvent);
27}
28
29pub struct NoopSink;
31
32impl EventSink for NoopSink {
33 fn emit(&self, _: HyphaEvent) {}
34}
35
36#[derive(Debug, Clone)]
42pub struct HyphaError {
43 pub code: String,
44 pub message: String,
45 pub hint: Option<String>,
46}
47
48impl HyphaError {
49 pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
50 Self {
51 code: code.into(),
52 message: message.into(),
53 hint: None,
54 }
55 }
56
57 pub fn with_hint(
58 code: impl Into<String>,
59 message: impl Into<String>,
60 hint: impl Into<String>,
61 ) -> Self {
62 Self {
63 code: code.into(),
64 message: message.into(),
65 hint: Some(hint.into()),
66 }
67 }
68}
69
70impl std::fmt::Display for HyphaError {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 write!(f, "{}: {}", self.code, self.message)
73 }
74}
75
76impl std::error::Error for HyphaError {}
77
78impl From<String> for HyphaError {
79 fn from(msg: String) -> Self {
80 Self {
81 code: "error".to_string(),
82 message: msg,
83 hint: None,
84 }
85 }
86}
87
88impl From<&str> for HyphaError {
89 fn from(msg: &str) -> Self {
90 Self::from(msg.to_string())
91 }
92}
93
94pub struct AfDataSink;
96
97fn emit(event: agent_first_data::Event) {
98 let stdout = std::io::stdout();
99 let mut emitter =
100 agent_first_data::CliEmitter::new(stdout.lock(), agent_first_data::OutputFormat::Json);
101 let _ = emitter.emit(event);
102}
103
104impl EventSink for AfDataSink {
105 fn emit(&self, event: HyphaEvent) {
106 match event {
107 HyphaEvent::Progress {
108 current,
109 total,
110 message,
111 } => {
112 emit(
113 agent_first_data::json_progress(serde_json::json!({
114 "current": current,
115 "total": total,
116 "message": message,
117 }))
118 .build(),
119 );
120 }
121 HyphaEvent::DownloadProgress {
122 downloaded_bytes,
123 total_bytes,
124 } => {
125 emit(
126 agent_first_data::json_progress(serde_json::json!({
127 "event": "download_progress",
128 "downloaded_bytes": downloaded_bytes,
129 "total_bytes": total_bytes,
130 }))
131 .build(),
132 );
133 }
134 HyphaEvent::Log { message } => {
135 emit(agent_first_data::json_log(serde_json::json!({ "message": message })).build());
136 }
137 HyphaEvent::Warn { message } => {
138 emit(
139 agent_first_data::json_log(
140 serde_json::json!({ "event": "warn", "message": message }),
141 )
142 .build(),
143 );
144 }
145 }
146 }
147}