1package providertests
2
3import (
4 "net/http"
5 "os"
6 "testing"
7
8 "github.com/charmbracelet/fantasy/ai"
9 "github.com/charmbracelet/fantasy/openrouter"
10 "gopkg.in/dnaeon/go-vcr.v4/pkg/recorder"
11)
12
13type openrouterModel struct {
14 name string
15 builderFunc builderFunc
16 providers []string
17}
18
19func TestOpenRouterCommon(t *testing.T) {
20 var pairs []builderPair
21 models := []openrouterModel{
22 openrouterKimiK2(),
23 openrouterGrokCodeFast1(),
24 openrouterClaudeSonnet4(),
25 openrouterGrok4FastFree(),
26 openrouterGemini25Flash(),
27 openrouterGemini20Flash(),
28 openrouterDeepseekV31Free(),
29 openrouterGpt5(),
30 }
31
32 for _, model := range models {
33 // add one entry for multi provider tests
34 pairs = append(
35 pairs,
36 builderPair{
37 model.name,
38 model.builderFunc,
39 nil,
40 })
41 for _, provider := range model.providers {
42 pairs = append(
43 pairs,
44 builderPair{
45 model.name + "_" + provider,
46 model.builderFunc,
47 ai.ProviderOptions{
48 openrouter.Name: &openrouter.ProviderOptions{
49 Provider: &openrouter.Provider{
50 Only: []string{provider},
51 },
52 },
53 },
54 })
55 }
56 }
57
58 testCommon(t, pairs)
59}
60
61func openrouterKimiK2() openrouterModel {
62 return openrouterModel{
63 name: "kimi-k2",
64 builderFunc: func(r *recorder.Recorder) (ai.LanguageModel, error) {
65 provider := openrouter.New(
66 openrouter.WithAPIKey(os.Getenv("OPENROUTER_API_KEY")),
67 openrouter.WithHTTPClient(&http.Client{Transport: r}),
68 )
69 return provider.LanguageModel("moonshotai/kimi-k2-0905")
70 },
71 providers: []string{
72 "deepinfra",
73 "siliconflow",
74 "fireworks",
75 "moonshotai",
76 "novita",
77 "baseten",
78 "together",
79 "groq",
80 "moonshotai/turbo",
81 "wandb",
82 },
83 }
84}
85
86func openrouterGrokCodeFast1() openrouterModel {
87 return openrouterModel{
88 name: "grok-code-fast-1",
89 builderFunc: func(r *recorder.Recorder) (ai.LanguageModel, error) {
90 provider := openrouter.New(
91 openrouter.WithAPIKey(os.Getenv("OPENROUTER_API_KEY")),
92 openrouter.WithHTTPClient(&http.Client{Transport: r}),
93 )
94 return provider.LanguageModel("x-ai/grok-code-fast-1")
95 },
96 providers: []string{
97 "xai",
98 },
99 }
100}
101
102func openrouterGrok4FastFree() openrouterModel {
103 return openrouterModel{
104 name: "grok-4-fast-free",
105 builderFunc: func(r *recorder.Recorder) (ai.LanguageModel, error) {
106 provider := openrouter.New(
107 openrouter.WithAPIKey(os.Getenv("OPENROUTER_API_KEY")),
108 openrouter.WithHTTPClient(&http.Client{Transport: r}),
109 )
110 return provider.LanguageModel("x-ai/grok-4-fast:free")
111 },
112 providers: []string{
113 "xai",
114 },
115 }
116}
117
118func openrouterGemini25Flash() openrouterModel {
119 return openrouterModel{
120 name: "gemini-2.5-flash",
121 builderFunc: func(r *recorder.Recorder) (ai.LanguageModel, error) {
122 provider := openrouter.New(
123 openrouter.WithAPIKey(os.Getenv("OPENROUTER_API_KEY")),
124 openrouter.WithHTTPClient(&http.Client{Transport: r}),
125 )
126 return provider.LanguageModel("google/gemini-2.5-flash")
127 },
128 providers: []string{
129 "google-vertex/global",
130 "google-ai-studio",
131 "google-vertex",
132 },
133 }
134}
135
136func openrouterGemini20Flash() openrouterModel {
137 return openrouterModel{
138 name: "gemini-2.0-flash",
139 builderFunc: func(r *recorder.Recorder) (ai.LanguageModel, error) {
140 provider := openrouter.New(
141 openrouter.WithAPIKey(os.Getenv("OPENROUTER_API_KEY")),
142 openrouter.WithHTTPClient(&http.Client{Transport: r}),
143 )
144 return provider.LanguageModel("google/gemini-2.0-flash-001")
145 },
146 providers: []string{
147 "google-ai-studio",
148 "google-vertex",
149 },
150 }
151}
152
153func openrouterDeepseekV31Free() openrouterModel {
154 return openrouterModel{
155 name: "deepseek-chat-v3.1-free",
156 builderFunc: func(r *recorder.Recorder) (ai.LanguageModel, error) {
157 provider := openrouter.New(
158 openrouter.WithAPIKey(os.Getenv("OPENROUTER_API_KEY")),
159 openrouter.WithHTTPClient(&http.Client{Transport: r}),
160 )
161 return provider.LanguageModel("deepseek/deepseek-chat-v3.1:free")
162 },
163 providers: []string{
164 "deepinfra",
165 },
166 }
167}
168
169func openrouterClaudeSonnet4() openrouterModel {
170 return openrouterModel{
171 name: "claude-sonnet-4",
172 builderFunc: func(r *recorder.Recorder) (ai.LanguageModel, error) {
173 provider := openrouter.New(
174 openrouter.WithAPIKey(os.Getenv("OPENROUTER_API_KEY")),
175 openrouter.WithHTTPClient(&http.Client{Transport: r}),
176 )
177 return provider.LanguageModel("anthropic/claude-sonnet-4")
178 },
179 providers: []string{
180 "google-vertex",
181 "google-vertex/global",
182 "anthropic",
183 "google-vertex/europe",
184 "amazon-bedrock",
185 },
186 }
187}
188
189func openrouterGpt5() openrouterModel {
190 return openrouterModel{
191 name: "gpt-5",
192 builderFunc: func(r *recorder.Recorder) (ai.LanguageModel, error) {
193 provider := openrouter.New(
194 openrouter.WithAPIKey(os.Getenv("OPENROUTER_API_KEY")),
195 openrouter.WithHTTPClient(&http.Client{Transport: r}),
196 )
197 return provider.LanguageModel("openai/gpt-5")
198 },
199 providers: []string{
200 "openai",
201 "azure",
202 },
203 }
204}