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