feebe6c7f2
- Introduced OpenAI-compatible image model support in the API, enabling integration through image generation and editing endpoints. - Added registry type for OpenAIImageModelType to classify and validate compatibility. - Implemented request handling for OpenAI-compatible image models, including JSON and multipart formats. - Enhanced executor methods to support OpenAI-compatible image streaming and non-streaming requests. - Included tests to validate model registration, streaming behavior, and multipart payload formatting.
135 lines
3.4 KiB
Go
135 lines
3.4 KiB
Go
package cliproxy
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
internalregistry "github.com/router-for-me/CLIProxyAPI/v7/internal/registry"
|
|
coreauth "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/auth"
|
|
"github.com/router-for-me/CLIProxyAPI/v7/sdk/config"
|
|
)
|
|
|
|
func TestRegisterModelsForAuth_UsesPreMergedExcludedModelsAttribute(t *testing.T) {
|
|
service := &Service{
|
|
cfg: &config.Config{
|
|
OAuthExcludedModels: map[string][]string{
|
|
"gemini-cli": {"gemini-2.5-pro"},
|
|
},
|
|
},
|
|
}
|
|
auth := &coreauth.Auth{
|
|
ID: "auth-gemini-cli",
|
|
Provider: "gemini-cli",
|
|
Status: coreauth.StatusActive,
|
|
Attributes: map[string]string{
|
|
"auth_kind": "oauth",
|
|
"excluded_models": "gemini-2.5-flash",
|
|
},
|
|
}
|
|
|
|
registry := GlobalModelRegistry()
|
|
registry.UnregisterClient(auth.ID)
|
|
t.Cleanup(func() {
|
|
registry.UnregisterClient(auth.ID)
|
|
})
|
|
|
|
service.registerModelsForAuth(auth)
|
|
|
|
models := registry.GetAvailableModelsByProvider("gemini-cli")
|
|
if len(models) == 0 {
|
|
t.Fatal("expected gemini-cli models to be registered")
|
|
}
|
|
|
|
for _, model := range models {
|
|
if model == nil {
|
|
continue
|
|
}
|
|
modelID := strings.TrimSpace(model.ID)
|
|
if strings.EqualFold(modelID, "gemini-2.5-flash") {
|
|
t.Fatalf("expected model %q to be excluded by auth attribute", modelID)
|
|
}
|
|
}
|
|
|
|
seenGlobalExcluded := false
|
|
for _, model := range models {
|
|
if model == nil {
|
|
continue
|
|
}
|
|
if strings.EqualFold(strings.TrimSpace(model.ID), "gemini-2.5-pro") {
|
|
seenGlobalExcluded = true
|
|
break
|
|
}
|
|
}
|
|
if !seenGlobalExcluded {
|
|
t.Fatal("expected global excluded model to be present when attribute override is set")
|
|
}
|
|
}
|
|
|
|
func TestRegisterModelsForAuth_OpenAICompatibilityImageModelType(t *testing.T) {
|
|
service := &Service{
|
|
cfg: &config.Config{
|
|
OpenAICompatibility: []config.OpenAICompatibility{
|
|
{
|
|
Name: "images",
|
|
BaseURL: "https://example.com/v1",
|
|
Models: []config.OpenAICompatibilityModel{
|
|
{Name: "upstream-image", Alias: "compat-image", Image: true},
|
|
{Name: "upstream-chat", Alias: "compat-chat"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
auth := &coreauth.Auth{
|
|
ID: "auth-openai-compat-image",
|
|
Provider: "openai-compatibility",
|
|
Status: coreauth.StatusActive,
|
|
Attributes: map[string]string{
|
|
"auth_kind": "api_key",
|
|
"compat_name": "images",
|
|
"provider_key": "images",
|
|
},
|
|
}
|
|
|
|
modelRegistry := internalregistry.GetGlobalRegistry()
|
|
modelRegistry.UnregisterClient(auth.ID)
|
|
t.Cleanup(func() {
|
|
modelRegistry.UnregisterClient(auth.ID)
|
|
})
|
|
|
|
service.registerModelsForAuth(auth)
|
|
|
|
models := modelRegistry.GetModelsForClient(auth.ID)
|
|
var imageModel *internalregistry.ModelInfo
|
|
var chatModel *internalregistry.ModelInfo
|
|
for _, model := range models {
|
|
if model == nil {
|
|
continue
|
|
}
|
|
switch strings.TrimSpace(model.ID) {
|
|
case "compat-image":
|
|
imageModel = model
|
|
case "compat-chat":
|
|
chatModel = model
|
|
}
|
|
}
|
|
if imageModel == nil {
|
|
t.Fatal("expected compat-image to be registered")
|
|
}
|
|
if imageModel.Type != internalregistry.OpenAIImageModelType {
|
|
t.Fatalf("image model type = %q, want %q", imageModel.Type, internalregistry.OpenAIImageModelType)
|
|
}
|
|
if imageModel.Thinking != nil {
|
|
t.Fatalf("image model thinking = %+v, want nil", imageModel.Thinking)
|
|
}
|
|
if chatModel == nil {
|
|
t.Fatal("expected compat-chat to be registered")
|
|
}
|
|
if chatModel.Type != "openai-compatibility" {
|
|
t.Fatalf("chat model type = %q, want openai-compatibility", chatModel.Type)
|
|
}
|
|
if chatModel.Thinking == nil {
|
|
t.Fatal("expected chat model to keep default thinking support")
|
|
}
|
|
}
|