mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
refactor: drop chat_model_configs provider column (#26877)
The provider type already lives authoritatively in ai_providers.type, reachable on every active row through ai_provider_id, which the chat_model_configs_ai_provider_required_when_active CHECK makes mandatory. The stored provider string was a denormalized copy the system kept in sync with a startup backfill and no longer needs. Every surface now derives provider type from the linked ai_providers row. Telemetry is the one exception: it keeps emitting provider, now sourced from ai_providers.type via a JOIN, so the BigQuery column and the Nexus dashboards that read it are unaffected. The experimental HTTP/SDK response drops provider and makes ai_provider_id required, since those endpoints return only active configs; consumers resolve provider type from ai_provider_id and the AI providers listing. This ships in a single release with no compatibility window: production reads the table via SELECT *, so a pre-drop binary fails config reads the moment the column is gone. Operators must scale to zero before upgrading, and there is no rollback. Closes CODAGT-599
This commit is contained in:
Generated
+65
-114
@@ -5025,37 +5025,6 @@ func (q *sqlQuerier) InsertChatFile(ctx context.Context, arg InsertChatFileParam
|
||||
return i, err
|
||||
}
|
||||
|
||||
const backfillChatModelConfigProvider = `-- name: BackfillChatModelConfigProvider :execresult
|
||||
UPDATE
|
||||
chat_model_configs
|
||||
SET
|
||||
provider = $1::text,
|
||||
updated_at = NOW()
|
||||
WHERE
|
||||
provider = $2::text
|
||||
AND deleted = FALSE
|
||||
AND ai_provider_id IS NOT NULL
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM ai_providers
|
||||
WHERE id = chat_model_configs.ai_provider_id
|
||||
AND type = $1::ai_provider_type
|
||||
AND deleted = FALSE
|
||||
)
|
||||
`
|
||||
|
||||
type BackfillChatModelConfigProviderParams struct {
|
||||
NewProvider string `db:"new_provider" json:"new_provider"`
|
||||
OldProvider string `db:"old_provider" json:"old_provider"`
|
||||
}
|
||||
|
||||
// old_provider is matched as text; new_provider is also cast to ai_provider_type
|
||||
// for the EXISTS check against ai_providers.type.
|
||||
// ai_provider_id IS NOT NULL is defensive; the check constraint already
|
||||
// enforces that non-deleted rows always have a provider ID.
|
||||
func (q *sqlQuerier) BackfillChatModelConfigProvider(ctx context.Context, arg BackfillChatModelConfigProviderParams) (sql.Result, error) {
|
||||
return q.db.ExecContext(ctx, backfillChatModelConfigProvider, arg.NewProvider, arg.OldProvider)
|
||||
}
|
||||
|
||||
const deleteChatModelConfigByID = `-- name: DeleteChatModelConfigByID :exec
|
||||
UPDATE
|
||||
chat_model_configs
|
||||
@@ -5089,26 +5058,9 @@ func (q *sqlQuerier) DeleteChatModelConfigsByAIProviderID(ctx context.Context, a
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteChatModelConfigsByProvider = `-- name: DeleteChatModelConfigsByProvider :exec
|
||||
UPDATE
|
||||
chat_model_configs
|
||||
SET
|
||||
deleted = TRUE,
|
||||
deleted_at = NOW(),
|
||||
updated_at = NOW()
|
||||
WHERE
|
||||
provider = $1::text
|
||||
AND deleted = FALSE
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) DeleteChatModelConfigsByProvider(ctx context.Context, provider string) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteChatModelConfigsByProvider, provider)
|
||||
return err
|
||||
}
|
||||
|
||||
const getChatModelConfigByID = `-- name: GetChatModelConfigByID :one
|
||||
SELECT
|
||||
id, provider, model, display_name, created_by, updated_by, enabled, is_default, deleted, deleted_at, created_at, updated_at, context_limit, compression_threshold, options, ai_provider_id
|
||||
id, model, display_name, created_by, updated_by, enabled, is_default, deleted, deleted_at, created_at, updated_at, context_limit, compression_threshold, options, ai_provider_id
|
||||
FROM
|
||||
chat_model_configs
|
||||
WHERE
|
||||
@@ -5121,7 +5073,6 @@ func (q *sqlQuerier) GetChatModelConfigByID(ctx context.Context, id uuid.UUID) (
|
||||
var i ChatModelConfig
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Provider,
|
||||
&i.Model,
|
||||
&i.DisplayName,
|
||||
&i.CreatedBy,
|
||||
@@ -5142,16 +5093,18 @@ func (q *sqlQuerier) GetChatModelConfigByID(ctx context.Context, id uuid.UUID) (
|
||||
|
||||
const getChatModelConfigs = `-- name: GetChatModelConfigs :many
|
||||
SELECT
|
||||
id, provider, model, display_name, created_by, updated_by, enabled, is_default, deleted, deleted_at, created_at, updated_at, context_limit, compression_threshold, options, ai_provider_id
|
||||
cmc.id, cmc.model, cmc.display_name, cmc.created_by, cmc.updated_by, cmc.enabled, cmc.is_default, cmc.deleted, cmc.deleted_at, cmc.created_at, cmc.updated_at, cmc.context_limit, cmc.compression_threshold, cmc.options, cmc.ai_provider_id
|
||||
FROM
|
||||
chat_model_configs
|
||||
chat_model_configs cmc
|
||||
LEFT JOIN
|
||||
ai_providers ap ON ap.id = cmc.ai_provider_id
|
||||
WHERE
|
||||
deleted = FALSE
|
||||
cmc.deleted = FALSE
|
||||
ORDER BY
|
||||
provider ASC,
|
||||
model ASC,
|
||||
updated_at DESC,
|
||||
id DESC
|
||||
ap.type::text ASC,
|
||||
cmc.model ASC,
|
||||
cmc.updated_at DESC,
|
||||
cmc.id DESC
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetChatModelConfigs(ctx context.Context) ([]ChatModelConfig, error) {
|
||||
@@ -5165,7 +5118,6 @@ func (q *sqlQuerier) GetChatModelConfigs(ctx context.Context) ([]ChatModelConfig
|
||||
var i ChatModelConfig
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.Provider,
|
||||
&i.Model,
|
||||
&i.DisplayName,
|
||||
&i.CreatedBy,
|
||||
@@ -5196,7 +5148,7 @@ func (q *sqlQuerier) GetChatModelConfigs(ctx context.Context) ([]ChatModelConfig
|
||||
|
||||
const getDefaultChatModelConfig = `-- name: GetDefaultChatModelConfig :one
|
||||
SELECT
|
||||
id, provider, model, display_name, created_by, updated_by, enabled, is_default, deleted, deleted_at, created_at, updated_at, context_limit, compression_threshold, options, ai_provider_id
|
||||
id, model, display_name, created_by, updated_by, enabled, is_default, deleted, deleted_at, created_at, updated_at, context_limit, compression_threshold, options, ai_provider_id
|
||||
FROM
|
||||
chat_model_configs
|
||||
WHERE
|
||||
@@ -5209,7 +5161,6 @@ func (q *sqlQuerier) GetDefaultChatModelConfig(ctx context.Context) (ChatModelCo
|
||||
var i ChatModelConfig
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Provider,
|
||||
&i.Model,
|
||||
&i.DisplayName,
|
||||
&i.CreatedBy,
|
||||
@@ -5230,7 +5181,7 @@ func (q *sqlQuerier) GetDefaultChatModelConfig(ctx context.Context) (ChatModelCo
|
||||
|
||||
const getEnabledChatModelConfigByID = `-- name: GetEnabledChatModelConfigByID :one
|
||||
SELECT
|
||||
cmc.id, cmc.provider, cmc.model, cmc.display_name, cmc.created_by, cmc.updated_by, cmc.enabled, cmc.is_default, cmc.deleted, cmc.deleted_at, cmc.created_at, cmc.updated_at, cmc.context_limit, cmc.compression_threshold, cmc.options, cmc.ai_provider_id
|
||||
cmc.id, cmc.model, cmc.display_name, cmc.created_by, cmc.updated_by, cmc.enabled, cmc.is_default, cmc.deleted, cmc.deleted_at, cmc.created_at, cmc.updated_at, cmc.context_limit, cmc.compression_threshold, cmc.options, cmc.ai_provider_id
|
||||
FROM
|
||||
chat_model_configs cmc
|
||||
JOIN
|
||||
@@ -5250,7 +5201,6 @@ func (q *sqlQuerier) GetEnabledChatModelConfigByID(ctx context.Context, id uuid.
|
||||
var i ChatModelConfig
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Provider,
|
||||
&i.Model,
|
||||
&i.DisplayName,
|
||||
&i.CreatedBy,
|
||||
@@ -5271,7 +5221,8 @@ func (q *sqlQuerier) GetEnabledChatModelConfigByID(ctx context.Context, id uuid.
|
||||
|
||||
const getEnabledChatModelConfigs = `-- name: GetEnabledChatModelConfigs :many
|
||||
SELECT
|
||||
cmc.id, cmc.provider, cmc.model, cmc.display_name, cmc.created_by, cmc.updated_by, cmc.enabled, cmc.is_default, cmc.deleted, cmc.deleted_at, cmc.created_at, cmc.updated_at, cmc.context_limit, cmc.compression_threshold, cmc.options, cmc.ai_provider_id
|
||||
cmc.id, cmc.model, cmc.display_name, cmc.created_by, cmc.updated_by, cmc.enabled, cmc.is_default, cmc.deleted, cmc.deleted_at, cmc.created_at, cmc.updated_at, cmc.context_limit, cmc.compression_threshold, cmc.options, cmc.ai_provider_id,
|
||||
ap.type::text AS provider
|
||||
FROM
|
||||
chat_model_configs cmc
|
||||
JOIN
|
||||
@@ -5282,38 +5233,43 @@ WHERE
|
||||
AND ap.enabled = TRUE
|
||||
AND ap.deleted = FALSE
|
||||
ORDER BY
|
||||
cmc.provider ASC,
|
||||
ap.type::text ASC,
|
||||
cmc.model ASC,
|
||||
cmc.updated_at DESC,
|
||||
cmc.id DESC
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetEnabledChatModelConfigs(ctx context.Context) ([]ChatModelConfig, error) {
|
||||
type GetEnabledChatModelConfigsRow struct {
|
||||
ChatModelConfig ChatModelConfig `db:"chat_model_config" json:"chat_model_config"`
|
||||
Provider string `db:"provider" json:"provider"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) GetEnabledChatModelConfigs(ctx context.Context) ([]GetEnabledChatModelConfigsRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getEnabledChatModelConfigs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ChatModelConfig
|
||||
var items []GetEnabledChatModelConfigsRow
|
||||
for rows.Next() {
|
||||
var i ChatModelConfig
|
||||
var i GetEnabledChatModelConfigsRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.ChatModelConfig.ID,
|
||||
&i.ChatModelConfig.Model,
|
||||
&i.ChatModelConfig.DisplayName,
|
||||
&i.ChatModelConfig.CreatedBy,
|
||||
&i.ChatModelConfig.UpdatedBy,
|
||||
&i.ChatModelConfig.Enabled,
|
||||
&i.ChatModelConfig.IsDefault,
|
||||
&i.ChatModelConfig.Deleted,
|
||||
&i.ChatModelConfig.DeletedAt,
|
||||
&i.ChatModelConfig.CreatedAt,
|
||||
&i.ChatModelConfig.UpdatedAt,
|
||||
&i.ChatModelConfig.ContextLimit,
|
||||
&i.ChatModelConfig.CompressionThreshold,
|
||||
&i.ChatModelConfig.Options,
|
||||
&i.ChatModelConfig.AIProviderID,
|
||||
&i.Provider,
|
||||
&i.Model,
|
||||
&i.DisplayName,
|
||||
&i.CreatedBy,
|
||||
&i.UpdatedBy,
|
||||
&i.Enabled,
|
||||
&i.IsDefault,
|
||||
&i.Deleted,
|
||||
&i.DeletedAt,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.ContextLimit,
|
||||
&i.CompressionThreshold,
|
||||
&i.Options,
|
||||
&i.AIProviderID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -5330,7 +5286,6 @@ func (q *sqlQuerier) GetEnabledChatModelConfigs(ctx context.Context) ([]ChatMode
|
||||
|
||||
const insertChatModelConfig = `-- name: InsertChatModelConfig :one
|
||||
INSERT INTO chat_model_configs (
|
||||
provider,
|
||||
model,
|
||||
display_name,
|
||||
created_by,
|
||||
@@ -5344,22 +5299,20 @@ INSERT INTO chat_model_configs (
|
||||
) VALUES (
|
||||
$1::text,
|
||||
$2::text,
|
||||
$3::text,
|
||||
$3::uuid,
|
||||
$4::uuid,
|
||||
$5::uuid,
|
||||
$5::boolean,
|
||||
$6::boolean,
|
||||
$7::boolean,
|
||||
$8::bigint,
|
||||
$9::integer,
|
||||
$10::jsonb,
|
||||
$11::uuid
|
||||
$7::bigint,
|
||||
$8::integer,
|
||||
$9::jsonb,
|
||||
$10::uuid
|
||||
)
|
||||
RETURNING
|
||||
id, provider, model, display_name, created_by, updated_by, enabled, is_default, deleted, deleted_at, created_at, updated_at, context_limit, compression_threshold, options, ai_provider_id
|
||||
id, model, display_name, created_by, updated_by, enabled, is_default, deleted, deleted_at, created_at, updated_at, context_limit, compression_threshold, options, ai_provider_id
|
||||
`
|
||||
|
||||
type InsertChatModelConfigParams struct {
|
||||
Provider string `db:"provider" json:"provider"`
|
||||
Model string `db:"model" json:"model"`
|
||||
DisplayName string `db:"display_name" json:"display_name"`
|
||||
CreatedBy uuid.NullUUID `db:"created_by" json:"created_by"`
|
||||
@@ -5374,7 +5327,6 @@ type InsertChatModelConfigParams struct {
|
||||
|
||||
func (q *sqlQuerier) InsertChatModelConfig(ctx context.Context, arg InsertChatModelConfigParams) (ChatModelConfig, error) {
|
||||
row := q.db.QueryRowContext(ctx, insertChatModelConfig,
|
||||
arg.Provider,
|
||||
arg.Model,
|
||||
arg.DisplayName,
|
||||
arg.CreatedBy,
|
||||
@@ -5389,7 +5341,6 @@ func (q *sqlQuerier) InsertChatModelConfig(ctx context.Context, arg InsertChatMo
|
||||
var i ChatModelConfig
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Provider,
|
||||
&i.Model,
|
||||
&i.DisplayName,
|
||||
&i.CreatedBy,
|
||||
@@ -5428,26 +5379,24 @@ const updateChatModelConfig = `-- name: UpdateChatModelConfig :one
|
||||
UPDATE
|
||||
chat_model_configs
|
||||
SET
|
||||
provider = $1::text,
|
||||
model = $2::text,
|
||||
display_name = $3::text,
|
||||
updated_by = $4::uuid,
|
||||
enabled = $5::boolean,
|
||||
is_default = $6::boolean,
|
||||
context_limit = $7::bigint,
|
||||
compression_threshold = $8::integer,
|
||||
options = $9::jsonb,
|
||||
ai_provider_id = $10::uuid,
|
||||
model = $1::text,
|
||||
display_name = $2::text,
|
||||
updated_by = $3::uuid,
|
||||
enabled = $4::boolean,
|
||||
is_default = $5::boolean,
|
||||
context_limit = $6::bigint,
|
||||
compression_threshold = $7::integer,
|
||||
options = $8::jsonb,
|
||||
ai_provider_id = $9::uuid,
|
||||
updated_at = NOW()
|
||||
WHERE
|
||||
id = $11::uuid
|
||||
id = $10::uuid
|
||||
AND deleted = FALSE
|
||||
RETURNING
|
||||
id, provider, model, display_name, created_by, updated_by, enabled, is_default, deleted, deleted_at, created_at, updated_at, context_limit, compression_threshold, options, ai_provider_id
|
||||
id, model, display_name, created_by, updated_by, enabled, is_default, deleted, deleted_at, created_at, updated_at, context_limit, compression_threshold, options, ai_provider_id
|
||||
`
|
||||
|
||||
type UpdateChatModelConfigParams struct {
|
||||
Provider string `db:"provider" json:"provider"`
|
||||
Model string `db:"model" json:"model"`
|
||||
DisplayName string `db:"display_name" json:"display_name"`
|
||||
UpdatedBy uuid.NullUUID `db:"updated_by" json:"updated_by"`
|
||||
@@ -5462,7 +5411,6 @@ type UpdateChatModelConfigParams struct {
|
||||
|
||||
func (q *sqlQuerier) UpdateChatModelConfig(ctx context.Context, arg UpdateChatModelConfigParams) (ChatModelConfig, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateChatModelConfig,
|
||||
arg.Provider,
|
||||
arg.Model,
|
||||
arg.DisplayName,
|
||||
arg.UpdatedBy,
|
||||
@@ -5477,7 +5425,6 @@ func (q *sqlQuerier) UpdateChatModelConfig(ctx context.Context, arg UpdateChatMo
|
||||
var i ChatModelConfig
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Provider,
|
||||
&i.Model,
|
||||
&i.DisplayName,
|
||||
&i.CreatedBy,
|
||||
@@ -6967,7 +6914,7 @@ const getChatCostPerModel = `-- name: GetChatCostPerModel :many
|
||||
SELECT
|
||||
cmc.id AS model_config_id,
|
||||
cmc.display_name,
|
||||
cmc.provider,
|
||||
COALESCE(ap.type::text, '')::text AS provider,
|
||||
cmc.model,
|
||||
COALESCE(SUM(cm.total_cost_micros), 0)::bigint AS total_cost_micros,
|
||||
COUNT(*) FILTER (
|
||||
@@ -6988,13 +6935,15 @@ JOIN
|
||||
chats c ON c.id = cm.chat_id
|
||||
JOIN
|
||||
chat_model_configs cmc ON cmc.id = cm.model_config_id
|
||||
LEFT JOIN
|
||||
ai_providers ap ON ap.id = cmc.ai_provider_id
|
||||
WHERE
|
||||
c.owner_id = $1::uuid
|
||||
AND cm.role = 'assistant'
|
||||
AND cm.created_at >= $2::timestamptz
|
||||
AND cm.created_at < $3::timestamptz
|
||||
GROUP BY
|
||||
cmc.id, cmc.display_name, cmc.provider, cmc.model
|
||||
cmc.id, cmc.display_name, ap.type, cmc.model
|
||||
ORDER BY
|
||||
total_cost_micros DESC
|
||||
`
|
||||
@@ -7960,9 +7909,10 @@ func (q *sqlQuerier) GetChatMessagesForPromptByChatID(ctx context.Context, chatI
|
||||
}
|
||||
|
||||
const getChatModelConfigsForTelemetry = `-- name: GetChatModelConfigsForTelemetry :many
|
||||
SELECT id, provider, model, context_limit, enabled, is_default
|
||||
FROM chat_model_configs
|
||||
WHERE deleted = false
|
||||
SELECT cmc.id, ap.type::text AS provider, cmc.model, cmc.context_limit, cmc.enabled, cmc.is_default
|
||||
FROM chat_model_configs cmc
|
||||
JOIN ai_providers ap ON ap.id = cmc.ai_provider_id
|
||||
WHERE cmc.deleted = false
|
||||
`
|
||||
|
||||
type GetChatModelConfigsForTelemetryRow struct {
|
||||
@@ -7975,6 +7925,7 @@ type GetChatModelConfigsForTelemetryRow struct {
|
||||
}
|
||||
|
||||
// Returns all model configurations for telemetry snapshot collection.
|
||||
// deleted = false guarantees ai_provider_id is non-null, so INNER JOIN is safe.
|
||||
func (q *sqlQuerier) GetChatModelConfigsForTelemetry(ctx context.Context) ([]GetChatModelConfigsForTelemetryRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getChatModelConfigsForTelemetry)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user