swiftide_core/chat_completion/
errors.rs

1use std::borrow::Cow;
2
3use thiserror::Error;
4
5use crate::CommandError;
6
7use super::ChatCompletionStream;
8
9/// A `ToolError` is an error that occurs when a tool is invoked.
10///
11/// Depending on the agent configuration, the tool might be retried with feedback to the LLM, up to
12/// a limit.
13#[derive(Error, Debug)]
14pub enum ToolError {
15    /// I.e. the llm calls the tool with the wrong arguments
16    #[error("arguments for tool failed to parse: {0:#}")]
17    WrongArguments(#[from] serde_json::Error),
18
19    /// Tool requires arguments but none were provided
20    #[error("arguments missing for tool {0:#}")]
21    MissingArguments(Cow<'static, str>),
22
23    /// Tool execution failed
24    #[error("tool execution failed: {0:#}")]
25    ExecutionFailed(#[from] CommandError),
26
27    #[error(transparent)]
28    Unknown(#[from] anyhow::Error),
29}
30
31impl ToolError {
32    /// Tool received arguments that it could not parse
33    pub fn wrong_arguments(e: impl Into<serde_json::Error>) -> Self {
34        ToolError::WrongArguments(e.into())
35    }
36
37    /// Tool is missing required arguments
38    pub fn missing_arguments(tool_name: impl Into<Cow<'static, str>>) -> Self {
39        ToolError::MissingArguments(tool_name.into())
40    }
41
42    /// Tool execution failed
43    pub fn execution_failed(e: impl Into<CommandError>) -> Self {
44        ToolError::ExecutionFailed(e.into())
45    }
46
47    /// Tool failed with an unknown error
48    pub fn unknown(e: impl Into<anyhow::Error>) -> Self {
49        ToolError::Unknown(e.into())
50    }
51}
52
53type BoxedError = Box<dyn std::error::Error + Send + Sync>;
54
55#[derive(Error, Debug)]
56pub enum LanguageModelError {
57    #[error("Context length exceeded: {0:#}")]
58    ContextLengthExceeded(BoxedError),
59    #[error("Permanent error: {0:#}")]
60    PermanentError(BoxedError),
61    #[error("Transient error: {0:#}")]
62    TransientError(BoxedError),
63}
64
65impl LanguageModelError {
66    pub fn permanent(e: impl Into<BoxedError>) -> Self {
67        LanguageModelError::PermanentError(e.into())
68    }
69
70    pub fn transient(e: impl Into<BoxedError>) -> Self {
71        LanguageModelError::TransientError(e.into())
72    }
73
74    pub fn context_length_exceeded(e: impl Into<BoxedError>) -> Self {
75        LanguageModelError::ContextLengthExceeded(e.into())
76    }
77}
78
79impl From<BoxedError> for LanguageModelError {
80    fn from(e: BoxedError) -> Self {
81        LanguageModelError::PermanentError(e)
82    }
83}
84
85impl From<anyhow::Error> for LanguageModelError {
86    fn from(e: anyhow::Error) -> Self {
87        LanguageModelError::PermanentError(e.into())
88    }
89}
90
91// Make it easier to use the error in streaming functions
92
93impl From<LanguageModelError> for ChatCompletionStream {
94    fn from(val: LanguageModelError) -> Self {
95        Box::pin(futures_util::stream::once(async move { Err(val) }))
96    }
97}