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