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