zeph_acp/error.rs
1// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4/// Errors produced by the ACP server and its subsystems.
5///
6/// Each variant corresponds to a distinct failure domain so callers can handle
7/// or propagate them appropriately.
8///
9/// # Examples
10///
11/// ```
12/// use zeph_acp::AcpError;
13///
14/// let err = AcpError::Transport("connection reset".to_owned());
15/// assert!(err.to_string().contains("transport error"));
16///
17/// let err = AcpError::TerminalTimeout { output: "partial".to_owned() };
18/// assert!(err.to_string().contains("timed out"));
19/// ```
20#[derive(Debug, thiserror::Error)]
21#[non_exhaustive]
22pub enum AcpError {
23 /// The underlying JSON-RPC transport (stdio, HTTP, WebSocket) encountered an I/O error.
24 #[error("transport error: {0}")]
25 Transport(String),
26
27 /// The connected IDE returned a protocol-level error response.
28 #[error("IDE returned error: {0}")]
29 ClientError(String),
30
31 /// The IDE did not advertise the required ACP capability.
32 #[error("capability not available: {0}")]
33 CapabilityUnavailable(String),
34
35 /// The internal async channel between the agent loop and the ACP handler was dropped.
36 ///
37 /// This typically means the session has already terminated.
38 #[error("channel closed")]
39 ChannelClosed,
40
41 /// A terminal command did not complete within the configured timeout.
42 ///
43 /// `output` contains whatever the terminal produced before the timeout.
44 #[error("terminal command timed out; partial output: {output}")]
45 TerminalTimeout { output: String },
46
47 /// The stdin data payload exceeds the 64 KiB limit.
48 #[error("stdin payload too large: {size} bytes (max 65536)")]
49 StdinTooLarge { size: usize },
50
51 /// The terminal's stdin channel was closed by the IDE before the write completed.
52 #[error("broken pipe: terminal stdin closed")]
53 BrokenPipe,
54
55 /// A `ResourceLink` URI could not be resolved (bad scheme, path traversal, SSRF, etc.).
56 #[error("resource link error: {0}")]
57 ResourceLink(String),
58
59 /// The requested LLM provider is disabled for this session.
60 ///
61 /// Returned when a session-level `providers/disable` call has been made for the given
62 /// provider and the agent loop tries to resolve it for the next turn.
63 #[error("provider disabled: {provider_id}")]
64 ProviderDisabled {
65 /// The identifier of the disabled provider.
66 provider_id: String,
67 },
68
69 /// The requested LLM provider does not exist in the global provider registry.
70 ///
71 /// Returned when `providers/set` or turn resolution references an unknown provider id.
72 #[error("provider not found: {provider_id}")]
73 ProviderNotFound {
74 /// The identifier of the unknown provider.
75 provider_id: String,
76 },
77}