1package ai
2
3import (
4 "encoding/json"
5 "errors"
6 "fmt"
7)
8
9// markerSymbol is used for identifying AI SDK Error instances.
10var markerSymbol = "ai.error"
11
12// AIError is a custom error type for AI SDK related errors.
13type AIError struct {
14 Name string
15 Message string
16 Cause error
17 marker string
18}
19
20// Error implements the error interface.
21func (e *AIError) Error() string {
22 return e.Message
23}
24
25// Unwrap returns the underlying cause of the error.
26func (e *AIError) Unwrap() error {
27 return e.Cause
28}
29
30// NewAIError creates a new AI SDK Error.
31func NewAIError(name, message string, cause error) *AIError {
32 return &AIError{
33 Name: name,
34 Message: message,
35 Cause: cause,
36 marker: markerSymbol,
37 }
38}
39
40// IsAIError checks if the given error is an AI SDK Error.
41func IsAIError(err error) bool {
42 var sdkErr *AIError
43 return errors.As(err, &sdkErr) && sdkErr.marker == markerSymbol
44}
45
46// APICallError represents an error from an API call.
47type APICallError struct {
48 *AIError
49 URL string
50 RequestBodyValues any
51 StatusCode int
52 ResponseHeaders map[string]string
53 ResponseBody string
54 IsRetryable bool
55 Data any
56}
57
58// NewAPICallError creates a new API call error.
59func NewAPICallError(message, url string, requestBodyValues any, statusCode int, responseHeaders map[string]string, responseBody string, cause error, isRetryable bool, data any) *APICallError {
60 if !isRetryable && statusCode != 0 {
61 isRetryable = statusCode == 408 || statusCode == 409 || statusCode == 429 || statusCode >= 500
62 }
63
64 return &APICallError{
65 AIError: NewAIError("AI_APICallError", message, cause),
66 URL: url,
67 RequestBodyValues: requestBodyValues,
68 StatusCode: statusCode,
69 ResponseHeaders: responseHeaders,
70 ResponseBody: responseBody,
71 IsRetryable: isRetryable,
72 Data: data,
73 }
74}
75
76// EmptyResponseBodyError represents an empty response body error.
77type EmptyResponseBodyError struct {
78 *AIError
79}
80
81// NewEmptyResponseBodyError creates a new empty response body error.
82func NewEmptyResponseBodyError(message string) *EmptyResponseBodyError {
83 if message == "" {
84 message = "Empty response body"
85 }
86 return &EmptyResponseBodyError{
87 AIError: NewAIError("AI_EmptyResponseBodyError", message, nil),
88 }
89}
90
91// InvalidArgumentError represents an invalid function argument error.
92type InvalidArgumentError struct {
93 *AIError
94 Argument string
95}
96
97// NewInvalidArgumentError creates a new invalid argument error.
98func NewInvalidArgumentError(argument, message string, cause error) *InvalidArgumentError {
99 return &InvalidArgumentError{
100 AIError: NewAIError("AI_InvalidArgumentError", message, cause),
101 Argument: argument,
102 }
103}
104
105// InvalidPromptError represents an invalid prompt error.
106type InvalidPromptError struct {
107 *AIError
108 Prompt any
109}
110
111// NewInvalidPromptError creates a new invalid prompt error.
112func NewInvalidPromptError(prompt any, message string, cause error) *InvalidPromptError {
113 return &InvalidPromptError{
114 AIError: NewAIError("AI_InvalidPromptError", fmt.Sprintf("Invalid prompt: %s", message), cause),
115 Prompt: prompt,
116 }
117}
118
119// InvalidResponseDataError represents invalid response data from the server.
120type InvalidResponseDataError struct {
121 *AIError
122 Data any
123}
124
125// NewInvalidResponseDataError creates a new invalid response data error.
126func NewInvalidResponseDataError(data any, message string) *InvalidResponseDataError {
127 if message == "" {
128 dataJSON, _ := json.Marshal(data)
129 message = fmt.Sprintf("Invalid response data: %s.", string(dataJSON))
130 }
131 return &InvalidResponseDataError{
132 AIError: NewAIError("AI_InvalidResponseDataError", message, nil),
133 Data: data,
134 }
135}
136
137// JSONParseError represents a JSON parsing error.
138type JSONParseError struct {
139 *AIError
140 Text string
141}
142
143// NewJSONParseError creates a new JSON parse error.
144func NewJSONParseError(text string, cause error) *JSONParseError {
145 message := fmt.Sprintf("JSON parsing failed: Text: %s.\nError message: %s", text, GetErrorMessage(cause))
146 return &JSONParseError{
147 AIError: NewAIError("AI_JSONParseError", message, cause),
148 Text: text,
149 }
150}
151
152// LoadAPIKeyError represents an error loading an API key.
153type LoadAPIKeyError struct {
154 *AIError
155}
156
157// NewLoadAPIKeyError creates a new load API key error.
158func NewLoadAPIKeyError(message string) *LoadAPIKeyError {
159 return &LoadAPIKeyError{
160 AIError: NewAIError("AI_LoadAPIKeyError", message, nil),
161 }
162}
163
164// LoadSettingError represents an error loading a setting.
165type LoadSettingError struct {
166 *AIError
167}
168
169// NewLoadSettingError creates a new load setting error.
170func NewLoadSettingError(message string) *LoadSettingError {
171 return &LoadSettingError{
172 AIError: NewAIError("AI_LoadSettingError", message, nil),
173 }
174}
175
176// NoContentGeneratedError is thrown when the AI provider fails to generate any content.
177type NoContentGeneratedError struct {
178 *AIError
179}
180
181// NewNoContentGeneratedError creates a new no content generated error.
182func NewNoContentGeneratedError(message string) *NoContentGeneratedError {
183 if message == "" {
184 message = "No content generated."
185 }
186 return &NoContentGeneratedError{
187 AIError: NewAIError("AI_NoContentGeneratedError", message, nil),
188 }
189}
190
191// ModelType represents the type of model.
192type ModelType string
193
194const (
195 ModelTypeLanguage ModelType = "languageModel"
196 ModelTypeTextEmbedding ModelType = "textEmbeddingModel"
197 ModelTypeImage ModelType = "imageModel"
198 ModelTypeTranscription ModelType = "transcriptionModel"
199 ModelTypeSpeech ModelType = "speechModel"
200)
201
202// NoSuchModelError represents an error when a model is not found.
203type NoSuchModelError struct {
204 *AIError
205 ModelID string
206 ModelType ModelType
207}
208
209// NewNoSuchModelError creates a new no such model error.
210func NewNoSuchModelError(modelID string, modelType ModelType, message string) *NoSuchModelError {
211 if message == "" {
212 message = fmt.Sprintf("No such %s: %s", modelType, modelID)
213 }
214 return &NoSuchModelError{
215 AIError: NewAIError("AI_NoSuchModelError", message, nil),
216 ModelID: modelID,
217 ModelType: modelType,
218 }
219}
220
221// TooManyEmbeddingValuesForCallError represents an error when too many values are provided for embedding.
222type TooManyEmbeddingValuesForCallError struct {
223 *AIError
224 Provider string
225 ModelID string
226 MaxEmbeddingsPerCall int
227 Values []any
228}
229
230// NewTooManyEmbeddingValuesForCallError creates a new too many embedding values error.
231func NewTooManyEmbeddingValuesForCallError(provider, modelID string, maxEmbeddingsPerCall int, values []any) *TooManyEmbeddingValuesForCallError {
232 message := fmt.Sprintf(
233 "Too many values for a single embedding call. The %s model \"%s\" can only embed up to %d values per call, but %d values were provided.",
234 provider, modelID, maxEmbeddingsPerCall, len(values),
235 )
236 return &TooManyEmbeddingValuesForCallError{
237 AIError: NewAIError("AI_TooManyEmbeddingValuesForCallError", message, nil),
238 Provider: provider,
239 ModelID: modelID,
240 MaxEmbeddingsPerCall: maxEmbeddingsPerCall,
241 Values: values,
242 }
243}
244
245// TypeValidationError represents a type validation error.
246type TypeValidationError struct {
247 *AIError
248 Value any
249}
250
251// NewTypeValidationError creates a new type validation error.
252func NewTypeValidationError(value any, cause error) *TypeValidationError {
253 valueJSON, _ := json.Marshal(value)
254 message := fmt.Sprintf(
255 "Type validation failed: Value: %s.\nError message: %s",
256 string(valueJSON), GetErrorMessage(cause),
257 )
258 return &TypeValidationError{
259 AIError: NewAIError("AI_TypeValidationError", message, cause),
260 Value: value,
261 }
262}
263
264// WrapTypeValidationError wraps an error into a TypeValidationError.
265func WrapTypeValidationError(value any, cause error) *TypeValidationError {
266 if tvErr, ok := cause.(*TypeValidationError); ok && tvErr.Value == value {
267 return tvErr
268 }
269 return NewTypeValidationError(value, cause)
270}
271
272// UnsupportedFunctionalityError represents an unsupported functionality error.
273type UnsupportedFunctionalityError struct {
274 *AIError
275 Functionality string
276}
277
278// NewUnsupportedFunctionalityError creates a new unsupported functionality error.
279func NewUnsupportedFunctionalityError(functionality, message string) *UnsupportedFunctionalityError {
280 if message == "" {
281 message = fmt.Sprintf("'%s' functionality not supported.", functionality)
282 }
283 return &UnsupportedFunctionalityError{
284 AIError: NewAIError("AI_UnsupportedFunctionalityError", message, nil),
285 Functionality: functionality,
286 }
287}
288
289// GetErrorMessage extracts a message from an error.
290func GetErrorMessage(err error) string {
291 if err == nil {
292 return "unknown error"
293 }
294 return err.Error()
295}