Changeset 0.9.0 (#50)

This commit is contained in:
2026-02-23 01:57:28 +00:00
parent 15be26c516
commit 8264aa6016
94 changed files with 9812 additions and 8574 deletions

View File

@@ -11,7 +11,9 @@ import (
"github.com/gin-gonic/gin"
"git.gobha.me/xcaliber/chat-switchboard/database"
"git.gobha.me/xcaliber/chat-switchboard/models"
"git.gobha.me/xcaliber/chat-switchboard/providers"
capspkg "git.gobha.me/xcaliber/chat-switchboard/capabilities"
"git.gobha.me/xcaliber/chat-switchboard/tools"
)
@@ -23,7 +25,7 @@ type completionRequest struct {
Content string `json:"content" binding:"required"`
Model string `json:"model,omitempty"`
PresetID string `json:"preset_id,omitempty"` // if set, unwraps preset → base model + config
APIConfigID string `json:"api_config_id,omitempty"`
APIConfigID string `json:"provider_config_id,omitempty"`
MaxTokens int `json:"max_tokens,omitempty"`
Temperature *float64 `json:"temperature,omitempty"`
TopP *float64 `json:"top_p,omitempty"`
@@ -88,8 +90,8 @@ func (h *CompletionHandler) Complete(c *gin.Context) {
if req.Model == "" {
req.Model = preset.BaseModelID
}
if req.APIConfigID == "" && preset.APIConfigID != nil {
req.APIConfigID = *preset.APIConfigID
if req.APIConfigID == "" && preset.ProviderConfigID != nil {
req.APIConfigID = *preset.ProviderConfigID
}
if req.Temperature == nil && preset.Temperature != nil {
req.Temperature = preset.Temperature
@@ -152,7 +154,7 @@ func (h *CompletionHandler) Complete(c *gin.Context) {
provReq.MaxTokens = req.MaxTokens
} else {
// ResolveMaxOutput checks: caps → known models → context/8 → 4096
provReq.MaxTokens = providers.ResolveMaxOutput(model, caps)
provReq.MaxTokens = capspkg.ResolveMaxOutput(model, caps)
}
if req.Temperature != nil {
@@ -477,14 +479,14 @@ func escapeJSON(s string) string {
return s
}
// getModelCapabilities looks up capabilities from model_configs DB,
// getModelCapabilities looks up capabilities from model_catalog DB,
// then overlays with known model defaults and heuristic detection.
func (h *CompletionHandler) getModelCapabilities(c *gin.Context, model, apiConfigID string) providers.ModelCapabilities {
func (h *CompletionHandler) getModelCapabilities(c *gin.Context, model, apiConfigID string) models.ModelCapabilities {
return ResolveModelCaps(c, model, apiConfigID)
}
// ── Config Resolution ───────────────────────
// Priority: request.api_config_id → chat.api_config_id → user's first active config
// Priority: request.provider_config_id → chat.provider_config_id → user's first active config
func (h *CompletionHandler) resolveConfig(userID string, channelID string, req completionRequest) (providers.ProviderConfig, string, string, string, error) {
var configID string
@@ -498,7 +500,7 @@ func (h *CompletionHandler) resolveConfig(userID string, channelID string, req c
if configID == "" {
var channelConfigID *string
err := database.DB.QueryRow(
`SELECT api_config_id FROM channels WHERE id = $1`, channelID,
`SELECT provider_config_id FROM channels WHERE id = $1`, channelID,
).Scan(&channelConfigID)
if err == nil && channelConfigID != nil {
configID = *channelConfigID
@@ -508,9 +510,12 @@ func (h *CompletionHandler) resolveConfig(userID string, channelID string, req c
// 3. User's first active config (personal first, then global — excludes team providers)
if configID == "" {
err := database.DB.QueryRow(`
SELECT id FROM api_configs
WHERE (user_id = $1 OR is_global = true) AND is_active = true AND team_id IS NULL
ORDER BY user_id NULLS LAST, created_at ASC
SELECT id FROM provider_configs
WHERE is_active = true AND (
(scope = 'personal' AND owner_id = $1)
OR scope = 'global'
)
ORDER BY scope ASC, created_at ASC
LIMIT 1
`, userID).Scan(&configID)
if err != nil {
@@ -523,11 +528,12 @@ func (h *CompletionHandler) resolveConfig(userID string, channelID string, req c
var apiKey, modelDefault *string
var customHeadersJSON, providerSettingsJSON []byte
err := database.DB.QueryRow(`
SELECT provider, endpoint, api_key_encrypted, model_default, custom_headers, provider_settings
FROM api_configs
SELECT provider, endpoint, api_key_enc, model_default, headers, settings
FROM provider_configs
WHERE id = $1 AND is_active = true
AND (user_id = $2 OR is_global = true
OR team_id IN (SELECT team_id FROM team_members WHERE user_id = $2))
AND (scope = 'global'
OR (scope = 'personal' AND owner_id = $2)
OR (scope = 'team' AND owner_id IN (SELECT team_id FROM team_members WHERE user_id = $2)))
`, configID, userID).Scan(&providerID, &endpoint, &apiKey, &modelDefault, &customHeadersJSON, &providerSettingsJSON)
if err == sql.ErrNoRows {