diff --git a/src/agent-client-protocol-rmcp/examples/with_mcp_server.rs b/src/agent-client-protocol-rmcp/examples/with_mcp_server.rs index 24c81e8..9a1b648 100644 --- a/src/agent-client-protocol-rmcp/examples/with_mcp_server.rs +++ b/src/agent-client-protocol-rmcp/examples/with_mcp_server.rs @@ -87,13 +87,12 @@ async fn main() -> Result<(), Box> { let mcp_server = McpServer::from_rmcp("example", ExampleMcpServer::new); // Set up the proxy connection with our MCP server - // ProxyToConductor already has proxy behavior built into its default_message_handler Proxy .builder() .name("mcp-server-proxy") // Register the MCP server as a handler .with_mcp_server(mcp_server) - // Start serving + // Connect the proxy to the conductor over stdio .connect_to(agent_client_protocol::ByteStreams::new( tokio::io::stdout().compat_write(), tokio::io::stdin().compat(), diff --git a/src/agent-client-protocol/src/component.rs b/src/agent-client-protocol/src/component.rs index b4a5ede..0a286e5 100644 --- a/src/agent-client-protocol/src/component.rs +++ b/src/agent-client-protocol/src/component.rs @@ -10,19 +10,16 @@ //! //! To implement a component, implement the `connect_to` method: //! -//! ```rust,ignore -//! use agent_client_protocol::{Agent, Client, Connect, Result}; +//! ```rust +//! use agent_client_protocol::{Agent, Client, ConnectTo, Result}; //! -//! struct MyAgent { -//! // configuration fields -//! } +//! struct MyAgent; //! //! // An agent connects to clients //! impl ConnectTo for MyAgent { //! async fn connect_to(self, client: impl ConnectTo) -> Result<()> { //! Agent.builder() //! .name("my-agent") -//! // configure handlers here //! .connect_to(client) //! .await //! } @@ -40,11 +37,11 @@ use crate::{Channel, Result, role::Role}; /// This trait represents anything that can communicate via JSON-RPC messages over channels - /// agents, proxies, in-process connections, or any ACP-speaking component. /// -/// The type parameter `R` is the role that this component serves (its counterpart). +/// The type parameter `R` is the role that this component connects to (its counterpart). /// For example: -/// - An agent implements `Serve` - it serves clients -/// - A proxy implements `Serve` - it serves conductors -/// - Transports like `Channel` implement `Serve` for all `R` since they're role-agnostic +/// - An agent implements `ConnectTo` to connect to clients +/// - A proxy implements `ConnectTo` to connect to conductors +/// - Transports like `Channel` implement `ConnectTo` for every `R` because they are role-agnostic /// /// # Component Types /// @@ -55,35 +52,29 @@ use crate::{Channel, Result, role::Role}; /// - **[`AcpAgent`]**: An external agent running in a separate process with stdio communication /// - **Custom components**: Proxies, transformers, or any ACP-aware service /// -/// # Two Ways to Serve +/// # Two Ways to Connect /// /// Components can be used in two ways: /// -/// 1. **`serve(client)`** - Serve by forwarding to another component (most components implement this) -/// 2. **`into_server()`** - Convert into a channel endpoint and server future (base cases implement this) +/// 1. **`connect_to(client)`** - Connect directly to another component (most components implement this) +/// 2. **`into_channel_and_future()`** - Obtain a channel endpoint and a future that drives the connection /// -/// Most components only need to implement `serve(client)` - the `into_server()` method has a default -/// implementation that creates an intermediate channel and calls `serve`. +/// Most components only need to implement `connect_to(client)`. The +/// `into_channel_and_future()` method has a default implementation that creates an intermediate +/// channel and calls `connect_to`. /// /// # Implementation Example /// -/// ```rust,ignore -/// use agent_client_protocol::{Agent, Result, Serve, role::Client}; +/// ```rust +/// use agent_client_protocol::{Agent, Client, ConnectTo, Result}; /// -/// struct MyAgent { -/// config: AgentConfig, -/// } +/// struct MyAgent; /// -/// impl Serve for MyAgent { -/// async fn serve(self, client: impl Serve) -> Result<()> { -/// // Set up connection that forwards to client +/// impl ConnectTo for MyAgent { +/// async fn connect_to(self, client: impl ConnectTo) -> Result<()> { /// Agent.builder() /// .name("my-agent") -/// .on_receive_request(async |req: MyRequest, cx| { -/// // Handle request -/// cx.respond(MyResponse { status: "ok".into() }) -/// }) -/// .serve(client) +/// .connect_to(client) /// .await /// } /// } @@ -93,32 +84,34 @@ use crate::{Channel, Result, role::Role}; /// /// For storing different component types in the same collection, use [`DynConnectTo`]: /// -/// ```rust,ignore -/// use agent_client_protocol::Client; +/// ```rust +/// use agent_client_protocol::{Channel, Client, DynConnectTo}; /// +/// let (first, _first_peer) = Channel::duplex(); +/// let (second, _second_peer) = Channel::duplex(); /// let components: Vec> = vec![ -/// DynConnectTo::new(proxy1), -/// DynConnectTo::new(proxy2), -/// DynConnectTo::new(agent), +/// DynConnectTo::new(first), +/// DynConnectTo::new(second), /// ]; +/// assert_eq!(components.len(), 2); /// ``` /// /// [`ByteStreams`]: crate::ByteStreams /// [`AcpAgent`]: crate::AcpAgent /// [`Builder`]: crate::Builder pub trait ConnectTo: Send + 'static { - /// Serve this component by forwarding to a client component. + /// Connect this component to another component. /// /// Most components implement this method to set up their connection and - /// forward messages to the provided client. + /// exchange messages with the provided component. /// /// # Arguments /// - /// * `client` - The component to forward messages to (implements `Serve`) + /// * `client` - The component to connect to (implements `ConnectTo`) /// /// # Returns /// - /// A future that resolves when the component stops serving, either successfully + /// A future that resolves when the connection ends, either successfully /// or with an error. The future must be `Send`. /// /// A component that buffers outbound messages should not return `Ok(())` @@ -131,7 +124,7 @@ pub trait ConnectTo: Send + 'static { client: impl ConnectTo, ) -> impl Future> + Send; - /// Convert this component into a channel endpoint and server future. + /// Convert this component into a channel endpoint and connection future. /// /// The returned [`Channel`] is the canonical frame-aware boundary. It carries /// complete [`TransportFrame`](crate::TransportFrame) values so default @@ -139,9 +132,9 @@ pub trait ConnectTo: Send + 'static { /// /// This method returns: /// - A `Channel` that can be used to communicate with this component - /// - A `BoxFuture` that runs the component's server logic + /// - A `BoxFuture` that drives the component's connection logic /// - /// The default implementation creates an intermediate channel pair and calls `serve` + /// The default implementation creates an intermediate channel pair and calls `connect_to` /// on one endpoint while returning the other endpoint for the caller to use. /// /// Base cases like `Channel` and `ByteStreams` override this to avoid unnecessary copying. @@ -149,7 +142,7 @@ pub trait ConnectTo: Send + 'static { /// # Returns /// /// A tuple of `(Channel, BoxFuture)` where the channel is for the caller to use - /// and the future must be spawned to run the server. + /// and the future must be polled to drive the connection. fn into_channel_and_future(self) -> (Channel, BoxFuture<'static, Result<()>>) where Self: Sized, @@ -177,7 +170,7 @@ trait ErasedConnectTo: Send { -> (Channel, BoxFuture<'static, Result<()>>); } -/// Blanket implementation: any `Serve` can be type-erased. +/// Blanket implementation: any `ConnectTo` can be type-erased. impl, R: Role> ErasedConnectTo for C { fn type_name(&self) -> &'static str { std::any::type_name::() @@ -210,18 +203,20 @@ impl, R: Role> ErasedConnectTo for C { /// allowing you to store different component types in the same collection. /// /// The type parameter `R` is the role that all components in the -/// collection serve (their counterpart). +/// collection connect to (their counterpart). /// /// # Examples /// -/// ```rust,ignore -/// use agent_client_protocol::{DynConnectTo, Client}; +/// ```rust +/// use agent_client_protocol::{Channel, Client, DynConnectTo}; /// +/// let (first, _first_peer) = Channel::duplex(); +/// let (second, _second_peer) = Channel::duplex(); /// let components: Vec> = vec![ -/// DynConnectTo::new(Proxy1), -/// DynConnectTo::new(Proxy2), -/// DynConnectTo::new(Agent), +/// DynConnectTo::new(first), +/// DynConnectTo::new(second), /// ]; +/// assert_eq!(components.len(), 2); /// ``` pub struct DynConnectTo { inner: Box>, diff --git a/src/agent-client-protocol/src/jsonrpc.rs b/src/agent-client-protocol/src/jsonrpc.rs index 2f958ce..c11e597 100644 --- a/src/agent-client-protocol/src/jsonrpc.rs +++ b/src/agent-client-protocol/src/jsonrpc.rs @@ -3975,9 +3975,9 @@ impl Dispatch { /// /// # Returns /// - /// * `Ok(Ok(typed))` if this is a request/notification of the given types - /// * `Ok(Err(self))` if not - /// * `Err` if has the correct method for the given types but parsing fails + /// * `Ok(Ok(typed))` if this dispatch matches the requested type for its variant + /// * `Ok(Err(self))` if it does not match the requested type for its variant + /// * `Err` if its method matches the requested type but parsing fails #[tracing::instrument(skip(self), fields(Request = ?std::any::type_name::(), Notif = ?std::any::type_name::()), level = "trace", ret)] pub(crate) fn into_typed_dispatch( self, @@ -4089,9 +4089,9 @@ impl Dispatch { /// /// # Returns /// - /// * `Ok(Ok(typed))` if this is a request/notification of the given types - /// * `Ok(Err(self))` if not - /// * `Err` if has the correct method for the given types but parsing fails + /// * `Ok(Ok(typed))` if this is a notification of the requested type + /// * `Ok(Err(self))` if this is not a matching notification + /// * `Err` if its method matches the requested type but parsing fails pub fn into_notification( self, ) -> Result, crate::Error> { @@ -4113,9 +4113,9 @@ impl Dispatch { /// /// # Returns /// - /// * `Ok(Ok(typed))` if this is a request/notification of the given types - /// * `Ok(Err(self))` if not - /// * `Err` if has the correct method for the given types but parsing fails + /// * `Ok(Ok(typed))` if this is a request of the requested type + /// * `Ok(Err(self))` if this is not a matching request + /// * `Err` if its method matches the requested type but parsing fails pub fn into_request( self, ) -> Result), Dispatch>, crate::Error> { diff --git a/src/agent-client-protocol/src/role.rs b/src/agent-client-protocol/src/role.rs index fc52e4a..5c53740 100644 --- a/src/agent-client-protocol/src/role.rs +++ b/src/agent-client-protocol/src/role.rs @@ -28,7 +28,7 @@ pub mod mcp; /// /// Each role determines: /// - Who the counterpart is (via [`Role::Counterpart`]) -/// - How unhandled messages are processed (via `Role::default_message_handler`) +/// - How unhandled messages are processed (via [`Role::default_handle_dispatch_from`]) pub trait Role: Debug + Clone + Send + Sync + 'static + Eq + Ord + Hash { /// The role that this endpoint connects to. /// @@ -264,7 +264,7 @@ where } /// A dummy role you can use to exchange JSON-RPC messages without any knowledge of the underlying protocol. -/// Don't sue this. +/// Prefer a protocol-specific role when one is available. #[derive( Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, )] diff --git a/src/agent-client-protocol/src/session.rs b/src/agent-client-protocol/src/session.rs index 709561a..70483d6 100644 --- a/src/agent-client-protocol/src/session.rs +++ b/src/agent-client-protocol/src/session.rs @@ -28,7 +28,7 @@ impl SessionBlockState for Blocking {} pub struct NonBlocking; impl SessionBlockState for NonBlocking {} -/// Trait for marker types that indicate blocking vs blocking API. +/// Trait for marker types that indicate blocking vs non-blocking API. /// See [`SessionBuilder::block_task`]. pub trait SessionBlockState: Send + 'static + Sync + std::fmt::Debug {}