1#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
2pub struct RemoteSessionScope {
3 pub session_id: String,
4 #[serde(default, skip_serializing_if = "Option::is_none")]
5 pub agent_frame_id: Option<String>,
6}
7
8impl RemoteSessionScope {
9 pub fn new(session_id: impl Into<String>) -> Self {
10 Self {
11 session_id: session_id.into(),
12 agent_frame_id: None,
13 }
14 }
15
16 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
17 require_non_empty(type_name, "session_id", &self.session_id)?;
18 if let Some(agent_frame_id) = &self.agent_frame_id {
19 require_non_empty(type_name, "agent_frame_id", agent_frame_id)?;
20 }
21 Ok(())
22 }
23}
24
25#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, JsonSchema)]
26#[serde(transparent)]
27pub struct RemoteProcessExecutionEnvRef(String);
28
29impl RemoteProcessExecutionEnvRef {
30 pub const PREFIX: &'static str = "process-env:sha256:";
31
32 pub fn parse(value: impl Into<String>) -> Result<Self, RemoteProtocolError> {
33 let value = value.into();
34 if is_canonical_process_execution_env_ref(&value) {
35 Ok(Self(value))
36 } else {
37 Err(RemoteProtocolError::InvalidEnvelope {
38 type_name: "RemoteProcessExecutionEnvRef",
39 message:
40 "env_ref must match `process-env:sha256:<64 lowercase hex>`".to_string(),
41 })
42 }
43 }
44
45 pub fn as_str(&self) -> &str {
46 &self.0
47 }
48
49 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
50 if is_canonical_process_execution_env_ref(&self.0) {
51 Ok(())
52 } else {
53 Err(RemoteProtocolError::InvalidEnvelope {
54 type_name,
55 message:
56 "env_ref must match `process-env:sha256:<64 lowercase hex>`".to_string(),
57 })
58 }
59 }
60}
61
62impl std::fmt::Display for RemoteProcessExecutionEnvRef {
63 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 formatter.write_str(&self.0)
65 }
66}
67
68impl std::str::FromStr for RemoteProcessExecutionEnvRef {
69 type Err = RemoteProtocolError;
70
71 fn from_str(value: &str) -> Result<Self, Self::Err> {
72 Self::parse(value)
73 }
74}
75
76impl<'de> serde::Deserialize<'de> for RemoteProcessExecutionEnvRef {
77 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
78 where
79 D: serde::Deserializer<'de>,
80 {
81 let value = String::deserialize(deserializer)?;
82 Self::parse(value).map_err(serde::de::Error::custom)
83 }
84}
85
86fn is_canonical_process_execution_env_ref(value: &str) -> bool {
87 let Some(digest) = value.strip_prefix(RemoteProcessExecutionEnvRef::PREFIX) else {
88 return false;
89 };
90 digest.len() == 64
91 && digest
92 .bytes()
93 .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
94}
95
96#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
97#[serde(tag = "type", rename_all = "snake_case")]
98pub enum RemoteProcessOriginator {
99 Host,
100 Session { scope: RemoteSessionScope },
101}
102
103impl RemoteProcessOriginator {
104 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
105 match self {
106 Self::Host => Ok(()),
107 Self::Session { scope } => scope.validate(type_name),
108 }
109 }
110}
111
112#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
113pub struct RemoteProcessProvenance {
114 pub originator: RemoteProcessOriginator,
115 #[serde(default, skip_serializing_if = "Option::is_none")]
116 pub caused_by: Option<RemoteCausalRef>,
117}
118
119impl RemoteProcessProvenance {
120 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
121 self.originator.validate(type_name)
122 }
123}
124
125#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
126pub struct RemoteProcessDefinitionIdentity {
127 #[serde(default)]
128 pub value: serde_json::Value,
129}
130
131impl RemoteProcessDefinitionIdentity {
132 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
133 if self.value.is_null() {
134 return Err(RemoteProtocolError::InvalidEnvelope {
135 type_name,
136 message: "definition value cannot be null".to_string(),
137 });
138 }
139 Ok(())
140 }
141}
142
143#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
144pub struct RemoteProcessIdentity {
145 pub kind: String,
146 #[serde(default, skip_serializing_if = "Option::is_none")]
147 pub label: Option<String>,
148 #[serde(default, skip_serializing_if = "Option::is_none")]
149 pub definition: Option<RemoteProcessDefinitionIdentity>,
150}
151
152impl RemoteProcessIdentity {
153 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
154 require_non_empty(type_name, "identity.kind", &self.kind)?;
155 if let Some(definition) = &self.definition {
156 definition.validate(type_name)?;
157 }
158 Ok(())
159 }
160}
161
162#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
163pub struct RemoteProcessHandleDescriptor {
164 #[serde(default, skip_serializing_if = "Option::is_none")]
165 pub kind: Option<String>,
166 #[serde(default, skip_serializing_if = "Option::is_none")]
167 pub label: Option<String>,
168}
169
170impl RemoteProcessHandleDescriptor {
171 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
172 if let Some(kind) = &self.kind {
173 require_non_empty(type_name, "descriptor.kind", kind)?;
174 }
175 if let Some(label) = &self.label {
176 require_non_empty(type_name, "descriptor.label", label)?;
177 }
178 Ok(())
179 }
180}
181
182#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
183pub struct RemoteProcessStartGrant {
184 pub session_scope: RemoteSessionScope,
185 pub descriptor: RemoteProcessHandleDescriptor,
186}
187
188impl RemoteProcessStartGrant {
189 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
190 self.session_scope.validate(type_name)?;
191 self.descriptor.validate(type_name)
192 }
193}
194
195#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
196#[serde(tag = "type", rename_all = "snake_case")]
197#[allow(clippy::large_enum_variant)]
198pub enum RemoteProcessInput {
199 ToolCall {
200 #[serde(default)]
201 prepared_tool_call: serde_json::Value,
202 },
203 Engine {
204 kind: String,
205 #[serde(default)]
206 payload: serde_json::Value,
207 },
208 SessionTurn {
209 #[serde(default)]
210 create_request: serde_json::Value,
211 turn_input: RemoteTurnInput,
212 #[serde(default, skip_serializing_if = "RemoteToolOutputContract::is_static")]
213 output_contract: RemoteToolOutputContract,
214 },
215 External {
216 #[serde(default)]
217 metadata: serde_json::Value,
218 },
219}
220
221impl RemoteProcessInput {
222 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
223 match self {
224 Self::ToolCall {
225 prepared_tool_call: _,
226 } => Ok(()),
227 Self::Engine { kind, payload: _ } => require_non_empty(type_name, "kind", kind),
228 Self::SessionTurn {
229 create_request: _,
230 turn_input,
231 output_contract,
232 } => {
233 turn_input.validate()?;
234 match output_contract {
235 RemoteToolOutputContract::Static => Ok(()),
236 RemoteToolOutputContract::FromInputSchema {
237 input_field,
238 default_schema: _,
239 } => require_non_empty(type_name, "output_contract.input_field", input_field),
240 }
241 }
242 Self::External { metadata: _ } => Ok(()),
243 }
244 }
245}
246
247#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
248#[serde(rename_all = "snake_case")]
249pub enum RemoteProcessLifecycleStatus {
250 #[default]
251 Running,
252 Completed,
253 Failed,
254 Cancelled,
255}
256
257impl RemoteProcessLifecycleStatus {
258 pub fn is_terminal(self) -> bool {
259 !matches!(self, Self::Running)
260 }
261}
262
263#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
264#[serde(tag = "state", rename_all = "snake_case")]
265pub enum RemoteProcessStatus {
266 #[default]
267 Running,
268 Completed { await_output: RemoteProcessAwaitOutput },
269 Failed { await_output: RemoteProcessAwaitOutput },
270 Cancelled { await_output: RemoteProcessAwaitOutput },
271}
272
273#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
274#[serde(tag = "type", rename_all = "snake_case")]
275pub enum RemoteProcessAwaitOutput {
276 Success {
277 value: serde_json::Value,
278 #[serde(default, skip_serializing_if = "Option::is_none")]
279 control: Option<serde_json::Value>,
280 },
281 Failure {
282 class: RemoteToolFailureClass,
283 code: String,
284 message: String,
285 #[serde(default, skip_serializing_if = "Option::is_none")]
286 raw: Option<serde_json::Value>,
287 #[serde(default, skip_serializing_if = "Option::is_none")]
288 control: Option<serde_json::Value>,
289 },
290 Cancelled {
291 message: String,
292 #[serde(default, skip_serializing_if = "Option::is_none")]
293 raw: Option<serde_json::Value>,
294 #[serde(default, skip_serializing_if = "Option::is_none")]
295 control: Option<serde_json::Value>,
296 },
297}
298
299impl RemoteProcessAwaitOutput {
300 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
301 match self {
302 Self::Success { .. } => Ok(()),
303 Self::Failure { code, message, .. } => {
304 require_non_empty(type_name, "await_output.code", code)?;
305 require_non_empty(type_name, "await_output.message", message)
306 }
307 Self::Cancelled { message, .. } => {
308 require_non_empty(type_name, "await_output.message", message)
309 }
310 }
311 }
312}
313
314#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
315#[serde(rename_all = "snake_case")]
316pub enum RemoteToolFailureClass {
317 InvalidRequest,
318 Unavailable,
319 PermissionDenied,
320 Timeout,
321 Execution,
322 External,
323 ResourceLimit,
324 Internal,
325}
326
327#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
328pub struct RemoteProcessExternalRef {
329 pub backend: String,
330 pub id: String,
331 #[serde(default, skip_serializing_if = "Option::is_none")]
332 pub metadata: Option<serde_json::Value>,
333}
334
335impl RemoteProcessExternalRef {
336 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
337 require_non_empty(type_name, "external_ref.backend", &self.backend)?;
338 require_non_empty(type_name, "external_ref.id", &self.id)
339 }
340}
341
342#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
343pub struct RemoteProcessWaitState {
344 pub kind: RemoteProcessWaitKind,
345 pub since_ms: u64,
346}
347
348#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
349#[serde(tag = "kind", rename_all = "snake_case")]
350pub enum RemoteProcessWaitKind {
351 Signal {
352 name: String,
353 event_type: String,
354 key: String,
355 ordinal: u64,
356 },
357}
358
359impl RemoteProcessWaitState {
360 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
361 match &self.kind {
362 RemoteProcessWaitKind::Signal {
363 name,
364 event_type,
365 key,
366 ordinal,
367 } => {
368 require_non_empty(type_name, "wait.name", name)?;
369 require_non_empty(type_name, "wait.event_type", event_type)?;
370 require_non_empty(type_name, "wait.key", key)?;
371 if *ordinal == 0 {
372 return Err(RemoteProtocolError::InvalidEnvelope {
373 type_name,
374 message: "wait ordinal must be non-zero".to_string(),
375 });
376 }
377 Ok(())
378 }
379 }
380 }
381}
382
383#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
384pub struct RemoteProcessSummary {
385 #[serde(rename = "__handle__")]
386 pub handle_type: String,
387 pub id: String,
388 pub process_id: String,
389 pub descriptor: RemoteProcessHandleDescriptor,
390 #[serde(default, skip_serializing_if = "Option::is_none")]
391 pub definition: Option<RemoteProcessDefinitionIdentity>,
392 pub status: RemoteProcessLifecycleStatus,
393}
394
395impl RemoteProcessSummary {
396 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
397 require_non_empty(type_name, "handle_type", &self.handle_type)?;
398 require_non_empty(type_name, "id", &self.id)?;
399 require_non_empty(type_name, "process_id", &self.process_id)?;
400 self.descriptor.validate(type_name)?;
401 if let Some(definition) = &self.definition {
402 definition.validate(type_name)?;
403 }
404 Ok(())
405 }
406}
407
408#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
409pub struct RemoteProcessRecord {
410 pub process_id: String,
411 pub input: RemoteProcessInput,
412 pub identity: RemoteProcessIdentity,
413 #[serde(default, skip_serializing_if = "Vec::is_empty")]
414 pub event_types: Vec<RemoteProcessEventType>,
415 pub provenance: RemoteProcessProvenance,
416 #[serde(default, skip_serializing_if = "Option::is_none")]
417 pub env_ref: Option<RemoteProcessExecutionEnvRef>,
418 #[serde(default, skip_serializing_if = "Option::is_none")]
419 pub wake_target: Option<RemoteSessionScope>,
420 pub created_at_ms: u64,
421 pub updated_at_ms: u64,
422 #[serde(default, skip_serializing_if = "Option::is_none")]
423 pub external_ref: Option<RemoteProcessExternalRef>,
424 #[serde(default, skip_serializing_if = "Option::is_none")]
425 pub wait: Option<RemoteProcessWaitState>,
426 #[serde(default)]
427 pub status: RemoteProcessStatus,
428}
429
430impl RemoteProcessRecord {
431 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
432 require_non_empty(type_name, "process_id", &self.process_id)?;
433 self.input.validate(type_name)?;
434 self.identity.validate(type_name)?;
435 for event_type in &self.event_types {
436 event_type.validate(type_name)?;
437 }
438 self.provenance.validate(type_name)?;
439 if let Some(env_ref) = &self.env_ref {
440 env_ref.validate(type_name)?;
441 }
442 if let Some(wake_target) = &self.wake_target {
443 wake_target.validate(type_name)?;
444 }
445 if let Some(external_ref) = &self.external_ref {
446 external_ref.validate(type_name)?;
447 }
448 if let Some(wait) = &self.wait {
449 wait.validate(type_name)?;
450 }
451 match &self.status {
452 RemoteProcessStatus::Running => Ok(()),
453 RemoteProcessStatus::Completed { await_output }
454 | RemoteProcessStatus::Failed { await_output }
455 | RemoteProcessStatus::Cancelled { await_output } => await_output.validate(type_name),
456 }
457 }
458}
459
460#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
461pub struct RemoteProcessWorkSnapshot {
462 pub protocol_version: u32,
463 pub session_id: String,
464 #[serde(default)]
465 pub visible_process_ids: Vec<String>,
466 #[serde(default)]
467 pub items: Vec<RemoteProcessWorkItem>,
468}
469
470impl RemoteProcessWorkSnapshot {
471 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
472 ensure_protocol_version(self.protocol_version)?;
473 require_non_empty("RemoteProcessWorkSnapshot", "session_id", &self.session_id)?;
474 for process_id in &self.visible_process_ids {
475 require_non_empty("RemoteProcessWorkSnapshot", "visible_process_ids", process_id)?;
476 }
477 for item in &self.items {
478 item.validate("RemoteProcessWorkSnapshot")?;
479 }
480 Ok(())
481 }
482}
483
484#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
485pub struct RemoteProcessWorkItem {
486 pub process: RemoteObservedProcess,
487 pub descriptor: RemoteProcessHandleDescriptor,
488 #[serde(default)]
489 pub events: Vec<RemoteObservedProcessEvent>,
490 pub kind: String,
491 pub label: String,
492}
493
494impl RemoteProcessWorkItem {
495 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
496 self.process.validate(type_name)?;
497 self.descriptor.validate(type_name)?;
498 for event in &self.events {
499 event.validate(type_name)?;
500 }
501 require_non_empty(type_name, "kind", &self.kind)?;
502 require_non_empty(type_name, "label", &self.label)
503 }
504}
505
506#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
507pub struct RemoteObservedProcess {
508 pub process_id: String,
509 pub graph_key: String,
510 pub kind: String,
511 pub identity: RemoteProcessIdentity,
512 pub lifecycle: RemoteProcessLifecycleStatus,
513 pub status_label: String,
514 pub terminal: bool,
515 #[serde(default, skip_serializing_if = "Option::is_none")]
516 pub error: Option<String>,
517 pub created_at_ms: u64,
518 pub updated_at_ms: u64,
519 pub input: RemoteProcessInput,
520 pub originator: RemoteProcessOriginator,
521 #[serde(default, skip_serializing_if = "Option::is_none")]
522 pub env_ref: Option<RemoteProcessExecutionEnvRef>,
523 #[serde(default, skip_serializing_if = "Option::is_none")]
524 pub wake_target: Option<RemoteSessionScope>,
525 #[serde(default, skip_serializing_if = "Option::is_none")]
526 pub caused_by: Option<RemoteCausalRef>,
527 #[serde(default, skip_serializing_if = "Option::is_none")]
528 pub external_ref: Option<RemoteProcessExternalRef>,
529 #[serde(default, skip_serializing_if = "Option::is_none")]
530 pub wait: Option<RemoteProcessWaitState>,
531 #[serde(default, skip_serializing_if = "Option::is_none")]
532 pub child_session_id: Option<String>,
533 pub label: String,
534}
535
536impl RemoteObservedProcess {
537 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
538 require_non_empty(type_name, "process_id", &self.process_id)?;
539 require_non_empty(type_name, "graph_key", &self.graph_key)?;
540 require_non_empty(type_name, "kind", &self.kind)?;
541 self.identity.validate(type_name)?;
542 require_non_empty(type_name, "status_label", &self.status_label)?;
543 self.input.validate(type_name)?;
544 self.originator.validate(type_name)?;
545 if let Some(env_ref) = &self.env_ref {
546 env_ref.validate(type_name)?;
547 }
548 if let Some(wake_target) = &self.wake_target {
549 wake_target.validate(type_name)?;
550 }
551 if let Some(external_ref) = &self.external_ref {
552 external_ref.validate(type_name)?;
553 }
554 if let Some(wait) = &self.wait {
555 wait.validate(type_name)?;
556 }
557 if let Some(child_session_id) = &self.child_session_id {
558 require_non_empty(type_name, "child_session_id", child_session_id)?;
559 }
560 require_non_empty(type_name, "label", &self.label)
561 }
562}
563
564#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
565pub struct RemoteObservedProcessEvent {
566 pub sequence: u64,
567 pub event_type: String,
568 pub occurred_at_ms: u64,
569 #[serde(default)]
570 pub payload: serde_json::Value,
571}
572
573impl RemoteObservedProcessEvent {
574 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
575 require_non_empty(type_name, "event_type", &self.event_type)
576 }
577}
578
579#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
580pub struct RemoteProcessEvent {
581 pub process_id: String,
582 pub sequence: u64,
583 pub event_type: String,
584 #[serde(default)]
585 pub payload: serde_json::Value,
586 #[serde(default, skip_serializing_if = "Option::is_none")]
587 pub invocation: Option<RemoteRuntimeInvocation>,
588 #[serde(default)]
589 pub semantics: RemoteProcessEventSemantics,
590 pub occurred_at_ms: u64,
591}
592
593impl RemoteProcessEvent {
594 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
595 require_non_empty(type_name, "process_id", &self.process_id)?;
596 require_non_empty(type_name, "event_type", &self.event_type)?;
597 if let Some(invocation) = &self.invocation {
598 invocation.validate(type_name)?;
599 }
600 self.semantics.validate(type_name)
601 }
602}
603
604#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
605pub struct RemoteProcessEventType {
606 pub name: String,
607 #[serde(default)]
608 pub payload_schema: serde_json::Value,
609 #[serde(default)]
610 pub semantics: RemoteProcessEventSemanticsSpec,
611}
612
613impl RemoteProcessEventType {
614 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
615 require_non_empty(type_name, "event_type.name", &self.name)?;
616 self.semantics.validate(type_name)
617 }
618}
619
620#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
621pub struct RemoteProcessEventSemanticsSpec {
622 #[serde(default, skip_serializing_if = "Option::is_none")]
623 pub terminal: Option<RemoteProcessTerminalSpec>,
624 #[serde(default, skip_serializing_if = "Option::is_none")]
625 pub wake: Option<RemoteProcessWakeSpec>,
626}
627
628impl RemoteProcessEventSemanticsSpec {
629 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
630 if let Some(terminal) = &self.terminal {
631 terminal.validate(type_name)?;
632 }
633 if let Some(wake) = &self.wake {
634 wake.validate(type_name)?;
635 }
636 Ok(())
637 }
638}
639
640#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
641pub struct RemoteProcessTerminalSpec {
642 pub state: RemoteProcessTerminalState,
643 #[serde(default, skip_serializing_if = "Option::is_none")]
644 pub await_output: Option<RemoteProcessValueSelector>,
645}
646
647impl RemoteProcessTerminalSpec {
648 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
649 if let Some(await_output) = &self.await_output {
650 await_output.validate(type_name)?;
651 }
652 Ok(())
653 }
654}
655
656#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
657pub struct RemoteProcessWakeSpec {
658 #[serde(default, skip_serializing_if = "Option::is_none")]
659 pub when: Option<RemoteProcessValueSelector>,
660 pub input: RemoteProcessValueSelector,
661 #[serde(default)]
662 pub dedupe_key: RemoteProcessWakeDedupeKey,
663}
664
665impl RemoteProcessWakeSpec {
666 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
667 if let Some(when) = &self.when {
668 when.validate(type_name)?;
669 }
670 self.input.validate(type_name)?;
671 self.dedupe_key.validate(type_name)
672 }
673}
674
675#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
676pub struct RemoteProcessEventSemantics {
677 #[serde(default, skip_serializing_if = "Option::is_none")]
678 pub terminal: Option<RemoteProcessTerminalSemantics>,
679 #[serde(default, skip_serializing_if = "Option::is_none")]
680 pub wake: Option<RemoteProcessWake>,
681}
682
683impl RemoteProcessEventSemantics {
684 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
685 if let Some(terminal) = &self.terminal {
686 terminal.await_output.validate(type_name)?;
687 }
688 if let Some(wake) = &self.wake {
689 wake.validate(type_name)?;
690 }
691 Ok(())
692 }
693}
694
695#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
696#[serde(rename_all = "snake_case")]
697pub enum RemoteProcessTerminalState {
698 Completed,
699 Failed,
700 Cancelled,
701}
702
703#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
704pub struct RemoteProcessTerminalSemantics {
705 pub state: RemoteProcessTerminalState,
706 pub await_output: RemoteProcessAwaitOutput,
707}
708
709#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
710pub struct RemoteProcessWake {
711 pub input: String,
712 pub dedupe_key: String,
713}
714
715impl RemoteProcessWake {
716 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
717 require_non_empty(type_name, "wake.input", &self.input)?;
718 require_non_empty(type_name, "wake.dedupe_key", &self.dedupe_key)
719 }
720}
721
722#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
723#[serde(rename_all = "snake_case")]
724pub enum RemoteProcessWakeDedupeKey {
725 #[default]
726 EventIdentity,
727 Selector(RemoteProcessValueSelector),
728 Const(String),
729}
730
731impl RemoteProcessWakeDedupeKey {
732 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
733 match self {
734 Self::EventIdentity => Ok(()),
735 Self::Selector(selector) => selector.validate(type_name),
736 Self::Const(value) => require_non_empty(type_name, "wake.dedupe_key.const", value),
737 }
738 }
739}
740
741#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
742#[serde(rename_all = "snake_case")]
743pub enum RemoteProcessValueSelector {
744 Payload,
745 Pointer(String),
746 Const(serde_json::Value),
747 Template {
748 template: String,
749 #[serde(default)]
750 fields: BTreeMap<String, RemoteProcessValueSelector>,
751 },
752 Present(String),
753}
754
755impl RemoteProcessValueSelector {
756 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
757 match self {
758 Self::Payload | Self::Const(_) => Ok(()),
759 Self::Pointer(pointer) => require_non_empty(type_name, "selector.pointer", pointer),
760 Self::Template { template, fields } => {
761 require_non_empty(type_name, "selector.template", template)?;
762 for (name, selector) in fields {
763 require_non_empty(type_name, "selector.field", name)?;
764 selector.validate(type_name)?;
765 }
766 Ok(())
767 }
768 Self::Present(pointer) => require_non_empty(type_name, "selector.present", pointer),
769 }
770 }
771}
772
773#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
774pub struct RemoteRuntimeInvocation {
775 pub scope: RemoteRuntimeScope,
776 pub subject: RemoteRuntimeSubject,
777 #[serde(default, skip_serializing_if = "Option::is_none")]
778 pub caused_by: Option<RemoteCausalRef>,
779 #[serde(default, skip_serializing_if = "Option::is_none")]
780 pub replay: Option<RemoteRuntimeReplay>,
781}
782
783impl RemoteRuntimeInvocation {
784 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
785 self.scope.validate(type_name)?;
786 self.subject.validate(type_name)?;
787 if let Some(replay) = &self.replay {
788 require_non_empty(type_name, "replay.key", &replay.key)?;
789 }
790 Ok(())
791 }
792}
793
794#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
795pub struct RemoteRuntimeScope {
796 pub session_id: String,
797 #[serde(default, skip_serializing_if = "Option::is_none")]
798 pub turn_id: Option<String>,
799 #[serde(default, skip_serializing_if = "Option::is_none")]
800 pub turn_index: Option<usize>,
801 #[serde(default, skip_serializing_if = "Option::is_none")]
802 pub protocol_iteration: Option<usize>,
803}
804
805impl RemoteRuntimeScope {
806 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
807 require_non_empty(type_name, "runtime_scope.session_id", &self.session_id)?;
808 if let Some(turn_id) = &self.turn_id {
809 require_non_empty(type_name, "runtime_scope.turn_id", turn_id)?;
810 }
811 Ok(())
812 }
813}
814
815#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
816pub struct RemoteRuntimeReplay {
817 pub key: String,
818}
819
820#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
821#[serde(tag = "type", rename_all = "snake_case")]
822pub enum RemoteRuntimeSubject {
823 Effect {
824 effect_id: String,
825 kind: RemoteRuntimeEffectKind,
826 },
827 Process {
828 process_id: String,
829 },
830 ProcessEvent {
831 process_id: String,
832 sequence: u64,
833 event_type: String,
834 },
835 TriggerOccurrence {
836 occurrence_id: String,
837 },
838 SessionNode {
839 node_id: String,
840 },
841}
842
843impl RemoteRuntimeSubject {
844 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
845 match self {
846 Self::Effect { effect_id, .. } => {
847 require_non_empty(type_name, "runtime_subject.effect_id", effect_id)
848 }
849 Self::Process { process_id } => {
850 require_non_empty(type_name, "runtime_subject.process_id", process_id)
851 }
852 Self::ProcessEvent {
853 process_id,
854 event_type,
855 ..
856 } => {
857 require_non_empty(type_name, "runtime_subject.process_id", process_id)?;
858 require_non_empty(type_name, "runtime_subject.event_type", event_type)
859 }
860 Self::TriggerOccurrence { occurrence_id } => {
861 require_non_empty(type_name, "runtime_subject.occurrence_id", occurrence_id)
862 }
863 Self::SessionNode { node_id } => {
864 require_non_empty(type_name, "runtime_subject.node_id", node_id)
865 }
866 }
867 }
868}
869
870#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
871#[serde(rename_all = "snake_case")]
872pub enum RemoteRuntimeEffectKind {
873 LlmCall,
874 Direct,
875 ToolAttempt,
876 ToolBatch,
877 Process,
878 ExecCode,
879 Checkpoint,
880 SyncExecutionEnvironment,
881 Sleep,
882 AwaitEvent,
883 DurableStep,
884}
885
886#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
887#[serde(deny_unknown_fields)]
888pub struct RemoteProcessPluginOptions {
889 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
890 pub plugins: BTreeMap<String, serde_json::Value>,
891}
892
893fn default_remote_context_window_tokens() -> usize {
894 1
895}
896
897#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
898#[serde(deny_unknown_fields)]
899pub struct RemoteProcessModelLimits {
900 #[serde(default = "default_remote_context_window_tokens")]
901 pub context_window_tokens: usize,
902 #[serde(default, skip_serializing_if = "Option::is_none")]
903 pub output_token_capacity: Option<usize>,
904}
905
906impl Default for RemoteProcessModelLimits {
907 fn default() -> Self {
908 Self {
909 context_window_tokens: default_remote_context_window_tokens(),
910 output_token_capacity: None,
911 }
912 }
913}
914
915#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
916#[serde(deny_unknown_fields)]
917pub struct RemoteProcessModelSpec {
918 #[serde(default)]
919 pub id: String,
920 #[serde(default, skip_serializing_if = "Option::is_none")]
921 pub variant: Option<String>,
922 #[serde(default)]
923 pub limits: RemoteProcessModelLimits,
924}
925
926#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
927#[serde(deny_unknown_fields)]
928pub struct RemoteProcessExecutionPolicy {
929 #[serde(default)]
930 pub model: RemoteProcessModelSpec,
931 #[serde(default)]
932 pub provider_id: String,
933 #[serde(default, skip_serializing_if = "Option::is_none")]
934 pub session_id: Option<String>,
935 #[serde(default)]
936 pub autonomous: bool,
937 #[serde(default, skip_serializing_if = "Option::is_none")]
938 pub max_turns: Option<usize>,
939 #[serde(default, skip_serializing_if = "RemotePromptLayer::is_empty")]
940 pub prompt: RemotePromptLayer,
941}
942
943#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
944#[serde(deny_unknown_fields)]
945pub struct RemoteProcessExecutionEnvSpec {
946 #[serde(default, skip_serializing_if = "RemoteProcessPluginOptions::is_empty")]
947 pub plugin_options: RemoteProcessPluginOptions,
948 #[serde(default, skip_serializing_if = "RemoteProcessExecutionPolicy::is_empty")]
949 pub policy: RemoteProcessExecutionPolicy,
950}
951
952impl RemoteProcessPluginOptions {
953 pub fn is_empty(&self) -> bool {
954 self.plugins.is_empty()
955 }
956}
957
958impl RemoteProcessExecutionPolicy {
959 pub fn is_empty(&self) -> bool {
960 self == &Self::default()
961 }
962}
963
964impl RemoteProcessExecutionEnvSpec {
965 pub fn is_empty(&self) -> bool {
966 self.plugin_options.is_empty() && self.policy.is_empty()
967 }
968
969 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
970 if self.policy.model.limits.context_window_tokens == 0 {
971 return Err(RemoteProtocolError::InvalidEnvelope {
972 type_name,
973 message: "env_spec.policy.model.limits.context_window_tokens must be greater than zero"
974 .to_string(),
975 });
976 }
977 if self
978 .policy
979 .model
980 .limits
981 .output_token_capacity
982 .is_some_and(|value| value == 0)
983 {
984 return Err(RemoteProtocolError::InvalidEnvelope {
985 type_name,
986 message:
987 "env_spec.policy.model.limits.output_token_capacity must be greater than zero"
988 .to_string(),
989 });
990 }
991 Ok(())
992 }
993}
994
995#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
996pub struct RemotePersistProcessEnvRequest {
997 pub protocol_version: u32,
998 pub env_spec: RemoteProcessExecutionEnvSpec,
999}
1000
1001impl RemotePersistProcessEnvRequest {
1002 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
1003 ensure_protocol_version(self.protocol_version)?;
1004 self.env_spec.validate("RemotePersistProcessEnvRequest")
1005 }
1006}
1007
1008#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1009pub struct RemotePersistProcessEnvResult {
1010 pub protocol_version: u32,
1011 pub env_ref: RemoteProcessExecutionEnvRef,
1012}
1013
1014impl RemotePersistProcessEnvResult {
1015 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
1016 ensure_protocol_version(self.protocol_version)?;
1017 self.env_ref.validate("RemotePersistProcessEnvResult")
1018 }
1019}
1020
1021#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
1022pub struct RemoteProcessStartRequest {
1023 pub protocol_version: u32,
1024 pub id: String,
1025 pub input: RemoteProcessInput,
1026 #[serde(default, skip_serializing_if = "Option::is_none")]
1027 pub env_spec: Option<RemoteProcessExecutionEnvSpec>,
1028 pub originator: RemoteProcessOriginator,
1029 #[serde(default, skip_serializing_if = "Option::is_none")]
1030 pub wake_target: Option<RemoteSessionScope>,
1031 #[serde(default, skip_serializing_if = "Option::is_none")]
1032 pub grant: Option<RemoteProcessStartGrant>,
1033 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1034 pub event_types: Vec<RemoteProcessEventType>,
1035}
1036
1037impl RemoteProcessStartRequest {
1038 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
1039 ensure_protocol_version(self.protocol_version)?;
1040 require_non_empty("RemoteProcessStartRequest", "id", &self.id)?;
1041 self.input.validate("RemoteProcessStartRequest")?;
1042 if let Some(env_spec) = &self.env_spec {
1043 env_spec.validate("RemoteProcessStartRequest")?;
1044 }
1045 if let RemoteProcessInput::SessionTurn { turn_input, .. } = &self.input
1046 && turn_input.protocol_version != self.protocol_version
1047 {
1048 return Err(RemoteProtocolError::MismatchedNestedProtocolVersion {
1049 parent: "RemoteProcessStartRequest",
1050 child: "input.turn_input",
1051 parent_version: self.protocol_version,
1052 child_version: turn_input.protocol_version,
1053 });
1054 }
1055 self.originator.validate("RemoteProcessStartRequest")?;
1056 if let Some(wake_target) = &self.wake_target {
1057 wake_target.validate("RemoteProcessStartRequest")?;
1058 }
1059 if let Some(grant) = &self.grant {
1060 grant.validate("RemoteProcessStartRequest")?;
1061 }
1062 for event_type in &self.event_types {
1063 event_type.validate("RemoteProcessStartRequest")?;
1064 }
1065 Ok(())
1066 }
1067}
1068
1069#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
1070pub struct RemoteProcessStartResult {
1071 pub protocol_version: u32,
1072 pub record: RemoteProcessRecord,
1073 #[serde(default, skip_serializing_if = "Option::is_none")]
1074 pub summary: Option<RemoteProcessSummary>,
1075}
1076
1077impl RemoteProcessStartResult {
1078 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
1079 ensure_protocol_version(self.protocol_version)?;
1080 self.record.validate("RemoteProcessStartResult")?;
1081 if let Some(summary) = &self.summary {
1082 summary.validate("RemoteProcessStartResult")?;
1083 }
1084 Ok(())
1085 }
1086}
1087
1088#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1089#[serde(rename_all = "snake_case")]
1090pub enum RemoteProcessStatusFilter {
1091 #[default]
1092 Running,
1093 Completed,
1094 Failed,
1095 Cancelled,
1096 Any,
1097}
1098
1099#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
1100pub struct RemoteProcessListFilter {
1101 pub protocol_version: u32,
1102 #[serde(default, skip_serializing_if = "Option::is_none")]
1103 pub definition: Option<RemoteProcessDefinitionIdentity>,
1104 #[serde(default)]
1105 pub status: RemoteProcessStatusFilter,
1106 #[serde(default, skip_serializing_if = "Option::is_none")]
1107 pub waiting: Option<bool>,
1108}
1109
1110impl Default for RemoteProcessListFilter {
1111 fn default() -> Self {
1112 Self {
1113 protocol_version: REMOTE_PROTOCOL_VERSION,
1114 definition: None,
1115 status: RemoteProcessStatusFilter::Running,
1116 waiting: None,
1117 }
1118 }
1119}
1120
1121impl RemoteProcessListFilter {
1122 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
1123 ensure_protocol_version(self.protocol_version)?;
1124 if let Some(definition) = &self.definition {
1125 definition.validate("RemoteProcessListFilter")?;
1126 }
1127 Ok(())
1128 }
1129}
1130
1131#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
1132pub struct RemoteProcessListResponse {
1133 pub protocol_version: u32,
1134 #[serde(default)]
1135 pub records: Vec<RemoteObservedProcess>,
1136}
1137
1138impl RemoteProcessListResponse {
1139 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
1140 ensure_protocol_version(self.protocol_version)?;
1141 for record in &self.records {
1142 record.validate("RemoteProcessListResponse")?;
1143 }
1144 Ok(())
1145 }
1146}
1147
1148#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1149pub struct RemoteProcessCancelRequest {
1150 pub protocol_version: u32,
1151 pub process_id: String,
1152 #[serde(default, skip_serializing_if = "Option::is_none")]
1153 pub reason: Option<String>,
1154}
1155
1156impl RemoteProcessCancelRequest {
1157 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
1158 ensure_protocol_version(self.protocol_version)?;
1159 require_non_empty(
1160 "RemoteProcessCancelRequest",
1161 "process_id",
1162 &self.process_id,
1163 )?;
1164 if let Some(reason) = &self.reason {
1165 require_non_empty("RemoteProcessCancelRequest", "reason", reason)?;
1166 }
1167 Ok(())
1168 }
1169}
1170
1171#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
1172pub struct RemoteProcessCancelResult {
1173 pub protocol_version: u32,
1174 pub process_id: String,
1175 pub status: RemoteProcessLifecycleStatus,
1176 #[serde(default, skip_serializing_if = "Option::is_none")]
1177 pub record: Option<RemoteProcessRecord>,
1178}
1179
1180impl RemoteProcessCancelResult {
1181 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
1182 ensure_protocol_version(self.protocol_version)?;
1183 require_non_empty(
1184 "RemoteProcessCancelResult",
1185 "process_id",
1186 &self.process_id,
1187 )?;
1188 if let Some(record) = &self.record {
1189 record.validate("RemoteProcessCancelResult")?;
1190 }
1191 Ok(())
1192 }
1193}
1194
1195#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
1196pub struct RemoteProcessSignalRequest {
1197 pub protocol_version: u32,
1198 pub process_id: String,
1199 pub signal_name: String,
1200 pub signal_id: String,
1201 #[serde(default)]
1202 pub payload: serde_json::Value,
1203 #[serde(default, skip_serializing_if = "Option::is_none")]
1204 pub replay_key: Option<String>,
1205 #[serde(default, skip_serializing_if = "Option::is_none")]
1206 pub wake_target_scope: Option<RemoteSessionScope>,
1207}
1208
1209impl RemoteProcessSignalRequest {
1210 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
1211 ensure_protocol_version(self.protocol_version)?;
1212 require_non_empty(
1213 "RemoteProcessSignalRequest",
1214 "process_id",
1215 &self.process_id,
1216 )?;
1217 require_non_empty(
1218 "RemoteProcessSignalRequest",
1219 "signal_name",
1220 &self.signal_name,
1221 )?;
1222 require_non_empty(
1223 "RemoteProcessSignalRequest",
1224 "signal_id",
1225 &self.signal_id,
1226 )?;
1227 if let Some(replay_key) = &self.replay_key {
1228 require_non_empty("RemoteProcessSignalRequest", "replay_key", replay_key)?;
1229 }
1230 if let Some(scope) = &self.wake_target_scope {
1231 scope.validate("RemoteProcessSignalRequest")?;
1232 }
1233 Ok(())
1234 }
1235}
1236
1237#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
1238pub struct RemoteProcessSignalResult {
1239 pub protocol_version: u32,
1240 pub event: RemoteProcessEvent,
1241}
1242
1243impl RemoteProcessSignalResult {
1244 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
1245 ensure_protocol_version(self.protocol_version)?;
1246 self.event.validate("RemoteProcessSignalResult")
1247 }
1248}
1249
1250#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1251pub struct RemoteProcessAwaitRequest {
1252 pub protocol_version: u32,
1253 pub process_id: String,
1254}
1255
1256impl RemoteProcessAwaitRequest {
1257 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
1258 ensure_protocol_version(self.protocol_version)?;
1259 require_non_empty(
1260 "RemoteProcessAwaitRequest",
1261 "process_id",
1262 &self.process_id,
1263 )
1264 }
1265}
1266
1267#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
1268pub struct RemoteProcessAwaitResult {
1269 pub protocol_version: u32,
1270 pub process_id: String,
1271 pub output: RemoteProcessAwaitOutput,
1272}
1273
1274impl RemoteProcessAwaitResult {
1275 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
1276 ensure_protocol_version(self.protocol_version)?;
1277 require_non_empty(
1278 "RemoteProcessAwaitResult",
1279 "process_id",
1280 &self.process_id,
1281 )?;
1282 self.output.validate("RemoteProcessAwaitResult")
1283 }
1284}
1285
1286#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1287pub struct RemoteProcessEventsRequest {
1288 pub protocol_version: u32,
1289 pub process_id: String,
1290 #[serde(default)]
1291 pub after_sequence: u64,
1292}
1293
1294impl RemoteProcessEventsRequest {
1295 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
1296 ensure_protocol_version(self.protocol_version)?;
1297 require_non_empty(
1298 "RemoteProcessEventsRequest",
1299 "process_id",
1300 &self.process_id,
1301 )
1302 }
1303}
1304
1305#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
1306pub struct RemoteProcessEventsResponse {
1307 pub protocol_version: u32,
1308 pub process_id: String,
1309 #[serde(default)]
1310 pub events: Vec<RemoteProcessEvent>,
1311}
1312
1313impl RemoteProcessEventsResponse {
1314 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
1315 ensure_protocol_version(self.protocol_version)?;
1316 require_non_empty(
1317 "RemoteProcessEventsResponse",
1318 "process_id",
1319 &self.process_id,
1320 )?;
1321 for event in &self.events {
1322 event.validate("RemoteProcessEventsResponse")?;
1323 }
1324 Ok(())
1325 }
1326}