1package providertests
2
3import (
4 "cmp"
5 "net/http"
6 "os"
7 "testing"
8
9 "charm.land/fantasy"
10 "charm.land/fantasy/providers/azure"
11 "charm.land/fantasy/providers/openai"
12 "github.com/stretchr/testify/require"
13 "gopkg.in/dnaeon/go-vcr.v4/pkg/recorder"
14)
15
16func TestAzureResponsesCommon(t *testing.T) {
17 var pairs []builderPair
18 models := []testModel{
19 {"azure-gpt-5-mini", "gpt-5-mini", true},
20 {"azure-o4-mini", "o4-mini", true},
21 }
22 for _, m := range models {
23 pairs = append(pairs, builderPair{m.name, azureReasoningBuilder(m.model), nil, nil})
24 }
25 testCommon(t, pairs)
26}
27
28func azureReasoningBuilder(model string) builderFunc {
29 return func(t *testing.T, r *recorder.Recorder) (fantasy.LanguageModel, error) {
30 provider, err := azure.New(
31 azure.WithBaseURL(cmp.Or(os.Getenv("FANTASY_AZURE_BASE_URL"), defaultBaseURL)),
32 azure.WithAPIKey(cmp.Or(os.Getenv("FANTASY_AZURE_API_KEY"), "(missing)")),
33 azure.WithHTTPClient(&http.Client{Transport: r}),
34 azure.WithUseResponsesAPI(),
35 )
36 if err != nil {
37 return nil, err
38 }
39 return provider.LanguageModel(t.Context(), model)
40 }
41}
42
43func TestAzureResponsesWithSummaryThinking(t *testing.T) {
44 opts := fantasy.ProviderOptions{
45 openai.Name: &openai.ResponsesProviderOptions{
46 Include: []openai.IncludeType{
47 openai.IncludeReasoningEncryptedContent,
48 },
49 ReasoningEffort: openai.ReasoningEffortOption(openai.ReasoningEffortHigh),
50 ReasoningSummary: fantasy.Opt("auto"),
51 },
52 }
53 var pairs []builderPair
54 models := []testModel{
55 {"azure-gpt-5-mini", "gpt-5-mini", true},
56 }
57 for _, m := range models {
58 if !m.reasoning {
59 continue
60 }
61 pairs = append(pairs, builderPair{m.name, azureReasoningBuilder(m.model), opts, nil})
62 }
63 testThinking(t, pairs, testAzureResponsesThinkingWithSummaryThinking)
64}
65
66func testAzureResponsesThinkingWithSummaryThinking(t *testing.T, result *fantasy.AgentResult) {
67 reasoningContentCount := 0
68 encryptedData := 0
69 // Test if we got the signature
70 for _, step := range result.Steps {
71 for _, msg := range step.Messages {
72 for _, content := range msg.Content {
73 if content.GetType() == fantasy.ContentTypeReasoning {
74 reasoningContentCount += 1
75 reasoningContent, ok := fantasy.AsContentType[fantasy.ReasoningPart](content)
76 if !ok {
77 continue
78 }
79 if len(reasoningContent.ProviderOptions) == 0 {
80 continue
81 }
82
83 openaiReasoningMetadata, ok := reasoningContent.ProviderOptions[openai.Name]
84 if !ok {
85 continue
86 }
87 if typed, ok := openaiReasoningMetadata.(*openai.ResponsesReasoningMetadata); ok {
88 require.NotEmpty(t, typed.EncryptedContent)
89 encryptedData += 1
90 }
91 }
92 }
93 }
94 }
95 require.Greater(t, reasoningContentCount, 0)
96 require.Greater(t, encryptedData, 0)
97 require.Equal(t, reasoningContentCount, encryptedData)
98}