rig_core/conversation/note.rs
1//! Notes in a transcript ([`Note`]).
2
3use serde::{Deserialize, Serialize};
4
5use super::{Aside, Author, MessageId};
6
7/// A note in a transcript: an [`Aside`] of kind [`Note::KIND`] that every
8/// front showing the conversation draws after the entry it follows, with
9/// what it shows collapsed, in a line, and what it shows expanded. It never
10/// reaches a model, and it is saved, restored and forked with the
11/// conversation; one made [`unsaved`](Aside::unsaved) is not saved.
12///
13/// ```
14/// use rig_core::conversation::{Author, Conversation, Note};
15/// use rig_core::message::Message;
16///
17/// let mut conversation = Conversation::new();
18/// conversation.push(Message::user("Why tabs?"));
19/// let after = conversation.id(0);
20/// let note = Note::new("Why tabs?", "The project's style says so.");
21/// conversation.add_aside(note.aside(Author::plugin("btw"), after));
22/// ```
23#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
24pub struct Note {
25 /// What it shows collapsed, in a line.
26 pub title: String,
27 /// What it shows expanded.
28 pub text: String,
29}
30
31impl Note {
32 /// The kind of the asides that hold a note.
33 pub const KIND: &'static str = "note";
34
35 /// A note titled `title`, showing `text` expanded.
36 pub fn new(title: impl Into<String>, text: impl Into<String>) -> Self {
37 Self {
38 title: title.into(),
39 text: text.into(),
40 }
41 }
42
43 /// The saved aside by `author` that holds this note, following the
44 /// entry `after` (`None`: before the first).
45 pub fn aside(self, author: Author, after: Option<MessageId>) -> Aside {
46 let value = serde_json::json!({ "title": self.title, "text": self.text });
47 Aside::new(Self::KIND, author, value).after(after)
48 }
49
50 /// The note `aside` holds, when it holds one.
51 pub fn of(aside: &Aside) -> Option<Self> {
52 if aside.kind != Self::KIND {
53 return None;
54 }
55 Self::deserialize(&aside.value).ok()
56 }
57}