1package providertests
2
3import (
4 "net/http"
5 "os"
6 "testing"
7
8 "github.com/charmbracelet/fantasy/ai"
9 "github.com/charmbracelet/fantasy/anthropic"
10 "github.com/stretchr/testify/require"
11 "gopkg.in/dnaeon/go-vcr.v4/pkg/recorder"
12)
13
14func TestAnthropicCommon(t *testing.T) {
15 testCommon(t, []builderPair{
16 {"claude-sonnet-4", builderAnthropicClaudeSonnet4, nil},
17 })
18
19 opts := ai.ProviderOptions{
20 anthropic.Name: &anthropic.ProviderOptions{
21 Thinking: &anthropic.ThinkingProviderOption{
22 BudgetTokens: 4000,
23 },
24 },
25 }
26 testThinking(t, []builderPair{
27 {"claude-sonnet-4", builderAnthropicClaudeSonnet4, opts},
28 }, testGoogleThinking)
29}
30
31func testAnthropicThinking(t *testing.T, result *ai.AgentResult) {
32 reasoningContentCount := 0
33 signaturesCount := 0
34 // Test if we got the signature
35 for _, step := range result.Steps {
36 for _, msg := range step.Messages {
37 for _, content := range msg.Content {
38 if content.GetType() == ai.ContentTypeReasoning {
39 reasoningContentCount += 1
40 reasoningContent, ok := ai.AsContentType[ai.ReasoningPart](content)
41 if !ok {
42 continue
43 }
44 if len(reasoningContent.ProviderOptions) == 0 {
45 continue
46 }
47
48 anthropicReasoningMetadata, ok := reasoningContent.ProviderOptions[anthropic.Name]
49 if !ok {
50 continue
51 }
52 if reasoningContent.Text != "" {
53 if typed, ok := anthropicReasoningMetadata.(*anthropic.ReasoningOptionMetadata); ok {
54 require.NotEmpty(t, typed.Signature)
55 signaturesCount += 1
56 }
57 }
58 }
59 }
60 }
61 }
62 require.Greater(t, reasoningContentCount, 0)
63 require.Greater(t, signaturesCount, 0)
64 require.Equal(t, reasoningContentCount, signaturesCount)
65}
66
67func builderAnthropicClaudeSonnet4(r *recorder.Recorder) (ai.LanguageModel, error) {
68 provider := anthropic.New(
69 anthropic.WithAPIKey(os.Getenv("ANTHROPIC_API_KEY")),
70 anthropic.WithHTTPClient(&http.Client{Transport: r}),
71 )
72 return provider.LanguageModel("claude-sonnet-4-20250514")
73}