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, 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 ),
393 payload,
394 )
395 }
396
397 fn scope_created_event(scope_id: ScopeId) -> Event<serde_json::Value> {
399 create_event(
400 EventKind::SCOPE_CREATED,
401 json!({
402 "scope_id": scope_id,
403 }),
404 )
405 }
406
407 fn scope_closed_event(scope_id: ScopeId) -> Event<serde_json::Value> {
409 create_event(
410 EventKind::SCOPE_CLOSED,
411 json!({
412 "scope_id": scope_id,
413 }),
414 )
415 }
416
417 fn scope_closed_error_event(scope_id: ScopeId, error: &str) -> Event<serde_json::Value> {
419 create_event(
420 EventKind::SCOPE_CLOSED,
421 json!({
422 "scope_id": scope_id,
423 "error": error,
424 }),
425 )
426 }
427
428 fn delegation_created_event(
431 to: AgentId,
432 delegation_id: DelegationId,
433 ) -> Event<serde_json::Value> {
434 create_event(
435 EventKind::DELEGATION_CREATED,
436 json!({
437 "to_agent_id": to,
438 "agent_id": to,
439 "delegation_id": delegation_id,
440 }),
441 )
442 }
443
444 fn delegation_completed_event() -> Event<serde_json::Value> {
446 create_event(EventKind::DELEGATION_COMPLETED, json!({}))
447 }
448
449 fn delegation_failed_event() -> Event<serde_json::Value> {
451 create_event(EventKind::DELEGATION_FAILED, json!({}))
452 }
453
454 fn delegation_accepted_event() -> Event<serde_json::Value> {
456 create_event(EventKind::DELEGATION_ACCEPTED, json!({}))
457 }
458
459 fn delegation_started_event() -> Event<serde_json::Value> {
461 create_event(EventKind::DELEGATION_STARTED, json!({}))
462 }
463
464 fn delegation_rejected_event() -> Event<serde_json::Value> {
466 create_event(EventKind::DELEGATION_REJECTED, json!({}))
467 }
468
469 #[test]
474 fn test_from_events_empty_returns_idle() {
475 let events = vec![];
476 let state = AgentState::from_events(&events);
477 assert_eq!(state, AgentState::Idle);
478 }
479
480 #[test]
481 fn test_from_events_scope_created_returns_gathering() {
482 let scope_id = ScopeId::now_v7();
483 let events = vec![scope_created_event(scope_id)];
484
485 let state = AgentState::from_events(&events);
486 assert_eq!(state, AgentState::Gathering { scope_id });
487 }
488
489 #[test]
490 fn test_from_events_scope_closed_returns_complete() {
491 let scope_id = ScopeId::now_v7();
492 let events = vec![scope_created_event(scope_id), scope_closed_event(scope_id)];
493
494 let state = AgentState::from_events(&events);
495 assert_eq!(state, AgentState::Complete { scope_id });
496 }
497
498 #[test]
499 fn test_from_events_scope_closed_with_error_returns_failed() {
500 let scope_id = ScopeId::now_v7();
501 let error_msg = "Test error occurred";
502 let events = vec![
503 scope_created_event(scope_id),
504 scope_closed_error_event(scope_id, error_msg),
505 ];
506
507 let state = AgentState::from_events(&events);
508 assert_eq!(
509 state,
510 AgentState::Failed {
511 scope_id,
512 error: error_msg.to_string()
513 }
514 );
515 }
516
517 #[test]
518 fn test_from_events_delegation_created_returns_delegating() {
519 let to = AgentId::now_v7();
520 let delegation_id = DelegationId::now_v7();
521 let events = vec![delegation_created_event(to, delegation_id)];
522
523 let state = AgentState::from_events(&events);
524 assert_eq!(state, AgentState::Delegating { to, delegation_id });
525 }
526
527 #[test]
528 fn test_from_events_delegation_completed_returns_idle() {
529 let to = AgentId::now_v7();
530 let delegation_id = DelegationId::now_v7();
531 let events = vec![
532 delegation_created_event(to, delegation_id),
533 delegation_completed_event(),
534 ];
535
536 let state = AgentState::from_events(&events);
537 assert_eq!(state, AgentState::Idle);
538 }
539
540 #[test]
541 fn test_from_events_delegation_failed_returns_idle() {
542 let to = AgentId::now_v7();
543 let delegation_id = DelegationId::now_v7();
544 let events = vec![
545 delegation_created_event(to, delegation_id),
546 delegation_failed_event(),
547 ];
548
549 let state = AgentState::from_events(&events);
550 assert_eq!(state, AgentState::Idle);
551 }
552
553 #[test]
554 fn test_from_events_delegation_accepted_stays_delegating() {
555 let to = AgentId::now_v7();
556 let delegation_id = DelegationId::now_v7();
557 let events = vec![
558 delegation_created_event(to, delegation_id),
559 delegation_accepted_event(),
560 ];
561
562 let state = AgentState::from_events(&events);
563 assert_eq!(state, AgentState::Delegating { to, delegation_id });
564 }
565
566 #[test]
567 fn test_from_events_delegation_started_stays_delegating() {
568 let to = AgentId::now_v7();
569 let delegation_id = DelegationId::now_v7();
570 let events = vec![
571 delegation_created_event(to, delegation_id),
572 delegation_accepted_event(),
573 delegation_started_event(),
574 ];
575
576 let state = AgentState::from_events(&events);
577 assert_eq!(state, AgentState::Delegating { to, delegation_id });
578 }
579
580 #[test]
581 fn test_from_events_delegation_rejected_returns_idle() {
582 let to = AgentId::now_v7();
583 let delegation_id = DelegationId::now_v7();
584 let events = vec![
585 delegation_created_event(to, delegation_id),
586 delegation_rejected_event(),
587 ];
588
589 let state = AgentState::from_events(&events);
590 assert_eq!(state, AgentState::Idle);
591 }
592
593 #[test]
594 fn test_from_events_full_delegation_lifecycle() {
595 let to = AgentId::now_v7();
596 let delegation_id = DelegationId::now_v7();
597 let events = vec![
598 delegation_created_event(to, delegation_id),
599 delegation_accepted_event(),
600 delegation_started_event(),
601 delegation_completed_event(),
602 ];
603
604 let state = AgentState::from_events(&events);
605 assert_eq!(state, AgentState::Idle);
606 }
607
608 #[test]
609 fn test_from_events_multiple_scopes_uses_latest() {
610 let scope_id_1 = ScopeId::now_v7();
611 let scope_id_2 = ScopeId::now_v7();
612 let events = vec![
613 scope_created_event(scope_id_1),
614 scope_closed_event(scope_id_1),
615 scope_created_event(scope_id_2),
616 ];
617
618 let state = AgentState::from_events(&events);
619 assert_eq!(
620 state,
621 AgentState::Gathering {
622 scope_id: scope_id_2
623 }
624 );
625 }
626
627 #[test]
628 fn test_from_events_scope_then_delegation() {
629 let scope_id = ScopeId::now_v7();
630 let to = AgentId::now_v7();
631 let delegation_id = DelegationId::now_v7();
632
633 let events = vec![
634 scope_created_event(scope_id),
635 scope_closed_event(scope_id),
636 delegation_created_event(to, delegation_id),
637 ];
638
639 let state = AgentState::from_events(&events);
640 assert_eq!(state, AgentState::Delegating { to, delegation_id });
641 }
642
643 #[test]
644 fn test_from_events_delegation_then_scope() {
645 let to = AgentId::now_v7();
646 let delegation_id = DelegationId::now_v7();
647 let scope_id = ScopeId::now_v7();
648
649 let events = vec![
650 delegation_created_event(to, delegation_id),
651 delegation_completed_event(),
652 scope_created_event(scope_id),
653 ];
654
655 let state = AgentState::from_events(&events);
656 assert_eq!(state, AgentState::Gathering { scope_id });
657 }
658
659 fn agent_status_changed_event(
661 status: &str,
662 payload_extra: serde_json::Value,
663 ) -> Event<serde_json::Value> {
664 let mut payload = payload_extra;
665 payload
666 .as_object_mut()
667 .unwrap()
668 .insert("status".to_string(), json!(status));
669 create_event(EventKind::AGENT_STATUS_CHANGED, payload)
670 }
671
672 #[test]
673 fn test_from_events_agent_status_changed_to_idle() {
674 let scope_id = ScopeId::now_v7();
675 let events = vec![
676 scope_created_event(scope_id),
677 agent_status_changed_event("idle", json!({})),
678 ];
679 let state = AgentState::from_events(&events);
680 assert_eq!(state, AgentState::Idle);
681 }
682
683 #[test]
684 fn test_from_events_agent_status_changed_to_failed() {
685 let scope_id = ScopeId::now_v7();
686 let events = vec![
687 scope_created_event(scope_id),
688 agent_status_changed_event("failed", json!({ "scope_id": scope_id, "error": "crash" })),
689 ];
690 let state = AgentState::from_events(&events);
691 assert_eq!(
692 state,
693 AgentState::Failed {
694 scope_id,
695 error: "crash".to_string()
696 }
697 );
698 }
699
700 #[test]
701 fn test_from_events_agent_status_changed_unknown_ignored() {
702 let scope_id = ScopeId::now_v7();
703 let events = vec![
704 scope_created_event(scope_id),
705 agent_status_changed_event("unknown_status", json!({})),
706 ];
707 let state = AgentState::from_events(&events);
709 assert_eq!(state, AgentState::Gathering { scope_id });
710 }
711
712 #[test]
713 fn test_from_events_ignores_unknown_event_kinds() {
714 let scope_id = ScopeId::now_v7();
715 let events = vec![
716 create_event(EventKind::SYSTEM_HEARTBEAT, json!({})),
717 scope_created_event(scope_id),
718 create_event(EventKind::MESSAGE_SENT, json!({})),
719 ];
720
721 let state = AgentState::from_events(&events);
722 assert_eq!(state, AgentState::Gathering { scope_id });
723 }
724
725 #[test]
726 fn test_from_events_complex_sequence() {
727 let scope_id_1 = ScopeId::now_v7();
728 let scope_id_2 = ScopeId::now_v7();
729 let to = AgentId::now_v7();
730 let delegation_id = DelegationId::now_v7();
731
732 let events = vec![
733 scope_created_event(scope_id_1),
734 scope_closed_event(scope_id_1),
735 delegation_created_event(to, delegation_id),
736 delegation_completed_event(),
737 scope_created_event(scope_id_2),
738 scope_closed_error_event(scope_id_2, "Something went wrong"),
739 ];
740
741 let state = AgentState::from_events(&events);
742 assert_eq!(
743 state,
744 AgentState::Failed {
745 scope_id: scope_id_2,
746 error: "Something went wrong".to_string()
747 }
748 );
749 }
750
751 #[test]
756 fn test_idle_can_transition_to_gathering() {
757 let from = AgentState::Idle;
758 let to = AgentState::Gathering {
759 scope_id: ScopeId::now_v7(),
760 };
761 assert!(from.can_transition_to(&to));
762 }
763
764 #[test]
765 fn test_idle_can_transition_to_delegating() {
766 let from = AgentState::Idle;
767 let to = AgentState::Delegating {
768 to: AgentId::now_v7(),
769 delegation_id: DelegationId::now_v7(),
770 };
771 assert!(from.can_transition_to(&to));
772 }
773
774 #[test]
775 fn test_idle_cannot_transition_to_planning() {
776 let from = AgentState::Idle;
777 let to = AgentState::Planning {
778 scope_id: ScopeId::now_v7(),
779 };
780 assert!(!from.can_transition_to(&to));
781 }
782
783 #[test]
784 fn test_idle_cannot_transition_to_executing() {
785 let from = AgentState::Idle;
786 let to = AgentState::Executing {
787 scope_id: ScopeId::now_v7(),
788 tool_call_id: "test_call".to_string(),
789 };
790 assert!(!from.can_transition_to(&to));
791 }
792
793 #[test]
794 fn test_gathering_can_transition_to_planning() {
795 let scope_id = ScopeId::now_v7();
796 let from = AgentState::Gathering { scope_id };
797 let to = AgentState::Planning { scope_id };
798 assert!(from.can_transition_to(&to));
799 }
800
801 #[test]
802 fn test_gathering_can_transition_to_failed() {
803 let scope_id = ScopeId::now_v7();
804 let from = AgentState::Gathering { scope_id };
805 let to = AgentState::Failed {
806 scope_id,
807 error: "Error".to_string(),
808 };
809 assert!(from.can_transition_to(&to));
810 }
811
812 #[test]
813 fn test_gathering_cannot_transition_to_executing() {
814 let scope_id = ScopeId::now_v7();
815 let from = AgentState::Gathering { scope_id };
816 let to = AgentState::Executing {
817 scope_id,
818 tool_call_id: "test_call".to_string(),
819 };
820 assert!(!from.can_transition_to(&to));
821 }
822
823 #[test]
824 fn test_planning_can_transition_to_executing() {
825 let scope_id = ScopeId::now_v7();
826 let from = AgentState::Planning { scope_id };
827 let to = AgentState::Executing {
828 scope_id,
829 tool_call_id: "test_call".to_string(),
830 };
831 assert!(from.can_transition_to(&to));
832 }
833
834 #[test]
835 fn test_planning_can_transition_to_failed() {
836 let scope_id = ScopeId::now_v7();
837 let from = AgentState::Planning { scope_id };
838 let to = AgentState::Failed {
839 scope_id,
840 error: "Error".to_string(),
841 };
842 assert!(from.can_transition_to(&to));
843 }
844
845 #[test]
846 fn test_planning_cannot_transition_to_gathering() {
847 let scope_id = ScopeId::now_v7();
848 let from = AgentState::Planning { scope_id };
849 let to = AgentState::Gathering { scope_id };
850 assert!(!from.can_transition_to(&to));
851 }
852
853 #[test]
854 fn test_executing_can_transition_to_waiting() {
855 let scope_id = ScopeId::now_v7();
856 let from = AgentState::Executing {
857 scope_id,
858 tool_call_id: "test_call".to_string(),
859 };
860 let to = AgentState::Waiting {
861 for_event_type: "USER_INPUT".to_string(),
862 };
863 assert!(from.can_transition_to(&to));
864 }
865
866 #[test]
867 fn test_executing_can_transition_to_complete() {
868 let scope_id = ScopeId::now_v7();
869 let from = AgentState::Executing {
870 scope_id,
871 tool_call_id: "test_call".to_string(),
872 };
873 let to = AgentState::Complete { scope_id };
874 assert!(from.can_transition_to(&to));
875 }
876
877 #[test]
878 fn test_executing_can_transition_to_failed() {
879 let scope_id = ScopeId::now_v7();
880 let from = AgentState::Executing {
881 scope_id,
882 tool_call_id: "test_call".to_string(),
883 };
884 let to = AgentState::Failed {
885 scope_id,
886 error: "Error".to_string(),
887 };
888 assert!(from.can_transition_to(&to));
889 }
890
891 #[test]
892 fn test_executing_cannot_transition_to_planning() {
893 let scope_id = ScopeId::now_v7();
894 let from = AgentState::Executing {
895 scope_id,
896 tool_call_id: "test_call".to_string(),
897 };
898 let to = AgentState::Planning { scope_id };
899 assert!(!from.can_transition_to(&to));
900 }
901
902 #[test]
903 fn test_waiting_can_transition_to_executing() {
904 let scope_id = ScopeId::now_v7();
905 let from = AgentState::Waiting {
906 for_event_type: "USER_INPUT".to_string(),
907 };
908 let to = AgentState::Executing {
909 scope_id,
910 tool_call_id: "test_call".to_string(),
911 };
912 assert!(from.can_transition_to(&to));
913 }
914
915 #[test]
916 fn test_waiting_can_transition_to_failed() {
917 let scope_id = ScopeId::now_v7();
918 let from = AgentState::Waiting {
919 for_event_type: "USER_INPUT".to_string(),
920 };
921 let to = AgentState::Failed {
922 scope_id,
923 error: "Error".to_string(),
924 };
925 assert!(from.can_transition_to(&to));
926 }
927
928 #[test]
929 fn test_waiting_cannot_transition_to_complete() {
930 let scope_id = ScopeId::now_v7();
931 let from = AgentState::Waiting {
932 for_event_type: "USER_INPUT".to_string(),
933 };
934 let to = AgentState::Complete { scope_id };
935 assert!(!from.can_transition_to(&to));
936 }
937
938 #[test]
939 fn test_delegating_can_transition_to_idle() {
940 let from = AgentState::Delegating {
941 to: AgentId::now_v7(),
942 delegation_id: DelegationId::now_v7(),
943 };
944 let to = AgentState::Idle;
945 assert!(from.can_transition_to(&to));
946 }
947
948 #[test]
949 fn test_delegating_can_transition_to_failed() {
950 let scope_id = ScopeId::now_v7();
951 let from = AgentState::Delegating {
952 to: AgentId::now_v7(),
953 delegation_id: DelegationId::now_v7(),
954 };
955 let to = AgentState::Failed {
956 scope_id,
957 error: "Error".to_string(),
958 };
959 assert!(from.can_transition_to(&to));
960 }
961
962 #[test]
963 fn test_delegating_cannot_transition_to_gathering() {
964 let scope_id = ScopeId::now_v7();
965 let from = AgentState::Delegating {
966 to: AgentId::now_v7(),
967 delegation_id: DelegationId::now_v7(),
968 };
969 let to = AgentState::Gathering { scope_id };
970 assert!(!from.can_transition_to(&to));
971 }
972
973 #[test]
974 fn test_complete_can_transition_to_idle() {
975 let from = AgentState::Complete {
976 scope_id: ScopeId::now_v7(),
977 };
978 let to = AgentState::Idle;
979 assert!(from.can_transition_to(&to));
980 }
981
982 #[test]
983 fn test_complete_cannot_transition_to_gathering() {
984 let scope_id = ScopeId::now_v7();
985 let from = AgentState::Complete { scope_id };
986 let to = AgentState::Gathering { scope_id };
987 assert!(!from.can_transition_to(&to));
988 }
989
990 #[test]
991 fn test_failed_can_transition_to_idle() {
992 let from = AgentState::Failed {
993 scope_id: ScopeId::now_v7(),
994 error: "Error".to_string(),
995 };
996 let to = AgentState::Idle;
997 assert!(from.can_transition_to(&to));
998 }
999
1000 #[test]
1001 fn test_failed_cannot_transition_to_gathering() {
1002 let scope_id = ScopeId::now_v7();
1003 let from = AgentState::Failed {
1004 scope_id,
1005 error: "Error".to_string(),
1006 };
1007 let to = AgentState::Gathering { scope_id };
1008 assert!(!from.can_transition_to(&to));
1009 }
1010
1011 #[test]
1012 fn test_invalid_self_transition_idle_to_idle() {
1013 let from = AgentState::Idle;
1014 let to = AgentState::Idle;
1015 assert!(!from.can_transition_to(&to));
1016 }
1017
1018 #[test]
1019 fn test_invalid_self_transition_gathering_to_gathering() {
1020 let scope_id = ScopeId::now_v7();
1021 let from = AgentState::Gathering { scope_id };
1022 let to = AgentState::Gathering { scope_id };
1023 assert!(!from.can_transition_to(&to));
1024 }
1025
1026 #[test]
1031 fn test_valid_transitions_from_idle() {
1032 let state = AgentState::Idle;
1033 let transitions = state.valid_transitions();
1034 assert_eq!(transitions.len(), 2);
1035 assert!(transitions
1036 .iter()
1037 .any(|s| matches!(s, AgentState::Gathering { .. })));
1038 assert!(transitions
1039 .iter()
1040 .any(|s| matches!(s, AgentState::Delegating { .. })));
1041 }
1042
1043 #[test]
1044 fn test_valid_transitions_from_gathering() {
1045 let scope_id = ScopeId::now_v7();
1046 let state = AgentState::Gathering { scope_id };
1047 let transitions = state.valid_transitions();
1048 assert_eq!(transitions.len(), 2);
1049 assert!(transitions
1050 .iter()
1051 .any(|s| matches!(s, AgentState::Planning { .. })));
1052 assert!(transitions
1053 .iter()
1054 .any(|s| matches!(s, AgentState::Failed { .. })));
1055 }
1056
1057 #[test]
1058 fn test_valid_transitions_from_planning() {
1059 let scope_id = ScopeId::now_v7();
1060 let state = AgentState::Planning { scope_id };
1061 let transitions = state.valid_transitions();
1062 assert_eq!(transitions.len(), 2);
1063 assert!(transitions
1064 .iter()
1065 .any(|s| matches!(s, AgentState::Executing { .. })));
1066 assert!(transitions
1067 .iter()
1068 .any(|s| matches!(s, AgentState::Failed { .. })));
1069 }
1070
1071 #[test]
1072 fn test_valid_transitions_from_executing() {
1073 let scope_id = ScopeId::now_v7();
1074 let state = AgentState::Executing {
1075 scope_id,
1076 tool_call_id: "test_call".to_string(),
1077 };
1078 let transitions = state.valid_transitions();
1079 assert_eq!(transitions.len(), 3);
1080 assert!(transitions
1081 .iter()
1082 .any(|s| matches!(s, AgentState::Waiting { .. })));
1083 assert!(transitions
1084 .iter()
1085 .any(|s| matches!(s, AgentState::Complete { .. })));
1086 assert!(transitions
1087 .iter()
1088 .any(|s| matches!(s, AgentState::Failed { .. })));
1089 }
1090
1091 #[test]
1092 fn test_valid_transitions_from_waiting() {
1093 let state = AgentState::Waiting {
1094 for_event_type: "USER_INPUT".to_string(),
1095 };
1096 let transitions = state.valid_transitions();
1097 assert_eq!(transitions.len(), 2);
1098 assert!(transitions
1099 .iter()
1100 .any(|s| matches!(s, AgentState::Executing { .. })));
1101 assert!(transitions
1102 .iter()
1103 .any(|s| matches!(s, AgentState::Failed { .. })));
1104 }
1105
1106 #[test]
1107 fn test_valid_transitions_from_delegating() {
1108 let state = AgentState::Delegating {
1109 to: AgentId::now_v7(),
1110 delegation_id: DelegationId::now_v7(),
1111 };
1112 let transitions = state.valid_transitions();
1113 assert_eq!(transitions.len(), 2);
1114 assert!(transitions.iter().any(|s| matches!(s, AgentState::Idle)));
1115 assert!(transitions
1116 .iter()
1117 .any(|s| matches!(s, AgentState::Failed { .. })));
1118 }
1119
1120 #[test]
1121 fn test_valid_transitions_from_complete() {
1122 let state = AgentState::Complete {
1123 scope_id: ScopeId::now_v7(),
1124 };
1125 let transitions = state.valid_transitions();
1126 assert_eq!(transitions.len(), 1);
1127 assert!(transitions.iter().any(|s| matches!(s, AgentState::Idle)));
1128 }
1129
1130 #[test]
1131 fn test_valid_transitions_from_failed() {
1132 let state = AgentState::Failed {
1133 scope_id: ScopeId::now_v7(),
1134 error: "Error".to_string(),
1135 };
1136 let transitions = state.valid_transitions();
1137 assert_eq!(transitions.len(), 1);
1138 assert!(transitions.iter().any(|s| matches!(s, AgentState::Idle)));
1139 }
1140}