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
//! 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(())
//! # }
//! ```
//!
//! You must send exactly one response per request. If your callback returns
//! without responding, an error response is sent automatically.
//!
//! # 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