mobius_gateway/wire/messages.rs
1use super::*;
2
3const MAX_REQUEST_ID_BYTES: usize = 256;
4
5/// One client-to-gateway frame.
6#[derive(Debug, Clone, PartialEq, Serialize)]
7pub struct ClientFrame {
8 /// The version.
9 pub version: u16,
10 #[serde(flatten)]
11 /// The message.
12 pub message: ClientMessage,
13}
14
15impl<'de> Deserialize<'de> for ClientFrame {
16 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
17 where
18 D: serde::Deserializer<'de>,
19 {
20 let (version, message) = deserialize_frame(deserializer)?;
21 if let Some(request_id) = message.get("request_id")
22 && !request_id
23 .as_str()
24 .is_some_and(|id| !id.is_empty() && id.len() <= MAX_REQUEST_ID_BYTES)
25 {
26 return Err(D::Error::custom("request ID must be 1–256 bytes"));
27 }
28 let message = serde_json::from_value(message).map_err(D::Error::custom)?;
29 Ok(Self { version, message })
30 }
31}
32
33impl ClientFrame {
34 /// Wraps a message in the current protocol version.
35 #[must_use]
36 pub const fn new(message: ClientMessage) -> Self {
37 Self {
38 version: PROTOCOL_VERSION,
39 message,
40 }
41 }
42}
43
44/// Authenticated operations accepted by the gateway.
45#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
46#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
47#[non_exhaustive]
48pub enum ClientMessage {
49 /// Opens the gateway-owned computer and foregrounds the chat's assigned tab.
50 OpenComputer {
51 /// The request identifier.
52 request_id: String,
53 /// The chat whose assigned browser tab to show.
54 session_id: String,
55 },
56 /// Opens or closes this authenticated connection's remote desktop stream.
57 SetDesktopStream {
58 /// The request identifier.
59 request_id: String,
60 /// Whether to stream the desktop.
61 enabled: bool,
62 },
63 /// Ordered RFB bytes for this connection's desktop stream.
64 DesktopData {
65 /// The raw RFB data, limited to [`MAX_DESKTOP_CHUNK_BYTES`].
66 #[serde(with = "desktop_bytes")]
67 data: Vec<u8>,
68 },
69 /// Requests or releases the gateway's human desktop lease.
70 SetDesktopControl {
71 /// The request identifier.
72 request_id: String,
73 /// Whether to take control.
74 enabled: bool,
75 /// The chat whose computer view requested control.
76 session_id: Option<String>,
77 },
78 /// Replaces this connection's optional notification exclusions.
79 SetNotifications {
80 /// The request identifier.
81 request_id: String,
82 /// Broadcasts to suppress until replaced or the connection closes.
83 disabled: BTreeSet<GatewayNotification>,
84 },
85 /// Selects a chat for file, history and workspace requests without replaying or
86 /// streaming its events; answered by `session_opened` alone.
87 SelectSession {
88 /// The request identifier.
89 request_id: String,
90 /// The session identifier.
91 session_id: String,
92 },
93 /// Asks for the line totals of a Git diff, as Git counts them.
94 GetGitDiffTotals {
95 /// The request identifier.
96 request_id: String,
97 /// The session identifier.
98 session_id: String,
99 /// The scope.
100 scope: GitDiffScope,
101 },
102 /// Registers the local Mac renderer for gateway-assigned browser pages.
103 SetBrowserRuntime {
104 /// The request identifier.
105 request_id: String,
106 /// Whether the renderer is available.
107 enabled: bool,
108 },
109 /// Supplies the scoped Unix endpoint of an assigned local browser page.
110 BrowserPageReply {
111 /// The gateway's page request identifier.
112 request_id: String,
113 /// The endpoint, or none if the renderer cannot provide the page.
114 endpoint: Option<String>,
115 },
116 /// Selects the set desktop runtime case.
117 SetDesktopRuntime {
118 /// The request identifier.
119 request_id: String,
120 /// The enabled.
121 enabled: bool,
122 },
123 /// Selects the desktop control reply case.
124 DesktopControlReply {
125 /// The request identifier.
126 request_id: String,
127 /// The response.
128 response: Value,
129 },
130 /// Selects the pair case.
131 Pair {
132 /// The code.
133 code: String,
134 /// The client label.
135 client_label: String,
136 /// The client kind.
137 client_kind: ClientKind,
138 },
139 /// Selects the repair pairing case.
140 RepairPairing {
141 /// The code.
142 code: String,
143 /// The digest of the client token being replaced.
144 replacing_token_digest: [u8; 32],
145 /// The client label.
146 client_label: String,
147 /// The client kind.
148 client_kind: ClientKind,
149 },
150 /// Selects the authenticate case.
151 Authenticate {
152 /// The token.
153 token: String,
154 /// The client kind.
155 client_kind: ClientKind,
156 /// The catalog this client already holds, or does not need. An empty hint is left
157 /// out, so the version check that replaces an older running gateway can reach it.
158 #[serde(default, skip_serializing_if = "CatalogHint::is_empty")]
159 catalog: CatalogHint,
160 },
161 /// Selects the list clients case.
162 ListClients {
163 /// The request identifier.
164 request_id: String,
165 },
166 /// Read collector configuration and delivery status.
167 GetTelemetry {
168 /// Correlates this response with its request.
169 request_id: String,
170 },
171 /// Read storage ownership and measured sizes without mutating files.
172 GetStorageUsage {
173 /// Correlates this response with its request.
174 request_id: String,
175 },
176 /// Replace collector configuration at an expected revision.
177 ConfigureTelemetry {
178 /// Correlates this response with its request.
179 request_id: String,
180 /// Configuration revision observed before editing.
181 expected_revision: u64,
182 /// Configured collectors.
183 sinks: Vec<crate::telemetry::TelemetrySink>,
184 /// IDs whose existing credential sources must survive a redacted report edit.
185 #[serde(default, skip_serializing_if = "Vec::is_empty")]
186 preserve_auth: Vec<String>,
187 },
188 /// Deliver a snapshot immediately.
189 SendTelemetry {
190 /// Correlates this response with its request.
191 request_id: String,
192 /// Collector to send now.
193 sink_id: String,
194 },
195 /// Selects the unpair client case.
196 UnpairClient {
197 /// The request identifier.
198 request_id: String,
199 /// The client identifier.
200 client_id: String,
201 },
202 /// Selects the list sessions case.
203 ListSessions {
204 /// The request identifier.
205 request_id: String,
206 },
207 /// Selects the list bot sessions case.
208 ListBotSessions {
209 /// The request identifier.
210 request_id: String,
211 /// The bot identifier.
212 bot_id: String,
213 },
214 /// Selects the create session case.
215 CreateSession {
216 /// The request identifier.
217 request_id: String,
218 /// The workspace.
219 workspace: PathBuf,
220 /// The bot identifier.
221 bot_id: String,
222 },
223 /// Selects the create workspace directory case.
224 CreateWorkspaceDirectory {
225 /// The request identifier.
226 request_id: String,
227 /// The parent.
228 parent: PathBuf,
229 /// The name.
230 name: String,
231 },
232 /// Selects the open session case.
233 OpenSession {
234 /// The request identifier.
235 request_id: String,
236 /// The session identifier.
237 session_id: String,
238 /// The last sequence.
239 last_sequence: Option<u64>,
240 },
241 /// Selects the get session history case.
242 GetSessionHistory {
243 /// The request identifier.
244 request_id: String,
245 /// The session identifier.
246 session_id: String,
247 /// The before sequence.
248 before_sequence: Option<u64>,
249 },
250 /// Selects the reassign session case.
251 ReassignSession {
252 /// The request identifier.
253 request_id: String,
254 /// The session identifier.
255 session_id: String,
256 /// The bot identifier.
257 bot_id: String,
258 },
259 /// Selects the rename session case.
260 RenameSession {
261 /// The request identifier.
262 request_id: String,
263 /// The session identifier.
264 session_id: String,
265 /// The title.
266 title: String,
267 },
268 /// Selects the attach session folder case.
269 AttachSessionFolder {
270 /// The request identifier.
271 request_id: String,
272 /// The session identifier.
273 session_id: String,
274 /// The folder.
275 folder: PathBuf,
276 },
277 /// Selects the set session pinned case.
278 SetSessionPinned {
279 /// The request identifier.
280 request_id: String,
281 /// The session identifier.
282 session_id: String,
283 /// The pinned.
284 pinned: bool,
285 },
286 /// Selects the delete sessions case.
287 DeleteSessions {
288 /// The request identifier.
289 request_id: String,
290 /// The session identifiers.
291 session_ids: Vec<String>,
292 /// Required deletion scope; history is removed only for all.
293 selection: mobius::backend::session_files::SessionFileSelection,
294 },
295 /// Selects the submit case.
296 Submit {
297 /// The session identifier.
298 session_id: String,
299 /// The submission.
300 submission: Submission,
301 },
302 /// Selects the start realtime voice case.
303 StartRealtimeVoice {
304 /// The request identifier.
305 request_id: String,
306 /// The session identifier.
307 session_id: String,
308 /// The offer sdp.
309 offer_sdp: String,
310 },
311 /// Selects the end realtime voice case.
312 EndRealtimeVoice {
313 /// The session identifier.
314 session_id: String,
315 /// The voice identifier.
316 voice_id: String,
317 },
318 /// Selects the get contributions case.
319 GetContributions {
320 /// The request identifier.
321 request_id: String,
322 },
323 /// Selects the submit contribution case.
324 SubmitContribution {
325 /// The request identifier.
326 request_id: String,
327 /// The operation.
328 operation: Op,
329 },
330 /// Selects the begin session file upload case.
331 BeginSessionFileUpload {
332 /// The request identifier.
333 request_id: String,
334 /// The session identifier.
335 session_id: String,
336 /// The name.
337 name: String,
338 /// The size.
339 size: u64,
340 /// The media type.
341 media_type: String,
342 },
343 /// Selects the upload session file chunk case.
344 UploadSessionFileChunk {
345 /// The request identifier.
346 request_id: String,
347 /// The session identifier.
348 session_id: String,
349 /// The upload identifier.
350 upload_id: String,
351 /// The offset.
352 offset: u64,
353 #[serde(with = "base64_bytes")]
354 /// The data.
355 data: Vec<u8>,
356 },
357 /// Selects the finish session file upload case.
358 FinishSessionFileUpload {
359 /// The request identifier.
360 request_id: String,
361 /// The session identifier.
362 session_id: String,
363 /// The upload identifier.
364 upload_id: String,
365 },
366 /// Selects the list session files case.
367 ListSessionFiles {
368 /// The request identifier.
369 request_id: String,
370 /// The session identifier.
371 session_id: String,
372 },
373 /// Selects the read session file case.
374 ReadSessionFile {
375 /// The request identifier.
376 request_id: String,
377 /// The session identifier.
378 session_id: String,
379 /// The file identifier.
380 file_id: String,
381 /// The offset.
382 offset: u64,
383 /// The max bytes.
384 max_bytes: usize,
385 },
386 /// Selects the create bot case.
387 CreateBot {
388 /// The request identifier.
389 request_id: String,
390 /// The name.
391 name: String,
392 /// The description.
393 description: String,
394 },
395 /// Selects the list bots case.
396 ListBots {
397 /// The request identifier.
398 request_id: String,
399 },
400 /// Selects the update bot case.
401 UpdateBot {
402 /// The request identifier.
403 request_id: String,
404 /// The identifier.
405 id: String,
406 /// The expected revision.
407 expected_revision: u64,
408 /// The name.
409 name: String,
410 /// The description.
411 description: String,
412 /// The tint.
413 tint: ProviderTint,
414 /// The face's silhouette.
415 shape: BotShape,
416 /// The config.
417 config: AgentComposition,
418 },
419 /// Selects the delete bot case.
420 DeleteBot {
421 /// The request identifier.
422 request_id: String,
423 /// The identifier.
424 id: String,
425 /// The expected revision.
426 expected_revision: u64,
427 },
428 /// Selects the configure bot defaults case.
429 ConfigureBotDefaults {
430 /// The request identifier.
431 request_id: String,
432 /// The expected revision.
433 expected_revision: u64,
434 /// The config.
435 config: AgentComposition,
436 },
437 /// Selects the install extension case.
438 InstallExtension {
439 /// The request identifier.
440 request_id: String,
441 /// The source.
442 source: String,
443 /// The reference.
444 reference: Option<String>,
445 /// The subdirectory.
446 subdirectory: Option<String>,
447 },
448 /// Selects the update extension case.
449 UpdateExtension {
450 /// The request identifier.
451 request_id: String,
452 /// The identifier.
453 id: String,
454 },
455 /// Selects the uninstall extension case.
456 UninstallExtension {
457 /// The request identifier.
458 request_id: String,
459 /// The identifier.
460 id: String,
461 },
462 /// Selects the trust extension hooks case.
463 TrustExtensionHooks {
464 /// The request identifier.
465 request_id: String,
466 /// The identifier.
467 id: String,
468 /// The expected digest.
469 expected_digest: String,
470 },
471 /// Selects the revoke extension hooks trust case.
472 RevokeExtensionHooksTrust {
473 /// The request identifier.
474 request_id: String,
475 /// The identifier.
476 id: String,
477 /// The expected digest.
478 expected_digest: String,
479 },
480 /// Selects the probe git credential case.
481 ProbeGitCredential {
482 /// The request identifier.
483 request_id: String,
484 /// The target.
485 target: String,
486 },
487 /// Selects the approve git credential case.
488 ApproveGitCredential {
489 /// The request identifier.
490 request_id: String,
491 /// The target.
492 target: String,
493 /// The username.
494 username: String,
495 /// The token.
496 token: String,
497 },
498 /// Selects the list ssh identities case.
499 ListSshIdentities {
500 /// The request identifier.
501 request_id: String,
502 },
503 /// Selects the generate ssh identity case.
504 GenerateSshIdentity {
505 /// The request identifier.
506 request_id: String,
507 },
508 /// Selects the get git diff case.
509 GetGitDiff {
510 /// The request identifier.
511 request_id: String,
512 /// The session identifier.
513 session_id: String,
514 /// The scope.
515 scope: GitDiffScope,
516 },
517 /// Selects the switch git branch case.
518 SwitchGitBranch {
519 /// The request identifier.
520 request_id: String,
521 /// The session identifier.
522 session_id: String,
523 /// The branch.
524 branch: String,
525 },
526 /// Selects the list directories case.
527 ListDirectories {
528 /// The request identifier.
529 request_id: String,
530 /// The path.
531 path: PathBuf,
532 /// The include files.
533 include_files: bool,
534 },
535 /// Selects the list workspace files case.
536 ListWorkspaceFiles {
537 /// The request identifier.
538 request_id: String,
539 /// The session identifier.
540 session_id: String,
541 /// The scope.
542 scope: WorkspaceFileScope,
543 },
544 /// Selects the read workspace file case.
545 ReadWorkspaceFile {
546 /// The request identifier.
547 request_id: String,
548 /// The session identifier.
549 session_id: String,
550 /// The path.
551 path: String,
552 /// The offset.
553 offset: u64,
554 /// The max bytes.
555 max_bytes: usize,
556 },
557 /// Deletes a file inside the selected workspace.
558 DeleteWorkspaceFile {
559 /// Request correlation identifier.
560 request_id: String,
561 /// Selected project chat.
562 session_id: String,
563 /// Relative regular file path.
564 path: String,
565 },
566 /// Writes one workspace text file.
567 WriteWorkspaceFile {
568 /// The request identifier.
569 request_id: String,
570 /// The session identifier.
571 session_id: String,
572 /// The path.
573 path: String,
574 /// The content.
575 content: String,
576 },
577 /// Selects the clear provider credential case.
578 ClearProviderCredential {
579 /// The request identifier.
580 request_id: String,
581 /// The instance.
582 instance: String,
583 },
584 /// Selects the set provider credential case.
585 SetProviderCredential {
586 /// The request identifier.
587 request_id: String,
588 /// The instance.
589 instance: String,
590 /// The provider.
591 provider: String,
592 /// The API key.
593 api_key: String,
594 /// The expires at.
595 expires_at: Option<u64>,
596 },
597 /// Selects the set provider endpoint credential case.
598 SetProviderEndpointCredential {
599 /// The request identifier.
600 request_id: String,
601 /// The instance.
602 instance: String,
603 /// The provider.
604 provider: String,
605 /// The base URL.
606 base_url: String,
607 /// The API key.
608 api_key: String,
609 /// The expires at.
610 expires_at: Option<u64>,
611 },
612 /// Selects the register provider case.
613 RegisterProvider {
614 /// The request identifier.
615 request_id: String,
616 /// The config.
617 config: ProviderConfig,
618 /// The label.
619 label: String,
620 /// The tint.
621 tint: ProviderTint,
622 /// The model identifiers.
623 model_ids: Vec<String>,
624 /// The reasoning efforts.
625 reasoning_efforts: Vec<String>,
626 },
627 /// Selects the remove provider case.
628 RemoveProvider {
629 /// The request identifier.
630 request_id: String,
631 /// The instance.
632 instance: String,
633 },
634 /// Selects the create pairing code case.
635 CreatePairingCode {
636 /// The request identifier.
637 request_id: String,
638 },
639 /// Selects the start provider login case.
640 StartProviderLogin {
641 /// The request identifier.
642 request_id: String,
643 /// The provider.
644 provider: String,
645 },
646 /// Selects the get profile case.
647 GetProfile {
648 /// The request identifier.
649 request_id: String,
650 /// The include provider usage.
651 include_provider_usage: bool,
652 },
653 /// Create a validated routine definition.
654 CreateRoutine {
655 /// Request identity.
656 request_id: String,
657 /// Owning Bot.
658 bot_id: String,
659 /// Editable content and exact bindings.
660 definition: RoutineDefinition,
661 },
662 /// List the current routine definitions.
663 ListRoutines {
664 /// Request identity.
665 request_id: String,
666 /// Optional owning Bot.
667 bot_id: Option<String>,
668 },
669 /// Apply the same typed command used by timers and hooks.
670 RoutineCommand {
671 /// Request and command identity.
672 request_id: String,
673 /// Target and action.
674 command: super::RoutineCommand,
675 },
676 /// Selects the list routine history case.
677 ListRoutineHistory {
678 /// The request identifier.
679 request_id: String,
680 /// The identifier.
681 id: Option<String>,
682 },
683 /// Selects the delete routine run case.
684 DeleteRoutineRun {
685 /// The request identifier.
686 request_id: String,
687 /// The identifier.
688 id: String,
689 },
690 /// Selects the get routine run preview case.
691 GetRoutineRunPreview {
692 /// The request identifier.
693 request_id: String,
694 /// The identifier.
695 id: String,
696 /// The before sequence.
697 before_sequence: Option<u64>,
698 },
699}
700
701/// One gateway-to-client frame.
702#[derive(Debug, Clone, PartialEq, Serialize)]
703pub struct ServerFrame {
704 /// The version.
705 pub version: u16,
706 #[serde(flatten)]
707 /// The message.
708 pub message: ServerMessage,
709}
710
711impl<'de> Deserialize<'de> for ServerFrame {
712 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
713 where
714 D: serde::Deserializer<'de>,
715 {
716 let (version, message) = deserialize_frame(deserializer)?;
717 let message = serde_json::from_value(message).map_err(D::Error::custom)?;
718 Ok(Self { version, message })
719 }
720}
721
722impl ServerFrame {
723 /// Wraps a message in the current protocol version.
724 #[must_use]
725 pub const fn new(message: ServerMessage) -> Self {
726 Self {
727 version: PROTOCOL_VERSION,
728 message,
729 }
730 }
731}
732
733/// Results and broadcasts emitted by the gateway.
734#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
735#[serde(tag = "type", rename_all = "snake_case")]
736#[non_exhaustive]
737pub enum ServerMessage {
738 /// Acknowledges showing the gateway-owned computer.
739 ComputerOpened {
740 /// The request identifier.
741 request_id: String,
742 /// The chat whose browser tab was shown.
743 session_id: String,
744 },
745 /// Acknowledges opening or closing this connection's desktop stream.
746 DesktopStreamState {
747 /// The request identifier.
748 request_id: String,
749 /// Whether the stream is open.
750 enabled: bool,
751 },
752 /// Ordered RFB bytes from the gateway desktop.
753 DesktopData {
754 /// The raw RFB data, limited to [`MAX_DESKTOP_CHUNK_BYTES`].
755 #[serde(with = "desktop_bytes")]
756 data: Vec<u8>,
757 },
758 /// The gateway's current desktop lease, relative to this connection.
759 DesktopControlState {
760 /// The acknowledged request, or absent for a broadcast update.
761 request_id: Option<String>,
762 /// Whether execution is held for pending or granted human control.
763 enabled: bool,
764 /// Whether this connection owns control.
765 is_owner: bool,
766 /// The controlling chat, or the latest agent chat when watching.
767 session_id: Option<String>,
768 },
769 /// A committed source changed; clients refresh their existing snapshots.
770 HookEvent {
771 /// Committed typed lifecycle fact.
772 event: super::HookEvent,
773 },
774 /// Fresh measured storage usage.
775 StorageUsage {
776 /// Correlates this response with its request.
777 request_id: String,
778 /// Measured storage ownership and totals.
779 usage: crate::storage_usage::StorageUsage,
780 },
781 /// Collector configuration and delivery state.
782 Telemetry {
783 /// Correlates this response with its request.
784 request_id: String,
785 /// Current collector configuration revision.
786 revision: u64,
787 /// Configured collectors.
788 sinks: Vec<crate::telemetry::TelemetrySinkReport>,
789 },
790 /// Requests the local renderer's assigned page for one chat.
791 BrowserPageRequested {
792 /// The request identifier.
793 request_id: String,
794 /// The chat identifier.
795 session_id: String,
796 /// Whether the human explicitly asked to activate this page.
797 foreground: bool,
798 },
799 /// Selects the desktop control requested case.
800 DesktopControlRequested {
801 /// The request identifier.
802 request_id: String,
803 /// The execution identifier.
804 execution_id: String,
805 /// The session identifier.
806 session_id: String,
807 /// The request.
808 request: Value,
809 },
810 /// Selects the desktop control ended case.
811 DesktopControlEnded {
812 /// The execution identifier.
813 execution_id: String,
814 },
815 /// Selects the paired case.
816 Paired {
817 /// The client identifier.
818 client_id: String,
819 /// The token.
820 token: String,
821 },
822 /// Selects the authenticated case.
823 Authenticated,
824 /// Selects the ready case.
825 Ready {
826 /// The payload.
827 payload: ReadyPayload,
828 },
829 /// Selects the session opened case.
830 SessionOpened {
831 /// The request identifier.
832 request_id: String,
833 /// The payload.
834 payload: SessionReadyPayload,
835 },
836 /// Selects the session replay complete case.
837 SessionReplayComplete {
838 /// The request identifier.
839 request_id: String,
840 /// The session identifier.
841 session_id: String,
842 },
843 /// Selects the session history case.
844 SessionHistory {
845 /// The request identifier.
846 request_id: String,
847 /// The session identifier.
848 session_id: String,
849 /// The records.
850 records: Vec<RecordedEvent>,
851 /// The next before sequence.
852 next_before_sequence: Option<u64>,
853 },
854 /// Selects the session changed case.
855 SessionChanged {
856 /// The payload.
857 payload: SessionReadyPayload,
858 },
859 /// Selects the realtime voice started case.
860 RealtimeVoiceStarted {
861 /// The request identifier.
862 request_id: String,
863 /// The session identifier.
864 session_id: String,
865 /// The voice identifier.
866 voice_id: String,
867 /// The answer sdp.
868 answer_sdp: String,
869 },
870 /// Selects the realtime voice failed case.
871 RealtimeVoiceFailed {
872 /// The request identifier.
873 request_id: String,
874 /// The session identifier.
875 session_id: String,
876 /// The message.
877 message: String,
878 },
879 /// Selects the realtime voice ended case.
880 RealtimeVoiceEnded {
881 /// The session identifier.
882 session_id: String,
883 /// The voice identifier.
884 voice_id: String,
885 /// The reason.
886 reason: Option<String>,
887 },
888 /// Selects the gateway configured case.
889 GatewayConfigured {
890 /// The request identifier.
891 request_id: String,
892 /// The payload.
893 payload: ReadyPayload,
894 },
895 /// Selects the contributions case.
896 Contributions {
897 /// The request identifier.
898 request_id: String,
899 /// The contributions.
900 contributions: Vec<FrontendContribution>,
901 },
902 /// Selects the accepted case.
903 Accepted {
904 /// The request identifier.
905 request_id: String,
906 },
907 /// Selects the session file upload ready case.
908 SessionFileUploadReady {
909 /// The request identifier.
910 request_id: String,
911 /// The session identifier.
912 session_id: String,
913 /// The upload identifier.
914 upload_id: String,
915 /// The max chunk bytes.
916 max_chunk_bytes: usize,
917 },
918 /// Selects the session file upload chunk accepted case.
919 SessionFileUploadChunkAccepted {
920 /// The request identifier.
921 request_id: String,
922 /// The session identifier.
923 session_id: String,
924 /// The upload identifier.
925 upload_id: String,
926 /// The next offset.
927 next_offset: u64,
928 },
929 /// Selects the session file upload completed case.
930 SessionFileUploadCompleted {
931 /// The request identifier.
932 request_id: String,
933 /// The session identifier.
934 session_id: String,
935 /// The file.
936 file: SessionFileReference,
937 },
938 /// Selects the session files case.
939 SessionFiles {
940 /// The request identifier.
941 request_id: String,
942 /// The session identifier.
943 session_id: String,
944 /// The files.
945 files: Vec<SessionFileRecord>,
946 },
947 /// Selects the session file chunk case.
948 SessionFileChunk {
949 /// The request identifier.
950 request_id: String,
951 /// The session identifier.
952 session_id: String,
953 /// The file identifier.
954 file_id: String,
955 /// The offset.
956 offset: u64,
957 #[serde(with = "base64_bytes")]
958 /// The data.
959 data: Vec<u8>,
960 /// The next offset.
961 next_offset: Option<u64>,
962 },
963 /// Selects the rejected case.
964 Rejected {
965 /// The request identifier.
966 request_id: String,
967 /// The code.
968 code: String,
969 /// The message.
970 message: String,
971 /// The fatal.
972 fatal: bool,
973 },
974 /// Selects the agent event case.
975 AgentEvent {
976 /// The session identifier.
977 session_id: String,
978 /// The record.
979 record: RecordedEvent,
980 },
981 /// Selects the sessions case.
982 Sessions {
983 #[serde(default, skip_serializing_if = "Option::is_none")]
984 /// The request identifier.
985 request_id: Option<String>,
986 /// The sessions.
987 sessions: Vec<SessionRecord>,
988 },
989 /// Selects the background approvals case.
990 BackgroundApprovals {
991 /// The approvals.
992 approvals: Vec<BackgroundApproval>,
993 },
994 /// The whole visible session catalog, in order, relative to the catalog this
995 /// connection last received; unsolicited catalog updates arrive only in this form.
996 SessionsChanged {
997 /// Every session of the catalog, unchanged ones by ID.
998 sessions: Vec<SessionSlot>,
999 /// The new catalog's revision.
1000 revision: String,
1001 },
1002
1003 /// Selects the bot sessions case.
1004 BotSessions {
1005 /// The request identifier.
1006 request_id: String,
1007 /// The bot identifier.
1008 bot_id: String,
1009 /// The sessions.
1010 sessions: Vec<SessionRecord>,
1011 },
1012 /// Selects the bots case.
1013 Bots {
1014 #[serde(default, skip_serializing_if = "Option::is_none")]
1015 /// The request identifier.
1016 request_id: Option<String>,
1017 /// The bots.
1018 bots: Vec<BotRecord>,
1019 },
1020
1021 /// Selects the clients case.
1022 Clients {
1023 /// The request identifier.
1024 request_id: String,
1025 /// The current client identifier.
1026 current_client_id: String,
1027 /// The clients.
1028 clients: Vec<ClientStatus>,
1029 },
1030 /// Selects the provider credential cleared case.
1031 ProviderCredentialCleared {
1032 /// The request identifier.
1033 request_id: String,
1034 /// The instance.
1035 instance: String,
1036 },
1037 /// Selects the provider credential saved case.
1038 ProviderCredentialSaved {
1039 /// The request identifier.
1040 request_id: String,
1041 /// The instance.
1042 instance: String,
1043 /// The provider.
1044 provider: String,
1045 },
1046 /// Selects the pairing code case.
1047 PairingCode {
1048 /// The request identifier.
1049 request_id: String,
1050 /// The code.
1051 code: String,
1052 /// The expires at.
1053 expires_at: i64,
1054 },
1055 /// Selects the provider login started case.
1056 ProviderLoginStarted {
1057 /// The request identifier.
1058 request_id: String,
1059 /// The login identifier.
1060 login_id: String,
1061 /// The provider.
1062 provider: String,
1063 /// The verification URL.
1064 verification_url: String,
1065 /// The user code.
1066 user_code: String,
1067 },
1068 /// Selects the provider login finished case.
1069 ProviderLoginFinished {
1070 /// The request identifier.
1071 request_id: String,
1072 /// The login identifier.
1073 login_id: String,
1074 /// The provider.
1075 provider: String,
1076 },
1077 /// Selects the git credential status case.
1078 GitCredentialStatus {
1079 /// The request identifier.
1080 request_id: String,
1081 /// The available.
1082 available: bool,
1083 #[serde(skip_serializing_if = "Option::is_none")]
1084 /// The username.
1085 username: Option<String>,
1086 },
1087 /// Selects the ssh identities case.
1088 SshIdentities {
1089 /// The request identifier.
1090 request_id: String,
1091 /// The identities.
1092 identities: Vec<SshIdentityRecord>,
1093 },
1094 /// Selects the ssh identity generated case.
1095 SshIdentityGenerated {
1096 /// The request identifier.
1097 request_id: String,
1098 /// The identity.
1099 identity: SshIdentityRecord,
1100 /// The public key.
1101 public_key: String,
1102 },
1103 /// Selects the profile case.
1104 Profile {
1105 /// The request identifier.
1106 request_id: String,
1107 /// The profile.
1108 profile: ProfileSnapshot,
1109 },
1110 /// Selects the git diff case.
1111 GitDiff {
1112 /// The request identifier.
1113 request_id: String,
1114 /// The session identifier.
1115 session_id: String,
1116 /// The scope.
1117 scope: GitDiffScope,
1118 /// The diff.
1119 diff: String,
1120 },
1121 /// Line totals of a Git diff.
1122 GitDiffTotals {
1123 /// The request identifier.
1124 request_id: String,
1125 /// The session identifier.
1126 session_id: String,
1127 /// The scope.
1128 scope: GitDiffScope,
1129 /// The totals.
1130 totals: DiffTotals,
1131 },
1132 /// Selects the directories case.
1133 Directories {
1134 /// The request identifier.
1135 request_id: String,
1136 /// The listing.
1137 listing: DirectoryListing,
1138 },
1139 /// Selects the workspace files case.
1140 WorkspaceFiles {
1141 /// The request identifier.
1142 request_id: String,
1143 /// The session identifier.
1144 session_id: String,
1145 /// The files.
1146 files: Vec<WorkspaceFileRecord>,
1147 /// The truncated.
1148 truncated: bool,
1149 },
1150 /// Selects the workspace file chunk case.
1151 WorkspaceFileChunk {
1152 /// The request identifier.
1153 request_id: String,
1154 /// The session identifier.
1155 session_id: String,
1156 /// The path.
1157 path: String,
1158 /// The offset.
1159 offset: u64,
1160 #[serde(with = "base64_bytes")]
1161 /// The data.
1162 data: Vec<u8>,
1163 /// The next offset.
1164 next_offset: Option<u64>,
1165 },
1166 /// Selects the routines case.
1167 Routines {
1168 /// The request identifier.
1169 request_id: String,
1170 /// The routines.
1171 routines: Vec<Routine>,
1172 },
1173 /// Selects the routine history case.
1174 RoutineHistory {
1175 /// The request identifier.
1176 request_id: String,
1177 /// The runs.
1178 runs: Vec<RoutineRun>,
1179 },
1180 /// Selects the routine run preview case.
1181 RoutineRunPreview {
1182 /// The request identifier.
1183 request_id: String,
1184 /// The preview.
1185 preview: RoutineRunPreview,
1186 },
1187 /// Selects the error case.
1188 Error {
1189 /// The code.
1190 code: String,
1191 /// The message.
1192 message: String,
1193 /// The fatal.
1194 fatal: bool,
1195 },
1196}
1197
1198/// One gateway response failure with its connection-level terminality preserved.
1199#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1200pub struct GatewayResponseError<'a> {
1201 /// The message.
1202 pub message: &'a str,
1203 /// The fatal.
1204 pub fatal: bool,
1205}
1206
1207impl ServerMessage {
1208 /// Returns the error which terminates a wait for `request_id`, if any.
1209 ///
1210 /// A correlated rejection terminates that request. An uncorrelated global error
1211 /// only terminates a wait when it also terminates the connection.
1212 #[must_use]
1213 pub fn response_error(&self, request_id: Option<&str>) -> Option<GatewayResponseError<'_>> {
1214 match self {
1215 Self::Rejected {
1216 request_id: actual,
1217 message,
1218 fatal,
1219 ..
1220 } if request_id == Some(actual.as_str()) => Some(GatewayResponseError {
1221 message,
1222 fatal: *fatal,
1223 }),
1224 Self::Error {
1225 message,
1226 fatal: true,
1227 ..
1228 } => Some(GatewayResponseError {
1229 message,
1230 fatal: true,
1231 }),
1232 _ => None,
1233 }
1234 }
1235}