ai_agent/services/
agent_summary.rs1pub const SUMMARY_INTERVAL_MS: u64 = 30000;
6
7pub fn build_summary_prompt(previous_summary: Option<&str>) -> String {
8 let prev_line = previous_summary
9 .map(|s| format!("\nPrevious: \"{}\" — say something NEW.\n", s))
10 .unwrap_or_default();
11
12 format!(
13 r#"Describe your most recent action in 3-5 words using present tense (-ing). Name the file or function, not the branch. Do not use tools.
14{}
15Good: "Reading runAgent.ts"
16Good: "Fixing null check in validate.ts"
17Good: "Running auth module tests"
18Good: "Adding retry logic to fetchUser"
19
20Bad (past tense): "Analyzed the branch diff"
21Bad (too vague): "Investigating the issue"
22Bad (too long): "Reviewing full branch diff and AgentTool.tsx integration"
23Bad (branch name): "Analyzed adam/background-summary branch diff""#,
24 prev_line
25 )
26}
27
28pub struct AgentSummaryHandle {
30 pub stop: Box<dyn Fn() + Send + Sync>,
31}
32
33impl AgentSummaryHandle {
34 pub fn new(stop: impl Fn() + Send + Sync + 'static) -> Self {
35 Self {
36 stop: Box::new(stop),
37 }
38 }
39}
40
41impl Clone for AgentSummaryHandle {
42 fn clone(&self) -> Self {
43 Self {
46 stop: Box::new(|| {}),
47 }
48 }
49}
50
51pub struct AgentSummaryState {
53 pub task_id: String,
54 pub agent_id: String,
55 pub summary: Option<String>,
56 pub is_running: bool,
57}
58
59impl AgentSummaryState {
60 pub fn new(task_id: impl Into<String>, agent_id: impl Into<String>) -> Self {
61 Self {
62 task_id: task_id.into(),
63 agent_id: agent_id.into(),
64 summary: None,
65 is_running: true,
66 }
67 }
68
69 pub fn stop(&mut self) {
70 self.is_running = false;
71 }
72
73 pub fn update_summary(&mut self, summary: impl Into<String>) {
74 self.summary = Some(summary.into());
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn test_build_summary_prompt_no_previous() {
84 let prompt = build_summary_prompt(None);
85 assert!(prompt.contains("Describe your most recent action"));
86 assert!(!prompt.contains("Previous:"));
87 }
88
89 #[test]
90 fn test_build_summary_prompt_with_previous() {
91 let prompt = build_summary_prompt(Some("Reading file"));
92 assert!(prompt.contains("Previous:"));
93 assert!(prompt.contains("Reading file"));
94 }
95
96 #[test]
97 fn test_agent_summary_state() {
98 let mut state = AgentSummaryState::new("task-1", "agent-1");
99
100 assert!(state.summary.is_none());
101 assert!(state.is_running);
102
103 state.update_summary("Reading file");
104 assert_eq!(state.summary, Some("Reading file".to_string()));
105
106 state.stop();
107 assert!(!state.is_running);
108 }
109
110 #[test]
111 fn test_summary_interval() {
112 assert_eq!(SUMMARY_INTERVAL_MS, 30000);
113 }
114}