1use std::{fmt::Debug, hash::Hash};
2
3#[cfg(feature = "unstable_protocol_v2")]
4use futures::{StreamExt as _, future};
5#[cfg(feature = "unstable_protocol_v2")]
6use serde::{Serialize, de::DeserializeOwned};
7
8#[cfg(feature = "unstable_protocol_v2")]
9use crate::DynConnectTo;
10use crate::jsonrpc::{Builder, handlers::NullHandler, run::NullRun};
11use crate::role::{HasPeer, RemoteStyle};
12use crate::schema::v1::{InitializeRequest, NewSessionRequest, NewSessionResponse, SessionId};
13#[cfg(feature = "unstable_protocol_v2")]
14use crate::schema::v1::{RequestId, Response as RpcResponse};
15use crate::schema::{InitializeProxyRequest, METHOD_INITIALIZE_PROXY};
16#[cfg(feature = "unstable_protocol_v2")]
17use crate::schema::{ProtocolVersion, v2};
18use crate::util::MatchDispatchFrom;
19#[cfg(feature = "unstable_protocol_v2")]
20use crate::{Channel, RawJsonRpcMessage, RawJsonRpcParams};
21use crate::{ConnectTo, ConnectionTo, Dispatch, HandleDispatchFrom, Handled, Role, RoleId};
22
23#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
27pub struct Client;
28
29impl Role for Client {
30 type Counterpart = Agent;
31
32 fn builder(self) -> Builder<Self> {
33 Builder::new(self).v1_client()
34 }
35
36 async fn default_handle_dispatch_from(
37 &self,
38 message: Dispatch,
39 _connection: ConnectionTo<Client>,
40 ) -> Result<Handled<Dispatch>, crate::Error> {
41 Ok(Handled::No {
42 message,
43 retry: false,
44 })
45 }
46
47 fn role_id(&self) -> RoleId {
48 RoleId::from_singleton(self)
49 }
50
51 fn counterpart(&self) -> Self::Counterpart {
52 Agent
53 }
54}
55
56impl Client {
57 pub fn builder(self) -> Builder<Client, NullHandler, NullRun> {
59 <Self as Role>::builder(self)
60 }
61
62 #[cfg(feature = "unstable_protocol_v2")]
70 pub fn v2(self) -> Builder<Client, NullHandler, NullRun> {
71 self.builder().v2_client()
72 }
73
74 #[cfg(feature = "unstable_protocol_v2")]
87 #[must_use]
88 pub fn protocol_connector(self) -> ClientProtocolConnector {
89 ClientProtocolConnector::new()
90 }
91
92 pub async fn connect_with<R>(
97 self,
98 agent: impl ConnectTo<Client>,
99 main_fn: impl AsyncFnOnce(ConnectionTo<Agent>) -> Result<R, crate::Error>,
100 ) -> Result<R, crate::Error> {
101 self.builder().connect_with(agent, main_fn).await
102 }
103}
104
105#[cfg(feature = "unstable_protocol_v2")]
112#[derive(Debug, Default)]
113pub struct ClientProtocolConnector {
114 v1: Option<DynConnectToFactory<Agent>>,
115 v2: Option<DynConnectToFactory<Agent>>,
116}
117
118#[cfg(feature = "unstable_protocol_v2")]
119impl ClientProtocolConnector {
120 #[must_use]
122 pub fn new() -> Self {
123 Self::default()
124 }
125
126 #[must_use]
128 pub fn with_v1<C>(mut self, client: impl FnMut() -> C + Send + 'static) -> Self
129 where
130 C: ConnectTo<Agent>,
131 {
132 self.v1 = Some(DynConnectToFactory::new(client));
133 self
134 }
135
136 #[must_use]
138 pub fn with_v2<C>(mut self, client: impl FnMut() -> C + Send + 'static) -> Self
139 where
140 C: ConnectTo<Agent>,
141 {
142 self.v2 = Some(DynConnectToFactory::new(client));
143 self
144 }
145
146 pub async fn connect_to<C>(
149 mut self,
150 mut agent: impl FnMut() -> C + Send + 'static,
151 ) -> Result<(), crate::Error>
152 where
153 C: ConnectTo<Client>,
154 {
155 let supported = SupportedClientProtocols {
156 v1: self.v1.is_some(),
157 v2: self.v2.is_some(),
158 };
159 let Some(selected) = supported.highest_configured() else {
160 return Err(crate::Error::invalid_request()
161 .data("client protocol connector has no configured ACP protocol implementations"));
162 };
163
164 match selected {
165 ClientProtocol::V1 => {
166 let client = self
167 .v1
168 .as_mut()
169 .expect("selected protocol is configured")
170 .create();
171 connect_client_protocol(ClientProtocol::V1, client, agent()).await
172 }
173 ClientProtocol::V2 => {
174 let client = self
175 .v2
176 .as_mut()
177 .expect("selected protocol is configured")
178 .create();
179 let agent_connection = RunningProtocolPeer::new(agent());
180 let (client, initialize) =
181 start_client_protocol(ClientProtocol::V2, client).await?;
182 let v2_initialize_as_v1 =
183 normalize_initialize_params_for_agent_protocol(&initialize, AgentProtocol::V1)?;
184 let (client, agent_connection, initialize_response) =
185 send_initialize_and_receive(client, agent_connection, initialize).await?;
186
187 if initialize_response_negotiated_v1(&initialize_response)
188 && let Some(v1) = self.v1.as_mut()
189 {
190 let fallback_client = v1.create();
191 let (fallback_client, fallback_initialize) =
192 start_client_protocol(ClientProtocol::V1, fallback_client).await?;
193 let v1_initialize = normalize_initialize_params_for_agent_protocol(
194 &fallback_initialize,
195 AgentProtocol::V1,
196 )?;
197
198 if v1_initialize == v2_initialize_as_v1 {
199 let fallback_response = initialize_response.with_id(
200 initialize_request_id(&fallback_initialize)
201 .expect("validated initialize request has an id"),
202 );
203 fallback_client.send(fallback_response)?;
204 return pipe_protocol_peers_until_done(fallback_client, agent_connection)
205 .await;
206 }
207
208 drop((client, agent_connection, initialize_response));
209 return connect_client_protocol(ClientProtocol::V1, v1.create(), agent()).await;
210 }
211
212 client.send(initialize_response.into_message())?;
213 pipe_protocol_peers_until_done(client, agent_connection).await
214 }
215 }
216 }
217}
218
219#[cfg(feature = "unstable_protocol_v2")]
220struct DynConnectToFactory<R: Role> {
221 inner: Box<dyn FnMut() -> DynConnectTo<R> + Send>,
222}
223
224#[cfg(feature = "unstable_protocol_v2")]
225impl<R: Role> DynConnectToFactory<R> {
226 fn new<C>(mut factory: impl FnMut() -> C + Send + 'static) -> Self
227 where
228 C: ConnectTo<R>,
229 {
230 Self {
231 inner: Box::new(move || DynConnectTo::new(factory())),
232 }
233 }
234
235 fn create(&mut self) -> DynConnectTo<R> {
236 (self.inner)()
237 }
238}
239
240#[cfg(feature = "unstable_protocol_v2")]
241impl<R: Role> Debug for DynConnectToFactory<R> {
242 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
243 f.debug_struct("DynConnectToFactory")
244 .finish_non_exhaustive()
245 }
246}
247
248impl HasPeer<Client> for Client {
249 fn remote_style(&self, _peer: Client) -> RemoteStyle {
250 RemoteStyle::Counterpart
251 }
252}
253
254#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
259pub struct Agent;
260
261impl Role for Agent {
262 type Counterpart = Client;
263
264 fn builder(self) -> Builder<Self> {
265 Builder::new(self).v1_agent()
266 }
267
268 fn role_id(&self) -> RoleId {
269 RoleId::from_singleton(self)
270 }
271
272 fn counterpart(&self) -> Self::Counterpart {
273 Client
274 }
275
276 async fn default_handle_dispatch_from(
277 &self,
278 message: Dispatch,
279 connection: ConnectionTo<Agent>,
280 ) -> Result<Handled<Dispatch>, crate::Error> {
281 MatchDispatchFrom::new(message, &connection)
282 .if_message_from(Agent, async |message: Dispatch| {
283 let retry = message.has_session_id();
291 Ok(Handled::No { message, retry })
292 })
293 .await
294 .done()
295 }
296}
297
298impl Agent {
299 pub fn builder(self) -> Builder<Agent, NullHandler, NullRun> {
301 <Self as Role>::builder(self)
302 }
303
304 #[cfg(feature = "unstable_protocol_v2")]
311 pub fn v2(self) -> Builder<Agent, NullHandler, NullRun> {
312 self.builder().v2_agent()
313 }
314
315 #[cfg(feature = "unstable_protocol_v2")]
328 #[must_use]
329 pub fn protocol_router(self) -> AgentProtocolRouter {
330 AgentProtocolRouter::new()
331 }
332}
333
334#[cfg(feature = "unstable_protocol_v2")]
340#[derive(Debug, Default)]
341pub struct AgentProtocolRouter {
342 v1: Option<DynConnectTo<Client>>,
343 v2: Option<DynConnectTo<Client>>,
344}
345
346#[cfg(feature = "unstable_protocol_v2")]
347impl AgentProtocolRouter {
348 #[must_use]
350 pub fn new() -> Self {
351 Self::default()
352 }
353
354 #[must_use]
356 pub fn with_v1(mut self, agent: impl ConnectTo<Client>) -> Self {
357 self.v1 = Some(DynConnectTo::new(agent));
358 self
359 }
360
361 #[must_use]
363 pub fn with_v2(mut self, agent: impl ConnectTo<Client>) -> Self {
364 self.v2 = Some(DynConnectTo::new(agent));
365 self
366 }
367}
368
369#[cfg(feature = "unstable_protocol_v2")]
370impl ConnectTo<Client> for AgentProtocolRouter {
371 async fn connect_to(self, client: impl ConnectTo<Agent>) -> Result<(), crate::Error> {
372 let client = RunningProtocolPeer::new(client);
373 let Some((mut first_message, client)) = client.next_message().await? else {
374 return Ok(());
375 };
376 let supported = SupportedAgentProtocols {
377 v1: self.v1.is_some(),
378 v2: self.v2.is_some(),
379 };
380 let selected = match select_agent_protocol(&mut first_message, supported) {
381 Ok(selected) => selected,
382 Err(error) => {
383 return reject_initialize(client, &first_message, error).await;
384 }
385 };
386 let Some(agent) = selected.take_agent(self) else {
387 let error = selected.unsupported_error(supported);
388 return reject_initialize(client, &first_message, error).await;
389 };
390
391 let agent = RunningProtocolPeer::new(agent);
392 agent.send(first_message)?;
393 pipe_protocol_peers_until_closed(client, agent).await
394 }
395}
396
397#[cfg(feature = "unstable_protocol_v2")]
398#[derive(Debug, Clone, Copy, PartialEq, Eq)]
399enum AgentProtocol {
400 V1,
401 V2,
402}
403
404#[cfg(feature = "unstable_protocol_v2")]
405impl AgentProtocol {
406 fn take_agent(self, agent: AgentProtocolRouter) -> Option<DynConnectTo<Client>> {
407 match self {
408 Self::V1 => agent.v1,
409 Self::V2 => agent.v2,
410 }
411 }
412
413 fn name(self) -> &'static str {
414 match self {
415 Self::V1 => "1",
416 Self::V2 => "2",
417 }
418 }
419
420 fn unsupported_error(self, supported: SupportedAgentProtocols) -> crate::Error {
421 crate::Error::invalid_request().data(format!(
422 "ACP protocol version {} is not configured; this endpoint supports {}",
423 self.name(),
424 supported.description()
425 ))
426 }
427}
428
429#[cfg(feature = "unstable_protocol_v2")]
430#[derive(Debug, Clone, Copy, PartialEq, Eq)]
431struct SupportedAgentProtocols {
432 v1: bool,
433 v2: bool,
434}
435
436#[cfg(feature = "unstable_protocol_v2")]
437impl SupportedAgentProtocols {
438 fn highest_compatible(self, requested: ProtocolVersion) -> Option<AgentProtocol> {
439 if self.v2 && requested >= ProtocolVersion::V2 {
440 return Some(AgentProtocol::V2);
441 }
442
443 if self.v1 && requested >= ProtocolVersion::V1 {
444 return Some(AgentProtocol::V1);
445 }
446
447 None
448 }
449
450 fn description(self) -> String {
451 match (self.v1, self.v2) {
452 (true, true) => "ACP protocol versions 1 and 2".into(),
453 (true, false) => "ACP protocol version 1".into(),
454 (false, true) => "ACP protocol version 2".into(),
455 (false, false) => "no ACP protocol versions".into(),
456 }
457 }
458}
459
460#[cfg(feature = "unstable_protocol_v2")]
461fn select_agent_protocol(
462 message: &mut RawJsonRpcMessage,
463 supported: SupportedAgentProtocols,
464) -> Result<AgentProtocol, crate::Error> {
465 let RawJsonRpcMessage::Request(request) = message else {
466 return Err(
467 crate::Error::invalid_request().data("first ACP message must be an initialize request")
468 );
469 };
470
471 if request.method.as_ref() != "initialize" {
472 return Err(crate::Error::invalid_request().data("first ACP request must be initialize"));
473 }
474
475 let Some(RawJsonRpcParams::Object(params)) = &mut request.params else {
476 return Err(invalid_initialize_protocol_version());
477 };
478 let Some(protocol_version) = params.get("protocolVersion") else {
479 return Err(invalid_initialize_protocol_version());
480 };
481
482 let requested = serde_json::from_value::<ProtocolVersion>(protocol_version.clone())
483 .map_err(|_| invalid_initialize_protocol_version())?;
484 let selected = highest_compatible_agent_protocol(requested, supported)?;
485 rewrite_initialize_params(params, requested, selected)?;
486
487 Ok(selected)
488}
489
490#[cfg(feature = "unstable_protocol_v2")]
491fn normalize_initialize_params_for_agent_protocol(
492 message: &RawJsonRpcMessage,
493 selected: AgentProtocol,
494) -> Result<serde_json::Map<String, serde_json::Value>, crate::Error> {
495 let RawJsonRpcMessage::Request(request) = message else {
496 return Err(
497 crate::Error::invalid_request().data("first ACP message must be an initialize request")
498 );
499 };
500
501 if request.method.as_ref() != "initialize" {
502 return Err(crate::Error::invalid_request().data("first ACP request must be initialize"));
503 }
504
505 let Some(RawJsonRpcParams::Object(params)) = &request.params else {
506 return Err(invalid_initialize_protocol_version());
507 };
508 let Some(protocol_version) = params.get("protocolVersion") else {
509 return Err(invalid_initialize_protocol_version());
510 };
511
512 let requested = serde_json::from_value::<ProtocolVersion>(protocol_version.clone())
513 .map_err(|_| invalid_initialize_protocol_version())?;
514 let mut params = params.clone();
515 rewrite_initialize_params(&mut params, requested, selected)?;
516 Ok(params)
517}
518
519#[cfg(feature = "unstable_protocol_v2")]
520fn rewrite_initialize_params(
521 params: &mut serde_json::Map<String, serde_json::Value>,
522 requested: ProtocolVersion,
523 selected: AgentProtocol,
524) -> Result<(), crate::Error> {
525 match selected {
526 AgentProtocol::V1 => {
527 let mut initialize = if requested >= ProtocolVersion::V2 {
528 v2::conversion::v2_to_v1(parse_initialize_params::<v2::InitializeRequest>(params)?)
529 .map_err(invalid_initialize_params)?
530 } else {
531 parse_initialize_params::<InitializeRequest>(params)?
532 };
533 initialize.protocol_version = ProtocolVersion::V1;
534 replace_initialize_params(params, initialize)
535 }
536 AgentProtocol::V2 => {
537 let mut initialize = if requested >= ProtocolVersion::V2 {
538 parse_initialize_params::<v2::InitializeRequest>(params)?
539 } else {
540 v2::conversion::v1_to_v2(parse_initialize_params::<InitializeRequest>(params)?)
541 .map_err(invalid_initialize_params)?
542 };
543 initialize.protocol_version = ProtocolVersion::V2;
544 replace_initialize_params(params, initialize)
545 }
546 }
547}
548
549#[cfg(feature = "unstable_protocol_v2")]
550fn parse_initialize_params<T: DeserializeOwned>(
551 params: &serde_json::Map<String, serde_json::Value>,
552) -> Result<T, crate::Error> {
553 serde_json::from_value(serde_json::Value::Object(params.clone()))
554 .map_err(invalid_initialize_params)
555}
556
557#[cfg(feature = "unstable_protocol_v2")]
558fn replace_initialize_params(
559 params: &mut serde_json::Map<String, serde_json::Value>,
560 initialize: impl Serialize,
561) -> Result<(), crate::Error> {
562 let value = serde_json::to_value(initialize).map_err(crate::Error::into_internal_error)?;
563 let serde_json::Value::Object(object) = value else {
564 return Err(crate::util::internal_error(
565 "initialize params did not serialize to an object",
566 ));
567 };
568 *params = object;
569 Ok(())
570}
571
572#[cfg(feature = "unstable_protocol_v2")]
573fn highest_compatible_agent_protocol(
574 requested: ProtocolVersion,
575 supported: SupportedAgentProtocols,
576) -> Result<AgentProtocol, crate::Error> {
577 supported.highest_compatible(requested).ok_or_else(|| {
578 crate::Error::invalid_request().data(format!(
579 "unsupported ACP protocol version {requested}; this endpoint supports {}",
580 supported.description()
581 ))
582 })
583}
584
585#[cfg(feature = "unstable_protocol_v2")]
586fn invalid_initialize_protocol_version() -> crate::Error {
587 crate::Error::invalid_params()
588 .data("initialize.protocolVersion must be a valid ACP protocol version")
589}
590
591#[cfg(feature = "unstable_protocol_v2")]
592fn invalid_initialize_params(error: impl ToString) -> crate::Error {
593 crate::Error::invalid_params().data(format!("invalid initialize params: {}", error.to_string()))
594}
595
596#[cfg(feature = "unstable_protocol_v2")]
597fn send_initialize_error(
598 tx: &futures::channel::mpsc::UnboundedSender<Result<RawJsonRpcMessage, crate::Error>>,
599 message: &RawJsonRpcMessage,
600 error: crate::Error,
601) -> Result<(), crate::Error> {
602 let id = match message {
603 RawJsonRpcMessage::Request(request) => request.id.clone(),
604 RawJsonRpcMessage::Notification(_) | RawJsonRpcMessage::Response(_) => RequestId::Null,
605 };
606 tx.unbounded_send(Ok(RawJsonRpcMessage::response(id, Err(error))))
607 .map_err(crate::util::internal_error)
608}
609
610#[cfg(feature = "unstable_protocol_v2")]
611async fn reject_initialize(
612 client: RunningProtocolPeer,
613 message: &RawJsonRpcMessage,
614 error: crate::Error,
615) -> Result<(), crate::Error> {
616 let RunningProtocolPeer { mut rx, tx, future } = client;
617 send_initialize_error(&tx, message, error)?;
618 drop(tx);
619
620 let drain_incoming = async move {
621 while let Some(message) = rx.next().await {
622 message?;
623 }
624 Ok(())
625 };
626
627 let ((), ()) = futures::try_join!(future, drain_incoming)?;
628 Ok(())
629}
630
631#[cfg(feature = "unstable_protocol_v2")]
632struct RunningProtocolPeer {
633 rx: futures::channel::mpsc::UnboundedReceiver<Result<RawJsonRpcMessage, crate::Error>>,
634 tx: futures::channel::mpsc::UnboundedSender<Result<RawJsonRpcMessage, crate::Error>>,
635 future: crate::BoxFuture<'static, Result<(), crate::Error>>,
636}
637
638#[cfg(feature = "unstable_protocol_v2")]
639impl RunningProtocolPeer {
640 fn new<R: Role>(component: impl ConnectTo<R>) -> Self {
641 let (Channel { rx, tx }, future) = component.into_channel_and_future();
642 Self { rx, tx, future }
643 }
644
645 async fn next_message(self) -> Result<Option<(RawJsonRpcMessage, Self)>, crate::Error> {
646 let Self { mut rx, tx, future } = self;
647 match future::select(Box::pin(rx.next()), future).await {
648 future::Either::Left((Some(message), future)) => {
649 Ok(Some((message?, Self { rx, tx, future })))
650 }
651 future::Either::Left((None, future)) => {
652 future.await?;
653 Ok(None)
654 }
655 future::Either::Right((result, next_message)) => {
656 result?;
657 drop(next_message);
658 let Some(message) = rx.next().await else {
659 return Ok(None);
660 };
661 Ok(Some((
662 message?,
663 Self {
664 rx,
665 tx,
666 future: Box::pin(future::ready(Ok(()))),
667 },
668 )))
669 }
670 }
671 }
672
673 fn send(&self, message: RawJsonRpcMessage) -> Result<(), crate::Error> {
674 self.tx
675 .unbounded_send(Ok(message))
676 .map_err(crate::util::internal_error)
677 }
678}
679
680#[cfg(feature = "unstable_protocol_v2")]
681async fn pipe_protocol_peers_until_closed(
682 left: RunningProtocolPeer,
683 right: RunningProtocolPeer,
684) -> Result<(), crate::Error> {
685 let ((), (), (), ()) = futures::try_join!(
686 left.future,
687 right.future,
688 Channel {
689 rx: left.rx,
690 tx: right.tx,
691 }
692 .copy(),
693 Channel {
694 rx: right.rx,
695 tx: left.tx,
696 }
697 .copy(),
698 )?;
699
700 Ok(())
701}
702
703#[cfg(feature = "unstable_protocol_v2")]
704async fn pipe_protocol_peers_until_done(
705 left: RunningProtocolPeer,
706 right: RunningProtocolPeer,
707) -> Result<(), crate::Error> {
708 let bridge = Box::pin(async move {
709 let ((), ()) = futures::try_join!(
710 Channel {
711 rx: left.rx,
712 tx: right.tx,
713 }
714 .copy(),
715 Channel {
716 rx: right.rx,
717 tx: left.tx,
718 }
719 .copy(),
720 )?;
721 Ok(())
722 });
723
724 match future::select(left.future, future::select(right.future, bridge)).await {
725 future::Either::Left((result, _))
726 | future::Either::Right((
727 future::Either::Left((result, _)) | future::Either::Right((result, _)),
728 _,
729 )) => result,
730 }
731}
732
733#[cfg(feature = "unstable_protocol_v2")]
734#[derive(Debug)]
735struct InitializeResponse {
736 id: RequestId,
737 result: Result<serde_json::Value, crate::Error>,
738}
739
740#[cfg(feature = "unstable_protocol_v2")]
741impl InitializeResponse {
742 fn from_message(message: RawJsonRpcMessage) -> Result<Self, crate::Error> {
743 match message {
744 RawJsonRpcMessage::Response(RpcResponse::Result { id, result }) => Ok(Self {
745 id,
746 result: Ok(result),
747 }),
748 RawJsonRpcMessage::Response(RpcResponse::Error { id, error }) => Ok(Self {
749 id,
750 result: Err(error),
751 }),
752 message => Err(crate::Error::invalid_request().data(format!(
753 "first ACP response must be an initialize response, got {message:?}",
754 ))),
755 }
756 }
757
758 fn into_message(self) -> RawJsonRpcMessage {
759 RawJsonRpcMessage::response(self.id, self.result)
760 }
761
762 fn with_id(self, id: RequestId) -> RawJsonRpcMessage {
763 RawJsonRpcMessage::response(id, self.result)
764 }
765
766 fn protocol_version(&self) -> Option<ProtocolVersion> {
767 serde_json::from_value(self.result.as_ref().ok()?.get("protocolVersion")?.clone()).ok()
768 }
769}
770
771#[cfg(feature = "unstable_protocol_v2")]
772#[derive(Debug, Clone, Copy, PartialEq, Eq)]
773enum ClientProtocol {
774 V1,
775 V2,
776}
777
778#[cfg(feature = "unstable_protocol_v2")]
779impl ClientProtocol {
780 fn name(self) -> &'static str {
781 match self {
782 Self::V1 => "1",
783 Self::V2 => "2",
784 }
785 }
786}
787
788#[cfg(feature = "unstable_protocol_v2")]
789#[derive(Debug, Clone, Copy, PartialEq, Eq)]
790struct SupportedClientProtocols {
791 v1: bool,
792 v2: bool,
793}
794
795#[cfg(feature = "unstable_protocol_v2")]
796impl SupportedClientProtocols {
797 fn highest_configured(self) -> Option<ClientProtocol> {
798 if self.v2 {
799 return Some(ClientProtocol::V2);
800 }
801
802 if self.v1 {
803 return Some(ClientProtocol::V1);
804 }
805
806 None
807 }
808}
809
810#[cfg(feature = "unstable_protocol_v2")]
811async fn start_client_protocol(
812 protocol: ClientProtocol,
813 client: DynConnectTo<Agent>,
814) -> Result<(RunningProtocolPeer, RawJsonRpcMessage), crate::Error> {
815 let client = RunningProtocolPeer::new(client);
816 let Some((initialize, client)) = client.next_message().await? else {
817 return Err(crate::Error::invalid_request().data(format!(
818 "ACP protocol version {} client implementation ended before initialize",
819 protocol.name()
820 )));
821 };
822 ensure_client_initialize_request(protocol, &initialize)?;
823 Ok((client, initialize))
824}
825
826#[cfg(feature = "unstable_protocol_v2")]
827async fn send_initialize_and_receive(
828 client: RunningProtocolPeer,
829 agent: RunningProtocolPeer,
830 initialize: RawJsonRpcMessage,
831) -> Result<(RunningProtocolPeer, RunningProtocolPeer, InitializeResponse), crate::Error> {
832 agent.send(initialize)?;
833 let Some((response, agent)) = agent.next_message().await? else {
834 return Err(crate::Error::internal_error().data("agent closed before initialize response"));
835 };
836 let response = InitializeResponse::from_message(response)?;
837 Ok((client, agent, response))
838}
839
840#[cfg(feature = "unstable_protocol_v2")]
841async fn initialize_client_protocol(
842 protocol: ClientProtocol,
843 client: DynConnectTo<Agent>,
844 agent: impl ConnectTo<Client>,
845) -> Result<(RunningProtocolPeer, RunningProtocolPeer, InitializeResponse), crate::Error> {
846 let agent = RunningProtocolPeer::new(agent);
847 let (client, initialize) = start_client_protocol(protocol, client).await?;
848 send_initialize_and_receive(client, agent, initialize).await
849}
850
851#[cfg(feature = "unstable_protocol_v2")]
852async fn connect_client_protocol(
853 protocol: ClientProtocol,
854 client: DynConnectTo<Agent>,
855 agent: impl ConnectTo<Client>,
856) -> Result<(), crate::Error> {
857 let (client, agent, initialize_response) =
858 initialize_client_protocol(protocol, client, agent).await?;
859 client.send(initialize_response.into_message())?;
860 pipe_protocol_peers_until_done(client, agent).await
861}
862
863#[cfg(feature = "unstable_protocol_v2")]
864fn ensure_client_initialize_request(
865 protocol: ClientProtocol,
866 message: &RawJsonRpcMessage,
867) -> Result<(), crate::Error> {
868 let RawJsonRpcMessage::Request(request) = message else {
869 return Err(crate::Error::invalid_request().data(format!(
870 "ACP protocol version {} client implementation must send initialize first",
871 protocol.name()
872 )));
873 };
874
875 if request.method.as_ref() != "initialize" {
876 return Err(crate::Error::invalid_request().data(format!(
877 "ACP protocol version {} client implementation must send initialize first",
878 protocol.name()
879 )));
880 }
881
882 Ok(())
883}
884
885#[cfg(feature = "unstable_protocol_v2")]
886fn initialize_request_id(message: &RawJsonRpcMessage) -> Option<RequestId> {
887 let RawJsonRpcMessage::Request(request) = message else {
888 return None;
889 };
890 Some(request.id.clone())
891}
892
893#[cfg(feature = "unstable_protocol_v2")]
894fn initialize_response_negotiated_v1(response: &InitializeResponse) -> bool {
895 response.protocol_version() == Some(ProtocolVersion::V1)
896}
897
898impl HasPeer<Agent> for Agent {
899 fn remote_style(&self, _peer: Agent) -> RemoteStyle {
900 RemoteStyle::Counterpart
901 }
902}
903
904#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
913pub struct Proxy;
914
915impl Role for Proxy {
916 type Counterpart = Conductor;
917
918 async fn default_handle_dispatch_from(
919 &self,
920 message: crate::Dispatch,
921 _connection: crate::ConnectionTo<Self>,
922 ) -> Result<crate::Handled<crate::Dispatch>, crate::Error> {
923 Ok(Handled::No {
924 message,
925 retry: false,
926 })
927 }
928
929 fn role_id(&self) -> RoleId {
930 RoleId::from_singleton(self)
931 }
932
933 fn counterpart(&self) -> Self::Counterpart {
934 Conductor
935 }
936}
937
938impl Proxy {
939 pub fn builder(self) -> Builder<Proxy, NullHandler, NullRun> {
941 Builder::new(self)
942 }
943}
944
945impl HasPeer<Proxy> for Proxy {
946 fn remote_style(&self, _peer: Proxy) -> RemoteStyle {
947 RemoteStyle::Counterpart
948 }
949}
950
951#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
956pub struct Conductor;
957
958impl Role for Conductor {
959 type Counterpart = Proxy;
960
961 fn role_id(&self) -> RoleId {
962 RoleId::from_singleton(self)
963 }
964
965 fn counterpart(&self) -> Self::Counterpart {
966 Proxy
967 }
968
969 async fn default_handle_dispatch_from(
970 &self,
971 message: Dispatch,
972 cx: ConnectionTo<Conductor>,
973 ) -> Result<Handled<Dispatch>, crate::Error> {
974 MatchDispatchFrom::new(message, &cx)
976 .if_request_from(Client, async |_req: InitializeRequest, responder| {
977 responder.respond_with_error(crate::Error::invalid_request().data(format!(
978 "proxies must be initialized with `{METHOD_INITIALIZE_PROXY}`"
979 )))
980 })
981 .await
982 .if_request_from(
985 Client,
986 async |request: InitializeProxyRequest, responder| {
987 let InitializeProxyRequest { initialize } = request;
988 cx.send_request_to(Agent, initialize)
989 .forward_response_to(responder)
990 },
991 )
992 .await
993 .if_request_from(Client, async |request: NewSessionRequest, responder| {
996 let sent = cx.send_request_to(Agent, request);
997 let sent = sent.forward_cancellation_from(responder.cancellation());
1002 sent.on_receiving_result({
1003 let cx = cx.clone();
1004 async move |result| {
1005 if let Ok(NewSessionResponse { session_id, .. }) = &result {
1006 cx.add_dynamic_handler(ProxySessionMessages::new(session_id.clone()))?
1007 .run_indefinitely();
1008 }
1009 responder.respond_with_result(result)
1010 }
1011 })
1012 })
1013 .await
1014 .if_message_from(Client, async |message: Dispatch| {
1016 cx.send_proxied_message_to(Agent, message)
1017 })
1018 .await
1019 .if_message_from(Agent, async |message: Dispatch| {
1021 cx.send_proxied_message_to(Client, message)
1022 })
1023 .await
1024 .done()
1025 }
1026}
1027
1028impl Conductor {
1029 pub fn builder(self) -> Builder<Conductor, NullHandler, NullRun> {
1031 Builder::new(self)
1032 }
1033}
1034
1035impl HasPeer<Client> for Conductor {
1036 fn remote_style(&self, _peer: Client) -> RemoteStyle {
1037 RemoteStyle::Predecessor
1038 }
1039}
1040
1041impl HasPeer<Agent> for Conductor {
1042 fn remote_style(&self, _peer: Agent) -> RemoteStyle {
1043 RemoteStyle::Successor
1044 }
1045}
1046
1047pub(crate) struct ProxySessionMessages {
1052 session_id: SessionId,
1053}
1054
1055impl ProxySessionMessages {
1056 pub fn new(session_id: SessionId) -> Self {
1058 Self { session_id }
1059 }
1060}
1061
1062impl<Counterpart: Role> HandleDispatchFrom<Counterpart> for ProxySessionMessages
1063where
1064 Counterpart: HasPeer<Agent> + HasPeer<Client>,
1065{
1066 async fn handle_dispatch_from(
1067 &mut self,
1068 message: Dispatch,
1069 connection: ConnectionTo<Counterpart>,
1070 ) -> Result<Handled<Dispatch>, crate::Error> {
1071 MatchDispatchFrom::new(message, &connection)
1072 .if_message_from(Agent, async |message| {
1073 if let Some(session_id) = message.get_session_id()?
1075 && session_id == self.session_id
1076 {
1077 connection.send_proxied_message_to(Client, message)?;
1078 return Ok(Handled::Yes);
1079 }
1080
1081 Ok(Handled::No {
1083 message,
1084 retry: false,
1085 })
1086 })
1087 .await
1088 .done()
1089 }
1090
1091 fn describe_chain(&self) -> impl std::fmt::Debug {
1092 format!("ProxySessionMessages({})", self.session_id)
1093 }
1094}