use super::*;
pub(super) const ROLE_POLL_IDLE_INTERVAL: Duration = Duration::from_millis(200);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StartRefusal(pub String);
impl std::fmt::Display for StartRefusal {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str(&self.0)
}
}
pub const PROMPT_HELD_MESSAGE: &str =
"a review of the last turn is open; forward, dismiss or cancel it first";
pub(super) static PROMPT_LOCK: LazyLock<Mutex<BTreeMap<String, PromptHold>>> =
LazyLock::new(Mutex::default);
#[derive(Debug, Default)]
pub(super) struct PromptHold {
pub(super) delivery_epoch: Option<u64>,
pub(super) delivery_command_id: Option<String>,
}
pub(crate) fn next_review_generation() -> Result<u64, String> {
let mut random = [0_u8; 8];
getrandom::fill(&mut random)
.map_err(|error| format!("generate reviewer generation: {error}"))?;
let generation = u64::from_le_bytes(random);
if generation == 0 {
return Err("generate reviewer generation: random nonce was zero".to_owned());
}
Ok(generation)
}
#[must_use]
pub fn prompt_refusal(session_id: &str) -> Option<&'static str> {
PROMPT_LOCK
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.contains_key(session_id)
.then_some(PROMPT_HELD_MESSAGE)
}
pub(super) fn hold_prompts(session_id: &str) {
PROMPT_LOCK
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.insert(session_id.to_owned(), PromptHold::default());
}
pub(super) fn release_prompts(session_id: &str) {
PROMPT_LOCK
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.remove(session_id);
}
pub(super) fn admit_review_delivery(
session_id: &str,
epoch: u64,
command_id: &str,
) -> Option<ReviewDeliveryAdmission> {
let mut locks = PROMPT_LOCK
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
let hold = locks.get_mut(session_id)?;
match (hold.delivery_epoch, hold.delivery_command_id.as_deref()) {
(Some(existing_epoch), Some(existing_command))
if existing_epoch != epoch || existing_command != command_id =>
{
None
}
_ => {
hold.delivery_epoch = Some(epoch);
hold.delivery_command_id = Some(command_id.to_owned());
Some(ReviewDeliveryAdmission::new(
session_id.to_owned(),
epoch,
command_id.to_owned(),
))
}
}
}
pub(crate) fn review_delivery_admitted(
session_id: &str,
admission: &ReviewDeliveryAdmission,
) -> bool {
let locks = PROMPT_LOCK
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
locks.get(session_id).is_some_and(|hold| {
admission.session_id() == session_id
&& hold.delivery_epoch == Some(admission.epoch())
&& hold.delivery_command_id.as_deref() == Some(admission.command_id())
})
}
pub type ReviewConfigSource = Arc<dyn Fn() -> ReviewConfig + Send + Sync>;