1package anthropic
2
3import (
4 "cmp"
5 "errors"
6 "net/http"
7 "regexp"
8 "strconv"
9 "strings"
10
11 "charm.land/fantasy"
12 "github.com/charmbracelet/anthropic-sdk-go"
13)
14
15var anthropicContextPattern = regexp.MustCompile(`prompt is too long:\s*(\d+)\s*tokens?\s*>\s*(\d+)\s*maximum`)
16
17func toProviderErr(err error) error {
18 var apiErr *anthropic.Error
19 if errors.As(err, &apiErr) {
20 providerErr := &fantasy.ProviderError{
21 Title: cmp.Or(fantasy.ErrorTitleForStatusCode(apiErr.StatusCode), "provider request failed"),
22 Message: apiErr.Error(),
23 Cause: apiErr,
24 URL: apiErr.Request.URL.String(),
25 StatusCode: apiErr.StatusCode,
26 RequestBody: apiErr.DumpRequest(true),
27 ResponseHeaders: toHeaderMap(apiErr.Response.Header),
28 ResponseBody: apiErr.DumpResponse(true),
29 }
30
31 parseContextTooLargeError(apiErr.Error(), providerErr)
32
33 return providerErr
34 }
35 return err
36}
37
38func parseContextTooLargeError(message string, providerErr *fantasy.ProviderError) {
39 matches := anthropicContextPattern.FindStringSubmatch(message)
40 if matches == nil {
41 return
42 }
43
44 providerErr.ContextTooLargeErr = true
45 providerErr.ContextUsedTokens, _ = strconv.Atoi(matches[1])
46 providerErr.ContextMaxTokens, _ = strconv.Atoi(matches[2])
47}
48
49func toHeaderMap(in http.Header) (out map[string]string) {
50 out = make(map[string]string, len(in))
51 for k, v := range in {
52 if l := len(v); l > 0 {
53 out[k] = v[l-1]
54 in[strings.ToLower(k)] = v
55 }
56 }
57 return out
58}