mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
refactor: load AI providers from the database at startup (#25672)
Replace the env-based `BuildProviders` with a DB-backed loader. The database is now the single source of truth for runtime provider configuration; env config arrives via `SeedAIProvidersFromEnv` (run at boot) and `BuildProviders` reads it back as `aibridge.Provider` instances. `cli/server.go` and `enterprise/cli/server.go` both call the same path, so aibridged and aibridgeproxyd see the same provider set. Per-provider `DumpDir` is replaced by a top-level `CODER_AI_GATEWAY_DUMP_DIR` base; each provider's effective dump path is `<base>/<provider name>`.
This commit is contained in:
+27
-19
@@ -899,6 +899,32 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
if err != nil {
|
||||
return xerrors.Errorf("remove secrets from deployment values: %w", err)
|
||||
}
|
||||
|
||||
// AI provider DB initialization runs synchronously here so
|
||||
// authorized reads complete before any background goroutine
|
||||
// starts. Otherwise a mid-startup cancellation can interrupt
|
||||
// them and fail startup. Seeding must also happen before
|
||||
// newAPI so the aibridgeproxyd in the enterprise closure
|
||||
// observes env-configured providers.
|
||||
//
|
||||
// This is a once-off operation; once completed, all providers
|
||||
// will be sourced from the database.
|
||||
if err := coderd.SeedAIProvidersFromEnv(
|
||||
ctx,
|
||||
options.Database,
|
||||
vals.AI.BridgeConfig,
|
||||
logger.Named("aibridge.envseed"),
|
||||
); err != nil {
|
||||
return xerrors.Errorf("seed ai providers from env: %w", err)
|
||||
}
|
||||
var aibridgeProviders []aibridge.Provider
|
||||
if vals.AI.BridgeConfig.Enabled.Value() {
|
||||
aibridgeProviders, err = BuildProviders(ctx, options.Database, vals.AI.BridgeConfig, logger.Named("aibridge.providers"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("build AI providers: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
telemetryReporter, err := telemetry.New(telemetry.Options{
|
||||
Disabled: !vals.Telemetry.Enable.Value(),
|
||||
BuiltinPostgres: builtinPostgres,
|
||||
@@ -1006,18 +1032,6 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
notificationReportGenerator := reports.NewReportGenerator(ctx, logger.Named("notifications.report_generator"), options.Database, options.NotificationsEnqueuer, quartz.NewReal())
|
||||
defer notificationReportGenerator.Close()
|
||||
|
||||
// Seed providers before newAPI so the aibridgeproxyd inside
|
||||
// the enterprise closure observes env-configured providers
|
||||
// at init.
|
||||
if err := coderd.SeedAIProvidersFromEnv(
|
||||
ctx,
|
||||
options.Database,
|
||||
vals.AI.BridgeConfig,
|
||||
logger.Named("aibridge.envseed"),
|
||||
); err != nil {
|
||||
return xerrors.Errorf("seed ai providers from env: %w", err)
|
||||
}
|
||||
|
||||
// We use a separate coderAPICloser so the Enterprise API
|
||||
// can have its own close functions. This is cleaner
|
||||
// than abstracting the Coder API itself.
|
||||
@@ -1034,11 +1048,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
// unconditionally when the bridge feature is enabled by config so
|
||||
// chatd can use it regardless of license entitlement.
|
||||
if vals.AI.BridgeConfig.Enabled.Value() {
|
||||
providers, err := BuildProviders(vals.AI.BridgeConfig)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("build AI providers: %w", err)
|
||||
}
|
||||
aibridgeDaemon, err := newAIBridgeDaemon(coderAPI, providers)
|
||||
aibridgeDaemon, err := newAIBridgeDaemon(coderAPI, aibridgeProviders)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create aibridged: %w", err)
|
||||
}
|
||||
@@ -3114,8 +3124,6 @@ func readAIProvidersForPrefix(logger slog.Logger, environ []string, prefix strin
|
||||
}
|
||||
case "BASE_URL":
|
||||
provider.BaseURL = v.Value
|
||||
case "DUMP_DIR":
|
||||
provider.DumpDir = v.Value
|
||||
case "BEDROCK_BASE_URL":
|
||||
provider.BedrockBaseURL = v.Value
|
||||
case "BEDROCK_REGION":
|
||||
|
||||
Reference in New Issue
Block a user