1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! Handling incoming messages with `on_receive_*` callbacks.
//!
//! So far we've seen how to *send* messages. But ACP is bidirectional - the
//! remote peer can also send messages to you. Use callbacks to handle them.
//!
//! # Handling Requests
//!
//! Use `on_receive_request` to handle incoming requests that expect a response:
//!
//! ```
//! # use agent_client_protocol::{Client, Agent, ConnectTo};
//! # use agent_client_protocol_test::{ValidateRequest, ValidateResponse};
//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
//! Client.builder()
//! .on_receive_request(async |req: ValidateRequest, responder, cx| {
//! // Process the request
//! let is_valid = req.data.len() > 0;
//!
//! // Send the response
//! responder.respond(ValidateResponse { is_valid, error: None })
//! }, agent_client_protocol::on_receive_request!())
//! .connect_with(transport, async |cx| { Ok(()) })
//! .await?;
//! # Ok(())
//! # }
//! ```
//!
//! Your callback receives three arguments:
//! - The request payload (e.g., `PermissionRequest`)
//! - A [`Responder`] for sending the response
//! - A [`ConnectionTo`] for sending other messages
//!
//! # Handling Notifications
//!
//! Use `on_receive_notification` for fire-and-forget messages that don't need
//! a response:
//!
//! ```
//! # use agent_client_protocol::{Client, Agent, ConnectTo};
//! # use agent_client_protocol_test::StatusUpdate;
//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
//! Client.builder()
//! .on_receive_notification(async |notif: StatusUpdate, cx| {
//! println!("Status: {}", notif.message);
//! Ok(())
//! }, agent_client_protocol::on_receive_notification!())
//! # .connect_with(transport, async |_| Ok(())).await?;
//! # Ok(())
//! # }
//! ```
//!
//! # The Request Context
//!
//! The [`Responder`] lets you send a response to the request:
//!
//! ```
//! # use agent_client_protocol::{Client, Agent, ConnectTo};
//! # use agent_client_protocol_test::{MyRequest, MyResponse};
//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
//! # Client.builder()
//! # .on_receive_request(async |req: MyRequest, responder, cx| {
//! // Send a successful response
//! responder.respond(MyResponse { status: "ok".into() })?;
//! # Ok(())
//! # }, agent_client_protocol::on_receive_request!())
//! # .connect_with(transport, async |_| Ok(())).await?;
//! # Ok(())
//! # }
//! ```
//!
//! Or send an error:
//!
//! ```
//! # use agent_client_protocol::{Client, Agent, ConnectTo};
//! # use agent_client_protocol_test::{MyRequest, MyResponse};
//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
//! # Client.builder()
//! # .on_receive_request(async |req: MyRequest, responder, cx| {
//! responder.respond_with_error(agent_client_protocol::Error::invalid_params())?;
//! # Ok(())
//! # }, agent_client_protocol::on_receive_request!())
//! # .connect_with(transport, async |_| Ok(())).await?;
//! # Ok(())
//! # }
//! ```
//!
//! Send at most one response per request. If a handler responds and then
//! returns an error, the first response wins and the duplicate completion is
//! ignored. Dropping a responder from a batch produces an automatic Internal
//! Error so sibling responses are not stranded; dropping the responder for an
//! individual request sends no response.
//!
//! # Multiple Handlers
//!
//! You can register multiple handlers. They're tried in order until one
//! handles the message:
//!
//! ```
//! # use agent_client_protocol::{Client, Agent, ConnectTo};
//! # use agent_client_protocol_test::{ValidateRequest, ValidateResponse, ExecuteRequest, ExecuteResponse};
//! # async fn example(transport: impl ConnectTo<Client>) -> Result<(), agent_client_protocol::Error> {
//! Client.builder()
//! .on_receive_request(async |req: ValidateRequest, responder, cx| {
//! // Handle validation requests
//! responder.respond(ValidateResponse { is_valid: true, error: None })
//! }, agent_client_protocol::on_receive_request!())
//! .on_receive_request(async |req: ExecuteRequest, responder, cx| {
//! // Handle execution requests
//! responder.respond(ExecuteResponse { result: "done".into() })
//! }, agent_client_protocol::on_receive_request!())
//! # .connect_with(transport, async |_| Ok(())).await?;
//! # Ok(())
//! # }
//! ```
//!
//! # Ordering Guarantees
//!
//! Callbacks run inside the dispatch loop and block further message processing
//! until they complete. This gives you ordering guarantees but also means you
//! need to be careful about deadlocks.
//!
//! See [Ordering](super::ordering) for the full details.
//!
//! # Next Steps
//!
//! - [Explicit Peers](super::peers) - Use `_from` variants to specify the source peer
//! - [Ordering](super::ordering) - Understand dispatch loop semantics
//!
//! [`Responder`]: crate::Responder
//! [`ConnectionTo`]: crate::ConnectionTo