1use crate::bridge::poll_config_defaults::PollIntervalConfig;
8use crate::bridge::repl_bridge_handle::{BridgeControlRequest, BridgeControlResponse, BridgeState};
9use crate::bridge::repl_bridge_transport::ReplBridgeTransport;
10use crate::bridge::SDKMessage;
11use crate::error::AgentError;
12use std::pin::Pin;
13use std::sync::Arc;
14use tokio::sync::RwLock;
15
16type BoxFuture<T> = Pin<Box<dyn std::future::Future<Output = T> + Send>>;
18
19#[derive(Clone)]
25pub struct ReplBridgeOptions {
26 pub dir: String,
28 pub machine_name: String,
30 pub branch: String,
32 pub git_repo_url: Option<String>,
34 pub title: String,
36 pub base_url: String,
38 pub session_ingress_url: String,
40 pub worker_type: String,
42 pub get_access_token: Arc<dyn Fn() -> Option<String> + Send + Sync>,
44 pub create_session: Arc<
46 dyn Fn(
47 String,
48 String,
49 Option<String>,
50 String,
51 ) -> BoxFuture<Result<Option<String>, AgentError>>
52 + Send
53 + Sync,
54 >,
55 pub archive_session: Arc<dyn Fn(String) -> BoxFuture<Result<(), AgentError>> + Send + Sync>,
57 pub get_current_title: Option<Arc<dyn Fn() -> String + Send + Sync>>,
59 pub to_sdk_messages:
61 Option<Arc<dyn Fn(Vec<crate::types::Message>) -> Vec<SDKMessage> + Send + Sync>>,
62 pub on_auth_401:
64 Option<Arc<dyn Fn(String) -> BoxFuture<Result<bool, AgentError>> + Send + Sync>>,
65 pub get_poll_interval_config: Option<Arc<dyn Fn() -> PollIntervalConfig + Send + Sync>>,
67 pub initial_history_cap: Option<u32>,
69 pub initial_messages: Option<Vec<crate::types::Message>>,
71 pub previously_flushed_uuids:
73 Option<Arc<dyn Fn() -> std::collections::HashSet<String> + Send + Sync>>,
74 pub on_inbound_message: Option<Arc<dyn Fn(SDKMessage) + Send + Sync>>,
76 pub on_permission_response: Option<Arc<dyn Fn(BridgeControlResponse) + Send + Sync>>,
78 pub on_interrupt: Option<Arc<dyn Fn() + Send + Sync>>,
80 pub on_set_model: Option<Arc<dyn Fn(Option<String>) + Send + Sync>>,
82 pub on_set_max_thinking_tokens: Option<Arc<dyn Fn(Option<u32>) + Send + Sync>>,
84 pub on_set_permission_mode:
86 Option<Arc<dyn Fn(crate::permission::PermissionMode) -> Result<(), String> + Send + Sync>>,
87 pub on_state_change: Option<Arc<dyn Fn(BridgeState, Option<String>) + Send + Sync>>,
89 pub on_user_message: Option<Arc<dyn Fn(String, String) -> bool + Send + Sync>>,
91 pub perpetual: Option<bool>,
93 pub initial_sse_sequence_num: Option<u64>,
95}
96
97impl Default for ReplBridgeOptions {
98 fn default() -> Self {
99 Self {
100 dir: std::env::current_dir()
101 .map(|p| p.to_string_lossy().to_string())
102 .unwrap_or_default(),
103 machine_name: "unknown".to_string(),
104 branch: String::new(),
105 git_repo_url: None,
106 title: String::new(),
107 base_url: String::new(),
108 session_ingress_url: String::new(),
109 worker_type: "repl".to_string(),
110 get_access_token: Arc::new(|| None),
111 create_session: Arc::new(|_, _, _, _| Box::pin(async { Ok(None) })),
112 archive_session: Arc::new(|_| Box::pin(async { Ok(()) })),
113 get_current_title: None,
114 to_sdk_messages: None,
115 on_auth_401: None,
116 get_poll_interval_config: None,
117 initial_history_cap: None,
118 initial_messages: None,
119 previously_flushed_uuids: None,
120 on_inbound_message: None,
121 on_permission_response: None,
122 on_interrupt: None,
123 on_set_model: None,
124 on_set_max_thinking_tokens: None,
125 on_set_permission_mode: None,
126 on_state_change: None,
127 on_user_message: None,
128 perpetual: None,
129 initial_sse_sequence_num: None,
130 }
131 }
132}
133
134pub struct ReplBridge {
136 pub session_id: RwLock<String>,
138 pub environment_id: RwLock<String>,
140 pub session_ingress_url: String,
142 pub inner: RwLock<Option<Arc<dyn ReplBridgeHandleInner>>>,
144}
145
146pub trait ReplBridgeHandleInner: Send + Sync {
148 fn write_messages(&self, messages: Vec<SDKMessage>);
150 fn write_sdk_messages(&self, messages: Vec<SDKMessage>);
152 fn send_control_request(&self, request: BridgeControlRequest);
154 fn send_control_response(&self, response: BridgeControlResponse);
156 fn send_control_cancel_request(&self, request_id: &str);
158 fn send_result(&self);
160 fn teardown(&self) -> BoxFuture<()>;
162}
163
164impl ReplBridge {
165 pub fn new(session_id: String, environment_id: String, session_ingress_url: String) -> Self {
167 Self {
168 session_id: RwLock::new(session_id),
169 environment_id: RwLock::new(environment_id),
170 session_ingress_url,
171 inner: RwLock::new(None),
172 }
173 }
174
175 pub async fn bridge_session_id(&self) -> String {
177 self.session_id.read().await.clone()
178 }
179
180 pub async fn environment_id(&self) -> String {
182 self.environment_id.read().await.clone()
183 }
184
185 pub fn session_ingress_url(&self) -> &str {
187 &self.session_ingress_url
188 }
189
190 pub fn write_messages(&self, messages: Vec<SDKMessage>) {
192 if let Some(inner) = self.inner.blocking_read().as_ref() {
193 inner.write_messages(messages);
194 }
195 }
196
197 pub fn write_sdk_messages(&self, messages: Vec<SDKMessage>) {
199 if let Some(inner) = self.inner.blocking_read().as_ref() {
200 inner.write_sdk_messages(messages);
201 }
202 }
203
204 pub fn send_control_request(&self, request: BridgeControlRequest) {
206 if let Some(inner) = self.inner.blocking_read().as_ref() {
207 inner.send_control_request(request);
208 }
209 }
210
211 pub fn send_control_response(&self, response: BridgeControlResponse) {
213 if let Some(inner) = self.inner.blocking_read().as_ref() {
214 inner.send_control_response(response);
215 }
216 }
217
218 pub fn send_control_cancel_request(&self, request_id: &str) {
220 if let Some(inner) = self.inner.blocking_read().as_ref() {
221 inner.send_control_cancel_request(request_id);
222 }
223 }
224
225 pub fn send_result(&self) {
227 if let Some(inner) = self.inner.blocking_read().as_ref() {
228 inner.send_result();
229 }
230 }
231
232 pub async fn teardown(&self) {
234 if let Some(inner) = self.inner.write().await.take() {
235 inner.teardown().await;
236 }
237 }
238}
239
240pub async fn init_repl_bridge(
248 _options: ReplBridgeOptions,
249) -> Result<Option<ReplBridge>, AgentError> {
250 Ok(None)
259}
260
261static REPL_BRIDGE_HANDLE: std::sync::OnceLock<ReplBridge> = std::sync::OnceLock::new();
268
269pub fn set_repl_bridge_handle(bridge: Option<ReplBridge>) {
271 let _ = REPL_BRIDGE_HANDLE.set(
272 bridge.unwrap_or_else(|| ReplBridge::new(String::new(), String::new(), String::new())),
273 );
274}
275
276pub fn get_repl_bridge_handle() -> Option<&'static ReplBridge> {
278 REPL_BRIDGE_HANDLE.get()
279}