swiftide_core/chat_completion/
errors.rs

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