1use std::collections::BTreeMap;
2
3use runifold_core::RetrySafety;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6use thiserror::Error;
7
8#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
10#[non_exhaustive]
11pub enum ToolErrorKind {
12 NotFound,
14 InvalidInput,
16 CapabilityDenied,
18 Cancelled,
20 DeadlineExceeded,
22 Execution,
24 InvalidOutput,
26}
27
28#[derive(Clone, Debug, Deserialize, Error, PartialEq, Serialize)]
30#[error("{kind:?}: {message}")]
31pub struct ToolError {
32 pub kind: ToolErrorKind,
34 pub message: String,
36 pub retry_safety: RetrySafety,
38 pub metadata: BTreeMap<String, Value>,
40}
41
42impl ToolError {
43 pub const fn diagnostic_code(&self) -> &'static str {
48 match self.kind {
49 ToolErrorKind::NotFound => "RF-TOOL-001",
50 ToolErrorKind::InvalidInput => "RF-TOOL-002",
51 ToolErrorKind::CapabilityDenied => "RF-TOOL-003",
52 ToolErrorKind::Cancelled => "RF-TOOL-004",
53 ToolErrorKind::DeadlineExceeded => "RF-TOOL-005",
54 ToolErrorKind::Execution => "RF-TOOL-006",
55 ToolErrorKind::InvalidOutput => "RF-TOOL-007",
56 }
57 }
58
59 pub fn local(kind: ToolErrorKind, message: impl Into<String>) -> Self {
61 Self {
62 kind,
63 message: message.into(),
64 retry_safety: RetrySafety::Unknown,
65 metadata: BTreeMap::new(),
66 }
67 }
68}
69
70pub trait IntoToolError {
75 fn into_tool_error(self) -> ToolError;
77}
78
79impl IntoToolError for ToolError {
80 fn into_tool_error(self) -> ToolError {
81 self
82 }
83}
84
85#[derive(Clone, Debug, Eq, Error, PartialEq)]
87#[non_exhaustive]
88pub enum ToolRegistrationError {
89 #[error("tool name cannot be empty")]
91 EmptyName,
92 #[error("tool `{0}` is already registered")]
94 DuplicateName(String),
95 #[error("tool `{tool}` has an invalid {direction} schema: {message}")]
97 InvalidSchema {
98 tool: String,
100 direction: &'static str,
102 message: String,
104 },
105}