use std::path::PathBuf;
use std::str::FromStr;
use agent_client_protocol::schema::{
InitializeRequest, ProtocolVersion, RequestPermissionOutcome, RequestPermissionRequest,
RequestPermissionResponse, SelectedPermissionOutcome,
};
use agent_client_protocol::{Agent, Client, ConnectionTo};
use agent_client_protocol_tokio::AcpAgent;
use tracing::{debug, info};
use crate::error::{AcpError, Result};
#[derive(Debug, Clone)]
pub struct AcpAgentConfig {
pub command: String,
pub working_dir: PathBuf,
pub auto_approve: bool,
}
impl AcpAgentConfig {
pub fn new(command: impl Into<String>) -> Self {
Self {
command: command.into(),
working_dir: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
auto_approve: true,
}
}
pub fn working_dir(mut self, path: impl Into<PathBuf>) -> Self {
self.working_dir = path.into();
self
}
pub fn auto_approve(mut self, approve: bool) -> Self {
self.auto_approve = approve;
self
}
}
pub async fn prompt_agent(config: &AcpAgentConfig, prompt: &str) -> Result<String> {
info!(command = %config.command, cwd = %config.working_dir.display(), "spawning ACP agent");
let agent = AcpAgent::from_str(&config.command).map_err(|e| {
AcpError::InvalidConfig(format!("invalid command '{}': {e}", config.command))
})?;
let prompt_text = prompt.to_string();
let working_dir = config.working_dir.clone();
let auto_approve = config.auto_approve;
let result: std::result::Result<String, agent_client_protocol::Error> = Client
.builder()
.on_receive_request(
async move |request: RequestPermissionRequest, responder, _cx: ConnectionTo<Agent>| {
if auto_approve {
debug!("auto-approving ACP permission request");
let option_id = request.options.first().map(|opt| opt.option_id.clone());
if let Some(id) = option_id {
responder.respond(RequestPermissionResponse::new(
RequestPermissionOutcome::Selected(SelectedPermissionOutcome::new(id)),
))
} else {
responder.respond(RequestPermissionResponse::new(
RequestPermissionOutcome::Cancelled,
))
}
} else {
debug!("rejecting ACP permission request (auto_approve=false)");
responder.respond(RequestPermissionResponse::new(
RequestPermissionOutcome::Cancelled,
))
}
},
agent_client_protocol::on_receive_request!(),
)
.connect_with(agent, |connection: ConnectionTo<Agent>| async move {
connection
.send_request(InitializeRequest::new(ProtocolVersion::V1))
.block_task()
.await?;
let response_text = connection
.build_session(&working_dir)
.block_task()
.run_until(async |mut session| {
session.send_prompt(&prompt_text)?;
let text = session.read_to_string().await?;
Ok(text)
})
.await?;
Ok(response_text)
})
.await;
result.map_err(|e| AcpError::Protocol(e.to_string()))
}