lash_remote_protocol/protocol/
observations.rs1#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
2pub struct RemoteSessionCursor {
3 pub protocol_version: u32,
4 pub cursor: String,
5}
6
7impl RemoteSessionCursor {
8 pub fn new(cursor: impl Into<String>) -> Self {
9 Self {
10 protocol_version: REMOTE_PROTOCOL_VERSION,
11 cursor: cursor.into(),
12 }
13 }
14
15 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
16 ensure_protocol_version(self.protocol_version)?;
17 require_non_empty("RemoteSessionCursor", "cursor", &self.cursor)
18 }
19}
20
21#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
22pub struct RemoteSessionObservation {
23 pub protocol_version: u32,
24 pub session_id: String,
25 pub cursor: String,
26 pub turn_index: u64,
27 pub usage: RemoteUsage,
28}
29
30impl RemoteSessionObservation {
31 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
32 ensure_protocol_version(self.protocol_version)?;
33 require_non_empty("RemoteSessionObservation", "session_id", &self.session_id)?;
34 require_non_empty("RemoteSessionObservation", "cursor", &self.cursor)
35 }
36}
37
38#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
39pub struct RemoteSessionObservationEvent {
40 pub protocol_version: u32,
41 pub session_id: String,
42 pub revision: u64,
43 pub cursor: String,
44 #[serde(flatten)]
45 pub event: RemoteSessionObservationEventPayload,
46}
47
48impl RemoteSessionObservationEvent {
49 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
50 ensure_protocol_version(self.protocol_version)?;
51 require_non_empty(
52 "RemoteSessionObservationEvent",
53 "session_id",
54 &self.session_id,
55 )?;
56 require_non_empty("RemoteSessionObservationEvent", "cursor", &self.cursor)?;
57 if let RemoteSessionObservationEventPayload::TurnActivity { activity } = &self.event {
58 activity.validate()?;
59 if activity.protocol_version != self.protocol_version {
60 return Err(RemoteProtocolError::MismatchedNestedProtocolVersion {
61 parent: "RemoteSessionObservationEvent",
62 child: "activity",
63 parent_version: self.protocol_version,
64 child_version: activity.protocol_version,
65 });
66 }
67 }
68 Ok(())
69 }
70}
71
72#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
73#[serde(tag = "type", rename_all = "snake_case")]
74pub enum RemoteSessionObservationEventPayload {
75 TurnActivity {
76 activity: RemoteTurnActivity,
77 },
78 Committed,
79 AgentFrameSwitched {
80 frame_id: String,
81 },
82 QueueChanged {
83 kind: RemoteSessionQueueEventKind,
84 batch_ids: Vec<String>,
85 },
86 ProcessChanged {
87 kind: RemoteSessionProcessEventKind,
88 process_ids: Vec<String>,
89 },
90}
91
92#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
93#[serde(rename_all = "snake_case")]
94pub enum RemoteSessionQueueEventKind {
95 Enqueued,
96 Cancelled,
97}
98
99#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
100#[serde(rename_all = "snake_case")]
101pub enum RemoteSessionProcessEventKind {
102 Started,
103 Cancelled,
104}
105
106#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
107pub struct RemoteLiveReplayGap {
108 pub protocol_version: u32,
109 pub session_id: String,
110 pub requested_cursor: String,
111 pub latest_cursor: String,
112 pub latest_revision: u64,
113 pub reason: RemoteLiveReplayGapReason,
114}
115
116impl RemoteLiveReplayGap {
117 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
118 ensure_protocol_version(self.protocol_version)?;
119 require_non_empty("RemoteLiveReplayGap", "session_id", &self.session_id)?;
120 require_non_empty(
121 "RemoteLiveReplayGap",
122 "requested_cursor",
123 &self.requested_cursor,
124 )?;
125 require_non_empty("RemoteLiveReplayGap", "latest_cursor", &self.latest_cursor)
126 }
127}
128
129#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
130#[serde(rename_all = "snake_case")]
131pub enum RemoteLiveReplayGapReason {
132 Trimmed,
133 Unavailable,
134}
135
136impl RemoteTurnResult {
137 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
138 ensure_protocol_version(self.protocol_version)?;
139 require_non_empty("RemoteTurnResult", "session_id", &self.session_id)?;
140 require_non_empty("RemoteTurnResult", "turn_id", &self.turn_id)?;
141 for activity in &self.activities {
142 if activity.protocol_version != self.protocol_version {
143 return Err(RemoteProtocolError::MismatchedNestedProtocolVersion {
144 parent: "RemoteTurnResult",
145 child: "activities",
146 parent_version: self.protocol_version,
147 child_version: activity.protocol_version,
148 });
149 }
150 activity.validate()?;
151 }
152 Ok(())
153 }
154}