Changeset 0.8.6 (#49)
This commit is contained in:
@@ -64,10 +64,10 @@ func (h *APIConfigHandler) ListConfigs(c *gin.Context) {
|
||||
userID := getUserID(c)
|
||||
page, perPage, offset := parsePagination(c)
|
||||
|
||||
// Count: user's configs + global configs
|
||||
// Count: user's configs + global configs (exclude team-scoped)
|
||||
var total int
|
||||
err := database.DB.QueryRow(
|
||||
`SELECT COUNT(*) FROM api_configs WHERE user_id = $1 OR user_id IS NULL`,
|
||||
`SELECT COUNT(*) FROM api_configs WHERE (user_id = $1 OR user_id IS NULL) AND team_id IS NULL`,
|
||||
userID,
|
||||
).Scan(&total)
|
||||
if err != nil {
|
||||
@@ -79,7 +79,7 @@ func (h *APIConfigHandler) ListConfigs(c *gin.Context) {
|
||||
SELECT id, user_id, name, provider, endpoint, api_key_encrypted,
|
||||
model_default, config, is_active, created_at, updated_at
|
||||
FROM api_configs
|
||||
WHERE user_id = $1 OR user_id IS NULL
|
||||
WHERE (user_id = $1 OR user_id IS NULL) AND team_id IS NULL
|
||||
ORDER BY user_id NULLS LAST, name ASC
|
||||
LIMIT $2 OFFSET $3
|
||||
`, userID, perPage, offset)
|
||||
@@ -169,7 +169,7 @@ func (h *APIConfigHandler) GetConfig(c *gin.Context) {
|
||||
SELECT id, user_id, name, provider, endpoint, api_key_encrypted,
|
||||
model_default, config::text, is_active, created_at, updated_at
|
||||
FROM api_configs
|
||||
WHERE id = $1 AND (user_id = $2 OR user_id IS NULL)
|
||||
WHERE id = $1 AND (user_id = $2 OR user_id IS NULL) AND team_id IS NULL
|
||||
`, configID, userID)
|
||||
|
||||
var cfg apiConfigResponse
|
||||
@@ -310,7 +310,7 @@ func (h *APIConfigHandler) ListModels(c *gin.Context) {
|
||||
err := database.DB.QueryRow(`
|
||||
SELECT provider, endpoint, api_key_encrypted
|
||||
FROM api_configs
|
||||
WHERE id = $1 AND (user_id = $2 OR user_id IS NULL) AND is_active = true
|
||||
WHERE id = $1 AND (user_id = $2 OR user_id IS NULL) AND team_id IS NULL AND is_active = true
|
||||
`, configID, userID).Scan(&providerID, &endpoint, &apiKey)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
@@ -357,7 +357,7 @@ func (h *APIConfigHandler) ListAllModels(c *gin.Context) {
|
||||
rows, err := database.DB.Query(`
|
||||
SELECT id, name, provider, endpoint, api_key_encrypted
|
||||
FROM api_configs
|
||||
WHERE (user_id = $1 OR user_id IS NULL) AND is_active = true
|
||||
WHERE (user_id = $1 OR user_id IS NULL) AND is_active = true AND team_id IS NULL
|
||||
`, userID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list configs"})
|
||||
@@ -422,26 +422,29 @@ func (h *APIConfigHandler) ListAllModels(c *gin.Context) {
|
||||
|
||||
// ── List Enabled Models (from model_configs) ─
|
||||
|
||||
// enabledModel is the unified model entry returned by ListEnabledModels.
|
||||
// Used across apiconfigs, capabilities, and preset resolution.
|
||||
type enabledModel struct {
|
||||
ID string `json:"id"`
|
||||
ModelID string `json:"model_id"`
|
||||
DisplayName *string `json:"display_name"`
|
||||
Provider string `json:"provider"`
|
||||
ProviderName string `json:"provider_name"`
|
||||
ConfigID string `json:"config_id"`
|
||||
Capabilities providers.ModelCapabilities `json:"capabilities"`
|
||||
Pricing *providers.ModelPricing `json:"pricing,omitempty"`
|
||||
Source string `json:"source,omitempty"`
|
||||
TeamName string `json:"team_name,omitempty"`
|
||||
IsPreset bool `json:"is_preset,omitempty"`
|
||||
PresetID string `json:"preset_id,omitempty"`
|
||||
PresetScope string `json:"preset_scope,omitempty"`
|
||||
PresetAvatar string `json:"preset_avatar,omitempty"`
|
||||
PresetTeamName string `json:"preset_team_name,omitempty"`
|
||||
}
|
||||
|
||||
func (h *APIConfigHandler) ListEnabledModels(c *gin.Context) {
|
||||
userID := getUserID(c)
|
||||
|
||||
type enabledModel struct {
|
||||
ID string `json:"id"`
|
||||
ModelID string `json:"model_id"`
|
||||
DisplayName *string `json:"display_name"`
|
||||
Provider string `json:"provider"`
|
||||
ProviderName string `json:"provider_name"`
|
||||
ConfigID string `json:"config_id"`
|
||||
Capabilities providers.ModelCapabilities `json:"capabilities"`
|
||||
Pricing *providers.ModelPricing `json:"pricing,omitempty"`
|
||||
Source string `json:"source,omitempty"`
|
||||
IsPreset bool `json:"is_preset,omitempty"`
|
||||
PresetID string `json:"preset_id,omitempty"`
|
||||
PresetScope string `json:"preset_scope,omitempty"`
|
||||
PresetAvatar string `json:"preset_avatar,omitempty"`
|
||||
PresetTeamName string `json:"preset_team_name,omitempty"`
|
||||
}
|
||||
|
||||
models := make([]enabledModel, 0)
|
||||
|
||||
// ── 1. Admin model_configs (pre-synced via FetchModels) ──
|
||||
@@ -449,7 +452,7 @@ func (h *APIConfigHandler) ListEnabledModels(c *gin.Context) {
|
||||
SELECT mc.id, mc.model_id, mc.display_name, ac.provider, ac.name, mc.api_config_id, mc.capabilities
|
||||
FROM model_configs mc
|
||||
JOIN api_configs ac ON mc.api_config_id = ac.id
|
||||
WHERE mc.visibility = 'enabled' AND ac.is_active = true AND ac.user_id IS NULL
|
||||
WHERE mc.visibility = 'enabled' AND ac.is_active = true AND ac.is_global = true
|
||||
ORDER BY ac.name, mc.model_id
|
||||
`)
|
||||
if err == nil {
|
||||
@@ -484,10 +487,13 @@ func (h *APIConfigHandler) ListEnabledModels(c *gin.Context) {
|
||||
}
|
||||
|
||||
// ── 2. User provider models (live query) ──
|
||||
// NOTE: Team provider models are NOT listed here. They are only
|
||||
// available to team admins for building presets (via ListAvailableModels).
|
||||
// Team members access team models through curated presets only.
|
||||
userRows, err := database.DB.Query(`
|
||||
SELECT id, name, provider, endpoint, api_key_encrypted, custom_headers
|
||||
FROM api_configs
|
||||
WHERE user_id = $1 AND is_active = true
|
||||
WHERE user_id = $1 AND is_active = true AND team_id IS NULL
|
||||
`, userID)
|
||||
if err == nil {
|
||||
defer userRows.Close()
|
||||
@@ -574,41 +580,12 @@ func (h *APIConfigHandler) ListEnabledModels(c *gin.Context) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Inherit capabilities from the base model already loaded in sections 1/2
|
||||
var caps providers.ModelCapabilities
|
||||
capsFound := false
|
||||
for _, existing := range models {
|
||||
if existing.ModelID == baseModelID {
|
||||
caps = existing.Capabilities
|
||||
capsFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !capsFound {
|
||||
// Base model not in enabled list — try synced model_configs
|
||||
var capsJSON []byte
|
||||
err := database.DB.QueryRow(`
|
||||
SELECT capabilities FROM model_configs
|
||||
WHERE model_id = $1 ORDER BY updated_at DESC LIMIT 1
|
||||
`, baseModelID).Scan(&capsJSON)
|
||||
if err == nil && len(capsJSON) > 0 {
|
||||
_ = json.Unmarshal(capsJSON, &caps)
|
||||
capsFound = true
|
||||
}
|
||||
}
|
||||
if !capsFound {
|
||||
var found bool
|
||||
caps, found = providers.LookupKnownModel(baseModelID)
|
||||
if !found {
|
||||
caps = providers.InferCapabilities(baseModelID)
|
||||
}
|
||||
}
|
||||
caps.MaxOutputTokens = providers.ResolveMaxOutput(baseModelID, caps)
|
||||
|
||||
// Inherit capabilities from base model via shared resolver
|
||||
cfgID := ""
|
||||
if apiConfigID != nil {
|
||||
cfgID = *apiConfigID
|
||||
}
|
||||
caps := ResolveModelCapsFromLoaded(c, baseModelID, cfgID, models)
|
||||
|
||||
// Build display name: "icon Name (base-model)"
|
||||
displayName := name
|
||||
@@ -665,3 +642,5 @@ func parseJSONBConfig(raw string) map[string]interface{} {
|
||||
_ = json.Unmarshal([]byte(raw), &result)
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user