Skip to main content

zeph_acp/client/
error.rs

1// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use thiserror::Error;
5
6/// Step in the ACP handshake sequence at which a failure occurred.
7#[derive(Debug, Clone, PartialEq, Eq)]
8#[non_exhaustive]
9pub enum HandshakeStep {
10    /// The `initialize` request round-trip failed.
11    Initialize,
12    /// The `session/new` request round-trip failed.
13    NewSession,
14}
15
16impl std::fmt::Display for HandshakeStep {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        match self {
19            Self::Initialize => f.write_str("initialize"),
20            Self::NewSession => f.write_str("session/new"),
21        }
22    }
23}
24
25/// Errors returned by the ACP sub-agent client.
26#[derive(Debug, Error)]
27#[non_exhaustive]
28pub enum AcpClientError {
29    /// The command string was empty or could not be shell-split.
30    #[error("invalid command config: {0}")]
31    InvalidConfig(String),
32
33    /// The subprocess failed to spawn.
34    #[error("failed to spawn subprocess: {0}")]
35    Spawn(#[source] std::io::Error),
36
37    /// The ACP handshake failed at the named step.
38    #[error("handshake failed at {step}: {source}")]
39    Handshake {
40        /// Which handshake step failed.
41        step: HandshakeStep,
42        /// The underlying protocol error.
43        #[source]
44        source: agent_client_protocol::Error,
45    },
46
47    /// The prompt or notification could not be sent to the sub-agent.
48    #[error("failed to send to sub-agent: {0}")]
49    SendFailed(#[source] agent_client_protocol::Error),
50
51    /// A second command was sent while the driver was already servicing a read.
52    ///
53    /// The caller should wait for the in-flight operation to complete before retrying.
54    #[error("driver is busy servicing another read operation")]
55    DriverBusy,
56
57    /// The driver task exited unexpectedly before the operation could complete.
58    ///
59    /// This usually means the subprocess crashed or the transport was closed.
60    #[error("driver task exited unexpectedly")]
61    DriverDied,
62
63    /// The operation timed out.
64    #[error("operation timed out")]
65    Timeout,
66
67    /// The session was closed by a call to [`super::SubagentHandle::close`] or via
68    /// a `SubagentCommand::Close` command.
69    #[error("session is closed")]
70    Closed,
71
72    /// A cancel was requested and the sub-agent acknowledged it by returning a
73    /// `StopReason::Cancelled` update.
74    #[error("operation cancelled")]
75    Cancelled,
76
77    /// Underlying SDK/protocol error not covered by the variants above.
78    #[error("ACP SDK error: {0}")]
79    Sdk(#[source] agent_client_protocol::Error),
80}