mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
tmp-commit
This commit is contained in:
@@ -14,11 +14,11 @@ import (
|
||||
// AIGatewayKey is a shared secret used by a standalone AI Gateway
|
||||
// to authenticate into coderd.
|
||||
type AIGatewayKey struct {
|
||||
ID uuid.UUID `json:"id" format:"uuid"`
|
||||
Name string `json:"name"`
|
||||
KeyPrefix string `json:"key_prefix"`
|
||||
CreatedAt time.Time `json:"created_at" format:"date-time"`
|
||||
LastUsedAt *time.Time `json:"last_used_at,omitempty" format:"date-time"`
|
||||
ID uuid.UUID `json:"id" table:"id" format:"uuid"`
|
||||
Name string `json:"name" table:"name,default_sort"`
|
||||
KeyPrefix string `json:"key_prefix" table:"key prefix"`
|
||||
CreatedAt time.Time `json:"created_at" table:"created at" format:"date-time"`
|
||||
LastUsedAt *time.Time `json:"last_used_at,omitempty" table:"last used at" format:"date-time"`
|
||||
}
|
||||
|
||||
// CreateAIGatewayKeyRequest requests a new AI Gateway key.
|
||||
|
||||
Generated
+16
@@ -0,0 +1,16 @@
|
||||
<!-- DO NOT EDIT | GENERATED CONTENT -->
|
||||
# ai
|
||||
|
||||
Manage AI features.
|
||||
|
||||
## Usage
|
||||
|
||||
```console
|
||||
coder ai
|
||||
```
|
||||
|
||||
## Subcommands
|
||||
|
||||
| Name | Purpose |
|
||||
|-----------------------------------------|--------------------|
|
||||
| [<code>gateway</code>](./ai_gateway.md) | Manage AI Gateway. |
|
||||
Generated
+16
@@ -0,0 +1,16 @@
|
||||
<!-- DO NOT EDIT | GENERATED CONTENT -->
|
||||
# ai gateway
|
||||
|
||||
Manage AI Gateway.
|
||||
|
||||
## Usage
|
||||
|
||||
```console
|
||||
coder ai gateway
|
||||
```
|
||||
|
||||
## Subcommands
|
||||
|
||||
| Name | Purpose |
|
||||
|-------------------------------------------|-------------------------|
|
||||
| [<code>keys</code>](./ai_gateway_keys.md) | Manage AI Gateway keys. |
|
||||
Generated
+18
@@ -0,0 +1,18 @@
|
||||
<!-- DO NOT EDIT | GENERATED CONTENT -->
|
||||
# ai gateway keys
|
||||
|
||||
Manage AI Gateway keys.
|
||||
|
||||
## Usage
|
||||
|
||||
```console
|
||||
coder ai gateway keys
|
||||
```
|
||||
|
||||
## Subcommands
|
||||
|
||||
| Name | Purpose |
|
||||
|----------------------------------------------------|--------------------------|
|
||||
| [<code>create</code>](./ai_gateway_keys_create.md) | Create an AI Gateway key |
|
||||
| [<code>delete</code>](./ai_gateway_keys_delete.md) | Delete an AI Gateway key |
|
||||
| [<code>list</code>](./ai_gateway_keys_list.md) | List AI Gateway keys |
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<!-- DO NOT EDIT | GENERATED CONTENT -->
|
||||
# ai gateway keys create
|
||||
|
||||
Create an AI Gateway key
|
||||
|
||||
## Usage
|
||||
|
||||
```console
|
||||
coder ai gateway keys create <name>
|
||||
```
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<!-- DO NOT EDIT | GENERATED CONTENT -->
|
||||
# ai gateway keys delete
|
||||
|
||||
Delete an AI Gateway key
|
||||
|
||||
Aliases:
|
||||
|
||||
* rm
|
||||
|
||||
## Usage
|
||||
|
||||
```console
|
||||
coder ai gateway keys delete [flags] <id>
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### -y, --yes
|
||||
|
||||
| | |
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass confirmation prompts.
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
<!-- DO NOT EDIT | GENERATED CONTENT -->
|
||||
# ai gateway keys list
|
||||
|
||||
List AI Gateway keys
|
||||
|
||||
## Usage
|
||||
|
||||
```console
|
||||
coder ai gateway keys list [flags]
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### -c, --column
|
||||
|
||||
| | |
|
||||
|---------|---------------------------------------------------------------|
|
||||
| Type | <code>[id\|name\|key prefix\|created at\|last used at]</code> |
|
||||
| Default | <code>id,name,key prefix,last used at,created at</code> |
|
||||
|
||||
Columns to display in table output.
|
||||
|
||||
### -o, --output
|
||||
|
||||
| | |
|
||||
|---------|--------------------------|
|
||||
| Type | <code>table\|json</code> |
|
||||
| Default | <code>table</code> |
|
||||
|
||||
Output format.
|
||||
Generated
+7
-6
@@ -66,13 +66,14 @@ Coder — A tool for provisioning self-hosted development environments with Terr
|
||||
| [<code>support</code>](./support.md) | Commands for troubleshooting issues with a Coder deployment. |
|
||||
| [<code>server</code>](./server.md) | Start a Coder server |
|
||||
| [<code>provisioner</code>](./provisioner.md) | View and manage provisioner daemons and jobs |
|
||||
| [<code>boundary</code>](./boundary.md) | Network isolation tool for monitoring and restricting HTTP/HTTPS requests |
|
||||
| [<code>features</code>](./features.md) | List Enterprise features |
|
||||
| [<code>licenses</code>](./licenses.md) | Add, delete, and list licenses |
|
||||
| [<code>groups</code>](./groups.md) | Manage groups |
|
||||
| [<code>prebuilds</code>](./prebuilds.md) | Manage Coder prebuilds |
|
||||
| [<code>external-workspaces</code>](./external-workspaces.md) | Create or manage external workspaces |
|
||||
| [<code>ai</code>](./ai.md) | Manage AI features. |
|
||||
| [<code>aibridge</code>](./aibridge.md) | Manage AI Bridge. |
|
||||
| [<code>boundary</code>](./boundary.md) | Network isolation tool for monitoring and restricting HTTP/HTTPS requests |
|
||||
| [<code>external-workspaces</code>](./external-workspaces.md) | Create or manage external workspaces |
|
||||
| [<code>features</code>](./features.md) | List Enterprise features |
|
||||
| [<code>groups</code>](./groups.md) | Manage groups |
|
||||
| [<code>licenses</code>](./licenses.md) | Add, delete, and list licenses |
|
||||
| [<code>prebuilds</code>](./prebuilds.md) | Manage Coder prebuilds |
|
||||
|
||||
## Options
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package cli
|
||||
|
||||
import "github.com/coder/serpent"
|
||||
|
||||
func (r *RootCmd) ai() *serpent.Command {
|
||||
return &serpent.Command{
|
||||
Use: "ai",
|
||||
Short: "Manage AI features.",
|
||||
Handler: func(inv *serpent.Invocation) error {
|
||||
return inv.Command.HelpHandler(inv)
|
||||
},
|
||||
Children: []*serpent.Command{
|
||||
r.aiGateway(),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/v2/cli/cliui"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/serpent"
|
||||
)
|
||||
|
||||
func (r *RootCmd) aiGateway() *serpent.Command {
|
||||
return &serpent.Command{
|
||||
Use: "gateway",
|
||||
Short: "Manage AI Gateway.",
|
||||
Handler: func(inv *serpent.Invocation) error {
|
||||
return inv.Command.HelpHandler(inv)
|
||||
},
|
||||
Children: []*serpent.Command{
|
||||
r.aiGatewayKeys(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RootCmd) aiGatewayKeys() *serpent.Command {
|
||||
return &serpent.Command{
|
||||
Use: "keys",
|
||||
Short: "Manage AI Gateway keys.",
|
||||
Handler: func(inv *serpent.Invocation) error {
|
||||
return inv.Command.HelpHandler(inv)
|
||||
},
|
||||
Children: []*serpent.Command{
|
||||
r.aiGatewayKeysCreate(),
|
||||
r.aiGatewayKeysDelete(),
|
||||
r.aiGatewayKeysList(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RootCmd) aiGatewayKeysCreate() *serpent.Command {
|
||||
return &serpent.Command{
|
||||
Use: "create <name>",
|
||||
Short: "Create an AI Gateway key",
|
||||
Middleware: serpent.Chain(
|
||||
serpent.RequireNArgs(1),
|
||||
),
|
||||
Handler: func(inv *serpent.Invocation) error {
|
||||
client, err := r.InitClient(inv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := client.CreateAIGatewayCoderdKey(inv.Context(), codersdk.CreateAIGatewayCoderdKeyRequest{
|
||||
Name: inv.Args[0],
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create AI Gateway key %q: %w", inv.Args[0], err)
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(
|
||||
inv.Stdout,
|
||||
"Successfully created AI Gateway key %s (ID: %s, Prefix: %s).\nSave this authentication token, it will not be shown again.\n\n%s\n",
|
||||
cliui.Keyword(res.Name),
|
||||
res.ID,
|
||||
res.KeyPrefix,
|
||||
cliui.Keyword(res.Key),
|
||||
)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RootCmd) aiGatewayKeysList() *serpent.Command {
|
||||
formatter := cliui.NewOutputFormatter(
|
||||
cliui.TableFormat([]codersdk.AIGatewayCoderdKey{}, []string{"id", "name", "key prefix", "last used at", "created at"}),
|
||||
cliui.JSONFormat(),
|
||||
)
|
||||
|
||||
cmd := &serpent.Command{
|
||||
Use: "list",
|
||||
Short: "List AI Gateway keys",
|
||||
Middleware: serpent.Chain(
|
||||
serpent.RequireNArgs(0),
|
||||
),
|
||||
Handler: func(inv *serpent.Invocation) error {
|
||||
client, err := r.InitClient(inv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keys, err := client.ListAIGatewayCoderdKeys(inv.Context())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("list AI Gateway keys: %w", err)
|
||||
}
|
||||
|
||||
out, err := formatter.Format(inv.Context(), keys)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("format AI Gateway keys: %w", err)
|
||||
}
|
||||
if out == "" {
|
||||
cliui.Info(inv.Stderr, "No AI Gateway keys found.")
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = fmt.Fprintln(inv.Stdout, out)
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
formatter.AttachOptions(&cmd.Options)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (r *RootCmd) aiGatewayKeysDelete() *serpent.Command {
|
||||
cmd := &serpent.Command{
|
||||
Use: "delete <id>",
|
||||
Short: "Delete an AI Gateway key",
|
||||
Middleware: serpent.Chain(
|
||||
serpent.RequireNArgs(1),
|
||||
),
|
||||
Options: serpent.OptionSet{
|
||||
cliui.SkipPromptOption(),
|
||||
},
|
||||
Handler: func(inv *serpent.Invocation) error {
|
||||
client, err := r.InitClient(inv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
key, err := aiGatewayKeyByNameOrID(inv.Context(), client, inv.Args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = cliui.Prompt(inv, cliui.PromptOptions{
|
||||
Text: fmt.Sprintf("Are you sure you want to delete AI Gateway key %s (ID: %s, Prefix: %s)?", cliui.Keyword(key.Name), key.ID, key.KeyPrefix),
|
||||
IsConfirm: true,
|
||||
Default: cliui.ConfirmNo,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = client.DeleteAIGatewayCoderdKey(inv.Context(), key.ID)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("delete AI Gateway key %q: %w", key.Name, err)
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(inv.Stdout, "Deleted AI Gateway key %s at %s.\n", cliui.Keyword(key.Name), cliui.Timestamp(time.Now()))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func aiGatewayKeyByNameOrID(ctx context.Context, client *codersdk.Client, nameOrID string) (codersdk.AIGatewayCoderdKey, error) {
|
||||
keys, err := client.ListAIGatewayCoderdKeys(ctx)
|
||||
if err != nil {
|
||||
return codersdk.AIGatewayCoderdKey{}, xerrors.Errorf("list AI Gateway keys: %w", err)
|
||||
}
|
||||
|
||||
for _, key := range keys {
|
||||
if key.ID.String() == nameOrID {
|
||||
return key, nil
|
||||
}
|
||||
}
|
||||
for _, key := range keys {
|
||||
if key.Name == nameOrID {
|
||||
return key, nil
|
||||
}
|
||||
}
|
||||
|
||||
return codersdk.AIGatewayCoderdKey{}, xerrors.Errorf("AI Gateway key %q not found", nameOrID)
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/v2/cli/clitest"
|
||||
"github.com/coder/coder/v2/coderd/coderdtest"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/enterprise/coderd/coderdenttest"
|
||||
"github.com/coder/coder/v2/enterprise/coderd/license"
|
||||
"github.com/coder/coder/v2/testutil"
|
||||
)
|
||||
|
||||
func TestAIGatewayKeys(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dv := coderdtest.DeploymentValues(t)
|
||||
dv.AI.BridgeConfig.Enabled = true
|
||||
ownerClient, owner := coderdenttest.New(t, &coderdenttest.Options{
|
||||
Options: &coderdtest.Options{
|
||||
DeploymentValues: dv,
|
||||
},
|
||||
LicenseOptions: &coderdenttest.LicenseOptions{
|
||||
Features: license.Features{
|
||||
codersdk.FeatureAIBridge: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
t.Run("CRUD", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
|
||||
// List returns empty when no keys exist.
|
||||
inv, root := newCLI(t, "ai", "gateway", "keys", "list")
|
||||
clitest.SetupConfig(t, ownerClient, root)
|
||||
out := bytes.NewBuffer(nil)
|
||||
stderr := bytes.NewBuffer(nil)
|
||||
inv.Stdout = out
|
||||
inv.Stderr = stderr
|
||||
|
||||
err := inv.WithContext(ctx).Run()
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, out.String())
|
||||
require.Contains(t, stderr.String(), "No AI Gateway keys found.")
|
||||
|
||||
// Create two keys and capture their IDs and prefixes from output.
|
||||
keyNames := []string{"gateway-key-a", "gateway-key-b"}
|
||||
createRe := regexp.MustCompile(`ID: ([0-9a-f-]+), Prefix: (\S+)\)`)
|
||||
type createdKey struct {
|
||||
id uuid.UUID
|
||||
prefix string
|
||||
}
|
||||
created := make([]createdKey, 0, len(keyNames))
|
||||
for _, name := range keyNames {
|
||||
inv, root = newCLI(t, "ai", "gateway", "keys", "create", name)
|
||||
clitest.SetupConfig(t, ownerClient, root)
|
||||
out = bytes.NewBuffer(nil)
|
||||
inv.Stdout = out
|
||||
|
||||
err = inv.WithContext(ctx).Run()
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, out.String(), "Successfully created AI Gateway key "+name)
|
||||
|
||||
matches := createRe.FindStringSubmatch(out.String())
|
||||
require.Len(t, matches, 3, "expected ID and Prefix in create output")
|
||||
id, err := uuid.Parse(matches[1])
|
||||
require.NoError(t, err)
|
||||
created = append(created, createdKey{id: id, prefix: matches[2]})
|
||||
}
|
||||
|
||||
// List returns both created keys as JSON with matching IDs and prefixes.
|
||||
inv, root = newCLI(t, "ai", "gateway", "keys", "list", "--output=json")
|
||||
clitest.SetupConfig(t, ownerClient, root)
|
||||
out = bytes.NewBuffer(nil)
|
||||
inv.Stdout = out
|
||||
|
||||
err = inv.WithContext(ctx).Run()
|
||||
require.NoError(t, err)
|
||||
|
||||
var listed []codersdk.AIGatewayCoderdKey
|
||||
require.NoError(t, json.Unmarshal(out.Bytes(), &listed))
|
||||
require.Len(t, listed, 2)
|
||||
for i, key := range listed {
|
||||
require.Equal(t, keyNames[i], key.Name)
|
||||
require.Equal(t, created[i].id, key.ID)
|
||||
require.Equal(t, created[i].prefix, key.KeyPrefix)
|
||||
}
|
||||
|
||||
// Delete the first key by name.
|
||||
inv, root = newCLI(t, "ai", "gateway", "keys", "delete", "--yes", keyNames[0])
|
||||
clitest.SetupConfig(t, ownerClient, root)
|
||||
out = bytes.NewBuffer(nil)
|
||||
inv.Stdout = out
|
||||
|
||||
err = inv.WithContext(ctx).Run()
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, out.String(), "Deleted AI Gateway key "+keyNames[0])
|
||||
|
||||
// List returns only the remaining key.
|
||||
inv, root = newCLI(t, "ai", "gateway", "keys", "list", "--output=json")
|
||||
clitest.SetupConfig(t, ownerClient, root)
|
||||
out = bytes.NewBuffer(nil)
|
||||
inv.Stdout = out
|
||||
|
||||
err = inv.WithContext(ctx).Run()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, json.Unmarshal(out.Bytes(), &listed))
|
||||
require.Len(t, listed, 1)
|
||||
require.Equal(t, keyNames[1], listed[0].Name)
|
||||
|
||||
// Delete the second key.
|
||||
inv, root = newCLI(t, "ai", "gateway", "keys", "delete", "--yes", keyNames[1])
|
||||
clitest.SetupConfig(t, ownerClient, root)
|
||||
|
||||
err = inv.WithContext(ctx).Run()
|
||||
require.NoError(t, err)
|
||||
|
||||
// List returns empty after all keys deleted.
|
||||
inv, root = newCLI(t, "ai", "gateway", "keys", "list", "--output=json")
|
||||
clitest.SetupConfig(t, ownerClient, root)
|
||||
out = bytes.NewBuffer(nil)
|
||||
inv.Stdout = out
|
||||
|
||||
err = inv.WithContext(ctx).Run()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, json.Unmarshal(out.Bytes(), &listed))
|
||||
require.Empty(t, listed)
|
||||
|
||||
// Delete a non-existent key returns not found.
|
||||
missingID := uuid.New()
|
||||
inv, root = newCLI(t, "ai", "gateway", "keys", "delete", "--yes", missingID.String())
|
||||
clitest.SetupConfig(t, ownerClient, root)
|
||||
|
||||
err = inv.WithContext(ctx).Run()
|
||||
require.ErrorContains(t, err, missingID.String())
|
||||
require.ErrorContains(t, err, "not found")
|
||||
})
|
||||
|
||||
t.Run("InvalidKeyName", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
|
||||
inv, root := newCLI(t, "ai", "gateway", "keys", "create", strings.Repeat("a", 65))
|
||||
clitest.SetupConfig(t, ownerClient, root)
|
||||
|
||||
err := inv.WithContext(ctx).Run()
|
||||
require.ErrorContains(t, err, "create AI Gateway key")
|
||||
require.ErrorContains(t, err, "Invalid key name")
|
||||
})
|
||||
|
||||
t.Run("MemberForbidden", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
|
||||
memberClient, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID)
|
||||
|
||||
for _, args := range [][]string{
|
||||
{"ai", "gateway", "keys", "list"},
|
||||
{"ai", "gateway", "keys", "create", "member-key"},
|
||||
{"ai", "gateway", "keys", "delete", "--yes", uuid.NewString()},
|
||||
} {
|
||||
inv, root := newCLI(t, args...)
|
||||
clitest.SetupConfig(t, memberClient, root)
|
||||
|
||||
err := inv.WithContext(ctx).Run()
|
||||
require.Error(t, err)
|
||||
require.ErrorContains(t, err, "Forbidden")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -18,15 +18,16 @@ func (r *RootCmd) enterpriseOnly() []*serpent.Command {
|
||||
agplcli.ExperimentalCommand(append(r.AGPLExperimental(), r.enterpriseExperimental()...)),
|
||||
|
||||
// New commands that don't exist in AGPL:
|
||||
r.ai(),
|
||||
r.aibridge(),
|
||||
r.boundary(),
|
||||
r.workspaceProxy(),
|
||||
r.externalWorkspaces(),
|
||||
r.features(),
|
||||
r.licenses(),
|
||||
r.groups(),
|
||||
r.licenses(),
|
||||
r.prebuilds(),
|
||||
r.provisionerd(),
|
||||
r.externalWorkspaces(),
|
||||
r.aibridge(),
|
||||
r.workspaceProxy(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -14,6 +14,7 @@ USAGE:
|
||||
$ coder templates init
|
||||
|
||||
SUBCOMMANDS:
|
||||
ai Manage AI features.
|
||||
aibridge Manage AI Bridge.
|
||||
boundary Network isolation tool for monitoring and restricting
|
||||
HTTP/HTTPS requests
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
coder v0.0.0-devel
|
||||
|
||||
USAGE:
|
||||
coder ai
|
||||
|
||||
Manage AI features.
|
||||
|
||||
SUBCOMMANDS:
|
||||
gateway Manage AI Gateway.
|
||||
|
||||
———
|
||||
Run `coder --help` for a list of global options.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
Generated
Vendored
+2
-2
@@ -33,11 +33,11 @@
|
||||
"schema_version": 1,
|
||||
"values": {
|
||||
"access_port": 443,
|
||||
"access_url": "https://dev.coder.com/",
|
||||
"access_url": "https://mydeployment.coder.com",
|
||||
"id": "f8c4851f-dcbd-48bc-9a14-3fd506f8f015",
|
||||
"is_prebuild": false,
|
||||
"is_prebuild_claim": false,
|
||||
"name": "ai-task-plan-check",
|
||||
"name": "default",
|
||||
"prebuild_count": 0,
|
||||
"start_count": 1,
|
||||
"template_id": "",
|
||||
|
||||
Reference in New Issue
Block a user