Skip to main content

lash_remote_protocol/protocol/
processes.rs

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