feat: add custom AI provider icons and instance-based model picker grouping (#27026)

This commit is contained in:
Danielle Maywood
2026-07-06 23:00:09 +01:00
committed by GitHub
parent 581f906947
commit d51762440b
53 changed files with 543 additions and 165 deletions
+1
View File
@@ -59,6 +59,7 @@ func AIProvider(row database.AIProvider, keys []database.AIProviderKey) (codersd
Type: codersdk.AIProviderType(row.Type),
Name: row.Name,
DisplayName: display,
Icon: row.Icon,
Enabled: row.Enabled,
BaseURL: row.BaseUrl,
APIKeys: maskAIProviderKeys(keys),
+2
View File
@@ -6848,6 +6848,7 @@ func (s *MethodTestSuite) TestAIBridge() {
ID: uuid.New(),
Type: database.AIProviderTypeOpenai,
Name: "test-provider",
Icon: "",
Enabled: true,
BaseUrl: "https://api.example.com/",
}
@@ -6860,6 +6861,7 @@ func (s *MethodTestSuite) TestAIBridge() {
arg := database.UpdateAIProviderParams{
ID: provider.ID,
Type: provider.Type,
Icon: provider.Icon,
Enabled: true,
BaseUrl: "https://api.example.com/",
}
+1
View File
@@ -221,6 +221,7 @@ func AIProvider(t testing.TB, db database.Store, seed database.AIProvider, munge
Type: provType,
Name: name,
DisplayName: displayName,
Icon: seed.Icon,
Enabled: takeFirst(seed.Enabled, true),
// Use an unsupported scheme so leaked test provider calls fail immediately without retries.
BaseUrl: takeFirst(seed.BaseUrl, "invalid://test.invalid/"),
+1
View File
@@ -1495,6 +1495,7 @@ CREATE TABLE ai_providers (
settings_key_id text,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
icon text DEFAULT ''::text NOT NULL,
CONSTRAINT ai_providers_name_check CHECK ((name ~ '^[a-z0-9]+(-[a-z0-9]+)*$'::text))
);
@@ -0,0 +1,2 @@
ALTER TABLE ai_providers
DROP COLUMN icon;
@@ -0,0 +1,2 @@
ALTER TABLE ai_providers
ADD COLUMN icon text NOT NULL DEFAULT '';
+1
View File
@@ -4657,6 +4657,7 @@ type AIProvider struct {
SettingsKeyID sql.NullString `db:"settings_key_id" json:"settings_key_id"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
Icon string `db:"icon" json:"icon"`
}
// API keys associated with AI providers. Bedrock providers have zero keys (they authenticate via settings). OpenAI and Anthropic providers have one or more keys for failover.
+29 -15
View File
@@ -571,7 +571,7 @@ func (q *sqlQuerier) DeleteAIProviderByID(ctx context.Context, id uuid.UUID) err
const getAIProviderByID = `-- name: GetAIProviderByID :one
SELECT
id, type, name, display_name, enabled, deleted, base_url, settings, settings_key_id, created_at, updated_at
id, type, name, display_name, enabled, deleted, base_url, settings, settings_key_id, created_at, updated_at, icon
FROM
ai_providers
WHERE
@@ -593,13 +593,14 @@ func (q *sqlQuerier) GetAIProviderByID(ctx context.Context, id uuid.UUID) (AIPro
&i.SettingsKeyID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Icon,
)
return i, err
}
const getAIProviderByIDForReferenceLock = `-- name: GetAIProviderByIDForReferenceLock :one
SELECT
id, type, name, display_name, enabled, deleted, base_url, settings, settings_key_id, created_at, updated_at
id, type, name, display_name, enabled, deleted, base_url, settings, settings_key_id, created_at, updated_at, icon
FROM
ai_providers
WHERE
@@ -625,13 +626,14 @@ func (q *sqlQuerier) GetAIProviderByIDForReferenceLock(ctx context.Context, id u
&i.SettingsKeyID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Icon,
)
return i, err
}
const getAIProviderByName = `-- name: GetAIProviderByName :one
SELECT
id, type, name, display_name, enabled, deleted, base_url, settings, settings_key_id, created_at, updated_at
id, type, name, display_name, enabled, deleted, base_url, settings, settings_key_id, created_at, updated_at, icon
FROM
ai_providers
WHERE
@@ -653,13 +655,14 @@ func (q *sqlQuerier) GetAIProviderByName(ctx context.Context, name string) (AIPr
&i.SettingsKeyID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Icon,
)
return i, err
}
const getAIProviders = `-- name: GetAIProviders :many
SELECT
id, type, name, display_name, enabled, deleted, base_url, settings, settings_key_id, created_at, updated_at
id, type, name, display_name, enabled, deleted, base_url, settings, settings_key_id, created_at, updated_at, icon
FROM
ai_providers
WHERE
@@ -697,6 +700,7 @@ func (q *sqlQuerier) GetAIProviders(ctx context.Context, arg GetAIProvidersParam
&i.SettingsKeyID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Icon,
); err != nil {
return nil, err
}
@@ -717,6 +721,7 @@ INSERT INTO ai_providers (
type,
name,
display_name,
icon,
enabled,
base_url,
settings,
@@ -726,13 +731,14 @@ INSERT INTO ai_providers (
$2::ai_provider_type,
$3::text,
$4::text,
$5::boolean,
$6::text,
$5::text,
$6::boolean,
$7::text,
$8::text
$8::text,
$9::text
)
RETURNING
id, type, name, display_name, enabled, deleted, base_url, settings, settings_key_id, created_at, updated_at
id, type, name, display_name, enabled, deleted, base_url, settings, settings_key_id, created_at, updated_at, icon
`
type InsertAIProviderParams struct {
@@ -740,6 +746,7 @@ type InsertAIProviderParams struct {
Type AIProviderType `db:"type" json:"type"`
Name string `db:"name" json:"name"`
DisplayName sql.NullString `db:"display_name" json:"display_name"`
Icon string `db:"icon" json:"icon"`
Enabled bool `db:"enabled" json:"enabled"`
BaseUrl string `db:"base_url" json:"base_url"`
Settings sql.NullString `db:"settings" json:"settings"`
@@ -752,6 +759,7 @@ func (q *sqlQuerier) InsertAIProvider(ctx context.Context, arg InsertAIProviderP
arg.Type,
arg.Name,
arg.DisplayName,
arg.Icon,
arg.Enabled,
arg.BaseUrl,
arg.Settings,
@@ -770,6 +778,7 @@ func (q *sqlQuerier) InsertAIProvider(ctx context.Context, arg InsertAIProviderP
&i.SettingsKeyID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Icon,
)
return i, err
}
@@ -780,20 +789,22 @@ UPDATE
SET
type = $1::ai_provider_type,
display_name = $2::text,
enabled = $3::boolean,
base_url = $4::text,
settings = $5::text,
settings_key_id = $6::text,
icon = $3::text,
enabled = $4::boolean,
base_url = $5::text,
settings = $6::text,
settings_key_id = $7::text,
updated_at = NOW()
WHERE
id = $7::uuid AND deleted = FALSE
id = $8::uuid AND deleted = FALSE
RETURNING
id, type, name, display_name, enabled, deleted, base_url, settings, settings_key_id, created_at, updated_at
id, type, name, display_name, enabled, deleted, base_url, settings, settings_key_id, created_at, updated_at, icon
`
type UpdateAIProviderParams struct {
Type AIProviderType `db:"type" json:"type"`
DisplayName sql.NullString `db:"display_name" json:"display_name"`
Icon string `db:"icon" json:"icon"`
Enabled bool `db:"enabled" json:"enabled"`
BaseUrl string `db:"base_url" json:"base_url"`
Settings sql.NullString `db:"settings" json:"settings"`
@@ -805,6 +816,7 @@ func (q *sqlQuerier) UpdateAIProvider(ctx context.Context, arg UpdateAIProviderP
row := q.db.QueryRowContext(ctx, updateAIProvider,
arg.Type,
arg.DisplayName,
arg.Icon,
arg.Enabled,
arg.BaseUrl,
arg.Settings,
@@ -824,6 +836,7 @@ func (q *sqlQuerier) UpdateAIProvider(ctx context.Context, arg UpdateAIProviderP
&i.SettingsKeyID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Icon,
)
return i, err
}
@@ -838,7 +851,7 @@ SET
WHERE
id = $3::uuid
RETURNING
id, type, name, display_name, enabled, deleted, base_url, settings, settings_key_id, created_at, updated_at
id, type, name, display_name, enabled, deleted, base_url, settings, settings_key_id, created_at, updated_at, icon
`
type UpdateEncryptedAIProviderSettingsParams struct {
@@ -866,6 +879,7 @@ func (q *sqlQuerier) UpdateEncryptedAIProviderSettings(ctx context.Context, arg
&i.SettingsKeyID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Icon,
)
return i, err
}
+3
View File
@@ -45,6 +45,7 @@ INSERT INTO ai_providers (
type,
name,
display_name,
icon,
enabled,
base_url,
settings,
@@ -54,6 +55,7 @@ INSERT INTO ai_providers (
@type::ai_provider_type,
@name::text,
sqlc.narg('display_name')::text,
@icon::text,
@enabled::boolean,
@base_url::text,
sqlc.narg('settings')::text,
@@ -68,6 +70,7 @@ UPDATE
SET
type = @type::ai_provider_type,
display_name = sqlc.narg('display_name')::text,
icon = @icon::text,
enabled = @enabled::boolean,
base_url = @base_url::text,
settings = sqlc.narg('settings')::text,