Skip to main content

harness_core/
error.rs

1use thiserror::Error;
2
3#[derive(Debug, Error)]
4#[non_exhaustive]
5pub enum HarnessError {
6    #[error("model error: {0}")]
7    Model(#[from] ModelError),
8    #[error("tool error: {0}")]
9    Tool(#[from] ToolError),
10    #[error("guide error: {0}")]
11    Guide(#[from] GuideError),
12    #[error("sensor error: {0}")]
13    Sensor(#[from] SensorError),
14    #[error("compaction error: {0}")]
15    Compact(#[from] CompactError),
16    #[error("skill error: {0}")]
17    Skill(#[from] SkillError),
18    #[error("budget exhausted after {iters} iterations")]
19    BudgetExhausted { iters: u32 },
20    #[error("policy violation: {0}")]
21    Policy(String),
22    #[error("{0}")]
23    Other(String),
24}
25
26#[derive(Debug, Error)]
27pub enum ModelError {
28    #[error("transport: {0}")]
29    Transport(String),
30    #[error("invalid response: {0}")]
31    Invalid(String),
32    #[error("rate limited (retry after {retry_after_ms}ms)")]
33    RateLimited { retry_after_ms: u64 },
34    #[error("context overflow: needed {needed} tokens, window is {window}")]
35    ContextOverflow { needed: u32, window: u32 },
36}
37
38#[derive(Debug, Error)]
39pub enum ToolError {
40    #[error("tool `{name}` not found")]
41    NotFound { name: String },
42    #[error("invalid args for `{name}`: {reason}")]
43    InvalidArgs { name: String, reason: String },
44    #[error("execution failed: {0}")]
45    Exec(String),
46    #[error("permission denied: {0}")]
47    Permission(String),
48}
49
50#[derive(Debug, Error)]
51pub enum GuideError {
52    #[error("guide `{id}` failed: {reason}")]
53    Failed { id: String, reason: String },
54}
55
56#[derive(Debug, Error)]
57pub enum SensorError {
58    #[error("sensor `{id}` failed: {reason}")]
59    Failed { id: String, reason: String },
60}
61
62#[derive(Debug, Error)]
63pub enum CompactError {
64    #[error("compaction stage {stage:?} failed: {reason}")]
65    Failed { stage: String, reason: String },
66}
67
68#[derive(Debug, Error)]
69pub enum SkillError {
70    #[error("io error: {0}")]
71    Io(String),
72    #[error("invalid SKILL.md at {path}: {reason}")]
73    Invalid { path: String, reason: String },
74    #[error("name regex violation: `{name}` — {reason}")]
75    NameRegex { name: String, reason: String },
76    #[error("description too long: {len} > 1024")]
77    DescriptionTooLong { len: usize },
78    #[error("compatibility too long: {len} > 500")]
79    CompatibilityTooLong { len: usize },
80    #[error("name `{name}` does not match parent directory `{dir}`")]
81    NameDirMismatch { name: String, dir: String },
82    #[error("missing required field `{field}`")]
83    MissingField { field: String },
84    #[error("skill `{name}` already registered")]
85    Duplicate { name: String },
86}
87
88pub type Result<T, E = HarnessError> = std::result::Result<T, E>;