pub struct Conversation { /* private fields */ }Expand description
A conversation: its entries (each a message with an id and, when it is
not the user’s own or the model’s, an author), its asides, why its last
user message is unanswered, and the changes made to it that nobody has
saved yet. Every edit builds a Change, applies it with the same code
a fold (apply) uses, and keeps it in the outbox
(unsaved).
Two conversations are equal when their entries (messages, ids and authors), saved asides and halt are: the outbox, the revision, unsaved asides and when entries were made are not compared, so a value folded from a log equals the live one and two values built alike are equal.
Its serde form is its state: entries, saved asides, halt and the next
ids, without the outbox, the revision or the lineage. A value read back
from it is Lineage::DETACHED.
Implementations§
Source§impl Conversation
impl Conversation
Sourcepub fn turns(
&self,
) -> impl DoubleEndedIterator<Item = (AsideId, TurnRecord)> + '_
pub fn turns( &self, ) -> impl DoubleEndedIterator<Item = (AsideId, TurnRecord)> + '_
The turn records, oldest first, with their asides’ ids; the newest
is turns().next_back(), found from the end.
Sourcepub fn open_turn(&mut self) -> TurnRecord
pub fn open_turn(&mut self) -> TurnRecord
Records a turn that begins now, numbered after the last record and
starting at turn_start. Returns the new record.
Source§impl Conversation
impl Conversation
Sourcepub fn from_messages(
messages: impl IntoIterator<Item = impl Into<Arc<Message>>>,
) -> Self
pub fn from_messages( messages: impl IntoIterator<Item = impl Into<Arc<Message>>>, ) -> Self
A conversation of messages, each its own entry, recorded so that
saving it writes them (an import, a library user’s history).
Sourcepub fn into_messages(self) -> Vec<Arc<Message>>
pub fn into_messages(self) -> Vec<Arc<Message>>
The messages, oldest first, taken out of the conversation: what a request sends, without a copy.
Sourcepub fn entries(
&self,
) -> impl DoubleEndedIterator<Item = EntryRef<'_>> + ExactSizeIterator
pub fn entries( &self, ) -> impl DoubleEndedIterator<Item = EntryRef<'_>> + ExactSizeIterator
The entries, oldest first.
Sourcepub fn entry(&self, at: usize) -> Option<Entry>
pub fn entry(&self, at: usize) -> Option<Entry>
Entry at, with its author, id and when it was made, to splice
back changed.
Sourcepub fn key(&self, at: usize) -> Option<MessageKey>
pub fn key(&self, at: usize) -> Option<MessageKey>
The identity of entry at beyond this conversation.
Sourcepub fn index_of_key(&self, key: MessageKey) -> Option<usize>
pub fn index_of_key(&self, key: MessageKey) -> Option<usize>
Where the entry with identity key is now; None when it is not
here, also when an entry with its id was made at another time.
Who wrote entry at; None for the user’s own text, the model’s
reply, a tool result, or no such entry.
Sourcepub fn index_of(&self, id: MessageId) -> Option<usize>
pub fn index_of(&self, id: MessageId) -> Option<usize>
Where entry id is now; None once an edit took it out.
Sourcepub fn start_of(&self, id: MessageId) -> usize
pub fn start_of(&self, id: MessageId) -> usize
Where a span that began at entry id begins now, such as a turn:
its index while it is there; the end for an entry not made yet; 0
for one an edit took out, as a summary then stands for what came
before it.
Sourcepub fn turn_start(&self) -> MessageId
pub fn turn_start(&self) -> MessageId
Where a turn starting now begins: the first of the user messages at the end, which it answers, else the first entry it adds.
Sourcepub fn asked(&self, start: MessageId) -> impl Iterator<Item = EntryRef<'_>>
pub fn asked(&self, start: MessageId) -> impl Iterator<Item = EntryRef<'_>>
The entries a turn that began at start (its
turn_start) answers: the user messages in a
row from where it begins now (start_of). After a
stopped turn they begin with that turn’s tool results and the
STOPPED note, before what was sent next.
Sourcepub fn request(&self, start: MessageId) -> Option<EntryRef<'_>>
pub fn request(&self, start: MessageId) -> Option<EntryRef<'_>>
The message that asked for the turn that began at start: the
first of the entries it answers (asked) that is a
request (EntryRef::is_request).
Sourcepub fn halted(&self) -> Option<Halt>
pub fn halted(&self) -> Option<Halt>
Why the user’s last message is left unanswered, if it was halted. Cleared when an entry is pushed or a splice reaches the end.
Sourcepub fn awaits_model(&self) -> bool
pub fn awaits_model(&self) -> bool
Whether the model owes an answer: the last message a model reads is
the user’s, and it was not halted. A failed or stopped reply after it
is never read (StopReason::is_failure), so the answer is still
owed.
Sourcepub fn pending_calls(&self) -> Vec<ToolCall>
pub fn pending_calls(&self) -> Vec<ToolCall>
The tool calls of the last assistant message that nothing answers
yet. See pairing::pending_calls.
Sourcepub fn validate(&self) -> Result<(), PairingError>
pub fn validate(&self) -> Result<(), PairingError>
Whether the messages pair every tool call with its result. See
pairing::validate.
Sourcepub fn asides(&self) -> impl DoubleEndedIterator<Item = (AsideId, &Aside)>
pub fn asides(&self) -> impl DoubleEndedIterator<Item = (AsideId, &Aside)>
The asides, in the order put.
Sourcepub fn aside_position(&self, aside: &Aside) -> usize
pub fn aside_position(&self, aside: &Aside) -> usize
Where aside is drawn: before entry position, after entry
position - 1. While an edit took out the entry it follows, after
the entry that stands for it now (start_of).
Sourcepub fn push(&mut self, entry: impl Into<Entry>) -> MessageId
pub fn push(&mut self, entry: impl Into<Entry>) -> MessageId
Pushes entry, after a STOPPED entry by Author::rig in the
same change when the user stopped the last request; a halt is
cleared. Returns the new entry’s id; a pushed entry never reuses one.
Sourcepub fn extend(
&mut self,
messages: impl IntoIterator<Item = impl Into<Arc<Message>>>,
)
pub fn extend( &mut self, messages: impl IntoIterator<Item = impl Into<Arc<Message>>>, )
Pushes each of messages as its own entry without an author, in one
change, as push does.
Sourcepub fn splice(
&mut self,
range: impl RangeBounds<usize>,
with: impl IntoIterator<Item = Entry>,
by: Author,
) -> Spliced
pub fn splice( &mut self, range: impl RangeBounds<usize>, with: impl IntoIterator<Item = Entry>, by: Author, ) -> Spliced
Replaces entries in range, clamped to the conversation, with
with, recorded as made by by. An entry of with keeps its id
when that id was in the range and no earlier entry of with kept
it; any other gets a new id. Nothing merges. A splice reaching the
end clears the halt. An empty range replaced by nothing changes and
records nothing.
Sourcepub fn restore(
&mut self,
range: impl RangeBounds<usize>,
with: impl IntoIterator<Item = Entry>,
by: Author,
) -> Spliced
pub fn restore( &mut self, range: impl RangeBounds<usize>, with: impl IntoIterator<Item = Entry>, by: Author, ) -> Spliced
As splice, and an entry of with whose id this
conversation made (below the next id), that no entry outside the
range holds and no earlier entry of with took, keeps that id and
when it was made (Entry::made, else now): entries put back as
they were, such as a summary’s originals or an edit undone. Asides that followed such an entry follow it again.
Only for entries this conversation held: an entry from elsewhere
that carries an id would take one that meant another message here.
use rig_core::completion::Message;
use rig_core::conversation::{Author, Conversation, Entry};
let mut conversation = Conversation::from_messages([
Message::user("one"),
Message::assistant("two"),
]);
let ids: Vec<_> = conversation.entries().map(|entry| entry.id).collect();
let originals: Vec<Entry> = (0..2).filter_map(|at| conversation.entry(at)).collect();
let summary = Entry::new(Message::user("a summary"));
conversation.splice(.., [summary], Author::plugin("compact"));
let undone = conversation.restore(.., originals, Author::plugin("undo"));
assert_eq!(undone.restored, ids);
assert!(conversation.entries().map(|entry| entry.id).eq(ids));Sourcepub fn set_entries(&mut self, entries: Vec<Entry>, by: Author) -> Spliced
pub fn set_entries(&mut self, entries: Vec<Entry>, by: Author) -> Spliced
Makes the conversation hold entries, as made by by: one
restore of the range between the longest start
and end it shares with them (the same messages, ids and authors), so
entries taken from it keep their ids. Nothing when they are equal.
Sourcepub fn edit_each(
&mut self,
by: Author,
edit: impl FnMut(EntryRef<'_>) -> Option<Message>,
) -> Vec<MessageId>
pub fn edit_each( &mut self, by: Author, edit: impl FnMut(EntryRef<'_>) -> Option<Message>, ) -> Vec<MessageId>
Rewrites entries in place, as made by by: edit sees each entry,
oldest first, and returns the message to put in its place, or
None to leave it. The entries it rewrote keep their ids and
authors, and the whole edit is one change: a splice
of the entries from the first rewritten to the last. Nothing is
recorded when it rewrote none. Returns the ids of the entries it
rewrote.
use rig_core::completion::Message;
use rig_core::conversation::{Author, Conversation};
let mut conversation = Conversation::from_messages([
Message::user("one"),
Message::user("two"),
]);
let before = conversation.id(1);
let changed = conversation.edit_each(Author::plugin("shout"), |entry| {
(entry.index == 1).then(|| Message::user("TWO"))
});
assert_eq!(changed, before.into_iter().collect::<Vec<_>>());
assert_eq!(conversation.messages().get(1).map(|message| &**message), Some(&Message::user("TWO")));
assert_eq!(conversation.id(1), before);Sourcepub fn normalize(&mut self, by: Author) -> Normalized
pub fn normalize(&mut self, by: Author) -> Normalized
Repairs the entries as pairing::normalize does, saved with
set_entries as made by by, so merged
entries keep the first’s id, author and made-time. An aside that
followed an entry merged into another follows that one; one that
followed a dropped entry follows the entry before it (each move
recorded, by by). Returns what it repaired.
Sourcepub fn reread(&mut self, from_log: Conversation) -> Result<(), ApplyError>
pub fn reread(&mut self, from_log: Conversation) -> Result<(), ApplyError>
Takes everything a log holds from from_log, a value read from that
log: entries, saved asides, halt, next ids, lineage and revision.
This value’s unsaved asides stay, with their ids. For a host whose
log was rewritten under the value it holds.
§Errors
ApplyError::Mismatch, changing nothing, while either value has
unsaved changes, or when an unsaved aside’s id is a saved one’s in
from_log.
Sourcepub fn halt(&mut self, halt: Halt) -> bool
pub fn halt(&mut self, halt: Halt) -> bool
Leaves the user’s last message unanswered, for halt. Whether it
was halted now: not when the model owes no answer.
Sourcepub fn resume(&mut self) -> bool
pub fn resume(&mut self) -> bool
Asks the model again for an answer to the user’s last message, also a halted one; whether the last message is the user’s.
Sourcepub fn add_aside(&mut self, aside: Aside) -> AsideId
pub fn add_aside(&mut self, aside: Aside) -> AsideId
Puts aside after the asides already put and returns its id. An
unsaved aside is not recorded.
Sourcepub fn replace_aside(&mut self, id: AsideId, aside: Aside) -> bool
pub fn replace_aside(&mut self, id: AsideId, aside: Aside) -> bool
Replaces aside id with aside, in its place; whether there was
one. Replacing a saved aside with an unsaved one records its
removal.
Sourcepub fn remove_aside(&mut self, id: AsideId) -> Option<Aside>
pub fn remove_aside(&mut self, id: AsideId) -> Option<Aside>
Removes aside id and returns it, or None if there was none.
Sourcepub fn apply(&mut self, change: &ChangeRecord) -> Result<(), ApplyError>
pub fn apply(&mut self, change: &ChangeRecord) -> Result<(), ApplyError>
Applies a recorded change verbatim, such as one read from a log or sent by a process that mirrors this conversation. It is not put in the outbox. Fails, changing nothing, when it does not fit.
Sourcepub fn dated<R>(&mut self, at: u64, edit: impl FnOnce(&mut Self) -> R) -> R
pub fn dated<R>(&mut self, at: u64, edit: impl FnOnce(&mut Self) -> R) -> R
Makes the edits of edit as made at at, in milliseconds since the
Unix epoch, such as messages imported at the times their source
logged them: their records carry that time, which a writer keeps,
and the entries they make were made then. An edit dated inside, by a
nested call, keeps its own time.
use rig_core::conversation::Conversation;
use rig_core::message::Message;
let mut conversation = Conversation::new();
conversation.dated(1_790_848_800_000, |conversation| {
conversation.push(Message::user("Imported"))
});
let at = conversation.unsaved().first().and_then(|recorded| recorded.at);
assert_eq!(at, Some(1_790_848_800_000));Sourcepub fn unsaved(&self) -> &[ChangeRecord]
pub fn unsaved(&self) -> &[ChangeRecord]
The changes made that nobody has saved yet, oldest first.
Sourcepub fn take_unsaved(&mut self) -> Vec<ChangeRecord>
pub fn take_unsaved(&mut self) -> Vec<ChangeRecord>
Takes the changes made that nobody has saved yet, to save them.
Sourcepub fn revision(&self) -> u64
pub fn revision(&self) -> u64
The changes behind this value, one per record: those of the log it
continues (lineage) when it was last loaded or
saved, then each applied or made since. An unsaved aside counts
none.
Sourcepub fn lineage(&self) -> Lineage
pub fn lineage(&self) -> Lineage
The saved log this value continues: Lineage::EMPTY when it was
begun here from nothing and never saved, Lineage::DETACHED when
it was read back from its serde form.
Sourcepub fn continues(&self, lineage: Lineage, changes: u64) -> bool
pub fn continues(&self, lineage: Lineage, changes: u64) -> bool
Whether this value’s unsaved changes, appended to the log of
lineage that holds changes changes, give this value: it
continues that log, holding all of its changes and since then only
its unsaved ones. A value begun here from nothing continues any
empty log.
Sourcepub fn continue_log(&mut self, lineage: Lineage, changes: u64)
pub fn continue_log(&mut self, lineage: Lineage, changes: u64)
Marks this value as holding the changes changes of the log of
lineage, then its unsaved ones: what a store does once it loaded
the value from that log or saved it there.
Sourcepub fn view(&self) -> Self
pub fn view(&self) -> Self
A copy with an empty outbox, for edits never saved (a preview, a reset’s state).
Sourcepub fn request_view(&self) -> Self
pub fn request_view(&self) -> Self
A view without the asides, for a model request’s
copy: a request never sends them, and one is built per model call.
Trait Implementations§
Source§impl Clone for Conversation
impl Clone for Conversation
Source§impl Debug for Conversation
impl Debug for Conversation
Source§impl Default for Conversation
impl Default for Conversation
Source§impl<'de> Deserialize<'de> for Conversation
impl<'de> Deserialize<'de> for Conversation
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl PartialEq for Conversation
impl PartialEq for Conversation
Auto Trait Implementations§
impl Freeze for Conversation
impl RefUnwindSafe for Conversation
impl Send for Conversation
impl Sync for Conversation
impl Unpin for Conversation
impl UnsafeUnpin for Conversation
impl UnwindSafe for Conversation
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more