1use serde::{Deserialize, Serialize};
25use std::fmt;
26use svix_ksuid::{Ksuid, KsuidLike};
27
28fn new_ksuid() -> String {
30 Ksuid::new(None, None).to_string()
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
44pub struct ExecutionId(String);
45
46impl ExecutionId {
47 pub fn new() -> Self {
49 Self(format!("exec_{}", new_ksuid()))
50 }
51
52 pub fn from_string(s: impl Into<String>) -> Self {
54 Self(s.into())
55 }
56
57 pub fn as_str(&self) -> &str {
59 &self.0
60 }
61}
62
63impl Default for ExecutionId {
64 fn default() -> Self {
65 Self::new()
66 }
67}
68
69impl fmt::Display for ExecutionId {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 write!(f, "{}", self.0)
72 }
73}
74
75impl From<String> for ExecutionId {
76 fn from(s: String) -> Self {
77 Self(s)
78 }
79}
80
81impl From<&str> for ExecutionId {
82 fn from(s: &str) -> Self {
83 Self(s.to_string())
84 }
85}
86
87pub type RunId = ExecutionId;
89
90#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
101pub struct StepId(String);
102
103impl StepId {
104 pub fn new() -> Self {
106 Self(format!("step_{}", new_ksuid()))
107 }
108
109 pub fn from_string(s: impl Into<String>) -> Self {
111 Self(s.into())
112 }
113
114 pub fn as_str(&self) -> &str {
116 &self.0
117 }
118}
119
120impl Default for StepId {
121 fn default() -> Self {
122 Self::new()
123 }
124}
125
126impl fmt::Display for StepId {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 write!(f, "{}", self.0)
129 }
130}
131
132impl From<String> for StepId {
133 fn from(s: String) -> Self {
134 Self(s)
135 }
136}
137
138impl From<&str> for StepId {
139 fn from(s: &str) -> Self {
140 Self(s.to_string())
141 }
142}
143
144pub type NodeId = StepId;
146
147#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
158pub struct GraphId(String);
159
160impl GraphId {
161 pub fn new() -> Self {
162 Self(format!("graph_{}", new_ksuid()))
163 }
164
165 pub fn from_string(s: impl Into<String>) -> Self {
166 Self(s.into())
167 }
168
169 pub fn as_str(&self) -> &str {
170 &self.0
171 }
172}
173
174impl Default for GraphId {
175 fn default() -> Self {
176 Self::new()
177 }
178}
179
180impl fmt::Display for GraphId {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 write!(f, "{}", self.0)
183 }
184}
185
186#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
196pub struct ArtifactId(String);
197
198impl ArtifactId {
199 pub fn new() -> Self {
200 Self(format!("artifact_{}", new_ksuid()))
201 }
202
203 pub fn from_string(s: impl Into<String>) -> Self {
204 Self(s.into())
205 }
206
207 pub fn as_str(&self) -> &str {
208 &self.0
209 }
210}
211
212impl Default for ArtifactId {
213 fn default() -> Self {
214 Self::new()
215 }
216}
217
218impl fmt::Display for ArtifactId {
219 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220 write!(f, "{}", self.0)
221 }
222}
223
224#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
232pub struct TenantId(String);
233
234impl TenantId {
235 pub fn new() -> Self {
236 Self(format!("tenant_{}", new_ksuid()))
237 }
238
239 pub fn from_string(s: impl Into<String>) -> Self {
240 Self(s.into())
241 }
242
243 pub fn as_str(&self) -> &str {
244 &self.0
245 }
246}
247
248impl Default for TenantId {
249 fn default() -> Self {
250 Self::new()
251 }
252}
253
254impl fmt::Display for TenantId {
255 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256 write!(f, "{}", self.0)
257 }
258}
259
260impl From<String> for TenantId {
261 fn from(s: String) -> Self {
262 Self(s)
263 }
264}
265
266impl From<&str> for TenantId {
267 fn from(s: &str) -> Self {
268 Self(s.to_string())
269 }
270}
271
272#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
276pub struct UserId(String);
277
278impl UserId {
279 pub fn new() -> Self {
280 Self(format!("user_{}", new_ksuid()))
281 }
282
283 pub fn from_string(s: impl Into<String>) -> Self {
284 Self(s.into())
285 }
286
287 pub fn as_str(&self) -> &str {
288 &self.0
289 }
290}
291
292impl Default for UserId {
293 fn default() -> Self {
294 Self::new()
295 }
296}
297
298impl fmt::Display for UserId {
299 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300 write!(f, "{}", self.0)
301 }
302}
303
304impl From<String> for UserId {
305 fn from(s: String) -> Self {
306 Self(s)
307 }
308}
309
310impl From<&str> for UserId {
311 fn from(s: &str) -> Self {
312 Self(s.to_string())
313 }
314}
315
316#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
322#[serde(rename_all = "PascalCase")]
323pub enum StepType {
324 LlmNode,
326 GraphNode,
328 ToolNode,
330 FunctionNode,
332 RouterNode,
334 BranchNode,
336 LoopNode,
338}
339
340impl fmt::Display for StepType {
341 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
342 match self {
343 StepType::LlmNode => write!(f, "LlmNode"),
344 StepType::GraphNode => write!(f, "GraphNode"),
345 StepType::ToolNode => write!(f, "ToolNode"),
346 StepType::FunctionNode => write!(f, "FunctionNode"),
347 StepType::RouterNode => write!(f, "RouterNode"),
348 StepType::BranchNode => write!(f, "BranchNode"),
349 StepType::LoopNode => write!(f, "LoopNode"),
350 }
351 }
352}
353
354#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
363#[serde(rename_all = "snake_case")]
364pub enum CallableType {
365 Completion,
367 Chat,
369 #[default]
371 Agent,
372 Workflow,
374 Background,
376 Composite,
378 Tool,
380 Custom,
382}
383
384impl fmt::Display for CallableType {
385 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
386 match self {
387 CallableType::Completion => write!(f, "completion"),
388 CallableType::Chat => write!(f, "chat"),
389 CallableType::Agent => write!(f, "agent"),
390 CallableType::Workflow => write!(f, "workflow"),
391 CallableType::Background => write!(f, "background"),
392 CallableType::Composite => write!(f, "composite"),
393 CallableType::Tool => write!(f, "tool"),
394 CallableType::Custom => write!(f, "custom"),
395 }
396 }
397}
398
399#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
408#[serde(rename_all = "snake_case")]
409pub enum ParentType {
410 UserMessage,
412 ScheduleEvent,
414 StepExecution,
416 Webhook,
418 A2aRequest,
420 System,
422 AssistantMessage,
424 ThreadStart,
426 ToolResult,
428}
429
430impl fmt::Display for ParentType {
431 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
432 match self {
433 ParentType::UserMessage => write!(f, "user_message"),
434 ParentType::ScheduleEvent => write!(f, "schedule_event"),
435 ParentType::StepExecution => write!(f, "step_execution"),
436 ParentType::Webhook => write!(f, "webhook"),
437 ParentType::A2aRequest => write!(f, "a2a_request"),
438 ParentType::System => write!(f, "system"),
439 ParentType::AssistantMessage => write!(f, "assistant_message"),
440 ParentType::ThreadStart => write!(f, "thread_start"),
441 ParentType::ToolResult => write!(f, "tool_result"),
442 }
443 }
444}
445
446#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
450pub struct ParentLink {
451 pub parent_id: String,
453 pub parent_type: ParentType,
455}
456
457impl ParentLink {
458 pub fn new(parent_id: impl Into<String>, parent_type: ParentType) -> Self {
460 Self {
461 parent_id: parent_id.into(),
462 parent_type,
463 }
464 }
465
466 pub fn from_user_message(message_id: impl Into<String>) -> Self {
468 Self::new(message_id, ParentType::UserMessage)
469 }
470
471 pub fn from_step(step_id: &StepId) -> Self {
473 Self::new(step_id.as_str(), ParentType::StepExecution)
474 }
475
476 pub fn execution(execution_id: ExecutionId) -> Self {
478 Self::new(execution_id.as_str(), ParentType::StepExecution)
479 }
480
481 pub fn system() -> Self {
483 Self::new("system", ParentType::System)
484 }
485}
486
487#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
496#[serde(rename_all = "snake_case")]
497pub enum StepSourceType {
498 #[default]
500 InitialPlan,
501 Discovered,
503 Retry,
505 UserGuidance,
507 ToolResult,
509 LlmOutput,
511 A2aMessage,
513}
514
515impl fmt::Display for StepSourceType {
516 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
517 match self {
518 StepSourceType::InitialPlan => write!(f, "initial_plan"),
519 StepSourceType::Discovered => write!(f, "discovered"),
520 StepSourceType::Retry => write!(f, "retry"),
521 StepSourceType::UserGuidance => write!(f, "user_guidance"),
522 StepSourceType::ToolResult => write!(f, "tool_result"),
523 StepSourceType::LlmOutput => write!(f, "llm_output"),
524 StepSourceType::A2aMessage => write!(f, "a2a_message"),
525 }
526 }
527}
528
529#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
538#[serde(rename_all = "camelCase")]
539pub struct StepSource {
540 pub source_type: StepSourceType,
542 #[serde(skip_serializing_if = "Option::is_none")]
544 pub triggered_by: Option<String>,
545 #[serde(skip_serializing_if = "Option::is_none")]
547 pub reason: Option<String>,
548 #[serde(skip_serializing_if = "Option::is_none")]
550 pub depth: Option<u32>,
551 #[serde(skip_serializing_if = "Option::is_none")]
553 pub spawn_mode: Option<SpawnMode>,
554}
555
556impl StepSource {
557 pub fn new(source_type: StepSourceType) -> Self {
559 Self {
560 source_type,
561 triggered_by: None,
562 reason: None,
563 depth: None,
564 spawn_mode: None,
565 }
566 }
567
568 pub fn initial_plan() -> Self {
570 Self::new(StepSourceType::InitialPlan)
571 }
572
573 pub fn discovered(triggered_by: &StepId, reason: impl Into<String>, depth: u32) -> Self {
575 Self {
576 source_type: StepSourceType::Discovered,
577 triggered_by: Some(triggered_by.as_str().to_string()),
578 reason: Some(reason.into()),
579 depth: Some(depth),
580 spawn_mode: None,
581 }
582 }
583
584 pub fn retry(original_step_id: &StepId) -> Self {
586 Self {
587 source_type: StepSourceType::Retry,
588 triggered_by: Some(original_step_id.as_str().to_string()),
589 reason: None,
590 depth: None,
591 spawn_mode: None,
592 }
593 }
594
595 pub fn user_guidance(message_id: impl Into<String>, reason: impl Into<String>) -> Self {
597 Self {
598 source_type: StepSourceType::UserGuidance,
599 triggered_by: Some(message_id.into()),
600 reason: Some(reason.into()),
601 depth: None,
602 spawn_mode: None,
603 }
604 }
605
606 pub fn llm_output(step_id: &StepId, reason: impl Into<String>, depth: u32) -> Self {
608 Self {
609 source_type: StepSourceType::LlmOutput,
610 triggered_by: Some(step_id.as_str().to_string()),
611 reason: Some(reason.into()),
612 depth: Some(depth),
613 spawn_mode: None,
614 }
615 }
616
617 pub fn tool_result(step_id: &StepId, reason: impl Into<String>, depth: u32) -> Self {
619 Self {
620 source_type: StepSourceType::ToolResult,
621 triggered_by: Some(step_id.as_str().to_string()),
622 reason: Some(reason.into()),
623 depth: Some(depth),
624 spawn_mode: None,
625 }
626 }
627
628 pub fn with_spawn_mode(mut self, spawn_mode: SpawnMode) -> Self {
630 self.spawn_mode = Some(spawn_mode);
631 self
632 }
633
634 pub fn with_triggered_by(mut self, triggered_by: impl Into<String>) -> Self {
636 self.triggered_by = Some(triggered_by.into());
637 self
638 }
639
640 pub fn with_reason(mut self, reason: impl Into<String>) -> Self {
642 self.reason = Some(reason.into());
643 self
644 }
645
646 pub fn with_depth(mut self, depth: u32) -> Self {
648 self.depth = Some(depth);
649 self
650 }
651}
652
653impl Default for StepSource {
654 fn default() -> Self {
655 Self::initial_plan()
656 }
657}
658
659#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
671#[serde(tag = "mode", rename_all = "snake_case")]
672pub enum SpawnMode {
673 #[default]
678 Inline,
679
680 Child {
682 #[serde(default)]
684 background: bool,
685
686 #[serde(default)]
688 inherit_inbox: bool,
689
690 #[serde(skip_serializing_if = "Option::is_none")]
692 policies: Option<serde_json::Value>,
693 },
694}
695
696impl SpawnMode {
697 pub fn inline() -> Self {
699 SpawnMode::Inline
700 }
701
702 pub fn child(background: bool, inherit_inbox: bool) -> Self {
704 SpawnMode::Child {
705 background,
706 inherit_inbox,
707 policies: None,
708 }
709 }
710
711 pub fn child_with_policies(
713 background: bool,
714 inherit_inbox: bool,
715 policies: serde_json::Value,
716 ) -> Self {
717 SpawnMode::Child {
718 background,
719 inherit_inbox,
720 policies: Some(policies),
721 }
722 }
723
724 pub fn is_inline(&self) -> bool {
726 matches!(self, SpawnMode::Inline)
727 }
728
729 pub fn is_child(&self) -> bool {
731 matches!(self, SpawnMode::Child { .. })
732 }
733
734 pub fn is_background(&self) -> bool {
736 matches!(
737 self,
738 SpawnMode::Child {
739 background: true,
740 ..
741 }
742 )
743 }
744
745 pub fn inherits_inbox(&self) -> bool {
747 matches!(
748 self,
749 SpawnMode::Child {
750 inherit_inbox: true,
751 ..
752 }
753 )
754 }
755}
756
757impl fmt::Display for SpawnMode {
758 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
759 match self {
760 SpawnMode::Inline => write!(f, "inline"),
761 SpawnMode::Child {
762 background,
763 inherit_inbox,
764 ..
765 } => {
766 write!(
767 f,
768 "child(background={}, inherit_inbox={})",
769 background, inherit_inbox
770 )
771 }
772 }
773 }
774}
775
776#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
787#[serde(rename_all = "snake_case")]
788pub enum CancellationPolicy {
789 #[default]
791 CascadeCancel,
792
793 WaitForChildren,
795
796 Detach,
798}
799
800impl fmt::Display for CancellationPolicy {
801 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
802 match self {
803 CancellationPolicy::CascadeCancel => write!(f, "cascade_cancel"),
804 CancellationPolicy::WaitForChildren => write!(f, "wait_for_children"),
805 CancellationPolicy::Detach => write!(f, "detach"),
806 }
807 }
808}
809
810#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
820pub struct ThreadId(String);
821
822impl ThreadId {
823 pub fn new() -> Self {
824 Self(format!("thread_{}", new_ksuid()))
825 }
826
827 pub fn from_string(s: impl Into<String>) -> Self {
828 Self(s.into())
829 }
830
831 pub fn as_str(&self) -> &str {
832 &self.0
833 }
834}
835
836impl Default for ThreadId {
837 fn default() -> Self {
838 Self::new()
839 }
840}
841
842impl fmt::Display for ThreadId {
843 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
844 write!(f, "{}", self.0)
845 }
846}
847
848impl From<String> for ThreadId {
849 fn from(s: String) -> Self {
850 Self(s)
851 }
852}
853
854impl From<&str> for ThreadId {
855 fn from(s: &str) -> Self {
856 Self(s.to_string())
857 }
858}
859
860#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
866pub struct MessageId(String);
867
868impl MessageId {
869 pub fn new() -> Self {
870 Self(format!("msg_{}", new_ksuid()))
871 }
872
873 pub fn from_string(s: impl Into<String>) -> Self {
874 Self(s.into())
875 }
876
877 pub fn as_str(&self) -> &str {
878 &self.0
879 }
880}
881
882impl Default for MessageId {
883 fn default() -> Self {
884 Self::new()
885 }
886}
887
888impl fmt::Display for MessageId {
889 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
890 write!(f, "{}", self.0)
891 }
892}
893
894impl From<String> for MessageId {
895 fn from(s: String) -> Self {
896 Self(s)
897 }
898}
899
900impl From<&str> for MessageId {
901 fn from(s: &str) -> Self {
902 Self(s.to_string())
903 }
904}
905
906pub mod prefixes {
912 pub const EXECUTION: &str = "exec_";
913 pub const STEP: &str = "step_";
914 pub const ARTIFACT: &str = "artifact_";
915 pub const GRAPH: &str = "graph_";
916 pub const TENANT: &str = "tenant_";
917 pub const USER: &str = "user_";
918 pub const EVENT: &str = "evt_";
919 pub const DECISION: &str = "dec_";
920 pub const CONTROL: &str = "ctrl_";
921 pub const THREAD: &str = "thread_";
922 pub const MESSAGE: &str = "msg_";
923}
924
925#[cfg(test)]
926mod tests {
927 use super::*;
928 use std::collections::HashSet;
929
930 #[test]
935 fn test_execution_id_new_has_correct_prefix() {
936 let id = ExecutionId::new();
937 assert!(
938 id.as_str().starts_with("exec_"),
939 "ExecutionId should start with 'exec_'"
940 );
941 }
942
943 #[test]
944 fn test_execution_id_new_unique() {
945 let id1 = ExecutionId::new();
946 let id2 = ExecutionId::new();
947 assert_ne!(id1, id2, "Each new ExecutionId should be unique");
948 }
949
950 #[test]
951 fn test_execution_id_from_string() {
952 let id = ExecutionId::from_string("exec_custom123");
953 assert_eq!(id.as_str(), "exec_custom123");
954 }
955
956 #[test]
957 fn test_execution_id_from_string_owned() {
958 let id = ExecutionId::from_string(String::from("exec_owned"));
959 assert_eq!(id.as_str(), "exec_owned");
960 }
961
962 #[test]
963 fn test_execution_id_display() {
964 let id = ExecutionId::from_string("exec_display_test");
965 assert_eq!(format!("{}", id), "exec_display_test");
966 }
967
968 #[test]
969 fn test_execution_id_default() {
970 let id = ExecutionId::default();
971 assert!(id.as_str().starts_with("exec_"));
972 }
973
974 #[test]
975 fn test_execution_id_from_string_trait() {
976 let id: ExecutionId = String::from("exec_from_string").into();
977 assert_eq!(id.as_str(), "exec_from_string");
978 }
979
980 #[test]
981 fn test_execution_id_from_str_trait() {
982 let id: ExecutionId = "exec_from_str".into();
983 assert_eq!(id.as_str(), "exec_from_str");
984 }
985
986 #[test]
987 fn test_execution_id_clone() {
988 let id1 = ExecutionId::new();
989 let id2 = id1.clone();
990 assert_eq!(id1, id2);
991 }
992
993 #[test]
994 fn test_execution_id_hash() {
995 let id1 = ExecutionId::from_string("exec_hash_test");
996 let id2 = ExecutionId::from_string("exec_hash_test");
997 let mut set = HashSet::new();
998 set.insert(id1);
999 assert!(set.contains(&id2));
1000 }
1001
1002 #[test]
1003 fn test_execution_id_debug() {
1004 let id = ExecutionId::from_string("exec_debug");
1005 let debug_str = format!("{:?}", id);
1006 assert!(debug_str.contains("exec_debug"));
1007 }
1008
1009 #[test]
1010 fn test_execution_id_serde() {
1011 let id = ExecutionId::from_string("exec_serde_test");
1012 let serialized = serde_json::to_string(&id).unwrap();
1013 let deserialized: ExecutionId = serde_json::from_str(&serialized).unwrap();
1014 assert_eq!(id, deserialized);
1015 }
1016
1017 #[test]
1022 fn test_step_id_new_has_correct_prefix() {
1023 let id = StepId::new();
1024 assert!(
1025 id.as_str().starts_with("step_"),
1026 "StepId should start with 'step_'"
1027 );
1028 }
1029
1030 #[test]
1031 fn test_step_id_new_unique() {
1032 let id1 = StepId::new();
1033 let id2 = StepId::new();
1034 assert_ne!(id1, id2);
1035 }
1036
1037 #[test]
1038 fn test_step_id_from_string() {
1039 let id = StepId::from_string("step_custom");
1040 assert_eq!(id.as_str(), "step_custom");
1041 }
1042
1043 #[test]
1044 fn test_step_id_display() {
1045 let id = StepId::from_string("step_display");
1046 assert_eq!(format!("{}", id), "step_display");
1047 }
1048
1049 #[test]
1050 fn test_step_id_default() {
1051 let id = StepId::default();
1052 assert!(id.as_str().starts_with("step_"));
1053 }
1054
1055 #[test]
1056 fn test_step_id_from_traits() {
1057 let id1: StepId = String::from("step_string").into();
1058 let id2: StepId = "step_str".into();
1059 assert_eq!(id1.as_str(), "step_string");
1060 assert_eq!(id2.as_str(), "step_str");
1061 }
1062
1063 #[test]
1064 fn test_step_id_hash() {
1065 let id = StepId::from_string("step_hash");
1066 let mut set = HashSet::new();
1067 set.insert(id.clone());
1068 assert!(set.contains(&id));
1069 }
1070
1071 #[test]
1072 fn test_step_id_serde() {
1073 let id = StepId::from_string("step_serde");
1074 let json = serde_json::to_string(&id).unwrap();
1075 let parsed: StepId = serde_json::from_str(&json).unwrap();
1076 assert_eq!(id, parsed);
1077 }
1078
1079 #[test]
1084 fn test_graph_id_new_has_correct_prefix() {
1085 let id = GraphId::new();
1086 assert!(id.as_str().starts_with("graph_"));
1087 }
1088
1089 #[test]
1090 fn test_graph_id_new_unique() {
1091 let id1 = GraphId::new();
1092 let id2 = GraphId::new();
1093 assert_ne!(id1, id2);
1094 }
1095
1096 #[test]
1097 fn test_graph_id_from_string() {
1098 let id = GraphId::from_string("graph_custom");
1099 assert_eq!(id.as_str(), "graph_custom");
1100 }
1101
1102 #[test]
1103 fn test_graph_id_display() {
1104 let id = GraphId::from_string("graph_display");
1105 assert_eq!(format!("{}", id), "graph_display");
1106 }
1107
1108 #[test]
1109 fn test_graph_id_default() {
1110 let id = GraphId::default();
1111 assert!(id.as_str().starts_with("graph_"));
1112 }
1113
1114 #[test]
1115 fn test_graph_id_serde() {
1116 let id = GraphId::from_string("graph_serde");
1117 let json = serde_json::to_string(&id).unwrap();
1118 let parsed: GraphId = serde_json::from_str(&json).unwrap();
1119 assert_eq!(id, parsed);
1120 }
1121
1122 #[test]
1127 fn test_artifact_id_new_has_correct_prefix() {
1128 let id = ArtifactId::new();
1129 assert!(id.as_str().starts_with("artifact_"));
1130 }
1131
1132 #[test]
1133 fn test_artifact_id_new_unique() {
1134 let id1 = ArtifactId::new();
1135 let id2 = ArtifactId::new();
1136 assert_ne!(id1, id2);
1137 }
1138
1139 #[test]
1140 fn test_artifact_id_from_string() {
1141 let id = ArtifactId::from_string("artifact_custom");
1142 assert_eq!(id.as_str(), "artifact_custom");
1143 }
1144
1145 #[test]
1146 fn test_artifact_id_display() {
1147 let id = ArtifactId::from_string("artifact_display");
1148 assert_eq!(format!("{}", id), "artifact_display");
1149 }
1150
1151 #[test]
1152 fn test_artifact_id_default() {
1153 let id = ArtifactId::default();
1154 assert!(id.as_str().starts_with("artifact_"));
1155 }
1156
1157 #[test]
1158 fn test_artifact_id_serde() {
1159 let id = ArtifactId::from_string("artifact_serde");
1160 let json = serde_json::to_string(&id).unwrap();
1161 let parsed: ArtifactId = serde_json::from_str(&json).unwrap();
1162 assert_eq!(id, parsed);
1163 }
1164
1165 #[test]
1170 fn test_tenant_id_new_has_correct_prefix() {
1171 let id = TenantId::new();
1172 assert!(id.as_str().starts_with("tenant_"));
1173 }
1174
1175 #[test]
1176 fn test_tenant_id_new_unique() {
1177 let id1 = TenantId::new();
1178 let id2 = TenantId::new();
1179 assert_ne!(id1, id2);
1180 }
1181
1182 #[test]
1183 fn test_tenant_id_from_string() {
1184 let id = TenantId::from_string("tenant_custom");
1185 assert_eq!(id.as_str(), "tenant_custom");
1186 }
1187
1188 #[test]
1189 fn test_tenant_id_display() {
1190 let id = TenantId::from_string("tenant_display");
1191 assert_eq!(format!("{}", id), "tenant_display");
1192 }
1193
1194 #[test]
1195 fn test_tenant_id_default() {
1196 let id = TenantId::default();
1197 assert!(id.as_str().starts_with("tenant_"));
1198 }
1199
1200 #[test]
1201 fn test_tenant_id_from_traits() {
1202 let id1: TenantId = String::from("tenant_string").into();
1203 let id2: TenantId = "tenant_str".into();
1204 assert_eq!(id1.as_str(), "tenant_string");
1205 assert_eq!(id2.as_str(), "tenant_str");
1206 }
1207
1208 #[test]
1209 fn test_tenant_id_serde() {
1210 let id = TenantId::from_string("tenant_serde");
1211 let json = serde_json::to_string(&id).unwrap();
1212 let parsed: TenantId = serde_json::from_str(&json).unwrap();
1213 assert_eq!(id, parsed);
1214 }
1215
1216 #[test]
1221 fn test_user_id_new_has_correct_prefix() {
1222 let id = UserId::new();
1223 assert!(id.as_str().starts_with("user_"));
1224 }
1225
1226 #[test]
1227 fn test_user_id_new_unique() {
1228 let id1 = UserId::new();
1229 let id2 = UserId::new();
1230 assert_ne!(id1, id2);
1231 }
1232
1233 #[test]
1234 fn test_user_id_from_string() {
1235 let id = UserId::from_string("user_custom");
1236 assert_eq!(id.as_str(), "user_custom");
1237 }
1238
1239 #[test]
1240 fn test_user_id_display() {
1241 let id = UserId::from_string("user_display");
1242 assert_eq!(format!("{}", id), "user_display");
1243 }
1244
1245 #[test]
1246 fn test_user_id_default() {
1247 let id = UserId::default();
1248 assert!(id.as_str().starts_with("user_"));
1249 }
1250
1251 #[test]
1252 fn test_user_id_from_traits() {
1253 let id1: UserId = String::from("user_string").into();
1254 let id2: UserId = "user_str".into();
1255 assert_eq!(id1.as_str(), "user_string");
1256 assert_eq!(id2.as_str(), "user_str");
1257 }
1258
1259 #[test]
1260 fn test_user_id_serde() {
1261 let id = UserId::from_string("user_serde");
1262 let json = serde_json::to_string(&id).unwrap();
1263 let parsed: UserId = serde_json::from_str(&json).unwrap();
1264 assert_eq!(id, parsed);
1265 }
1266
1267 #[test]
1272 fn test_step_type_display_llm_node() {
1273 assert_eq!(format!("{}", StepType::LlmNode), "LlmNode");
1274 }
1275
1276 #[test]
1277 fn test_step_type_display_graph_node() {
1278 assert_eq!(format!("{}", StepType::GraphNode), "GraphNode");
1279 }
1280
1281 #[test]
1282 fn test_step_type_display_tool_node() {
1283 assert_eq!(format!("{}", StepType::ToolNode), "ToolNode");
1284 }
1285
1286 #[test]
1287 fn test_step_type_display_function_node() {
1288 assert_eq!(format!("{}", StepType::FunctionNode), "FunctionNode");
1289 }
1290
1291 #[test]
1292 fn test_step_type_display_router_node() {
1293 assert_eq!(format!("{}", StepType::RouterNode), "RouterNode");
1294 }
1295
1296 #[test]
1297 fn test_step_type_display_branch_node() {
1298 assert_eq!(format!("{}", StepType::BranchNode), "BranchNode");
1299 }
1300
1301 #[test]
1302 fn test_step_type_display_loop_node() {
1303 assert_eq!(format!("{}", StepType::LoopNode), "LoopNode");
1304 }
1305
1306 #[test]
1307 fn test_step_type_serde_llm_node() {
1308 let step = StepType::LlmNode;
1309 let json = serde_json::to_string(&step).unwrap();
1310 assert_eq!(json, "\"LlmNode\"");
1311 let parsed: StepType = serde_json::from_str(&json).unwrap();
1312 assert_eq!(parsed, StepType::LlmNode);
1313 }
1314
1315 #[test]
1316 fn test_step_type_serde_all_variants() {
1317 let variants = vec![
1318 StepType::LlmNode,
1319 StepType::GraphNode,
1320 StepType::ToolNode,
1321 StepType::FunctionNode,
1322 StepType::RouterNode,
1323 StepType::BranchNode,
1324 StepType::LoopNode,
1325 ];
1326 for variant in variants {
1327 let json = serde_json::to_string(&variant).unwrap();
1328 let parsed: StepType = serde_json::from_str(&json).unwrap();
1329 assert_eq!(parsed, variant);
1330 }
1331 }
1332
1333 #[test]
1334 fn test_step_type_equality() {
1335 assert_eq!(StepType::LlmNode, StepType::LlmNode);
1336 assert_ne!(StepType::LlmNode, StepType::ToolNode);
1337 }
1338
1339 #[test]
1340 fn test_step_type_clone() {
1341 let step = StepType::GraphNode;
1342 let cloned = step.clone();
1343 assert_eq!(step, cloned);
1344 }
1345
1346 #[test]
1351 fn test_callable_type_display_all() {
1352 assert_eq!(format!("{}", CallableType::Completion), "completion");
1353 assert_eq!(format!("{}", CallableType::Chat), "chat");
1354 assert_eq!(format!("{}", CallableType::Agent), "agent");
1355 assert_eq!(format!("{}", CallableType::Workflow), "workflow");
1356 assert_eq!(format!("{}", CallableType::Background), "background");
1357 assert_eq!(format!("{}", CallableType::Composite), "composite");
1358 assert_eq!(format!("{}", CallableType::Tool), "tool");
1359 assert_eq!(format!("{}", CallableType::Custom), "custom");
1360 }
1361
1362 #[test]
1363 fn test_callable_type_default() {
1364 let default_type = CallableType::default();
1365 assert_eq!(default_type, CallableType::Agent);
1366 }
1367
1368 #[test]
1369 fn test_callable_type_serde_all_variants() {
1370 let variants = vec![
1371 CallableType::Completion,
1372 CallableType::Chat,
1373 CallableType::Agent,
1374 CallableType::Workflow,
1375 CallableType::Background,
1376 CallableType::Composite,
1377 CallableType::Tool,
1378 CallableType::Custom,
1379 ];
1380 for variant in variants {
1381 let json = serde_json::to_string(&variant).unwrap();
1382 let parsed: CallableType = serde_json::from_str(&json).unwrap();
1383 assert_eq!(parsed, variant);
1384 }
1385 }
1386
1387 #[test]
1388 fn test_callable_type_serde_snake_case() {
1389 let json = serde_json::to_string(&CallableType::Background).unwrap();
1391 assert_eq!(json, "\"background\"");
1392
1393 let json = serde_json::to_string(&CallableType::Workflow).unwrap();
1394 assert_eq!(json, "\"workflow\"");
1395 }
1396
1397 #[test]
1398 fn test_callable_type_equality() {
1399 assert_eq!(CallableType::Agent, CallableType::Agent);
1400 assert_ne!(CallableType::Agent, CallableType::Chat);
1401 }
1402
1403 #[test]
1404 fn test_callable_type_clone() {
1405 let callable = CallableType::Workflow;
1406 let cloned = callable.clone();
1407 assert_eq!(callable, cloned);
1408 }
1409
1410 #[test]
1411 fn test_callable_type_hash() {
1412 use std::collections::HashSet;
1413 let mut set = HashSet::new();
1414 set.insert(CallableType::Agent);
1415 set.insert(CallableType::Chat);
1416 set.insert(CallableType::Agent); assert_eq!(set.len(), 2);
1418 }
1419
1420 #[test]
1425 fn test_parent_type_display_user_message() {
1426 assert_eq!(format!("{}", ParentType::UserMessage), "user_message");
1427 }
1428
1429 #[test]
1430 fn test_parent_type_display_schedule_event() {
1431 assert_eq!(format!("{}", ParentType::ScheduleEvent), "schedule_event");
1432 }
1433
1434 #[test]
1435 fn test_parent_type_display_step_execution() {
1436 assert_eq!(format!("{}", ParentType::StepExecution), "step_execution");
1437 }
1438
1439 #[test]
1440 fn test_parent_type_display_webhook() {
1441 assert_eq!(format!("{}", ParentType::Webhook), "webhook");
1442 }
1443
1444 #[test]
1445 fn test_parent_type_display_a2a_request() {
1446 assert_eq!(format!("{}", ParentType::A2aRequest), "a2a_request");
1447 }
1448
1449 #[test]
1450 fn test_parent_type_display_system() {
1451 assert_eq!(format!("{}", ParentType::System), "system");
1452 }
1453
1454 #[test]
1455 fn test_parent_type_serde_all_variants() {
1456 let variants = vec![
1457 ParentType::UserMessage,
1458 ParentType::ScheduleEvent,
1459 ParentType::StepExecution,
1460 ParentType::Webhook,
1461 ParentType::A2aRequest,
1462 ParentType::System,
1463 ];
1464 for variant in variants {
1465 let json = serde_json::to_string(&variant).unwrap();
1466 let parsed: ParentType = serde_json::from_str(&json).unwrap();
1467 assert_eq!(parsed, variant);
1468 }
1469 }
1470
1471 #[test]
1472 fn test_parent_type_equality() {
1473 assert_eq!(ParentType::System, ParentType::System);
1474 assert_ne!(ParentType::System, ParentType::Webhook);
1475 }
1476
1477 #[test]
1482 fn test_parent_link_new() {
1483 let link = ParentLink::new("msg_123", ParentType::UserMessage);
1484 assert_eq!(link.parent_id, "msg_123");
1485 assert_eq!(link.parent_type, ParentType::UserMessage);
1486 }
1487
1488 #[test]
1489 fn test_parent_link_new_with_string() {
1490 let link = ParentLink::new(String::from("wh_456"), ParentType::Webhook);
1491 assert_eq!(link.parent_id, "wh_456");
1492 assert_eq!(link.parent_type, ParentType::Webhook);
1493 }
1494
1495 #[test]
1496 fn test_parent_link_from_user_message() {
1497 let link = ParentLink::from_user_message("msg_user_789");
1498 assert_eq!(link.parent_id, "msg_user_789");
1499 assert_eq!(link.parent_type, ParentType::UserMessage);
1500 }
1501
1502 #[test]
1503 fn test_parent_link_from_step() {
1504 let step_id = StepId::from_string("step_abc123");
1505 let link = ParentLink::from_step(&step_id);
1506 assert_eq!(link.parent_id, "step_abc123");
1507 assert_eq!(link.parent_type, ParentType::StepExecution);
1508 }
1509
1510 #[test]
1511 fn test_parent_link_execution() {
1512 let exec_id = ExecutionId::from_string("exec_parent");
1513 let link = ParentLink::execution(exec_id);
1514 assert_eq!(link.parent_id, "exec_parent");
1515 assert_eq!(link.parent_type, ParentType::StepExecution);
1516 }
1517
1518 #[test]
1519 fn test_parent_link_system() {
1520 let link = ParentLink::system();
1521 assert_eq!(link.parent_id, "system");
1522 assert_eq!(link.parent_type, ParentType::System);
1523 }
1524
1525 #[test]
1526 fn test_parent_link_serde() {
1527 let link = ParentLink::new("test_id", ParentType::A2aRequest);
1528 let json = serde_json::to_string(&link).unwrap();
1529 let parsed: ParentLink = serde_json::from_str(&json).unwrap();
1530 assert_eq!(link, parsed);
1531 }
1532
1533 #[test]
1534 fn test_parent_link_equality() {
1535 let link1 = ParentLink::new("same_id", ParentType::System);
1536 let link2 = ParentLink::new("same_id", ParentType::System);
1537 let link3 = ParentLink::new("different_id", ParentType::System);
1538 assert_eq!(link1, link2);
1539 assert_ne!(link1, link3);
1540 }
1541
1542 #[test]
1543 fn test_parent_link_clone() {
1544 let link = ParentLink::from_user_message("msg_clone");
1545 let cloned = link.clone();
1546 assert_eq!(link, cloned);
1547 }
1548
1549 #[test]
1554 fn test_prefix_execution() {
1555 assert_eq!(prefixes::EXECUTION, "exec_");
1556 }
1557
1558 #[test]
1559 fn test_prefix_step() {
1560 assert_eq!(prefixes::STEP, "step_");
1561 }
1562
1563 #[test]
1564 fn test_prefix_artifact() {
1565 assert_eq!(prefixes::ARTIFACT, "artifact_");
1566 }
1567
1568 #[test]
1569 fn test_prefix_graph() {
1570 assert_eq!(prefixes::GRAPH, "graph_");
1571 }
1572
1573 #[test]
1574 fn test_prefix_tenant() {
1575 assert_eq!(prefixes::TENANT, "tenant_");
1576 }
1577
1578 #[test]
1579 fn test_prefix_user() {
1580 assert_eq!(prefixes::USER, "user_");
1581 }
1582
1583 #[test]
1584 fn test_prefix_event() {
1585 assert_eq!(prefixes::EVENT, "evt_");
1586 }
1587
1588 #[test]
1589 fn test_prefix_decision() {
1590 assert_eq!(prefixes::DECISION, "dec_");
1591 }
1592
1593 #[test]
1594 fn test_prefix_control() {
1595 assert_eq!(prefixes::CONTROL, "ctrl_");
1596 }
1597
1598 #[test]
1603 fn test_run_id_alias() {
1604 let exec_id = ExecutionId::from_string("exec_alias");
1605 let run_id: RunId = exec_id.clone();
1606 assert_eq!(exec_id.as_str(), run_id.as_str());
1607 }
1608
1609 #[test]
1610 fn test_node_id_alias() {
1611 let step_id = StepId::from_string("step_alias");
1612 let node_id: NodeId = step_id.clone();
1613 assert_eq!(step_id.as_str(), node_id.as_str());
1614 }
1615
1616 #[test]
1621 fn test_execution_id_ksuid_length() {
1622 let id = ExecutionId::new();
1623 assert_eq!(id.as_str().len(), 32);
1625 }
1626
1627 #[test]
1628 fn test_step_id_ksuid_length() {
1629 let id = StepId::new();
1630 assert_eq!(id.as_str().len(), 32);
1632 }
1633
1634 #[test]
1635 fn test_graph_id_ksuid_length() {
1636 let id = GraphId::new();
1637 assert_eq!(id.as_str().len(), 33);
1639 }
1640
1641 #[test]
1642 fn test_artifact_id_ksuid_length() {
1643 let id = ArtifactId::new();
1644 assert_eq!(id.as_str().len(), 36);
1646 }
1647
1648 #[test]
1649 fn test_tenant_id_ksuid_length() {
1650 let id = TenantId::new();
1651 assert_eq!(id.as_str().len(), 34);
1653 }
1654
1655 #[test]
1656 fn test_user_id_ksuid_length() {
1657 let id = UserId::new();
1658 assert_eq!(id.as_str().len(), 32);
1660 }
1661
1662 #[test]
1667 fn test_execution_ids_sortable() {
1668 let mut ids: Vec<ExecutionId> = (0..10).map(|_| ExecutionId::new()).collect();
1670 let original_count = ids.len();
1671
1672 ids.sort_by(|a, b| a.as_str().cmp(b.as_str()));
1674 ids.dedup_by(|a, b| a.as_str() == b.as_str());
1675 assert_eq!(
1676 ids.len(),
1677 original_count,
1678 "All generated IDs should be unique"
1679 );
1680 }
1681
1682 #[test]
1683 fn test_ksuid_contains_alphanumeric() {
1684 let id = ExecutionId::new();
1685 let ksuid_part = &id.as_str()[5..]; assert!(ksuid_part.chars().all(|c| c.is_ascii_alphanumeric()));
1687 }
1688
1689 #[test]
1694 fn test_thread_id_new_has_correct_prefix() {
1695 let id = ThreadId::new();
1696 assert!(
1697 id.as_str().starts_with("thread_"),
1698 "ThreadId should start with 'thread_'"
1699 );
1700 }
1701
1702 #[test]
1703 fn test_thread_id_new_unique() {
1704 let id1 = ThreadId::new();
1705 let id2 = ThreadId::new();
1706 assert_ne!(id1, id2, "Each new ThreadId should be unique");
1707 }
1708
1709 #[test]
1710 fn test_thread_id_from_string() {
1711 let id = ThreadId::from_string("thread_custom123");
1712 assert_eq!(id.as_str(), "thread_custom123");
1713 }
1714
1715 #[test]
1716 fn test_thread_id_display() {
1717 let id = ThreadId::from_string("thread_display_test");
1718 assert_eq!(format!("{}", id), "thread_display_test");
1719 }
1720
1721 #[test]
1722 fn test_thread_id_default() {
1723 let id = ThreadId::default();
1724 assert!(id.as_str().starts_with("thread_"));
1725 }
1726
1727 #[test]
1728 fn test_thread_id_from_traits() {
1729 let id1: ThreadId = String::from("thread_string").into();
1730 let id2: ThreadId = "thread_str".into();
1731 assert_eq!(id1.as_str(), "thread_string");
1732 assert_eq!(id2.as_str(), "thread_str");
1733 }
1734
1735 #[test]
1736 fn test_thread_id_hash() {
1737 let id = ThreadId::from_string("thread_hash");
1738 let mut set = HashSet::new();
1739 set.insert(id.clone());
1740 assert!(set.contains(&id));
1741 }
1742
1743 #[test]
1744 fn test_thread_id_serde() {
1745 let id = ThreadId::from_string("thread_serde");
1746 let json = serde_json::to_string(&id).unwrap();
1747 let parsed: ThreadId = serde_json::from_str(&json).unwrap();
1748 assert_eq!(id, parsed);
1749 }
1750
1751 #[test]
1752 fn test_thread_id_ksuid_length() {
1753 let id = ThreadId::new();
1754 assert_eq!(id.as_str().len(), 34);
1756 }
1757
1758 #[test]
1763 fn test_message_id_new_has_correct_prefix() {
1764 let id = MessageId::new();
1765 assert!(
1766 id.as_str().starts_with("msg_"),
1767 "MessageId should start with 'msg_'"
1768 );
1769 }
1770
1771 #[test]
1772 fn test_message_id_new_unique() {
1773 let id1 = MessageId::new();
1774 let id2 = MessageId::new();
1775 assert_ne!(id1, id2, "Each new MessageId should be unique");
1776 }
1777
1778 #[test]
1779 fn test_message_id_from_string() {
1780 let id = MessageId::from_string("msg_custom123");
1781 assert_eq!(id.as_str(), "msg_custom123");
1782 }
1783
1784 #[test]
1785 fn test_message_id_display() {
1786 let id = MessageId::from_string("msg_display_test");
1787 assert_eq!(format!("{}", id), "msg_display_test");
1788 }
1789
1790 #[test]
1791 fn test_message_id_default() {
1792 let id = MessageId::default();
1793 assert!(id.as_str().starts_with("msg_"));
1794 }
1795
1796 #[test]
1797 fn test_message_id_from_traits() {
1798 let id1: MessageId = String::from("msg_string").into();
1799 let id2: MessageId = "msg_str".into();
1800 assert_eq!(id1.as_str(), "msg_string");
1801 assert_eq!(id2.as_str(), "msg_str");
1802 }
1803
1804 #[test]
1805 fn test_message_id_hash() {
1806 let id = MessageId::from_string("msg_hash");
1807 let mut set = HashSet::new();
1808 set.insert(id.clone());
1809 assert!(set.contains(&id));
1810 }
1811
1812 #[test]
1813 fn test_message_id_serde() {
1814 let id = MessageId::from_string("msg_serde");
1815 let json = serde_json::to_string(&id).unwrap();
1816 let parsed: MessageId = serde_json::from_str(&json).unwrap();
1817 assert_eq!(id, parsed);
1818 }
1819
1820 #[test]
1821 fn test_message_id_ksuid_length() {
1822 let id = MessageId::new();
1823 assert_eq!(id.as_str().len(), 31);
1825 }
1826
1827 #[test]
1832 fn test_prefix_thread() {
1833 assert_eq!(prefixes::THREAD, "thread_");
1834 }
1835
1836 #[test]
1837 fn test_prefix_message() {
1838 assert_eq!(prefixes::MESSAGE, "msg_");
1839 }
1840
1841 #[test]
1846 fn test_spawn_mode_inline_default() {
1847 let mode = SpawnMode::Inline;
1850 assert_eq!(mode, SpawnMode::Inline);
1851 }
1852
1853 #[test]
1854 fn test_spawn_mode_child_default_fields() {
1855 let mode = SpawnMode::Child {
1856 background: false,
1857 inherit_inbox: false,
1858 policies: None,
1859 };
1860 if let SpawnMode::Child {
1861 background,
1862 inherit_inbox,
1863 policies,
1864 } = mode
1865 {
1866 assert!(!background, "default background should be false");
1867 assert!(!inherit_inbox, "default inherit_inbox should be false");
1868 assert!(policies.is_none(), "default policies should be None");
1869 } else {
1870 panic!("Expected SpawnMode::Child");
1871 }
1872 }
1873
1874 #[test]
1875 fn test_spawn_mode_child_with_inherit_inbox() {
1876 let mode = SpawnMode::Child {
1877 background: false,
1878 inherit_inbox: true,
1879 policies: None,
1880 };
1881 if let SpawnMode::Child { inherit_inbox, .. } = mode {
1882 assert!(inherit_inbox, "inherit_inbox should be true");
1883 } else {
1884 panic!("Expected SpawnMode::Child");
1885 }
1886 }
1887
1888 #[test]
1889 fn test_spawn_mode_child_background() {
1890 let mode = SpawnMode::Child {
1891 background: true,
1892 inherit_inbox: false,
1893 policies: None,
1894 };
1895 if let SpawnMode::Child { background, .. } = mode {
1896 assert!(background, "background should be true");
1897 } else {
1898 panic!("Expected SpawnMode::Child");
1899 }
1900 }
1901
1902 #[test]
1903 fn test_spawn_mode_serde_inline() {
1904 let mode = SpawnMode::Inline;
1905 let json = serde_json::to_string(&mode).unwrap();
1906 assert!(
1907 json.contains("\"mode\":\"inline\""),
1908 "Inline should serialize with mode tag"
1909 );
1910 let parsed: SpawnMode = serde_json::from_str(&json).unwrap();
1911 assert_eq!(mode, parsed);
1912 }
1913
1914 #[test]
1915 fn test_spawn_mode_serde_child() {
1916 let mode = SpawnMode::Child {
1917 background: true,
1918 inherit_inbox: true,
1919 policies: None,
1920 };
1921 let json = serde_json::to_string(&mode).unwrap();
1922 assert!(
1923 json.contains("\"mode\":\"child\""),
1924 "Child should serialize with mode tag"
1925 );
1926 assert!(
1927 json.contains("\"background\":true"),
1928 "background should be serialized"
1929 );
1930 assert!(
1931 json.contains("\"inherit_inbox\":true"),
1932 "inherit_inbox should be serialized"
1933 );
1934 let parsed: SpawnMode = serde_json::from_str(&json).unwrap();
1935 assert_eq!(mode, parsed);
1936 }
1937
1938 #[test]
1939 fn test_spawn_mode_serde_child_with_policies() {
1940 let policies = serde_json::json!({
1941 "max_steps": 100,
1942 "max_tokens": 10000
1943 });
1944 let mode = SpawnMode::Child {
1945 background: false,
1946 inherit_inbox: true,
1947 policies: Some(policies.clone()),
1948 };
1949 let json = serde_json::to_string(&mode).unwrap();
1950 let parsed: SpawnMode = serde_json::from_str(&json).unwrap();
1951 assert_eq!(mode, parsed);
1952 if let SpawnMode::Child {
1953 policies: Some(p), ..
1954 } = parsed
1955 {
1956 assert_eq!(p["max_steps"], 100);
1957 } else {
1958 panic!("Expected SpawnMode::Child with policies");
1959 }
1960 }
1961
1962 #[test]
1963 fn test_spawn_mode_equality() {
1964 let mode1 = SpawnMode::Inline;
1965 let mode2 = SpawnMode::Inline;
1966 let mode3 = SpawnMode::Child {
1967 background: false,
1968 inherit_inbox: false,
1969 policies: None,
1970 };
1971 assert_eq!(mode1, mode2);
1972 assert_ne!(mode1, mode3);
1973 }
1974
1975 #[test]
1976 fn test_spawn_mode_clone() {
1977 let mode = SpawnMode::Child {
1978 background: true,
1979 inherit_inbox: true,
1980 policies: Some(serde_json::json!({"key": "value"})),
1981 };
1982 let cloned = mode.clone();
1983 assert_eq!(mode, cloned);
1984 }
1985
1986 #[test]
1991 fn test_cancellation_policy_default() {
1992 let policy = CancellationPolicy::default();
1993 assert_eq!(policy, CancellationPolicy::CascadeCancel);
1994 }
1995
1996 #[test]
1997 fn test_cancellation_policy_variants() {
1998 let cascade = CancellationPolicy::CascadeCancel;
1999 let wait = CancellationPolicy::WaitForChildren;
2000 let detach = CancellationPolicy::Detach;
2001
2002 assert_ne!(cascade, wait);
2003 assert_ne!(wait, detach);
2004 assert_ne!(cascade, detach);
2005 }
2006
2007 #[test]
2008 fn test_cancellation_policy_serde_cascade() {
2009 let policy = CancellationPolicy::CascadeCancel;
2010 let json = serde_json::to_string(&policy).unwrap();
2011 assert_eq!(json, "\"cascade_cancel\"");
2012 let parsed: CancellationPolicy = serde_json::from_str(&json).unwrap();
2013 assert_eq!(policy, parsed);
2014 }
2015
2016 #[test]
2017 fn test_cancellation_policy_serde_wait() {
2018 let policy = CancellationPolicy::WaitForChildren;
2019 let json = serde_json::to_string(&policy).unwrap();
2020 assert_eq!(json, "\"wait_for_children\"");
2021 let parsed: CancellationPolicy = serde_json::from_str(&json).unwrap();
2022 assert_eq!(policy, parsed);
2023 }
2024
2025 #[test]
2026 fn test_cancellation_policy_serde_detach() {
2027 let policy = CancellationPolicy::Detach;
2028 let json = serde_json::to_string(&policy).unwrap();
2029 assert_eq!(json, "\"detach\"");
2030 let parsed: CancellationPolicy = serde_json::from_str(&json).unwrap();
2031 assert_eq!(policy, parsed);
2032 }
2033
2034 #[test]
2035 fn test_cancellation_policy_all_variants_serde() {
2036 let variants = vec![
2037 CancellationPolicy::CascadeCancel,
2038 CancellationPolicy::WaitForChildren,
2039 CancellationPolicy::Detach,
2040 ];
2041 for variant in variants {
2042 let json = serde_json::to_string(&variant).unwrap();
2043 let parsed: CancellationPolicy = serde_json::from_str(&json).unwrap();
2044 assert_eq!(parsed, variant);
2045 }
2046 }
2047
2048 #[test]
2049 fn test_cancellation_policy_clone() {
2050 let policy = CancellationPolicy::WaitForChildren;
2051 let cloned = policy.clone();
2052 assert_eq!(policy, cloned);
2053 }
2054
2055 #[test]
2056 fn test_cancellation_policy_hash() {
2057 let policy = CancellationPolicy::Detach;
2058 let mut set = HashSet::new();
2059 set.insert(policy.clone());
2060 assert!(set.contains(&policy));
2061 }
2062
2063 #[test]
2068 fn test_step_source_with_spawn_mode() {
2069 let source = StepSource {
2070 source_type: StepSourceType::Discovered,
2071 triggered_by: Some("step_parent".to_string()),
2072 reason: Some("test spawn".to_string()),
2073 depth: Some(1),
2074 spawn_mode: Some(SpawnMode::Child {
2075 background: false,
2076 inherit_inbox: true,
2077 policies: None,
2078 }),
2079 };
2080 assert!(source.spawn_mode.is_some());
2081 if let Some(SpawnMode::Child { inherit_inbox, .. }) = source.spawn_mode {
2082 assert!(inherit_inbox);
2083 }
2084 }
2085
2086 #[test]
2087 fn test_step_source_discovered_default_spawn_mode() {
2088 let spawner = StepId::new();
2089 let source = StepSource::discovered(&spawner, "test reason", 1);
2090 assert!(
2091 source.spawn_mode.is_none(),
2092 "discovered() should default to None spawn_mode"
2093 );
2094 }
2095
2096 #[test]
2097 fn test_step_source_serde_with_spawn_mode() {
2098 let source = StepSource {
2099 source_type: StepSourceType::Discovered,
2100 triggered_by: Some("step_123".to_string()),
2101 reason: Some("test reason".to_string()),
2102 depth: Some(2),
2103 spawn_mode: Some(SpawnMode::Inline),
2104 };
2105 let json = serde_json::to_string(&source).unwrap();
2106 let parsed: StepSource = serde_json::from_str(&json).unwrap();
2107 assert_eq!(source, parsed);
2108 }
2109}