Skip to main content

cap_rs/
driver.rs

1//! Driver backends — concrete implementations that drive a CLI agent.
2//!
3//! Each driver is gated behind a feature flag. The cross-driver API is the
4//! [`Driver`] trait; all drivers emit the same [`crate::core::AgentEvent`]
5//! stream regardless of wire format.
6
7#[cfg(feature = "stream-json")]
8pub mod stream_json;
9
10#[cfg(feature = "pty")]
11pub mod pty;
12
13// Future modules — gated on their respective features:
14// #[cfg(feature = "acp")]          pub mod acp;
15// #[cfg(feature = "a2a")]          pub mod a2a;
16// #[cfg(feature = "grpc")]         pub mod grpc;
17// #[cfg(feature = "orchestrator")] pub mod orchestrator;
18
19// The Driver trait and DriverError are shared across all driver backends.
20// They're gated on `any(stream-json, pty, ...)` because their deps
21// (async-trait, thiserror) come in via those features.
22
23#[cfg(any(feature = "stream-json", feature = "pty"))]
24mod common {
25    use crate::core::{AgentEvent, ClientFrame};
26
27    /// A unified driver interface. Concrete drivers translate this to their
28    /// underlying wire format (PTY, stream-json, gRPC, ACP-stdio, A2A SSE).
29    #[async_trait::async_trait]
30    pub trait Driver: Send {
31        /// Send a frame to the agent. The frame is processed asynchronously;
32        /// resulting events arrive via [`Driver::next_event`].
33        async fn send(&mut self, frame: ClientFrame) -> Result<(), DriverError>;
34
35        /// Await the next event from the agent. Returns `None` when the
36        /// agent has exited cleanly.
37        async fn next_event(&mut self) -> Option<AgentEvent>;
38
39        /// Shut down the agent process and release resources.
40        async fn shutdown(&mut self) -> Result<(), DriverError>;
41    }
42
43    /// Driver-level errors.
44    #[derive(Debug, thiserror::Error)]
45    #[non_exhaustive]
46    pub enum DriverError {
47        #[error("agent binary not found on PATH: {0}")]
48        BinaryNotFound(String),
49
50        #[error("failed to spawn agent process: {0}")]
51        SpawnFailed(#[source] std::io::Error),
52
53        #[error("agent process exited unexpectedly")]
54        AgentExited,
55
56        #[error("io error while talking to agent: {0}")]
57        Io(#[from] std::io::Error),
58
59        #[error("failed to parse agent output: {0}")]
60        Parse(String),
61
62        #[error("agent reported error: {code} — {message}")]
63        AgentError { code: String, message: String },
64    }
65
66    #[cfg(feature = "stream-json")]
67    impl From<serde_json::Error> for DriverError {
68        fn from(e: serde_json::Error) -> Self {
69            DriverError::Parse(e.to_string())
70        }
71    }
72}
73
74#[cfg(any(feature = "stream-json", feature = "pty"))]
75pub use common::{Driver, DriverError};