use objectiveai_sdk::error::StatusError;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("agent completions error: {0}")]
AgentCompletions(#[from] crate::agent::completions::Error),
#[error("invalid state: {0}")]
InvalidState(String),
#[error("name already exists: {0}")]
NameAlreadyExists(String),
#[error("overwrite forbidden")]
OverwriteForbidden,
#[error("github token error: {0}")]
GithubToken(#[from] crate::github::Error),
#[error("github token missing permissions: {0}")]
GithubTokenMissingPermissions(String),
#[error("invalid name: {0}")]
InvalidName(String),
#[error("state not found")]
StateNotFound,
#[error("filesystem error: {0}")]
Filesystem(#[from] crate::filesystem::Error),
#[error("function fetch error: {0}")]
FunctionFetch(objectiveai_sdk::error::ResponseError),
#[error("prompt does not support type: {0}")]
PromptUnsupportedType(String),
#[error("prompt fetch error: {0}")]
PromptFetch(objectiveai_sdk::error::ResponseError),
#[error("mcp list_tools error during tool subscription: {0}")]
McpListTools(String),
#[error(
"timed out waiting for invention tools to become visible: \
expected {expected:?}, observed {observed:?}"
)]
ToolSubscriptionTimeout {
expected: Vec<String>,
observed: Vec<String>,
},
#[error("step `{step}` failed validation after {attempts} attempts: {last_error}")]
ValidationFailedAfterRetries {
step: &'static str,
attempts: u32,
last_error: String,
},
}
impl StatusError for Error {
fn status(&self) -> u16 {
match self {
Error::AgentCompletions(e) => e.status(),
Error::InvalidState(_) => 400,
Error::NameAlreadyExists(_) => 409,
Error::OverwriteForbidden => 403,
Error::GithubToken(e) => e.status(),
Error::GithubTokenMissingPermissions(_) => 403,
Error::StateNotFound => 404,
Error::InvalidName(_) => 400,
Error::Filesystem(e) => e.status(),
Error::FunctionFetch(e) => e.code,
Error::PromptUnsupportedType(_) => 400,
Error::PromptFetch(e) => e.code,
Error::McpListTools(_) => 502,
Error::ToolSubscriptionTimeout { .. } => 504,
Error::ValidationFailedAfterRetries { .. } => 422,
}
}
fn message(&self) -> Option<serde_json::Value> {
let error_value = match self {
Error::AgentCompletions(e) => serde_json::json!({
"kind": "agent_completions",
"error": e.message(),
}),
Error::InvalidState(msg) => serde_json::json!({
"kind": "invalid_state",
"error": msg,
}),
Error::NameAlreadyExists(name) => serde_json::json!({
"kind": "name_already_exists",
"error": format!("Repository '{}' already exists. Set overwrite to true to allow this.", name),
}),
Error::OverwriteForbidden => serde_json::json!({
"kind": "overwrite_forbidden",
"error": "Overwrite is forbidden by server configuration.",
}),
Error::GithubToken(e) => serde_json::json!({
"kind": "github_token",
"error": e.message(),
}),
Error::GithubTokenMissingPermissions(msg) => serde_json::json!({
"kind": "github_token_missing_permissions",
"error": msg,
}),
Error::StateNotFound => serde_json::json!({
"kind": "state_not_found",
"error": "remote state not found",
}),
Error::InvalidName(msg) => serde_json::json!({
"kind": "invalid_name",
"error": msg,
}),
Error::Filesystem(e) => serde_json::json!({
"kind": "filesystem",
"error": e.message(),
}),
Error::FunctionFetch(e) => serde_json::json!({
"kind": "function_fetch",
"error": e.message,
}),
Error::PromptUnsupportedType(msg) => serde_json::json!({
"kind": "prompt_unsupported_type",
"error": msg,
}),
Error::PromptFetch(e) => serde_json::json!({
"kind": "prompt_fetch",
"error": e.message,
}),
Error::McpListTools(msg) => serde_json::json!({
"kind": "mcp_list_tools",
"error": msg,
}),
Error::ToolSubscriptionTimeout { expected, observed } => serde_json::json!({
"kind": "tool_subscription_timeout",
"expected": expected,
"observed": observed,
}),
Error::ValidationFailedAfterRetries { step, attempts, last_error } => serde_json::json!({
"kind": "validation_failed_after_retries",
"step": step,
"attempts": attempts,
"last_error": last_error,
}),
};
Some(serde_json::json!({
"kind": "invention",
"error": error_value,
}))
}
}