ras_agent/application/
detect_loop.rs1use ras_llm::ChatMessage;
2
3use crate::domain::loop_detector::ActionLoopDetector;
4
5#[must_use]
6pub fn build_loop_nudge(detector: &ActionLoopDetector) -> Option<ChatMessage> {
7 let mut parts: Vec<String> = Vec::new();
8 if detector.action_loop_detected() {
9 parts.push(
10 "Heads up: the same action repeated several times. Try a different element or strategy."
11 .into(),
12 );
13 }
14 if detector.page_stagnation_detected() {
15 parts.push(
16 "Heads up: the page state has not changed for several steps. Reassess your approach."
17 .into(),
18 );
19 }
20 if parts.is_empty() {
21 return None;
22 }
23 Some(ChatMessage::system(parts.join("\n\n")))
24}
25
26#[must_use]
27pub fn build_budget_warning(step: u32, max_steps: u32) -> Option<ChatMessage> {
28 if max_steps == 0 {
29 return None;
30 }
31 let pct = (step * 100) / max_steps.max(1);
32 if pct < 75 {
33 return None;
34 }
35 let bound = if pct < 90 { 75 } else { 90 };
36 Some(ChatMessage::system(format!(
37 "You are at {pct}% of your step budget (>= {bound}%). Wrap up: call done if you have an answer, or pivot decisively."
38 )))
39}