1use serde::{Deserialize, Serialize}; 2 3use crate::chat::ChatState; 4use crate::profile::Age; 5use whiskers_icons::IconId; 6use crate::types::{Direction, Entry, Fact, Image, MemorySnapshot, NewFact, PictureId, Turn, Verdict}; 7 8/// The model could not answer. `resting` is the one reason that is not a fault: the time the 9/// grown-ups allow for thinking is used up for now, which the child is told differently. 10#[derive(Debug)] 11pub struct ModelError { 12 pub reason: String, 13 pub resting: bool, 14} 15 16impl ModelError { 17 pub fn new(reason: impl Into<String>) -> Self { 18 Self { reason: reason.into(), resting: false } 19 } 20 21 pub fn resting(reason: impl Into<String>) -> Self { 22 Self { reason: reason.into(), resting: true } 23 } 24} 25#[derive(Debug)] 26pub struct GuardError(pub String); 27#[derive(Debug)] 28pub struct LogError(pub String); 29#[derive(Debug)] 30pub struct PictureError(pub String); 31#[derive(Debug)] 32pub struct MemoryError(pub String); 33#[derive(Debug)] 34pub struct EmbedError(pub String); 35#[derive(Debug)] 36pub struct RankError(pub String); 37#[derive(Debug)] 38pub struct ChatError(pub String); 39#[derive(Debug)] 40pub struct IconError(pub String); 41 42/// Where a turn failed, for the log. 43#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] 44pub enum FailureStage { 45 GuardingInput, 46 Model, 47 GuardingOutput, 48 Remembering, 49 SavingChat, 50} 51 52/// The language model, reached through the gateway. The last turn in 53/// `history` is the one to answer and may carry pictures. 54pub trait Model: Send + Sync { 55 fn complete(&self, system: &str, history: &[Turn]) -> Result<String, ModelError>; 56} 57 58/// Decides whether a message may pass, judged for a child of `age`. An `Err` is not an 59/// `Allow`: the pipeline treats a guard it cannot reach as a refusal. The guard is given the 60/// age and nothing else about the child: the name cannot reach it. 61pub trait Guard: Send + Sync { 62 fn check(&self, direction: Direction, age: Age, text: &str) -> Result<Verdict, GuardError>; 63} 64 65/// The parents' record. Append-only. 66pub trait Log { 67 fn append(&mut self, entry: &Entry) -> Result<(), LogError>; 68} 69 70/// Keeps what she shows Whiskers, so the parents can see it too. 71pub trait Pictures { 72 fn save(&mut self, image: &Image) -> Result<PictureId, PictureError>; 73} 74 75/// What Whiskers remembers between conversations. 76pub trait Memory: Send { 77 fn facts(&self) -> Vec<Fact>; 78 fn add(&mut self, new: NewFact, at_ms: u64) -> Result<Fact, MemoryError>; 79 fn set_embedding(&mut self, id: u64, embedding: Vec<f32>) -> Result<(), MemoryError>; 80 fn forget(&mut self, id: u64) -> Result<Fact, MemoryError>; 81 /// Gives a fact its picture if it has none yet (the first choice is kept). 82 fn give_icon(&mut self, id: u64, icon: IconId) -> Result<Fact, MemoryError>; 83 /// She puts a fact away: it stays, the parents still see it, Whiskers stops using it. Not `forget`. 84 fn hide(&mut self, id: u64, at_ms: u64) -> Result<Fact, MemoryError>; 85 /// A parent restores a fact she put away. 86 fn restore(&mut self, id: u64, at_ms: u64) -> Result<Fact, MemoryError>; 87 /// What this device knows, for another to merge. 88 fn snapshot(&self) -> MemorySnapshot; 89 /// Takes in what another device knows. Returns how many facts changed here. 90 fn merge(&mut self, remote: MemorySnapshot) -> Result<usize, MemoryError>; 91} 92 93/// Chooses the picture for a fact from the admitted set. `Ok(None)` is an answer ("none fits"); an `Err` is 94/// "could not decide" and is worth trying again later. Never an error shown to the child: a fact with no picture 95/// simply shows a generic star. 96pub trait IconChooser: Send + Sync { 97 fn choose(&self, text: &str) -> Result<Option<IconId>, IconError>; 98} 99 100/// Chooses nothing; for a device with no service to ask. 101pub struct NoIcons; 102 103impl IconChooser for NoIcons { 104 fn choose(&self, _text: &str) -> Result<Option<IconId>, IconError> { 105 Err(IconError("no service to ask".into())) 106 } 107} 108 109/// Turns text into vectors that are close when the meanings are. 110pub trait Embedder: Send + Sync { 111 fn embed(&self, texts: &[String]) -> Result<Vec<Vec<f32>>, EmbedError>; 112} 113 114/// Says how well each candidate memory fits a message: a probability each, same order. 115pub trait Ranker: Send + Sync { 116 fn rank(&self, query: &str, candidates: &[String]) -> Result<Vec<f32>, RankError>; 117} 118 119/// Keeps the running chat between launches. 120pub trait ChatStore: Send { 121 fn load(&self) -> Result<ChatState, ChatError>; 122 fn save(&mut self, state: &ChatState) -> Result<(), ChatError>; 123} 124 125pub trait Clock: Send + Sync { 126 fn now_ms(&self) -> u64; 127}