diff --git a/config.example.yaml b/config.example.yaml index 7a3265b4..40bb8721 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -201,6 +201,9 @@ nonstream-keepalive-interval: 0 # alias: "vertex-flash" # client-visible alias # - name: "gemini-2.5-pro" # alias: "vertex-pro" +# excluded-models: # optional: models to exclude from listing +# - "imagen-3.0-generate-002" +# - "imagen-*" # Amp Integration # ampcode: diff --git a/internal/api/handlers/management/config_lists.go b/internal/api/handlers/management/config_lists.go index 66e89992..503179c1 100644 --- a/internal/api/handlers/management/config_lists.go +++ b/internal/api/handlers/management/config_lists.go @@ -516,12 +516,13 @@ func (h *Handler) PutVertexCompatKeys(c *gin.Context) { } func (h *Handler) PatchVertexCompatKey(c *gin.Context) { type vertexCompatPatch struct { - APIKey *string `json:"api-key"` - Prefix *string `json:"prefix"` - BaseURL *string `json:"base-url"` - ProxyURL *string `json:"proxy-url"` - Headers *map[string]string `json:"headers"` - Models *[]config.VertexCompatModel `json:"models"` + APIKey *string `json:"api-key"` + Prefix *string `json:"prefix"` + BaseURL *string `json:"base-url"` + ProxyURL *string `json:"proxy-url"` + Headers *map[string]string `json:"headers"` + Models *[]config.VertexCompatModel `json:"models"` + ExcludedModels *[]string `json:"excluded-models"` } var body struct { Index *int `json:"index"` @@ -585,6 +586,9 @@ func (h *Handler) PatchVertexCompatKey(c *gin.Context) { if body.Value.Models != nil { entry.Models = append([]config.VertexCompatModel(nil), (*body.Value.Models)...) } + if body.Value.ExcludedModels != nil { + entry.ExcludedModels = config.NormalizeExcludedModels(*body.Value.ExcludedModels) + } normalizeVertexCompatKey(&entry) h.cfg.VertexCompatAPIKey[targetIndex] = entry h.cfg.SanitizeVertexCompatKeys() @@ -1025,6 +1029,7 @@ func normalizeVertexCompatKey(entry *config.VertexCompatKey) { entry.BaseURL = strings.TrimSpace(entry.BaseURL) entry.ProxyURL = strings.TrimSpace(entry.ProxyURL) entry.Headers = config.NormalizeHeaders(entry.Headers) + entry.ExcludedModels = config.NormalizeExcludedModels(entry.ExcludedModels) if len(entry.Models) == 0 { return } diff --git a/internal/config/vertex_compat.go b/internal/config/vertex_compat.go index 786c5318..5f6c7c88 100644 --- a/internal/config/vertex_compat.go +++ b/internal/config/vertex_compat.go @@ -34,6 +34,9 @@ type VertexCompatKey struct { // Models defines the model configurations including aliases for routing. Models []VertexCompatModel `yaml:"models,omitempty" json:"models,omitempty"` + + // ExcludedModels lists model IDs that should be excluded for this provider. + ExcludedModels []string `yaml:"excluded-models,omitempty" json:"excluded-models,omitempty"` } func (k VertexCompatKey) GetAPIKey() string { return k.APIKey } @@ -74,6 +77,7 @@ func (cfg *Config) SanitizeVertexCompatKeys() { } entry.ProxyURL = strings.TrimSpace(entry.ProxyURL) entry.Headers = NormalizeHeaders(entry.Headers) + entry.ExcludedModels = NormalizeExcludedModels(entry.ExcludedModels) // Sanitize models: remove entries without valid alias sanitizedModels := make([]VertexCompatModel, 0, len(entry.Models)) diff --git a/internal/watcher/diff/config_diff.go b/internal/watcher/diff/config_diff.go index b7d537da..7997f04e 100644 --- a/internal/watcher/diff/config_diff.go +++ b/internal/watcher/diff/config_diff.go @@ -304,6 +304,11 @@ func BuildConfigChangeDetails(oldCfg, newCfg *config.Config) []string { if oldModels.hash != newModels.hash { changes = append(changes, fmt.Sprintf("vertex[%d].models: updated (%d -> %d entries)", i, oldModels.count, newModels.count)) } + oldExcluded := SummarizeExcludedModels(o.ExcludedModels) + newExcluded := SummarizeExcludedModels(n.ExcludedModels) + if oldExcluded.hash != newExcluded.hash { + changes = append(changes, fmt.Sprintf("vertex[%d].excluded-models: updated (%d -> %d entries)", i, oldExcluded.count, newExcluded.count)) + } if !equalStringMap(o.Headers, n.Headers) { changes = append(changes, fmt.Sprintf("vertex[%d].headers: updated", i)) } diff --git a/internal/watcher/synthesizer/config.go b/internal/watcher/synthesizer/config.go index 69194efc..52ae9a48 100644 --- a/internal/watcher/synthesizer/config.go +++ b/internal/watcher/synthesizer/config.go @@ -315,7 +315,7 @@ func (s *ConfigSynthesizer) synthesizeVertexCompat(ctx *SynthesisContext) []*cor CreatedAt: now, UpdatedAt: now, } - ApplyAuthExcludedModelsMeta(a, cfg, nil, "apikey") + ApplyAuthExcludedModelsMeta(a, cfg, compat.ExcludedModels, "apikey") out = append(out, a) } return out diff --git a/sdk/cliproxy/service.go b/sdk/cliproxy/service.go index 9952e7b2..6124f8b1 100644 --- a/sdk/cliproxy/service.go +++ b/sdk/cliproxy/service.go @@ -791,10 +791,13 @@ func (s *Service) registerModelsForAuth(a *coreauth.Auth) { case "vertex": // Vertex AI Gemini supports the same model identifiers as Gemini. models = registry.GetGeminiVertexModels() - if authKind == "apikey" { - if entry := s.resolveConfigVertexCompatKey(a); entry != nil && len(entry.Models) > 0 { + if entry := s.resolveConfigVertexCompatKey(a); entry != nil { + if len(entry.Models) > 0 { models = buildVertexCompatConfigModels(entry) } + if authKind == "apikey" { + excluded = entry.ExcludedModels + } } models = applyExcludedModels(models, excluded) case "gemini-cli":