1use crate::cli::AppServerBuilder;
46use crate::error::{Error, ParseError, Result};
47use crate::jsonrpc::{
48 JsonRpcError, JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, RequestId,
49};
50use crate::messages::{Notification, ServerMessage, ServerRequest};
51use crate::protocol::{
52 ClientInfo, InitializeParams, InitializeResponse, ThreadArchiveParams, ThreadArchiveResponse,
53 ThreadDeleteParams, ThreadDeleteResponse, ThreadForkParams, ThreadForkResponse,
54 ThreadItemsListParams, ThreadItemsListResponse, ThreadResumeParams, ThreadResumeResponse,
55 ThreadRevertParams, ThreadRevertResponse, ThreadStartParams, ThreadStartResponse,
56 ThreadTurnsListParams, ThreadTurnsListResponse, TurnInterruptParams, TurnInterruptResponse,
57 TurnStartParams, TurnStartResponse, TurnSteerParams, TurnSteerResponse,
58};
59use log::{debug, warn};
60use serde::de::DeserializeOwned;
61use serde::Serialize;
62use std::collections::VecDeque;
63use std::io::{BufRead, BufReader, BufWriter, Write};
64use std::process::Child;
65
66const STDOUT_BUFFER_SIZE: usize = 10 * 1024 * 1024;
68
69pub struct SyncClient {
78 child: Child,
79 writer: BufWriter<std::process::ChildStdin>,
80 reader: BufReader<std::process::ChildStdout>,
81 _stderr_drain: std::thread::JoinHandle<()>,
85 next_id: i64,
86 buffered: VecDeque<ServerMessage>,
87}
88
89impl SyncClient {
90 pub fn new(mut child: Child) -> Result<Self> {
98 let stdin = child
99 .stdin
100 .take()
101 .ok_or_else(|| Error::Protocol("Failed to get stdin".to_string()))?;
102 let stdout = child
103 .stdout
104 .take()
105 .ok_or_else(|| Error::Protocol("Failed to get stdout".to_string()))?;
106 let stderr = child
107 .stderr
108 .take()
109 .ok_or_else(|| Error::Protocol("Failed to get stderr".to_string()))?;
110
111 let stderr_drain = crate::stderr_drain::spawn_sync(stderr);
116
117 Ok(Self {
118 child,
119 writer: BufWriter::new(stdin),
120 reader: BufReader::with_capacity(STDOUT_BUFFER_SIZE, stdout),
121 _stderr_drain: stderr_drain,
122 next_id: 1,
123 buffered: VecDeque::new(),
124 })
125 }
126
127 pub fn start() -> Result<Self> {
139 Self::start_with(AppServerBuilder::new())
140 }
141
142 pub fn start_with(builder: AppServerBuilder) -> Result<Self> {
153 let mut client = Self::spawn(builder)?;
154 client.initialize(&InitializeParams {
155 client_info: ClientInfo {
156 name: "codex-codes".to_string(),
157 version: env!("CARGO_PKG_VERSION").to_string(),
158 title: None,
159 },
160 capabilities: None,
161 })?;
162 Ok(client)
163 }
164
165 pub fn spawn(builder: AppServerBuilder) -> Result<Self> {
171 crate::version::check_codex_version()?;
172 Self::new(builder.spawn_sync()?)
173 }
174
175 pub fn request<P: Serialize, R: DeserializeOwned>(
186 &mut self,
187 method: &str,
188 params: &P,
189 ) -> Result<R> {
190 let id = RequestId::Integer(self.next_id);
191 self.next_id += 1;
192
193 let req = JsonRpcRequest {
194 id: id.clone(),
195 method: method.to_string(),
196 params: Some(serde_json::to_value(params).map_err(Error::Json)?),
197 };
198
199 self.send_raw(&req)?;
200
201 loop {
202 let msg = self.read_message()?;
203 match msg {
204 JsonRpcMessage::Response(resp) if resp.id == id => {
205 let result: R = serde_json::from_value(resp.result).map_err(Error::Json)?;
206 return Ok(result);
207 }
208 JsonRpcMessage::Error(err) if err.id == id => {
209 return Err(Error::JsonRpc {
210 code: err.error.code,
211 message: err.error.message,
212 });
213 }
214 JsonRpcMessage::Notification(notif) => {
215 let typed = Notification::from_envelope(¬if.method, notif.params)
216 .map_err(Error::Json)?;
217 self.buffered.push_back(ServerMessage::Notification(typed));
218 }
219 JsonRpcMessage::Request(req) => {
220 let typed = ServerRequest::from_envelope(&req.method, req.params)
221 .map_err(Error::Json)?;
222 self.buffered.push_back(ServerMessage::Request {
223 id: req.id,
224 request: typed,
225 });
226 }
227 JsonRpcMessage::Response(resp) => {
228 warn!(
229 "[CLIENT] Unexpected response for id={}, expected id={}",
230 resp.id, id
231 );
232 }
233 JsonRpcMessage::Error(err) => {
234 warn!(
235 "[CLIENT] Unexpected error for id={}, expected id={}",
236 err.id, id
237 );
238 }
239 }
240 }
241 }
242
243 pub fn thread_start(&mut self, params: &ThreadStartParams) -> Result<ThreadStartResponse> {
248 self.request(crate::protocol::methods::THREAD_START, params)
249 }
250
251 pub fn thread_resume(&mut self, params: &ThreadResumeParams) -> Result<ThreadResumeResponse> {
255 self.request(crate::protocol::methods::THREAD_RESUME, params)
256 }
257
258 pub fn thread_fork(&mut self, params: &ThreadForkParams) -> Result<ThreadForkResponse> {
260 self.request(crate::protocol::methods::THREAD_FORK, params)
261 }
262
263 pub fn turn_start(&mut self, params: &TurnStartParams) -> Result<TurnStartResponse> {
268 self.request(crate::protocol::methods::TURN_START, params)
269 }
270
271 pub fn turn_steer(&mut self, params: &TurnSteerParams) -> Result<TurnSteerResponse> {
273 self.request(crate::protocol::methods::TURN_STEER, params)
274 }
275
276 pub fn thread_items_list(
278 &mut self,
279 params: &ThreadItemsListParams,
280 ) -> Result<ThreadItemsListResponse> {
281 self.request(crate::protocol::methods::THREAD_ITEMS_LIST, params)
282 }
283
284 pub fn thread_turns_list(
286 &mut self,
287 params: &ThreadTurnsListParams,
288 ) -> Result<ThreadTurnsListResponse> {
289 self.request(crate::protocol::methods::THREAD_TURNS_LIST, params)
290 }
291
292 pub fn thread_revert(&mut self, params: &ThreadRevertParams) -> Result<ThreadRevertResponse> {
294 self.request(crate::protocol::methods::THREAD_REVERT, params)
295 }
296
297 pub fn turn_interrupt(
299 &mut self,
300 params: &TurnInterruptParams,
301 ) -> Result<TurnInterruptResponse> {
302 self.request(crate::protocol::methods::TURN_INTERRUPT, params)
303 }
304
305 pub fn thread_archive(
307 &mut self,
308 params: &ThreadArchiveParams,
309 ) -> Result<ThreadArchiveResponse> {
310 self.request(crate::protocol::methods::THREAD_ARCHIVE, params)
311 }
312
313 pub fn thread_delete(&mut self, params: &ThreadDeleteParams) -> Result<ThreadDeleteResponse> {
315 self.request(crate::protocol::methods::THREAD_DELETE, params)
316 }
317
318 pub fn initialize(&mut self, params: &InitializeParams) -> Result<InitializeResponse> {
324 let resp: InitializeResponse =
325 self.request(crate::protocol::methods::INITIALIZE, params)?;
326 self.send_notification(crate::protocol::methods::INITIALIZED)?;
327 Ok(resp)
328 }
329
330 pub fn respond<R: Serialize>(&mut self, id: RequestId, result: &R) -> Result<()> {
337 let resp = JsonRpcResponse {
338 id,
339 result: serde_json::to_value(result).map_err(Error::Json)?,
340 };
341 self.send_raw(&resp)
342 }
343
344 pub fn respond_error(&mut self, id: RequestId, code: i64, message: &str) -> Result<()> {
346 let err = JsonRpcError {
347 id,
348 error: crate::jsonrpc::JsonRpcErrorData {
349 code,
350 message: message.to_string(),
351 data: None,
352 },
353 };
354 self.send_raw(&err)
355 }
356
357 pub fn next_message(&mut self) -> Result<Option<ServerMessage>> {
364 if let Some(msg) = self.buffered.pop_front() {
365 return Ok(Some(msg));
366 }
367
368 loop {
369 let msg = match self.read_message_opt()? {
370 Some(m) => m,
371 None => return Ok(None),
372 };
373
374 match msg {
375 JsonRpcMessage::Notification(notif) => {
376 let JsonRpcNotification { method, params } = notif;
377 let typed =
378 Notification::from_envelope(&method, params.clone()).map_err(|e| {
379 Error::Deserialization(ParseError::from_envelope(method, params, e))
380 })?;
381 return Ok(Some(ServerMessage::Notification(typed)));
382 }
383 JsonRpcMessage::Request(req) => {
384 let JsonRpcRequest { id, method, params } = req;
385 let typed =
386 ServerRequest::from_envelope(&method, params.clone()).map_err(|e| {
387 Error::Deserialization(ParseError::from_envelope(method, params, e))
388 })?;
389 return Ok(Some(ServerMessage::Request { id, request: typed }));
390 }
391 JsonRpcMessage::Response(resp) => {
392 warn!(
393 "[CLIENT] Unexpected response (no pending request): id={}",
394 resp.id
395 );
396 }
397 JsonRpcMessage::Error(err) => {
398 warn!(
399 "[CLIENT] Unexpected error (no pending request): id={} code={}",
400 err.id, err.error.code
401 );
402 }
403 }
404 }
405 }
406
407 pub fn events(&mut self) -> EventIterator<'_> {
413 EventIterator { client: self }
414 }
415
416 pub fn shutdown(&mut self) -> Result<()> {
420 debug!("[CLIENT] Shutting down");
421 match self.child.try_wait() {
422 Ok(Some(_)) => Ok(()),
423 Ok(None) => {
424 self.child.kill().map_err(Error::Io)?;
425 self.child.wait().map_err(Error::Io)?;
426 Ok(())
427 }
428 Err(e) => Err(Error::Io(e)),
429 }
430 }
431
432 fn send_notification(&mut self, method: &str) -> Result<()> {
435 let notif = JsonRpcNotification {
436 method: method.to_string(),
437 params: None,
438 };
439 self.send_raw(¬if)
440 }
441
442 fn send_raw<T: Serialize>(&mut self, msg: &T) -> Result<()> {
443 let json = serde_json::to_string(msg).map_err(Error::Json)?;
444 debug!("[CLIENT] Sending: {}", json);
445 self.writer.write_all(json.as_bytes()).map_err(Error::Io)?;
446 self.writer.write_all(b"\n").map_err(Error::Io)?;
447 self.writer.flush().map_err(Error::Io)?;
448 Ok(())
449 }
450
451 fn read_message(&mut self) -> Result<JsonRpcMessage> {
452 self.read_message_opt()?.ok_or(Error::ServerClosed)
453 }
454
455 fn read_message_opt(&mut self) -> Result<Option<JsonRpcMessage>> {
456 loop {
457 let mut line = String::new();
458 match self.reader.read_line(&mut line) {
459 Ok(0) => {
460 debug!("[CLIENT] Stream closed (EOF)");
461 return Ok(None);
462 }
463 Ok(_) => {
464 let trimmed = line.trim();
465 if trimmed.is_empty() {
466 continue;
467 }
468
469 debug!("[CLIENT] Received: {}", trimmed);
470
471 match serde_json::from_str::<JsonRpcMessage>(trimmed) {
472 Ok(msg) => return Ok(Some(msg)),
473 Err(e) => {
474 warn!(
475 "[CLIENT] Failed to deserialize message. \
476 Please report this at https://github.com/meawoppl/rust-code-agent-sdks/issues"
477 );
478 warn!("[CLIENT] Parse error: {}", e);
479 warn!("[CLIENT] Raw: {}", trimmed);
480 return Err(Error::Deserialization(ParseError::from_line(trimmed, e)));
481 }
482 }
483 }
484 Err(e) => {
485 debug!("[CLIENT] Error reading stdout: {}", e);
486 return Err(Error::Io(e));
487 }
488 }
489 }
490 }
491}
492
493impl Drop for SyncClient {
494 fn drop(&mut self) {
495 if let Err(e) = self.shutdown() {
496 debug!("[CLIENT] Error during shutdown: {}", e);
497 }
498 }
499}
500
501pub struct EventIterator<'a> {
503 client: &'a mut SyncClient,
504}
505
506impl Iterator for EventIterator<'_> {
507 type Item = Result<ServerMessage>;
508
509 fn next(&mut self) -> Option<Self::Item> {
510 match self.client.next_message() {
511 Ok(Some(msg)) => Some(Ok(msg)),
512 Ok(None) => None,
513 Err(e) => Some(Err(e)),
514 }
515 }
516}
517
518#[cfg(test)]
519mod tests {
520 use super::*;
521
522 #[test]
523 fn test_buffer_size() {
524 assert_eq!(STDOUT_BUFFER_SIZE, 10 * 1024 * 1024);
525 }
526}