mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-18 04:10:51 +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.
116 lines
3.3 KiB
Go
116 lines
3.3 KiB
Go
package routing
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
|
"github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/executor"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// mockProvider is a test double for Provider.
|
|
type mockProvider struct {
|
|
name string
|
|
providerType ProviderType
|
|
supportsModels map[string]bool
|
|
available bool
|
|
priority int
|
|
}
|
|
|
|
func (m *mockProvider) Name() string { return m.name }
|
|
func (m *mockProvider) Type() ProviderType { return m.providerType }
|
|
func (m *mockProvider) SupportsModel(model string) bool { return m.supportsModels[model] }
|
|
func (m *mockProvider) Available(model string) bool { return m.available }
|
|
func (m *mockProvider) Priority() int { return m.priority }
|
|
func (m *mockProvider) Execute(ctx context.Context, model string, req executor.Request) (executor.Response, error) {
|
|
return executor.Response{}, nil
|
|
}
|
|
func (m *mockProvider) ExecuteStream(ctx context.Context, model string, req executor.Request) (<-chan executor.StreamChunk, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func TestRouter_Resolve_ModelMappings(t *testing.T) {
|
|
registry := NewRegistry()
|
|
|
|
// Add a provider
|
|
p := &mockProvider{
|
|
name: "test-provider",
|
|
providerType: ProviderTypeOAuth,
|
|
supportsModels: map[string]bool{"target-model": true},
|
|
available: true,
|
|
priority: 1,
|
|
}
|
|
registry.Register(p)
|
|
|
|
// Create router with model mapping
|
|
cfg := &config.Config{
|
|
AmpCode: config.AmpCode{
|
|
ModelMappings: []config.AmpModelMapping{
|
|
{From: "user-model", To: "target-model"},
|
|
},
|
|
},
|
|
}
|
|
router := NewRouter(registry, cfg)
|
|
|
|
// Resolve
|
|
decision := router.Resolve("user-model")
|
|
|
|
assert.Equal(t, "user-model", decision.RequestedModel)
|
|
assert.Equal(t, "target-model", decision.ResolvedModel)
|
|
assert.Len(t, decision.Candidates, 1)
|
|
assert.Equal(t, "target-model", decision.Candidates[0].Model)
|
|
}
|
|
|
|
func TestRouter_Resolve_OAuthAliases(t *testing.T) {
|
|
registry := NewRegistry()
|
|
|
|
// Add providers
|
|
p1 := &mockProvider{
|
|
name: "oauth-1",
|
|
providerType: ProviderTypeOAuth,
|
|
supportsModels: map[string]bool{"primary-model": true},
|
|
available: true,
|
|
priority: 1,
|
|
}
|
|
p2 := &mockProvider{
|
|
name: "oauth-2",
|
|
providerType: ProviderTypeOAuth,
|
|
supportsModels: map[string]bool{"fallback-model": true},
|
|
available: true,
|
|
priority: 2,
|
|
}
|
|
registry.Register(p1)
|
|
registry.Register(p2)
|
|
|
|
// Create router with oauth aliases
|
|
cfg := &config.Config{
|
|
OAuthModelAlias: map[string][]config.OAuthModelAlias{
|
|
"test-channel": {
|
|
{Name: "primary-model", Alias: "fallback-model"},
|
|
},
|
|
},
|
|
}
|
|
router := NewRouter(registry, cfg)
|
|
|
|
// Resolve
|
|
decision := router.Resolve("primary-model")
|
|
|
|
assert.Equal(t, "primary-model", decision.ResolvedModel)
|
|
assert.Len(t, decision.Candidates, 2)
|
|
// Primary should come first (lower priority value)
|
|
assert.Equal(t, "primary-model", decision.Candidates[0].Model)
|
|
assert.Equal(t, "fallback-model", decision.Candidates[1].Model)
|
|
}
|
|
|
|
func TestRouter_Resolve_NoProviders(t *testing.T) {
|
|
registry := NewRegistry()
|
|
cfg := &config.Config{}
|
|
router := NewRouter(registry, cfg)
|
|
|
|
decision := router.Resolve("unknown-model")
|
|
|
|
assert.Equal(t, "unknown-model", decision.ResolvedModel)
|
|
assert.Empty(t, decision.Candidates)
|
|
}
|