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