aether_cli/acp/
testing.rs1use super::handlers::acp_agent_builder;
2use super::relay::spawn_relay;
3use super::session::Session;
4use super::session_manager::{InitialSessionSelection, SessionManager, SessionManagerConfig};
5use super::session_registry::SessionRegistry;
6use super::session_store::SessionStore;
7use acp_utils::testing::{TestPeer, duplex_pair};
8use aether_core::core::AgentHandle;
9use aether_core::events::{AgentMessage, UserMessage};
10use agent_client_protocol::schema::SessionId;
11use agent_client_protocol::{Agent, Client, ConnectionTo};
12use llm::oauth::OAuthCredentialStore;
13use std::sync::Arc;
14use tempfile::TempDir;
15use tokio::sync::{mpsc, oneshot};
16use tokio::task::spawn_local;
17
18pub struct AcpTestHarness {
24 pub client_cx: ConnectionTo<Agent>,
25 pub peer: TestPeer,
26 agent_cx: ConnectionTo<Client>,
27 registry: Arc<SessionRegistry>,
28 session_store: Arc<SessionStore>,
29 _tmp: TempDir,
30}
31
32impl AcpTestHarness {
33 pub async fn start() -> Self {
34 let tmp = tempfile::tempdir().expect("tempdir for session store");
35 let registry = Arc::new(SessionRegistry::new());
36 let session_store = Arc::new(SessionStore::from_path(tmp.path().to_path_buf()));
37 let manager = Arc::new(SessionManager::new(SessionManagerConfig {
38 registry: registry.clone(),
39 session_store: session_store.clone(),
40 has_oauth_credential: OAuthCredentialStore::has_credential,
41 initial_selection: InitialSessionSelection::default(),
42 }));
43
44 let (peer, client_builder) = TestPeer::new();
45 let (agent_transport, client_transport) = duplex_pair();
46 let (agent_cx_tx, agent_cx_rx) = oneshot::channel::<ConnectionTo<Client>>();
47 let (client_cx_tx, client_cx_rx) = oneshot::channel::<ConnectionTo<Agent>>();
48
49 spawn_local(async move {
50 let _ = acp_agent_builder(manager)
51 .connect_with(agent_transport, async move |cx: ConnectionTo<Client>| {
52 let _ = agent_cx_tx.send(cx);
53 std::future::pending::<()>().await;
54 Ok(())
55 })
56 .await;
57 });
58
59 spawn_local(async move {
60 let _ = client_builder
61 .connect_with(client_transport, async move |cx: ConnectionTo<Agent>| {
62 let _ = client_cx_tx.send(cx);
63 std::future::pending::<()>().await;
64 Ok(())
65 })
66 .await;
67 });
68
69 let agent_cx = agent_cx_rx.await.expect("agent side connect_with produced a ConnectionTo");
70 let client_cx = client_cx_rx.await.expect("client side connect_with produced a ConnectionTo");
71 Self { client_cx, peer, agent_cx, registry, session_store, _tmp: tmp }
72 }
73
74 pub async fn insert_stub_session(
80 &self,
81 agent_tx: mpsc::Sender<UserMessage>,
82 agent_rx: mpsc::Receiver<AgentMessage>,
83 agent_handle: AgentHandle,
84 id: SessionId,
85 model: &str,
86 ) {
87 let (mcp_tx, _mcp_rx) = mpsc::channel(1);
88 let (_event_tx, event_rx) = mpsc::channel(1);
89 let session = Session {
90 agent_tx,
91 agent_rx,
92 agent_handle,
93 _mcp_handle: tokio::spawn(async {}),
94 mcp_tx,
95 event_rx,
96 initial_server_statuses: vec![],
97 };
98 let relay = spawn_relay(session, self.agent_cx.clone(), id.clone(), self.session_store.clone());
99 self.registry.insert(id.0.to_string(), relay, model.to_string(), None, None, vec![]).await;
100 }
101}