use std::future::{Future, IntoFuture};
use std::pin::Pin;
use crate::jobs::{JobKind, MemoryJobsStore};
use crate::memory::{MemoryKind, RetirementReason};
use crate::store::MemoryStore;
use super::{Client, ClientError};
#[must_use = "feedback(..) returns a builder that must be awaited"]
pub struct FeedbackBuilder<'a> {
client: &'a Client,
pid: String,
correction: Option<String>,
}
impl<'a> FeedbackBuilder<'a> {
pub(super) fn new(client: &'a Client, pid: String) -> Self {
Self {
client,
pid,
correction: None,
}
}
pub fn correction(mut self, correction: impl Into<String>) -> Self {
self.correction = Some(correction.into());
self
}
}
impl<'a> IntoFuture for FeedbackBuilder<'a> {
type Output = Result<(), ClientError>;
type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>;
fn into_future(self) -> Self::IntoFuture {
Box::pin(execute(self))
}
}
async fn execute(builder: FeedbackBuilder<'_>) -> Result<(), ClientError> {
let FeedbackBuilder {
client,
pid,
correction,
} = builder;
let inner = client.inner.clone();
let target = inner.store.recall(&pid).await?;
if target.kind != MemoryKind::Semantic {
return Err(ClientError::NotCorrectable {
pid,
reason: "feedback corrects a wrong extraction; the target must be a semantic memory (edit the episodic source instead)".to_string(),
});
}
let source_pid = target.source_pid.ok_or_else(|| ClientError::NotCorrectable {
pid: pid.clone(),
reason: "semantic memory has no episodic source to reprocess".to_string(),
})?;
let mut payload = serde_json::json!({ "reason": RetirementReason::Rejected.as_ref() });
if let Some(correction) = correction {
payload["feedback"] = serde_json::Value::String(correction);
}
inner.jobs.enqueue(JobKind::Reprocess, source_pid, payload).await?;
Ok(())
}