Repository navigation
Expand file tree
/
Copy pathmodels.go
More file actions
275 lines (242 loc) · 7.64 KB
/
Copy pathmodels.go
File metadata and controls
275 lines (242 loc) · 7.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
package model
import (
"fmt"
"strings"
)
const (
// Provider names
ProviderOpenAI = "openai"
ProviderAnthropic = "anthropic"
ProviderGoogle = "google"
// OpenAI model names
OpenAIGPT5MiniName = "openai-gpt5-mini"
OpenAIGPT52Name = "openai-gpt5.2"
OpenAIGPT52CodexName = "openai-gpt5.2-codex"
// Anthropic model names
Claude45SonnetName = "claude-sonnet-4-5"
Claude45SonnetInputName = "claude-4.5-sonnet"
Claude45HaikuName = "claude-haiku-4-5"
Claude45HaikuInputName = "claude-4.5-haiku"
// Google model names
Gemini25ProName = "gemini-2.5-pro"
Gemini25FlashName = "gemini-2.5-flash"
Gemini2FlashLiteName = "gemini-2.0-flash-lite"
Gemini3FlashName = "gemini-3-flash-preview"
Gemini3FlashInputName = "gemini-3-flash"
// Mistral model names
Devstral2Name = "devstral-2"
// Qwen model names
Qwen25Starcoder7bName = "qwen2.5-coder-7b"
)
type Model struct {
ID int
Name string
CLIName string // user-facing CLI name; falls back to Name if empty
Provider string
RawAPIModel string // When set, this is used directly for API calls (for custom AI Gateway models)
}
var (
ModelUnknown = Model{ID: 0, Name: Unknown, Provider: Unknown}
// OpenAI models
OpenAIGPT5Mini = Model{ID: 12, Name: OpenAIGPT5MiniName, Provider: ProviderOpenAI}
OpenAIGPT52 = Model{ID: 13, Name: OpenAIGPT52Name, Provider: ProviderOpenAI}
OpenAIGPT52Codex = Model{ID: 13, Name: OpenAIGPT52CodexName, Provider: ProviderOpenAI}
// Anthropic models
Claude45Sonnet = Model{ID: 34, Name: Claude45SonnetName, CLIName: Claude45SonnetInputName, Provider: ProviderAnthropic}
Claude45Haiku = Model{ID: 35, Name: Claude45HaikuName, CLIName: Claude45HaikuInputName, Provider: ProviderAnthropic}
// Google models
Gemini25Pro = Model{ID: 51, Name: Gemini25ProName, Provider: ProviderGoogle}
Gemini25Flash = Model{ID: 52, Name: Gemini25FlashName, Provider: ProviderGoogle}
Gemini2FlashLite = Model{ID: 53, Name: Gemini2FlashLiteName, Provider: ProviderGoogle}
Gemini3Flash = Model{ID: 54, Name: Gemini3FlashName, CLIName: Gemini3FlashInputName, Provider: ProviderGoogle}
// Mistral
Devstral2 = Model{ID: 71, Name: Devstral2Name, Provider: "mistral"}
// Qwen
Qwen25Starcoder7b = Model{ID: 91, Name: Qwen25Starcoder7bName, Provider: "qwen"}
)
func (m Model) String() string {
return m.Name
}
func (m Model) GetCLIName() string {
if m.CLIName != "" {
return m.CLIName
}
return m.Name
}
func GetModel(modelStr string) (Model, error) {
cleanModelStr := strings.ToLower(strings.TrimSpace(modelStr))
// Only support explicitly defined models
switch cleanModelStr {
case OpenAIGPT5MiniName:
return OpenAIGPT5Mini, nil
case OpenAIGPT52Name:
return OpenAIGPT52, nil
case OpenAIGPT52CodexName:
return OpenAIGPT52Codex, nil
case Claude45SonnetInputName:
return Claude45Sonnet, nil
case Claude45HaikuInputName:
return Claude45Haiku, nil
case Gemini25ProName:
return Gemini25Pro, nil
case Gemini25FlashName:
return Gemini25Flash, nil
case Gemini2FlashLiteName:
return Gemini2FlashLite, nil
case Gemini3FlashInputName:
return Gemini3Flash, nil
case Devstral2Name:
return Devstral2, nil
case Qwen25Starcoder7bName:
return Qwen25Starcoder7b, nil
default:
availableModels := strings.Join(GetAllModelStrings(), ", ")
return ModelUnknown, fmt.Errorf("unsupported model '%s'. Available models: %s", modelStr, availableModels)
}
}
// GetModelOrPassthrough attempts to get a predefined model, but if allowPassthrough is true
// and the model is not found, it will accept any arbitrary string as a custom model.
// This is useful for AI Gateway scenarios where the model string can be arbitrary.
func GetModelOrPassthrough(modelStr string, allowPassthrough bool) (Model, error) {
// Try predefined models first
m, err := GetModel(modelStr)
if err == nil {
return m, nil
}
// If passthrough allowed (AI Gateway mode), accept any string
if allowPassthrough {
return Model{
ID: -1, // Negative ID for custom models
Name: modelStr,
Provider: Unknown,
RawAPIModel: modelStr, // This being set indicates custom model
}, nil
}
return ModelUnknown, err
}
func GetAllModels() []Model {
return []Model{
OpenAIGPT5Mini, OpenAIGPT52, OpenAIGPT52Codex,
Claude45Sonnet, Claude45Haiku,
Gemini25Pro, Gemini25Flash, Gemini2FlashLite, Gemini3Flash,
}
}
func GetAllModelStrings() []string {
models := GetAllModels()
result := make([]string, len(models))
for i, m := range models {
result[i] = m.GetCLIName()
}
return result
}
// GetModelByID gets a model by its numeric ID and returns true if found, otherwise false.
func GetModelByID(id int) (Model, bool) {
models := GetAllModels()
for _, m := range models {
if m.ID == id {
return m, true
}
}
return Model{}, false
}
func (m Model) ToAPIModel() string {
return m.ToAPIModelWithFormat(false) // Default to direct provider format
}
func (m Model) ToAPIModelWithFormat(isAIGateway bool) string {
// If RawAPIModel is set, this is a custom model - return it directly
if m.RawAPIModel != "" {
return m.RawAPIModel
}
if isAIGateway {
return m.toAIGatewayFormat()
}
return m.toDirectProviderFormat()
}
func (m Model) toDirectProviderFormat() string {
// Direct provider API format (original behavior)
switch m.ID {
case OpenAIGPT5Mini.ID:
return "gpt-5-mini"
case OpenAIGPT52.ID:
return "gpt-5.2"
case OpenAIGPT52Codex.ID:
return "gpt-5.2-codex"
case Gemini25Pro.ID:
return Gemini25ProName
case Gemini25Flash.ID:
return Gemini25FlashName
case Gemini2FlashLite.ID:
return "gemini-2.0-flash-lite-preview"
case Gemini3Flash.ID:
return Gemini3FlashName
case Claude45Sonnet.ID:
return Claude45SonnetName
case Claude45Haiku.ID:
return Claude45HaikuName
default:
return Unknown
}
}
func (m Model) toAIGatewayFormat() string {
// AI Gateway expects provider/model format
providerName := m.Provider
if m.Provider == ProviderGoogle {
providerName = "gemini" // AI Gateway uses "gemini" not "google"
}
switch m.ID {
case OpenAIGPT5Mini.ID:
return ProviderOpenAI + "/gpt-5-mini"
case OpenAIGPT52.ID:
return ProviderOpenAI + "/gpt-5.2"
case OpenAIGPT52Codex.ID:
return ProviderOpenAI + "/gpt-5.2-codex"
case Claude45Sonnet.ID:
return ProviderAnthropic + "/claude-sonnet-4-5-20250929"
case Claude45Haiku.ID:
return ProviderAnthropic + "/claude-3-haiku-20240307"
case Gemini25Pro.ID:
return "gemini/" + Gemini25ProName
case Gemini25Flash.ID:
return "gemini/" + Gemini25FlashName
case Gemini3Flash.ID:
return "gemini/" + Gemini3FlashName
case Gemini2FlashLite.ID:
return "gemini/gemini-2.0-flash-lite-preview"
case Devstral2.ID:
return "datadoginternal/mistralai/devstral-small-2"
case Qwen25Starcoder7b.ID:
return "datadoginternal/Qwen/Qwen2.5-Coder-7B"
default:
return providerName + "/" + m.Name
}
}
func (m Model) IsOpenAI() bool {
// Custom models (RawAPIModel set) return false
if m.RawAPIModel != "" {
return false
}
return m.Provider == ProviderOpenAI
}
func (m Model) IsAnthropic() bool {
// Custom models (RawAPIModel set) return false
if m.RawAPIModel != "" {
return false
}
return m.Provider == ProviderAnthropic
}
func (m Model) IsGoogle() bool {
// Custom models (RawAPIModel set) return false
if m.RawAPIModel != "" {
return false
}
return m.Provider == ProviderGoogle
}
func (m Model) IsCustom() bool {
return m.RawAPIModel != ""
}
// RequiresMaxCompletionTokens returns true if this model requires MaxCompletionTokens instead of MaxTokens
func (m Model) RequiresMaxCompletionTokens() bool {
// Newer OpenAI models (GPT-5 Mini, GPT-4.1 Mini) require MaxCompletionTokens
return m.ID == OpenAIGPT5Mini.ID
}
// No dynamic model detection - all models must be explicitly defined above