use argonauts_core::events::session::{InputPart, InputPartKind};
use argonauts_core::settings::Settings;
use argonauts_core::settings::approvals::ApprovalMode;
use super::tools;
use super::{ConversationState, direct};
use crate::controller::Ctx;
use crate::controller::turn::part;
pub(super) fn lines(offered: &[String]) -> Option<String> {
let about = tools::about(offered);
if about.is_empty() {
return None;
}
Some(crate::prompts::standing(&about))
}
pub(super) fn setup_note(
ctx: &Ctx,
conversation: &mut ConversationState,
fresh: bool,
) -> Option<InputPart> {
let setup = Setup::now(ctx, conversation);
let line = setup.line();
let heard = conversation.direct.told_setup.as_deref() == Some(line.as_str());
if heard && !fresh {
return None;
}
conversation.direct.told_setup = Some(line.clone());
Some(part(InputPartKind::Notes, "setup", format!("\n\n{line}")))
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct Setup {
workflow: Option<String>,
ultracode: bool,
autopilot: bool,
}
impl Setup {
fn now(ctx: &Ctx, conversation: &ConversationState) -> Self {
let settings = ctx.settings();
Self {
workflow: workflow_for(ctx, conversation),
ultracode: settings.ultracode,
autopilot: direct::approval(conversation) == ApprovalMode::Autopilot,
}
}
fn line(&self) -> String {
let mut line = match (&self.workflow, self.ultracode) {
(Some(workflow), false) => format!(
"Argonauts Code setup: the {workflow} workflow is in use, and ultracode is off. \
Small changes are yours to make. Real work goes to the workflow."
),
(Some(workflow), true) => format!(
"Argonauts Code setup: the {workflow} workflow is in use, and ultracode is on. \
Every change goes to the workflow, small ones too. Questions are still yours to \
answer."
),
(None, _) => {
"Argonauts Code setup: Captain is in use, so the work stays with you. Start a \
workflow only when the user's own words ask for the crew, for other \
agents, for a workflow or for a checked worktree."
.to_owned()
}
};
if self.autopilot {
line.push_str(
" Autopilot is on: when you can't tell whether the user wants work done or \
only an answer, answer and leave things as they are.",
);
}
line
}
}
pub(super) fn workflow_for(ctx: &Ctx, conversation: &ConversationState) -> Option<String> {
if conversation.place.is_some() {
return None;
}
workflow_in_use(ctx.settings())
}
pub(super) fn workflow_in_use(settings: &Settings) -> Option<String> {
if direct::workflow_is_direct(settings) {
return None;
}
let name = settings.workflow.trim();
Some(if name.is_empty() { "crew" } else { name }.to_owned())
}
#[cfg(test)]
mod tests {
use super::*;
fn setup(workflow: Option<&str>) -> Setup {
Setup {
workflow: workflow.map(str::to_owned),
ultracode: false,
autopilot: false,
}
}
#[test]
fn the_setup_line_says_what_leaves_the_session() {
let council = setup(Some("council")).line();
assert!(council.starts_with("Argonauts Code setup: the council workflow is in use"));
assert!(council.contains("ultracode is off"), "{council}");
assert!(council.contains("Small changes are yours"), "{council}");
let ultra = Setup {
ultracode: true,
..setup(Some("orchestrator"))
}
.line();
assert!(ultra.contains("ultracode is on"), "{ultra}");
assert!(ultra.contains("small ones too"), "{ultra}");
assert!(ultra.contains("Questions are still yours"), "{ultra}");
let captain = setup(None).line();
assert!(captain.contains("Captain is in use"), "{captain}");
assert!(
captain.contains("only when the user's own words ask"),
"{captain}"
);
}
#[test]
fn autopilot_adds_its_sentence() {
let line = Setup {
autopilot: true,
..setup(Some("council"))
}
.line();
assert!(line.contains("Autopilot is on"), "{line}");
assert!(
line.contains("answer and leave things as they are"),
"{line}"
);
}
#[test]
fn no_tools_means_no_standing_lines() {
assert_eq!(lines(&[]), None);
let offered = vec![tools::start_workflow::NAME.to_owned()];
let lines = lines(&offered).expect("lines");
assert!(lines.contains("`argonauts_start_workflow`"), "{lines}");
assert!(lines.contains("nothing outside this session happens until you call one"));
assert!(lines.contains("say that nothing is changed"), "{lines}");
assert!(!lines.contains("{{"), "{lines}");
}
}