diff --git a/backend/internal/pkg/xai/models.go b/backend/internal/pkg/xai/models.go index 2deec44c22..ae4b8ac9d5 100644 --- a/backend/internal/pkg/xai/models.go +++ b/backend/internal/pkg/xai/models.go @@ -115,7 +115,7 @@ var grokTextResponsesModelAliases = map[string]string{ "grok-3-mini": "grok-3-mini", "grok-3-mini-fast": "grok-3-mini-fast", "grok-build": "grok-build-0.1", - "grok-build-latest": "grok-build-0.1", + "grok-build-latest": DefaultTextModel, "grok-build-0.1": "grok-build-0.1", "grok-composer-2.5-fast": "grok-composer-2.5-fast", "grok-composer": "grok-composer-2.5-fast", diff --git a/backend/internal/pkg/xai/models_test.go b/backend/internal/pkg/xai/models_test.go index 7319f7efd9..84d147fdb9 100644 --- a/backend/internal/pkg/xai/models_test.go +++ b/backend/internal/pkg/xai/models_test.go @@ -7,14 +7,15 @@ import ( ) func TestDefaultModelMappingExcludesCrossClientWildcards(t *testing.T) { - t.Parallel() + original := RuntimeModelMappingOptions() + t.Cleanup(func() { SetRuntimeModelMappingOptions(original) }) SetRuntimeModelMappingOptions(ModelMappingOptions{}) mapping := DefaultModelMapping() require.Equal(t, "grok-4.5", mapping["grok"]) require.Equal(t, "grok-4.5", mapping["grok-latest"]) require.Equal(t, "grok-build-0.1", mapping["grok-build"]) - require.Equal(t, "grok-build-0.1", mapping["grok-build-latest"]) + require.Equal(t, "grok-4.5", mapping["grok-build-latest"]) require.Equal(t, DefaultImagineVideo15LegacyModel, mapping["grok-imagine-video-1.5"]) require.Equal(t, DefaultImagineVideo15Model, mapping["grok-imagine-video-1.5-preview"]) require.Equal(t, "grok-4.5", mapping["xai/grok"]) diff --git a/backend/internal/pkg/xai/oauth_test.go b/backend/internal/pkg/xai/oauth_test.go index 7c179a5ec1..b97e40966e 100644 --- a/backend/internal/pkg/xai/oauth_test.go +++ b/backend/internal/pkg/xai/oauth_test.go @@ -338,8 +338,8 @@ func TestRuntimeSanityReportsInvalidOverridesWithoutSecrets(t *testing.T) { } func TestDefaultModelMappingIncludesGrokAliases(t *testing.T) { - t.Parallel() - + original := RuntimeModelMappingOptions() + t.Cleanup(func() { SetRuntimeModelMappingOptions(original) }) SetRuntimeModelMappingOptions(ModelMappingOptions{}) mapping := DefaultModelMapping() require.Equal(t, "grok-4.5", mapping["grok"]) @@ -347,7 +347,7 @@ func TestDefaultModelMappingIncludesGrokAliases(t *testing.T) { require.Equal(t, "grok-4.5", mapping["grok-4.5"]) require.Equal(t, "grok-4.5", mapping["grok-4.5-latest"]) require.Equal(t, "grok-build-0.1", mapping["grok-build"]) - require.Equal(t, "grok-build-0.1", mapping["grok-build-latest"]) + require.Equal(t, "grok-4.5", mapping["grok-build-latest"]) require.Equal(t, "grok-composer-2.5-fast", mapping["grok-composer"]) require.Equal(t, "grok-composer-2.5-fast", mapping["composer-2.5"]) require.Equal(t, "grok-4.20-0309-reasoning", mapping["grok-4.20-reasoning"]) diff --git a/frontend/src/api/__tests__/admin.grok.spec.ts b/frontend/src/api/__tests__/admin.grok.spec.ts index 7560ce443f..87b0a7f7e6 100644 --- a/frontend/src/api/__tests__/admin.grok.spec.ts +++ b/frontend/src/api/__tests__/admin.grok.spec.ts @@ -8,7 +8,7 @@ vi.mock('@/api/client', () => ({ apiClient: { post }, })) -import { createFromSSO, getGrokSSOImportTimeout } from '@/api/admin/grok' +import { authorizePassword, createFromSSO, getGrokSSOImportTimeout } from '@/api/admin/grok' describe('admin Grok SSO import API', () => { beforeEach(() => { @@ -34,4 +34,20 @@ describe('admin Grok SSO import API', () => { { timeout: expectedTimeout }, ) }) + + it('preserves password whitespace and applies the authorization timeout', async () => { + post.mockResolvedValueOnce({ data: { access_token: 'access-token' } }) + + await authorizePassword(' user@example.com ---- password with spaces ', 7) + + expect(post).toHaveBeenCalledWith( + '/admin/grok/oauth/password', + { + email: 'user@example.com', + password: ' password with spaces ', + proxy_id: 7, + }, + { timeout: 120_000 }, + ) + }) }) diff --git a/frontend/src/components/account/CreateAccountModal.vue b/frontend/src/components/account/CreateAccountModal.vue index b450444877..7727d08d73 100644 --- a/frontend/src/components/account/CreateAccountModal.vue +++ b/frontend/src/components/account/CreateAccountModal.vue @@ -5488,8 +5488,9 @@ const handleGrokAuthorizePassword = async (emailPasswordInput: string) => { const lines = emailPasswordInput .split('\n') - .map((line) => line.trim()) - .filter((line) => line && line.includes('----')) + // Keep the password portion byte-for-byte; trim is only for determining + // whether this textarea line is blank. + .filter((line) => line.trim() && line.includes('----')) if (lines.length === 0) { grokOAuth.error.value = t( diff --git a/frontend/src/components/admin/account/ReAuthAccountModal.vue b/frontend/src/components/admin/account/ReAuthAccountModal.vue index a476a5684c..28bbf2a6cc 100644 --- a/frontend/src/components/admin/account/ReAuthAccountModal.vue +++ b/frontend/src/components/admin/account/ReAuthAccountModal.vue @@ -678,8 +678,8 @@ const handleGrokAuthorizePassword = async (emailPasswordInput: string) => { if (!props.account || !isGrok.value) return const line = emailPasswordInput .split('\n') - .map((item) => item.trim()) - .find((item) => item.includes('----')) + // Email is normalized in the API helper, but password whitespace is valid. + .find((item) => item.trim() && item.includes('----')) if (!line) { grokOAuth.error.value = t( 'admin.accounts.oauth.grok.pleaseEnterPassword',