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// InvalidArgumentError represents an invalid function argument error.
75type InvalidArgumentError struct {
76 *AIError
77 Argument string
78}
79
80// NewInvalidArgumentError creates a new invalid argument error.
81func NewInvalidArgumentError(argument, message string, cause error) *InvalidArgumentError {
82 return &InvalidArgumentError{
83 AIError: NewAIError("AI_InvalidArgumentError", message, cause),
84 Argument: argument,
85 }
86}
87
88// InvalidPromptError represents an invalid prompt error.
89type InvalidPromptError struct {
90 *AIError
91 Prompt any
92}
93
94// NewInvalidPromptError creates a new invalid prompt error.
95func NewInvalidPromptError(prompt any, message string, cause error) *InvalidPromptError {
96 return &InvalidPromptError{
97 AIError: NewAIError("AI_InvalidPromptError", fmt.Sprintf("Invalid prompt: %s", message), cause),
98 Prompt: prompt,
99 }
100}
101
102// InvalidResponseDataError represents invalid response data from the server.
103type InvalidResponseDataError struct {
104 *AIError
105 Data any
106}
107
108// NewInvalidResponseDataError creates a new invalid response data error.
109func NewInvalidResponseDataError(data any, message string) *InvalidResponseDataError {
110 if message == "" {
111 dataJSON, _ := json.Marshal(data)
112 message = fmt.Sprintf("Invalid response data: %s.", string(dataJSON))
113 }
114 return &InvalidResponseDataError{
115 AIError: NewAIError("AI_InvalidResponseDataError", message, nil),
116 Data: data,
117 }
118}
119
120// UnsupportedFunctionalityError represents an unsupported functionality error.
121type UnsupportedFunctionalityError struct {
122 *AIError
123 Functionality string
124}
125
126// NewUnsupportedFunctionalityError creates a new unsupported functionality error.
127func NewUnsupportedFunctionalityError(functionality, message string) *UnsupportedFunctionalityError {
128 if message == "" {
129 message = fmt.Sprintf("'%s' functionality not supported.", functionality)
130 }
131 return &UnsupportedFunctionalityError{
132 AIError: NewAIError("AI_UnsupportedFunctionalityError", message, nil),
133 Functionality: functionality,
134 }
135}