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