mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 04:50:52 +08:00
**refactor(cliproxy, config): remove vertex-compat flow, streamline Vertex API key handling**
- Removed `vertex-compat` executor and related configuration. - Consolidated Vertex compatibility checks into `vertex` handling with `apikey`-based model resolution. - Streamlined model generation logic for Vertex API key entries.
This commit is contained in:
@@ -145,6 +145,19 @@ ws-auth: false
|
|||||||
# - name: "moonshotai/kimi-k2:free" # The actual model name.
|
# - name: "moonshotai/kimi-k2:free" # The actual model name.
|
||||||
# alias: "kimi-k2" # The alias used in the API.
|
# alias: "kimi-k2" # The alias used in the API.
|
||||||
|
|
||||||
|
# Vertex API keys (Vertex-compatible endpoints, use API key + base URL)
|
||||||
|
#vertex-api-key:
|
||||||
|
# - api-key: "vk-123..." # x-goog-api-key header
|
||||||
|
# base-url: "https://example.com/api" # e.g. https://zenmux.ai/api
|
||||||
|
# proxy-url: "socks5://proxy.example.com:1080" # optional per-key proxy override
|
||||||
|
# headers:
|
||||||
|
# X-Custom-Header: "custom-value"
|
||||||
|
# models: # optional: map aliases to upstream model names
|
||||||
|
# - name: "gemini-2.0-flash" # upstream model name
|
||||||
|
# alias: "vertex-flash" # client-visible alias
|
||||||
|
# - name: "gemini-1.5-pro"
|
||||||
|
# alias: "vertex-pro"
|
||||||
|
|
||||||
#payload: # Optional payload configuration
|
#payload: # Optional payload configuration
|
||||||
# default: # Default rules only set parameters when they are missing in the payload.
|
# default: # Default rules only set parameters when they are missing in the payload.
|
||||||
# - models:
|
# - models:
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func (cfg *Config) SanitizeVertexCompatKeys() {
|
|||||||
}
|
}
|
||||||
entry.BaseURL = strings.TrimSpace(entry.BaseURL)
|
entry.BaseURL = strings.TrimSpace(entry.BaseURL)
|
||||||
if entry.BaseURL == "" {
|
if entry.BaseURL == "" {
|
||||||
// BaseURL is required for vertex-compat keys
|
// BaseURL is required for Vertex API key entries
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
entry.ProxyURL = strings.TrimSpace(entry.ProxyURL)
|
entry.ProxyURL = strings.TrimSpace(entry.ProxyURL)
|
||||||
|
|||||||
@@ -44,22 +44,6 @@ func NewGeminiVertexExecutor(cfg *config.Config) *GeminiVertexExecutor {
|
|||||||
// Identifier returns provider key for manager routing.
|
// Identifier returns provider key for manager routing.
|
||||||
func (e *GeminiVertexExecutor) Identifier() string { return "vertex" }
|
func (e *GeminiVertexExecutor) Identifier() string { return "vertex" }
|
||||||
|
|
||||||
// GeminiVertexCompatExecutor is a thin wrapper around GeminiVertexExecutor
|
|
||||||
// that provides the correct identifier for vertex-compat routing.
|
|
||||||
type GeminiVertexCompatExecutor struct {
|
|
||||||
*GeminiVertexExecutor
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGeminiVertexCompatExecutor constructs the Vertex-compatible executor.
|
|
||||||
func NewGeminiVertexCompatExecutor(cfg *config.Config) *GeminiVertexCompatExecutor {
|
|
||||||
return &GeminiVertexCompatExecutor{
|
|
||||||
GeminiVertexExecutor: NewGeminiVertexExecutor(cfg),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Identifier returns provider key for manager routing.
|
|
||||||
func (e *GeminiVertexCompatExecutor) Identifier() string { return "vertex-compat" }
|
|
||||||
|
|
||||||
// PrepareRequest is a no-op for Vertex.
|
// PrepareRequest is a no-op for Vertex.
|
||||||
func (e *GeminiVertexExecutor) PrepareRequest(_ *http.Request, _ *cliproxyauth.Auth) error {
|
func (e *GeminiVertexExecutor) PrepareRequest(_ *http.Request, _ *cliproxyauth.Auth) error {
|
||||||
return nil
|
return nil
|
||||||
@@ -393,7 +377,6 @@ func (e *GeminiVertexExecutor) executeWithServiceAccount(ctx context.Context, au
|
|||||||
}
|
}
|
||||||
|
|
||||||
// executeWithAPIKey handles authentication using API key credentials.
|
// executeWithAPIKey handles authentication using API key credentials.
|
||||||
// This method follows the vertex-compat pattern for API key authentication.
|
|
||||||
func (e *GeminiVertexExecutor) executeWithAPIKey(ctx context.Context, auth *cliproxyauth.Auth, req cliproxyexecutor.Request, opts cliproxyexecutor.Options, apiKey, baseURL string) (resp cliproxyexecutor.Response, err error) {
|
func (e *GeminiVertexExecutor) executeWithAPIKey(ctx context.Context, auth *cliproxyauth.Auth, req cliproxyexecutor.Request, opts cliproxyexecutor.Options, apiKey, baseURL string) (resp cliproxyexecutor.Response, err error) {
|
||||||
reporter := newUsageReporter(ctx, e.Identifier(), req.Model, auth)
|
reporter := newUsageReporter(ctx, e.Identifier(), req.Model, auth)
|
||||||
defer reporter.trackFailure(ctx, &err)
|
defer reporter.trackFailure(ctx, &err)
|
||||||
|
|||||||
@@ -986,7 +986,7 @@ func (w *Watcher) reloadClients(rescanAuth bool, affectedOAuthProviders []string
|
|||||||
|
|
||||||
w.refreshAuthState()
|
w.refreshAuthState()
|
||||||
|
|
||||||
log.Infof("full client load complete - %d clients (%d auth files + %d Gemini API keys + %d Vertex-compat keys + %d Claude API keys + %d Codex keys + %d OpenAI-compat)",
|
log.Infof("full client load complete - %d clients (%d auth files + %d Gemini API keys + %d Vertex API keys + %d Claude API keys + %d Codex keys + %d OpenAI-compat)",
|
||||||
totalNewClients,
|
totalNewClients,
|
||||||
authFileCount,
|
authFileCount,
|
||||||
geminiAPIKeyCount,
|
geminiAPIKeyCount,
|
||||||
@@ -1273,18 +1273,18 @@ func (w *Watcher) SnapshotCoreAuths() []*coreauth.Auth {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process Vertex compatibility providers
|
// Process Vertex API key providers (Vertex-compatible endpoints)
|
||||||
for i := range cfg.VertexCompatAPIKey {
|
for i := range cfg.VertexCompatAPIKey {
|
||||||
compat := &cfg.VertexCompatAPIKey[i]
|
compat := &cfg.VertexCompatAPIKey[i]
|
||||||
providerName := "vertex-compat"
|
providerName := "vertex"
|
||||||
base := strings.TrimSpace(compat.BaseURL)
|
base := strings.TrimSpace(compat.BaseURL)
|
||||||
|
|
||||||
key := strings.TrimSpace(compat.APIKey)
|
key := strings.TrimSpace(compat.APIKey)
|
||||||
proxyURL := strings.TrimSpace(compat.ProxyURL)
|
proxyURL := strings.TrimSpace(compat.ProxyURL)
|
||||||
idKind := fmt.Sprintf("vertex-compatibility:%s", base)
|
idKind := fmt.Sprintf("vertex:apikey:%s", base)
|
||||||
id, token := idGen.next(idKind, key, base, proxyURL)
|
id, token := idGen.next(idKind, key, base, proxyURL)
|
||||||
attrs := map[string]string{
|
attrs := map[string]string{
|
||||||
"source": fmt.Sprintf("config:vertex-compatibility[%s]", token),
|
"source": fmt.Sprintf("config:vertex-apikey[%s]", token),
|
||||||
"base_url": base,
|
"base_url": base,
|
||||||
"provider_key": providerName,
|
"provider_key": providerName,
|
||||||
}
|
}
|
||||||
@@ -1298,13 +1298,14 @@ func (w *Watcher) SnapshotCoreAuths() []*coreauth.Auth {
|
|||||||
a := &coreauth.Auth{
|
a := &coreauth.Auth{
|
||||||
ID: id,
|
ID: id,
|
||||||
Provider: providerName,
|
Provider: providerName,
|
||||||
Label: "Vertex Compatibility",
|
Label: "vertex-apikey",
|
||||||
Status: coreauth.StatusActive,
|
Status: coreauth.StatusActive,
|
||||||
ProxyURL: proxyURL,
|
ProxyURL: proxyURL,
|
||||||
Attributes: attrs,
|
Attributes: attrs,
|
||||||
CreatedAt: now,
|
CreatedAt: now,
|
||||||
UpdatedAt: now,
|
UpdatedAt: now,
|
||||||
}
|
}
|
||||||
|
applyAuthExcludedModelsMeta(a, cfg, nil, "apikey")
|
||||||
out = append(out, a)
|
out = append(out, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -362,8 +362,6 @@ func (s *Service) ensureExecutorsForAuth(a *coreauth.Auth) {
|
|||||||
s.coreManager.RegisterExecutor(executor.NewGeminiExecutor(s.cfg))
|
s.coreManager.RegisterExecutor(executor.NewGeminiExecutor(s.cfg))
|
||||||
case "vertex":
|
case "vertex":
|
||||||
s.coreManager.RegisterExecutor(executor.NewGeminiVertexExecutor(s.cfg))
|
s.coreManager.RegisterExecutor(executor.NewGeminiVertexExecutor(s.cfg))
|
||||||
case "vertex-compat":
|
|
||||||
s.coreManager.RegisterExecutor(executor.NewGeminiVertexCompatExecutor(s.cfg))
|
|
||||||
case "gemini-cli":
|
case "gemini-cli":
|
||||||
s.coreManager.RegisterExecutor(executor.NewGeminiCLIExecutor(s.cfg))
|
s.coreManager.RegisterExecutor(executor.NewGeminiCLIExecutor(s.cfg))
|
||||||
case "aistudio":
|
case "aistudio":
|
||||||
@@ -681,36 +679,12 @@ func (s *Service) registerModelsForAuth(a *coreauth.Auth) {
|
|||||||
case "vertex":
|
case "vertex":
|
||||||
// Vertex AI Gemini supports the same model identifiers as Gemini.
|
// Vertex AI Gemini supports the same model identifiers as Gemini.
|
||||||
models = registry.GetGeminiVertexModels()
|
models = registry.GetGeminiVertexModels()
|
||||||
models = applyExcludedModels(models, excluded)
|
if authKind == "apikey" {
|
||||||
case "vertex-compat":
|
if entry := s.resolveConfigVertexCompatKey(a); entry != nil && len(entry.Models) > 0 {
|
||||||
// Handle Vertex AI compatibility providers with custom model definitions
|
models = buildVertexCompatConfigModels(entry)
|
||||||
if s.cfg != nil && len(s.cfg.VertexCompatAPIKey) > 0 {
|
|
||||||
// Create models for all Vertex compatibility providers
|
|
||||||
allModels := make([]*ModelInfo, 0)
|
|
||||||
for i := range s.cfg.VertexCompatAPIKey {
|
|
||||||
compat := &s.cfg.VertexCompatAPIKey[i]
|
|
||||||
for j := range compat.Models {
|
|
||||||
m := compat.Models[j]
|
|
||||||
// Use alias as model ID, fallback to name if alias is empty
|
|
||||||
modelID := m.Alias
|
|
||||||
if modelID == "" {
|
|
||||||
modelID = m.Name
|
|
||||||
}
|
|
||||||
if modelID != "" {
|
|
||||||
allModels = append(allModels, &ModelInfo{
|
|
||||||
ID: modelID,
|
|
||||||
Object: "model",
|
|
||||||
Created: time.Now().Unix(),
|
|
||||||
OwnedBy: "vertex-compat",
|
|
||||||
Type: "vertex-compat",
|
|
||||||
DisplayName: m.Name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
models = allModels
|
|
||||||
}
|
}
|
||||||
|
models = applyExcludedModels(models, excluded)
|
||||||
case "gemini-cli":
|
case "gemini-cli":
|
||||||
models = registry.GetGeminiCLIModels()
|
models = registry.GetGeminiCLIModels()
|
||||||
models = applyExcludedModels(models, excluded)
|
models = applyExcludedModels(models, excluded)
|
||||||
@@ -905,6 +879,40 @@ func (s *Service) resolveConfigGeminiKey(auth *coreauth.Auth) *config.GeminiKey
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) resolveConfigVertexCompatKey(auth *coreauth.Auth) *config.VertexCompatKey {
|
||||||
|
if auth == nil || s.cfg == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var attrKey, attrBase string
|
||||||
|
if auth.Attributes != nil {
|
||||||
|
attrKey = strings.TrimSpace(auth.Attributes["api_key"])
|
||||||
|
attrBase = strings.TrimSpace(auth.Attributes["base_url"])
|
||||||
|
}
|
||||||
|
for i := range s.cfg.VertexCompatAPIKey {
|
||||||
|
entry := &s.cfg.VertexCompatAPIKey[i]
|
||||||
|
cfgKey := strings.TrimSpace(entry.APIKey)
|
||||||
|
cfgBase := strings.TrimSpace(entry.BaseURL)
|
||||||
|
if attrKey != "" && strings.EqualFold(cfgKey, attrKey) {
|
||||||
|
if cfgBase == "" || strings.EqualFold(cfgBase, attrBase) {
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if attrKey == "" && attrBase != "" && strings.EqualFold(cfgBase, attrBase) {
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if attrKey != "" {
|
||||||
|
for i := range s.cfg.VertexCompatAPIKey {
|
||||||
|
entry := &s.cfg.VertexCompatAPIKey[i]
|
||||||
|
if strings.EqualFold(strings.TrimSpace(entry.APIKey), attrKey) {
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) resolveConfigCodexKey(auth *coreauth.Auth) *config.CodexKey {
|
func (s *Service) resolveConfigCodexKey(auth *coreauth.Auth) *config.CodexKey {
|
||||||
if auth == nil || s.cfg == nil {
|
if auth == nil || s.cfg == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -1023,6 +1031,44 @@ func matchWildcard(pattern, value string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildVertexCompatConfigModels(entry *config.VertexCompatKey) []*ModelInfo {
|
||||||
|
if entry == nil || len(entry.Models) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
now := time.Now().Unix()
|
||||||
|
out := make([]*ModelInfo, 0, len(entry.Models))
|
||||||
|
seen := make(map[string]struct{}, len(entry.Models))
|
||||||
|
for i := range entry.Models {
|
||||||
|
model := entry.Models[i]
|
||||||
|
name := strings.TrimSpace(model.Name)
|
||||||
|
alias := strings.TrimSpace(model.Alias)
|
||||||
|
if alias == "" {
|
||||||
|
alias = name
|
||||||
|
}
|
||||||
|
if alias == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
key := strings.ToLower(alias)
|
||||||
|
if _, exists := seen[key]; exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[key] = struct{}{}
|
||||||
|
display := name
|
||||||
|
if display == "" {
|
||||||
|
display = alias
|
||||||
|
}
|
||||||
|
out = append(out, &ModelInfo{
|
||||||
|
ID: alias,
|
||||||
|
Object: "model",
|
||||||
|
Created: now,
|
||||||
|
OwnedBy: "vertex",
|
||||||
|
Type: "vertex",
|
||||||
|
DisplayName: display,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
func buildClaudeConfigModels(entry *config.ClaudeKey) []*ModelInfo {
|
func buildClaudeConfigModels(entry *config.ClaudeKey) []*ModelInfo {
|
||||||
if entry == nil || len(entry.Models) == 0 {
|
if entry == nil || len(entry.Models) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in New Issue
Block a user