// Package registry provides model definitions and lookup helpers for various AI providers. // Static model metadata is loaded from the embedded models.json file and can be refreshed from network. package registry import ( "sort" "strings" ) // AntigravityModelConfig captures static antigravity model overrides, including // Thinking budget limits and provider max completion tokens. type AntigravityModelConfig struct { Thinking *ThinkingSupport `json:"thinking,omitempty"` MaxCompletionTokens int `json:"max_completion_tokens,omitempty"` } // staticModelsJSON mirrors the top-level structure of models.json. type staticModelsJSON struct { Claude []*ModelInfo `json:"claude"` Gemini []*ModelInfo `json:"gemini"` Vertex []*ModelInfo `json:"vertex"` GeminiCLI []*ModelInfo `json:"gemini-cli"` AIStudio []*ModelInfo `json:"aistudio"` CodexFree []*ModelInfo `json:"codex-free"` CodexTeam []*ModelInfo `json:"codex-team"` CodexPlus []*ModelInfo `json:"codex-plus"` CodexPro []*ModelInfo `json:"codex-pro"` Qwen []*ModelInfo `json:"qwen"` IFlow []*ModelInfo `json:"iflow"` Kimi []*ModelInfo `json:"kimi"` Antigravity map[string]*AntigravityModelConfig `json:"antigravity"` } // GetClaudeModels returns the standard Claude model definitions. func GetClaudeModels() []*ModelInfo { return cloneModelInfos(getModels().Claude) } // GetGeminiModels returns the standard Gemini model definitions. func GetGeminiModels() []*ModelInfo { return cloneModelInfos(getModels().Gemini) } // GetGeminiVertexModels returns Gemini model definitions for Vertex AI. func GetGeminiVertexModels() []*ModelInfo { return cloneModelInfos(getModels().Vertex) } // GetGeminiCLIModels returns Gemini model definitions for the Gemini CLI. func GetGeminiCLIModels() []*ModelInfo { return cloneModelInfos(getModels().GeminiCLI) } // GetAIStudioModels returns model definitions for AI Studio. func GetAIStudioModels() []*ModelInfo { return cloneModelInfos(getModels().AIStudio) } // GetCodexFreeModels returns model definitions for the Codex free plan tier. func GetCodexFreeModels() []*ModelInfo { return cloneModelInfos(getModels().CodexFree) } // GetCodexTeamModels returns model definitions for the Codex team plan tier. func GetCodexTeamModels() []*ModelInfo { return cloneModelInfos(getModels().CodexTeam) } // GetCodexPlusModels returns model definitions for the Codex plus plan tier. func GetCodexPlusModels() []*ModelInfo { return cloneModelInfos(getModels().CodexPlus) } // GetCodexProModels returns model definitions for the Codex pro plan tier. func GetCodexProModels() []*ModelInfo { return cloneModelInfos(getModels().CodexPro) } // GetQwenModels returns the standard Qwen model definitions. func GetQwenModels() []*ModelInfo { return cloneModelInfos(getModels().Qwen) } // GetIFlowModels returns the standard iFlow model definitions. func GetIFlowModels() []*ModelInfo { return cloneModelInfos(getModels().IFlow) } // GetKimiModels returns the standard Kimi (Moonshot AI) model definitions. func GetKimiModels() []*ModelInfo { return cloneModelInfos(getModels().Kimi) } // GetAntigravityModelConfig returns static configuration for antigravity models. // Keys use upstream model names returned by the Antigravity models endpoint. func GetAntigravityModelConfig() map[string]*AntigravityModelConfig { data := getModels() if len(data.Antigravity) == 0 { return nil } out := make(map[string]*AntigravityModelConfig, len(data.Antigravity)) for k, v := range data.Antigravity { out[k] = cloneAntigravityModelConfig(v) } return out } func cloneAntigravityModelConfig(cfg *AntigravityModelConfig) *AntigravityModelConfig { if cfg == nil { return nil } copyConfig := *cfg if cfg.Thinking != nil { copyThinking := *cfg.Thinking if len(cfg.Thinking.Levels) > 0 { copyThinking.Levels = append([]string(nil), cfg.Thinking.Levels...) } copyConfig.Thinking = ©Thinking } return ©Config } // cloneModelInfos returns a shallow copy of the slice with each element deep-cloned. func cloneModelInfos(models []*ModelInfo) []*ModelInfo { if len(models) == 0 { return nil } out := make([]*ModelInfo, len(models)) for i, m := range models { out[i] = cloneModelInfo(m) } return out } // GetStaticModelDefinitionsByChannel returns static model definitions for a given channel/provider. // It returns nil when the channel is unknown. // // Supported channels: // - claude // - gemini // - vertex // - gemini-cli // - aistudio // - codex // - qwen // - iflow // - kimi // - antigravity (returns static overrides only) func GetStaticModelDefinitionsByChannel(channel string) []*ModelInfo { key := strings.ToLower(strings.TrimSpace(channel)) switch key { case "claude": return GetClaudeModels() case "gemini": return GetGeminiModels() case "vertex": return GetGeminiVertexModels() case "gemini-cli": return GetGeminiCLIModels() case "aistudio": return GetAIStudioModels() case "codex": return GetCodexProModels() case "qwen": return GetQwenModels() case "iflow": return GetIFlowModels() case "kimi": return GetKimiModels() case "antigravity": cfg := GetAntigravityModelConfig() if len(cfg) == 0 { return nil } models := make([]*ModelInfo, 0, len(cfg)) for modelID, entry := range cfg { if modelID == "" || entry == nil { continue } models = append(models, &ModelInfo{ ID: modelID, Object: "model", OwnedBy: "antigravity", Type: "antigravity", Thinking: entry.Thinking, MaxCompletionTokens: entry.MaxCompletionTokens, }) } sort.Slice(models, func(i, j int) bool { return strings.ToLower(models[i].ID) < strings.ToLower(models[j].ID) }) return models default: return nil } } // LookupStaticModelInfo searches all static model definitions for a model by ID. // Returns nil if no matching model is found. func LookupStaticModelInfo(modelID string) *ModelInfo { if modelID == "" { return nil } data := getModels() allModels := [][]*ModelInfo{ data.Claude, data.Gemini, data.Vertex, data.GeminiCLI, data.AIStudio, data.CodexPro, data.Qwen, data.IFlow, data.Kimi, } for _, models := range allModels { for _, m := range models { if m != nil && m.ID == modelID { return cloneModelInfo(m) } } } // Check Antigravity static config if cfg := cloneAntigravityModelConfig(data.Antigravity[modelID]); cfg != nil { return &ModelInfo{ ID: modelID, Thinking: cfg.Thinking, MaxCompletionTokens: cfg.MaxCompletionTokens, } } return nil }