feat: add /api/v2/ai-gateway API route aliases (#26475)

## Description

Registers `/api/v2/ai-gateway/*` as the new API path for AI Gateway, replacing `/api/v2/aibridge/*`. Both prefixes share the same route builder (`aiBridgeRoutes`) backed by a single in-memory handler, so existing `/aibridge` endpoints continue to work. New endpoints must be registered on the enterprise API handler under `/api/v2/ai-gateway` only.

Swagger annotations now point to `/api/v2/ai-gateway` paths with a backward-compatibility note referencing `/aibridge`. The legacy `/aibridge` routes are skipped in the swagger documentation test.

## Changes

- Store one raw handler (`aiGatewayHandler`) instead of two prefix-stripped handlers
- Register `/ai-gateway` and `/ai-gateway/proxy` route aliases alongside legacy `/aibridge` routes
- Move `/aibridge/keys` to `/ai-gateway/keys`
- Update in-process transport to use `/api/v2/ai-gateway` prefix
- Update SDK client URLs and proxy forwarding URL
- Swap `@Router` and `@Tags` annotations from `aibridge`/`AI Bridge` to `ai-gateway`/`AI Gateway`
- Rename user-facing error messages from "AI Bridge" to "AI Gateway"
- Define consts for route prefixes (`AIGatewayRootPath`, `AIBridgeRootPath`)
- Update tests and comments to use new paths

Note: the following will be addressed in follow-up PRs:
- Frontend API URLs
- Frontend routes and redirects
- Dogfood main.tf updates
- Hand-written documentation URL updates
- aibridge internal comments and nits
- Scale tests path updates

Refs https://linear.app/coder/issue/AIGOV-230

> Generated with the assistance of Coder Agents (@ssncferreira)
This commit is contained in:
Susana Ferreira
2026-06-23 12:15:10 +01:00
committed by GitHub
parent 4691ef39cd
commit 970bd73691
28 changed files with 727 additions and 630 deletions
+31 -5
View File
@@ -5,10 +5,17 @@ import (
"github.com/go-chi/chi/v5"
agplaibridge "github.com/coder/coder/v2/coderd/aibridge"
"github.com/coder/coder/v2/coderd/httpapi"
"github.com/coder/coder/v2/codersdk"
)
// API route prefixes for the AI Gateway Proxy and legacy AI Bridge Proxy endpoints.
const (
AIGatewayProxyPath = agplaibridge.AIGatewayRootPath + "/proxy"
AIBridgeProxyPath = agplaibridge.AIBridgeRootPath + "/proxy"
)
// RegisterInMemoryAIBridgeProxydHTTPHandler mounts [aibridgeproxyd.Server]'s HTTP handler
// onto [API]'s router, so that requests to aibridgedproxy will be relayed from Coder's API server
// to the in-memory aibridgedproxy.
@@ -20,8 +27,27 @@ func (api *API) RegisterInMemoryAIBridgeProxydHTTPHandler(srv http.Handler) {
api.aibridgeproxydHandler = srv
}
// aibridgeproxyHandler handles AI Bridge Proxy endpoints.
func aibridgeproxyHandler(api *API, middlewares ...func(http.Handler) http.Handler) func(r chi.Router) {
// aibridgeProxyHTTPHandler returns the legacy /api/v2/aibridge/proxy route tree.
// Kept for backward compatibility only.
//
// NOTE: new endpoints must be registered on the enterprise API
// handler under /api/v2/ai-gateway, not in this shared route builder.
func aibridgeProxyHTTPHandler(api *API, middlewares ...func(http.Handler) http.Handler) func(r chi.Router) {
return aiGatewayProxyRoutes(api, AIBridgeProxyPath, middlewares...)
}
// aiGatewayProxyHTTPHandler returns the /api/v2/ai-gateway/proxy route tree.
// This shares the same route builder as /aibridge/proxy for endpoints that
// existed before the rename.
//
// NOTE: new endpoints must be registered on the enterprise API
// handler under /api/v2/ai-gateway, not in this shared route builder.
func aiGatewayProxyHTTPHandler(api *API, middlewares ...func(http.Handler) http.Handler) func(r chi.Router) {
return aiGatewayProxyRoutes(api, AIGatewayProxyPath, middlewares...)
}
// aiGatewayProxyRoutes builds the route tree for AI Gateway Proxy endpoints.
func aiGatewayProxyRoutes(api *API, stripPrefix string, middlewares ...func(http.Handler) http.Handler) func(r chi.Router) {
return func(r chi.Router) {
r.Use(api.RequireFeatureMW(codersdk.FeatureAIBridge))
r.Use(middlewares...)
@@ -30,7 +56,7 @@ func aibridgeproxyHandler(api *API, middlewares ...func(http.Handler) http.Handl
// Check if the proxy is enabled.
if !api.DeploymentValues.AI.BridgeProxyConfig.Enabled.Value() {
httpapi.Write(r.Context(), rw, http.StatusNotFound, codersdk.Response{
Message: "AI Bridge Proxy is not enabled.",
Message: "AI Gateway Proxy is not enabled.",
})
return
}
@@ -38,13 +64,13 @@ func aibridgeproxyHandler(api *API, middlewares ...func(http.Handler) http.Handl
// Check if the handler is registered.
if api.aibridgeproxydHandler == nil {
httpapi.Write(r.Context(), rw, http.StatusNotFound, codersdk.Response{
Message: "AI Bridge Proxy handler not mounted.",
Message: "AI Gateway Proxy handler not mounted.",
})
return
}
// Strip the prefix and relay to the aibridgeproxyd handler.
http.StripPrefix("/api/v2/aibridge/proxy", api.aibridgeproxydHandler).ServeHTTP(rw, r)
http.StripPrefix(stripPrefix, api.aibridgeproxydHandler).ServeHTTP(rw, r)
})
}
}