Changeset 0.28.0.9 (#181)
This commit is contained in:
@@ -13,7 +13,6 @@ import (
|
||||
"git.gobha.me/xcaliber/chat-switchboard/database"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/health"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/models"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/providers"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/store"
|
||||
)
|
||||
|
||||
@@ -74,7 +73,7 @@ func (h *ModelHandler) ListEnabledModels(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"models": userModels, "default_model": defaultModel})
|
||||
c.JSON(http.StatusOK, gin.H{"data": userModels, "default_model": defaultModel})
|
||||
}
|
||||
|
||||
// buildHealthMap returns a map of configID → ProviderStatus from current health windows.
|
||||
@@ -147,52 +146,3 @@ func capsFromCatalog(modelID, configID string) (models.ModelCapabilities, bool)
|
||||
return resolved, true
|
||||
}
|
||||
|
||||
// liveQueryModelCaps queries a provider API to get capabilities for a specific model.
|
||||
func liveQueryModelCaps(c *gin.Context, configID, modelID string) (models.ModelCapabilities, bool) {
|
||||
if database.DB == nil {
|
||||
return models.ModelCapabilities{}, false
|
||||
}
|
||||
|
||||
var providerID, endpoint string
|
||||
var apiKey *string
|
||||
var headersJSON []byte
|
||||
err := database.DB.QueryRow(database.Q(`
|
||||
SELECT provider, endpoint, api_key_enc, headers
|
||||
FROM provider_configs WHERE id = $1 AND is_active = true
|
||||
`), configID).Scan(&providerID, &endpoint, &apiKey, &headersJSON)
|
||||
if err != nil {
|
||||
return models.ModelCapabilities{}, false
|
||||
}
|
||||
|
||||
provider, err := providers.Get(providerID)
|
||||
if err != nil {
|
||||
return models.ModelCapabilities{}, false
|
||||
}
|
||||
|
||||
key := ""
|
||||
if apiKey != nil {
|
||||
key = *apiKey
|
||||
}
|
||||
|
||||
var customHeaders map[string]string
|
||||
_ = json.Unmarshal(headersJSON, &customHeaders)
|
||||
|
||||
modelList, err := provider.ListModels(c.Request.Context(), providers.ProviderConfig{
|
||||
Endpoint: endpoint,
|
||||
APIKey: key,
|
||||
CustomHeaders: customHeaders,
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("[caps] live query for %s via config %s failed: %v", modelID, configID, err)
|
||||
return models.ModelCapabilities{}, false
|
||||
}
|
||||
|
||||
for _, m := range modelList {
|
||||
if m.ID == modelID {
|
||||
resolved := capspkg.ResolveIntrinsic(modelID, &m.Capabilities, nil)
|
||||
return resolved, true
|
||||
}
|
||||
}
|
||||
|
||||
return models.ModelCapabilities{}, false
|
||||
}
|
||||
|
||||
@@ -829,7 +829,7 @@ func TestIntegration_ModelVisibilityResolution(t *testing.T) {
|
||||
}
|
||||
var modelsResp map[string]interface{}
|
||||
decode(w, &modelsResp)
|
||||
modelsList := modelsResp["models"].([]interface{})
|
||||
modelsList := modelsResp["data"].([]interface{})
|
||||
if len(modelsList) != 0 {
|
||||
t.Errorf("disabled model should not appear, got %d models", len(modelsList))
|
||||
}
|
||||
@@ -849,7 +849,7 @@ func TestIntegration_ModelVisibilityResolution(t *testing.T) {
|
||||
t.Fatalf("models/enabled after enable: want 200, got %d: %s", w.Code, w.Body.String())
|
||||
}
|
||||
decode(w, &modelsResp)
|
||||
modelsList = modelsResp["models"].([]interface{})
|
||||
modelsList = modelsResp["data"].([]interface{})
|
||||
if len(modelsList) != 1 {
|
||||
t.Errorf("enabled model should appear, want 1 got %d", len(modelsList))
|
||||
}
|
||||
@@ -1163,13 +1163,13 @@ func TestIntegration_AdminModelFetchEnableUserSees(t *testing.T) {
|
||||
}
|
||||
var userResp map[string]interface{}
|
||||
decode(w, &userResp)
|
||||
userModels := userResp["models"].([]interface{})
|
||||
userModels := userResp["data"].([]interface{})
|
||||
if len(userModels) != 0 {
|
||||
t.Errorf("disabled models must not appear for user, got %d", len(userModels))
|
||||
}
|
||||
|
||||
// Verify user response is non-null array
|
||||
if userResp["models"] == nil {
|
||||
if userResp["data"] == nil {
|
||||
t.Fatal("user models must be [] not null — causes '📋 Loaded 0 models' to crash")
|
||||
}
|
||||
|
||||
@@ -1192,7 +1192,7 @@ func TestIntegration_AdminModelFetchEnableUserSees(t *testing.T) {
|
||||
t.Fatalf("user models/enabled after enable: want 200, got %d: %s", w.Code, w.Body.String())
|
||||
}
|
||||
decode(w, &userResp)
|
||||
userModels = userResp["models"].([]interface{})
|
||||
userModels = userResp["data"].([]interface{})
|
||||
if len(userModels) != 1 {
|
||||
t.Fatalf("user should see 1 enabled model, got %d", len(userModels))
|
||||
}
|
||||
@@ -1260,10 +1260,10 @@ func (h *testHarness) getModels(token string) []interface{} {
|
||||
}
|
||||
var resp map[string]interface{}
|
||||
decode(w, &resp)
|
||||
if resp["models"] == nil {
|
||||
if resp["data"] == nil {
|
||||
h.t.Fatal("models response must never be null")
|
||||
}
|
||||
return resp["models"].([]interface{})
|
||||
return resp["data"].([]interface{})
|
||||
}
|
||||
|
||||
func getModelIDs(models []interface{}) []string {
|
||||
|
||||
@@ -444,7 +444,7 @@ func TestLive_ProviderFullFlow(t *testing.T) {
|
||||
w = h.request("GET", "/api/v1/models/enabled", adminToken, nil)
|
||||
var enabledResp map[string]interface{}
|
||||
decode(w, &enabledResp)
|
||||
enabledModels := enabledResp["models"].([]interface{})
|
||||
enabledModels := enabledResp["data"].([]interface{})
|
||||
if len(enabledModels) < 1 {
|
||||
t.Fatal("models/enabled should return at least 1 model")
|
||||
}
|
||||
@@ -476,7 +476,7 @@ func TestLive_ProviderFullFlow(t *testing.T) {
|
||||
w = h.request("GET", "/api/v1/models/enabled", userToken, nil)
|
||||
var userResp map[string]interface{}
|
||||
decode(w, &userResp)
|
||||
userModels := userResp["models"].([]interface{})
|
||||
userModels := userResp["data"].([]interface{})
|
||||
if len(userModels) < 1 {
|
||||
t.Fatal("regular user should see at least 1 enabled model")
|
||||
}
|
||||
@@ -778,7 +778,7 @@ func TestLive_BYOK_AutoFetch(t *testing.T) {
|
||||
w = h.request("GET", "/api/v1/models/enabled", userToken, nil)
|
||||
var resp map[string]interface{}
|
||||
decode(w, &resp)
|
||||
userModels := resp["models"].([]interface{})
|
||||
userModels := resp["data"].([]interface{})
|
||||
|
||||
personalCount := 0
|
||||
for _, raw := range userModels {
|
||||
|
||||
@@ -28,7 +28,11 @@ func (h *ModelPrefsHandler) GetPreferences(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"preferences": prefs})
|
||||
if prefs == nil {
|
||||
prefs = []models.UserModelSetting{}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"data": prefs})
|
||||
}
|
||||
|
||||
// SetPreference upserts a single model preference.
|
||||
@@ -37,7 +41,7 @@ func (h *ModelPrefsHandler) SetPreference(c *gin.Context) {
|
||||
|
||||
var req struct {
|
||||
ModelID string `json:"model_id" binding:"required"`
|
||||
ProviderConfigID *string `json:"provider_config_id,omitempty"`
|
||||
ProviderConfigID string `json:"provider_config_id" binding:"required"`
|
||||
Hidden *bool `json:"hidden,omitempty"`
|
||||
PreferredTemperature *float64 `json:"preferred_temperature,omitempty"`
|
||||
PreferredMaxTokens *int `json:"preferred_max_tokens,omitempty"`
|
||||
@@ -48,15 +52,16 @@ func (h *ModelPrefsHandler) SetPreference(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
pcid := req.ProviderConfigID
|
||||
patch := models.UserModelSettingPatch{
|
||||
ProviderConfigID: req.ProviderConfigID,
|
||||
ProviderConfigID: &pcid,
|
||||
Hidden: req.Hidden,
|
||||
PreferredTemperature: req.PreferredTemperature,
|
||||
PreferredMaxTokens: req.PreferredMaxTokens,
|
||||
SortOrder: req.SortOrder,
|
||||
}
|
||||
|
||||
if err := h.stores.UserSettings.Set(c.Request.Context(), userID, req.ModelID, req.ProviderConfigID, patch); err != nil {
|
||||
if err := h.stores.UserSettings.Set(c.Request.Context(), userID, req.ModelID, &pcid, patch); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to set preference"})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package postgres
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.gobha.me/xcaliber/chat-switchboard/models"
|
||||
)
|
||||
@@ -148,5 +147,3 @@ func patchIntOrNil(i *int) interface{} {
|
||||
return *i
|
||||
}
|
||||
|
||||
// unused but keeping for reference - will be used in ListOptions-based queries
|
||||
var _ = strings.Join
|
||||
|
||||
@@ -3,7 +3,6 @@ package sqlite
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.gobha.me/xcaliber/chat-switchboard/models"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/store"
|
||||
@@ -149,5 +148,3 @@ func patchIntOrNil(i *int) interface{} {
|
||||
return *i
|
||||
}
|
||||
|
||||
// unused but keeping for reference - will be used in ListOptions-based queries
|
||||
var _ = strings.Join
|
||||
|
||||
Reference in New Issue
Block a user