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}