#![allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::indexing_slicing,
clippy::as_conversions,
clippy::arithmetic_side_effects,
reason = "test code"
)]
use super::super::tests::no_offload;
use super::super::{PackContext, package};
use super::*;
use crate::offload::OffloadSite;
use storage::Cas;
fn conversation() -> Conversation {
let mut conversation = Conversation::new();
conversation.push_task_lines(
"do it",
"it is done",
crate::conversation::Opening::FromJob,
"the User",
);
conversation
}
fn scripted(answer: Result<AdviserAnswer, AdviserFailure>) -> Adviser {
Adviser::with(move |_ask, _window| answer.clone())
}
#[test]
fn an_answer_to_another_question_is_a_fallback() {
let mut adviser = scripted(Ok(AdviserAnswer::Score { score_bp: 1 }));
let consultation = adviser.consult(Ask::noul("toolu_01", "material"), &conversation(), 7);
assert_eq!(
consultation,
Consultation::FellBack {
ask: AdviserAsk::Noul,
subject: "toolu_01".to_owned(),
reason: AdviserFailure::Unreadable,
}
);
assert!(consultation.answer().is_none());
}
#[test]
fn a_choice_outside_the_offered_options_is_a_fallback() {
let mut adviser = scripted(Ok(AdviserAnswer::Choice {
chosen: "something-else".to_owned(),
}));
let consultation = adviser.consult(
Ask::choice("dispatch", vec!["sonnet".to_owned(), "opus".to_owned()]),
&conversation(),
3,
);
assert_eq!(consultation.answer(), None);
let Consultation::FellBack { reason, .. } = consultation else {
panic!("an off-list choice is not an answer");
};
assert_eq!(reason, AdviserFailure::Unreadable);
}
#[test]
fn a_missing_adviser_falls_back_as_unavailable() {
let mut adviser = Adviser::none();
let consultation = adviser.consult(Ask::score("toolu_02", "text"), &conversation(), 0);
let Consultation::FellBack { reason, ask, .. } = consultation else {
panic!("no adviser means no answer");
};
assert_eq!(reason, AdviserFailure::Unavailable);
assert_eq!(ask, AdviserAsk::Score);
}
#[test]
fn a_valid_answer_is_kept_and_records_the_two_lines() {
let mut adviser = scripted(Ok(AdviserAnswer::Noul {
keep: false,
confidence_bp: 8_750,
}));
let consultation = adviser.consult(Ask::noul("toolu_01", "material"), &conversation(), 41);
assert_eq!(
consultation.answer(),
Some(&AdviserAnswer::Noul {
keep: false,
confidence_bp: 8_750
})
);
let payloads = consultation.payloads().unwrap();
assert_eq!(
payloads.first().unwrap().as_map().get("ask"),
Some(&serde_json::json!("noul"))
);
assert_eq!(
payloads.get(1).unwrap().as_map().get("keep"),
Some(&serde_json::json!(false))
);
assert_eq!(
payloads.get(1).unwrap().as_map().get("elapsed_ms"),
Some(&serde_json::json!(41))
);
}
#[test]
fn a_fallback_records_the_reason() {
let mut adviser = scripted(Err(AdviserFailure::Timeout));
let consultation = adviser.consult(Ask::score("toolu_09", "text"), &conversation(), 900);
let payloads = consultation.payloads().unwrap();
assert_eq!(
payloads.get(1).unwrap().as_map().get("reason"),
Some(&serde_json::json!("timeout"))
);
assert_eq!(
payloads.get(1).unwrap().as_map().get("subject"),
Some(&serde_json::json!("toolu_09"))
);
}
#[test]
fn a_density_score_scales_the_budget_and_records_the_two_lines() {
let text = "The first sentence says what this result is about. ".repeat(40);
let mut conversation = Conversation::new();
conversation.push_task_lines("t", "g", crate::conversation::Opening::FromJob, "the User");
let mut adviser = Adviser::with(|_ask, _window| {
Ok(kernel::event::record::AdviserAnswer::Score { score_bp: 1_000 })
});
let consultation = adviser.consult(Ask::score("result", text.as_str()), &conversation, 12);
let mut ctx = no_offload(4_096);
ctx.adviser = Some(consultation);
let out = package(text.as_bytes(), ctx).unwrap();
assert!(
out.content.len() < text.len() && out.content.contains("[truncated: "),
"a low score shortens what would otherwise fit"
);
assert_eq!(out.events.len(), 2, "asked then answered");
let answered = serde_json::to_value(&out.events[1]).unwrap();
assert_eq!(answered["ask"], "score");
assert_eq!(answered["score_bp"], 1_000);
assert_eq!(answered["elapsed_ms"], 12);
assert_eq!(
package(text.as_bytes(), no_offload(4_096)).unwrap().content,
text,
"without an adviser the same result is kept whole"
);
}
#[test]
fn a_fallback_is_recorded_and_leaves_every_figure_alone() {
let text = "The first sentence says what this result is about. ".repeat(40);
let mut conversation = Conversation::new();
conversation.push_task_lines("t", "g", crate::conversation::Opening::FromJob, "the User");
let mut adviser = Adviser::none();
let consultation = adviser.consult(Ask::score("result", text.as_str()), &conversation, 0);
let mut ctx = no_offload(4_096);
ctx.adviser = Some(consultation);
let out = package(text.as_bytes(), ctx).unwrap();
assert_eq!(out.content, text, "no answer means no adjustment");
assert_eq!(out.events.len(), 2);
let fell_back = serde_json::to_value(&out.events[1]).unwrap();
assert_eq!(fell_back["reason"], "unavailable");
assert_eq!(fell_back["subject"], "result");
}
#[test]
fn an_advisers_not_needed_acts_only_where_a_store_could_hold_it() {
let dir = tempfile::tempdir().unwrap();
let mut cas = Cas::open(&dir.path().join("cas")).unwrap();
let env = dir.path().join("env");
std::fs::create_dir_all(&env).unwrap();
let mut conversation = Conversation::new();
conversation.push_task_lines("t", "g", crate::conversation::Opening::FromJob, "the User");
let mut adviser = Adviser::with(|_ask, _window| {
Ok(kernel::event::record::AdviserAnswer::Noul {
keep: false,
confidence_bp: 9_000,
})
});
let big = "The first sentence says what this result is about. ".repeat(400);
let consultation = adviser.consult(Ask::noul("result", big.as_str()), &conversation, 5);
let out = package(
big.as_bytes(),
PackContext {
cap_bytes: 1_024,
stamp: None,
net_notice: false,
steer: None,
reminder: None,
offload: Some(OffloadSite {
cas: &mut cas,
city_root: &env,
room: &kernel::Address::parse("room").unwrap(),
origin: crate::offload::tests::origin(),
}),
sieve: None,
adviser: Some(consultation),
},
)
.unwrap();
assert!(
out.content.contains("[offloaded: total"),
"a result too big for the window leaves with a way back: {}",
out.content
);
let small = "{\"ok\":true}";
let consultation = adviser.consult(Ask::noul("result", small), &conversation, 5);
let out = package(
small.as_bytes(),
PackContext {
cap_bytes: 4_096,
stamp: None,
net_notice: false,
steer: None,
reminder: None,
offload: Some(OffloadSite {
cas: &mut cas,
city_root: &env,
room: &kernel::Address::parse("room").unwrap(),
origin: crate::offload::tests::origin(),
}),
sieve: None,
adviser: Some(consultation),
},
)
.unwrap();
assert_eq!(out.content, small, "a result that fits is not turned away");
assert_eq!(out.events.len(), 2, "the answer is recorded either way");
}