@@ -10,6 +10,202 @@ import (
1010 "github.com/openai/openai-go/v3"
1111)
1212
13+ // modelConfig holds model configuration including whether it requires user's own API key
14+ type modelConfig struct {
15+ name string
16+ slugOpenRouter string // Slug for OpenRouter API (used when user doesn't provide own key)
17+ slugOpenAI string // Slug for OpenAI API (used when user provides own key)
18+ totalContext int64
19+ maxOutput int64
20+ inputPrice int64
21+ outputPrice int64
22+ requireOwnKey bool // If true, this model requires user to provide their own API key
23+ }
24+
25+ // allModels defines all available models in the system
26+ var allModels = []modelConfig {
27+ {
28+ name : "GPT-5.1" ,
29+ slugOpenRouter : "openai/gpt-5.1" ,
30+ slugOpenAI : openai .ChatModelGPT5_1 ,
31+ totalContext : 400000 ,
32+ maxOutput : 128000 ,
33+ inputPrice : 125 , // $1.25
34+ outputPrice : 1000 , // $10.00
35+ requireOwnKey : false ,
36+ },
37+ {
38+ name : "GPT-5.2" ,
39+ slugOpenRouter : "openai/gpt-5.2" ,
40+ slugOpenAI : openai .ChatModelGPT5_2 ,
41+ totalContext : 400000 ,
42+ maxOutput : 128000 ,
43+ inputPrice : 175 , // $1.75
44+ outputPrice : 1400 , // $14.00
45+ requireOwnKey : true ,
46+ },
47+ {
48+ name : "GPT-5 Mini" ,
49+ slugOpenRouter : "openai/gpt-5-mini" ,
50+ slugOpenAI : openai .ChatModelGPT5Mini ,
51+ totalContext : 400000 ,
52+ maxOutput : 128000 ,
53+ inputPrice : 25 ,
54+ outputPrice : 200 ,
55+ requireOwnKey : false ,
56+ },
57+ {
58+ name : "GPT-5 Nano" ,
59+ slugOpenRouter : "openai/gpt-5-nano" ,
60+ slugOpenAI : openai .ChatModelGPT5Nano ,
61+ totalContext : 400000 ,
62+ maxOutput : 128000 ,
63+ inputPrice : 5 , // $0.20
64+ outputPrice : 40 , // $0.80
65+ requireOwnKey : false ,
66+ },
67+ {
68+ name : "GPT-4.1" ,
69+ slugOpenRouter : "openai/gpt-4.1" ,
70+ slugOpenAI : openai .ChatModelGPT4_1 ,
71+ totalContext : 1050000 ,
72+ maxOutput : 32800 ,
73+ inputPrice : 200 , // $2.00
74+ outputPrice : 800 ,
75+ requireOwnKey : false ,
76+ },
77+ {
78+ name : "GPT-4.1-mini" ,
79+ slugOpenRouter : "openai/gpt-4.1-mini" ,
80+ slugOpenAI : openai .ChatModelGPT4_1Mini ,
81+ totalContext : 128000 ,
82+ maxOutput : 16400 ,
83+ inputPrice : 15 ,
84+ outputPrice : 60 ,
85+ requireOwnKey : false ,
86+ },
87+ {
88+ name : "GPT-4o" ,
89+ slugOpenRouter : "openai/gpt-4o" ,
90+ slugOpenAI : openai .ChatModelGPT4o ,
91+ totalContext : 128000 ,
92+ maxOutput : 16400 ,
93+ inputPrice : 250 ,
94+ outputPrice : 1000 ,
95+ requireOwnKey : true ,
96+ },
97+ {
98+ name : "OpenAI: gpt-oss-120b (free)" ,
99+ slugOpenRouter : "openai/gpt-oss-120b:free" ,
100+ slugOpenAI : "" ,
101+ totalContext : 131072 ,
102+ maxOutput : 131072 ,
103+ inputPrice : 0 ,
104+ outputPrice : 0 ,
105+ requireOwnKey : false ,
106+ },
107+ {
108+ name : "Qwen Plus (balanced)" ,
109+ slugOpenRouter : "qwen/qwen-plus" ,
110+ slugOpenAI : "" , // OpenAI doesn't support Qwen, use OpenRouter slug
111+ totalContext : 131100 ,
112+ maxOutput : 8200 ,
113+ inputPrice : 40 ,
114+ outputPrice : 120 ,
115+ requireOwnKey : false ,
116+ },
117+ {
118+ name : "Qwen Turbo (fast)" ,
119+ slugOpenRouter : "qwen/qwen-turbo" ,
120+ slugOpenAI : "" , // OpenAI doesn't support Qwen, use OpenRouter slug
121+ totalContext : 1000000 ,
122+ maxOutput : 8200 ,
123+ inputPrice : 5 ,
124+ outputPrice : 20 ,
125+ requireOwnKey : false ,
126+ },
127+ {
128+ name : "Qwen3 Coder 480B A35B (free)" ,
129+ slugOpenRouter : "qwen/qwen3-coder:free" ,
130+ slugOpenAI : "" ,
131+ totalContext : 262000 ,
132+ maxOutput : 262000 ,
133+ inputPrice : 0 ,
134+ outputPrice : 0 ,
135+ requireOwnKey : false ,
136+ },
137+ {
138+ name : "GLM 4.5 Air (free)" ,
139+ slugOpenRouter : "z-ai/glm-4.5-air:free" ,
140+ slugOpenAI : "" ,
141+ totalContext : 131072 ,
142+ maxOutput : 131072 ,
143+ inputPrice : 0 ,
144+ outputPrice : 0 ,
145+ requireOwnKey : false ,
146+ },
147+ {
148+ name : "Gemini 2.5 Flash (fast)" ,
149+ slugOpenRouter : "google/gemini-2.5-flash" ,
150+ slugOpenAI : "" , // OpenAI doesn't support Gemini, use OpenRouter slug
151+ totalContext : 1050000 ,
152+ maxOutput : 65500 ,
153+ inputPrice : 30 ,
154+ outputPrice : 250 ,
155+ requireOwnKey : false ,
156+ },
157+ {
158+ name : "Gemini 3 Flash Preview" ,
159+ slugOpenRouter : "google/gemini-3-flash-preview" ,
160+ slugOpenAI : "" , // OpenAI doesn't support Gemini, use OpenRouter slug
161+ totalContext : 1050000 ,
162+ maxOutput : 65500 ,
163+ inputPrice : 50 ,
164+ outputPrice : 300 ,
165+ requireOwnKey : false ,
166+ },
167+ {
168+ name : "o1 Mini" ,
169+ slugOpenRouter : "openai/o1-mini" ,
170+ slugOpenAI : openai .ChatModelO1Mini ,
171+ totalContext : 128000 ,
172+ maxOutput : 65536 ,
173+ inputPrice : 300 , // $3.00
174+ outputPrice : 1200 , // $12.00
175+ requireOwnKey : true ,
176+ },
177+ {
178+ name : "o3" ,
179+ slugOpenRouter : "openai/o3" ,
180+ slugOpenAI : openai .ChatModelO3 ,
181+ totalContext : 200000 ,
182+ maxOutput : 100000 ,
183+ inputPrice : 200 ,
184+ outputPrice : 800 ,
185+ requireOwnKey : true ,
186+ },
187+ {
188+ name : "o3 Mini" ,
189+ slugOpenRouter : "openai/o3-mini" ,
190+ slugOpenAI : openai .ChatModelO3Mini ,
191+ totalContext : 200000 ,
192+ maxOutput : 100000 ,
193+ inputPrice : 110 ,
194+ outputPrice : 440 ,
195+ requireOwnKey : true ,
196+ },
197+ {
198+ name : "o4 Mini" ,
199+ slugOpenRouter : "openai/o4-mini" ,
200+ slugOpenAI : openai .ChatModelO4Mini ,
201+ totalContext : 128000 ,
202+ maxOutput : 65536 ,
203+ inputPrice : 110 ,
204+ outputPrice : 440 ,
205+ requireOwnKey : true ,
206+ },
207+ }
208+
13209func (s * ChatServerV2 ) ListSupportedModels (
14210 ctx context.Context ,
15211 req * chatv2.ListSupportedModelsRequest ,
@@ -24,89 +220,43 @@ func (s *ChatServerV2) ListSupportedModels(
24220 return nil , err
25221 }
26222
223+ hasOwnAPIKey := strings .TrimSpace (settings .OpenAIAPIKey ) != ""
224+
27225 var models []* chatv2.SupportedModel
28- if strings .TrimSpace (settings .OpenAIAPIKey ) == "" {
29- models = []* chatv2.SupportedModel {
30- {
31- Name : "GPT-4.1" ,
32- Slug : "openai/gpt-4.1" ,
33- TotalContext : 1050000 ,
34- MaxOutput : 32800 ,
35- InputPrice : 200 ,
36- OutputPrice : 800 ,
37- },
38- {
39- Name : "GPT-4.1-mini" ,
40- Slug : "openai/gpt-4.1-mini" ,
41- TotalContext : 128000 ,
42- MaxOutput : 16400 ,
43- InputPrice : 15 ,
44- OutputPrice : 60 ,
45- },
46- {
47- Name : "Qwen Plus (balanced)" ,
48- Slug : "qwen/qwen-plus" ,
49- TotalContext : 131100 ,
50- MaxOutput : 8200 ,
51- InputPrice : 40 ,
52- OutputPrice : 120 ,
53- },
54- {
55- Name : "Qwen Turbo (fast)" ,
56- Slug : "qwen/qwen-turbo" ,
57- TotalContext : 1000000 ,
58- MaxOutput : 8200 ,
59- InputPrice : 5 ,
60- OutputPrice : 20 ,
61- },
62- {
63- Name : "Gemini 2.5 Flash (fast)" ,
64- Slug : "google/gemini-2.5-flash" ,
65- TotalContext : 1050000 ,
66- MaxOutput : 65500 ,
67- InputPrice : 30 ,
68- OutputPrice : 250 ,
69- },
70- {
71- Name : "Gemini 3 Flash Preview" ,
72- Slug : "google/gemini-3-flash-preview" ,
73- TotalContext : 1050000 ,
74- MaxOutput : 65500 ,
75- InputPrice : 50 ,
76- OutputPrice : 300 ,
77- },
226+ for _ , config := range allModels {
227+ // Choose the appropriate slug based on whether user has their own API key.
228+ //
229+ // Some models are only available via OpenRouter; for those, slugOpenAI may be empty.
230+ // In that case, keep using the OpenRouter slug to avoid returning an empty model slug.
231+ slug := config .slugOpenRouter
232+ if hasOwnAPIKey && strings .TrimSpace (config .slugOpenAI ) != "" {
233+ slug = config .slugOpenAI
78234 }
79- } else {
80- models = []* chatv2.SupportedModel {
81- {
82- Name : "GPT-4.1" ,
83- Slug : openai .ChatModelGPT4_1 ,
84- TotalContext : 1050000 ,
85- MaxOutput : 32800 ,
86- InputPrice : 200 ,
87- OutputPrice : 800 ,
88- },
89- {
90- Name : "GPT-4o" ,
91- Slug : openai .ChatModelGPT4o ,
92- TotalContext : 128000 ,
93- MaxOutput : 16400 ,
94- InputPrice : 250 ,
95- OutputPrice : 1000 ,
96- },
97- {
98- Name : "GPT-4.1-mini" ,
99- Slug : openai .ChatModelGPT4_1Mini ,
100- TotalContext : 128000 ,
101- MaxOutput : 16400 ,
102- InputPrice : 15 ,
103- OutputPrice : 60 ,
104- },
105- // TODO: add user custom models
235+
236+ model := & chatv2.SupportedModel {
237+ Name : config .name ,
238+ Slug : slug ,
239+ TotalContext : config .totalContext ,
240+ MaxOutput : config .maxOutput ,
241+ InputPrice : config .inputPrice ,
242+ OutputPrice : config .outputPrice ,
106243 }
244+
245+ // If model requires own key but user hasn't provided one, mark as disabled
246+ if config .requireOwnKey && ! hasOwnAPIKey {
247+ model .Disabled = true
248+ model .DisabledReason = stringPtr ("Requires your own OpenAI API key. Configure it in Settings." )
249+ }
250+
251+ models = append (models , model )
107252 }
108253
109254 return & chatv2.ListSupportedModelsResponse {
110255 Models : models ,
111256 }, nil
112257}
258+
259+ // stringPtr returns a pointer to the given string
260+ func stringPtr (s string ) * string {
261+ return & s
262+ }
0 commit comments