-
Notifications
You must be signed in to change notification settings - Fork 0
/
client.go
129 lines (104 loc) · 2.89 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package anthropic
import (
"bufio"
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
utils "github.com/adamchol/go-anthropic-sdk/internal"
)
// Anthropic API Client for making requests
type Client struct {
config ClientConfig
requestBuilder utils.RequestBuilder
}
// NewClientWithConfig creates an Anthropic API client with specified configuration
func NewClientWithConfig(config ClientConfig) *Client {
return &Client{
config: config,
requestBuilder: utils.NewRequestBuilder(),
}
}
// NewClient creates an Anthropic API client with API key
func NewClient(apiKey string) *Client {
return NewClientWithConfig(DefaultConfig(apiKey))
}
type requestOptions struct {
body any
header http.Header
}
type requestOption func(*requestOptions)
func withBody(body any) requestOption {
return func(args *requestOptions) {
args.body = body
}
}
func (c *Client) newRequest(ctx context.Context, method, url string, setters ...requestOption) (*http.Request, error) {
args := &requestOptions{
body: nil,
header: make(http.Header),
}
for _, setter := range setters {
setter(args)
}
req, err := c.requestBuilder.Build(ctx, method, url, args.body, args.header)
if err != nil {
return nil, err
}
c.setCommonHeaders(req)
return req, nil
}
func (c *Client) sendRequest(request *http.Request, v any) error {
resp, err := c.config.HTTPClient.Do(request)
if err != nil {
return err
}
defer resp.Body.Close()
if isFailureStatusCode(resp) {
// TODO: handle errors properly
return handleErrorResponse(resp)
}
return json.NewDecoder(resp.Body).Decode(v)
}
func (c *Client) sendStreamRequest(req *http.Request) (*streamReader, error) {
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "text/event-stream")
req.Header.Set("Cache-Control", "no-cache")
req.Header.Set("Connection", "keep-alive")
resp, err := c.config.HTTPClient.Do(req)
if err != nil {
return new(streamReader), err
}
return &streamReader{
response: resp,
reader: bufio.NewReader(resp.Body),
}, nil
}
func (c *Client) setCommonHeaders(req *http.Request) {
req.Header.Set("content-type", "application/json")
req.Header.Set("anthropic-version", string(c.config.APIVersion))
req.Header.Set("x-api-key", c.config.authToken)
}
func (c *Client) fullURL(suffix string) string {
return fmt.Sprintf("%s%s", c.config.BaseUrl, suffix)
}
func isFailureStatusCode(response *http.Response) bool {
return response.StatusCode < http.StatusOK || response.StatusCode >= http.StatusBadRequest
}
type ErrorResponse struct {
Type string `json:"type"`
Error *APIError `json:"error"`
}
type APIError struct {
Type string `json:"type"`
Message string `json:"message"`
}
func handleErrorResponse(resp *http.Response) error {
var errResp ErrorResponse
err := json.NewDecoder(resp.Body).Decode(&errResp)
if err != nil || errResp.Error == nil {
return err
}
return errors.New(errResp.Error.Message)
}