mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add ai-gateway start command (#26605)
> AI Tools were used to produce this PR This PR adds `coder ai-gateway start` command that runs the AI Gateway as an independent process. - Standalone process doesn't have access to DB. Uses DRPC services under `/api/v2/ai-gateway/serve`for auth, recording and provider initialization. - It only handles LLM traffic, other endpoints (eg. `/sessions`) are only available though `coderd`. - The standalone gateway reuses applicable flags from AI Gateway deployment options. Provider-seeding and coderd-only options are excluded. - Only added to fat build, the slim build stub rejects the command. Some wiring used by this new command is added. **`NewWebsocketDialer`** - implements the standalone gateway's connection to coderd's `/api/v2/ai-gateway/serve` endpoint. It upgrades to a WebSocket, multiplexes with yamux, and wires all DRPC services. **`AIGatewayDataPlaneMiddleware`** - extracts the per-request middleware chain (concurrency limiting, rate limiting, BYOK gating) into a shared function used by both the embedded route and the standalone gateway. **`RootCmd.ResolveClientConnection`** - resolve the deployment URL and builds an HTTP transport without requiring a session token. Used in `ai-gateway start`command as it authenticates using different credential type. --------- Co-authored-by: Danny Kopping <danny@coder.com>
This commit is contained in:
co-authored by
Danny Kopping
parent
195dffc651
commit
ccba3969ab
+47
-10
@@ -58,6 +58,8 @@ var (
|
||||
// anything.
|
||||
ErrSilent = xerrors.New("silent error")
|
||||
|
||||
ErrClientURLNotConfigured = xerrors.New("client URL is not configured")
|
||||
|
||||
errKeyringNotSupported = xerrors.New("keyring storage is not supported on this operating system; omit --use-keyring to use file-based storage")
|
||||
)
|
||||
|
||||
@@ -602,23 +604,58 @@ func (r *RootCmd) SetClock(clk quartz.Clock) {
|
||||
// ensureClientURL loads the client URL from the config file if it
|
||||
// wasn't provided via --url or CODER_URL.
|
||||
func (r *RootCmd) ensureClientURL() error {
|
||||
if r.clientURL != nil && r.clientURL.String() != "" {
|
||||
return nil
|
||||
}
|
||||
rawURL, err := r.createConfig().URL().Read()
|
||||
// If the configuration files are absent, the user is logged out.
|
||||
if os.IsNotExist(err) {
|
||||
binPath, err := os.Executable()
|
||||
if err != nil {
|
||||
u, err := r.resolveClientURL()
|
||||
|
||||
if errors.Is(err, ErrClientURLNotConfigured) {
|
||||
binPath, execErr := os.Executable()
|
||||
if execErr != nil {
|
||||
binPath = "coder"
|
||||
}
|
||||
return xerrors.Errorf(notLoggedInMessage, binPath)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.clientURL, err = url.Parse(strings.TrimSpace(rawURL))
|
||||
return err
|
||||
|
||||
r.clientURL = u
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RootCmd) resolveClientURL() (*url.URL, error) {
|
||||
if r.clientURL != nil && r.clientURL.String() != "" {
|
||||
return r.clientURL, nil
|
||||
}
|
||||
|
||||
rawURL, err := r.createConfig().URL().Read()
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return nil, ErrClientURLNotConfigured
|
||||
}
|
||||
return nil, xerrors.Errorf("read configured URL: %w", err)
|
||||
}
|
||||
parsedURL, err := url.Parse(strings.TrimSpace(rawURL))
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse configured URL: %w", err)
|
||||
}
|
||||
return parsedURL, nil
|
||||
}
|
||||
|
||||
// ResolveClientConnection resolves the deployment URL and client TLS transport
|
||||
// without reading or requiring a user session.
|
||||
func (r *RootCmd) ResolveClientConnection() (*url.URL, http.RoundTripper, error) {
|
||||
serverURL, err := r.resolveClientURL()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := r.ensureTLSConfig(); err != nil {
|
||||
return nil, nil, xerrors.Errorf("load client TLS config: %w", err)
|
||||
}
|
||||
transport, err := newHTTPTransport(r.tlsConfig)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("create HTTP transport: %w", err)
|
||||
}
|
||||
return serverURL, transport, nil
|
||||
}
|
||||
|
||||
// ensureTLSConfig loads the TLS configuration from files if specified.
|
||||
|
||||
Reference in New Issue
Block a user