use std::sync::{Arc, Mutex};
use serde_json::json;
use crate::acp::{PermissionHandler, PermissionRequest};
use crate::transports::{ChoiceMade, ChoiceToMake, Chooser, ThingToChoose};
#[derive(Clone, Debug)]
pub(crate) struct ChoiceCorrelation {
pub message_id: String,
pub target_session: String,
pub decider_sessions: Vec<String>,
}
pub(crate) fn build_acp_permission_handler(
chooser: Chooser,
correlation: ChoiceCorrelation,
pending_choice_outcome: Arc<Mutex<Option<ChoiceMade>>>,
) -> PermissionHandler {
Box::new(
move |permission_request: PermissionRequest, mut responder| {
let chooser = Arc::clone(&chooser);
let correlation = correlation.clone();
let writer = Arc::clone(&pending_choice_outcome);
std::thread::Builder::new()
.name("acp-permission-resolver".to_string())
.spawn(move || {
let choice = build_choice_to_make(&correlation, &permission_request);
let made = (chooser)(choice);
let response_option_id = match &made {
ChoiceMade::Chosen { option_id, .. } => Some(option_id.clone()),
ChoiceMade::Cancelled { .. } => None,
};
*writer.lock().expect("pending_choice_outcome mutex") = Some(made);
responder.respond(response_option_id);
})
.expect("spawn ACP permission resolver thread");
},
)
}
fn build_choice_to_make(
correlation: &ChoiceCorrelation,
request: &PermissionRequest,
) -> ChoiceToMake {
let details = json!({
"tool_call_title": request.tool_call_title.clone(),
"options": request.options.clone(),
"acp_request_id": request.request_id,
"raw": request.requested_details.clone(),
});
ChoiceToMake {
request_id: request.request_id,
message_id: correlation.message_id.clone(),
target_session: correlation.target_session.clone(),
decider_sessions: correlation.decider_sessions.clone(),
title: request.tool_call_title.clone(),
species: request.requested_kind.clone(),
details,
options: request
.options
.iter()
.map(|option| ThingToChoose {
option_id: option.option_id.clone(),
name: option.name.clone(),
species: option.kind.clone(),
})
.collect(),
}
}