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