The native backend: every port, as files and calls on this machine.
3use std::path::PathBuf;
5use log::error; 6use whiskers_ports::{ 7 HasAllowance, HasChat, HasClock, HasEmbedder, HasHousehold, HasIcons, HasJournal, HasJudge, HasMemory, HasPictures, HasThinker, HasVoice, 8}; 9 10use crate::allowance::FileAllowance; 11use crate::clock::SystemClock; 12use crate::embed::LlamaEmbedder; 13use crate::hubs::{FileChatHub, FileHouseholdHub, FileMemoryHub}; 14use crate::journal::FileJournal; 15use crate::judge::JevJudge; 16use crate::model::GatewayThinker; 17use crate::pictures::DirShelf; 18use crate::secrets::EnvSecrets; 19use crate::speak::ElevenLabsVoice;
Why the service could not start. The process exits with exit_code.
A setting is missing or wrong: the operator has something to fix. Exit code 2.
25 Configuration(String),
30impl StartError { 31 pub fn exit_code(&self) -> i32 { 32 match self { 33 StartError::Configuration(_) => 2, 34 StartError::Storage(_) => 1, 35 } 36 } 37} 38 39impl std::fmt::Display for StartError { 40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 41 match self { 42 StartError::Configuration(m) | StartError::Storage(m) => f.write_str(m), 43 } 44 } 45} 46 47pub struct Native { 48 memory: FileMemoryHub, 49 household: FileHouseholdHub, 50 chat: FileChatHub, 51 journal: FileJournal, 52 pictures: DirShelf, 53 allowance: FileAllowance, 54 judge: JevJudge, 55 embedder: LlamaEmbedder, 56 icons: whiskers_ports::IconVectors, 57 voice: ElevenLabsVoice<EnvSecrets>, 58 thinker: GatewayThinker, 59 clock: SystemClock, 60}
Where the hubs keep their documents: $HOME/.local/share/whiskers.
71impl Native {
Everything the service needs, from the environment and the data directory.
73 pub fn from_env() -> Result<Self, StartError> { 74 let secrets = EnvSecrets::process(); 75 let judge = JevJudge::start(&secrets); 76 let voice = ElevenLabsVoice::new(secrets); 77 whiskers_ports::run_ready(voice.report_configuration()); 78 let allowance = FileAllowance::from_env(); 79 let thinker = GatewayThinker::from_env().map_err(|e| { 80 error!("cannot start: {e}"); 81 StartError::Configuration(e) 82 })?; 83 let embedder = LlamaEmbedder::from_env(); 84 let dir = hub_dir(); 85 let memory = FileMemoryHub::open(&dir.join("memory-hub.json")).map_err(|e| StartError::Storage(format!("cannot open the shared memory: {e}")))?; 86 Ok(Self { 87 memory, 88 household: FileHouseholdHub::open(&dir.join("household-hub.json")), 89 chat: FileChatHub::open(&dir.join("chat-hub.json")), 90 journal: FileJournal::open(&dir.join("journal")), 91 pictures: DirShelf::open(&dir.join("pictures")), 92 allowance, 93 judge, 94 embedder, 95 icons: whiskers_ports::IconVectors::default(), 96 voice, 97 thinker, 98 clock: SystemClock, 99 }) 100 } 101}
Every capability: the native binary is a complete Backend, and Service::complete holds it to that.
104impl HasMemory for Native { 105 type Memory = FileMemoryHub; 106 fn memory(&self) -> &FileMemoryHub { 107 &self.memory 108 } 109} 110impl HasHousehold for Native { 111 type Household = FileHouseholdHub; 112 fn household(&self) -> &FileHouseholdHub { 113 &self.household 114 } 115} 116impl HasChat for Native { 117 type Chat = FileChatHub; 118 fn chat(&self) -> &FileChatHub { 119 &self.chat 120 } 121} 122impl HasJournal for Native { 123 type Journal = FileJournal; 124 fn journal(&self) -> &FileJournal { 125 &self.journal 126 } 127} 128impl HasPictures for Native { 129 type Pictures = DirShelf; 130 fn pictures(&self) -> &DirShelf { 131 &self.pictures 132 } 133} 134impl HasAllowance for Native { 135 type Allowance = FileAllowance; 136 fn allowance(&self) -> &FileAllowance { 137 &self.allowance 138 } 139} 140impl HasJudge for Native { 141 type Judge = JevJudge; 142 fn judge(&self) -> &JevJudge { 143 &self.judge 144 } 145} 146impl HasEmbedder for Native { 147 type Embedder = LlamaEmbedder; 148 fn embedder(&self) -> &LlamaEmbedder { 149 &self.embedder 150 } 151} 152impl HasIcons for Native { 153 fn icon_vectors(&self) -> &whiskers_ports::IconVectors { 154 &self.icons 155 } 156} 157impl HasVoice for Native { 158 type Voice = ElevenLabsVoice<EnvSecrets>; 159 fn voice(&self) -> &ElevenLabsVoice<EnvSecrets> { 160 &self.voice 161 } 162} 163impl HasThinker for Native { 164 type Thinker = GatewayThinker; 165 fn thinker(&self) -> &GatewayThinker { 166 &self.thinker 167 } 168} 169impl HasClock for Native { 170 type Clock = SystemClock; 171 fn clock(&self) -> &SystemClock { 172 &self.clock 173 } 174}