test: add thinking to anthropic

Kujtim Hoxha created

Change summary

providertests/anthropic_test.go                                 | 48 +++
providertests/testdata/TestAnthropicCommon/claude-sonnet-4.yaml | 26 +
2 files changed, 74 insertions(+)

Detailed changes

providertests/anthropic_test.go 🔗

@@ -7,6 +7,7 @@ import (
 
 	"github.com/charmbracelet/fantasy/ai"
 	"github.com/charmbracelet/fantasy/anthropic"
+	"github.com/stretchr/testify/require"
 	"gopkg.in/dnaeon/go-vcr.v4/pkg/recorder"
 )
 
@@ -14,6 +15,53 @@ func TestAnthropicCommon(t *testing.T) {
 	testCommon(t, []builderPair{
 		{"claude-sonnet-4", builderAnthropicClaudeSonnet4, nil},
 	})
+
+	opts := ai.ProviderOptions{
+		anthropic.Name: &anthropic.ProviderOptions{
+			Thinking: &anthropic.ThinkingProviderOption{
+				BudgetTokens: 4000,
+			},
+		},
+	}
+	testThinking(t, []builderPair{
+		{"claude-sonnet-4", builderAnthropicClaudeSonnet4, opts},
+	}, testGoogleThinking)
+}
+
+func testAnthropicThinking(t *testing.T, result *ai.AgentResult) {
+	reasoningContentCount := 0
+	signaturesCount := 0
+	// Test if we got the signature
+	for _, step := range result.Steps {
+		for _, msg := range step.Messages {
+			for _, content := range msg.Content {
+				if content.GetType() == ai.ContentTypeReasoning {
+					reasoningContentCount += 1
+					reasoningContent, ok := ai.AsContentType[ai.ReasoningPart](content)
+					if !ok {
+						continue
+					}
+					if len(reasoningContent.ProviderOptions) == 0 {
+						continue
+					}
+
+					anthropicReasoningMetadata, ok := reasoningContent.ProviderOptions[anthropic.Name]
+					if !ok {
+						continue
+					}
+					if reasoningContent.Text != "" {
+						if typed, ok := anthropicReasoningMetadata.(*anthropic.ReasoningOptionMetadata); ok {
+							require.NotEmpty(t, typed.Signature)
+							signaturesCount += 1
+						}
+					}
+				}
+			}
+		}
+	}
+	require.Greater(t, reasoningContentCount, 0)
+	require.Greater(t, signaturesCount, 0)
+	require.Equal(t, reasoningContentCount, signaturesCount)
 }
 
 func builderAnthropicClaudeSonnet4(r *recorder.Recorder) (ai.LanguageModel, error) {

providertests/testdata/TestAnthropicCommon/claude-sonnet-4.yaml 🔗

@@ -0,0 +1,63 @@
+---
+version: 2
+interactions:
+  - id: 0
+    request:
+        proto: HTTP/1.1
+        proto_major: 1
+        proto_minor: 1
+        content_length: 548
+        host: ""
+        body: '{"max_tokens":8096,"messages":[{"content":[{"text":"What''s the weather in Florence, Italy?","type":"text"}],"role":"user"}],"model":"claude-sonnet-4-20250514","system":[{"text":"You are a helpful assistant","type":"text"}],"thinking":{"budget_tokens":4000,"type":"enabled"},"tool_choice":{"disable_parallel_tool_use":false,"type":"auto"},"tools":[{"input_schema":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"},"name":"weather","description":"Get weather information for a location"}]}'
+        headers:
+            Accept:
+              - application/json
+            Content-Type:
+              - application/json
+            User-Agent:
+              - Anthropic/Go 1.10.0
+        url: https://api.anthropic.com/v1/messages
+        method: POST
+    response:
+        proto: HTTP/2.0
+        proto_major: 2
+        proto_minor: 0
+        content_length: -1
+        uncompressed: true