1package anthropic
2
3import (
4 "encoding/json"
5 "net/http"
6 "net/http/httptest"
7 "testing"
8
9 "charm.land/fantasy"
10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/require"
12)
13
14func TestUserAgent(t *testing.T) {
15 t.Parallel()
16
17 newUAServer := func() (*httptest.Server, *[]map[string]string) {
18 var captured []map[string]string
19 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
20 h := make(map[string]string)
21 for k, v := range r.Header {
22 if len(v) > 0 {
23 h[k] = v[0]
24 }
25 }
26 captured = append(captured, h)
27
28 w.Header().Set("Content-Type", "application/json")
29 _ = json.NewEncoder(w).Encode(mockAnthropicGenerateResponse())
30 }))
31 return server, &captured
32 }
33
34 prompt := fantasy.Prompt{
35 {
36 Role: fantasy.MessageRoleUser,
37 Content: []fantasy.MessagePart{fantasy.TextPart{Text: "Hi"}},
38 },
39 }
40
41 t.Run("default UA applied", func(t *testing.T) {
42 t.Parallel()
43 server, captured := newUAServer()
44 defer server.Close()
45
46 p, err := New(WithAPIKey("k"), WithBaseURL(server.URL))
47 require.NoError(t, err)
48 model, _ := p.LanguageModel(t.Context(), "claude-sonnet-4-20250514")
49 _, _ = model.Generate(t.Context(), fantasy.Call{Prompt: prompt})
50
51 require.Len(t, *captured, 1)
52 assert.Equal(t, "Charm Fantasy/"+fantasy.Version, (*captured)[0]["User-Agent"])
53 })
54
55 t.Run("WithUserAgent wins over both", func(t *testing.T) {
56 t.Parallel()
57 server, captured := newUAServer()
58 defer server.Close()
59
60 p, err := New(
61 WithAPIKey("k"),
62 WithBaseURL(server.URL),
63 WithHeaders(map[string]string{"User-Agent": "from-headers"}),
64 WithUserAgent("explicit-ua"),
65 )
66 require.NoError(t, err)
67 model, _ := p.LanguageModel(t.Context(), "claude-sonnet-4-20250514")
68 _, _ = model.Generate(t.Context(), fantasy.Call{Prompt: prompt})
69
70 require.Len(t, *captured, 1)
71 assert.Equal(t, "explicit-ua", (*captured)[0]["User-Agent"])
72 })
73}