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
+4 -4
View File
@@ -54,7 +54,7 @@ func newMockUpstream(t *testing.T, name string) *mockUpstream {
// startTestAIBridgeDaemon wires an in-process aibridged daemon onto
// the supplied API and subscribes it to ai_providers change events.
// This mirrors what cli/server.go does in production so /api/v2/aibridge
// This mirrors what cli/server.go does in production so /api/v2/ai-gateway
// requests dispatch through the real pool and reloader.
func startTestAIBridgeDaemon(t *testing.T, api *coderd.API) *aibridged.Metrics {
t.Helper()
@@ -109,7 +109,7 @@ func (r *testPoolReloader) Reload(ctx context.Context) error {
// TestAIBridgeProviderHotReload exercises the end-to-end CRUD ->
// reload -> routing path: every provider mutation made through codersdk
// must, within a short window, change the routing observed at
// /api/v2/aibridge/{name}/v1/models. The OpenAI passthrough route
// /api/v2/ai-gateway/{name}/v1/models. The OpenAI passthrough route
// /v1/models reverse-proxies to BaseURL, so the upstream that responds
// identifies which provider the daemon's mux dispatched to.
func TestAIBridgeProviderHotReload(t *testing.T) {
@@ -162,11 +162,11 @@ func TestAIBridgeProviderHotReload(t *testing.T) {
ctx := testutil.Context(t, testutil.WaitLong)
// sendRequest issues GET /api/v2/aibridge/{name}/v1/models and
// sendRequest issues GET /api/v2/ai-gateway/{name}/v1/models and
// returns the status and the upstream marker decoded from the
// JSON body (empty if the body was not the marker JSON).
sendRequest := func(providerName string) (int, string) {
url := client.URL.String() + "/api/v2/aibridge/" + providerName + "/v1/models"
url := client.URL.String() + "/api/v2/ai-gateway/" + providerName + "/v1/models"
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
require.NoError(t, err)
req.Header.Set("Authorization", "Bearer "+client.SessionToken())