WIP push-to-talk Letta chat frontend

stub frontend state machine

graham.systems 00c54789 dbf098ea

verified
Changed files
+362 -145
src
src-tauri
src
cartesia
+19 -2
deno.lock
··· 19 19 "npm:@tauri-apps/plugin-positioner@2.3": "2.3.0", 20 20 "npm:@tauri-apps/plugin-store@2.4": "2.4.0", 21 21 "npm:@tauri-apps/plugin-window-state@2.4": "2.4.0", 22 + "npm:@xstate/svelte@5": "5.0.0_svelte@5.38.3__acorn@8.15.0_xstate@5.21.0", 22 23 "npm:svelte-check@4": "4.3.1_svelte@5.38.3__acorn@8.15.0_typescript@5.6.3", 23 24 "npm:svelte@5": "5.38.3_acorn@8.15.0", 24 25 "npm:tailwindcss@^4.1.12": "4.1.12", 25 26 "npm:typescript@~5.6.2": "5.6.3", 26 - "npm:vite@^6.0.3": "6.3.5_picomatch@4.0.3" 27 + "npm:vite@^6.0.3": "6.3.5_picomatch@4.0.3", 28 + "npm:xstate@^5.21.0": "5.21.0" 27 29 }, 28 30 "jsr": { 29 31 "@std/async@1.0.14": { ··· 670 672 "@types/estree@1.0.8": { 671 673 "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==" 672 674 }, 675 + "@xstate/svelte@5.0.0_svelte@5.38.3__acorn@8.15.0_xstate@5.21.0": { 676 + "integrity": "sha512-VZABqXXwKIpnEDIoz5Vb7P1C+4rIivxG8u3eNqCKW048cVg7eHBXc4lr+icwXQitSJG/fJSmfgvSGYjn9ouuRQ==", 677 + "dependencies": [ 678 + "svelte", 679 + "xstate" 680 + ], 681 + "optionalPeers": [ 682 + "xstate" 683 + ] 684 + }, 673 685 "acorn@8.15.0": { 674 686 "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", 675 687 "bin": true ··· 1119 1131 "vite" 1120 1132 ] 1121 1133 }, 1134 + "xstate@5.21.0": { 1135 + "integrity": "sha512-y4wmqxjyAa0tgz4k3m/MgTF1kDOahE5+xLfWt5eh1sk+43DatLhKlI8lQDJZpvihZavjbD3TUgy2PRMphhhqgQ==" 1136 + }, 1122 1137 "yallist@5.0.0": { 1123 1138 "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==" 1124 1139 }, ··· 1149 1164 "npm:@tauri-apps/plugin-positioner@2.3", 1150 1165 "npm:@tauri-apps/plugin-store@2.4", 1151 1166 "npm:@tauri-apps/plugin-window-state@2.4", 1167 + "npm:@xstate/svelte@5", 1152 1168 "npm:svelte-check@4", 1153 1169 "npm:svelte@5", 1154 1170 "npm:tailwindcss@^4.1.12", 1155 1171 "npm:typescript@~5.6.2", 1156 - "npm:vite@^6.0.3" 1172 + "npm:vite@^6.0.3", 1173 + "npm:xstate@^5.21.0" 1157 1174 ] 1158 1175 } 1159 1176 }
+3 -1
package.json
··· 26 26 "@tauri-apps/plugin-positioner": "~2.3.0", 27 27 "@tauri-apps/plugin-store": "~2.4.0", 28 28 "@tauri-apps/plugin-window-state": "~2.4.0", 29 - "tailwindcss": "^4.1.12" 29 + "@xstate/svelte": "^5.0.0", 30 + "tailwindcss": "^4.1.12", 31 + "xstate": "^5.21.0" 30 32 }, 31 33 "devDependencies": { 32 34 "@sveltejs/adapter-static": "^3.0.6",
+2 -2
src-tauri/src/cartesia/commands.rs
··· 1 1 use tauri::ipc::Channel; 2 2 3 - use crate::{cartesia::stt::TranscriptionWord, state::AppState}; 3 + use crate::{cartesia::stt::SttTranscriptionWord, state::AppState}; 4 4 5 5 #[tauri::command] 6 6 pub async fn start_stt( 7 7 state: tauri::State<'_, AppState>, 8 - on_event: Channel<TranscriptionWord>, 8 + on_event: Channel<SttTranscriptionWord>, 9 9 ) -> Result<(), ()> { 10 10 let mut rec = state.stt_manager.transcribe().await; 11 11
+8 -6
src-tauri/src/cartesia/stt.rs
··· 10 10 use tauri::async_runtime::{channel, spawn, Mutex, Receiver, RwLock, Sender}; 11 11 use tokio::net::TcpStream; 12 12 use tokio_tungstenite::{MaybeTlsStream, WebSocketStream}; 13 + use ts_rs::TS; 13 14 use tungstenite::{Bytes, Error, Message, Utf8Bytes}; 14 15 15 16 #[derive(Debug)] ··· 28 29 input: Arc<InputDeviceManager>, 29 30 } 30 31 31 - #[derive(Deserialize, Debug, Serialize)] 32 - pub struct TranscriptionWord { 32 + #[derive(Deserialize, Debug, Serialize, TS)] 33 + #[ts(export)] 34 + pub struct SttTranscriptionWord { 33 35 word: String, 34 36 start: f32, 35 37 end: f32, ··· 44 46 text: String, 45 47 duration: Option<f32>, 46 48 language: Option<String>, 47 - words: Option<Vec<TranscriptionWord>>, 49 + words: Option<Vec<SttTranscriptionWord>>, 48 50 }, 49 51 Error { 50 52 message: String, ··· 68 70 } 69 71 70 72 /// Begins transcribing text via Cartesia. Blocks until `stop_transcription` is called 71 - pub async fn transcribe(&self) -> Receiver<TranscriptionWord> { 73 + pub async fn transcribe(&self) -> Receiver<SttTranscriptionWord> { 72 74 { 73 75 let mut status = self.status.write().await; 74 76 *status = SttStatus::Opening; ··· 77 79 let input = self.input.start_listening().await; 78 80 let stream = self.client.open_stt_connection().await; 79 81 let (socket_in, socket_out) = stream.split(); 80 - let (fn_in, fn_out) = channel::<TranscriptionWord>(500); 82 + let (fn_in, fn_out) = channel::<SttTranscriptionWord>(500); 81 83 let writer = Arc::new(Mutex::new(socket_in)); 82 84 83 85 { ··· 114 116 input: Arc<InputDeviceManager>, 115 117 mut socket_reader: SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>, 116 118 socket_writer: Arc<Mutex<SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, Message>>>, 117 - out_writer: Sender<TranscriptionWord>, 119 + out_writer: Sender<SttTranscriptionWord>, 118 120 ) { 119 121 while let Some(message) = socket_reader.next().await { 120 122 match message {
+326
src/lib/actors/conversation.ts
··· 1 + import { setup, fromPromise, assign, emit } from "xstate"; 2 + import { invoke, Channel } from "@tauri-apps/api/core"; 3 + import type { LettaCompletionMessage } from "../rust/LettaCompletionMessage.ts"; 4 + import type { SttTranscriptionWord } from "../rust/SttTranscriptionWord.ts"; 5 + 6 + interface Context { 7 + draft: string; 8 + history: Array<LettaCompletionMessage>; 9 + responseInProgress?: LettaCompletionMessage; 10 + } 11 + 12 + type Event = 13 + | { 14 + type: "stt.start"; 15 + } 16 + | { 17 + type: "stt.transcribed"; 18 + word: SttTranscriptionWord; 19 + } 20 + | { 21 + type: "stt.stop"; 22 + } 23 + | { 24 + type: "stt.error"; 25 + } 26 + | { 27 + type: "message.start"; 28 + msg: LettaCompletionMessage; 29 + } 30 + | { 31 + type: "message.update"; 32 + msg: LettaCompletionMessage; 33 + } 34 + | { 35 + type: "message.done"; 36 + msg: LettaCompletionMessage; 37 + } 38 + | { 39 + type: "turn.unfinished"; 40 + } 41 + | { 42 + type: "turn.finished"; 43 + } 44 + | { 45 + type: "tts.speak"; 46 + } 47 + | { 48 + type: "tts.progress"; 49 + } 50 + | { 51 + type: "tts.stop"; 52 + } 53 + | { 54 + type: "tts.error"; 55 + } 56 + | { 57 + type: "interrupt"; 58 + } 59 + | { 60 + type: "draft.start"; 61 + } 62 + | { 63 + type: "draft.update"; 64 + draft: string; 65 + } 66 + | { 67 + type: "draft.submit"; 68 + draft: string; 69 + } 70 + | { 71 + type: "draft.abandon"; 72 + }; 73 + 74 + export const conversation = setup({ 75 + types: { 76 + context: {} as Context, 77 + events: {} as Event, 78 + }, 79 + actors: { 80 + stt: fromPromise<void, undefined, Event>(async ({ emit }) => { 81 + const onEvent = new Channel<SttTranscriptionWord>(); 82 + 83 + onEvent.onmessage = (word) => { 84 + emit({ type: "stt.transcribed", word }); 85 + }; 86 + 87 + await invoke("start_stt", { onEvent }); 88 + }), 89 + startCompletion: fromPromise<void, { prompt: string }, Event>( 90 + async ({ input: { prompt }, emit }) => { 91 + const onEvent = new Channel<LettaCompletionMessage>(); 92 + 93 + onEvent.onmessage = (msg) => { 94 + // emit({ type: "message.start", msg }) 95 + 96 + emit({ type: "message.update", msg }); 97 + 98 + // emit({ type: "message.done", msg }) 99 + }; 100 + 101 + await invoke("start_llm_completion", { prompt, onEvent }); 102 + } 103 + ), 104 + }, 105 + actions: { 106 + async stopStt() { 107 + await invoke("stop_stt"); 108 + }, 109 + updateDraft: assign({ 110 + draft: ({ context, event }) => { 111 + switch (event.type) { 112 + case "draft.update": 113 + return event.draft; 114 + case "stt.transcribed": 115 + return context.draft + event.word.word; 116 + default: 117 + return context.draft; 118 + } 119 + }, 120 + }), 121 + resetDraft: assign({ draft: "" }), 122 + commitDraft: assign({ 123 + history: ({ context }, params: { draft: string }) => { 124 + const history = context.history; 125 + const message: LettaCompletionMessage = { 126 + id: crypto.randomUUID(), 127 + date: new Date().toISOString(), 128 + message_type: "user_message", 129 + content: [{ type: "text", text: params.draft }], 130 + is_err: false, 131 + name: null, 132 + otid: null, 133 + run_id: null, 134 + sender_id: null, 135 + seq_id: null, 136 + step_id: null, 137 + }; 138 + 139 + history.push(message); 140 + 141 + return new Array(...history); 142 + }, 143 + }), 144 + }, 145 + guards: { 146 + hasDraft({ context }) { 147 + return Boolean(context.draft.trim()); 148 + }, 149 + }, 150 + }).createMachine({ 151 + /** @xstate-layout N4IgpgJg5mDOIC5QGMD2A7AbmATrAhgC4CWGAdMRADZgDEEO+AZoWbIfjoQNoAMAuolAAHVLGIkMQkAA9EAZgAsARjIA2AKxqATFrUBOAOyKjygDQgAnomVreZE-v3zeADiO95aw-IC+vizQsXAJJdApqOnZWdk4eAWlRcTDpOQQlVU0dPSMTQ3MrRG1FbTINXgqlQ29eHWVtf0CMbDwiUnCGZhJ0KHpGFjYAVwAjAFsJPkEkECSJdtTEDW0LawRlDQ1DMkMnNXXaww1FVw1GkCCW0PayTpZiHr6usnxh-HQIDEnEsTmpabT5PJMlpdGoDMZTCtEK5tK4yNonBpXHttOstK4zhcQm1yLdulAyIRGOhYMgcMRhvdeh90GAKFhUABrOlY1phG79fGE4mk8mUnoIe6YVDIHHoSZfaazFL-Gy8ZRw3iKAyo7TaeSbVyuKEIRQbMo+WrKJWGHa1U4Bc7NbHsvFU7lvXkUqm0XA4VA4MjCKhEJge0ZkVlXXGc+1Ex1k50CoUisUShJSn4y0BpY0KshKlX1dWa7WFBBqZFkdZqeSG-TaPYKzHWtnXO09B0kyP83rRNiEVDCSUiJPzWUF+SlTMnfLG-T1Qw6xSKeRkfQaFyaVzHdzymvBOshrphnktl3t8PNvmQHszPt-FOIUvD5VawyuU2uXj6HUItTzpz6GGuIdK-R6hulxihyO6NmgoyzA8eJkIMwgQEQYBntK-ZXgg2ieHOJT6GCj5KsU6w6kCcL1BUsKOGW8pqEBNr1qG4GoJBPwPO2sRcMhF7oAsayHFsrj1Ecyg7Js3hqERQkGkuyjyFqGq8KaNFbh09EEm6HqQI8AywCM4zxFMvbJKhsg2Eo9iKNU6L4d+r75ho+j2JsLglMo9k7NJinBspYGqTg7o4BpMFwQhhBIQmBm-FxA62EY2zlLwaqAmCLlifmYL2CuaizlqdgueZHkgRB3pgFyVDEOwYDoPalA0LQoxwAQMAdnEHGGZexk8boZBKF4exLDlXg6gqsIZvFY4IrwdmPvl7KFTQJVlSFlWNkFbQPHVsANXSK0hS1EXcaiShdXZCKotkaqDYY2hbC4V3OIumrHNN1yzcV9qleVS0EttLrrZtNwYKF+nnq1kVoUJnXdUlfXygN+a2JdI2VjotSlusT3kC980ffatIyIQtX1fgjVsXp3wg9xWqlBqFZarO34KgUqwuXZsWVi+K4Igqijo+EmNvQtFU42AeO0IQgw4OEgzoEw9xlQAFqeYXA3tA6U0dNMrvI9P8YN-FwrolZ62a3g84GjFFVji1CyLYsS2QMuVbACsQLtybtWr1Owpr2uMzYi76Ij1R2EcM4lP4lroKgEBwNIQZimTKtoQAtClqwI1+E5Xai6zGNzlpx+y1VgAnbtpCUF0fo437Pr+arGNR+e1p5oF3D0JdGWkSKKBmd6bMo46ToNmgjRUDOHI+zgNI3m7Nw2BJHk6rbt21aT5HCvH8XYdgzu4Op2Ro861FdLmAkCGym3PZtMeIbeJuTA4YWWxaKBNj71MqRjyNO5SSRNlbOMocyXgL4qTIGpfyEBl6g3atJWoGYgRXRftJQsWgdTeC2I5eKCJJ7EVNnzW+4VS4KBwp+JwKglTlH4ooQagD159TXiYeopY8HmzmvaGAtJGD4igdxZUpQM7kL1G4QBg1YT2EOP-Z8Ws3D6BYZBNhjZ3pWwIcrIhuoZykIAsaIRVDBpawDhIwsQljD5FnHIi2-NsaNiLjwqKlY5yewnPKZEE4pxwxhMOUa9RcpCUetPYCM1WGvUUQLT6sF4KrSgLYtCqI4GQ0yto+8GhdaAjIM+Y+FRnCGE8BifxtEMZBMtoLRsuNCDRPaiYfhX5BGUJEXDDYcJ7L-0zrCQBFomgzwKoUyxyiCQ0mLnfROMD7Hq05s4gwQlBqLlUBI7JOxMroPDr4IAA */ 152 + id: "conversation", 153 + initial: "idle", 154 + context: { 155 + draft: "", 156 + history: [], 157 + }, 158 + states: { 159 + idle: { 160 + description: "Waiting for the user to compose a draft", 161 + on: { 162 + "draft.start": { 163 + description: "User composing draft with text", 164 + target: "drafting.composing", 165 + }, 166 + "stt.start": { 167 + description: "User composing draft with voice", 168 + target: "drafting.transcribing", 169 + }, 170 + }, 171 + }, 172 + drafting: { 173 + description: "User is drafting a prompt for the agent", 174 + states: { 175 + transcribing: { 176 + description: "User is actively using STT", 177 + invoke: { 178 + src: "stt", 179 + onDone: { 180 + description: "STT invocation finished without error", 181 + target: "composing", 182 + }, 183 + onError: { 184 + target: "errored", 185 + }, 186 + }, 187 + on: { 188 + "stt.stop": { 189 + description: 190 + "User finished with STT; stop the backend transcription process", 191 + actions: ["stopStt"], 192 + }, 193 + "stt.transcribed": { 194 + description: 195 + "Backend emitted a transcription event; append to draft", 196 + actions: ["updateDraft"], 197 + }, 198 + }, 199 + exit: ["stopStt"], 200 + }, 201 + composing: { 202 + description: "User is editing the draft via textarea", 203 + on: { 204 + "draft.update": { 205 + description: "onChange event fired, update draft", 206 + actions: ["updateDraft"], 207 + }, 208 + "stt.start": { 209 + description: "User switching to voice; start STT", 210 + target: "transcribing", 211 + }, 212 + }, 213 + }, 214 + errored: { 215 + description: 216 + "Backend encountered an error, likely during transcription", 217 + on: { 218 + "draft.submit": { 219 + description: "User submitted draft in error state; disallow", 220 + }, 221 + "draft.update": { 222 + description: "User is manually correcting prompt; recover", 223 + actions: ["updateDraft"], 224 + target: "composing", 225 + }, 226 + }, 227 + }, 228 + }, 229 + on: { 230 + "draft.submit": { 231 + description: 232 + "If we have a draft, submit it to history and start completion", 233 + guard: "hasDraft", 234 + target: "completing", 235 + actions: [ 236 + { 237 + type: "commitDraft", 238 + params: ({ context }) => ({ draft: context.draft }), 239 + }, 240 + "resetDraft", 241 + ], 242 + }, 243 + "draft.abandon": { 244 + description: "User changed their mind about the current draft", 245 + target: "idle", 246 + actions: ["resetDraft"], 247 + }, 248 + }, 249 + }, 250 + completing: { 251 + description: 252 + "Present the written prompt to Letta and Cartesia TTS for completion", 253 + type: "parallel", 254 + states: { 255 + generating: { 256 + description: "Start completion turn and emit events from the backend", 257 + invoke: { 258 + src: "startCompletion", 259 + input: ({ context, event }) => ({ 260 + prompt: 261 + event.type === "draft.submit" ? event.draft : context.draft, 262 + }), 263 + }, 264 + }, 265 + listening: { 266 + description: 267 + "Represent the state of the backend process from emitted events", 268 + initial: "idle", 269 + states: { 270 + idle: { 271 + description: 272 + "Completion has started, but we haven't recieved initial metadata yet", 273 + on: { 274 + "message.start": { 275 + description: "Message metadata recieved", 276 + target: "updating", 277 + }, 278 + }, 279 + }, 280 + updating: { 281 + description: 282 + "Backend is receiving streamed updates to the current message", 283 + on: { 284 + "message.update": { 285 + description: 286 + "New content chunk recieved; append to current message", 287 + actions: [], 288 + }, 289 + "message.done": { 290 + description: 291 + "All updates for the current message have been transmitted", 292 + target: "next", 293 + }, 294 + }, 295 + }, 296 + next: { 297 + description: "Requesting the next message in the completion turn", 298 + on: { 299 + "message.start": { 300 + description: 301 + "The backend already has metadata for the next message; immediately start streaming updates", 302 + target: "updating", 303 + }, 304 + "turn.unfinished": { 305 + description: 306 + "The current completion turn is not complete, but don't have the metadata for the next message yet", 307 + target: "idle", 308 + }, 309 + "turn.finished": { 310 + description: "All messages have been streamed to the client", 311 + target: "done", 312 + }, 313 + }, 314 + }, 315 + done: { 316 + description: 317 + "The current generated turn is complete; return to idle", 318 + type: "final", 319 + target: "#idle", 320 + }, 321 + }, 322 + }, 323 + }, 324 + }, 325 + }, 326 + });
+1 -134
src/lib/rust/LettaCompletionMessage.ts
··· 5 5 import type { LettaToolCall } from "./LettaToolCall"; 6 6 import type { LettaToolReturnStatus } from "./LettaToolReturnStatus"; 7 7 8 - export type LettaCompletionMessage = 9 - | { 10 - message_type: "system_message"; 11 - id: string; 12 - date: string; 13 - content: string; 14 - name: string | null; 15 - otid: string | null; 16 - sender_id: string | null; 17 - step_id: string | null; 18 - is_err: boolean | null; 19 - seq_id: bigint | null; 20 - run_id: string | null; 21 - } 22 - | { 23 - message_type: "user_message"; 24 - id: string; 25 - date: string; 26 - content: Array<LettaMessageContent>; 27 - name: string | null; 28 - otid: string | null; 29 - sender_id: string | null; 30 - step_id: string | null; 31 - is_err: boolean | null; 32 - seq_id: bigint | null; 33 - run_id: string | null; 34 - } 35 - | { 36 - message_type: "reasoning_message"; 37 - id: string; 38 - date: string; 39 - reasoning: string; 40 - name: string | null; 41 - otid: string | null; 42 - sender_id: string | null; 43 - step_id: string | null; 44 - is_err: boolean | null; 45 - seq_id: bigint | null; 46 - run_id: string | null; 47 - source: LettaReasoningSource | null; 48 - signature: string | null; 49 - } 50 - | { 51 - message_type: "hidden_reasoning_message"; 52 - id: string; 53 - date: string; 54 - state: LettaHiddenReasoningState; 55 - name: string | null; 56 - otid: string | null; 57 - sender_id: string | null; 58 - step_id: string | null; 59 - is_err: boolean | null; 60 - seq_id: bigint | null; 61 - run_id: string | null; 62 - hidden_reasoning: string | null; 63 - } 64 - | { 65 - message_type: "tool_call_message"; 66 - id: string; 67 - date: string; 68 - tool_call: LettaToolCall; 69 - name: string | null; 70 - otid: string | null; 71 - sender_id: string | null; 72 - step_id: string | null; 73 - is_err: boolean | null; 74 - seq_id: bigint | null; 75 - run_id: string | null; 76 - } 77 - | { 78 - message_type: "tool_return_message"; 79 - id: string; 80 - date: string; 81 - tool_return: string; 82 - status: LettaToolReturnStatus; 83 - tool_call_id: string; 84 - name: string | null; 85 - otid: string | null; 86 - sender_id: string | null; 87 - step_id: string | null; 88 - is_err: boolean | null; 89 - seq_id: bigint | null; 90 - run_id: string | null; 91 - stdout: Array<string> | null; 92 - stderr: Array<string> | null; 93 - } 94 - | { 95 - message_type: "assistant_message"; 96 - id: string; 97 - date: string; 98 - content: Array<LettaMessageContent>; 99 - name: string | null; 100 - otid: string | null; 101 - sender_id: string | null; 102 - step_id: string | null; 103 - is_err: boolean | null; 104 - seq_id: bigint | null; 105 - run_id: string | null; 106 - } 107 - | { 108 - message_type: "approval_request_message"; 109 - id: string; 110 - date: string; 111 - tool_call: LettaToolCall; 112 - name: string | null; 113 - otid: string | null; 114 - sender_id: string | null; 115 - step_id: string | null; 116 - is_err: boolean | null; 117 - seq_id: bigint | null; 118 - run_id: string | null; 119 - } 120 - | { 121 - message_type: "approval_response_message"; 122 - id: string; 123 - date: string; 124 - approve: boolean; 125 - approval_request_id: string; 126 - name: string | null; 127 - otid: string | null; 128 - sender_id: string | null; 129 - step_id: string | null; 130 - is_err: boolean | null; 131 - seq_id: bigint | null; 132 - run_id: string | null; 133 - reason: string | null; 134 - } 135 - | { message_type: "stop_reason"; stop_reason: string } 136 - | { 137 - message_type: "usage_statistics"; 138 - completion_tokens: bigint; 139 - prompt_tokens: bigint; 140 - step_count: bigint; 141 - }; 8 + export type LettaCompletionMessage = { "message_type": "system_message", id: string, date: string, content: string, name: string | null, otid: string | null, sender_id: string | null, step_id: string | null, is_err: boolean | null, seq_id: bigint | null, run_id: string | null, } | { "message_type": "user_message", id: string, date: string, content: Array<LettaMessageContent>, name: string | null, otid: string | null, sender_id: string | null, step_id: string | null, is_err: boolean | null, seq_id: bigint | null, run_id: string | null, } | { "message_type": "reasoning_message", id: string, date: string, reasoning: string, name: string | null, otid: string | null, sender_id: string | null, step_id: string | null, is_err: boolean | null, seq_id: bigint | null, run_id: string | null, source: LettaReasoningSource | null, signature: string | null, } | { "message_type": "hidden_reasoning_message", id: string, date: string, state: LettaHiddenReasoningState, name: string | null, otid: string | null, sender_id: string | null, step_id: string | null, is_err: boolean | null, seq_id: bigint | null, run_id: string | null, hidden_reasoning: string | null, } | { "message_type": "tool_call_message", id: string, date: string, tool_call: LettaToolCall, name: string | null, otid: string | null, sender_id: string | null, step_id: string | null, is_err: boolean | null, seq_id: bigint | null, run_id: string | null, } | { "message_type": "tool_return_message", id: string, date: string, tool_return: string, status: LettaToolReturnStatus, tool_call_id: string, name: string | null, otid: string | null, sender_id: string | null, step_id: string | null, is_err: boolean | null, seq_id: bigint | null, run_id: string | null, stdout: Array<string> | null, stderr: Array<string> | null, } | { "message_type": "assistant_message", id: string, date: string, content: Array<LettaMessageContent>, name: string | null, otid: string | null, sender_id: string | null, step_id: string | null, is_err: boolean | null, seq_id: bigint | null, run_id: string | null, } | { "message_type": "approval_request_message", id: string, date: string, tool_call: LettaToolCall, name: string | null, otid: string | null, sender_id: string | null, step_id: string | null, is_err: boolean | null, seq_id: bigint | null, run_id: string | null, } | { "message_type": "approval_response_message", id: string, date: string, approve: boolean, approval_request_id: string, name: string | null, otid: string | null, sender_id: string | null, step_id: string | null, is_err: boolean | null, seq_id: bigint | null, run_id: string | null, reason: string | null, } | { "message_type": "stop_reason", stop_reason: string, } | { "message_type": "usage_statistics", completion_tokens: bigint, prompt_tokens: bigint, step_count: bigint, };
+3
src/lib/rust/SttTranscriptionWord.ts
··· 1 + // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. 2 + 3 + export type SttTranscriptionWord = { word: string, start: number, end: number, };