+19
-2
deno.lock
+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
+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
+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
+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
+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
+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, };