Changeset 0.9.4 (#54)
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
"git.gobha.me/xcaliber/chat-switchboard/database"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/models"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/providers"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/crypto"
|
||||
capspkg "git.gobha.me/xcaliber/chat-switchboard/capabilities"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/tools"
|
||||
)
|
||||
@@ -33,11 +34,13 @@ type completionRequest struct {
|
||||
}
|
||||
|
||||
// CompletionHandler proxies LLM requests through the backend.
|
||||
type CompletionHandler struct{}
|
||||
type CompletionHandler struct{
|
||||
vault *crypto.KeyResolver
|
||||
}
|
||||
|
||||
// NewCompletionHandler creates a new handler.
|
||||
func NewCompletionHandler() *CompletionHandler {
|
||||
return &CompletionHandler{}
|
||||
func NewCompletionHandler(vault *crypto.KeyResolver) *CompletionHandler {
|
||||
return &CompletionHandler{vault: vault}
|
||||
}
|
||||
|
||||
// ── Chat Completion ─────────────────────────
|
||||
@@ -387,16 +390,20 @@ func (h *CompletionHandler) resolveConfig(userID string, channelID string, req c
|
||||
|
||||
// Load the config — allow personal, global, OR team configs the user belongs to
|
||||
var providerID, endpoint string
|
||||
var apiKey, modelDefault *string
|
||||
var modelDefault *string
|
||||
var apiKeyEnc, keyNonce []byte
|
||||
var keyScope string
|
||||
var customHeadersJSON, providerSettingsJSON []byte
|
||||
err := database.DB.QueryRow(`
|
||||
SELECT provider, endpoint, api_key_enc, model_default, headers, settings
|
||||
SELECT provider, endpoint, api_key_enc, key_nonce, key_scope,
|
||||
model_default, headers, settings
|
||||
FROM provider_configs
|
||||
WHERE id = $1 AND is_active = true
|
||||
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)
|
||||
`, configID, userID).Scan(&providerID, &endpoint, &apiKeyEnc, &keyNonce, &keyScope,
|
||||
&modelDefault, &customHeadersJSON, &providerSettingsJSON)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
return providers.ProviderConfig{}, "", "", "", fmt.Errorf("API config not found or not accessible")
|
||||
@@ -414,9 +421,22 @@ func (h *CompletionHandler) resolveConfig(userID string, channelID string, req c
|
||||
return providers.ProviderConfig{}, "", "", "", fmt.Errorf("no model specified and no default model in config")
|
||||
}
|
||||
|
||||
// Decrypt API key using the appropriate tier
|
||||
key := ""
|
||||
if apiKey != nil {
|
||||
key = *apiKey
|
||||
if len(apiKeyEnc) > 0 {
|
||||
if h.vault != nil {
|
||||
var err error
|
||||
key, err = h.vault.Decrypt(apiKeyEnc, keyNonce, keyScope, userID)
|
||||
if err != nil {
|
||||
if err == crypto.ErrVaultLocked {
|
||||
return providers.ProviderConfig{}, "", "", "", fmt.Errorf("personal vault is locked — please log in again")
|
||||
}
|
||||
return providers.ProviderConfig{}, "", "", "", fmt.Errorf("failed to decrypt API key: %w", err)
|
||||
}
|
||||
} else {
|
||||
// No vault — key stored as raw bytes (unencrypted fallback)
|
||||
key = string(apiKeyEnc)
|
||||
}
|
||||
}
|
||||
|
||||
// Parse custom headers
|
||||
|
||||
Reference in New Issue
Block a user