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};
11#[cfg(feature = "unstable_protocol_v2")]
12use crate::jsonrpc::{
13 TransportBatch, TransportBatchEntry, TransportFrame, is_response_only_shape,
14 raw_is_response_only_shape,
15};
16use crate::role::{HasPeer, RemoteStyle};
17use crate::schema::v1::{InitializeRequest, NewSessionRequest, NewSessionResponse, SessionId};
18#[cfg(feature = "unstable_protocol_v2")]
19use crate::schema::v1::{RequestId, Response as RpcResponse};
20use crate::schema::{InitializeProxyRequest, METHOD_INITIALIZE_PROXY};
21#[cfg(feature = "unstable_protocol_v2")]
22use crate::schema::{ProtocolVersion, v2};
23use crate::util::MatchDispatchFrom;
24#[cfg(feature = "unstable_protocol_v2")]
25use crate::{Channel, RawJsonRpcMessage, RawJsonRpcParams};
26use crate::{ConnectTo, ConnectionTo, Dispatch, HandleDispatchFrom, Handled, Role, RoleId};
27
28#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
32pub struct Client;
33
34impl Role for Client {
35 type Counterpart = Agent;
36
37 fn builder(self) -> Builder<Self> {
38 Builder::new(self).v1_client()
39 }
40
41 async fn default_handle_dispatch_from(
42 &self,
43 message: Dispatch,
44 _connection: ConnectionTo<Client>,
45 ) -> Result<Handled<Dispatch>, crate::Error> {
46 Ok(Handled::No {
47 message,
48 retry: false,
49 })
50 }
51
52 fn role_id(&self) -> RoleId {
53 RoleId::from_singleton(self)
54 }
55
56 fn counterpart(&self) -> Self::Counterpart {
57 Agent
58 }
59}
60
61impl Client {
62 pub fn builder(self) -> Builder<Client, NullHandler, NullRun> {
64 <Self as Role>::builder(self)
65 }
66
67 #[cfg(feature = "unstable_protocol_v2")]
75 pub fn v2(self) -> Builder<Client, NullHandler, NullRun> {
76 self.builder().v2_client()
77 }
78
79 #[cfg(feature = "unstable_protocol_v2")]
92 #[must_use]
93 pub fn protocol_connector(self) -> ClientProtocolConnector {
94 ClientProtocolConnector::new()
95 }
96
97 pub async fn connect_with<R>(
102 self,
103 agent: impl ConnectTo<Client>,
104 main_fn: impl AsyncFnOnce(ConnectionTo<Agent>) -> Result<R, crate::Error>,
105 ) -> Result<R, crate::Error> {
106 self.builder().connect_with(agent, main_fn).await
107 }
108}
109
110#[cfg(feature = "unstable_protocol_v2")]
117#[derive(Debug, Default)]
118pub struct ClientProtocolConnector {
119 v1: Option<DynConnectToFactory<Agent>>,
120 v2: Option<DynConnectToFactory<Agent>>,
121}
122
123#[cfg(feature = "unstable_protocol_v2")]
124impl ClientProtocolConnector {
125 #[must_use]
127 pub fn new() -> Self {
128 Self::default()
129 }
130
131 #[must_use]
133 pub fn with_v1<C>(mut self, client: impl FnMut() -> C + Send + 'static) -> Self
134 where
135 C: ConnectTo<Agent>,
136 {
137 self.v1 = Some(DynConnectToFactory::new(client));
138 self
139 }
140
141 #[must_use]
143 pub fn with_v2<C>(mut self, client: impl FnMut() -> C + Send + 'static) -> Self
144 where
145 C: ConnectTo<Agent>,
146 {
147 self.v2 = Some(DynConnectToFactory::new(client));
148 self
149 }
150
151 pub async fn connect_to<C>(
154 mut self,
155 mut agent: impl FnMut() -> C + Send + 'static,
156 ) -> Result<(), crate::Error>
157 where
158 C: ConnectTo<Client>,
159 {
160 let supported = SupportedClientProtocols {
161 v1: self.v1.is_some(),
162 v2: self.v2.is_some(),
163 };
164 let Some(selected) = supported.highest_configured() else {
165 return Err(crate::Error::invalid_request()
166 .data("client protocol connector has no configured ACP protocol implementations"));
167 };
168
169 match selected {
170 ClientProtocol::V1 => {
171 let client = self
172 .v1
173 .as_mut()
174 .expect("selected protocol is configured")
175 .create();
176 connect_client_protocol(ClientProtocol::V1, client, agent()).await
177 }
178 ClientProtocol::V2 => {
179 let client = self
180 .v2
181 .as_mut()
182 .expect("selected protocol is configured")
183 .create();
184 let agent_connection = RunningProtocolPeer::new(agent());
185 let (client, initialize) =
186 start_client_protocol(ClientProtocol::V2, client).await?;
187 let v2_initialize_as_v1 =
188 normalize_initialize_params_for_agent_protocol(&initialize, AgentProtocol::V1)?;
189 let (client, agent_connection, initialize_response) =
190 send_initialize_and_receive(client, agent_connection, initialize).await?;
191
192 if initialize_response_negotiated_v1(&initialize_response)
193 && let Some(v1) = self.v1.as_mut()
194 {
195 let fallback_client = v1.create();
196 let (fallback_client, fallback_initialize) =
197 start_client_protocol(ClientProtocol::V1, fallback_client).await?;
198 let v1_initialize = normalize_initialize_params_for_agent_protocol(
199 &fallback_initialize,
200 AgentProtocol::V1,
201 )?;
202
203 if v1_initialize == v2_initialize_as_v1 {
204 let fallback_response = initialize_response.with_id(
205 initialize_request_id(&fallback_initialize)
206 .expect("validated initialize request has an id"),
207 );
208 drop(client);
213 fallback_client.send(fallback_response)?;
214 return pipe_protocol_peers_until_done(fallback_client, agent_connection)
215 .await;
216 }
217
218 drop((
222 client,
223 fallback_client,
224 agent_connection,
225 initialize_response,
226 ));
227 return connect_client_protocol(ClientProtocol::V1, v1.create(), agent()).await;
228 }
229
230 client.send(initialize_response.into_message())?;
231 pipe_protocol_peers_until_done(client, agent_connection).await
232 }
233 }
234 }
235}
236
237#[cfg(feature = "unstable_protocol_v2")]
238struct DynConnectToFactory<R: Role> {
239 inner: Box<dyn FnMut() -> DynConnectTo<R> + Send>,
240}
241
242#[cfg(feature = "unstable_protocol_v2")]
243impl<R: Role> DynConnectToFactory<R> {
244 fn new<C>(mut factory: impl FnMut() -> C + Send + 'static) -> Self
245 where
246 C: ConnectTo<R>,
247 {
248 Self {
249 inner: Box::new(move || DynConnectTo::new(factory())),
250 }
251 }
252
253 fn create(&mut self) -> DynConnectTo<R> {
254 (self.inner)()
255 }
256}
257
258#[cfg(feature = "unstable_protocol_v2")]
259impl<R: Role> Debug for DynConnectToFactory<R> {
260 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
261 f.debug_struct("DynConnectToFactory")
262 .finish_non_exhaustive()
263 }
264}
265
266impl HasPeer<Client> for Client {
267 fn remote_style(&self, _peer: Client) -> RemoteStyle {
268 RemoteStyle::Counterpart
269 }
270}
271
272#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
277pub struct Agent;
278
279impl Role for Agent {
280 type Counterpart = Client;
281
282 fn builder(self) -> Builder<Self> {
283 Builder::new(self).v1_agent()
284 }
285
286 fn role_id(&self) -> RoleId {
287 RoleId::from_singleton(self)
288 }
289
290 fn counterpart(&self) -> Self::Counterpart {
291 Client
292 }
293
294 async fn default_handle_dispatch_from(
295 &self,
296 message: Dispatch,
297 connection: ConnectionTo<Agent>,
298 ) -> Result<Handled<Dispatch>, crate::Error> {
299 MatchDispatchFrom::new(message, &connection)
300 .if_dispatch_from(Agent, async |message: Dispatch| {
301 let retry = message.has_session_id();
309 Ok(Handled::No { message, retry })
310 })
311 .await
312 .done()
313 }
314}
315
316impl Agent {
317 pub fn builder(self) -> Builder<Agent, NullHandler, NullRun> {
319 <Self as Role>::builder(self)
320 }
321
322 #[cfg(feature = "unstable_protocol_v2")]
329 pub fn v2(self) -> Builder<Agent, NullHandler, NullRun> {
330 self.builder().v2_agent()
331 }
332
333 #[cfg(feature = "unstable_protocol_v2")]
346 #[must_use]
347 pub fn protocol_router(self) -> AgentProtocolRouter {
348 AgentProtocolRouter::new()
349 }
350}
351
352#[cfg(feature = "unstable_protocol_v2")]
358#[derive(Debug, Default)]
359pub struct AgentProtocolRouter {
360 v1: Option<DynConnectTo<Client>>,
361 v2: Option<DynConnectTo<Client>>,
362}
363
364#[cfg(feature = "unstable_protocol_v2")]
365impl AgentProtocolRouter {
366 #[must_use]
368 pub fn new() -> Self {
369 Self::default()
370 }
371
372 #[must_use]
374 pub fn with_v1(mut self, agent: impl ConnectTo<Client>) -> Self {
375 self.v1 = Some(DynConnectTo::new(agent));
376 self
377 }
378
379 #[must_use]
381 pub fn with_v2(mut self, agent: impl ConnectTo<Client>) -> Self {
382 self.v2 = Some(DynConnectTo::new(agent));
383 self
384 }
385}
386
387#[cfg(feature = "unstable_protocol_v2")]
388impl ConnectTo<Client> for AgentProtocolRouter {
389 async fn connect_to(self, client: impl ConnectTo<Agent>) -> Result<(), crate::Error> {
390 let supported = SupportedAgentProtocols {
391 v1: self.v1.is_some(),
392 v2: self.v2.is_some(),
393 };
394 let mut client = RunningProtocolPeer::new(client);
395 let (first_frame, client, selected) = loop {
396 let Some((mut frame, next_client)) = client.next_frame().await? else {
397 return Ok(());
398 };
399 let message = match initialize_message_mut(&mut frame) {
400 Ok(Some(message)) => message,
401 Ok(None) => {
402 client = next_client;
403 continue;
404 }
405 Err(error) => return reject_initialize(next_client, &frame, error).await,
406 };
407 let selected = match select_agent_protocol(message, supported) {
408 Ok(selected) => selected,
409 Err(error) => return reject_initialize(next_client, &frame, error).await,
410 };
411 break (frame, next_client, selected);
412 };
413 let Some(agent) = selected.take_agent(self) else {
414 let error = selected.unsupported_error(supported);
415 return reject_initialize(client, &first_frame, error).await;
416 };
417
418 let agent = RunningProtocolPeer::new(agent);
419 agent.send_frame(first_frame)?;
420 pipe_protocol_peers_until_closed(client, agent).await
421 }
422}
423
424#[cfg(feature = "unstable_protocol_v2")]
425#[derive(Debug, Clone, Copy, PartialEq, Eq)]
426enum AgentProtocol {
427 V1,
428 V2,
429}
430
431#[cfg(feature = "unstable_protocol_v2")]
432impl AgentProtocol {
433 fn take_agent(self, agent: AgentProtocolRouter) -> Option<DynConnectTo<Client>> {
434 match self {
435 Self::V1 => agent.v1,
436 Self::V2 => agent.v2,
437 }
438 }
439
440 fn name(self) -> &'static str {
441 match self {
442 Self::V1 => "1",
443 Self::V2 => "2",
444 }
445 }
446
447 fn unsupported_error(self, supported: SupportedAgentProtocols) -> crate::Error {
448 crate::Error::invalid_request().data(format!(
449 "ACP protocol version {} is not configured; this endpoint supports {}",
450 self.name(),
451 supported.description()
452 ))
453 }
454}
455
456#[cfg(feature = "unstable_protocol_v2")]
457#[derive(Debug, Clone, Copy, PartialEq, Eq)]
458struct SupportedAgentProtocols {
459 v1: bool,
460 v2: bool,
461}
462
463#[cfg(feature = "unstable_protocol_v2")]
464impl SupportedAgentProtocols {
465 fn highest_compatible(self, requested: ProtocolVersion) -> Option<AgentProtocol> {
466 if self.v2 && requested >= ProtocolVersion::V2 {
467 return Some(AgentProtocol::V2);
468 }
469
470 if self.v1 && requested >= ProtocolVersion::V1 {
471 return Some(AgentProtocol::V1);
472 }
473
474 None
475 }
476
477 fn description(self) -> String {
478 match (self.v1, self.v2) {
479 (true, true) => "ACP protocol versions 1 and 2".into(),
480 (true, false) => "ACP protocol version 1".into(),
481 (false, true) => "ACP protocol version 2".into(),
482 (false, false) => "no ACP protocol versions".into(),
483 }
484 }
485}
486
487#[cfg(feature = "unstable_protocol_v2")]
488fn select_agent_protocol(
489 message: &mut RawJsonRpcMessage,
490 supported: SupportedAgentProtocols,
491) -> Result<AgentProtocol, crate::Error> {
492 let RawJsonRpcMessage::Request(request) = message else {
493 return Err(
494 crate::Error::invalid_request().data("first ACP message must be an initialize request")
495 );
496 };
497
498 if request.method.as_ref() != "initialize" {
499 return Err(crate::Error::invalid_request().data("first ACP request must be initialize"));
500 }
501
502 let Some(RawJsonRpcParams::Object(params)) = &mut request.params else {
503 return Err(invalid_initialize_protocol_version());
504 };
505 let Some(protocol_version) = params.get("protocolVersion") else {
506 return Err(invalid_initialize_protocol_version());
507 };
508
509 let requested = serde_json::from_value::<ProtocolVersion>(protocol_version.clone())
510 .map_err(|_| invalid_initialize_protocol_version())?;
511 let selected = highest_compatible_agent_protocol(requested, supported)?;
512 rewrite_initialize_params(params, requested, selected)?;
513
514 Ok(selected)
515}
516
517#[cfg(feature = "unstable_protocol_v2")]
518fn normalize_initialize_params_for_agent_protocol(
519 message: &RawJsonRpcMessage,
520 selected: AgentProtocol,
521) -> Result<serde_json::Map<String, serde_json::Value>, crate::Error> {
522 let RawJsonRpcMessage::Request(request) = message else {
523 return Err(
524 crate::Error::invalid_request().data("first ACP message must be an initialize request")
525 );
526 };
527
528 if request.method.as_ref() != "initialize" {
529 return Err(crate::Error::invalid_request().data("first ACP request must be initialize"));
530 }
531
532 let Some(RawJsonRpcParams::Object(params)) = &request.params else {
533 return Err(invalid_initialize_protocol_version());
534 };
535 let Some(protocol_version) = params.get("protocolVersion") else {
536 return Err(invalid_initialize_protocol_version());
537 };
538
539 let requested = serde_json::from_value::<ProtocolVersion>(protocol_version.clone())
540 .map_err(|_| invalid_initialize_protocol_version())?;
541 let mut params = params.clone();
542 rewrite_initialize_params(&mut params, requested, selected)?;
543 Ok(params)
544}
545
546#[cfg(feature = "unstable_protocol_v2")]
547fn rewrite_initialize_params(
548 params: &mut serde_json::Map<String, serde_json::Value>,
549 requested: ProtocolVersion,
550 selected: AgentProtocol,
551) -> Result<(), crate::Error> {
552 match selected {
553 AgentProtocol::V1 => {
554 let mut initialize = if requested >= ProtocolVersion::V2 {
555 v2::conversion::try_v2_to_v1(parse_initialize_params::<v2::InitializeRequest>(
556 params,
557 )?)
558 .map_err(invalid_initialize_params)?
559 } else {
560 parse_initialize_params::<InitializeRequest>(params)?
561 };
562 initialize.protocol_version = ProtocolVersion::V1;
563 replace_initialize_params(params, initialize)
564 }
565 AgentProtocol::V2 => {
566 let mut initialize = if requested >= ProtocolVersion::V2 {
567 parse_initialize_params::<v2::InitializeRequest>(params)?
568 } else {
569 v2::conversion::try_v1_to_v2(parse_initialize_params::<InitializeRequest>(params)?)
570 .map_err(invalid_initialize_params)?
571 };
572 initialize.protocol_version = ProtocolVersion::V2;
573 replace_initialize_params(params, initialize)
574 }
575 }
576}
577
578#[cfg(feature = "unstable_protocol_v2")]
579fn parse_initialize_params<T: DeserializeOwned>(
580 params: &serde_json::Map<String, serde_json::Value>,
581) -> Result<T, crate::Error> {
582 serde_json::from_value(serde_json::Value::Object(params.clone()))
583 .map_err(invalid_initialize_params)
584}
585
586#[cfg(feature = "unstable_protocol_v2")]
587fn replace_initialize_params(
588 params: &mut serde_json::Map<String, serde_json::Value>,
589 initialize: impl Serialize,
590) -> Result<(), crate::Error> {
591 let value = serde_json::to_value(initialize).map_err(crate::Error::into_internal_error)?;
592 let serde_json::Value::Object(object) = value else {
593 return Err(crate::util::internal_error(
594 "initialize params did not serialize to an object",
595 ));
596 };
597 *params = object;
598 Ok(())
599}
600
601#[cfg(feature = "unstable_protocol_v2")]
602fn highest_compatible_agent_protocol(
603 requested: ProtocolVersion,
604 supported: SupportedAgentProtocols,
605) -> Result<AgentProtocol, crate::Error> {
606 supported.highest_compatible(requested).ok_or_else(|| {
607 crate::Error::invalid_request().data(format!(
608 "unsupported ACP protocol version {requested}; this endpoint supports {}",
609 supported.description()
610 ))
611 })
612}
613
614#[cfg(feature = "unstable_protocol_v2")]
615fn invalid_initialize_protocol_version() -> crate::Error {
616 crate::Error::invalid_params()
617 .data("initialize.protocolVersion must be a valid ACP protocol version")
618}
619
620#[cfg(feature = "unstable_protocol_v2")]
621fn invalid_initialize_params(error: impl ToString) -> crate::Error {
622 crate::Error::invalid_params().data(format!("invalid initialize params: {}", error.to_string()))
623}
624
625#[cfg(feature = "unstable_protocol_v2")]
626fn send_initialize_error(
627 tx: &futures::channel::mpsc::UnboundedSender<TransportFrame>,
628 frame: &TransportFrame,
629 error: crate::Error,
630) -> Result<(), crate::Error> {
631 fn response_for_message(
632 entry: &RawJsonRpcMessage,
633 initialize_error: &crate::Error,
634 ) -> Option<RawJsonRpcMessage> {
635 match entry {
636 RawJsonRpcMessage::Request(request) => Some(RawJsonRpcMessage::response(
637 request.id.clone(),
638 Err(initialize_error.clone()),
639 )),
640 RawJsonRpcMessage::Notification(_) | RawJsonRpcMessage::Response(_) => None,
641 }
642 }
643
644 fn response_for_entry(
645 entry: &TransportBatchEntry,
646 initialize_error: &crate::Error,
647 ) -> Option<RawJsonRpcMessage> {
648 match entry {
649 TransportBatchEntry::Message(message) => {
650 response_for_message(message, initialize_error)
651 }
652 TransportBatchEntry::Malformed { raw, error } if !is_response_only_shape(raw) => Some(
653 RawJsonRpcMessage::response(RequestId::Null, Err(error.clone())),
654 ),
655 TransportBatchEntry::Malformed { .. } => None,
656 }
657 }
658
659 let response = match frame {
660 TransportFrame::Single(entry) => {
661 let Some(response) = response_for_message(entry, &error) else {
662 return Ok(());
663 };
664 TransportFrame::Single(response)
665 }
666 TransportFrame::Malformed { raw, error } if !raw_is_response_only_shape(raw) => {
667 TransportFrame::Single(RawJsonRpcMessage::response(
668 RequestId::Null,
669 Err(error.clone()),
670 ))
671 }
672 TransportFrame::Malformed { .. } => return Ok(()),
673 TransportFrame::Batch(batch) => {
674 let responses = batch
675 .entries()
676 .filter_map(|entry| response_for_entry(entry, &error))
677 .collect::<Vec<_>>();
678 let Some(responses) = TransportBatch::from_messages(responses) else {
679 return Ok(());
680 };
681 TransportFrame::Batch(responses)
682 }
683 };
684
685 tx.unbounded_send(response)
686 .map_err(crate::util::internal_error)
687}
688
689#[cfg(feature = "unstable_protocol_v2")]
690async fn reject_initialize(
691 client: RunningProtocolPeer,
692 frame: &TransportFrame,
693 error: crate::Error,
694) -> Result<(), crate::Error> {
695 let RunningProtocolPeer { mut rx, tx, future } = client;
696 send_initialize_error(&tx, frame, error)?;
697 drop(tx);
698
699 let drain_incoming = async move {
700 while rx.next().await.is_some() {}
704 Ok::<_, crate::Error>(())
705 };
706
707 let ((), ()) = futures::try_join!(future, drain_incoming)?;
708 Ok(())
709}
710
711#[cfg(feature = "unstable_protocol_v2")]
712struct RunningProtocolPeer {
713 rx: futures::channel::mpsc::UnboundedReceiver<TransportFrame>,
714 tx: futures::channel::mpsc::UnboundedSender<TransportFrame>,
715 future: crate::BoxFuture<'static, Result<(), crate::Error>>,
716}
717
718#[cfg(feature = "unstable_protocol_v2")]
719impl RunningProtocolPeer {
720 fn new<R: Role>(component: impl ConnectTo<R>) -> Self {
721 let (Channel { rx, tx }, future) = component.into_channel_and_future();
722 Self { rx, tx, future }
723 }
724
725 async fn next_frame(self) -> Result<Option<(TransportFrame, Self)>, crate::Error> {
726 let Self { mut rx, tx, future } = self;
727 match future::select(Box::pin(rx.next()), future).await {
728 future::Either::Left((Some(frame), future)) => {
729 Ok(Some((frame, Self { rx, tx, future })))
730 }
731 future::Either::Left((None, future)) => {
732 future.await?;
733 Ok(None)
734 }
735 future::Either::Right((result, next_message)) => {
736 result?;
737 drop(next_message);
738 let Some(frame) = rx.next().await else {
739 return Ok(None);
740 };
741 Ok(Some((
742 frame,
743 Self {
744 rx,
745 tx,
746 future: Box::pin(future::ready(Ok(()))),
747 },
748 )))
749 }
750 }
751 }
752
753 async fn next_message(self) -> Result<Option<(RawJsonRpcMessage, Self)>, crate::Error> {
754 let Some((frame, peer)) = self.next_frame().await? else {
755 return Ok(None);
756 };
757 Ok(Some((initialize_message(frame)?, peer)))
758 }
759
760 fn send(&self, message: RawJsonRpcMessage) -> Result<(), crate::Error> {
761 self.send_frame(TransportFrame::Single(message))
762 }
763
764 fn send_frame(&self, frame: TransportFrame) -> Result<(), crate::Error> {
765 self.tx
766 .unbounded_send(frame)
767 .map_err(crate::util::internal_error)
768 }
769}
770
771#[cfg(feature = "unstable_protocol_v2")]
772fn initialize_message(frame: TransportFrame) -> Result<RawJsonRpcMessage, crate::Error> {
773 match frame {
774 TransportFrame::Single(message) => Ok(message),
775 TransportFrame::Malformed { error, .. } => Err(error),
776 TransportFrame::Batch(_) => Err(crate::Error::invalid_request()
777 .data("ACP initialize request and response messages must be sent individually")),
778 }
779}
780
781#[cfg(feature = "unstable_protocol_v2")]
782fn initialize_message_mut(
783 frame: &mut TransportFrame,
784) -> Result<Option<&mut RawJsonRpcMessage>, crate::Error> {
785 match frame {
786 TransportFrame::Single(RawJsonRpcMessage::Response(_)) => Ok(None),
787 TransportFrame::Single(entry) => Ok(Some(entry)),
788 TransportFrame::Malformed { raw, .. } if raw_is_response_only_shape(raw) => Ok(None),
789 TransportFrame::Malformed { error, .. } => Err(error.clone()),
790 TransportFrame::Batch(batch) => {
791 for entry in batch.entries_mut() {
792 match entry {
793 TransportBatchEntry::Message(RawJsonRpcMessage::Response(_)) => {}
794 TransportBatchEntry::Message(message) => return Ok(Some(message)),
795 TransportBatchEntry::Malformed { raw, .. } if is_response_only_shape(raw) => {}
796 TransportBatchEntry::Malformed { error, .. } => return Err(error.clone()),
797 }
798 }
799 Ok(None)
800 }
801 }
802}
803
804#[cfg(feature = "unstable_protocol_v2")]
805async fn pipe_protocol_peers_until_closed(
806 left: RunningProtocolPeer,
807 right: RunningProtocolPeer,
808) -> Result<(), crate::Error> {
809 let ((), (), (), ()) = futures::try_join!(
810 left.future,
811 right.future,
812 Channel {
813 rx: left.rx,
814 tx: right.tx,
815 }
816 .copy(),
817 Channel {
818 rx: right.rx,
819 tx: left.tx,
820 }
821 .copy(),
822 )?;
823
824 Ok(())
825}
826
827#[cfg(feature = "unstable_protocol_v2")]
828async fn pipe_protocol_peers_until_done(
829 left: RunningProtocolPeer,
830 right: RunningProtocolPeer,
831) -> Result<(), crate::Error> {
832 let bridge = Box::pin(async move {
833 let ((), ()) = futures::try_join!(
834 Channel {
835 rx: left.rx,
836 tx: right.tx,
837 }
838 .copy(),
839 Channel {
840 rx: right.rx,
841 tx: left.tx,
842 }
843 .copy(),
844 )?;
845 Ok(())
846 });
847
848 match future::select(left.future, future::select(right.future, bridge)).await {
849 future::Either::Left((result, _))
850 | future::Either::Right((
851 future::Either::Left((result, _)) | future::Either::Right((result, _)),
852 _,
853 )) => result,
854 }
855}
856
857#[cfg(feature = "unstable_protocol_v2")]
858#[derive(Debug)]
859struct InitializeResponse {
860 id: RequestId,
861 result: Result<serde_json::Value, crate::Error>,
862}
863
864#[cfg(feature = "unstable_protocol_v2")]
865impl InitializeResponse {
866 fn from_message(message: RawJsonRpcMessage) -> Result<Self, crate::Error> {
867 match message {
868 RawJsonRpcMessage::Response(RpcResponse::Result { id, result }) => Ok(Self {
869 id,
870 result: Ok(result),
871 }),
872 RawJsonRpcMessage::Response(RpcResponse::Error { id, error }) => Ok(Self {
873 id,
874 result: Err(error),
875 }),
876 message => Err(crate::Error::invalid_request().data(format!(
877 "first ACP response must be an initialize response, got {message:?}",
878 ))),
879 }
880 }
881
882 fn into_message(self) -> RawJsonRpcMessage {
883 RawJsonRpcMessage::response(self.id, self.result)
884 }
885
886 fn with_id(self, id: RequestId) -> RawJsonRpcMessage {
887 RawJsonRpcMessage::response(id, self.result)
888 }
889
890 fn protocol_version(&self) -> Option<ProtocolVersion> {
891 serde_json::from_value(self.result.as_ref().ok()?.get("protocolVersion")?.clone()).ok()
892 }
893}
894
895#[cfg(feature = "unstable_protocol_v2")]
896#[derive(Debug, Clone, Copy, PartialEq, Eq)]
897enum ClientProtocol {
898 V1,
899 V2,
900}
901
902#[cfg(feature = "unstable_protocol_v2")]
903impl ClientProtocol {
904 fn name(self) -> &'static str {
905 match self {
906 Self::V1 => "1",
907 Self::V2 => "2",
908 }
909 }
910}
911
912#[cfg(feature = "unstable_protocol_v2")]
913#[derive(Debug, Clone, Copy, PartialEq, Eq)]
914struct SupportedClientProtocols {
915 v1: bool,
916 v2: bool,
917}
918
919#[cfg(feature = "unstable_protocol_v2")]
920impl SupportedClientProtocols {
921 fn highest_configured(self) -> Option<ClientProtocol> {
922 if self.v2 {
923 return Some(ClientProtocol::V2);
924 }
925
926 if self.v1 {
927 return Some(ClientProtocol::V1);
928 }
929
930 None
931 }
932}
933
934#[cfg(feature = "unstable_protocol_v2")]
935async fn start_client_protocol(
936 protocol: ClientProtocol,
937 client: DynConnectTo<Agent>,
938) -> Result<(RunningProtocolPeer, RawJsonRpcMessage), crate::Error> {
939 let client = RunningProtocolPeer::new(client);
940 let Some((initialize, client)) = client.next_message().await? else {
941 return Err(crate::Error::invalid_request().data(format!(
942 "ACP protocol version {} client implementation ended before initialize",
943 protocol.name()
944 )));
945 };
946 ensure_client_initialize_request(protocol, &initialize)?;
947 Ok((client, initialize))
948}
949
950#[cfg(feature = "unstable_protocol_v2")]
951async fn send_initialize_and_receive(
952 client: RunningProtocolPeer,
953 agent: RunningProtocolPeer,
954 initialize: RawJsonRpcMessage,
955) -> Result<(RunningProtocolPeer, RunningProtocolPeer, InitializeResponse), crate::Error> {
956 agent.send(initialize)?;
957 let Some((response, agent)) = agent.next_message().await? else {
958 return Err(crate::Error::internal_error().data("agent closed before initialize response"));
959 };
960 let response = InitializeResponse::from_message(response)?;
961 Ok((client, agent, response))
962}
963
964#[cfg(feature = "unstable_protocol_v2")]
965async fn initialize_client_protocol(
966 protocol: ClientProtocol,
967 client: DynConnectTo<Agent>,
968 agent: impl ConnectTo<Client>,
969) -> Result<(RunningProtocolPeer, RunningProtocolPeer, InitializeResponse), crate::Error> {
970 let agent = RunningProtocolPeer::new(agent);
971 let (client, initialize) = start_client_protocol(protocol, client).await?;
972 send_initialize_and_receive(client, agent, initialize).await
973}
974
975#[cfg(feature = "unstable_protocol_v2")]
976async fn connect_client_protocol(
977 protocol: ClientProtocol,
978 client: DynConnectTo<Agent>,
979 agent: impl ConnectTo<Client>,
980) -> Result<(), crate::Error> {
981 let (client, agent, initialize_response) =
982 initialize_client_protocol(protocol, client, agent).await?;
983 client.send(initialize_response.into_message())?;
984 pipe_protocol_peers_until_done(client, agent).await
985}
986
987#[cfg(feature = "unstable_protocol_v2")]
988fn ensure_client_initialize_request(
989 protocol: ClientProtocol,
990 message: &RawJsonRpcMessage,
991) -> Result<(), crate::Error> {
992 let RawJsonRpcMessage::Request(request) = message else {
993 return Err(crate::Error::invalid_request().data(format!(
994 "ACP protocol version {} client implementation must send initialize first",
995 protocol.name()
996 )));
997 };
998
999 if request.method.as_ref() != "initialize" {
1000 return Err(crate::Error::invalid_request().data(format!(
1001 "ACP protocol version {} client implementation must send initialize first",
1002 protocol.name()
1003 )));
1004 }
1005
1006 Ok(())
1007}
1008
1009#[cfg(feature = "unstable_protocol_v2")]
1010fn initialize_request_id(message: &RawJsonRpcMessage) -> Option<RequestId> {
1011 let RawJsonRpcMessage::Request(request) = message else {
1012 return None;
1013 };
1014 Some(request.id.clone())
1015}
1016
1017#[cfg(feature = "unstable_protocol_v2")]
1018fn initialize_response_negotiated_v1(response: &InitializeResponse) -> bool {
1019 response.protocol_version() == Some(ProtocolVersion::V1)
1020}
1021
1022impl HasPeer<Agent> for Agent {
1023 fn remote_style(&self, _peer: Agent) -> RemoteStyle {
1024 RemoteStyle::Counterpart
1025 }
1026}
1027
1028#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1037pub struct Proxy;
1038
1039impl Role for Proxy {
1040 type Counterpart = Conductor;
1041
1042 async fn default_handle_dispatch_from(
1043 &self,
1044 message: crate::Dispatch,
1045 _connection: crate::ConnectionTo<Self>,
1046 ) -> Result<crate::Handled<crate::Dispatch>, crate::Error> {
1047 Ok(Handled::No {
1048 message,
1049 retry: false,
1050 })
1051 }
1052
1053 fn role_id(&self) -> RoleId {
1054 RoleId::from_singleton(self)
1055 }
1056
1057 fn counterpart(&self) -> Self::Counterpart {
1058 Conductor
1059 }
1060}
1061
1062impl Proxy {
1063 pub fn builder(self) -> Builder<Proxy, NullHandler, NullRun> {
1065 Builder::new(self)
1066 }
1067}
1068
1069impl HasPeer<Proxy> for Proxy {
1070 fn remote_style(&self, _peer: Proxy) -> RemoteStyle {
1071 RemoteStyle::Counterpart
1072 }
1073}
1074
1075#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1080pub struct Conductor;
1081
1082impl Role for Conductor {
1083 type Counterpart = Proxy;
1084
1085 fn role_id(&self) -> RoleId {
1086 RoleId::from_singleton(self)
1087 }
1088
1089 fn counterpart(&self) -> Self::Counterpart {
1090 Proxy
1091 }
1092
1093 async fn default_handle_dispatch_from(
1094 &self,
1095 message: Dispatch,
1096 cx: ConnectionTo<Conductor>,
1097 ) -> Result<Handled<Dispatch>, crate::Error> {
1098 MatchDispatchFrom::new(message, &cx)
1100 .if_request_from(Client, async |_req: InitializeRequest, responder| {
1101 responder.respond_with_error(crate::Error::invalid_request().data(format!(
1102 "proxies must be initialized with `{METHOD_INITIALIZE_PROXY}`"
1103 )))
1104 })
1105 .await
1106 .if_request_from(
1109 Client,
1110 async |request: InitializeProxyRequest, responder| {
1111 let InitializeProxyRequest { initialize } = request;
1112 cx.send_request_to(Agent, initialize)
1113 .forward_response_to(responder)
1114 },
1115 )
1116 .await
1117 .if_request_from(Client, async |request: NewSessionRequest, responder| {
1120 let sent = cx.send_request_to(Agent, request);
1121 let sent = sent.forward_cancellation_from(responder.cancellation());
1126 sent.on_receiving_result({
1127 let cx = cx.clone();
1128 async move |result| {
1129 if let Ok(NewSessionResponse { session_id, .. }) = &result {
1130 cx.add_dynamic_handler(ProxySessionMessages::new(session_id.clone()))?
1131 .detach();
1132 }
1133 responder.respond_with_result(result)
1134 }
1135 })
1136 })
1137 .await
1138 .if_dispatch_from(Client, async |message: Dispatch| {
1140 cx.send_proxied_message_to(Agent, message)
1141 })
1142 .await
1143 .if_dispatch_from(Agent, async |message: Dispatch| {
1145 cx.send_proxied_message_to(Client, message)
1146 })
1147 .await
1148 .done()
1149 }
1150}
1151
1152impl Conductor {
1153 pub fn builder(self) -> Builder<Conductor, NullHandler, NullRun> {
1155 Builder::new(self)
1156 }
1157}
1158
1159impl HasPeer<Client> for Conductor {
1160 fn remote_style(&self, _peer: Client) -> RemoteStyle {
1161 RemoteStyle::Predecessor
1162 }
1163}
1164
1165impl HasPeer<Agent> for Conductor {
1166 fn remote_style(&self, _peer: Agent) -> RemoteStyle {
1167 RemoteStyle::Successor
1168 }
1169}
1170
1171pub(crate) struct ProxySessionMessages {
1176 session_id: SessionId,
1177}
1178
1179impl ProxySessionMessages {
1180 pub fn new(session_id: SessionId) -> Self {
1182 Self { session_id }
1183 }
1184}
1185
1186impl<Counterpart: Role> HandleDispatchFrom<Counterpart> for ProxySessionMessages
1187where
1188 Counterpart: HasPeer<Agent> + HasPeer<Client>,
1189{
1190 async fn handle_dispatch_from(
1191 &mut self,
1192 message: Dispatch,
1193 connection: ConnectionTo<Counterpart>,
1194 ) -> Result<Handled<Dispatch>, crate::Error> {
1195 MatchDispatchFrom::new(message, &connection)
1196 .if_dispatch_from(Agent, async |message| {
1197 if let Some(session_id) = message.get_session_id()?
1199 && session_id == self.session_id
1200 {
1201 connection.send_proxied_message_to(Client, message)?;
1202 return Ok(Handled::Yes);
1203 }
1204
1205 Ok(Handled::No {
1207 message,
1208 retry: false,
1209 })
1210 })
1211 .await
1212 .done()
1213 }
1214
1215 fn describe_chain(&self) -> impl std::fmt::Debug {
1216 format!("ProxySessionMessages({})", self.session_id)
1217 }
1218}