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