errors.go

  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	Message string
 15	Cause   error
 16	marker  string
 17}
 18
 19// Error implements the error interface.
 20func (e *AIError) Error() string {
 21	return e.Message
 22}
 23
 24// Unwrap returns the underlying cause of the error.
 25func (e *AIError) Unwrap() error {
 26	return e.Cause
 27}
 28
 29// NewAIError creates a new AI SDK Error.
 30func NewAIError(message string, cause error) *AIError {
 31	return &AIError{
 32		Message: message,
 33		Cause:   cause,
 34		marker:  markerSymbol,
 35	}
 36}
 37
 38// IsAIError checks if the given error is an AI SDK Error.
 39func IsAIError(err error) bool {
 40	var sdkErr *AIError
 41	return errors.As(err, &sdkErr) && sdkErr.marker == markerSymbol
 42}
 43
 44// APICallError represents an error from an API call.
 45type APICallError struct {
 46	*AIError
 47	URL             string
 48	RequestDump     string
 49	StatusCode      int
 50	ResponseHeaders map[string]string
 51	ResponseDump    string
 52	IsRetryable     bool
 53}
 54
 55// NewAPICallError creates a new API call error.
 56func NewAPICallError(message, url string, requestDump string, statusCode int, responseHeaders map[string]string, responseDump string, cause error, isRetryable bool) *APICallError {
 57	if !isRetryable && statusCode != 0 {
 58		isRetryable = statusCode == 408 || statusCode == 409 || statusCode == 429 || statusCode >= 500
 59	}
 60
 61	return &APICallError{
 62		AIError:         NewAIError(message, cause),
 63		URL:             url,
 64		RequestDump:     requestDump,
 65		StatusCode:      statusCode,
 66		ResponseHeaders: responseHeaders,
 67		ResponseDump:    responseDump,
 68		IsRetryable:     isRetryable,
 69	}
 70}
 71
 72// InvalidArgumentError represents an invalid function argument error.
 73type InvalidArgumentError struct {
 74	*AIError
 75	Argument string
 76}
 77
 78// NewInvalidArgumentError creates a new invalid argument error.
 79func NewInvalidArgumentError(argument, message string, cause error) *InvalidArgumentError {
 80	return &InvalidArgumentError{
 81		AIError:  NewAIError(message, cause),
 82		Argument: argument,
 83	}
 84}
 85
 86// InvalidPromptError represents an invalid prompt error.
 87type InvalidPromptError struct {
 88	*AIError
 89	Prompt any
 90}
 91
 92// NewInvalidPromptError creates a new invalid prompt error.
 93func NewInvalidPromptError(prompt any, message string, cause error) *InvalidPromptError {
 94	return &InvalidPromptError{
 95		AIError: NewAIError(fmt.Sprintf("Invalid prompt: %s", message), cause),
 96		Prompt:  prompt,
 97	}
 98}
 99
100// InvalidResponseDataError represents invalid response data from the server.
101type InvalidResponseDataError struct {
102	*AIError
103	Data any
104}
105
106// NewInvalidResponseDataError creates a new invalid response data error.
107func NewInvalidResponseDataError(data any, message string) *InvalidResponseDataError {
108	if message == "" {
109		dataJSON, _ := json.Marshal(data)
110		message = fmt.Sprintf("Invalid response data: %s.", string(dataJSON))
111	}
112	return &InvalidResponseDataError{
113		AIError: NewAIError(message, nil),
114		Data:    data,
115	}
116}
117
118// UnsupportedFunctionalityError represents an unsupported functionality error.
119type UnsupportedFunctionalityError struct {
120	*AIError
121	Functionality string
122}
123
124// NewUnsupportedFunctionalityError creates a new unsupported functionality error.
125func NewUnsupportedFunctionalityError(functionality, message string) *UnsupportedFunctionalityError {
126	if message == "" {
127		message = fmt.Sprintf("'%s' functionality not supported.", functionality)
128	}
129	return &UnsupportedFunctionalityError{
130		AIError:       NewAIError(message, nil),
131		Functionality: functionality,
132	}
133}