cascade_agent/agent/
state.rs1use llm_cascade::{Conversation, Message};
4use serde::Serialize;
5
6use crate::error::Result;
7use crate::memory::state::ConversationStateAccess;
8
9#[derive(Debug, Serialize)]
14pub struct ConversationState {
15 pub messages: Vec<Message>,
17 pub system_prompt: String,
19 pub turn_count: usize,
21 pub task_id: String,
23 pub created_at: chrono::DateTime<chrono::Utc>,
25}
26
27impl ConversationState {
28 pub fn new(system_prompt: String, task_id: String) -> Self {
30 Self {
31 messages: Vec::new(),
32 system_prompt,
33 turn_count: 0,
34 task_id,
35 created_at: chrono::Utc::now(),
36 }
37 }
38
39 pub fn add_user_message(&mut self, content: String) {
41 self.messages.push(Message::user(content));
42 self.turn_count += 1;
43 }
44
45 pub fn add_assistant_text(&mut self, content: String) {
47 self.messages.push(Message::assistant(content));
48 }
49
50 pub fn add_tool_result(&mut self, tool_call_id: &str, result: &str) {
52 self.messages
53 .push(Message::tool(result.to_string(), tool_call_id.to_string()));
54 }
55
56 pub fn to_conversation(&self) -> Conversation {
61 let mut all_msgs = vec![Message::system(&self.system_prompt)];
62 all_msgs.extend(self.messages.clone());
63 Conversation::new(all_msgs)
64 }
65
66 pub fn last_assistant_text(&self) -> Option<String> {
68 self.messages
69 .iter()
70 .rev()
71 .find(|m| matches!(m.role, llm_cascade::MessageRole::Assistant))
72 .map(|m| m.content.clone())
73 }
74
75 pub fn to_json(&self) -> Result<String> {
77 serde_json::to_string_pretty(self).map_err(Into::into)
78 }
79
80 pub fn to_json_file(&self, dir: &str) -> Result<std::path::PathBuf> {
82 std::fs::create_dir_all(dir)?;
83 let filename = format!(
84 "state_{}_{}.json",
85 self.created_at.format("%Y%m%d_%H%M%S"),
86 &self.task_id[..8.min(self.task_id.len())]
87 );
88 let path = std::path::PathBuf::from(dir).join(filename);
89 std::fs::write(&path, self.to_json()?)?;
90 Ok(path)
91 }
92}
93
94impl ConversationStateAccess for ConversationState {
95 fn messages(&self) -> &[Message] {
96 &self.messages
97 }
98
99 fn messages_mut(&mut self) -> &mut Vec<Message> {
100 &mut self.messages
101 }
102
103 fn system_prompt(&self) -> &str {
104 &self.system_prompt
105 }
106}