use argonauts_core::events::RunEventKind;
use argonauts_core::events::session::{EndReason, InputPart};
use argonauts_core::names::{ModelRef, SessionKey};
use argonauts_core::steps::asking;
use argonauts_core::steps::task::TaskReport;
use argonauts_core::{Note, NoteLevel, TaskId};
use super::session::Ended;
use crate::engine::host::Host;
use crate::engine::shared::lock;
use crate::error::EngineResult;
pub(crate) fn reply(
host: &Host,
task: &TaskId,
worker: &ModelRef,
ended: &Ended,
) -> EngineResult<Option<InputPart>> {
let resumes = ended.end.cli_session.is_some()
&& host
.services()
.workers
.get(worker)
.is_ok_and(|model| model.capabilities().resume);
if ended.end.reason != EndReason::Completed || !resumes {
return Ok(None);
}
let Some(limit) = host.ask_limit().map(u32::from) else {
return Ok(None);
};
let asked_before = lock(&host.shared().asked_anyway)
.get(task)
.copied()
.unwrap_or(0);
let Some(mut reply) = asking::reply(&ended.end, asked_before, Some(limit)) else {
return Ok(None);
};
reply.text.push_str(
" List each thing you assumed in its `concerns`, on a line starting with \"Assumed:\".",
);
lock(&host.shared().asked_anyway).insert(task.clone(), asked_before + 1);
let told = if asked_before >= limit {
"to take the option it recommended"
} else {
"to decide and carry on"
};
let label = host.read(|state| crate::labels::task_label(state, task));
let note = Note {
level: NoteLevel::Info,
text: format!("{label} ended its turn with a question, so it was told {told}."),
};
host.record(Some(task), Some(&ended.key), RunEventKind::Note(note))?;
Ok(Some(reply))
}
pub(crate) fn on_report(
host: &Host,
task: &TaskId,
session: &SessionKey,
report: &TaskReport,
) -> EngineResult<()> {
lock(&host.shared().asked_anyway).remove(task);
let assumed = report.assumptions();
if assumed.is_empty() {
return Ok(());
}
let label = host.read(|state| crate::labels::task_label(state, task));
let note = Note {
level: NoteLevel::Info,
text: format!("{label} assumed: {}", assumed.join("; ")),
};
host.record(Some(task), Some(session), RunEventKind::Note(note))?;
Ok(())
}
#[cfg(test)]
mod tests {
use argonauts_core::steps::task::ReportStatus;
use super::*;
fn report(concerns: &[&str]) -> TaskReport {
TaskReport {
status: ReportStatus::Done,
summary: "Built it.".to_owned(),
files_changed: Vec::new(),
tests_run: Vec::new(),
concerns: concerns
.iter()
.map(|concern| (*concern).to_owned())
.collect(),
questions: Vec::new(),
change_requests: Vec::new(),
memory_proposals: Vec::new(),
answer: String::new(),
}
}
#[test]
fn assumptions_are_the_concerns_marked_as_assumed() {
let reported = report(&[
"Assumed: dates without a year mean this year.",
"The store has no pool yet.",
"- assumed: ISO dates only\nAssumed:",
]);
assert_eq!(
reported.assumptions(),
["dates without a year mean this year", "ISO dates only"]
);
assert!(
report(&["Nothing was assumed here."])
.assumptions()
.is_empty()
);
}
}