diff --git a/backend/internal/server/api_contract_test.go b/backend/internal/server/api_contract_test.go index 7f3b25f763..2bca68d3be 100644 --- a/backend/internal/server/api_contract_test.go +++ b/backend/internal/server/api_contract_test.go @@ -886,7 +886,7 @@ func TestAPIContracts(t *testing.T) { "invitation_code_enabled": false, "home_content": "", "hide_ccs_import_button": false, - "grok_default_text_model": "grok-4.5", + "grok_default_text_model": "grok-4.6", "grok_default_base_url_mode": "cli", "grok_cross_client_model_map_enabled": true, "purchase_subscription_enabled": false, @@ -1169,7 +1169,7 @@ func TestAPIContracts(t *testing.T) { "doc_url": "", "home_content": "", "hide_ccs_import_button": false, - "grok_default_text_model": "grok-4.5", + "grok_default_text_model": "grok-4.6", "grok_default_base_url_mode": "cli", "grok_cross_client_model_map_enabled": true, "purchase_subscription_enabled": false, diff --git a/backend/internal/service/setting_gateway_runtime.go b/backend/internal/service/setting_gateway_runtime.go index 2f13278e3b..e7eda7c30e 100644 --- a/backend/internal/service/setting_gateway_runtime.go +++ b/backend/internal/service/setting_gateway_runtime.go @@ -457,6 +457,37 @@ func (s *SettingService) MigrateOpenAIAllowClaudeCodeCodexPluginSetting(ctx cont return nil } +// MigrateGrokDefaultTextModel upgrades the pre-4.6 built-in default for +// existing installations. Explicit operator choices are left untouched. +func (s *SettingService) MigrateGrokDefaultTextModel(ctx context.Context) error { + if s == nil || s.settingRepo == nil { + return nil + } + if ctx == nil { + ctx = context.Background() + } + dbCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), codexRestrictionPolicyDBTimeout) + defer cancel() + + value, err := s.settingRepo.GetValue(dbCtx, SettingKeyGrokDefaultTextModel) + if err != nil { + if errors.Is(err, ErrSettingNotFound) { + return nil + } + return fmt.Errorf("get %s setting: %w", SettingKeyGrokDefaultTextModel, err) + } + // Only migrate the value that was previously shipped as the built-in + // default. Any other value is an explicit operator choice or a future + // default and must remain unchanged. + if strings.TrimSpace(value) != "grok-4.5" { + return nil + } + if err := s.settingRepo.Set(dbCtx, SettingKeyGrokDefaultTextModel, "grok-4.6"); err != nil { + return fmt.Errorf("set %s setting: %w", SettingKeyGrokDefaultTextModel, err) + } + return nil +} + // MigrateCodexBodyFingerprintToSignals 把已废弃的 codex_cli_only_allow_body_engine_fingerprint // 开关并入引擎指纹信号列表。幂等:信号键已存在(非空)则不动;缺失时写默认种子, // 并把 body 路径行的 Required 设为旧 body 开关的值(旧 true ⇒ 勾上 body 行)。 diff --git a/backend/internal/service/setting_service_codex_policy_test.go b/backend/internal/service/setting_service_codex_policy_test.go index 1c17b91ef8..e426dea2c5 100644 --- a/backend/internal/service/setting_service_codex_policy_test.go +++ b/backend/internal/service/setting_service_codex_policy_test.go @@ -202,3 +202,34 @@ func TestMigrateCodexBodyFingerprintToSignals(t *testing.T) { require.Equal(t, openai.DefaultEngineFingerprintSignalsJSON(), repo.values[SettingKeyCodexCLIOnlyEngineFingerprintSignals]) }) } + +func TestMigrateGrokDefaultTextModel(t *testing.T) { + t.Run("upgrades legacy built-in default", func(t *testing.T) { + repo := &codexPolicyMigrationRepoStub{values: map[string]string{ + SettingKeyGrokDefaultTextModel: "grok-4.5", + }} + svc := NewSettingService(repo, &config.Config{}) + require.NoError(t, svc.MigrateGrokDefaultTextModel(context.Background())) + require.Equal(t, "grok-4.6", repo.values[SettingKeyGrokDefaultTextModel]) + require.Equal(t, "grok-4.6", repo.sets[SettingKeyGrokDefaultTextModel]) + }) + + t.Run("does not overwrite an explicit model", func(t *testing.T) { + repo := &codexPolicyMigrationRepoStub{values: map[string]string{ + SettingKeyGrokDefaultTextModel: "grok-4.3", + }} + svc := NewSettingService(repo, &config.Config{}) + require.NoError(t, svc.MigrateGrokDefaultTextModel(context.Background())) + require.Equal(t, "grok-4.3", repo.values[SettingKeyGrokDefaultTextModel]) + _, wrote := repo.sets[SettingKeyGrokDefaultTextModel] + require.False(t, wrote) + }) + + t.Run("missing setting is left for normal defaults", func(t *testing.T) { + repo := &codexPolicyMigrationRepoStub{values: map[string]string{}} + svc := NewSettingService(repo, &config.Config{}) + require.NoError(t, svc.MigrateGrokDefaultTextModel(context.Background())) + _, wrote := repo.sets[SettingKeyGrokDefaultTextModel] + require.False(t, wrote) + }) +} diff --git a/backend/internal/service/wire.go b/backend/internal/service/wire.go index 88c3a1f185..2e34ce7b9c 100644 --- a/backend/internal/service/wire.go +++ b/backend/internal/service/wire.go @@ -745,6 +745,9 @@ func ProvideSettingService(settingRepo SettingRepository, groupRepo GroupReposit if err := svc.MigrateCodexBodyFingerprintToSignals(context.Background()); err != nil { logger.LegacyPrintf("service.setting", "Warning: migrate codex body fingerprint to signals failed: %v", err) } + if err := svc.MigrateGrokDefaultTextModel(context.Background()); err != nil { + logger.LegacyPrintf("service.setting", "Warning: migrate Grok default text model failed: %v", err) + } antigravity.SetUserAgentVersionResolver(svc.GetAntigravityUserAgentVersion) // enforceCodexIdentityHeaders 是所有 Codex 出站路径共用的纯函数收口点,拿不到 ctx, // 故注入无参解析器;解析器内部自带 60s TTL 缓存,热路径不触库。