1use crate::identity::EntityIdType;
6use crate::{AgentId, BeliefId, DelegationId, Effect, GoalId, PlanId, ScopeId};
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
11#[serde(rename_all = "snake_case")]
12pub enum AgentState {
13 Idle,
14 Gathering {
15 scope_id: ScopeId,
16 },
17 Planning {
18 scope_id: ScopeId,
19 },
20 Executing {
21 scope_id: ScopeId,
22 tool_call_id: String,
23 },
24 Waiting {
25 for_event_type: String,
26 },
27 Delegating {
28 to: AgentId,
29 delegation_id: DelegationId,
30 },
31 Complete {
32 scope_id: ScopeId,
33 },
34 Failed {
35 scope_id: ScopeId,
36 error: String,
37 },
38}
39
40impl AgentState {
41 pub fn from_events(events: &[crate::Event<serde_json::Value>]) -> Self {
49 use crate::EventKind;
50
51 let mut current_state = AgentState::Idle;
52
53 for event in events.iter() {
55 match event.header.event_kind {
56 EventKind::SCOPE_CREATED => {
57 if let Some(scope_id) = extract_scope_id(&event.payload) {
58 current_state = AgentState::Gathering { scope_id };
59 }
60 }
61 EventKind::SCOPE_CLOSED => {
62 if let Some(scope_id) = extract_scope_id(&event.payload) {
63 if let Some(error) = extract_error(&event.payload) {
65 current_state = AgentState::Failed { scope_id, error };
66 } else {
67 current_state = AgentState::Complete { scope_id };
68 }
69 }
70 }
71 EventKind::DELEGATION_CREATED => {
72 if let (Some(to), Some(delegation_id)) = (
73 extract_agent_id(&event.payload),
74 extract_delegation_id(&event.payload),
75 ) {
76 current_state = AgentState::Delegating { to, delegation_id };
77 }
78 }
79 EventKind::DELEGATION_ACCEPTED | EventKind::DELEGATION_STARTED => {
82 }
85 EventKind::DELEGATION_COMPLETED
87 | EventKind::DELEGATION_FAILED
88 | EventKind::DELEGATION_REJECTED => {
89 current_state = AgentState::Idle;
90 }
91 EventKind::AGENT_STATUS_CHANGED => {
93 if let Some(new_state) = extract_agent_state(&event.payload) {
94 current_state = new_state;
95 }
96 }
97 _ => {
98 }
100 }
101 }
102
103 current_state
104 }
105
106 pub fn can_transition_to(&self, target: &AgentState) -> bool {
117 use AgentState::*;
118
119 match (self, target) {
120 (Idle, Gathering { .. }) => true,
122 (Idle, Delegating { .. }) => true,
123
124 (Gathering { .. }, Planning { .. }) => true,
126 (Gathering { .. }, Failed { .. }) => true,
127
128 (Planning { .. }, Executing { .. }) => true,
130 (Planning { .. }, Failed { .. }) => true,
131
132 (Executing { .. }, Waiting { .. }) => true,
134 (Executing { .. }, Complete { .. }) => true,
135 (Executing { .. }, Failed { .. }) => true,
136
137 (Waiting { .. }, Executing { .. }) => true,
139 (Waiting { .. }, Failed { .. }) => true,
140
141 (Delegating { .. }, Idle) => true,
143 (Delegating { .. }, Failed { .. }) => true,
144
145 (Complete { .. }, Idle) => true,
147
148 (Failed { .. }, Idle) => true,
150
151 _ => false,
153 }
154 }
155
156 pub fn valid_transitions(&self) -> Vec<AgentState> {
159 use AgentState::*;
160
161 match self {
162 Idle => vec![
163 Gathering {
165 scope_id: ScopeId::nil(),
166 },
167 Delegating {
168 to: AgentId::nil(),
169 delegation_id: DelegationId::nil(),
170 },
171 ],
172 Gathering { scope_id } => vec![
173 Planning {
174 scope_id: *scope_id,
175 },
176 Failed {
177 scope_id: *scope_id,
178 error: String::new(),
179 },
180 ],
181 Planning { scope_id } => vec![
182 Executing {
183 scope_id: *scope_id,
184 tool_call_id: String::new(),
185 },
186 Failed {
187 scope_id: *scope_id,
188 error: String::new(),
189 },
190 ],
191 Executing { scope_id, .. } => vec![
192 Waiting {
193 for_event_type: String::new(),
194 },
195 Complete {
196 scope_id: *scope_id,
197 },
198 Failed {
199 scope_id: *scope_id,
200 error: String::new(),
201 },
202 ],
203 Waiting { .. } => vec![
204 Executing {
206 scope_id: ScopeId::nil(),
207 tool_call_id: String::new(),
208 },
209 Failed {
210 scope_id: ScopeId::nil(),
211 error: String::new(),
212 },
213 ],
214 Delegating { .. } => vec![
215 Idle,
216 Failed {
217 scope_id: ScopeId::nil(),
218 error: String::new(),
219 },
220 ],
221 Complete { .. } => vec![Idle],
222 Failed { .. } => vec![Idle],
223 }
224 }
225}
226
227fn extract_scope_id(payload: &serde_json::Value) -> Option<ScopeId> {
230 payload
231 .get("scope_id")
232 .and_then(|v| serde_json::from_value(v.clone()).ok())
233}
234
235fn extract_agent_id(payload: &serde_json::Value) -> Option<AgentId> {
236 payload
240 .get("to_agent_id")
241 .or_else(|| payload.get("delegatee_id"))
242 .or_else(|| payload.get("agent_id"))
243 .or_else(|| payload.get("to"))
244 .and_then(|v| serde_json::from_value(v.clone()).ok())
245}
246
247fn extract_delegation_id(payload: &serde_json::Value) -> Option<DelegationId> {
248 payload
249 .get("delegation_id")
250 .and_then(|v| serde_json::from_value(v.clone()).ok())
251}
252
253fn extract_error(payload: &serde_json::Value) -> Option<String> {
254 payload
255 .get("error")
256 .and_then(|v| v.as_str())
257 .map(|s| s.to_string())
258}
259
260fn extract_agent_state(payload: &serde_json::Value) -> Option<AgentState> {
264 let status = payload.get("status").and_then(|v| v.as_str())?;
265 match status {
266 "idle" => Some(AgentState::Idle),
267 "executing" => {
268 let scope_id = extract_scope_id(payload).unwrap_or_else(ScopeId::nil);
269 let tool_call_id = payload
270 .get("tool_call_id")
271 .and_then(|v| v.as_str())
272 .unwrap_or("")
273 .to_string();
274 Some(AgentState::Executing {
275 scope_id,
276 tool_call_id,
277 })
278 }
279 "waiting" => {
280 let for_event_type = payload
281 .get("for_event_type")
282 .and_then(|v| v.as_str())
283 .unwrap_or("")
284 .to_string();
285 Some(AgentState::Waiting { for_event_type })
286 }
287 "failed" => {
288 let scope_id = extract_scope_id(payload).unwrap_or_else(ScopeId::nil);
289 let error = extract_error(payload).unwrap_or_default();
290 Some(AgentState::Failed { scope_id, error })
291 }
292 "gathering" => {
293 let scope_id = extract_scope_id(payload).unwrap_or_else(ScopeId::nil);
294 Some(AgentState::Gathering { scope_id })
295 }
296 "planning" => {
297 let scope_id = extract_scope_id(payload).unwrap_or_else(ScopeId::nil);
298 Some(AgentState::Planning { scope_id })
299 }
300 _ => None, }
302}
303
304pub trait AgentLifecycle: Send + Sync {
310 fn on_wait(&self, _state: &AgentState) -> Effect<()> {
314 Effect::Ok(())
315 }
316
317 fn on_resume(&self, _state: &AgentState) -> Effect<()> {
319 Effect::Ok(())
320 }
321
322 fn on_goal_created(&self, _goal_id: GoalId, _description: &str) -> Effect<()> {
326 Effect::Ok(())
327 }
328
329 fn on_goal_activated(&self, _goal_id: GoalId) -> Effect<()> {
331 Effect::Ok(())
332 }
333
334 fn on_goal_achieved(&self, _goal_id: GoalId) -> Effect<()> {
336 Effect::Ok(())
337 }
338
339 fn on_goal_failed(&self, _goal_id: GoalId, _reason: &str) -> Effect<()> {
341 Effect::Ok(())
342 }
343
344 fn on_plan_created(&self, _plan_id: PlanId, _goal_id: GoalId) -> Effect<()> {
348 Effect::Ok(())
349 }
350
351 fn on_plan_completed(&self, _plan_id: PlanId) -> Effect<()> {
353 Effect::Ok(())
354 }
355
356 fn on_belief_updated(&self, _belief_id: BeliefId, _confidence: f32) -> Effect<()> {
360 Effect::Ok(())
361 }
362
363 fn on_belief_superseded(&self, _old: BeliefId, _new: BeliefId) -> Effect<()> {
365 Effect::Ok(())
366 }
367
368 fn on_drift_detected(&self, _other_agent: AgentId, _composite_score: f64) -> Effect<()> {
372 Effect::Ok(())
373 }
374}
375
376#[cfg(test)]
377mod tests {
378 use super::*;
379 use crate::{DagPosition, Event, EventFlags, EventHeader, EventId, EventKind};
380 use serde_json::json;
381
382 fn create_event(event_kind: EventKind, payload: serde_json::Value) -> Event<serde_json::Value> {
384 Event::new(
385 EventHeader::new(
386 EventId::now_v7(),
387 EventId::now_v7(),
388 chrono::Utc::now().timestamp_micros(),
389 DagPosition::root(),
390 0,
391 event_kind,
392 EventFlags::empty(),
393 None,
394 ),
395 payload,
396 )
397 }
398
399 fn scope_created_event(scope_id: ScopeId) -> Event<serde_json::Value> {
401 create_event(
402 EventKind::SCOPE_CREATED,
403 json!({
404 "scope_id": scope_id,
405 }),
406 )
407 }
408
409 fn scope_closed_event(scope_id: ScopeId) -> Event<serde_json::Value> {
411 create_event(
412 EventKind::SCOPE_CLOSED,
413 json!({
414 "scope_id": scope_id,
415 }),
416 )
417 }
418
419 fn scope_closed_error_event(scope_id: ScopeId, error: &str) -> Event<serde_json::Value> {
421 create_event(
422 EventKind::SCOPE_CLOSED,
423 json!({
424 "scope_id": scope_id,
425 "error": error,
426 }),
427 )
428 }
429
430 fn delegation_created_event(
433 to: AgentId,
434 delegation_id: DelegationId,
435 ) -> Event<serde_json::Value> {
436 create_event(
437 EventKind::DELEGATION_CREATED,
438 json!({
439 "to_agent_id": to,
440 "agent_id": to,
441 "delegation_id": delegation_id,
442 }),
443 )
444 }
445
446 fn delegation_completed_event() -> Event<serde_json::Value> {
448 create_event(EventKind::DELEGATION_COMPLETED, json!({}))
449 }
450
451 fn delegation_failed_event() -> Event<serde_json::Value> {
453 create_event(EventKind::DELEGATION_FAILED, json!({}))
454 }
455
456 fn delegation_accepted_event() -> Event<serde_json::Value> {
458 create_event(EventKind::DELEGATION_ACCEPTED, json!({}))
459 }
460
461 fn delegation_started_event() -> Event<serde_json::Value> {
463 create_event(EventKind::DELEGATION_STARTED, json!({}))
464 }
465
466 fn delegation_rejected_event() -> Event<serde_json::Value> {
468 create_event(EventKind::DELEGATION_REJECTED, json!({}))
469 }
470
471 #[test]
476 fn test_from_events_empty_returns_idle() {
477 let events = vec![];
478 let state = AgentState::from_events(&events);
479 assert_eq!(state, AgentState::Idle);
480 }
481
482 #[test]
483 fn test_from_events_scope_created_returns_gathering() {
484 let scope_id = ScopeId::now_v7();
485 let events = vec![scope_created_event(scope_id)];
486
487 let state = AgentState::from_events(&events);
488 assert_eq!(state, AgentState::Gathering { scope_id });
489 }
490
491 #[test]
492 fn test_from_events_scope_closed_returns_complete() {
493 let scope_id = ScopeId::now_v7();
494 let events = vec![scope_created_event(scope_id), scope_closed_event(scope_id)];
495
496 let state = AgentState::from_events(&events);
497 assert_eq!(state, AgentState::Complete { scope_id });
498 }
499
500 #[test]
501 fn test_from_events_scope_closed_with_error_returns_failed() {
502 let scope_id = ScopeId::now_v7();
503 let error_msg = "Test error occurred";
504 let events = vec![
505 scope_created_event(scope_id),
506 scope_closed_error_event(scope_id, error_msg),
507 ];
508
509 let state = AgentState::from_events(&events);
510 assert_eq!(
511 state,
512 AgentState::Failed {
513 scope_id,
514 error: error_msg.to_string()
515 }
516 );
517 }
518
519 #[test]
520 fn test_from_events_delegation_created_returns_delegating() {
521 let to = AgentId::now_v7();
522 let delegation_id = DelegationId::now_v7();
523 let events = vec![delegation_created_event(to, delegation_id)];
524
525 let state = AgentState::from_events(&events);
526 assert_eq!(state, AgentState::Delegating { to, delegation_id });
527 }
528
529 #[test]
530 fn test_from_events_delegation_completed_returns_idle() {
531 let to = AgentId::now_v7();
532 let delegation_id = DelegationId::now_v7();
533 let events = vec![
534 delegation_created_event(to, delegation_id),
535 delegation_completed_event(),
536 ];
537
538 let state = AgentState::from_events(&events);
539 assert_eq!(state, AgentState::Idle);
540 }
541
542 #[test]
543 fn test_from_events_delegation_failed_returns_idle() {
544 let to = AgentId::now_v7();
545 let delegation_id = DelegationId::now_v7();
546 let events = vec![
547 delegation_created_event(to, delegation_id),
548 delegation_failed_event(),
549 ];
550
551 let state = AgentState::from_events(&events);
552 assert_eq!(state, AgentState::Idle);
553 }
554
555 #[test]
556 fn test_from_events_delegation_accepted_stays_delegating() {
557 let to = AgentId::now_v7();
558 let delegation_id = DelegationId::now_v7();
559 let events = vec![
560 delegation_created_event(to, delegation_id),
561 delegation_accepted_event(),
562 ];
563
564 let state = AgentState::from_events(&events);
565 assert_eq!(state, AgentState::Delegating { to, delegation_id });
566 }
567
568 #[test]
569 fn test_from_events_delegation_started_stays_delegating() {
570 let to = AgentId::now_v7();
571 let delegation_id = DelegationId::now_v7();
572 let events = vec![
573 delegation_created_event(to, delegation_id),
574 delegation_accepted_event(),
575 delegation_started_event(),
576 ];
577
578 let state = AgentState::from_events(&events);
579 assert_eq!(state, AgentState::Delegating { to, delegation_id });
580 }
581
582 #[test]
583 fn test_from_events_delegation_rejected_returns_idle() {
584 let to = AgentId::now_v7();
585 let delegation_id = DelegationId::now_v7();
586 let events = vec![
587 delegation_created_event(to, delegation_id),
588 delegation_rejected_event(),
589 ];
590
591 let state = AgentState::from_events(&events);
592 assert_eq!(state, AgentState::Idle);
593 }
594
595 #[test]
596 fn test_from_events_full_delegation_lifecycle() {
597 let to = AgentId::now_v7();
598 let delegation_id = DelegationId::now_v7();
599 let events = vec![
600 delegation_created_event(to, delegation_id),
601 delegation_accepted_event(),
602 delegation_started_event(),
603 delegation_completed_event(),
604 ];
605
606 let state = AgentState::from_events(&events);
607 assert_eq!(state, AgentState::Idle);
608 }
609
610 #[test]
611 fn test_from_events_multiple_scopes_uses_latest() {
612 let scope_id_1 = ScopeId::now_v7();
613 let scope_id_2 = ScopeId::now_v7();
614 let events = vec![
615 scope_created_event(scope_id_1),
616 scope_closed_event(scope_id_1),
617 scope_created_event(scope_id_2),
618 ];
619
620 let state = AgentState::from_events(&events);
621 assert_eq!(
622 state,
623 AgentState::Gathering {
624 scope_id: scope_id_2
625 }
626 );
627 }
628
629 #[test]
630 fn test_from_events_scope_then_delegation() {
631 let scope_id = ScopeId::now_v7();
632 let to = AgentId::now_v7();
633 let delegation_id = DelegationId::now_v7();
634
635 let events = vec![
636 scope_created_event(scope_id),
637 scope_closed_event(scope_id),
638 delegation_created_event(to, delegation_id),
639 ];
640
641 let state = AgentState::from_events(&events);
642 assert_eq!(state, AgentState::Delegating { to, delegation_id });
643 }
644
645 #[test]
646 fn test_from_events_delegation_then_scope() {
647 let to = AgentId::now_v7();
648 let delegation_id = DelegationId::now_v7();
649 let scope_id = ScopeId::now_v7();
650
651 let events = vec![
652 delegation_created_event(to, delegation_id),
653 delegation_completed_event(),
654 scope_created_event(scope_id),
655 ];
656
657 let state = AgentState::from_events(&events);
658 assert_eq!(state, AgentState::Gathering { scope_id });
659 }
660
661 fn agent_status_changed_event(
663 status: &str,
664 payload_extra: serde_json::Value,
665 ) -> Event<serde_json::Value> {
666 let mut payload = payload_extra;
667 payload
668 .as_object_mut()
669 .unwrap()
670 .insert("status".to_string(), json!(status));
671 create_event(EventKind::AGENT_STATUS_CHANGED, payload)
672 }
673
674 #[test]
675 fn test_from_events_agent_status_changed_to_idle() {
676 let scope_id = ScopeId::now_v7();
677 let events = vec![
678 scope_created_event(scope_id),
679 agent_status_changed_event("idle", json!({})),
680 ];
681 let state = AgentState::from_events(&events);
682 assert_eq!(state, AgentState::Idle);
683 }
684
685 #[test]
686 fn test_from_events_agent_status_changed_to_failed() {
687 let scope_id = ScopeId::now_v7();
688 let events = vec![
689 scope_created_event(scope_id),
690 agent_status_changed_event("failed", json!({ "scope_id": scope_id, "error": "crash" })),
691 ];
692 let state = AgentState::from_events(&events);
693 assert_eq!(
694 state,
695 AgentState::Failed {
696 scope_id,
697 error: "crash".to_string()
698 }
699 );
700 }
701
702 #[test]
703 fn test_from_events_agent_status_changed_unknown_ignored() {
704 let scope_id = ScopeId::now_v7();
705 let events = vec![
706 scope_created_event(scope_id),
707 agent_status_changed_event("unknown_status", json!({})),
708 ];
709 let state = AgentState::from_events(&events);
711 assert_eq!(state, AgentState::Gathering { scope_id });
712 }
713
714 #[test]
715 fn test_from_events_ignores_unknown_event_kinds() {
716 let scope_id = ScopeId::now_v7();
717 let events = vec![
718 create_event(EventKind::SYSTEM_HEARTBEAT, json!({})),
719 scope_created_event(scope_id),
720 create_event(EventKind::MESSAGE_SENT, json!({})),
721 ];
722
723 let state = AgentState::from_events(&events);
724 assert_eq!(state, AgentState::Gathering { scope_id });
725 }
726
727 #[test]
728 fn test_from_events_complex_sequence() {
729 let scope_id_1 = ScopeId::now_v7();
730 let scope_id_2 = ScopeId::now_v7();
731 let to = AgentId::now_v7();
732 let delegation_id = DelegationId::now_v7();
733
734 let events = vec![
735 scope_created_event(scope_id_1),
736 scope_closed_event(scope_id_1),
737 delegation_created_event(to, delegation_id),
738 delegation_completed_event(),
739 scope_created_event(scope_id_2),
740 scope_closed_error_event(scope_id_2, "Something went wrong"),
741 ];
742
743 let state = AgentState::from_events(&events);
744 assert_eq!(
745 state,
746 AgentState::Failed {
747 scope_id: scope_id_2,
748 error: "Something went wrong".to_string()
749 }
750 );
751 }
752
753 #[test]
758 fn test_idle_can_transition_to_gathering() {
759 let from = AgentState::Idle;
760 let to = AgentState::Gathering {
761 scope_id: ScopeId::now_v7(),
762 };
763 assert!(from.can_transition_to(&to));
764 }
765
766 #[test]
767 fn test_idle_can_transition_to_delegating() {
768 let from = AgentState::Idle;
769 let to = AgentState::Delegating {
770 to: AgentId::now_v7(),
771 delegation_id: DelegationId::now_v7(),
772 };
773 assert!(from.can_transition_to(&to));
774 }
775
776 #[test]
777 fn test_idle_cannot_transition_to_planning() {
778 let from = AgentState::Idle;
779 let to = AgentState::Planning {
780 scope_id: ScopeId::now_v7(),
781 };
782 assert!(!from.can_transition_to(&to));
783 }
784
785 #[test]
786 fn test_idle_cannot_transition_to_executing() {
787 let from = AgentState::Idle;
788 let to = AgentState::Executing {
789 scope_id: ScopeId::now_v7(),
790 tool_call_id: "test_call".to_string(),
791 };
792 assert!(!from.can_transition_to(&to));
793 }
794
795 #[test]
796 fn test_gathering_can_transition_to_planning() {
797 let scope_id = ScopeId::now_v7();
798 let from = AgentState::Gathering { scope_id };
799 let to = AgentState::Planning { scope_id };
800 assert!(from.can_transition_to(&to));
801 }
802
803 #[test]
804 fn test_gathering_can_transition_to_failed() {
805 let scope_id = ScopeId::now_v7();
806 let from = AgentState::Gathering { scope_id };
807 let to = AgentState::Failed {
808 scope_id,
809 error: "Error".to_string(),
810 };
811 assert!(from.can_transition_to(&to));
812 }
813
814 #[test]
815 fn test_gathering_cannot_transition_to_executing() {
816 let scope_id = ScopeId::now_v7();
817 let from = AgentState::Gathering { scope_id };
818 let to = AgentState::Executing {
819 scope_id,
820 tool_call_id: "test_call".to_string(),
821 };
822 assert!(!from.can_transition_to(&to));
823 }
824
825 #[test]
826 fn test_planning_can_transition_to_executing() {
827 let scope_id = ScopeId::now_v7();
828 let from = AgentState::Planning { scope_id };
829 let to = AgentState::Executing {
830 scope_id,
831 tool_call_id: "test_call".to_string(),
832 };
833 assert!(from.can_transition_to(&to));
834 }
835
836 #[test]
837 fn test_planning_can_transition_to_failed() {
838 let scope_id = ScopeId::now_v7();
839 let from = AgentState::Planning { scope_id };
840 let to = AgentState::Failed {
841 scope_id,
842 error: "Error".to_string(),
843 };
844 assert!(from.can_transition_to(&to));
845 }
846
847 #[test]
848 fn test_planning_cannot_transition_to_gathering() {
849 let scope_id = ScopeId::now_v7();
850 let from = AgentState::Planning { scope_id };
851 let to = AgentState::Gathering { scope_id };
852 assert!(!from.can_transition_to(&to));
853 }
854
855 #[test]
856 fn test_executing_can_transition_to_waiting() {
857 let scope_id = ScopeId::now_v7();
858 let from = AgentState::Executing {
859 scope_id,
860 tool_call_id: "test_call".to_string(),
861 };
862 let to = AgentState::Waiting {
863 for_event_type: "USER_INPUT".to_string(),
864 };
865 assert!(from.can_transition_to(&to));
866 }
867
868 #[test]
869 fn test_executing_can_transition_to_complete() {
870 let scope_id = ScopeId::now_v7();
871 let from = AgentState::Executing {
872 scope_id,
873 tool_call_id: "test_call".to_string(),
874 };
875 let to = AgentState::Complete { scope_id };
876 assert!(from.can_transition_to(&to));
877 }
878
879 #[test]
880 fn test_executing_can_transition_to_failed() {
881 let scope_id = ScopeId::now_v7();
882 let from = AgentState::Executing {
883 scope_id,
884 tool_call_id: "test_call".to_string(),
885 };
886 let to = AgentState::Failed {
887 scope_id,
888 error: "Error".to_string(),
889 };
890 assert!(from.can_transition_to(&to));
891 }
892
893 #[test]
894 fn test_executing_cannot_transition_to_planning() {
895 let scope_id = ScopeId::now_v7();
896 let from = AgentState::Executing {
897 scope_id,
898 tool_call_id: "test_call".to_string(),
899 };
900 let to = AgentState::Planning { scope_id };
901 assert!(!from.can_transition_to(&to));
902 }
903
904 #[test]
905 fn test_waiting_can_transition_to_executing() {
906 let scope_id = ScopeId::now_v7();
907 let from = AgentState::Waiting {
908 for_event_type: "USER_INPUT".to_string(),
909 };
910 let to = AgentState::Executing {
911 scope_id,
912 tool_call_id: "test_call".to_string(),
913 };
914 assert!(from.can_transition_to(&to));
915 }
916
917 #[test]
918 fn test_waiting_can_transition_to_failed() {
919 let scope_id = ScopeId::now_v7();
920 let from = AgentState::Waiting {
921 for_event_type: "USER_INPUT".to_string(),
922 };
923 let to = AgentState::Failed {
924 scope_id,
925 error: "Error".to_string(),
926 };
927 assert!(from.can_transition_to(&to));
928 }
929
930 #[test]
931 fn test_waiting_cannot_transition_to_complete() {
932 let scope_id = ScopeId::now_v7();
933 let from = AgentState::Waiting {
934 for_event_type: "USER_INPUT".to_string(),
935 };
936 let to = AgentState::Complete { scope_id };
937 assert!(!from.can_transition_to(&to));
938 }
939
940 #[test]
941 fn test_delegating_can_transition_to_idle() {
942 let from = AgentState::Delegating {
943 to: AgentId::now_v7(),
944 delegation_id: DelegationId::now_v7(),
945 };
946 let to = AgentState::Idle;
947 assert!(from.can_transition_to(&to));
948 }
949
950 #[test]
951 fn test_delegating_can_transition_to_failed() {
952 let scope_id = ScopeId::now_v7();
953 let from = AgentState::Delegating {
954 to: AgentId::now_v7(),
955 delegation_id: DelegationId::now_v7(),
956 };
957 let to = AgentState::Failed {
958 scope_id,
959 error: "Error".to_string(),
960 };
961 assert!(from.can_transition_to(&to));
962 }
963
964 #[test]
965 fn test_delegating_cannot_transition_to_gathering() {
966 let scope_id = ScopeId::now_v7();
967 let from = AgentState::Delegating {
968 to: AgentId::now_v7(),
969 delegation_id: DelegationId::now_v7(),
970 };
971 let to = AgentState::Gathering { scope_id };
972 assert!(!from.can_transition_to(&to));
973 }
974
975 #[test]
976 fn test_complete_can_transition_to_idle() {
977 let from = AgentState::Complete {
978 scope_id: ScopeId::now_v7(),
979 };
980 let to = AgentState::Idle;
981 assert!(from.can_transition_to(&to));
982 }
983
984 #[test]
985 fn test_complete_cannot_transition_to_gathering() {
986 let scope_id = ScopeId::now_v7();
987 let from = AgentState::Complete { scope_id };
988 let to = AgentState::Gathering { scope_id };
989 assert!(!from.can_transition_to(&to));
990 }
991
992 #[test]
993 fn test_failed_can_transition_to_idle() {
994 let from = AgentState::Failed {
995 scope_id: ScopeId::now_v7(),
996 error: "Error".to_string(),
997 };
998 let to = AgentState::Idle;
999 assert!(from.can_transition_to(&to));
1000 }
1001
1002 #[test]
1003 fn test_failed_cannot_transition_to_gathering() {
1004 let scope_id = ScopeId::now_v7();
1005 let from = AgentState::Failed {
1006 scope_id,
1007 error: "Error".to_string(),
1008 };
1009 let to = AgentState::Gathering { scope_id };
1010 assert!(!from.can_transition_to(&to));
1011 }
1012
1013 #[test]
1014 fn test_invalid_self_transition_idle_to_idle() {
1015 let from = AgentState::Idle;
1016 let to = AgentState::Idle;
1017 assert!(!from.can_transition_to(&to));
1018 }
1019
1020 #[test]
1021 fn test_invalid_self_transition_gathering_to_gathering() {
1022 let scope_id = ScopeId::now_v7();
1023 let from = AgentState::Gathering { scope_id };
1024 let to = AgentState::Gathering { scope_id };
1025 assert!(!from.can_transition_to(&to));
1026 }
1027
1028 #[test]
1033 fn test_valid_transitions_from_idle() {
1034 let state = AgentState::Idle;
1035 let transitions = state.valid_transitions();
1036 assert_eq!(transitions.len(), 2);
1037 assert!(transitions
1038 .iter()
1039 .any(|s| matches!(s, AgentState::Gathering { .. })));
1040 assert!(transitions
1041 .iter()
1042 .any(|s| matches!(s, AgentState::Delegating { .. })));
1043 }
1044
1045 #[test]
1046 fn test_valid_transitions_from_gathering() {
1047 let scope_id = ScopeId::now_v7();
1048 let state = AgentState::Gathering { scope_id };
1049 let transitions = state.valid_transitions();
1050 assert_eq!(transitions.len(), 2);
1051 assert!(transitions
1052 .iter()
1053 .any(|s| matches!(s, AgentState::Planning { .. })));
1054 assert!(transitions
1055 .iter()
1056 .any(|s| matches!(s, AgentState::Failed { .. })));
1057 }
1058
1059 #[test]
1060 fn test_valid_transitions_from_planning() {
1061 let scope_id = ScopeId::now_v7();
1062 let state = AgentState::Planning { scope_id };
1063 let transitions = state.valid_transitions();
1064 assert_eq!(transitions.len(), 2);
1065 assert!(transitions
1066 .iter()
1067 .any(|s| matches!(s, AgentState::Executing { .. })));
1068 assert!(transitions
1069 .iter()
1070 .any(|s| matches!(s, AgentState::Failed { .. })));
1071 }
1072
1073 #[test]
1074 fn test_valid_transitions_from_executing() {
1075 let scope_id = ScopeId::now_v7();
1076 let state = AgentState::Executing {
1077 scope_id,
1078 tool_call_id: "test_call".to_string(),
1079 };
1080 let transitions = state.valid_transitions();
1081 assert_eq!(transitions.len(), 3);
1082 assert!(transitions
1083 .iter()
1084 .any(|s| matches!(s, AgentState::Waiting { .. })));
1085 assert!(transitions
1086 .iter()
1087 .any(|s| matches!(s, AgentState::Complete { .. })));
1088 assert!(transitions
1089 .iter()
1090 .any(|s| matches!(s, AgentState::Failed { .. })));
1091 }
1092
1093 #[test]
1094 fn test_valid_transitions_from_waiting() {
1095 let state = AgentState::Waiting {
1096 for_event_type: "USER_INPUT".to_string(),
1097 };
1098 let transitions = state.valid_transitions();
1099 assert_eq!(transitions.len(), 2);
1100 assert!(transitions
1101 .iter()
1102 .any(|s| matches!(s, AgentState::Executing { .. })));
1103 assert!(transitions
1104 .iter()
1105 .any(|s| matches!(s, AgentState::Failed { .. })));
1106 }
1107
1108 #[test]
1109 fn test_valid_transitions_from_delegating() {
1110 let state = AgentState::Delegating {
1111 to: AgentId::now_v7(),
1112 delegation_id: DelegationId::now_v7(),
1113 };
1114 let transitions = state.valid_transitions();
1115 assert_eq!(transitions.len(), 2);
1116 assert!(transitions.iter().any(|s| matches!(s, AgentState::Idle)));
1117 assert!(transitions
1118 .iter()
1119 .any(|s| matches!(s, AgentState::Failed { .. })));
1120 }
1121
1122 #[test]
1123 fn test_valid_transitions_from_complete() {
1124 let state = AgentState::Complete {
1125 scope_id: ScopeId::now_v7(),
1126 };
1127 let transitions = state.valid_transitions();
1128 assert_eq!(transitions.len(), 1);
1129 assert!(transitions.iter().any(|s| matches!(s, AgentState::Idle)));
1130 }
1131
1132 #[test]
1133 fn test_valid_transitions_from_failed() {
1134 let state = AgentState::Failed {
1135 scope_id: ScopeId::now_v7(),
1136 error: "Error".to_string(),
1137 };
1138 let transitions = state.valid_transitions();
1139 assert_eq!(transitions.len(), 1);
1140 assert!(transitions.iter().any(|s| matches!(s, AgentState::Idle)));
1141 }
1142}