feat(copilot): complete runtime provider configuration

This commit is contained in:
2026-07-13 14:57:28 +08:00
parent 6b42853c0b
commit 0a69d80f7c
17 changed files with 1163 additions and 319 deletions
@@ -12,7 +12,6 @@ import (
"github.com/gochat/gochat/internal/llm"
"github.com/gochat/gochat/internal/model"
"github.com/gochat/gochat/internal/repository"
"github.com/gochat/gochat/internal/security"
"github.com/gochat/gochat/internal/service"
"github.com/stretchr/testify/require"
"gorm.io/datatypes"
@@ -40,10 +39,8 @@ func newCaptainPreferenceFixture(t *testing.T) *captainPreferenceFixture {
prefRepo := repository.NewCaptainPreferenceRepo(db)
accountRepo := repository.NewAccountRepo(db)
installationConfigRepo := repository.NewInstallationConfigRepo(db)
encryptor, err := security.NewEncryptor(security.DefaultEncryptionConfig())
require.NoError(t, err)
manager := llm.NewProviderManager()
copilotConfigService := service.NewCopilotConfigService(installationConfigRepo, encryptor, manager)
copilotConfigService := service.NewCopilotConfigService(installationConfigRepo, manager)
preferenceService := service.NewCaptainPreferenceService(prefRepo, accountRepo)
preferenceService.SetCopilotConfigService(copilotConfigService)
handler := NewCaptainPreferenceHandler(preferenceService)
@@ -105,13 +102,13 @@ func TestCaptainPreferencesGetReturnsRawChatwootConfig(t *testing.T) {
features := payload["features"].(map[string]any)
editor := features["editor"].(map[string]any)
require.Equal(t, false, editor["enabled"])
require.Equal(t, "gpt-4.1-mini", editor["default"])
require.Equal(t, "gpt-4.1-mini", editor["selected"])
require.Equal(t, true, editor["enabled"])
require.Equal(t, "gpt-4o-mini", editor["default"])
require.Equal(t, "gpt-4o-mini", editor["selected"])
require.NotEmpty(t, editor["models"].([]any))
}
func TestCaptainPreferencesUpdateProviderConfiguration(t *testing.T) {
func TestCaptainPreferencesCannotUpdatePlatformProviderConfiguration(t *testing.T) {
f := newCaptainPreferenceFixture(t)
w := f.request(http.MethodPut, f.path(""), map[string]any{
@@ -125,10 +122,7 @@ func TestCaptainPreferencesUpdateProviderConfiguration(t *testing.T) {
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
payload := decodeCaptainPreferencePayload(t, w)
providerConfig := payload["provider_config"].(map[string]any)
require.Equal(t, "openai_compatible", providerConfig["provider"])
require.Equal(t, "https://llm.example.com/v1", providerConfig["base_url"])
require.Equal(t, "example-model", providerConfig["model"])
require.Equal(t, true, providerConfig["api_key_configured"])
require.Equal(t, false, providerConfig["configured"])
require.NotContains(t, w.Body.String(), "secret-key-value")
}
@@ -163,15 +157,16 @@ func TestCaptainPreferencesUpdateMergesAccountModelsAndFeatures(t *testing.T) {
require.False(t, featureValues["assistant"])
}
func TestCaptainPreferencesUpdateRejectsNonAdminAndInvalidModel(t *testing.T) {
func TestCaptainPreferencesUpdateRejectsNonAdminAndAcceptsCustomModel(t *testing.T) {
f := newCaptainPreferenceFixture(t)
w := f.request(http.MethodPut, f.path("/as-agent"), map[string]any{"captain_models": map[string]any{"editor": "gpt-4.1"}})
require.Equal(t, http.StatusUnauthorized, w.Code, w.Body.String())
w = f.request(http.MethodPut, f.path(""), map[string]any{"captain_models": map[string]any{"editor": "not-a-model"}})
require.Equal(t, http.StatusUnprocessableEntity, w.Code, w.Body.String())
require.Contains(t, decodeCaptainPreferencePayload(t, w)["error"], "not a valid model")
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
features := decodeCaptainPreferencePayload(t, w)["features"].(map[string]any)
require.Equal(t, "not-a-model", features["editor"].(map[string]any)["selected"])
}
func TestCaptainPreferencesInvalidAccountID(t *testing.T) {