errors.go

  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}