423 lines
20 KiB
Go
423 lines
20 KiB
Go
package windsurf
|
|
|
|
import (
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type ModelMeta struct {
|
|
Name string `json:"name"`
|
|
Provider string `json:"provider"`
|
|
EnumValue int `json:"enum_value"`
|
|
ModelUID string `json:"model_uid,omitempty"`
|
|
Credit float64 `json:"credit"`
|
|
}
|
|
|
|
type ModelListEntry struct {
|
|
ID string `json:"id"`
|
|
Object string `json:"object"`
|
|
Created int64 `json:"created"`
|
|
OwnedBy string `json:"owned_by"`
|
|
}
|
|
|
|
var catalog = map[string]ModelMeta{
|
|
// Anthropic
|
|
"claude-3.5-sonnet": {Name: "claude-3.5-sonnet", Provider: "anthropic", EnumValue: 166, Credit: 2},
|
|
"claude-3.7-sonnet": {Name: "claude-3.7-sonnet", Provider: "anthropic", EnumValue: 226, Credit: 2},
|
|
"claude-3.7-sonnet-thinking": {Name: "claude-3.7-sonnet-thinking", Provider: "anthropic", EnumValue: 227, Credit: 3},
|
|
"claude-4-sonnet": {Name: "claude-4-sonnet", Provider: "anthropic", EnumValue: 281, ModelUID: "MODEL_CLAUDE_4_SONNET", Credit: 2},
|
|
"claude-4-sonnet-thinking": {Name: "claude-4-sonnet-thinking", Provider: "anthropic", EnumValue: 282, ModelUID: "MODEL_CLAUDE_4_SONNET_THINKING", Credit: 3},
|
|
"claude-4-opus": {Name: "claude-4-opus", Provider: "anthropic", EnumValue: 290, ModelUID: "MODEL_CLAUDE_4_OPUS", Credit: 4},
|
|
"claude-4-opus-thinking": {Name: "claude-4-opus-thinking", Provider: "anthropic", EnumValue: 291, ModelUID: "MODEL_CLAUDE_4_OPUS_THINKING", Credit: 5},
|
|
"claude-4.1-opus": {Name: "claude-4.1-opus", Provider: "anthropic", EnumValue: 328, ModelUID: "MODEL_CLAUDE_4_1_OPUS", Credit: 4},
|
|
"claude-4.1-opus-thinking": {Name: "claude-4.1-opus-thinking", Provider: "anthropic", EnumValue: 329, ModelUID: "MODEL_CLAUDE_4_1_OPUS_THINKING", Credit: 5},
|
|
"claude-4.5-haiku": {Name: "claude-4.5-haiku", Provider: "anthropic", ModelUID: "MODEL_PRIVATE_11", Credit: 1},
|
|
"claude-4.5-sonnet": {Name: "claude-4.5-sonnet", Provider: "anthropic", EnumValue: 353, ModelUID: "MODEL_PRIVATE_2", Credit: 2},
|
|
"claude-4.5-sonnet-thinking": {Name: "claude-4.5-sonnet-thinking", Provider: "anthropic", EnumValue: 354, ModelUID: "MODEL_PRIVATE_3", Credit: 3},
|
|
"claude-4.5-opus": {Name: "claude-4.5-opus", Provider: "anthropic", EnumValue: 391, ModelUID: "MODEL_CLAUDE_4_5_OPUS", Credit: 4},
|
|
"claude-4.5-opus-thinking": {Name: "claude-4.5-opus-thinking", Provider: "anthropic", EnumValue: 392, ModelUID: "MODEL_CLAUDE_4_5_OPUS_THINKING", Credit: 5},
|
|
"claude-sonnet-4.6": {Name: "claude-sonnet-4.6", Provider: "anthropic", ModelUID: "claude-sonnet-4-6", Credit: 4},
|
|
"claude-sonnet-4.6-thinking": {Name: "claude-sonnet-4.6-thinking", Provider: "anthropic", ModelUID: "claude-sonnet-4-6-thinking", Credit: 6},
|
|
"claude-sonnet-4.6-1m": {Name: "claude-sonnet-4.6-1m", Provider: "anthropic", ModelUID: "claude-sonnet-4-6-1m", Credit: 12},
|
|
"claude-sonnet-4.6-thinking-1m": {Name: "claude-sonnet-4.6-thinking-1m", Provider: "anthropic", ModelUID: "claude-sonnet-4-6-thinking-1m", Credit: 16},
|
|
"claude-opus-4.6": {Name: "claude-opus-4.6", Provider: "anthropic", ModelUID: "claude-opus-4-6", Credit: 6},
|
|
"claude-opus-4.6-thinking": {Name: "claude-opus-4.6-thinking", Provider: "anthropic", ModelUID: "claude-opus-4-6-thinking", Credit: 8},
|
|
"claude-opus-4-7-medium": {Name: "claude-opus-4-7-medium", Provider: "anthropic", ModelUID: "claude-opus-4-7-medium", Credit: 8},
|
|
|
|
// OpenAI GPT
|
|
"gpt-4o": {Name: "gpt-4o", Provider: "openai", EnumValue: 109, ModelUID: "MODEL_CHAT_GPT_4O_2024_08_06", Credit: 1},
|
|
"gpt-4o-mini": {Name: "gpt-4o-mini", Provider: "openai", EnumValue: 113, Credit: 0.5},
|
|
"gpt-4.1": {Name: "gpt-4.1", Provider: "openai", EnumValue: 259, ModelUID: "MODEL_CHAT_GPT_4_1_2025_04_14", Credit: 1},
|
|
"gpt-4.1-mini": {Name: "gpt-4.1-mini", Provider: "openai", EnumValue: 260, Credit: 0.5},
|
|
"gpt-4.1-nano": {Name: "gpt-4.1-nano", Provider: "openai", EnumValue: 261, Credit: 0.25},
|
|
"gpt-5": {Name: "gpt-5", Provider: "openai", EnumValue: 340, ModelUID: "MODEL_PRIVATE_6", Credit: 0.5},
|
|
"gpt-5-medium": {Name: "gpt-5-medium", Provider: "openai", ModelUID: "MODEL_PRIVATE_7", Credit: 1},
|
|
"gpt-5-high": {Name: "gpt-5-high", Provider: "openai", ModelUID: "MODEL_PRIVATE_8", Credit: 2},
|
|
"gpt-5-mini": {Name: "gpt-5-mini", Provider: "openai", EnumValue: 337, Credit: 0.25},
|
|
"gpt-5-codex": {Name: "gpt-5-codex", Provider: "openai", EnumValue: 346, ModelUID: "MODEL_CHAT_GPT_5_CODEX", Credit: 0.5},
|
|
"gpt-5.2": {Name: "gpt-5.2", Provider: "openai", EnumValue: 401, ModelUID: "MODEL_GPT_5_2_MEDIUM", Credit: 2},
|
|
"gpt-5.2-low": {Name: "gpt-5.2-low", Provider: "openai", EnumValue: 400, ModelUID: "MODEL_GPT_5_2_LOW", Credit: 1},
|
|
"gpt-5.2-high": {Name: "gpt-5.2-high", Provider: "openai", EnumValue: 402, ModelUID: "MODEL_GPT_5_2_HIGH", Credit: 3},
|
|
"gpt-5.2-xhigh": {Name: "gpt-5.2-xhigh", Provider: "openai", EnumValue: 403, ModelUID: "MODEL_GPT_5_2_XHIGH", Credit: 8},
|
|
|
|
// O-series
|
|
"o3-mini": {Name: "o3-mini", Provider: "openai", EnumValue: 207, Credit: 0.5},
|
|
"o3": {Name: "o3", Provider: "openai", EnumValue: 218, ModelUID: "MODEL_CHAT_O3", Credit: 1},
|
|
"o3-high": {Name: "o3-high", Provider: "openai", ModelUID: "MODEL_CHAT_O3_HIGH", Credit: 1},
|
|
"o3-pro": {Name: "o3-pro", Provider: "openai", EnumValue: 294, Credit: 4},
|
|
"o4-mini": {Name: "o4-mini", Provider: "openai", EnumValue: 264, Credit: 0.5},
|
|
|
|
// Gemini
|
|
"gemini-2.5-pro": {Name: "gemini-2.5-pro", Provider: "google", EnumValue: 246, ModelUID: "MODEL_GOOGLE_GEMINI_2_5_PRO", Credit: 1},
|
|
"gemini-2.5-flash": {Name: "gemini-2.5-flash", Provider: "google", EnumValue: 312, ModelUID: "MODEL_GOOGLE_GEMINI_2_5_FLASH", Credit: 0.5},
|
|
"gemini-3.0-pro": {Name: "gemini-3.0-pro", Provider: "google", EnumValue: 412, ModelUID: "MODEL_GOOGLE_GEMINI_3_0_PRO_LOW", Credit: 1},
|
|
"gemini-3.0-flash": {Name: "gemini-3.0-flash", Provider: "google", EnumValue: 415, ModelUID: "MODEL_GOOGLE_GEMINI_3_0_FLASH_MEDIUM", Credit: 1},
|
|
|
|
// DeepSeek
|
|
"deepseek-v3": {Name: "deepseek-v3", Provider: "deepseek", EnumValue: 205, Credit: 0.5},
|
|
"deepseek-v3-2": {Name: "deepseek-v3-2", Provider: "deepseek", EnumValue: 409, Credit: 0.5},
|
|
"deepseek-r1": {Name: "deepseek-r1", Provider: "deepseek", EnumValue: 206, Credit: 1},
|
|
|
|
// Grok
|
|
"grok-3": {Name: "grok-3", Provider: "xai", EnumValue: 217, ModelUID: "MODEL_XAI_GROK_3", Credit: 1},
|
|
"grok-3-mini": {Name: "grok-3-mini", Provider: "xai", EnumValue: 234, Credit: 0.5},
|
|
|
|
// Qwen
|
|
"qwen-3": {Name: "qwen-3", Provider: "alibaba", EnumValue: 324, Credit: 0.5},
|
|
|
|
// Kimi
|
|
"kimi-k2": {Name: "kimi-k2", Provider: "moonshot", EnumValue: 323, ModelUID: "MODEL_KIMI_K2", Credit: 0.5},
|
|
|
|
// GLM
|
|
"glm-4.7": {Name: "glm-4.7", Provider: "zhipu", EnumValue: 417, ModelUID: "MODEL_GLM_4_7", Credit: 0.25},
|
|
|
|
// Windsurf SWE
|
|
"swe-1.5": {Name: "swe-1.5", Provider: "windsurf", EnumValue: 369, ModelUID: "MODEL_SWE_1_5_SLOW", Credit: 0.5},
|
|
"swe-1.5-fast": {Name: "swe-1.5-fast", Provider: "windsurf", EnumValue: 359, ModelUID: "MODEL_SWE_1_5", Credit: 0.5},
|
|
"swe-1.6": {Name: "swe-1.6", Provider: "windsurf", ModelUID: "swe-1-6", Credit: 0.5},
|
|
"swe-1.6-fast": {Name: "swe-1.6-fast", Provider: "windsurf", ModelUID: "swe-1-6-fast", Credit: 0.5},
|
|
|
|
// Claude Opus 4.7 variants (Windsurf string UIDs; Credit from GetCascadeModelConfigs 2026-04-24)
|
|
"claude-opus-4.7-low": {Name: "claude-opus-4.7-low", Provider: "anthropic", ModelUID: "claude-opus-4-7-low", Credit: 7},
|
|
"claude-opus-4.7-high": {Name: "claude-opus-4.7-high", Provider: "anthropic", ModelUID: "claude-opus-4-7-high", Credit: 14},
|
|
"claude-opus-4.7-xhigh": {Name: "claude-opus-4.7-xhigh", Provider: "anthropic", ModelUID: "claude-opus-4-7-xhigh", Credit: 16},
|
|
"claude-opus-4.7-max": {Name: "claude-opus-4.7-max", Provider: "anthropic", ModelUID: "claude-opus-4-7-max", Credit: 30},
|
|
|
|
// GPT-5.4 Mini variants
|
|
"gpt-5.4-mini-low": {Name: "gpt-5.4-mini-low", Provider: "openai", ModelUID: "gpt-5-4-mini-low", Credit: 1.5},
|
|
"gpt-5.4-mini-medium": {Name: "gpt-5.4-mini-medium", Provider: "openai", ModelUID: "gpt-5-4-mini-medium", Credit: 1.5},
|
|
"gpt-5.4-mini-high": {Name: "gpt-5.4-mini-high", Provider: "openai", ModelUID: "gpt-5-4-mini-high", Credit: 4.5},
|
|
"gpt-5.4-mini-xhigh": {Name: "gpt-5.4-mini-xhigh", Provider: "openai", ModelUID: "gpt-5-4-mini-xhigh", Credit: 12},
|
|
|
|
// Gemini 3.1 Pro variants
|
|
"gemini-3.1-pro-low": {Name: "gemini-3.1-pro-low", Provider: "google", ModelUID: "gemini-3-1-pro-low", Credit: 1},
|
|
"gemini-3.1-pro-high": {Name: "gemini-3.1-pro-high", Provider: "google", ModelUID: "gemini-3-1-pro-high", Credit: 2},
|
|
|
|
// Gemini 3.0 Flash variants
|
|
"gemini-3.0-flash-minimal": {Name: "gemini-3.0-flash-minimal", Provider: "google", ModelUID: "MODEL_GOOGLE_GEMINI_3_0_FLASH_MINIMAL", Credit: 0.75},
|
|
"gemini-3.0-flash-low": {Name: "gemini-3.0-flash-low", Provider: "google", ModelUID: "MODEL_GOOGLE_GEMINI_3_0_FLASH_LOW", Credit: 1},
|
|
"gemini-3.0-flash-high": {Name: "gemini-3.0-flash-high", Provider: "google", ModelUID: "MODEL_GOOGLE_GEMINI_3_0_FLASH_HIGH", Credit: 1.75},
|
|
|
|
// Kimi variants
|
|
"kimi-k2.5": {Name: "kimi-k2.5", Provider: "moonshot", ModelUID: "kimi-k2-5", Credit: 1},
|
|
"kimi-k2.6": {Name: "kimi-k2.6", Provider: "moonshot", ModelUID: "kimi-k2-6", Credit: 0},
|
|
|
|
// GLM
|
|
"glm-5": {Name: "glm-5", Provider: "zhipu", ModelUID: "glm-5", Credit: 1.5},
|
|
"glm-5.1": {Name: "glm-5.1", Provider: "zhipu", ModelUID: "glm-5-1", Credit: 1.5},
|
|
|
|
// Minimax
|
|
"minimax-m2.5": {Name: "minimax-m2.5", Provider: "minimax", ModelUID: "minimax-m2-5", Credit: 1},
|
|
|
|
// GPT-5.1 (MODEL_PRIVATE_12..15, _20..23)
|
|
"gpt-5.1": {Name: "gpt-5.1", Provider: "openai", ModelUID: "MODEL_PRIVATE_12", Credit: 0.5},
|
|
"gpt-5.1-low": {Name: "gpt-5.1-low", Provider: "openai", ModelUID: "MODEL_PRIVATE_13", Credit: 0.5},
|
|
"gpt-5.1-medium": {Name: "gpt-5.1-medium", Provider: "openai", ModelUID: "MODEL_PRIVATE_14", Credit: 1},
|
|
"gpt-5.1-high": {Name: "gpt-5.1-high", Provider: "openai", ModelUID: "MODEL_PRIVATE_15", Credit: 2},
|
|
"gpt-5.1-fast": {Name: "gpt-5.1-fast", Provider: "openai", ModelUID: "MODEL_PRIVATE_20", Credit: 1},
|
|
"gpt-5.1-low-fast": {Name: "gpt-5.1-low-fast", Provider: "openai", ModelUID: "MODEL_PRIVATE_21", Credit: 1},
|
|
"gpt-5.1-medium-fast": {Name: "gpt-5.1-medium-fast", Provider: "openai", ModelUID: "MODEL_PRIVATE_22", Credit: 2},
|
|
"gpt-5.1-high-fast": {Name: "gpt-5.1-high-fast", Provider: "openai", ModelUID: "MODEL_PRIVATE_23", Credit: 4},
|
|
|
|
// GPT-5.1 Codex variants
|
|
"gpt-5.1-codex-low": {Name: "gpt-5.1-codex-low", Provider: "openai", ModelUID: "MODEL_GPT_5_1_CODEX_LOW", Credit: 0.5},
|
|
"gpt-5.1-codex-medium": {Name: "gpt-5.1-codex-medium", Provider: "openai", ModelUID: "MODEL_PRIVATE_9", Credit: 1},
|
|
"gpt-5.1-codex-mini": {Name: "gpt-5.1-codex-mini", Provider: "openai", ModelUID: "MODEL_PRIVATE_19", Credit: 0.5},
|
|
"gpt-5.1-codex-mini-low": {Name: "gpt-5.1-codex-mini-low", Provider: "openai", ModelUID: "MODEL_GPT_5_1_CODEX_MINI_LOW", Credit: 0.25},
|
|
"gpt-5.1-codex-max-low": {Name: "gpt-5.1-codex-max-low", Provider: "openai", ModelUID: "MODEL_GPT_5_1_CODEX_MAX_LOW", Credit: 1},
|
|
"gpt-5.1-codex-max-medium": {Name: "gpt-5.1-codex-max-medium", Provider: "openai", ModelUID: "MODEL_GPT_5_1_CODEX_MAX_MEDIUM", Credit: 1.25},
|
|
"gpt-5.1-codex-max-high": {Name: "gpt-5.1-codex-max-high", Provider: "openai", ModelUID: "MODEL_GPT_5_1_CODEX_MAX_HIGH", Credit: 1.5},
|
|
|
|
// GPT-5.2 additional (existing: gpt-5.2, gpt-5.2-low, gpt-5.2-high, gpt-5.2-xhigh)
|
|
"gpt-5.2-none": {Name: "gpt-5.2-none", Provider: "openai", ModelUID: "MODEL_GPT_5_2_NONE", Credit: 1},
|
|
"gpt-5.2-none-fast": {Name: "gpt-5.2-none-fast", Provider: "openai", ModelUID: "MODEL_GPT_5_2_NONE_PRIORITY", Credit: 2},
|
|
"gpt-5.2-low-fast": {Name: "gpt-5.2-low-fast", Provider: "openai", ModelUID: "MODEL_GPT_5_2_LOW_PRIORITY", Credit: 2},
|
|
"gpt-5.2-medium-fast": {Name: "gpt-5.2-medium-fast", Provider: "openai", ModelUID: "MODEL_GPT_5_2_MEDIUM_PRIORITY", Credit: 4},
|
|
"gpt-5.2-high-fast": {Name: "gpt-5.2-high-fast", Provider: "openai", ModelUID: "MODEL_GPT_5_2_HIGH_PRIORITY", Credit: 6},
|
|
"gpt-5.2-xhigh-fast": {Name: "gpt-5.2-xhigh-fast", Provider: "openai", ModelUID: "MODEL_GPT_5_2_XHIGH_PRIORITY", Credit: 16},
|
|
|
|
// GPT-5.2 Codex variants
|
|
"gpt-5.2-codex-low": {Name: "gpt-5.2-codex-low", Provider: "openai", ModelUID: "MODEL_GPT_5_2_CODEX_LOW", Credit: 1},
|
|
"gpt-5.2-codex-medium": {Name: "gpt-5.2-codex-medium", Provider: "openai", ModelUID: "MODEL_GPT_5_2_CODEX_MEDIUM", Credit: 1},
|
|
"gpt-5.2-codex-high": {Name: "gpt-5.2-codex-high", Provider: "openai", ModelUID: "MODEL_GPT_5_2_CODEX_HIGH", Credit: 2},
|
|
"gpt-5.2-codex-xhigh": {Name: "gpt-5.2-codex-xhigh", Provider: "openai", ModelUID: "MODEL_GPT_5_2_CODEX_XHIGH", Credit: 3},
|
|
"gpt-5.2-codex-low-fast": {Name: "gpt-5.2-codex-low-fast", Provider: "openai", ModelUID: "MODEL_GPT_5_2_CODEX_LOW_PRIORITY", Credit: 2},
|
|
"gpt-5.2-codex-medium-fast": {Name: "gpt-5.2-codex-medium-fast", Provider: "openai", ModelUID: "MODEL_GPT_5_2_CODEX_MEDIUM_PRIORITY", Credit: 2},
|
|
"gpt-5.2-codex-high-fast": {Name: "gpt-5.2-codex-high-fast", Provider: "openai", ModelUID: "MODEL_GPT_5_2_CODEX_HIGH_PRIORITY", Credit: 4},
|
|
"gpt-5.2-codex-xhigh-fast": {Name: "gpt-5.2-codex-xhigh-fast", Provider: "openai", ModelUID: "MODEL_GPT_5_2_CODEX_XHIGH_PRIORITY", Credit: 6},
|
|
|
|
// GPT-OSS
|
|
"gpt-oss-120b": {Name: "gpt-oss-120b", Provider: "openai", ModelUID: "MODEL_GPT_OSS_120B", Credit: 0.25},
|
|
|
|
// Grok — runtime UID for mini reasoning (was missing, existing grok-3-mini used legacy enum only)
|
|
"grok-3-mini-reasoning": {Name: "grok-3-mini-reasoning", Provider: "xai", ModelUID: "MODEL_XAI_GROK_3_MINI_REASONING", Credit: 0.125},
|
|
"grok-code-fast-1": {Name: "grok-code-fast-1", Provider: "xai", ModelUID: "MODEL_PRIVATE_4", Credit: 0.5},
|
|
}
|
|
|
|
var (
|
|
lookupOnce sync.Once
|
|
lookupMap map[string]string
|
|
)
|
|
|
|
func buildLookup() {
|
|
lookupMap = make(map[string]string, len(catalog)*4)
|
|
for id, info := range catalog {
|
|
lookupMap[id] = id
|
|
lookupMap[strings.ToLower(id)] = id
|
|
if info.ModelUID != "" {
|
|
lookupMap[info.ModelUID] = id
|
|
lookupMap[strings.ToLower(info.ModelUID)] = id
|
|
}
|
|
}
|
|
|
|
aliases := map[string]string{
|
|
// Anthropic dated names
|
|
"claude-3-5-sonnet-20240620": "claude-3.5-sonnet",
|
|
"claude-3-5-sonnet-20241022": "claude-3.5-sonnet",
|
|
"claude-3-5-sonnet-latest": "claude-3.5-sonnet",
|
|
"claude-3-7-sonnet-20250219": "claude-3.7-sonnet",
|
|
"claude-3-7-sonnet-latest": "claude-3.7-sonnet",
|
|
"claude-sonnet-4-20250514": "claude-4-sonnet",
|
|
"claude-sonnet-4-0": "claude-4-sonnet",
|
|
"claude-opus-4-20250514": "claude-4-opus",
|
|
"claude-opus-4-0": "claude-4-opus",
|
|
"claude-opus-4-1": "claude-4.1-opus",
|
|
"claude-opus-4-1-20250805": "claude-4.1-opus",
|
|
"claude-sonnet-4-5": "claude-4.5-sonnet",
|
|
"claude-sonnet-4-5-20250929": "claude-4.5-sonnet",
|
|
"claude-haiku-4-5": "claude-4.5-haiku",
|
|
"claude-haiku-4-5-20251001": "claude-4.5-haiku",
|
|
"claude-opus-4-5": "claude-4.5-opus",
|
|
"claude-opus-4-5-20251101": "claude-4.5-opus",
|
|
"claude-opus-4-7": "claude-opus-4-7-medium",
|
|
"claude-opus-4-7-latest": "claude-opus-4-7-medium",
|
|
"claude-opus-4.7": "claude-opus-4-7-medium",
|
|
"claude-opus-4.7-thinking": "claude-opus-4-7-medium",
|
|
"claude-sonnet-4-6": "claude-sonnet-4.6",
|
|
"claude-opus-4-6": "claude-opus-4.6",
|
|
"claude-sonnet-4-6-thinking": "claude-sonnet-4.6-thinking",
|
|
"claude-opus-4-6-thinking": "claude-opus-4.6-thinking",
|
|
"MODEL_CLAUDE_4_5_SONNET": "claude-4.5-sonnet",
|
|
"MODEL_CLAUDE_4_5_SONNET_THINKING": "claude-4.5-sonnet-thinking",
|
|
|
|
// OpenAI dated names
|
|
"gpt-4o-2024-11-20": "gpt-4o",
|
|
"gpt-4o-2024-08-06": "gpt-4o",
|
|
"gpt-4o-2024-05-13": "gpt-4o",
|
|
"gpt-4o-mini-2024-07-18": "gpt-4o-mini",
|
|
"gpt-4.1-2025-04-14": "gpt-4.1",
|
|
"gpt-4.1-mini-2025-04-14": "gpt-4.1-mini",
|
|
"gpt-4.1-nano-2025-04-14": "gpt-4.1-nano",
|
|
"gpt-5-2025-08-07": "gpt-5",
|
|
|
|
// Cursor-friendly aliases
|
|
"opus-4.6": "claude-opus-4.6",
|
|
"opus-4.6-thinking": "claude-opus-4.6-thinking",
|
|
"opus-4-7": "claude-opus-4-7-medium",
|
|
"opus-4.7": "claude-opus-4-7-medium",
|
|
"opus-4.7-low": "claude-opus-4.7-low",
|
|
"opus-4.7-high": "claude-opus-4.7-high",
|
|
"opus-4.7-xhigh": "claude-opus-4.7-xhigh",
|
|
"opus-4.7-max": "claude-opus-4.7-max",
|
|
"sonnet-4.6": "claude-sonnet-4.6",
|
|
"sonnet-4.6-thinking": "claude-sonnet-4.6-thinking",
|
|
"sonnet-4.6-1m": "claude-sonnet-4.6-1m",
|
|
"sonnet-4.5": "claude-4.5-sonnet",
|
|
"sonnet-4.5-thinking": "claude-4.5-sonnet-thinking",
|
|
"haiku-4.5": "claude-4.5-haiku",
|
|
"sonnet-4": "claude-4-sonnet",
|
|
"opus-4": "claude-4-opus",
|
|
"opus-4.1": "claude-4.1-opus",
|
|
"sonnet-3.7": "claude-3.7-sonnet",
|
|
"sonnet-3.5": "claude-3.5-sonnet",
|
|
"ws-opus": "claude-opus-4.6",
|
|
"ws-sonnet": "claude-sonnet-4.6",
|
|
"ws-opus-thinking": "claude-opus-4.6-thinking",
|
|
"ws-sonnet-thinking": "claude-sonnet-4.6-thinking",
|
|
"ws-haiku": "claude-4.5-haiku",
|
|
}
|
|
for k, v := range aliases {
|
|
lookupMap[k] = v
|
|
lookupMap[strings.ToLower(k)] = v
|
|
}
|
|
}
|
|
|
|
func ensureLookup() {
|
|
lookupOnce.Do(buildLookup)
|
|
}
|
|
|
|
func ResolveModel(name string) string {
|
|
if name == "" {
|
|
return ""
|
|
}
|
|
ensureLookup()
|
|
if id, ok := lookupMap[name]; ok {
|
|
return id
|
|
}
|
|
if id, ok := lookupMap[strings.ToLower(name)]; ok {
|
|
return id
|
|
}
|
|
return name
|
|
}
|
|
|
|
func GetModelInfo(id string) *ModelMeta {
|
|
if m, ok := catalog[id]; ok {
|
|
return &m
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetChatMode(m *ModelMeta, legacyEnumCutoff int) string {
|
|
if m == nil {
|
|
return "cascade"
|
|
}
|
|
if m.ModelUID != "" {
|
|
return "cascade"
|
|
}
|
|
if m.EnumValue > 0 {
|
|
if legacyEnumCutoff > 0 && m.EnumValue <= legacyEnumCutoff {
|
|
return "legacy"
|
|
}
|
|
return "cascade"
|
|
}
|
|
return "cascade"
|
|
}
|
|
|
|
var freeTierModels = []string{"gpt-4o-mini", "gemini-2.5-flash"}
|
|
|
|
func GetTierModels(tier string) []string {
|
|
switch tier {
|
|
case "pro":
|
|
keys := make([]string, 0, len(catalog))
|
|
for k := range catalog {
|
|
keys = append(keys, k)
|
|
}
|
|
return keys
|
|
case "free", "unknown":
|
|
return freeTierModels
|
|
case "expired":
|
|
return nil
|
|
default:
|
|
return freeTierModels
|
|
}
|
|
}
|
|
|
|
func ListModelsOpenAI() []ModelListEntry {
|
|
ts := time.Now().Unix()
|
|
entries := make([]ModelListEntry, 0, len(catalog))
|
|
for _, info := range catalog {
|
|
entries = append(entries, ModelListEntry{
|
|
ID: info.Name,
|
|
Object: "model",
|
|
Created: ts,
|
|
OwnedBy: info.Provider,
|
|
})
|
|
}
|
|
return entries
|
|
}
|
|
|
|
var cloudModelsMu sync.Mutex
|
|
|
|
func MergeCloudModels(configs []ModelInfo) int {
|
|
cloudModelsMu.Lock()
|
|
defer cloudModelsMu.Unlock()
|
|
ensureLookup()
|
|
|
|
providerMap := map[string]string{
|
|
"MODEL_PROVIDER_ANTHROPIC": "anthropic",
|
|
"MODEL_PROVIDER_OPENAI": "openai",
|
|
"MODEL_PROVIDER_GOOGLE": "google",
|
|
"MODEL_PROVIDER_DEEPSEEK": "deepseek",
|
|
"MODEL_PROVIDER_XAI": "xai",
|
|
"MODEL_PROVIDER_WINDSURF": "windsurf",
|
|
"MODEL_PROVIDER_MOONSHOT": "moonshot",
|
|
}
|
|
|
|
added := 0
|
|
for _, m := range configs {
|
|
if m.ModelUID == "" {
|
|
continue
|
|
}
|
|
if _, ok := lookupMap[m.ModelUID]; ok {
|
|
continue
|
|
}
|
|
if _, ok := lookupMap[strings.ToLower(m.ModelUID)]; ok {
|
|
continue
|
|
}
|
|
|
|
key := strings.ToLower(strings.ReplaceAll(m.ModelUID, "_", "-"))
|
|
if _, exists := catalog[key]; exists {
|
|
continue
|
|
}
|
|
|
|
provider := providerMap[m.Label]
|
|
if provider == "" {
|
|
provider = "unknown"
|
|
}
|
|
|
|
credit := m.CreditMultiplier
|
|
if credit == 0 {
|
|
credit = 1
|
|
}
|
|
|
|
catalog[key] = ModelMeta{
|
|
Name: key,
|
|
Provider: provider,
|
|
ModelUID: m.ModelUID,
|
|
Credit: credit,
|
|
}
|
|
lookupMap[key] = key
|
|
lookupMap[m.ModelUID] = key
|
|
lookupMap[strings.ToLower(m.ModelUID)] = key
|
|
added++
|
|
}
|
|
return added
|
|
}
|
|
|
|
func MapTeamsTier(t int) string {
|
|
if t == 0 || t == 6 || t == 19 {
|
|
return "free"
|
|
}
|
|
if t > 0 {
|
|
return "pro"
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
func TeamsTierLabel(t int) string {
|
|
labels := map[int]string{
|
|
0: "Unspecified", 1: "Teams", 2: "Pro", 3: "Enterprise (SaaS)",
|
|
4: "Hybrid", 5: "Enterprise (Self-Hosted)", 6: "Waitlist Pro",
|
|
7: "Teams Ultimate", 8: "Pro Ultimate", 9: "Trial",
|
|
10: "Enterprise (Self-Serve)", 11: "Enterprise (SaaS Pooled)",
|
|
12: "Devin Enterprise", 14: "Devin Teams", 15: "Devin Teams V2",
|
|
16: "Devin Pro", 17: "Devin Max", 18: "Max",
|
|
19: "Devin Free", 20: "Devin Trial",
|
|
}
|
|
if l, ok := labels[t]; ok {
|
|
return l
|
|
}
|
|
return "unknown"
|
|
}
|