pub trait ConnectTo<R: Role>: Send + 'static {
// Required method
fn connect_to(
self,
client: impl ConnectTo<R::Counterpart>,
) -> impl Future<Output = Result<()>> + Send;
// Provided method
fn into_channel_and_future(
self,
) -> (Channel, BoxFuture<'static, Result<()>>)
where Self: Sized { ... }
}Expand description
A component that can exchange JSON-RPC messages to an endpoint playing the role R
(e.g., an ACP Agent or an MCP Server).
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 connects to (its counterpart).
For example:
- An agent implements
ConnectTo<Client>to connect to clients - A proxy implements
ConnectTo<Conductor>to connect to conductors - Transports like
ChannelimplementConnectTo<R>for everyRbecause they are role-agnostic
§Component Types
The trait is implemented by several built-in types representing different communication patterns:
ByteStreams: A component communicating over byte streams (stdin/stdout, sockets, etc.)Channel: A component communicating via in-process message channels (for testing or direct connections)AcpAgent: An external agent running in a separate process with stdio communication- Custom components: Proxies, transformers, or any ACP-aware service
§Two Ways to Connect
Components can be used in two ways:
connect_to(client)- Connect directly to another component (most components implement this)into_channel_and_future()- Obtain a channel endpoint and a future that drives the connection
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
use agent_client_protocol::{Agent, Client, ConnectTo, Result};
struct MyAgent;
impl ConnectTo<Client> for MyAgent {
async fn connect_to(self, client: impl ConnectTo<Agent>) -> Result<()> {
Agent.builder()
.name("my-agent")
.connect_to(client)
.await
}
}§Heterogeneous Collections
For storing different component types in the same collection, use DynConnectTo:
use agent_client_protocol::{Channel, Client, DynConnectTo};
let (first, _first_peer) = Channel::duplex();
let (second, _second_peer) = Channel::duplex();
let components: Vec<DynConnectTo<Client>> = vec![
DynConnectTo::new(first),
DynConnectTo::new(second),
];
assert_eq!(components.len(), 2);Required Methods§
Sourcefn connect_to(
self,
client: impl ConnectTo<R::Counterpart>,
) -> impl Future<Output = Result<()>> + Send
fn connect_to( self, client: impl ConnectTo<R::Counterpart>, ) -> impl Future<Output = Result<()>> + Send
Connect this component to another component.
Most components implement this method to set up their connection and exchange messages with the provided component.
§Arguments
client- The component to connect to (implementsConnectTo<R::Counterpart>)
§Returns
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(())
merely because its client completed: it should first finish messages the
client already transferred to it. This lets wrappers preserve graceful
drain guarantees through to the physical transport sink. Errors may
still terminate the connection immediately.
Provided Methods§
Sourcefn into_channel_and_future(self) -> (Channel, BoxFuture<'static, Result<()>>)where
Self: Sized,
fn into_channel_and_future(self) -> (Channel, BoxFuture<'static, Result<()>>)where
Self: Sized,
Convert this component into a channel endpoint and connection future.
The returned Channel is the canonical frame-aware boundary. It carries
complete TransportFrame values so default
adapters preserve batch grouping.
This method returns:
- A
Channelthat can be used to communicate with this component - A
BoxFuturethat drives the component’s connection logic
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.
§Returns
A tuple of (Channel, BoxFuture) where the channel is for the caller to use
and the future must be polled to drive the connection.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".
Implementors§
impl ConnectTo<Client> for AgentProtocolRouter
unstable_protocol_v2 only.