1use super::frames::{
6 ClientFrame, SecretEntryDto, ServerFrame, ServerFrameType, ServerPayload, TaskInfoDto,
7 deserialize_frame, serialize_frame,
8};
9use anyhow::Result;
10use futures_util::SinkExt;
11use tokio_tungstenite::tungstenite::Message;
12
13pub async fn send_frame<S>(writer: &mut S, frame: &ServerFrame) -> Result<()>
16where
17 S: SinkExt<Message> + Unpin,
18{
19 let bytes = serialize_frame(frame).map_err(|e| anyhow::anyhow!("serialize failed: {}", e))?;
20 writer
21 .send(Message::Binary(bytes.into()))
22 .await
23 .map_err(|_e| anyhow::anyhow!("send failed"))
24}
25
26pub fn parse_client_frame(bytes: &[u8]) -> Result<ClientFrame> {
28 deserialize_frame(bytes).map_err(|e| anyhow::anyhow!("parse failed: {}", e))
29}
30
31pub async fn send_hello<S>(
33 writer: &mut S,
34 agent: &str,
35 settings_dir: &str,
36 vault_locked: bool,
37 provider: Option<&str>,
38 model: Option<&str>,
39) -> Result<()>
40where
41 S: SinkExt<Message> + Unpin,
42{
43 let frame = ServerFrame {
44 frame_type: ServerFrameType::Hello,
45 payload: ServerPayload::Hello {
46 agent: agent.into(),
47 settings_dir: settings_dir.into(),
48 vault_locked,
49 provider: provider.map(|s| s.into()),
50 model: model.map(|s| s.into()),
51 },
52 };
53 send_frame(writer, &frame).await
54}
55
56pub async fn send_auth_challenge<S>(writer: &mut S, method: &str) -> Result<()>
58where
59 S: SinkExt<Message> + Unpin,
60{
61 let frame = ServerFrame {
62 frame_type: ServerFrameType::AuthChallenge,
63 payload: ServerPayload::AuthChallenge {
64 method: method.into(),
65 },
66 };
67 send_frame(writer, &frame).await
68}
69
70pub async fn send_auth_result<S>(
72 writer: &mut S,
73 ok: bool,
74 message: Option<&str>,
75 retry: Option<bool>,
76) -> Result<()>
77where
78 S: SinkExt<Message> + Unpin,
79{
80 let frame = ServerFrame {
81 frame_type: ServerFrameType::AuthResult,
82 payload: ServerPayload::AuthResult {
83 ok,
84 message: message.map(|s| s.into()),
85 retry,
86 },
87 };
88 send_frame(writer, &frame).await
89}
90
91pub async fn send_error<S>(writer: &mut S, message: &str) -> Result<()>
93where
94 S: SinkExt<Message> + Unpin,
95{
96 let frame = ServerFrame {
97 frame_type: ServerFrameType::Error,
98 payload: ServerPayload::Error {
99 ok: false,
100 message: message.into(),
101 },
102 };
103 send_frame(writer, &frame).await
104}
105
106pub async fn send_info<S>(writer: &mut S, message: &str) -> Result<()>
108where
109 S: SinkExt<Message> + Unpin,
110{
111 let frame = ServerFrame {
112 frame_type: ServerFrameType::Info,
113 payload: ServerPayload::Info {
114 message: message.into(),
115 },
116 };
117 send_frame(writer, &frame).await
118}
119
120pub async fn send_status<S>(
122 writer: &mut S,
123 status: super::frames::StatusType,
124 detail: &str,
125) -> Result<()>
126where
127 S: SinkExt<Message> + Unpin,
128{
129 let frame = ServerFrame {
130 frame_type: ServerFrameType::Status,
131 payload: ServerPayload::Status {
132 status,
133 detail: detail.into(),
134 },
135 };
136 send_frame(writer, &frame).await
137}
138
139pub async fn send_vault_unlocked<S>(writer: &mut S, ok: bool, message: Option<&str>) -> Result<()>
141where
142 S: SinkExt<Message> + Unpin,
143{
144 let frame = ServerFrame {
145 frame_type: ServerFrameType::VaultUnlocked,
146 payload: ServerPayload::VaultUnlocked {
147 ok,
148 message: message.map(|s| s.into()),
149 },
150 };
151 send_frame(writer, &frame).await
152}
153
154pub async fn send_secrets_list_result<S>(
156 writer: &mut S,
157 ok: bool,
158 entries: Vec<SecretEntryDto>,
159) -> Result<()>
160where
161 S: SinkExt<Message> + Unpin,
162{
163 let frame = ServerFrame {
164 frame_type: ServerFrameType::SecretsListResult,
165 payload: ServerPayload::SecretsListResult { ok, entries },
166 };
167 send_frame(writer, &frame).await
168}
169
170pub async fn send_secrets_store_result<S>(writer: &mut S, ok: bool, message: &str) -> Result<()>
172where
173 S: SinkExt<Message> + Unpin,
174{
175 let frame = ServerFrame {
176 frame_type: ServerFrameType::SecretsStoreResult,
177 payload: ServerPayload::SecretsStoreResult {
178 ok,
179 message: message.into(),
180 },
181 };
182 send_frame(writer, &frame).await
183}
184
185pub async fn send_secrets_get_result<S>(
187 writer: &mut S,
188 ok: bool,
189 key: &str,
190 value: Option<&str>,
191 message: Option<&str>,
192) -> Result<()>
193where
194 S: SinkExt<Message> + Unpin,
195{
196 let frame = ServerFrame {
197 frame_type: ServerFrameType::SecretsGetResult,
198 payload: ServerPayload::SecretsGetResult {
199 ok,
200 key: key.into(),
201 value: value.map(|s| s.into()),
202 message: message.map(|s| s.into()),
203 },
204 };
205 send_frame(writer, &frame).await
206}
207
208pub async fn send_secrets_delete_result<S>(
210 writer: &mut S,
211 ok: bool,
212 message: Option<&str>,
213) -> Result<()>
214where
215 S: SinkExt<Message> + Unpin,
216{
217 let frame = ServerFrame {
218 frame_type: ServerFrameType::SecretsDeleteResult,
219 payload: ServerPayload::SecretsDeleteResult {
220 ok,
221 message: message.map(|s| s.into()),
222 },
223 };
224 send_frame(writer, &frame).await
225}
226
227pub async fn send_secrets_peek_result<S>(
229 writer: &mut S,
230 ok: bool,
231 fields: Vec<(String, String)>,
232 message: Option<&str>,
233) -> Result<()>
234where
235 S: SinkExt<Message> + Unpin,
236{
237 let frame = ServerFrame {
238 frame_type: ServerFrameType::SecretsPeekResult,
239 payload: ServerPayload::SecretsPeekResult {
240 ok,
241 fields,
242 message: message.map(|s| s.into()),
243 },
244 };
245 send_frame(writer, &frame).await
246}
247
248pub async fn send_secrets_set_policy_result<S>(
250 writer: &mut S,
251 ok: bool,
252 message: Option<&str>,
253) -> Result<()>
254where
255 S: SinkExt<Message> + Unpin,
256{
257 let frame = ServerFrame {
258 frame_type: ServerFrameType::SecretsSetPolicyResult,
259 payload: ServerPayload::SecretsSetPolicyResult {
260 ok,
261 message: message.map(|s| s.into()),
262 },
263 };
264 send_frame(writer, &frame).await
265}
266
267pub async fn send_secrets_set_disabled_result<S>(
269 writer: &mut S,
270 ok: bool,
271 message: Option<&str>,
272) -> Result<()>
273where
274 S: SinkExt<Message> + Unpin,
275{
276 let frame = ServerFrame {
277 frame_type: ServerFrameType::SecretsSetDisabledResult,
278 payload: ServerPayload::SecretsSetDisabledResult {
279 ok,
280 message: message.map(|s| s.into()),
281 },
282 };
283 send_frame(writer, &frame).await
284}
285
286pub async fn send_secrets_delete_credential_result<S>(
288 writer: &mut S,
289 ok: bool,
290 message: Option<&str>,
291) -> Result<()>
292where
293 S: SinkExt<Message> + Unpin,
294{
295 let frame = ServerFrame {
296 frame_type: ServerFrameType::SecretsDeleteCredentialResult,
297 payload: ServerPayload::SecretsDeleteCredentialResult {
298 ok,
299 message: message.map(|s| s.into()),
300 },
301 };
302 send_frame(writer, &frame).await
303}
304
305pub async fn send_secrets_has_totp_result<S>(writer: &mut S, has_totp: bool) -> Result<()>
307where
308 S: SinkExt<Message> + Unpin,
309{
310 let frame = ServerFrame {
311 frame_type: ServerFrameType::SecretsHasTotpResult,
312 payload: ServerPayload::SecretsHasTotpResult { has_totp },
313 };
314 send_frame(writer, &frame).await
315}
316
317pub async fn send_secrets_setup_totp_result<S>(
319 writer: &mut S,
320 ok: bool,
321 uri: Option<&str>,
322 message: Option<&str>,
323) -> Result<()>
324where
325 S: SinkExt<Message> + Unpin,
326{
327 let frame = ServerFrame {
328 frame_type: ServerFrameType::SecretsSetupTotpResult,
329 payload: ServerPayload::SecretsSetupTotpResult {
330 ok,
331 uri: uri.map(|s| s.into()),
332 message: message.map(|s| s.into()),
333 },
334 };
335 send_frame(writer, &frame).await
336}
337
338pub async fn send_secrets_verify_totp_result<S>(
340 writer: &mut S,
341 ok: bool,
342 message: Option<&str>,
343) -> Result<()>
344where
345 S: SinkExt<Message> + Unpin,
346{
347 let frame = ServerFrame {
348 frame_type: ServerFrameType::SecretsVerifyTotpResult,
349 payload: ServerPayload::SecretsVerifyTotpResult {
350 ok,
351 message: message.map(|s| s.into()),
352 },
353 };
354 send_frame(writer, &frame).await
355}
356
357pub async fn send_secrets_remove_totp_result<S>(
359 writer: &mut S,
360 ok: bool,
361 message: Option<&str>,
362) -> Result<()>
363where
364 S: SinkExt<Message> + Unpin,
365{
366 let frame = ServerFrame {
367 frame_type: ServerFrameType::SecretsRemoveTotpResult,
368 payload: ServerPayload::SecretsRemoveTotpResult {
369 ok,
370 message: message.map(|s| s.into()),
371 },
372 };
373 send_frame(writer, &frame).await
374}
375
376pub async fn send_reload_result<S>(
378 writer: &mut S,
379 ok: bool,
380 provider: &str,
381 model: &str,
382 message: Option<&str>,
383) -> Result<()>
384where
385 S: SinkExt<Message> + Unpin,
386{
387 let frame = ServerFrame {
388 frame_type: ServerFrameType::ReloadResult,
389 payload: ServerPayload::ReloadResult {
390 ok,
391 provider: provider.into(),
392 model: model.into(),
393 message: message.map(|s| s.into()),
394 },
395 };
396 send_frame(writer, &frame).await
397}
398
399pub async fn send_chunk<S>(writer: &mut S, delta: &str) -> Result<()>
401where
402 S: SinkExt<Message> + Unpin,
403{
404 let frame = ServerFrame {
405 frame_type: ServerFrameType::Chunk,
406 payload: ServerPayload::Chunk {
407 delta: delta.into(),
408 },
409 };
410 send_frame(writer, &frame).await
411}
412
413pub async fn send_response_done<S>(writer: &mut S, ok: bool) -> Result<()>
415where
416 S: SinkExt<Message> + Unpin,
417{
418 let frame = ServerFrame {
419 frame_type: ServerFrameType::ResponseDone,
420 payload: ServerPayload::ResponseDone { ok },
421 };
422 send_frame(writer, &frame).await
423}
424
425pub async fn send_stream_start<S>(writer: &mut S) -> Result<()>
427where
428 S: SinkExt<Message> + Unpin,
429{
430 let frame = ServerFrame {
431 frame_type: ServerFrameType::StreamStart,
432 payload: ServerPayload::StreamStart,
433 };
434 send_frame(writer, &frame).await
435}
436
437pub async fn send_tool_call<S>(writer: &mut S, id: &str, name: &str, arguments: &str) -> Result<()>
439where
440 S: SinkExt<Message> + Unpin,
441{
442 let frame = ServerFrame {
443 frame_type: ServerFrameType::ToolCall,
444 payload: ServerPayload::ToolCall {
445 id: id.into(),
446 name: name.into(),
447 arguments: arguments.into(),
448 },
449 };
450 send_frame(writer, &frame).await
451}
452
453pub async fn send_tool_result<S>(
455 writer: &mut S,
456 id: &str,
457 name: &str,
458 result: &str,
459 is_error: bool,
460) -> Result<()>
461where
462 S: SinkExt<Message> + Unpin,
463{
464 let frame = ServerFrame {
465 frame_type: ServerFrameType::ToolResult,
466 payload: ServerPayload::ToolResult {
467 id: id.into(),
468 name: name.into(),
469 result: result.into(),
470 is_error,
471 },
472 };
473 send_frame(writer, &frame).await
474}
475
476pub async fn send_tool_approval_request<S>(
478 writer: &mut S,
479 id: &str,
480 name: &str,
481 arguments: &str,
482) -> Result<()>
483where
484 S: SinkExt<Message> + Unpin,
485{
486 let frame = ServerFrame {
487 frame_type: ServerFrameType::ToolApprovalRequest,
488 payload: ServerPayload::ToolApprovalRequest {
489 id: id.into(),
490 name: name.into(),
491 arguments: arguments.into(),
492 },
493 };
494 send_frame(writer, &frame).await
495}
496
497pub async fn send_user_prompt_request<S>(
499 writer: &mut S,
500 id: &str,
501 prompt: &crate::user_prompt_types::UserPrompt,
502) -> Result<()>
503where
504 S: SinkExt<Message> + Unpin,
505{
506 let frame = ServerFrame {
507 frame_type: ServerFrameType::UserPromptRequest,
508 payload: ServerPayload::UserPromptRequest {
509 id: id.into(),
510 prompt: prompt.clone(),
511 },
512 };
513 send_frame(writer, &frame).await
514}
515
516pub async fn send_tasks_update<S>(writer: &mut S, tasks: Vec<TaskInfoDto>) -> Result<()>
518where
519 S: SinkExt<Message> + Unpin,
520{
521 let frame = ServerFrame {
522 frame_type: ServerFrameType::TasksUpdate,
523 payload: ServerPayload::TasksUpdate { tasks },
524 };
525 send_frame(writer, &frame).await
526}