use std::collections::HashMap;
use bitrouter_sdk::acp::client::{AcpClient, PendingPermission};
use bitrouter_tui::machine::Effect;
use bitrouter_tui::permission::{Decision, Policy, Prompt};
pub(crate) struct Wire<'a> {
client: &'a AcpClient,
session_id: &'a str,
outstanding: HashMap<String, PendingPermission>,
}
impl<'a> Wire<'a> {
pub(crate) fn new(client: &'a AcpClient, session_id: &'a str) -> Self {
Self {
client,
session_id,
outstanding: HashMap::new(),
}
}
pub(crate) fn admit(&mut self, request: PendingPermission) -> Prompt {
let prompt = Prompt::new(
request.request_id.clone(),
request.tool_call.fields.title.clone(),
request.tool_call.tool_call_id.0.to_string(),
request.tool_call.fields.kind,
request.options.clone(),
);
self.outstanding.insert(request.request_id.clone(), request);
prompt
}
pub(crate) async fn answer(
&mut self,
request: PendingPermission,
policy: &Policy,
) -> (Decision, Prompt) {
let prompt = self.admit(request);
let (decision, effect) = bitrouter_tui::machine::decide(policy, &prompt);
let _ = self.apply(effect).await;
(decision, prompt)
}
pub(crate) async fn apply(&mut self, effect: Effect) -> Option<Effect> {
match effect {
Effect::Resolve { id, outcome } => {
if let Some(request) = self.outstanding.remove(&id) {
request.resolve(outcome);
}
}
Effect::Cancel => {
let told = self.client.cancel(self.session_id).await;
self.outstanding.clear();
self.client.deny_session_permissions(self.session_id);
if let Err(error) = told {
tracing::warn!(%error, "cancelling the turn");
}
}
other => return Some(other),
}
None
}
}