@@ -11,6 +11,7 @@ import (
1111 "time"
1212
1313 "github.com/gin-gonic/gin"
14+ "github.com/router-for-me/CLIProxyAPI/v6/internal/config"
1415 "github.com/router-for-me/CLIProxyAPI/v6/internal/runtime/geminicli"
1516 coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
1617 "github.com/router-for-me/CLIProxyAPI/v6/sdk/proxyutil"
@@ -636,6 +637,11 @@ func (h *Handler) apiCallTransport(auth *coreauth.Auth) http.RoundTripper {
636637 if proxyStr := strings .TrimSpace (auth .ProxyURL ); proxyStr != "" {
637638 proxyCandidates = append (proxyCandidates , proxyStr )
638639 }
640+ if h != nil && h .cfg != nil {
641+ if proxyStr := strings .TrimSpace (proxyURLFromAPIKeyConfig (h .cfg , auth )); proxyStr != "" {
642+ proxyCandidates = append (proxyCandidates , proxyStr )
643+ }
644+ }
639645 }
640646 if h != nil && h .cfg != nil {
641647 if proxyStr := strings .TrimSpace (h .cfg .ProxyURL ); proxyStr != "" {
@@ -658,6 +664,123 @@ func (h *Handler) apiCallTransport(auth *coreauth.Auth) http.RoundTripper {
658664 return clone
659665}
660666
667+ type apiKeyConfigEntry interface {
668+ GetAPIKey () string
669+ GetBaseURL () string
670+ }
671+
672+ func resolveAPIKeyConfig [T apiKeyConfigEntry ](entries []T , auth * coreauth.Auth ) * T {
673+ if auth == nil || len (entries ) == 0 {
674+ return nil
675+ }
676+ attrKey , attrBase := "" , ""
677+ if auth .Attributes != nil {
678+ attrKey = strings .TrimSpace (auth .Attributes ["api_key" ])
679+ attrBase = strings .TrimSpace (auth .Attributes ["base_url" ])
680+ }
681+ for i := range entries {
682+ entry := & entries [i ]
683+ cfgKey := strings .TrimSpace ((* entry ).GetAPIKey ())
684+ cfgBase := strings .TrimSpace ((* entry ).GetBaseURL ())
685+ if attrKey != "" && attrBase != "" {
686+ if strings .EqualFold (cfgKey , attrKey ) && strings .EqualFold (cfgBase , attrBase ) {
687+ return entry
688+ }
689+ continue
690+ }
691+ if attrKey != "" && strings .EqualFold (cfgKey , attrKey ) {
692+ if cfgBase == "" || strings .EqualFold (cfgBase , attrBase ) {
693+ return entry
694+ }
695+ }
696+ if attrKey == "" && attrBase != "" && strings .EqualFold (cfgBase , attrBase ) {
697+ return entry
698+ }
699+ }
700+ if attrKey != "" {
701+ for i := range entries {
702+ entry := & entries [i ]
703+ if strings .EqualFold (strings .TrimSpace ((* entry ).GetAPIKey ()), attrKey ) {
704+ return entry
705+ }
706+ }
707+ }
708+ return nil
709+ }
710+
711+ func proxyURLFromAPIKeyConfig (cfg * config.Config , auth * coreauth.Auth ) string {
712+ if cfg == nil || auth == nil {
713+ return ""
714+ }
715+ authKind , authAccount := auth .AccountInfo ()
716+ if ! strings .EqualFold (strings .TrimSpace (authKind ), "api_key" ) {
717+ return ""
718+ }
719+
720+ attrs := auth .Attributes
721+ compatName := ""
722+ providerKey := ""
723+ if len (attrs ) > 0 {
724+ compatName = strings .TrimSpace (attrs ["compat_name" ])
725+ providerKey = strings .TrimSpace (attrs ["provider_key" ])
726+ }
727+ if compatName != "" || strings .EqualFold (strings .TrimSpace (auth .Provider ), "openai-compatibility" ) {
728+ return resolveOpenAICompatAPIKeyProxyURL (cfg , auth , strings .TrimSpace (authAccount ), providerKey , compatName )
729+ }
730+
731+ switch strings .ToLower (strings .TrimSpace (auth .Provider )) {
732+ case "gemini" :
733+ if entry := resolveAPIKeyConfig (cfg .GeminiKey , auth ); entry != nil {
734+ return strings .TrimSpace (entry .ProxyURL )
735+ }
736+ case "claude" :
737+ if entry := resolveAPIKeyConfig (cfg .ClaudeKey , auth ); entry != nil {
738+ return strings .TrimSpace (entry .ProxyURL )
739+ }
740+ case "codex" :
741+ if entry := resolveAPIKeyConfig (cfg .CodexKey , auth ); entry != nil {
742+ return strings .TrimSpace (entry .ProxyURL )
743+ }
744+ }
745+ return ""
746+ }
747+
748+ func resolveOpenAICompatAPIKeyProxyURL (cfg * config.Config , auth * coreauth.Auth , apiKey , providerKey , compatName string ) string {
749+ if cfg == nil || auth == nil {
750+ return ""
751+ }
752+ apiKey = strings .TrimSpace (apiKey )
753+ if apiKey == "" {
754+ return ""
755+ }
756+ candidates := make ([]string , 0 , 3 )
757+ if v := strings .TrimSpace (compatName ); v != "" {
758+ candidates = append (candidates , v )
759+ }
760+ if v := strings .TrimSpace (providerKey ); v != "" {
761+ candidates = append (candidates , v )
762+ }
763+ if v := strings .TrimSpace (auth .Provider ); v != "" {
764+ candidates = append (candidates , v )
765+ }
766+
767+ for i := range cfg .OpenAICompatibility {
768+ compat := & cfg .OpenAICompatibility [i ]
769+ for _ , candidate := range candidates {
770+ if candidate != "" && strings .EqualFold (strings .TrimSpace (candidate ), compat .Name ) {
771+ for j := range compat .APIKeyEntries {
772+ entry := & compat .APIKeyEntries [j ]
773+ if strings .EqualFold (strings .TrimSpace (entry .APIKey ), apiKey ) {
774+ return strings .TrimSpace (entry .ProxyURL )
775+ }
776+ }
777+ return ""
778+ }
779+ }
780+ }
781+ return ""
782+ }
783+
661784func buildProxyTransport (proxyStr string ) * http.Transport {
662785 transport , _ , errBuild := proxyutil .BuildHTTPTransport (proxyStr )
663786 if errBuild != nil {
0 commit comments