diff --git a/backend/internal/server/routes/gateway.go b/backend/internal/server/routes/gateway.go index 45db227e58..f73379981e 100644 --- a/backend/internal/server/routes/gateway.go +++ b/backend/internal/server/routes/gateway.go @@ -42,6 +42,13 @@ func RegisterGatewayRoutes( isOpenAIGatewayPlatform := func(c *gin.Context) bool { return getGroupPlatform(c) == service.PlatformOpenAI } + modelsHandler := func(c *gin.Context) { + if isOpenAIGatewayPlatform(c) && c.Query("client_version") != "" { + h.OpenAIGateway.CodexModels(c) + return + } + h.Gateway.Models(c) + } imagesHandler := func(c *gin.Context) { switch getGroupPlatform(c) { case service.PlatformOpenAI: @@ -140,13 +147,7 @@ func RegisterGatewayRoutes( // Codex CLI / Codex app refresh their model picker from the provider's // /models endpoint with a client_version query and expect the ChatGPT // Codex manifest format; other clients keep the OpenAI-style list. - gateway.GET("/models", func(c *gin.Context) { - if isOpenAIGatewayPlatform(c) && c.Query("client_version") != "" { - h.OpenAIGateway.CodexModels(c) - return - } - h.Gateway.Models(c) - }) + gateway.GET("/models", modelsHandler) gateway.GET("/usage", h.Gateway.Usage) // OpenAI Responses API: auto-route based on group platform gateway.POST("/responses", func(c *gin.Context) { @@ -235,6 +236,7 @@ func RegisterGatewayRoutes( r.GET("/responses", bodyLimit, clientRequestID, opsErrorLogger, endpointNorm, gin.HandlerFunc(apiKeyAuth), requireGroupAnthropic, func(c *gin.Context) { h.OpenAIGateway.ResponsesWebSocket(c) }) + r.GET("/models", bodyLimit, clientRequestID, opsErrorLogger, endpointNorm, gin.HandlerFunc(apiKeyAuth), requireGroupAnthropic, modelsHandler) codexDirect := r.Group("/backend-api/codex") codexDirect.Use(bodyLimit, clientRequestID, opsErrorLogger, endpointNorm, gin.HandlerFunc(apiKeyAuth), requireGroupAnthropic) { diff --git a/backend/internal/server/routes/gateway_codex_models_test.go b/backend/internal/server/routes/gateway_codex_models_test.go index 74af755919..04a8b8fa67 100644 --- a/backend/internal/server/routes/gateway_codex_models_test.go +++ b/backend/internal/server/routes/gateway_codex_models_test.go @@ -10,13 +10,15 @@ import ( func TestGatewayRoutesCodexModelsManifestPathIsRegistered(t *testing.T) { router := newGatewayRoutesTestRouter() - registered := make(map[string]bool) + registered := make(map[string]string) for _, route := range router.Routes() { if route.Method == http.MethodGet { - registered[route.Path] = true + registered[route.Path] = route.Handler } } - require.True(t, registered["/backend-api/codex/models"], "GET /backend-api/codex/models should be registered") - require.True(t, registered["/v1/models"], "GET /v1/models should be registered") + require.NotEmpty(t, registered["/backend-api/codex/models"], "GET /backend-api/codex/models should be registered") + require.NotEmpty(t, registered["/v1/models"], "GET /v1/models should be registered") + require.NotEmpty(t, registered["/models"], "GET /models should be registered") + require.Equal(t, registered["/v1/models"], registered["/models"], "root alias should use the same platform-aware handler") } diff --git a/backend/internal/web/embed_on.go b/backend/internal/web/embed_on.go index 398a6d813b..4bd984301b 100644 --- a/backend/internal/web/embed_on.go +++ b/backend/internal/web/embed_on.go @@ -308,6 +308,7 @@ func shouldBypassEmbeddedFrontend(path string) bool { strings.HasPrefix(trimmed, "/antigravity/") || strings.HasPrefix(trimmed, "/setup/") || trimmed == "/health" || + trimmed == "/models" || trimmed == "/responses" || strings.HasPrefix(trimmed, "/responses/") || trimmed == "/alpha/search" || diff --git a/backend/internal/web/embed_test.go b/backend/internal/web/embed_test.go index 3ca874e1e9..769b856ac1 100644 --- a/backend/internal/web/embed_test.go +++ b/backend/internal/web/embed_test.go @@ -485,6 +485,7 @@ func TestFrontendServer_Middleware(t *testing.T) { apiPaths := []string{ "/api/v1/users", + "/models", "/v1/models", "/v1beta/chat", "/backend-api/codex/responses", @@ -746,6 +747,7 @@ func TestServeEmbeddedFrontend(t *testing.T) { apiPaths := []string{ "/api/users", + "/models", "/v1/models", "/v1beta/chat", "/backend-api/codex/responses",