diff --git a/tools/ui/src/lib/services/migration.service.ts b/tools/ui/src/lib/services/migration.service.ts index 152b78cd3..d7709bc6b 100644 --- a/tools/ui/src/lib/services/migration.service.ts +++ b/tools/ui/src/lib/services/migration.service.ts @@ -551,13 +551,49 @@ const mcpDefaultEnabledMigration: Migration = { } }; +const CONFIG_TYPES_MIGRATION_ID = 'config-type-normalization-v1'; + +const configTypesMigration: Migration = { + id: CONFIG_TYPES_MIGRATION_ID, + description: 'Coerce legacy string-encoded booleans in persisted config to real booleans', + + async run(): Promise { + const configRaw = localStorage.getItem(CONFIG_LOCALSTORAGE_KEY); + if (configRaw === null) return; + + const config = JSON.parse(configRaw); + let changed = false; + + // Pre-schema configs persisted booleans as the strings "true"/"false", which the + // strict server schema now rejects. Coerce those back to real booleans. No config + // string field holds exactly "true"/"false", so the match is unambiguous. + for (const key of Object.keys(config)) { + if (config[key] === 'true') { + config[key] = true; + changed = true; + } else if (config[key] === 'false') { + config[key] = false; + changed = true; + } + } + + if (changed) { + localStorage.setItem(CONFIG_LOCALSTORAGE_KEY, JSON.stringify(config)); + } + + if (import.meta.env.DEV && import.meta.env.VITE_DEBUG) + console.log(`[Migration] Config types: coerced string booleans (changed=${changed})`); + } +}; + const migrations: Migration[] = [ localStorageMigration, idxdbMigration, legacyMessageMigration, themeMigration, customJsonKeyMigration, - mcpDefaultEnabledMigration + mcpDefaultEnabledMigration, + configTypesMigration ]; export const MigrationService = { diff --git a/tools/ui/src/lib/stores/conversations.svelte.ts b/tools/ui/src/lib/stores/conversations.svelte.ts index ef8d61309..486202207 100644 --- a/tools/ui/src/lib/stores/conversations.svelte.ts +++ b/tools/ui/src/lib/stores/conversations.svelte.ts @@ -114,14 +114,13 @@ class ConversationsStore { /** Load thinking-enabled default from localStorage */ private static loadThinkingDefaults(): boolean { - if (typeof globalThis.localStorage === 'undefined') return false; + if (typeof globalThis.localStorage === 'undefined') return true; try { const raw = localStorage.getItem(THINKING_ENABLED_DEFAULT_LOCALSTORAGE_KEY); - if (!raw) return false; - const parsed = raw === 'true'; - return typeof parsed === 'boolean' ? parsed : false; + if (!raw) return true; + return raw === 'true'; } catch { - return false; + return true; } } @@ -333,7 +332,7 @@ class ConversationsStore { } this.pendingMcpServerOverrides = []; - this.pendingThinkingEnabled = false; + this.pendingThinkingEnabled = ConversationsStore.loadThinkingDefaults(); this.activeConversation = conversation; if (conversation.currNode) {