diff --git a/Makefile b/Makefile index 2b4ddbf..e4d75c5 100644 --- a/Makefile +++ b/Makefile @@ -59,4 +59,4 @@ help: @echo " make run-web - Run web interface only" @echo " make clean - Clean build artifacts" @echo " make db-reset - Reset database" - @echo " make help - Show this help message" \ No newline at end of file + @echo " make help - Show this help message" diff --git a/proxy/internal/handler/handlers.go b/proxy/internal/handler/handlers.go index 4cc3223..05d1360 100644 --- a/proxy/internal/handler/handlers.go +++ b/proxy/internal/handler/handlers.go @@ -130,29 +130,12 @@ func (h *Handler) Messages(w http.ResponseWriter, r *http.Request) { } func (h *Handler) Models(w http.ResponseWriter, r *http.Request) { - + // This proxy uses pattern-based routing and supports any model dynamically. + // Returning an empty list since the actual supported models depend on the + // upstream providers (Anthropic, OpenAI) and their current offerings. response := &model.ModelsResponse{ Object: "list", - Data: []model.ModelInfo{ - { - ID: "claude-3-sonnet-20240229", - Object: "model", - Created: 1677610602, - OwnedBy: "anthropic", - }, - { - ID: "claude-3-opus-20240229", - Object: "model", - Created: 1677610602, - OwnedBy: "anthropic", - }, - { - ID: "claude-3-haiku-20240307", - Object: "model", - Created: 1677610602, - OwnedBy: "anthropic", - }, - }, + Data: []model.ModelInfo{}, } writeJSONResponse(w, response) diff --git a/proxy/internal/service/model_router.go b/proxy/internal/service/model_router.go index afc5276..9322a3a 100644 --- a/proxy/internal/service/model_router.go +++ b/proxy/internal/service/model_router.go @@ -25,10 +25,24 @@ type ModelRouter struct { providers map[string]provider.Provider subagentMappings map[string]string // agentName -> targetModel customAgentPrompts map[string]SubagentDefinition // promptHash -> definition - modelProviderMap map[string]string // model -> provider mapping logger *log.Logger } +// providerPattern maps model name prefixes to their provider +type providerPattern struct { + prefix string + provider string +} + +// providerPatterns defines how to route models to providers based on name prefix. +// Order matters - first match wins. +var providerPatterns = []providerPattern{ + {"gpt-", "openai"}, + {"o1", "openai"}, // o1, o1-mini, o1-pro + {"o3", "openai"}, // o3, o3-mini, o3-pro + {"claude-", "anthropic"}, +} + type SubagentDefinition struct { Name string TargetModel string @@ -42,7 +56,6 @@ func NewModelRouter(cfg *config.Config, providers map[string]provider.Provider, providers: providers, subagentMappings: cfg.Subagents.Mappings, customAgentPrompts: make(map[string]SubagentDefinition), - modelProviderMap: initializeModelProviderMap(), logger: logger, } @@ -58,63 +71,6 @@ func NewModelRouter(cfg *config.Config, providers map[string]provider.Provider, return router } -// initializeModelProviderMap creates a mapping of model names to their providers -func initializeModelProviderMap() map[string]string { - modelMap := make(map[string]string) - - // OpenAI models - openaiModels := []string{ - // GPT-5 family - "gpt-5", "gpt-5-mini", "gpt-5-nano", - - // GPT-4.1 family - "gpt-4.1", "gpt-4.1-2025-04-14", - "gpt-4.1-mini", "gpt-4.1-mini-2025-04-14", - "gpt-4.1-nano", "gpt-4.1-nano-2025-04-14", - - // GPT-4.5 - "gpt-4.5-preview", "gpt-4.5-preview-2025-02-27", - - // GPT-4o variants - "gpt-4o", "gpt-4o-2024-08-06", - "gpt-4o-mini", "gpt-4o-mini-2024-07-18", - - // GPT-3.5 variants - "gpt-3.5-turbo", "gpt-3.5-turbo-0125", "gpt-3.5-turbo-1106", "gpt-3.5-turbo-instruct", - - // O1 series - "o1", "o1-2024-12-17", - "o1-pro", "o1-pro-2025-03-19", - "o1-mini", "o1-mini-2024-09-12", - - // O3 series - "o3-pro", "o3-pro-2025-06-10", - "o3", "o3-2025-04-16", - "o3-mini", "o3-mini-2025-01-31", - } - - for _, model := range openaiModels { - modelMap[model] = "openai" - } - - // Anthropic models - anthropicModels := []string{ - "claude-opus-4-1-20250805", - "claude-opus-4-20250514", - "claude-sonnet-4-20250514", - "claude-sonnet-4-5-20250929", - "claude-opus-4-5-20251101", - "claude-3-7-sonnet-20250219", - "claude-3-5-haiku-20241022", - } - - for _, model := range anthropicModels { - modelMap[model] = "anthropic" - } - - return modelMap -} - // extractStaticPrompt extracts the portion before "Notes:" if it exists func (r *ModelRouter) extractStaticPrompt(systemPrompt string) string { // Find the "Notes:" section @@ -265,11 +221,12 @@ func (r *ModelRouter) hashString(s string) string { } func (r *ModelRouter) getProviderNameForModel(model string) string { - if provider, exists := r.modelProviderMap[model]; exists { - return provider + for _, pattern := range providerPatterns { + if strings.HasPrefix(model, pattern.prefix) { + return pattern.provider + } } - - // Default to anthropic - r.logger.Printf("⚠️ Model '%s' doesn't match any known patterns, defaulting to anthropic", model) + // Default to anthropic (this is an Anthropic proxy after all) + r.logger.Printf("ℹ️ Model '%s' has no matching pattern, defaulting to anthropic", model) return "anthropic" }