use crate::brain::agent::service::is_analysis_intent;
const PROMPT_BUILDER_SRC: &str = include_str!("../brain/prompt_builder.rs");
const TOOL_LOOP_SRC: &str = include_str!("../brain/agent/service/tool_loop.rs");
#[test]
fn detects_audit_verb_in_user_request() {
assert!(is_analysis_intent("audit the PR for me"));
assert!(is_analysis_intent("Audit the PR"));
assert!(is_analysis_intent("can you audit the latest PRs"));
}
#[test]
fn detects_review_compare_explain_at_start() {
assert!(is_analysis_intent("review this PR"));
assert!(is_analysis_intent("compare these two changes"));
assert!(is_analysis_intent("explain what this code does"));
assert!(is_analysis_intent("summarise the changes since v0.3.31"));
assert!(is_analysis_intent("summarize the failures from yesterday"));
}
#[test]
fn detects_question_shapes() {
assert!(is_analysis_intent("what does this function do"));
assert!(is_analysis_intent("how does the fallback chain work"));
assert!(is_analysis_intent("why does the agent loop on completion"));
assert!(is_analysis_intent("what is the current model"));
assert!(is_analysis_intent("what are the open issues"));
}
#[test]
fn detects_show_tell_investigate_diagnose() {
assert!(is_analysis_intent("tell me what changed"));
assert!(is_analysis_intent("show me the recent commits"));
assert!(is_analysis_intent("investigate the phantom loop"));
assert!(is_analysis_intent("diagnose the crash"));
}
#[test]
fn detects_check_describe_find() {
assert!(is_analysis_intent("check the logs"));
assert!(is_analysis_intent("describe the schema"));
assert!(is_analysis_intent("find the bug in this function"));
assert!(is_analysis_intent("look up the docs for X"));
assert!(is_analysis_intent("look at issue #141"));
}
#[test]
fn does_not_match_side_effect_verbs() {
assert!(!is_analysis_intent("commit the changes"));
assert!(!is_analysis_intent("push to main"));
assert!(!is_analysis_intent("edit the file to fix the bug"));
assert!(!is_analysis_intent("delete the old config"));
assert!(!is_analysis_intent("close issue #141"));
assert!(!is_analysis_intent("tag the release"));
assert!(!is_analysis_intent("create a PR"));
assert!(!is_analysis_intent("send a message to slack"));
}
#[test]
fn does_not_trip_on_verb_inside_other_words() {
assert!(!is_analysis_intent("the auditorium was packed"));
assert!(!is_analysis_intent("examines the wreckage"));
assert!(!is_analysis_intent("the report says nothing"));
assert!(!is_analysis_intent("we couldn't refind the missing key"));
}
#[test]
fn handles_channel_prefix_wrapped_messages() {
let wrapped = "[Channel: Telegram — your text response is automatically sent. \
Do NOT call telegram_send to deliver your answer. Only use \
telegram_send for: sending to a different chat_id, media, polls.]\n\
audit the latest PR";
assert!(
is_analysis_intent(wrapped),
"must detect the analysis verb on the line AFTER the channel prefix"
);
}
#[test]
fn empty_or_whitespace_input_returns_false() {
assert!(!is_analysis_intent(""));
assert!(!is_analysis_intent(" "));
assert!(!is_analysis_intent("\n\n"));
}
#[test]
fn brain_preamble_splits_finishing_a_turn_into_two_cases() {
assert!(
PROMPT_BUILDER_SRC.contains("SIDE-EFFECT tasks"),
"directive must label the side-effect branch"
);
assert!(
PROMPT_BUILDER_SRC.contains("DATA-FETCH / ANALYSIS tasks"),
"directive must label the analysis branch — the gap that produced \
the empty-text-after-tool-calls regression"
);
assert!(
PROMPT_BUILDER_SRC.contains("INPUT to your answer"),
"directive must spell out that for analysis tasks the fetched data \
is INPUT, not the answer itself"
);
assert!(
PROMPT_BUILDER_SRC.contains("\"Done.\" after `gh pr view` is WRONG"),
"directive must call out the specific failure shape from the user incident"
);
}
#[test]
fn tool_loop_wires_analysis_nudge_at_turn_end_site() {
assert!(
TOOL_LOOP_SRC.contains("let mut analysis_nudge_used: bool = false;"),
"one-shot nudge budget must be declared at turn scope"
);
assert!(
TOOL_LOOP_SRC.contains("super::phantom::is_analysis_intent(user_text_for_intent)"),
"nudge condition must call is_analysis_intent on the clean user text \
(display_text_override-aware so channel prefixes don't shadow the verb)"
);
assert!(
TOOL_LOOP_SRC.contains("iteration_text.trim().is_empty()"),
"nudge must fire when the final iteration produced zero text — \
that's the empty-close case"
);
assert!(
TOOL_LOOP_SRC.contains("tool_calls_completed_this_turn > 0"),
"nudge must require at least one successful tool call this turn \
— otherwise this isn't the empty-after-fetch case, it's just \
a model that refused to answer at all"
);
}