rig_core/conversation/
turn.rs1use serde::{Deserialize, Serialize};
6
7use super::{Aside, AsideId, Author, Conversation, MessageId};
8
9pub const TURN: &str = "rig.turn";
11
12#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
16pub struct TurnRecord {
17 pub index: u64,
19 pub start: MessageId,
23 #[serde(default, skip_serializing_if = "Option::is_none")]
26 pub end: Option<TurnEnd>,
27}
28
29#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
31#[serde(tag = "how", rename_all = "snake_case")]
32pub enum TurnEnd {
33 Answered {
35 #[serde(default, rename = "by", skip_serializing_if = "Option::is_none")]
38 answer: Option<MessageId>,
39 },
40 Failed {
42 why: String,
44 },
45 Stopped {
48 #[serde(default, skip_serializing_if = "Option::is_none")]
50 why: Option<String>,
51 },
52}
53
54impl TurnRecord {
55 pub fn of(aside: &Aside) -> Option<Self> {
58 (aside.kind == TURN)
59 .then(|| Self::deserialize(&aside.value).ok())
60 .flatten()
61 }
62}
63
64impl Conversation {
65 pub fn turns(&self) -> impl DoubleEndedIterator<Item = (AsideId, TurnRecord)> + '_ {
68 self.asides()
69 .filter_map(|(id, aside)| Some((id, TurnRecord::of(aside)?)))
70 }
71
72 pub fn open_turn(&mut self) -> TurnRecord {
75 let last = self.turns().next_back().map(|(_, record)| record.index);
76 let record = TurnRecord {
77 index: last.map_or(0, |index| index.saturating_add(1)),
78 start: self.turn_start(),
79 end: None,
80 };
81 let after = self.entries().next_back().map(|entry| entry.id);
82 let value = serde_json::to_value(&record).unwrap_or_default();
83 self.add_aside(Aside::new(TURN, Author::rig(), value).after(after));
84 record
85 }
86
87 pub fn end_turn(&mut self, end: TurnEnd) -> bool {
90 let Some((id, record)) = self.turns().next_back() else {
91 return false;
92 };
93 let Some(aside) = self.aside(id).filter(|_| record.end.is_none()).cloned() else {
94 return false;
95 };
96 let ended = TurnRecord {
97 end: Some(end),
98 ..record
99 };
100 let value = serde_json::to_value(ended).unwrap_or_default();
101 self.replace_aside(id, Aside { value, ..aside })
102 }
103}