1use crate::cli::Cli;
2use crate::error::AppError;
3use crate::settings::{StatusLineSettings, WispSettings};
4use crate::workspace_status::WorkspaceStatus;
5use acp_utils::client::{AcpClientError, AcpEvent, AcpPromptHandle, TokioAcpAgent, spawn_acp_session};
6use agent_client_protocol::schema::ProtocolVersion;
7use agent_client_protocol::schema::v1::{
8 AuthMethod, Implementation, InitializeRequest, NewSessionRequest, PromptCapabilities, SessionCapabilities,
9 SessionConfigOption, SessionId,
10};
11use std::env::current_dir;
12use std::str::FromStr;
13use tokio::sync::mpsc;
14use tui::Theme;
15
16#[doc = include_str!("docs/runtime_state.md")]
17pub struct RuntimeState {
18 pub session_id: SessionId,
19 pub agent_name: String,
20 pub prompt_capabilities: PromptCapabilities,
21 pub session_capabilities: SessionCapabilities,
22 pub config_options: Vec<SessionConfigOption>,
23 pub auth_methods: Vec<AuthMethod>,
24 pub theme: Theme,
25 pub settings: WispSettings,
26 pub event_rx: mpsc::UnboundedReceiver<AcpEvent>,
27 pub prompt_handle: AcpPromptHandle,
28 pub working_dir: std::path::PathBuf,
29 pub workspace_status: WorkspaceStatus,
30}
31
32impl RuntimeState {
33 pub async fn new(agent_command: &str, settings: WispSettings) -> Result<Self, AppError> {
34 let cwd = current_dir().unwrap_or_else(|_| std::path::PathBuf::from("."));
35 let workspace_status = WorkspaceStatus::resolve(&cwd);
36 let new_session_request = NewSessionRequest::new(cwd.clone());
37 let init_request = InitializeRequest::new(ProtocolVersion::V1)
38 .client_info(Implementation::new("wisp", env!("CARGO_PKG_VERSION")));
39
40 let agent = TokioAcpAgent::from_str(agent_command).map_err(AcpClientError::InvalidAgentCommand)?;
41 let session = spawn_acp_session(agent, init_request, new_session_request).await.map_err(AppError::Acp)?;
42
43 let theme = crate::settings::load_theme(&settings);
44
45 Ok(Self {
46 session_id: session.session_id,
47 agent_name: session.agent_name,
48 prompt_capabilities: session.prompt_capabilities,
49 session_capabilities: session.session_capabilities,
50 config_options: session.config_options,
51 auth_methods: session.auth_methods,
52 theme,
53 settings,
54 event_rx: session.event_rx,
55 prompt_handle: session.prompt_handle,
56 working_dir: cwd,
57 workspace_status,
58 })
59 }
60
61 pub async fn from_cli(cli: &Cli) -> Result<Self, AppError> {
62 Self::new(&cli.agent, crate::settings::load_or_create_settings(StatusLineSettings::defaults())).await
63 }
64}