refactor(agent): extract claude driver into hive-claude crate
This commit is contained in:
parent
e35acca814
commit
a3b66241d1
13 changed files with 907 additions and 442 deletions
77
hive-claude/src/error.rs
Normal file
77
hive-claude/src/error.rs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
//! Typed errors for the driver. See the crate-level docs for why this is a
|
||||
//! `thiserror` enum rather than `anyhow`.
|
||||
|
||||
use std::process::ExitStatus;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
/// Why a claude run did not complete cleanly. A normal, finished turn is
|
||||
/// `Ok(())`; everything else is one of these variants.
|
||||
///
|
||||
/// Two families share the enum on purpose, so a caller can handle them with a
|
||||
/// single `match` on the `Result`:
|
||||
///
|
||||
/// - **Recognized sentinels** — [`Error::PromptTooLong`],
|
||||
/// [`Error::RateLimited`], [`Error::AuthFailed`], [`Error::SessionNotFound`].
|
||||
/// These are *expected* non-completion states parsed from claude's output,
|
||||
/// not crashes; callers typically compact, park-and-retry, re-auth, or
|
||||
/// create-a-session in response.
|
||||
/// - **Hard failures** — [`Error::Spawn`], [`Error::Stdin`], [`Error::Wait`],
|
||||
/// [`Error::Exit`], [`Error::Io`]. The process couldn't run, or died with no
|
||||
/// recognizable reason.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
/// `Prompt is too long` — the session is past the model's context window.
|
||||
#[error("prompt is too long for the model's context window")]
|
||||
PromptTooLong,
|
||||
|
||||
/// The API refused for rate-limit / usage-cap / credit-balance reasons.
|
||||
#[error("request was rate-limited or hit a usage/credit cap")]
|
||||
RateLimited,
|
||||
|
||||
/// The API rejected the request with 401 (auth/session expired or revoked).
|
||||
#[error("authentication failed (HTTP 401)")]
|
||||
AuthFailed,
|
||||
|
||||
/// `--resume` matched no session for the given id or title (e.g. the title
|
||||
/// was never created, or its backing file was moved away).
|
||||
#[error("no session matched the requested id or title")]
|
||||
SessionNotFound,
|
||||
|
||||
/// The `claude` binary could not be spawned (not on `PATH`, not
|
||||
/// executable, …).
|
||||
#[error("failed to spawn `{program}`: {source}")]
|
||||
Spawn {
|
||||
/// The program name we tried to run.
|
||||
program: String,
|
||||
/// The underlying spawn error.
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
},
|
||||
|
||||
/// Writing the prompt to claude's stdin failed.
|
||||
#[error("writing prompt to claude stdin failed: {0}")]
|
||||
Stdin(#[source] std::io::Error),
|
||||
|
||||
/// Awaiting the child process failed.
|
||||
#[error("waiting on claude failed: {0}")]
|
||||
Wait(#[source] std::io::Error),
|
||||
|
||||
/// claude exited non-zero and raised none of the recognized sentinels.
|
||||
/// `stderr_tail` is the last handful of stderr lines (empty if there were
|
||||
/// none), included so the caller can surface a real diagnostic.
|
||||
#[error("claude exited {status}\n{stderr_tail}")]
|
||||
Exit {
|
||||
/// The child's exit status.
|
||||
status: ExitStatus,
|
||||
/// Tail of stderr, newline-joined; empty when claude wrote nothing.
|
||||
stderr_tail: String,
|
||||
},
|
||||
|
||||
/// A filesystem operation (session lookup / archive) failed.
|
||||
#[error("session store i/o failed: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
}
|
||||
|
||||
/// Convenience alias for results from this crate.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
Loading…
Reference in a new issue