diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go
index a280e5e7c4..86eea40d2c 100644
--- a/coderd/apidoc/docs.go
+++ b/coderd/apidoc/docs.go
@@ -1434,10 +1434,7 @@ const docTemplate = `{
{
"CoderSessionToken": []
}
- ],
- "x-apidocgen": {
- "skip": true
- }
+ ]
},
"post": {
"consumes": [
@@ -1474,10 +1471,7 @@ const docTemplate = `{
{
"CoderSessionToken": []
}
- ],
- "x-apidocgen": {
- "skip": true
- }
+ ]
}
},
"/api/v2/ai-gateway/keys/{key}": {
@@ -1506,10 +1500,7 @@ const docTemplate = `{
{
"CoderSessionToken": []
}
- ],
- "x-apidocgen": {
- "skip": true
- }
+ ]
}
},
"/api/v2/ai-gateway/models": {
@@ -1557,10 +1548,7 @@ const docTemplate = `{
{
"AIGatewayKey": []
}
- ],
- "x-apidocgen": {
- "skip": true
- }
+ ]
}
},
"/api/v2/ai-gateway/sessions": {
diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json
index 5eaa93a980..d30e6894da 100644
--- a/coderd/apidoc/swagger.json
+++ b/coderd/apidoc/swagger.json
@@ -1269,10 +1269,7 @@
{
"CoderSessionToken": []
}
- ],
- "x-apidocgen": {
- "skip": true
- }
+ ]
},
"post": {
"consumes": ["application/json"],
@@ -1303,10 +1300,7 @@
{
"CoderSessionToken": []
}
- ],
- "x-apidocgen": {
- "skip": true
- }
+ ]
}
},
"/api/v2/ai-gateway/keys/{key}": {
@@ -1333,10 +1327,7 @@
{
"CoderSessionToken": []
}
- ],
- "x-apidocgen": {
- "skip": true
- }
+ ]
}
},
"/api/v2/ai-gateway/models": {
@@ -1378,10 +1369,7 @@
{
"AIGatewayKey": []
}
- ],
- "x-apidocgen": {
- "skip": true
- }
+ ]
}
},
"/api/v2/ai-gateway/sessions": {
diff --git a/docs/reference/api/enterprise.md b/docs/reference/api/enterprise.md
index 9823449008..f631241229 100644
--- a/docs/reference/api/enterprise.md
+++ b/docs/reference/api/enterprise.md
@@ -178,6 +178,152 @@ curl -X GET http://coder-server:8080/api/v2/agent-firewall/sessions/{id}/logs \
To perform this operation, you must be authenticated. [Learn more](authentication.md).
+## List AI Gateway keys
+
+### Code samples
+
+```shell
+# Example request using curl
+curl -X GET http://coder-server:8080/api/v2/ai-gateway/keys \
+ -H 'Accept: application/json' \
+ -H 'Coder-Session-Token: API_KEY'
+```
+
+`GET /api/v2/ai-gateway/keys`
+
+### Example responses
+
+> 200 Response
+
+```json
+[
+ {
+ "created_at": "2019-08-24T14:15:22Z",
+ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "key_prefix": "string",
+ "last_heartbeat_at": "2019-08-24T14:15:22Z",
+ "name": "string"
+ }
+]
+```
+
+### Responses
+
+| Status | Meaning | Description | Schema |
+|--------|---------------------------------------------------------|-------------|-------------------------------------------------------------------|
+| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | array of [codersdk.AIGatewayKey](schemas.md#codersdkaigatewaykey) |
+
+
Response Schema
+
+Status Code **200**
+
+| Name | Type | Required | Restrictions | Description |
+|-----------------------|-------------------|----------|--------------|-------------|
+| `[array item]` | array | false | | |
+| `» created_at` | string(date-time) | false | | |
+| `» id` | string(uuid) | false | | |
+| `» key_prefix` | string | false | | |
+| `» last_heartbeat_at` | string(date-time) | false | | |
+| `» name` | string | false | | |
+
+To perform this operation, you must be authenticated. [Learn more](authentication.md).
+
+## Create AI Gateway key
+
+### Code samples
+
+```shell
+# Example request using curl
+curl -X POST http://coder-server:8080/api/v2/ai-gateway/keys \
+ -H 'Content-Type: application/json' \
+ -H 'Accept: application/json' \
+ -H 'Coder-Session-Token: API_KEY'
+```
+
+`POST /api/v2/ai-gateway/keys`
+
+> Body parameter
+
+```json
+{
+ "name": "string"
+}
+```
+
+### Parameters
+
+| Name | In | Type | Required | Description |
+|--------|------|------------------------------------------------------------------------------------|----------|-------------------------------|
+| `body` | body | [codersdk.CreateAIGatewayKeyRequest](schemas.md#codersdkcreateaigatewaykeyrequest) | true | Create AI Gateway key request |
+
+### Example responses
+
+> 201 Response
+
+```json
+{
+ "created_at": "2019-08-24T14:15:22Z",
+ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "key": "string",
+ "key_prefix": "string",
+ "name": "string"
+}
+```
+
+### Responses
+
+| Status | Meaning | Description | Schema |
+|--------|--------------------------------------------------------------|-------------|--------------------------------------------------------------------------------------|
+| 201 | [Created](https://tools.ietf.org/html/rfc7231#section-6.3.2) | Created | [codersdk.CreateAIGatewayKeyResponse](schemas.md#codersdkcreateaigatewaykeyresponse) |
+
+To perform this operation, you must be authenticated. [Learn more](authentication.md).
+
+## Delete AI Gateway key
+
+### Code samples
+
+```shell
+# Example request using curl
+curl -X DELETE http://coder-server:8080/api/v2/ai-gateway/keys/{key} \
+ -H 'Coder-Session-Token: API_KEY'
+```
+
+`DELETE /api/v2/ai-gateway/keys/{key}`
+
+### Parameters
+
+| Name | In | Type | Required | Description |
+|-------|------|--------------|----------|-------------|
+| `key` | path | string(uuid) | true | Key ID |
+
+### Responses
+
+| Status | Meaning | Description | Schema |
+|--------|-----------------------------------------------------------------|-------------|--------|
+| 204 | [No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5) | No Content | |
+
+To perform this operation, you must be authenticated. [Learn more](authentication.md).
+
+## AI Gateway serve
+
+### Code samples
+
+```shell
+# Example request using curl
+curl -X GET http://coder-server:8080/api/v2/ai-gateway/serve \
+ -H 'X-AI-Governance-Gateway-Key: API_KEY'
+```
+
+`GET /api/v2/ai-gateway/serve`
+
+### Responses
+
+| Status | Meaning | Description | Schema |
+|--------|--------------------------------------------------------------------------|---------------------|--------|
+| 101 | [Switching Protocols](https://tools.ietf.org/html/rfc7231#section-6.2.2) | Switching Protocols | |
+
+To perform this operation, you must be authenticated. [Learn more](authentication.md).
+
## Get appearance
### Code samples
diff --git a/docs/reference/cli/index.md b/docs/reference/cli/index.md
index a25269fd06..218cffa7db 100644
--- a/docs/reference/cli/index.md
+++ b/docs/reference/cli/index.md
@@ -66,6 +66,7 @@ Coder — A tool for provisioning self-hosted development environments with Terr
| [support](./support.md) | Commands for troubleshooting issues with a Coder deployment. |
| [server](./server.md) | Start a Coder server |
| [provisioner](./provisioner.md) | View and manage provisioner daemons and jobs |
+| [ai-gateway](./ai-gateway.md) | Manage AI Gateway |
| [agent-firewall](./agent-firewall.md) | Network isolation tool for monitoring and restricting HTTP/HTTPS requests |
| [features](./features.md) | List Enterprise features |
| [licenses](./licenses.md) | Add, delete, and list licenses |
diff --git a/enterprise/cli/aigateway.go b/enterprise/cli/aigateway.go
index 11aae44a57..2844ef43dc 100644
--- a/enterprise/cli/aigateway.go
+++ b/enterprise/cli/aigateway.go
@@ -14,9 +14,8 @@ import (
func (r *RootCmd) aiGateway() *serpent.Command {
return &serpent.Command{
- Use: "ai-gateway",
- Short: "Manage AI Gateway",
- Hidden: true,
+ Use: "ai-gateway",
+ Short: "Manage AI Gateway",
Handler: func(inv *serpent.Invocation) error {
return inv.Command.HelpHandler(inv)
},
diff --git a/enterprise/cli/testdata/coder_--help.golden b/enterprise/cli/testdata/coder_--help.golden
index 4e392a8dd6..c9e3b53168 100644
--- a/enterprise/cli/testdata/coder_--help.golden
+++ b/enterprise/cli/testdata/coder_--help.golden
@@ -16,6 +16,7 @@ USAGE:
SUBCOMMANDS:
agent-firewall Network isolation tool for monitoring and restricting
HTTP/HTTPS requests
+ ai-gateway Manage AI Gateway
external-workspaces Create or manage external workspaces
features List Enterprise features
groups Manage groups
diff --git a/enterprise/cli/testdata/coder_ai-gateway_--help.golden b/enterprise/cli/testdata/coder_ai-gateway_--help.golden
new file mode 100644
index 0000000000..2c0d35058b
--- /dev/null
+++ b/enterprise/cli/testdata/coder_ai-gateway_--help.golden
@@ -0,0 +1,12 @@
+coder v0.0.0-devel
+
+USAGE:
+ coder ai-gateway
+
+ Manage AI Gateway
+
+SUBCOMMANDS:
+ keys Manage AI Gateway keys
+
+———
+Run `coder --help` for a list of global options.
diff --git a/enterprise/cli/testdata/coder_ai-gateway_keys_--help.golden b/enterprise/cli/testdata/coder_ai-gateway_keys_--help.golden
new file mode 100644
index 0000000000..8c465b07b2
--- /dev/null
+++ b/enterprise/cli/testdata/coder_ai-gateway_keys_--help.golden
@@ -0,0 +1,14 @@
+coder v0.0.0-devel
+
+USAGE:
+ coder ai-gateway keys
+
+ Manage AI Gateway keys
+
+SUBCOMMANDS:
+ create Create an AI Gateway key
+ delete Delete an AI Gateway key
+ list List AI Gateway keys
+
+———
+Run `coder --help` for a list of global options.
diff --git a/enterprise/cli/testdata/coder_ai-gateway_keys_create_--help.golden b/enterprise/cli/testdata/coder_ai-gateway_keys_create_--help.golden
new file mode 100644
index 0000000000..bcaa7cd6d1
--- /dev/null
+++ b/enterprise/cli/testdata/coder_ai-gateway_keys_create_--help.golden
@@ -0,0 +1,9 @@
+coder v0.0.0-devel
+
+USAGE:
+ coder ai-gateway keys create
+
+ Create an AI Gateway key
+
+———
+Run `coder --help` for a list of global options.
diff --git a/enterprise/cli/testdata/coder_ai-gateway_keys_delete_--help.golden b/enterprise/cli/testdata/coder_ai-gateway_keys_delete_--help.golden
new file mode 100644
index 0000000000..62b0db207a
--- /dev/null
+++ b/enterprise/cli/testdata/coder_ai-gateway_keys_delete_--help.golden
@@ -0,0 +1,15 @@
+coder v0.0.0-devel
+
+USAGE:
+ coder ai-gateway keys delete [flags]
+
+ Delete an AI Gateway key
+
+ Aliases: rm
+
+OPTIONS:
+ -y, --yes bool
+ Bypass confirmation prompts.
+
+———
+Run `coder --help` for a list of global options.
diff --git a/enterprise/cli/testdata/coder_ai-gateway_keys_list_--help.golden b/enterprise/cli/testdata/coder_ai-gateway_keys_list_--help.golden
new file mode 100644
index 0000000000..f922806ded
--- /dev/null
+++ b/enterprise/cli/testdata/coder_ai-gateway_keys_list_--help.golden
@@ -0,0 +1,18 @@
+coder v0.0.0-devel
+
+USAGE:
+ coder ai-gateway keys list [flags]
+
+ List AI Gateway keys
+
+ Aliases: ls
+
+OPTIONS:
+ -c, --column [id|name|key prefix|created at|last heartbeat at] (default: id,name,key prefix,last heartbeat at,created at)
+ Columns to display in table output.
+
+ -o, --output table|json (default: table)
+ Output format.
+
+———
+Run `coder --help` for a list of global options.
diff --git a/enterprise/coderd/aibridgeserve.go b/enterprise/coderd/aibridgeserve.go
index 562dd539cb..f2f9fcc54d 100644
--- a/enterprise/coderd/aibridgeserve.go
+++ b/enterprise/coderd/aibridgeserve.go
@@ -42,7 +42,6 @@ const aiGatewayKeyHeartbeatInterval = 60 * time.Second
// @Tags Enterprise
// @Success 101
// @Router /api/v2/ai-gateway/serve [get]
-// @x-apidocgen {"skip": true}
func (api *API) aiGatewayServe(rw http.ResponseWriter, r *http.Request) {
key := r.Header.Get(codersdk.AIGatewayKeyHeader)
if key == "" {
diff --git a/enterprise/coderd/aigatewaykeys.go b/enterprise/coderd/aigatewaykeys.go
index d7032a32a5..30815f9bdc 100644
--- a/enterprise/coderd/aigatewaykeys.go
+++ b/enterprise/coderd/aigatewaykeys.go
@@ -29,7 +29,6 @@ const nameFormatDetail = "Must be 64 characters or fewer, lowercase letters, num
// @Param request body codersdk.CreateAIGatewayKeyRequest true "Create AI Gateway key request"
// @Success 201 {object} codersdk.CreateAIGatewayKeyResponse
// @Router /api/v2/ai-gateway/keys [post]
-// @x-apidocgen {"skip": true}
func (api *API) postAIGatewayKey(rw http.ResponseWriter, r *http.Request) {
var (
ctx = r.Context()
@@ -118,7 +117,6 @@ func writeKeyInsertError(ctx context.Context, rw http.ResponseWriter, err error)
// @Tags Enterprise
// @Success 200 {array} codersdk.AIGatewayKey
// @Router /api/v2/ai-gateway/keys [get]
-// @x-apidocgen {"skip": true}
func (api *API) aiGatewayKeys(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
@@ -149,7 +147,6 @@ func (api *API) aiGatewayKeys(rw http.ResponseWriter, r *http.Request) {
// @Param key path string true "Key ID" format(uuid)
// @Success 204
// @Router /api/v2/ai-gateway/keys/{key} [delete]
-// @x-apidocgen {"skip": true}
func (api *API) deleteAIGatewayKey(rw http.ResponseWriter, r *http.Request) {
var (
ctx = r.Context()
diff --git a/site/src/modules/management/AISettingsSidebarView.tsx b/site/src/modules/management/AISettingsSidebarView.tsx
index c9502b61c2..875055f047 100644
--- a/site/src/modules/management/AISettingsSidebarView.tsx
+++ b/site/src/modules/management/AISettingsSidebarView.tsx
@@ -42,6 +42,11 @@ const AISettingsSidebarView: FC = ({
AI Governance
)}
+ {permissions.viewAIGatewayKeys && (
+
+ AI Gateway keys
+
+ )}
{permissions.viewAnyAIProvider && (
Providers
diff --git a/site/src/router.tsx b/site/src/router.tsx
index b83be153a9..c3fd85d72e 100644
--- a/site/src/router.tsx
+++ b/site/src/router.tsx
@@ -434,7 +434,7 @@ const AISettingsAddProviderPage = lazy(
"./pages/AISettingsPage/ProvidersPage/AddProviderPage/AddProviderPage"
),
);
-const _AISettingsGatewayKeysPage = lazy(
+const AISettingsGatewayKeysPage = lazy(
() => import("./pages/AISettingsPage/GatewayKeysPage/GatewayKeysPage"),
);
const AISettingsModelsPage = lazy(
@@ -476,6 +476,10 @@ const AISettingsIndexRedirect = () => {
return ;
}
+ if (permissions.viewAIGatewayKeys) {
+ return ;
+ }
+
if (permissions.editDeploymentConfig) {
return ;
}
@@ -756,6 +760,10 @@ export const router = createBrowserRouter(
}>
} />
+ }
+ />
} />
} />
} />