|
| 1 | +package config |
| 2 | + |
| 3 | +import "strings" |
| 4 | + |
| 5 | +// VertexCompatKey represents the configuration for Vertex AI-compatible API keys. |
| 6 | +// This supports third-party services that use Vertex AI-style endpoint paths |
| 7 | +// (/publishers/google/models/{model}:streamGenerateContent) but authenticate |
| 8 | +// with simple API keys instead of Google Cloud service account credentials. |
| 9 | +// |
| 10 | +// Example services: zenmux.ai and similar Vertex-compatible providers. |
| 11 | +type VertexCompatKey struct { |
| 12 | + // APIKey is the authentication key for accessing the Vertex-compatible API. |
| 13 | + // Maps to the x-goog-api-key header. |
| 14 | + APIKey string `yaml:"api-key" json:"api-key"` |
| 15 | + |
| 16 | + // BaseURL is the base URL for the Vertex-compatible API endpoint. |
| 17 | + // The executor will append "/v1/publishers/google/models/{model}:action" to this. |
| 18 | + // Example: "https://zenmux.ai/api" becomes "https://zenmux.ai/api/v1/publishers/google/models/..." |
| 19 | + BaseURL string `yaml:"base-url,omitempty" json:"base-url,omitempty"` |
| 20 | + |
| 21 | + // ProxyURL optionally overrides the global proxy for this API key. |
| 22 | + ProxyURL string `yaml:"proxy-url,omitempty" json:"proxy-url,omitempty"` |
| 23 | + |
| 24 | + // Headers optionally adds extra HTTP headers for requests sent with this key. |
| 25 | + // Commonly used for cookies, user-agent, and other authentication headers. |
| 26 | + Headers map[string]string `yaml:"headers,omitempty" json:"headers,omitempty"` |
| 27 | + |
| 28 | + // Models defines the model configurations including aliases for routing. |
| 29 | + Models []VertexCompatModel `yaml:"models,omitempty" json:"models,omitempty"` |
| 30 | +} |
| 31 | + |
| 32 | +// VertexCompatModel represents a model configuration for Vertex compatibility, |
| 33 | +// including the actual model name and its alias for API routing. |
| 34 | +type VertexCompatModel struct { |
| 35 | + // Name is the actual model name used by the external provider. |
| 36 | + Name string `yaml:"name" json:"name"` |
| 37 | + |
| 38 | + // Alias is the model name alias that clients will use to reference this model. |
| 39 | + Alias string `yaml:"alias" json:"alias"` |
| 40 | +} |
| 41 | + |
| 42 | +// SanitizeVertexCompatKeys deduplicates and normalizes Vertex-compatible API key credentials. |
| 43 | +func (cfg *Config) SanitizeVertexCompatKeys() { |
| 44 | + if cfg == nil { |
| 45 | + return |
| 46 | + } |
| 47 | + |
| 48 | + seen := make(map[string]struct{}, len(cfg.VertexCompatAPIKey)) |
| 49 | + out := cfg.VertexCompatAPIKey[:0] |
| 50 | + for i := range cfg.VertexCompatAPIKey { |
| 51 | + entry := cfg.VertexCompatAPIKey[i] |
| 52 | + entry.APIKey = strings.TrimSpace(entry.APIKey) |
| 53 | + if entry.APIKey == "" { |
| 54 | + continue |
| 55 | + } |
| 56 | + entry.BaseURL = strings.TrimSpace(entry.BaseURL) |
| 57 | + if entry.BaseURL == "" { |
| 58 | + // BaseURL is required for vertex-compat keys |
| 59 | + continue |
| 60 | + } |
| 61 | + entry.ProxyURL = strings.TrimSpace(entry.ProxyURL) |
| 62 | + entry.Headers = NormalizeHeaders(entry.Headers) |
| 63 | + |
| 64 | + // Sanitize models: remove entries without valid alias |
| 65 | + sanitizedModels := make([]VertexCompatModel, 0, len(entry.Models)) |
| 66 | + for _, model := range entry.Models { |
| 67 | + model.Alias = strings.TrimSpace(model.Alias) |
| 68 | + model.Name = strings.TrimSpace(model.Name) |
| 69 | + if model.Alias != "" && model.Name != "" { |
| 70 | + sanitizedModels = append(sanitizedModels, model) |
| 71 | + } |
| 72 | + } |
| 73 | + entry.Models = sanitizedModels |
| 74 | + |
| 75 | + // Use API key + base URL as uniqueness key |
| 76 | + uniqueKey := entry.APIKey + "|" + entry.BaseURL |
| 77 | + if _, exists := seen[uniqueKey]; exists { |
| 78 | + continue |
| 79 | + } |
| 80 | + seen[uniqueKey] = struct{}{} |
| 81 | + out = append(out, entry) |
| 82 | + } |
| 83 | + cfg.VertexCompatAPIKey = out |
| 84 | +} |
0 commit comments