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