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