agent_client_protocol/concepts/peers.rs
1//! Explicit peers: using `_to` and `_from` variants.
2//!
3//! So far, we've used methods like `send_request` and `on_receive_request`
4//! without specifying *who* we're sending to or receiving from. That's because
5//! each role type has a **default peer**.
6//!
7//! # Default Peers
8//!
9//! For simple role types, there's only one peer to talk to:
10//!
11//! | Role Type | Default Peer |
12//! |-----------|--------------|
13//! | [`Client`] | The agent |
14//! | [`Agent`] | The client |
15//!
16//! So when you write:
17//!
18//! ```
19//! # use agent_client_protocol::{Client, Agent, ConnectTo};
20//! # use agent_client_protocol::schema::{ProtocolVersion, v1::InitializeRequest};
21//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
22//! # Client.builder().connect_with(transport, async |cx| {
23//! // As a client
24//! cx.send_request(InitializeRequest::new(ProtocolVersion::V1));
25//! # Ok(())
26//! # }).await?;
27//! # Ok(())
28//! # }
29//! ```
30//!
31//! The request automatically goes to the agent, because that's the only peer
32//! a client can talk to.
33//!
34//! # Explicit Peer Methods
35//!
36//! Every method has an explicit variant that takes a peer argument:
37//!
38//! | Default method | Explicit variant |
39//! |----------------|------------------|
40//! | `send_request` | `send_request_to(peer, request)` |
41//! | `send_notification` | `send_notification_to(peer, request)` |
42//! | `on_receive_request` | `on_receive_request_from(peer, callback)` |
43//! | `on_receive_notification` | `on_receive_notification_from(peer, callback)` |
44//!
45//! For simple role types, the explicit form is equivalent:
46//!
47//! ```
48//! # use agent_client_protocol::{Client, Agent, ConnectTo};
49//! # use agent_client_protocol_test::MyRequest;
50//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
51//! # Client.builder().connect_with(transport, async |cx| {
52//! # let req = MyRequest {};
53//! // These are equivalent for Client:
54//! let request = cx.send_request(req.clone());
55//! let same = cx.send_request_to(Agent, req);
56//! # let _ = (request, same);
57//! # Ok(())
58//! # }).await?;
59//! # Ok(())
60//! # }
61//! ```
62//!
63//! # Why Explicit Peers Matter
64//!
65//! Explicit peers become essential when working with proxies. A proxy sits
66//! between a client and an agent, so it has *two* peers:
67//!
68//! - [`Client`] - the client (or previous proxy in the chain)
69//! - [`Agent`] - the agent (or next proxy in the chain)
70//!
71//! When writing proxy code, you need to specify which direction:
72//!
73//! ```
74//! # use agent_client_protocol::{Proxy, Client, Agent, Conductor, ConnectTo};
75//! # use agent_client_protocol_test::MyRequest;
76//! # async fn example(transport: impl ConnectTo<Proxy>) -> Result<(), agent_client_protocol::Error> {
77//! Proxy.builder()
78//! // Receive a request from the client
79//! .on_receive_request_from(Client, async |req: MyRequest, responder, cx| {
80//! // Forward it to the agent
81//! cx.send_request_to(Agent, req)
82//! .forward_response_to(responder)
83//! }, agent_client_protocol::on_receive_request!())
84//! .connect_to(transport)
85//! .await?;
86//! # Ok(())
87//! # }
88//! ```
89//!
90//! See [Proxies and Conductors](super::proxies) for more on building proxies.
91//!
92//! # Available Peer Types
93//!
94//! | Peer Type | Represents |
95//! |-----------|------------|
96//! | [`Client`] | The client direction |
97//! | [`Agent`] | The agent direction |
98//! | [`Conductor`] | The conductor (for proxies) |
99//!
100//! # Next Steps
101//!
102//! - [Ordering](super::ordering) - Understand dispatch loop semantics
103//! - [Proxies and Conductors](super::proxies) - Build proxies that use explicit peers
104//!
105//! [`Client`]: crate::Client
106//! [`Agent`]: crate::Agent
107//! [`Conductor`]: crate::Conductor