validate.ts
1 import type { 2 ProviderEndpointMode, 3 ReasoningLevel, 4 ThinkingLevel, 5 WebSearchProvider, 6 } from '@/lib/shared/chat' 7 8 export function normalizeNullableString( 9 value: string | null | undefined, 10 ): string | null { 11 const trimmed = value?.trim() 12 return trimmed ? trimmed : null 13 } 14 15 export function normalizeThinkingLevel( 16 value: string | null | undefined, 17 ): ThinkingLevel | null { 18 if ( 19 value === 'off' || 20 value === 'minimal' || 21 value === 'low' || 22 value === 'medium' || 23 value === 'high' 24 ) { 25 return value 26 } 27 return null 28 } 29 30 export function normalizeReasoningLevel( 31 value: string | null | undefined, 32 ): ReasoningLevel | null { 33 if (value === 'off' || value === 'on' || value === 'stream') { 34 return value 35 } 36 return null 37 } 38 39 export function normalizeProviderEndpointMode( 40 value: string | null | undefined, 41 ): ProviderEndpointMode | null { 42 if ( 43 value === 'auto' || 44 value === 'responses' || 45 value === 'chat_completions' 46 ) { 47 return value 48 } 49 return null 50 } 51 52 export function normalizeRetentionDays(value: number | null | undefined): number { 53 const fallback = 30 54 if (value == null || !Number.isFinite(value)) { 55 return fallback 56 } 57 const rounded = Math.round(value) 58 return Math.min(3650, Math.max(1, rounded)) 59 } 60 61 export function normalizeWebSearchProvider( 62 rawValue: string | null | undefined, 63 ): WebSearchProvider | null { 64 if (!rawValue) return null 65 const validProviders = [ 66 'brave', 67 'perplexity', 68 'grok', 69 'gemini', 70 'kimi', 71 'openrouter', 72 ] 73 return validProviders.includes(rawValue) 74 ? (rawValue as WebSearchProvider) 75 : null 76 } 77 78 export function normalizeAgentBackendsEnabled( 79 value: string | null | undefined, 80 ): Partial<Record<string, boolean>> { 81 if (!value) return {} 82 try { 83 const parsed = JSON.parse(value) as unknown 84 if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { 85 return {} 86 } 87 return normalizeAgentBackendsEnabledPatch( 88 parsed as Record<string, unknown>, 89 ) 90 } catch { 91 return {} 92 } 93 } 94 95 export function normalizeAgentBackendsEnabledPatch( 96 value: Record<string, unknown> | null | undefined, 97 ): Partial<Record<string, boolean>> { 98 if (!value) return {} 99 const next: Partial<Record<string, boolean>> = {} 100 for (const [key, raw] of Object.entries(value)) { 101 const backendId = key.trim().toLowerCase() 102 if (!backendId || typeof raw !== 'boolean') { 103 continue 104 } 105 next[backendId] = raw 106 } 107 return next 108 }