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