1use swiftide_core::chat_completion::ToolCall;
4
5#[derive(Clone, Debug, Default, strum_macros::EnumDiscriminants, strum_macros::EnumIs)]
6pub enum State {
7 #[default]
8 Pending,
9 Running,
10 Stopped(StopReason),
11}
12
13impl State {
14 pub fn stop_reason(&self) -> Option<&StopReason> {
15 match self {
16 State::Stopped(reason) => Some(reason),
17 _ => None,
18 }
19 }
20}
21
22#[non_exhaustive]
26#[derive(Clone, Debug, strum_macros::EnumIs)]
27pub enum StopReason {
28 RequestedByTool(ToolCall),
30
31 ToolCallsOverLimit(ToolCall),
33
34 FeedbackRequired {
36 tool_call: ToolCall,
37 payload: Option<serde_json::Value>,
38 },
39 Error,
41
42 NoNewMessages,
44
45 Other(String),
46}
47
48impl StopReason {
49 pub fn as_requested_by_tool(&self) -> Option<&ToolCall> {
50 if let StopReason::RequestedByTool(t) = self {
51 Some(t)
52 } else {
53 None
54 }
55 }
56
57 pub fn as_tool_calls_over_limit(&self) -> Option<&ToolCall> {
58 if let StopReason::ToolCallsOverLimit(t) = self {
59 Some(t)
60 } else {
61 None
62 }
63 }
64
65 pub fn as_feedback_required(&self) -> Option<(&ToolCall, Option<&serde_json::Value>)> {
66 if let StopReason::FeedbackRequired { tool_call, payload } = self {
67 Some((tool_call, payload.as_ref()))
68 } else {
69 None
70 }
71 }
72
73 pub fn as_error(&self) -> Option<()> {
74 if matches!(self, StopReason::Error) {
75 Some(())
76 } else {
77 None
78 }
79 }
80
81 pub fn as_no_new_messages(&self) -> Option<()> {
82 if matches!(self, StopReason::NoNewMessages) {
83 Some(())
84 } else {
85 None
86 }
87 }
88
89 pub fn as_other(&self) -> Option<&str> {
90 if let StopReason::Other(s) = self {
91 Some(s)
92 } else {
93 None
94 }
95 }
96}
97impl Default for StopReason {
98 fn default() -> Self {
99 StopReason::Other("No reason provided".to_string())
100 }
101}
102
103impl<S: AsRef<str>> From<S> for StopReason {
104 fn from(value: S) -> Self {
105 StopReason::Other(value.as_ref().to_string())
106 }
107}