@@ -6,6 +6,7 @@ package handlers
66import (
77 "fmt"
88 "net/http"
9+ "strings"
910
1011 "github.com/gin-gonic/gin"
1112 "github.com/router-for-me/CLIProxyAPI/v6/internal/interfaces"
@@ -46,6 +47,9 @@ type BaseAPIHandler struct {
4647
4748 // Cfg holds the current application configuration.
4849 Cfg * config.SDKConfig
50+
51+ // OpenAICompatProviders is a list of provider names for OpenAI compatibility.
52+ OpenAICompatProviders []string
4953}
5054
5155// NewBaseAPIHandlers creates a new API handlers instance.
@@ -57,10 +61,11 @@ type BaseAPIHandler struct {
5761//
5862// Returns:
5963// - *BaseAPIHandler: A new API handlers instance
60- func NewBaseAPIHandlers (cfg * config.SDKConfig , authManager * coreauth.Manager ) * BaseAPIHandler {
64+ func NewBaseAPIHandlers (cfg * config.SDKConfig , authManager * coreauth.Manager , openAICompatProviders [] string ) * BaseAPIHandler {
6165 return & BaseAPIHandler {
62- Cfg : cfg ,
63- AuthManager : authManager ,
66+ Cfg : cfg ,
67+ AuthManager : authManager ,
68+ OpenAICompatProviders : openAICompatProviders ,
6469 }
6570}
6671
@@ -133,10 +138,9 @@ func (h *BaseAPIHandler) GetContextWithCancel(handler interfaces.APIHandler, c *
133138// ExecuteWithAuthManager executes a non-streaming request via the core auth manager.
134139// This path is the only supported execution route.
135140func (h * BaseAPIHandler ) ExecuteWithAuthManager (ctx context.Context , handlerType , modelName string , rawJSON []byte , alt string ) ([]byte , * interfaces.ErrorMessage ) {
136- normalizedModel , metadata := normalizeModelMetadata (modelName )
137- providers := util .GetProviderName (normalizedModel )
138- if len (providers ) == 0 {
139- return nil , & interfaces.ErrorMessage {StatusCode : http .StatusBadRequest , Error : fmt .Errorf ("unknown provider for model %s" , modelName )}
141+ providers , normalizedModel , metadata , errMsg := h .getRequestDetails (modelName )
142+ if errMsg != nil {
143+ return nil , errMsg
140144 }
141145 req := coreexecutor.Request {
142146 Model : normalizedModel ,
@@ -176,10 +180,9 @@ func (h *BaseAPIHandler) ExecuteWithAuthManager(ctx context.Context, handlerType
176180// ExecuteCountWithAuthManager executes a non-streaming request via the core auth manager.
177181// This path is the only supported execution route.
178182func (h * BaseAPIHandler ) ExecuteCountWithAuthManager (ctx context.Context , handlerType , modelName string , rawJSON []byte , alt string ) ([]byte , * interfaces.ErrorMessage ) {
179- normalizedModel , metadata := normalizeModelMetadata (modelName )
180- providers := util .GetProviderName (normalizedModel )
181- if len (providers ) == 0 {
182- return nil , & interfaces.ErrorMessage {StatusCode : http .StatusBadRequest , Error : fmt .Errorf ("unknown provider for model %s" , modelName )}
183+ providers , normalizedModel , metadata , errMsg := h .getRequestDetails (modelName )
184+ if errMsg != nil {
185+ return nil , errMsg
183186 }
184187 req := coreexecutor.Request {
185188 Model : normalizedModel ,
@@ -219,11 +222,10 @@ func (h *BaseAPIHandler) ExecuteCountWithAuthManager(ctx context.Context, handle
219222// ExecuteStreamWithAuthManager executes a streaming request via the core auth manager.
220223// This path is the only supported execution route.
221224func (h * BaseAPIHandler ) ExecuteStreamWithAuthManager (ctx context.Context , handlerType , modelName string , rawJSON []byte , alt string ) (<- chan []byte , <- chan * interfaces.ErrorMessage ) {
222- normalizedModel , metadata := normalizeModelMetadata (modelName )
223- providers := util .GetProviderName (normalizedModel )
224- if len (providers ) == 0 {
225+ providers , normalizedModel , metadata , errMsg := h .getRequestDetails (modelName )
226+ if errMsg != nil {
225227 errChan := make (chan * interfaces.ErrorMessage , 1 )
226- errChan <- & interfaces. ErrorMessage { StatusCode : http . StatusBadRequest , Error : fmt . Errorf ( "unknown provider for model %s" , modelName )}
228+ errChan <- errMsg
227229 close (errChan )
228230 return nil , errChan
229231 }
@@ -292,6 +294,58 @@ func (h *BaseAPIHandler) ExecuteStreamWithAuthManager(ctx context.Context, handl
292294 return dataChan , errChan
293295}
294296
297+ func (h * BaseAPIHandler ) getRequestDetails (modelName string ) (providers []string , normalizedModel string , metadata map [string ]any , err * interfaces.ErrorMessage ) {
298+ providerName , extractedModelName , isDynamic := h .parseDynamicModel (modelName )
299+
300+ // First, normalize the model name to handle suffixes like "-thinking-128"
301+ // This needs to happen before determining the provider for non-dynamic models.
302+ normalizedModel , metadata = normalizeModelMetadata (modelName )
303+
304+ if isDynamic {
305+ providers = []string {providerName }
306+ // For dynamic models, the extractedModelName is already normalized by parseDynamicModel
307+ // so we use it as the final normalizedModel.
308+ normalizedModel = extractedModelName
309+ } else {
310+ // For non-dynamic models, use the normalizedModel to get the provider name.
311+ providers = util .GetProviderName (normalizedModel )
312+ }
313+
314+ if len (providers ) == 0 {
315+ return nil , "" , nil , & interfaces.ErrorMessage {StatusCode : http .StatusBadRequest , Error : fmt .Errorf ("unknown provider for model %s" , modelName )}
316+ }
317+
318+ // If it's a dynamic model, the normalizedModel was already set to extractedModelName.
319+ // If it's a non-dynamic model, normalizedModel was set by normalizeModelMetadata.
320+ // So, normalizedModel is already correctly set at this point.
321+
322+ return providers , normalizedModel , metadata , nil
323+ }
324+
325+ func (h * BaseAPIHandler ) parseDynamicModel (modelName string ) (providerName , model string , isDynamic bool ) {
326+ var providerPart , modelPart string
327+ for _ , sep := range []string {"://" } {
328+ if parts := strings .SplitN (modelName , sep , 2 ); len (parts ) == 2 {
329+ providerPart = parts [0 ]
330+ modelPart = parts [1 ]
331+ break
332+ }
333+ }
334+
335+ if providerPart == "" {
336+ return "" , modelName , false
337+ }
338+
339+ // Check if the provider is a configured openai-compatibility provider
340+ for _ , pName := range h .OpenAICompatProviders {
341+ if pName == providerPart {
342+ return providerPart , modelPart , true
343+ }
344+ }
345+
346+ return "" , modelName , false
347+ }
348+
295349func cloneBytes (src []byte ) []byte {
296350 if len (src ) == 0 {
297351 return nil
0 commit comments