use std::fmt;
pub const OK: i32 = 0;
pub const FAILED: i32 = 1;
pub const USAGE: i32 = 2;
pub const CONFIG: i32 = 3;
pub const LIMIT: i32 = 4;
pub const INTERRUPTED: i32 = 130;
#[derive(Debug)]
pub struct Fail {
pub code: i32,
pub message: String,
pub hint: Option<String>,
pub first_run: bool,
}
impl Fail {
pub fn usage(message: impl Into<String>) -> Self {
Fail { code: USAGE, message: message.into(), hint: None, first_run: false }
}
pub fn config(message: impl Into<String>) -> Self {
Fail { code: CONFIG, message: message.into(), hint: None, first_run: false }
}
pub fn with_hint(mut self, hint: impl Into<String>) -> Self {
self.hint = Some(hint.into());
self
}
}
impl fmt::Display for Fail {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.message)?;
if let Some(h) = &self.hint {
write!(f, "\n hint: {h}")?;
}
Ok(())
}
}
impl std::error::Error for Fail {}
impl From<kodact_core::CoreError> for Fail {
fn from(e: kodact_core::CoreError) -> Self {
use kodact_core::CoreError::*;
match e {
Auth(m) => Fail {
first_run: true,
..Fail::config(m).with_hint("Run `kodact doctor` to see which endpoint and key KodAct found.")
},
Config(m) => Fail::config(m),
Engine(e) => Fail::config(e.to_string()),
Session(kodact_session::SessionError::NotFound(id)) => Fail::config(format!("no session {id}"))
.with_hint("List sessions with `kodact --resume` in that project."),
Session(kodact_session::SessionError::InvalidId(id)) => {
Fail::usage(format!("invalid session id {id:?}: session ids are UUIDs"))
}
Session(e) => Fail::config(e.to_string()),
Api(e) => Fail {
code: if e.is_auth_failure() { CONFIG } else { FAILED },
message: e.to_string(),
hint: e.hint(),
first_run: false,
},
}
}
}
pub fn for_result(r: &kodact_engine::TurnResult) -> i32 {
use kodact_types::sdk::ResultSubtype::*;
if r.prompt_blocked.is_some() {
return FAILED;
}
if r.auth_failed {
return CONFIG;
}
match r.subtype {
Success => OK,
ErrorMaxTurns | ErrorMaxBudgetUsd => LIMIT,
ErrorDuringExecution | ErrorMaxStructuredOutputRetries => FAILED,
}
}