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