use serde::{Deserialize, Serialize};
use serde_json::Value;
use swiftide_core::chat_completion::ToolCall;
#[derive(
Clone,
Debug,
Default,
PartialEq,
Serialize,
Deserialize,
strum_macros::EnumDiscriminants,
strum_macros::EnumIs,
)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub enum State {
#[default]
Pending,
Running,
Stopped(StopReason),
}
impl State {
pub fn stop_reason(&self) -> Option<&StopReason> {
match self {
State::Stopped(reason) => Some(reason),
_ => None,
}
}
}
#[non_exhaustive]
#[derive(Clone, Debug, strum_macros::EnumIs, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub enum StopReason {
RequestedByTool(ToolCall, Option<Value>),
AgentFailed(Option<Value>),
ToolCallsOverLimit(ToolCall),
FeedbackRequired {
tool_call: ToolCall,
payload: Option<serde_json::Value>,
},
Error,
NoNewMessages,
Other(String),
}
impl StopReason {
pub fn as_requested_by_tool(&self) -> Option<(&ToolCall, Option<&Value>)> {
if let StopReason::RequestedByTool(t, message) = self {
Some((t, message.as_ref()))
} else {
None
}
}
pub fn as_tool_calls_over_limit(&self) -> Option<&ToolCall> {
if let StopReason::ToolCallsOverLimit(t) = self {
Some(t)
} else {
None
}
}
pub fn as_feedback_required(&self) -> Option<(&ToolCall, Option<&serde_json::Value>)> {
if let StopReason::FeedbackRequired { tool_call, payload } = self {
Some((tool_call, payload.as_ref()))
} else {
None
}
}
pub fn as_error(&self) -> Option<()> {
if matches!(self, StopReason::Error) {
Some(())
} else {
None
}
}
pub fn as_no_new_messages(&self) -> Option<()> {
if matches!(self, StopReason::NoNewMessages) {
Some(())
} else {
None
}
}
pub fn as_other(&self) -> Option<&str> {
if let StopReason::Other(s) = self {
Some(s)
} else {
None
}
}
}
impl Default for StopReason {
fn default() -> Self {
StopReason::Other("No reason provided".into())
}
}
impl<S: AsRef<str>> From<S> for StopReason {
fn from(value: S) -> Self {
StopReason::Other(value.as_ref().to_string())
}
}