1pub(crate) mod platform;
2pub mod session_config_view;
3pub(crate) mod session_model;
4pub mod terminal;
5pub mod workspace_status;
6
7use crate::error::AppError;
8use crate::session::workspace_status::WorkspaceStatus;
9use acp_utils::client::{AcpClientError, AcpClientHandle, AcpEvent, TokioAcpAgent, connect_acp_client};
10use agent_client_protocol::schema::ProtocolVersion;
11use agent_client_protocol::schema::v1::{
12 AuthMethod, ClientCapabilities, ElicitationCapabilities, ElicitationFormCapabilities, ElicitationUrlCapabilities,
13 Implementation, InitializeRequest, NewSessionRequest, PromptCapabilities, SessionCapabilities, SessionConfigOption,
14 SessionId,
15};
16use std::env::current_dir;
17use std::path::PathBuf;
18use std::str::FromStr;
19use tokio::sync::mpsc;
20
21pub struct Session {
22 pub session_id: SessionId,
23 pub agent_name: String,
24 pub prompt_capabilities: PromptCapabilities,
25 pub session_capabilities: SessionCapabilities,
26 pub config_options: Vec<SessionConfigOption>,
27 pub auth_methods: Vec<AuthMethod>,
28 pub event_rx: mpsc::UnboundedReceiver<AcpEvent>,
29 pub client_handle: AcpClientHandle,
30 pub working_dir: PathBuf,
31 pub workspace_status: WorkspaceStatus,
32}
33
34impl Session {
35 pub async fn connect(agent_command: &str) -> Result<Self, AppError> {
36 let working_dir = current_dir().unwrap_or_else(|_| PathBuf::from("."));
37 let workspace_status = WorkspaceStatus::initial(&working_dir);
38 let agent = TokioAcpAgent::from_str(agent_command).map_err(AcpClientError::InvalidAgentCommand)?;
39 let init_request = InitializeRequest::new(ProtocolVersion::LATEST)
40 .client_capabilities(client_capabilities())
41 .client_info(Implementation::new("wisp", env!("CARGO_PKG_VERSION")));
42 let client = connect_acp_client(agent, init_request).await?;
43 let session_response = client.handle.new_session(NewSessionRequest::new(working_dir.clone())).await?;
44
45 Ok(Self {
46 session_id: session_response.session_id,
47 agent_name: client.agent_name(),
48 prompt_capabilities: client.prompt_capabilities().clone(),
49 session_capabilities: client.session_capabilities().clone(),
50 config_options: session_response.config_options.unwrap_or_default(),
51 auth_methods: client.auth_methods().to_vec(),
52 event_rx: client.event_rx,
53 client_handle: client.handle,
54 working_dir,
55 workspace_status,
56 })
57 }
58}
59
60fn client_capabilities() -> ClientCapabilities {
61 ClientCapabilities::new().elicitation(
62 ElicitationCapabilities::new()
63 .form(ElicitationFormCapabilities::new())
64 .url(ElicitationUrlCapabilities::new()),
65 )
66}