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