Completions api (#8) (#29)

This commit is contained in:
2026-02-16 17:00:11 +00:00
parent d83217504c
commit d9ab162dfb
13 changed files with 1885 additions and 113 deletions

View File

@@ -10,10 +10,12 @@ import (
"git.gobha.me/xcaliber/chat-switchboard/config"
"git.gobha.me/xcaliber/chat-switchboard/handlers"
"git.gobha.me/xcaliber/chat-switchboard/middleware"
"git.gobha.me/xcaliber/chat-switchboard/providers"
)
func init() {
gin.SetMode(gin.TestMode)
providers.Init()
}
func TestHealthEndpoint(t *testing.T) {
@@ -53,6 +55,8 @@ func TestAllRoutesRegistered(t *testing.T) {
auth := handlers.NewAuthHandler(cfg)
chats := handlers.NewChatHandler()
msgs := handlers.NewMessageHandler()
comp := handlers.NewCompletionHandler()
apiCfg := handlers.NewAPIConfigHandler()
r := gin.New()
api := r.Group("/api/v1")
@@ -67,15 +71,29 @@ func TestAllRoutesRegistered(t *testing.T) {
protected := api.Group("")
{
// Chats
protected.GET("/chats", chats.ListChats)
protected.POST("/chats", chats.CreateChat)
protected.GET("/chats/:id", chats.GetChat)
protected.PUT("/chats/:id", chats.UpdateChat)
protected.DELETE("/chats/:id", chats.DeleteChat)
// Messages
protected.GET("/chats/:id/messages", msgs.ListMessages)
protected.POST("/chats/:id/messages", msgs.CreateMessage)
protected.POST("/chats/:id/regenerate", msgs.Regenerate)
// Chat Engine
protected.POST("/chat/completions", comp.Complete)
// API Configs
protected.GET("/api-configs", apiCfg.ListConfigs)
protected.POST("/api-configs", apiCfg.CreateConfig)
protected.GET("/api-configs/:id", apiCfg.GetConfig)
protected.PUT("/api-configs/:id", apiCfg.UpdateConfig)
protected.DELETE("/api-configs/:id", apiCfg.DeleteConfig)
protected.GET("/api-configs/:id/models", apiCfg.ListModels)
protected.GET("/models", apiCfg.ListAllModels)
}
routes := r.Routes()
@@ -85,18 +103,32 @@ func TestAllRoutesRegistered(t *testing.T) {
}
expected := []string{
// Auth
"POST /api/v1/auth/register",
"POST /api/v1/auth/login",
"POST /api/v1/auth/refresh",
"POST /api/v1/auth/logout",
// Chats
"GET /api/v1/chats",
"POST /api/v1/chats",
"GET /api/v1/chats/:id",
"PUT /api/v1/chats/:id",
"DELETE /api/v1/chats/:id",
// Messages
"GET /api/v1/chats/:id/messages",
"POST /api/v1/chats/:id/messages",
"POST /api/v1/chats/:id/regenerate",
// Chat Engine
"POST /api/v1/chat/completions",
// API Configs
"GET /api/v1/api-configs",
"POST /api/v1/api-configs",
"GET /api/v1/api-configs/:id",
"PUT /api/v1/api-configs/:id",
"DELETE /api/v1/api-configs/:id",
"GET /api/v1/api-configs/:id/models",
// Models
"GET /api/v1/models",
}
for _, e := range expected {
@@ -106,6 +138,60 @@ func TestAllRoutesRegistered(t *testing.T) {
}
}
func TestProviderRegistry(t *testing.T) {
ids := providers.List()
if len(ids) < 2 {
t.Errorf("Expected at least 2 providers, got %d", len(ids))
}
// OpenAI should be registered
p, err := providers.Get("openai")
if err != nil {
t.Errorf("OpenAI provider not found: %v", err)
}
if p.ID() != "openai" {
t.Errorf("Expected ID 'openai', got '%s'", p.ID())
}
// Anthropic should be registered
p, err = providers.Get("anthropic")
if err != nil {
t.Errorf("Anthropic provider not found: %v", err)
}
if p.ID() != "anthropic" {
t.Errorf("Expected ID 'anthropic', got '%s'", p.ID())
}
// Unknown should fail
_, err = providers.Get("nonexistent")
if err == nil {
t.Error("Expected error for unknown provider")
}
}
func TestAnthropicStaticModels(t *testing.T) {
p := &providers.AnthropicProvider{}
models, err := p.ListModels(nil, providers.ProviderConfig{})
if err != nil {
t.Errorf("ListModels should not fail: %v", err)
}
if len(models) == 0 {
t.Error("Expected some static models")
}
// Check that known models are present
found := false
for _, m := range models {
if m.ID == "claude-sonnet-4-20250514" {
found = true
break
}
}
if !found {
t.Error("Expected claude-sonnet-4 in static model list")
}
}
func TestStubHandler(t *testing.T) {
r := gin.New()
r.GET("/test", stubHandler("settings"))