mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-19 04:40:52 +08:00
- Added a new routing package to manage provider registration and model resolution. - Introduced Router, Executor, and Provider interfaces to handle different provider types. - Implemented OAuthProvider and APIKeyProvider to support OAuth and API key authentication. - Enhanced DefaultModelMapper to include OAuth model alias handling and fallback mechanisms. - Updated context management in API handlers to preserve fallback models. - Added tests for routing logic and provider selection. - Enhanced Claude request conversion to handle reasoning content based on thinking mode.
133 lines
3.3 KiB
Go
133 lines
3.3 KiB
Go
package providers
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"sync"
|
|
|
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/routing"
|
|
coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
|
|
"github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/executor"
|
|
)
|
|
|
|
// OAuthProvider wraps OAuth-based auths as routing.Provider.
|
|
type OAuthProvider struct {
|
|
name string
|
|
auths []*coreauth.Auth
|
|
mu sync.RWMutex
|
|
executor coreauth.ProviderExecutor
|
|
}
|
|
|
|
// NewOAuthProvider creates a new OAuth provider.
|
|
func NewOAuthProvider(name string, exec coreauth.ProviderExecutor) *OAuthProvider {
|
|
return &OAuthProvider{
|
|
name: name,
|
|
auths: make([]*coreauth.Auth, 0),
|
|
executor: exec,
|
|
}
|
|
}
|
|
|
|
// Name returns the provider name.
|
|
func (p *OAuthProvider) Name() string {
|
|
return p.name
|
|
}
|
|
|
|
// Type returns ProviderTypeOAuth.
|
|
func (p *OAuthProvider) Type() routing.ProviderType {
|
|
return routing.ProviderTypeOAuth
|
|
}
|
|
|
|
// SupportsModel checks if any auth supports the model.
|
|
func (p *OAuthProvider) SupportsModel(model string) bool {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
|
|
// OAuth providers typically support models via oauth-model-alias
|
|
// The actual model support is determined at execution time
|
|
return true
|
|
}
|
|
|
|
// Available checks if there's an available auth for the model.
|
|
func (p *OAuthProvider) Available(model string) bool {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
|
|
for _, auth := range p.auths {
|
|
if p.isAuthAvailable(auth, model) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Priority returns the priority (OAuth is preferred over API key).
|
|
func (p *OAuthProvider) Priority() int {
|
|
return 10
|
|
}
|
|
|
|
// Execute sends the request using an available OAuth auth.
|
|
func (p *OAuthProvider) Execute(ctx context.Context, model string, req executor.Request) (executor.Response, error) {
|
|
auth := p.selectAuth(model)
|
|
if auth == nil {
|
|
return executor.Response{}, ErrNoAvailableAuth
|
|
}
|
|
|
|
return p.executor.Execute(ctx, auth, req, executor.Options{})
|
|
}
|
|
|
|
// ExecuteStream sends a streaming request.
|
|
func (p *OAuthProvider) ExecuteStream(ctx context.Context, model string, req executor.Request) (<-chan executor.StreamChunk, error) {
|
|
auth := p.selectAuth(model)
|
|
if auth == nil {
|
|
return nil, ErrNoAvailableAuth
|
|
}
|
|
|
|
return p.executor.ExecuteStream(ctx, auth, req, executor.Options{})
|
|
}
|
|
|
|
// AddAuth adds an auth to this provider.
|
|
func (p *OAuthProvider) AddAuth(auth *coreauth.Auth) {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
p.auths = append(p.auths, auth)
|
|
}
|
|
|
|
// RemoveAuth removes an auth from this provider.
|
|
func (p *OAuthProvider) RemoveAuth(authID string) {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
|
|
filtered := make([]*coreauth.Auth, 0, len(p.auths))
|
|
for _, auth := range p.auths {
|
|
if auth.ID != authID {
|
|
filtered = append(filtered, auth)
|
|
}
|
|
}
|
|
p.auths = filtered
|
|
}
|
|
|
|
// isAuthAvailable checks if an auth is available for the model.
|
|
func (p *OAuthProvider) isAuthAvailable(auth *coreauth.Auth, model string) bool {
|
|
// TODO: integrate with model_registry for quota checking
|
|
// For now, just check if auth exists
|
|
return auth != nil
|
|
}
|
|
|
|
// selectAuth selects an available auth for the model.
|
|
func (p *OAuthProvider) selectAuth(model string) *coreauth.Auth {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
|
|
for _, auth := range p.auths {
|
|
if p.isAuthAvailable(auth, model) {
|
|
return auth
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Errors
|
|
var (
|
|
ErrNoAvailableAuth = errors.New("no available OAuth auth for model")
|
|
)
|