Skip to main content

converge_provider/tools/
error.rs

1// Copyright 2024-2026 Reflective Labs
2// SPDX-License-Identifier: MIT
3
4//! Error types for tool operations.
5
6use thiserror::Error;
7
8/// Error kinds for tool operations.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum ToolErrorKind {
11    NotFound,
12    InvalidArguments,
13    ExecutionFailed,
14    ConnectionFailed,
15    ServerError,
16    Timeout,
17    ValidationFailed,
18    PermissionDenied,
19    UnsupportedSource,
20}
21
22impl ToolErrorKind {
23    #[must_use]
24    pub const fn is_retryable(&self) -> bool {
25        matches!(
26            self,
27            Self::ConnectionFailed | Self::ServerError | Self::Timeout
28        )
29    }
30}
31
32/// Error type for tool operations.
33#[derive(Debug, Error)]
34#[error("{kind:?}: {message}")]
35pub struct ToolError {
36    pub kind: ToolErrorKind,
37    pub message: String,
38    #[source]
39    pub source: Option<Box<dyn std::error::Error + Send + Sync>>,
40}
41
42impl ToolError {
43    #[must_use]
44    pub fn new(kind: ToolErrorKind, message: impl Into<String>) -> Self {
45        Self {
46            kind,
47            message: message.into(),
48            source: None,
49        }
50    }
51
52    #[must_use]
53    pub fn not_found(tool_name: impl Into<String>) -> Self {
54        let name = tool_name.into();
55        Self::new(ToolErrorKind::NotFound, format!("Tool not found: {name}"))
56    }
57
58    #[must_use]
59    pub fn invalid_arguments(message: impl Into<String>) -> Self {
60        Self::new(ToolErrorKind::InvalidArguments, message)
61    }
62
63    #[must_use]
64    pub fn connection_failed(message: impl Into<String>) -> Self {
65        Self::new(ToolErrorKind::ConnectionFailed, message)
66    }
67
68    #[must_use]
69    pub fn validation_failed(message: impl Into<String>) -> Self {
70        Self::new(ToolErrorKind::ValidationFailed, message)
71    }
72
73    #[must_use]
74    pub fn unsupported_source(source_type: impl Into<String>) -> Self {
75        let source = source_type.into();
76        Self::new(
77            ToolErrorKind::UnsupportedSource,
78            format!("Unsupported tool source: {source}"),
79        )
80    }
81
82    #[must_use]
83    pub fn is_retryable(&self) -> bool {
84        self.kind.is_retryable()
85    }
86}