use crate::ids::{ModelId, ProviderId};
use crate::provider::TokenMeasurementSource;
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Clone, Debug, PartialEq, Error, Serialize, Deserialize)]
pub enum ProviderError {
#[error("authentication failed")]
Auth,
#[error("rate limited")]
RateLimit,
#[error("context overflow")]
ContextOverflow,
#[error("invalid request: {0}")]
InvalidRequest(String),
#[error("network error: {0}")]
Network(String),
#[error("protocol error: {0}")]
Protocol(String),
#[error("cancelled")]
Cancelled,
#[error("unknown provider error: {0}")]
Unknown(String),
}
#[derive(Clone, Debug, PartialEq, Error, Serialize, Deserialize)]
pub enum ToolError {
#[error("invalid arguments: {0}")]
InvalidArguments(String),
#[error("execution failed: {0}")]
Execution(String),
#[error("cancelled")]
Cancelled,
}
#[derive(Clone, Debug, PartialEq, Error, Serialize, Deserialize)]
pub enum CredentialError {
#[error("credential resolve failed: {0}")]
Resolve(String),
}
#[derive(Clone, Debug, PartialEq, Error, Serialize, Deserialize)]
pub enum PromptError {
#[error("prompt render failed: {0}")]
Render(String),
}
#[derive(Clone, Debug, PartialEq, Error, Serialize, Deserialize)]
pub enum ContextError {
#[error("context load failed: {0}")]
Load(String),
}
#[derive(Clone, Debug, PartialEq, Error, Serialize, Deserialize)]
pub enum StoreError {
#[error("store io error: {0}")]
Io(String),
#[error("store internal error: {0}")]
Internal(String),
}
#[derive(Clone, Debug, PartialEq, Error, Serialize, Deserialize)]
pub enum PolicyError {
#[error("policy evaluation failed: {0}")]
Evaluate(String),
}
#[derive(Clone, Debug, PartialEq, Error, Serialize, Deserialize)]
pub enum KaynineError {
#[error("invalid request")]
InvalidRequest,
#[error("session not found")]
SessionNotFound,
#[error("session busy")]
SessionBusy,
#[error("run already active")]
RunAlreadyActive,
#[error("revision conflict")]
RevisionConflict,
#[error("idempotency conflict")]
IdempotencyConflict,
#[error("approval expired")]
ApprovalExpired,
#[error("store error: {0}")]
Store(#[from] StoreError),
#[error("internal error")]
Internal,
}
#[derive(Clone, Debug, PartialEq, Error, Serialize, Deserialize)]
pub enum RunFailureReason {
#[error("agent definition unavailable")]
DefinitionUnavailable,
#[error("model capability mismatch: {requirement} (provider {provider}, model {model})")]
ModelCapabilityMismatch {
requirement: String,
provider: ProviderId,
model: ModelId,
},
#[error("context budget exceeded: {measured_tokens} > {available_tokens}")]
ContextBudgetExceeded {
measured_tokens: u64,
available_tokens: u64,
source: TokenMeasurementSource,
},
#[error("provider failure: {0}")]
Provider(#[from] ProviderError),
#[error("prompt failure: {0}")]
Prompt(#[from] PromptError),
#[error("context provider failure: {0}")]
Context(#[from] ContextError),
#[error("store failure: {0}")]
Store(#[from] StoreError),
#[error("internal error")]
Internal,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn kaynine_error_roundtrips() {
let err = KaynineError::SessionBusy;
let json = serde_json::to_string(&err).unwrap();
let back: KaynineError = serde_json::from_str(&json).unwrap();
assert_eq!(back, err);
}
#[test]
fn run_failure_reason_roundtrips_with_payload() {
let reason = RunFailureReason::ContextBudgetExceeded {
measured_tokens: 100,
available_tokens: 50,
source: TokenMeasurementSource::Heuristic,
};
let json = serde_json::to_string(&reason).unwrap();
let back: RunFailureReason = serde_json::from_str(&json).unwrap();
assert_eq!(back, reason);
}
#[test]
fn policy_error_roundtrips() {
let err = PolicyError::Evaluate("boom".into());
let json = serde_json::to_string(&err).unwrap();
let back: PolicyError = serde_json::from_str(&json).unwrap();
assert_eq!(back, err);
}
#[test]
fn provider_error_covers_spec_categories() {
let categories = [
ProviderError::Auth,
ProviderError::RateLimit,
ProviderError::ContextOverflow,
ProviderError::InvalidRequest("x".into()),
ProviderError::Network("x".into()),
ProviderError::Protocol("x".into()),
ProviderError::Cancelled,
ProviderError::Unknown("x".into()),
];
for c in categories {
let json = serde_json::to_string(&c).unwrap();
let back: ProviderError = serde_json::from_str(&json).unwrap();
assert_eq!(back, c);
}
}
}