diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index d040371b1f..c84a394b87 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -1108,9 +1108,7 @@ async def chat_completion( model = request.app.state.MODELS[model_id] model_info = await Models.get_model_by_id(model_id) missing_base_model = bool( - model_info - and model_info.base_model_id - and model_info.base_model_id not in request.app.state.MODELS + model_info and model_info.base_model_id and model_info.base_model_id not in request.app.state.MODELS ) if missing_base_model and ENABLE_CUSTOM_MODEL_FALLBACK: diff --git a/backend/open_webui/migrations/versions/6d09d1bf1f23_repair_double_encoded_user_oauth.py b/backend/open_webui/migrations/versions/6d09d1bf1f23_repair_double_encoded_user_oauth.py index 995fe263ae..d1f8595059 100644 --- a/backend/open_webui/migrations/versions/6d09d1bf1f23_repair_double_encoded_user_oauth.py +++ b/backend/open_webui/migrations/versions/6d09d1bf1f23_repair_double_encoded_user_oauth.py @@ -5,6 +5,7 @@ Revises: 1ce6ade7d93b Create Date: 2026-08-10 23:20:20.374826 """ + import json from typing import Sequence, Union diff --git a/backend/open_webui/retrieval/web/sougou.py b/backend/open_webui/retrieval/web/sougou.py index edac4b7ae8..8e3ddf4e5a 100644 --- a/backend/open_webui/retrieval/web/sougou.py +++ b/backend/open_webui/retrieval/web/sougou.py @@ -31,7 +31,8 @@ def search_sougou( params = JSONCodec.dumps({'Query': query, 'Cnt': 20}) common_client = CommonClient('tms', '2020-12-29', cred, '', profile=client_profile) results = [ - JSONCodec.loads(page) for page in common_client.call_json('SearchPro', JSONCodec.loads(params))['Response']['Pages'] + JSONCodec.loads(page) + for page in common_client.call_json('SearchPro', JSONCodec.loads(params))['Response']['Pages'] ] sorted_results = sorted(results, key=lambda x: x.get('scour', 0.0), reverse=True) if filter_list: diff --git a/backend/open_webui/routers/knowledge.py b/backend/open_webui/routers/knowledge.py index 5c259e8c44..d2864683e6 100644 --- a/backend/open_webui/routers/knowledge.py +++ b/backend/open_webui/routers/knowledge.py @@ -79,6 +79,7 @@ async def delete_file_resource(file: FileModel, db: AsyncSession) -> bool: return result + ############################ # Knowledge Base Embedding ############################ diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index ee9eeb9339..517565f12f 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -2205,9 +2205,10 @@ async def _fetch_url(url: str, max_size_mb: int | str | None) -> dict: if not is_attachment and base_content_type in {'', 'application/octet-stream', 'binary/octet-stream'}: sample = first_chunk[:4096].lstrip().lower() - if sample.startswith( - (b' 0 else '') - + content[start:end] - + ('...' if end < len(content) else '') + ('...' if start > 0 else '') + content[start:end] + ('...' if end < len(content) else '') ) break if snippet: diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 2d685a2e03..cc5f57e0c3 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -1990,11 +1990,7 @@ async def chat_completion_files_handler( __event_emitter__ = extra_params['__event_emitter__'] sources = [] - files = [ - item - for item in (body.get('metadata', {}).get('files', None) or []) - if item.get('type') != 'filesystem' - ] + files = [item for item in (body.get('metadata', {}).get('files', None) or []) if item.get('type') != 'filesystem'] if files: # Check if all files are in full context mode all_full_context = all(item.get('context') == 'full' for item in files) diff --git a/backend/open_webui/utils/misc.py b/backend/open_webui/utils/misc.py index 21368c8fd3..ea15adf75e 100644 --- a/backend/open_webui/utils/misc.py +++ b/backend/open_webui/utils/misc.py @@ -318,9 +318,7 @@ def get_reasoning_details(payload: dict): return None provider_fields = payload.get('provider_specific_fields') or {} - provider_details = ( - provider_fields.get('reasoning_details') if isinstance(provider_fields, dict) else None - ) + provider_details = provider_fields.get('reasoning_details') if isinstance(provider_fields, dict) else None return payload.get('reasoning_details') or provider_details diff --git a/backend/open_webui/utils/oauth.py b/backend/open_webui/utils/oauth.py index 05b67d1f78..96505a6be0 100644 --- a/backend/open_webui/utils/oauth.py +++ b/backend/open_webui/utils/oauth.py @@ -2320,11 +2320,7 @@ class OAuthManager: raise jwt.InvalidTokenError(str(e)) signing_key = next( - ( - key - for key in jwk_set.keys - if key.key_id == token_kid and key.public_key_use in ['sig', None] - ), + (key for key in jwk_set.keys if key.key_id == token_kid and key.public_key_use in ['sig', None]), None, ) if not signing_key: diff --git a/backend/open_webui/utils/subagents.py b/backend/open_webui/utils/subagents.py index 7092df44c2..809dd601ae 100644 --- a/backend/open_webui/utils/subagents.py +++ b/backend/open_webui/utils/subagents.py @@ -339,10 +339,7 @@ async def delegate( for file in metadata.get('files') or [] if str(file.get('id') or '') in requested_file_ids or str(file.get('url') or '') in requested_file_ids - or ( - isinstance(file.get('file'), dict) - and str(file.get('file', {}).get('id') or '') in requested_file_ids - ) + or (isinstance(file.get('file'), dict) and str(file.get('file', {}).get('id') or '') in requested_file_ids) ] found_file_ids = { str(value) diff --git a/backend/open_webui/utils/tool_approval.py b/backend/open_webui/utils/tool_approval.py index 81fe750ec6..c59b2d6316 100644 --- a/backend/open_webui/utils/tool_approval.py +++ b/backend/open_webui/utils/tool_approval.py @@ -43,8 +43,7 @@ async def resolve_tool_call_output( ( item for item in output - if item.get('type') == 'function_call' - and (item.get('call_id') or item.get('id')) == form_data.call_id + if item.get('type') == 'function_call' and (item.get('call_id') or item.get('id')) == form_data.call_id ), None, ) diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index cc9bba3cb4..4ab5c96504 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -954,10 +954,10 @@ def add_terminal_display_file_inline_param(spec: dict) -> dict: return spec spec['description'] = ( - f"{spec.get('description', '')} " - "Set inline=true when the file should be shown inline in the chat message instead of opening the file viewer. " - "Set page for PDF, DOCX, and PPTX files when you want the preview to open at a specific 1-based page or slide. " - "After display_file succeeds, do not display the same file again or emit Markdown for it." + f'{spec.get("description", "")} ' + 'Set inline=true when the file should be shown inline in the chat message instead of opening the file viewer. ' + 'Set page for PDF, DOCX, and PPTX files when you want the preview to open at a specific 1-based page or slide. ' + 'After display_file succeeds, do not display the same file again or emit Markdown for it.' ).strip() parameters = spec.setdefault('parameters', {'type': 'object', 'properties': {}, 'required': []}) parameters.setdefault('type', 'object') @@ -1411,11 +1411,7 @@ async def get_terminal_tools( context_id = terminal_context_id(connection, metadata, terminal_context) config = terminal_context_config(connection, terminal_context) - if ( - isinstance(config, dict) - and config.get('context_id') in {'chat_id', 'automation_id'} - and not context_id - ): + if isinstance(config, dict) and config.get('context_id') in {'chat_id', 'automation_id'} and not context_id: raise RuntimeError(f"Terminal server '{terminal_id}' requires a saved {terminal_context} context") if context_id: headers[TERMINAL_CONTEXT_HEADER] = context_id @@ -1586,8 +1582,7 @@ async def get_tool_servers_data(servers: list[dict[str, Any]]) -> list[dict[str, 'openapi': response, 'info': response.get('info', {}), 'specs': [ - add_terminal_display_file_inline_param(spec) - for spec in convert_openapi_to_tool_payload(response) + add_terminal_display_file_inline_param(spec) for spec in convert_openapi_to_tool_payload(response) ], } diff --git a/package-lock.json b/package-lock.json index f78827475e..cd0cf349f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "open-webui", - "version": "0.11.0", + "version": "0.11.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "open-webui", - "version": "0.11.0", + "version": "0.11.1", "dependencies": { "@azure/msal-browser": "^4.5.0", "@codemirror/lang-javascript": "^6.2.2", diff --git a/package.json b/package.json index 57712f50c5..85b7735b46 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "open-webui", - "version": "0.11.0", + "version": "0.11.1", "private": true, "scripts": { "dev": "npm run pyodide:fetch && vite dev --host", diff --git a/src/lib/components/AddTerminalServerModal.svelte b/src/lib/components/AddTerminalServerModal.svelte index 31f2f30e30..15be4244e8 100644 --- a/src/lib/components/AddTerminalServerModal.svelte +++ b/src/lib/components/AddTerminalServerModal.svelte @@ -375,7 +375,8 @@ else if (automationContextMode === 'automation_id') { contexts.automation = { context_id: 'automation_id' }; } - const useContexts = !direct && serverType === 'orchestrator' && Object.keys(contexts).length > 0; + const useContexts = + !direct && serverType === 'orchestrator' && Object.keys(contexts).length > 0; const connectionConfig: Record = connection?.config && typeof connection.config === 'object' ? { ...connection.config } : {}; if (!direct) connectionConfig.access_grants = accessGrants; @@ -583,259 +584,261 @@ {#if showOrchestratorAdvanced} -
-
-
-
- {$i18n.t('Terminal Contexts')} +
+
+
+
+ {$i18n.t('Terminal Contexts')} +
-
-
- - - - -
-
-
- -
-
-
-
- {$i18n.t('Policy ID')} -
-
-
- -
-
-
- {#if loadingPolicy} -
{$i18n.t('Loading policy...')}
- {:else if policyLoadError} -
- {$i18n.t('Failed to load policy: {{error}}', { error: policyLoadError })} -
- {/if} - -
-
-
-
- {$i18n.t('Image')} - ({$i18n.t('optional')}) -
-
-
- -
-
-
- -
-
-
-
- {$i18n.t('CPU')} -
-
-
- -
-
-
-
-
- {$i18n.t('Memory')} -
-
-
- -
-
-
- -
-
-
-
- {$i18n.t('Storage')} -
-
-
-
- + + + + + +
- {#if policyStorage === 'persistent'} -
- +
+
+ +
+
+
+
+ {$i18n.t('Policy ID')}
- {/if} +
+
+ +
+
+
+ {#if loadingPolicy} +
{$i18n.t('Loading policy...')}
+ {:else if policyLoadError} +
+ {$i18n.t('Failed to load policy: {{error}}', { error: policyLoadError })} +
+ {/if} + +
+
+
+
+ {$i18n.t('Image')} + ({$i18n.t('optional')}) +
+
+
+ +
-
-
-
- {$i18n.t('Idle Timeout')} - ({$i18n.t('min')}) +
+
+
+
+ {$i18n.t('CPU')} +
+
+
+
-
- +
+
+
+ {$i18n.t('Memory')} +
+
+
+ +
-
- -
-
-
-
- {$i18n.t('Environment Variables')} +
+
+
+
+ {$i18n.t('Storage')} +
+
+
+
+ +
+ {#if policyStorage === 'persistent'} +
+ +
+ {/if}
-
- {#each policyEnvPairs as pair, idx} -
+ +
+
+
+ {$i18n.t('Idle Timeout')} + ({$i18n.t('min')}) +
+
+
- +
+
+
+ + +
+
+
+
+ {$i18n.t('Environment Variables')} +
- {/each} -
-
- -
-
-
-
- {$i18n.t('Lifecycle JSON')} -
+ {#each policyEnvPairs as pair, idx} +
+ + + +
+ {/each}
-
-
-
-
- - +
+
+
+
+ {$i18n.t('Lifecycle JSON')} +
+
+ +
-
- {$i18n.t( - 'Policy changes apply to newly provisioned terminals. Refresh matching terminals to apply them to existing terminals.' - )} + +
+
+ + +
+
+ {$i18n.t( + 'Policy changes apply to newly provisioned terminals. Refresh matching terminals to apply them to existing terminals.' + )} +
+
- -
{/if} {/if} diff --git a/src/lib/components/admin/Analytics/ChartLine.svelte b/src/lib/components/admin/Analytics/ChartLine.svelte index 7d5d8e39ba..12de0eb36f 100644 --- a/src/lib/components/admin/Analytics/ChartLine.svelte +++ b/src/lib/components/admin/Analytics/ChartLine.svelte @@ -88,7 +88,9 @@ : period === 'year' || period === 'all' ? 'M/D/YY' : 'M/D'} -
+
{#each Array(labelCount) as _, i} {@const idx = i === labelCount - 1 ? data.length - 1 : Math.min(i * step, data.length - 1)} {#if data[idx]} diff --git a/src/lib/components/admin/Evaluations/FeedbackModal.svelte b/src/lib/components/admin/Evaluations/FeedbackModal.svelte index 61ef01b418..116ffccdff 100644 --- a/src/lib/components/admin/Evaluations/FeedbackModal.svelte +++ b/src/lib/components/admin/Evaluations/FeedbackModal.svelte @@ -125,7 +125,8 @@
{#each selectedFeedback?.data?.tags as tag} - {tag} {/each} diff --git a/src/lib/components/admin/Settings/General.svelte b/src/lib/components/admin/Settings/General.svelte index c080a2e4b1..bb480612f3 100644 --- a/src/lib/components/admin/Settings/General.svelte +++ b/src/lib/components/admin/Settings/General.svelte @@ -416,7 +416,8 @@
- {Object.keys(defaultInterfaceSettings).length} {$i18n.t('settings configured')} + {Object.keys(defaultInterfaceSettings).length} + {$i18n.t('settings configured')}
{#if Object.keys(defaultInterfaceSettings).length > 0} diff --git a/src/lib/components/admin/Settings/Models/Manage/ManageProviderModels.svelte b/src/lib/components/admin/Settings/Models/Manage/ManageProviderModels.svelte index c61f3a039a..cc5dfc91c8 100644 --- a/src/lib/components/admin/Settings/Models/Manage/ManageProviderModels.svelte +++ b/src/lib/components/admin/Settings/Models/Manage/ManageProviderModels.svelte @@ -55,11 +55,13 @@ const iconButtonClass = 'inline-flex h-7 items-center justify-center rounded-lg border border-gray-100/50 bg-gray-50/40 px-2.5 text-gray-700 transition-colors hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-50 dark:border-white/[0.04] dark:bg-white/[0.03] dark:text-gray-300 dark:hover:bg-white/[0.06]'; - const getModelId = (model: ProviderModel) => model.key ?? model.id ?? model.name ?? model.model ?? ''; + const getModelId = (model: ProviderModel) => + model.key ?? model.id ?? model.name ?? model.model ?? ''; const getDisplayName = (model: ProviderModel) => model.display_name ?? getModelId(model); - const getUnloadId = (model: ProviderModel) => model.loaded_instances?.[0]?.id ?? getModelId(model); + const getUnloadId = (model: ProviderModel) => + model.loaded_instances?.[0]?.id ?? getModelId(model); const getStatus = (model: ProviderModel) => { if (model.loaded_instances?.length) { @@ -140,11 +142,7 @@ const model = modelRef.trim(); if (!model) return; - await runModelAction( - model, - downloadProviderModel, - $i18n.t('Model download started') - ); + await runModelAction(model, downloadProviderModel, $i18n.t('Model download started')); modelRef = ''; }; @@ -210,7 +208,11 @@ autocomplete="off" /> - @@ -225,7 +227,9 @@ {$i18n.t('No models found')}
{:else} -
+
{#each providerModels as model} {@const modelId = getModelId(model)} {@const displayName = getDisplayName(model)} diff --git a/src/lib/components/admin/Settings/Models/ManageModelsModal.svelte b/src/lib/components/admin/Settings/Models/ManageModelsModal.svelte index 1a330c2b1c..e7f50c19e2 100644 --- a/src/lib/components/admin/Settings/Models/ManageModelsModal.svelte +++ b/src/lib/components/admin/Settings/Models/ManageModelsModal.svelte @@ -15,7 +15,12 @@ export let show = false; - type ProviderConnection = { idx: number; url: string; provider: string; config: Record }; + type ProviderConnection = { + idx: number; + url: string; + provider: string; + config: Record; + }; const MANAGEMENT_PROVIDERS = new Set(['llama.cpp', 'lmstudio']); let selected: '' | 'ollama' | 'provider' | null = null; @@ -38,27 +43,31 @@ })() ]); - providerConnections = - openaiConfig?.ENABLE_OPENAI_API - ? (openaiConfig.OPENAI_API_BASE_URLS ?? []) - .map((url: string, idx: number) => ({ - idx, - url, - provider: - (openaiConfig.OPENAI_API_CONFIGS?.[idx] ?? - openaiConfig.OPENAI_API_CONFIGS?.[String(idx)] ?? - openaiConfig.OPENAI_API_CONFIGS?.[url] ?? - {})?.provider ?? '', - config: + providerConnections = openaiConfig?.ENABLE_OPENAI_API + ? (openaiConfig.OPENAI_API_BASE_URLS ?? []) + .map((url: string, idx: number) => ({ + idx, + url, + provider: + ( openaiConfig.OPENAI_API_CONFIGS?.[idx] ?? openaiConfig.OPENAI_API_CONFIGS?.[String(idx)] ?? openaiConfig.OPENAI_API_CONFIGS?.[url] ?? {} - })) - .filter((connection: ProviderConnection) => MANAGEMENT_PROVIDERS.has(connection.provider)) - : []; + )?.provider ?? '', + config: + openaiConfig.OPENAI_API_CONFIGS?.[idx] ?? + openaiConfig.OPENAI_API_CONFIGS?.[String(idx)] ?? + openaiConfig.OPENAI_API_CONFIGS?.[url] ?? + {} + })) + .filter((connection: ProviderConnection) => + MANAGEMENT_PROVIDERS.has(connection.provider) + ) + : []; - const hasOllama = ollamaConfig?.ENABLE_OLLAMA_API && (ollamaConfig?.OLLAMA_BASE_URLS ?? []).length > 0; + const hasOllama = + ollamaConfig?.ENABLE_OLLAMA_API && (ollamaConfig?.OLLAMA_BASE_URLS ?? []).length > 0; const hasProvider = providerConnections.length > 0; if (hasOllama) { diff --git a/src/lib/components/admin/Settings/WebSearch.svelte b/src/lib/components/admin/Settings/WebSearch.svelte index e257620e58..9c9572aceb 100644 --- a/src/lib/components/admin/Settings/WebSearch.svelte +++ b/src/lib/components/admin/Settings/WebSearch.svelte @@ -47,7 +47,7 @@ 'yandex', 'youcom', 'linkup', - 'openserp' + 'openserp' ]; let webLoaderEngines = ['playwright', 'firecrawl', 'tavily', 'microsoft_web_iq', 'external']; @@ -1011,14 +1011,14 @@ />
- {:else if webConfig.WEB_SEARCH_ENGINE === 'openserp'} + {:else if webConfig.WEB_SEARCH_ENGINE === 'openserp'}
{$i18n.t('OpenSERP URL')}
-
+
channelName(channel).toLowerCase().includes(normalizedChannelSearch)) + ? channelOptions.filter((channel) => + channelName(channel).toLowerCase().includes(normalizedChannelSearch) + ) : channelOptions; const selectChat = () => { @@ -139,7 +141,10 @@
{#if tab === ''} -
+
- {:else} -
-
- {$i18n.t('No results found')} -
+ {:else} +
+
+ {$i18n.t('No results found')}
+
{/if} {:else} @@ -1172,114 +1181,39 @@
{/if} - {#each downloadTargets as target, targetIndex (target.id)} - {#if target.download} - -
- -
- {$i18n.t('Downloading "{{searchValue}}"', { searchValue: searchValue })} -
- {#if 'pullProgress' in target.download} -
- {target.download.pullProgress}% -
- {/if} - -
-
- {:else} - - - - {/if} - {/each} - - {#each selectionOnly ? [] : Object.keys($MODEL_DOWNLOAD_POOL).filter((model) => !activeDownloadKeys.has(model)) as model} - {@const download = $MODEL_DOWNLOAD_POOL[model]} - {@const downloadName = download?.model ?? model} + {#each downloadTargets as target, targetIndex (target.id)} + {#if target.download}
- Downloading "{downloadName}"{download?.providerLabel - ? ` from ${download.providerLabel}` - : ''} + {$i18n.t('Downloading "{{searchValue}}"', { searchValue: searchValue })}
- {#if 'pullProgress' in download} -
- {download.pullProgress}% + {#if 'pullProgress' in target.download} +
+ {target.download.pullProgress}%
{/if}
- {/each} + {:else} + + + + {/if} + {/each} + + {#each selectionOnly ? [] : Object.keys($MODEL_DOWNLOAD_POOL).filter((model) => !activeDownloadKeys.has(model)) as model} + {@const download = $MODEL_DOWNLOAD_POOL[model]} + {@const downloadName = download?.model ?? model} + +
+ +
+ Downloading "{downloadName}"{download?.providerLabel + ? ` from ${download.providerLabel}` + : ''} +
+ {#if 'pullProgress' in download} +
+ {download.pullProgress}% +
+ {/if} + +
+
+ {/each}
{#if showSetDefault} diff --git a/src/lib/components/common/InterfaceSettings.svelte b/src/lib/components/common/InterfaceSettings.svelte index e32672aa86..2bbaee1cd2 100644 --- a/src/lib/components/common/InterfaceSettings.svelte +++ b/src/lib/components/common/InterfaceSettings.svelte @@ -128,7 +128,11 @@ const hasSettingPath = (source: Record, path: string) => { let current: any = source; for (const part of path.split('.')) { - if (!current || typeof current !== 'object' || !Object.prototype.hasOwnProperty.call(current, part)) { + if ( + !current || + typeof current !== 'object' || + !Object.prototype.hasOwnProperty.call(current, part) + ) { return false; } current = current[part]; @@ -394,1426 +398,1424 @@ />
-

{$i18n.t('UI')}

+

{$i18n.t('UI')}

-
-
- +
+
+ -
- -
-
- - {#if textScale !== null && (showTextScaleSlider || !isDefaultSetting('textScale'))} -
- - -
- { - setTextScaleHandler(textScale ?? 1); - }} - aria-labelledby="ui-scale-label" - aria-valuemin="1" - aria-valuemax="1.5" - aria-valuenow={textScale} - aria-valuetext={`${textScale}x`} - /> -
- - -
- {/if} -

- {$i18n.t('Set a local zoom level for the app interface.')} -

-
- -
-
-
- {$i18n.t('High Contrast Mode')} -
- -
- { - saveSettings({ highContrastMode }); - }} - /> -
-
-

- {$i18n.t('Enable accessibility-focused visual enhancements.')} -

-
- -
-
-
- {$i18n.t('Display Chat Title in Tab')} -
- -
- { - saveSettings({ showChatTitleInTab }); - }} - /> -
-
-

- {$i18n.t('Use the active chat title as the browser tab title.')} -

-
- -
-
-
{$i18n.t('Allow User Location')}
- -
- { - toggleUserLocation(); - }} - /> -
-
-

- {$i18n.t('Share your current location with features that can use it.')} -

-
- -
-
-
- {$i18n.t('Haptic Feedback')} ({$i18n.t('Android')}) -
- -
- { - saveSettings({ hapticFeedback }); - }} - /> -
-
-

- {$i18n.t('Use device vibration feedback on supported Android devices.')} -

-
- -
-
-
- {$i18n.t('Copy Formatted Text')} -
- -
- { - saveSettings({ copyFormatted }); - }} - /> -
-
-

- {$i18n.t('Copy rich formatted content instead of plain text.')} -

-
- - {#if $user?.role === 'admin'} -
-
-
- {$i18n.t('Toast Notifications for New Updates')} -
- -
- { - saveSettings({ showUpdateToast }); - }} - /> -
-
-

- {$i18n.t('Show update toasts to admins when new versions are available.')} -

-
- -
-
-
- {$i18n.t(`Show "What's New" Modal on Login`)} -
- -
- { - saveSettings({ showChangelog }); - }} - /> -
-
-

- {$i18n.t('Open the changelog modal after sign-in when enabled.')} -

-
- {/if} - -
{$i18n.t('Chat')}
- -
-
-
- {$i18n.t('Enable Message Queue')} -
- -
- { - saveSettings({ enableMessageQueue }); - }} - /> -
-
-

- {$i18n.t('Queue outgoing messages instead of interrupting active responses.')} -

-
- -
-
-
- {$i18n.t('Chat Direction')} -
- - -
-

- {$i18n.t('Choose automatic, left-to-right, or right-to-left text flow.')} -

-
- -
-
-
- {$i18n.t('Landing Page Mode')} -
- - -
-

- {$i18n.t('Choose whether the app opens to the default home or chat view.')} -

-
- -
-
-
- {$i18n.t('Chat Background Image')} -
- - +
+
+ + {#if textScale !== null && (showTextScaleSlider || !isDefaultSetting('textScale'))} +
+ + +
+ { + setTextScaleHandler(textScale ?? 1); }} - type="button" - > - {backgroundImageUrl !== null ? $i18n.t('Reset') : $i18n.t('Upload')} - + aria-labelledby="ui-scale-label" + aria-valuemin="1" + aria-valuemax="1.5" + aria-valuenow={textScale} + aria-valuetext={`${textScale}x`} + />
-

- {$i18n.t('Upload or reset the image shown behind chat content.')} -

+ + +
+ {/if} +

+ {$i18n.t('Set a local zoom level for the app interface.')} +

+
+ +
+
+
+ {$i18n.t('High Contrast Mode')}
-
-
-
- {$i18n.t('Chat Bubble UI')} -
+
+ { + saveSettings({ highContrastMode }); + }} + /> +
+
+

+ {$i18n.t('Enable accessibility-focused visual enhancements.')} +

+
-
- { - saveSettings({ chatBubble }); - }} - /> -
-
-

- {$i18n.t('Render messages in compact bubble containers.')} -

+
+
+
+ {$i18n.t('Display Chat Title in Tab')}
- {#if !chatBubble} -
-
-
- {$i18n.t('Display the Username Instead of You in the Chat')} -
+
+ { + saveSettings({ showChatTitleInTab }); + }} + /> +
+
+

+ {$i18n.t('Use the active chat title as the browser tab title.')} +

+
-
- { - saveSettings({ showUsername }); - }} - /> -
-
-

- {$i18n.t('Show your username label instead of You in chat bubbles.')} -

-
- {/if} +
+
+
{$i18n.t('Allow User Location')}
-
-
-
- {$i18n.t('Widescreen Mode')} -
+
+ { + toggleUserLocation(); + }} + /> +
+
+

+ {$i18n.t('Share your current location with features that can use it.')} +

+
-
- { - saveSettings({ widescreenMode }); - }} - /> -
-
-

- {$i18n.t('Use a wider chat layout on large displays.')} -

+
+
+
+ {$i18n.t('Haptic Feedback')} ({$i18n.t('Android')})
- {#if $user?.role === 'admin' || $user?.permissions?.chat?.temporary} -
-
-
- {$i18n.t('Temporary Chat by Default')} -
+
+ { + saveSettings({ hapticFeedback }); + }} + /> +
+
+

+ {$i18n.t('Use device vibration feedback on supported Android devices.')} +

+
-
- { - saveSettings({ temporaryChatByDefault }); - }} - /> -
-
-

- {$i18n.t('Start new chats as temporary unless changed.')} -

-
- {/if} - -
-
-
- {$i18n.t('Fade Effect for Streaming Text')} -
- -
- { - saveSettings({ chatFadeStreamingText }); - }} - /> -
-
-

- {$i18n.t('Fade streaming text as it arrives.')} -

+
+
+
+ {$i18n.t('Copy Formatted Text')}
-
-
-
- {$i18n.t('Render Markdown in User Messages')} -
+
+ { + saveSettings({ copyFormatted }); + }} + /> +
+
+

+ {$i18n.t('Copy rich formatted content instead of plain text.')} +

+
-
- { - saveSettings({ renderMarkdownInUserMessages }); - }} - /> -
+ {#if $user?.role === 'admin'} +
+
+
+ {$i18n.t('Toast Notifications for New Updates')}
-

- {$i18n.t('Format Markdown syntax in your own messages.')} -

+ +
+ { + saveSettings({ showUpdateToast }); + }} + /> +
+
+

+ {$i18n.t('Show update toasts to admins when new versions are available.')} +

+
+ +
+
+
+ {$i18n.t(`Show "What's New" Modal on Login`)} +
+ +
+ { + saveSettings({ showChangelog }); + }} + /> +
+
+

+ {$i18n.t('Open the changelog modal after sign-in when enabled.')} +

+
+ {/if} + +
{$i18n.t('Chat')}
+ +
+
+
+ {$i18n.t('Enable Message Queue')}
-
-
-
- {$i18n.t('Render Markdown in Assistant Messages')} -
+
+ { + saveSettings({ enableMessageQueue }); + }} + /> +
+
+

+ {$i18n.t('Queue outgoing messages instead of interrupting active responses.')} +

+
-
- { - saveSettings({ renderMarkdownInAssistantMessages }); - }} - /> -
-
-

- {$i18n.t('Format Markdown syntax in assistant responses.')} -

+
+
+
+ {$i18n.t('Chat Direction')}
-
-
-
- {$i18n.t('Render Markdown in Previews')} -
+ +
+

+ {$i18n.t('Choose automatic, left-to-right, or right-to-left text flow.')} +

+
-
- { - saveSettings({ renderMarkdownInPreviews }); - }} - /> -
-
-

- {$i18n.t('Format Markdown in previews and compact content surfaces.')} -

+
+
+
+ {$i18n.t('Landing Page Mode')}
-
-
-
- {$i18n.t('Title Auto-Generation')} -
+ +
+

+ {$i18n.t('Choose whether the app opens to the default home or chat view.')} +

+
-
- { - toggleTitleAutoGenerate(); - }} - /> -
-
-

- {$i18n.t('Generate chat titles automatically from conversation content.')} -

+
+
+
+ {$i18n.t('Chat Background Image')}
-
-
-
- {$i18n.t('Follow-Up Auto-Generation')} -
+ +
+

+ {$i18n.t('Upload or reset the image shown behind chat content.')} +

+
-
- { - saveSettings({ autoFollowUps }); - }} - /> -
-
-

- {$i18n.t('Generate suggested follow-up prompts after responses.')} -

+
+
+
+ {$i18n.t('Chat Bubble UI')}
-
-
-
- {$i18n.t('Chat Tags Auto-Generation')} -
+
+ { + saveSettings({ chatBubble }); + }} + /> +
+
+

+ {$i18n.t('Render messages in compact bubble containers.')} +

+
-
- { - saveSettings({ autoTags }); - }} - /> -
+ {#if !chatBubble} +
+
+
+ {$i18n.t('Display the Username Instead of You in the Chat')}
-

- {$i18n.t('Generate tags for chats automatically.')} -

+ +
+ { + saveSettings({ showUsername }); + }} + /> +
+
+

+ {$i18n.t('Show your username label instead of You in chat bubbles.')} +

+
+ {/if} + +
+
+
+ {$i18n.t('Widescreen Mode')}
-
-
-
- {$i18n.t('Auto-Copy Response to Clipboard')} -
+
+ { + saveSettings({ widescreenMode }); + }} + /> +
+
+

+ {$i18n.t('Use a wider chat layout on large displays.')} +

+
-
- { - toggleResponseAutoCopy(); - }} - /> -
+ {#if $user?.role === 'admin' || $user?.permissions?.chat?.temporary} +
+
+
+ {$i18n.t('Temporary Chat by Default')}
-

- {$i18n.t('Copy the latest assistant response when it completes.')} -

+ +
+ { + saveSettings({ temporaryChatByDefault }); + }} + /> +
+
+

+ {$i18n.t('Start new chats as temporary unless changed.')} +

+
+ {/if} + +
+
+
+ {$i18n.t('Fade Effect for Streaming Text')}
-
-
-
- {$i18n.t('Response Auto-Scroll')} -
+
+ { + saveSettings({ chatFadeStreamingText }); + }} + /> +
+
+

+ {$i18n.t('Fade streaming text as it arrives.')} +

+
-
- { - saveSettings({ scrollOnResponseGeneration }); - }} - /> -
-
-

- {$i18n.t('Follow assistant responses as they are generated.')} -

+
+
+
+ {$i18n.t('Render Markdown in User Messages')}
-
-
-
- {$i18n.t('Scroll On Branch Change')} -
+
+ { + saveSettings({ renderMarkdownInUserMessages }); + }} + /> +
+
+

+ {$i18n.t('Format Markdown syntax in your own messages.')} +

+
-
- { - saveSettings({ scrollOnBranchChange }); - }} - /> -
-
-

- {$i18n.t('Scroll to the active branch when switching response branches.')} -

+
+
+
+ {$i18n.t('Render Markdown in Assistant Messages')}
-
-
-
- {$i18n.t('Insert Suggestion Prompt to Input')} -
+
+ { + saveSettings({ renderMarkdownInAssistantMessages }); + }} + /> +
+
+

+ {$i18n.t('Format Markdown syntax in assistant responses.')} +

+
-
- { - saveSettings({ insertSuggestionPrompt }); - }} - /> -
-
-

- {$i18n.t('Place selected suggestion text into the composer.')} -

+
+
+
+ {$i18n.t('Render Markdown in Previews')}
-
-
-
- {$i18n.t('Keep Follow-Up Prompts in Chat')} -
+
+ { + saveSettings({ renderMarkdownInPreviews }); + }} + /> +
+
+

+ {$i18n.t('Format Markdown in previews and compact content surfaces.')} +

+
-
- { - saveSettings({ keepFollowUpPrompts }); - }} - /> -
-
-

- {$i18n.t('Keep generated follow-up prompts visible in the chat.')} -

+
+
+
+ {$i18n.t('Title Auto-Generation')}
-
-
-
- {$i18n.t('Insert Follow-Up Prompt to Input')} -
+
+ { + toggleTitleAutoGenerate(); + }} + /> +
+
+

+ {$i18n.t('Generate chat titles automatically from conversation content.')} +

+
-
- { - saveSettings({ insertFollowUpPrompt }); - }} - /> -
-
-

- {$i18n.t('Insert selected follow-up prompts directly into the composer.')} -

+
+
+
+ {$i18n.t('Follow-Up Auto-Generation')}
-
-
-
- {$i18n.t('Regenerate Menu')} -
+
+ { + saveSettings({ autoFollowUps }); + }} + /> +
+
+

+ {$i18n.t('Generate suggested follow-up prompts after responses.')} +

+
-
- { - saveSettings({ regenerateMenu }); - }} - /> -
-
-

- {$i18n.t('Show the regenerate action menu for assistant responses.')} -

+
+
+
+ {$i18n.t('Chat Tags Auto-Generation')}
-
-
-
- {$i18n.t('Always Collapse Code Blocks')} -
+
+ { + saveSettings({ autoTags }); + }} + /> +
+
+

+ {$i18n.t('Generate tags for chats automatically.')} +

+
-
- { - saveSettings({ collapseCodeBlocks }); - }} - /> -
-
-

- {$i18n.t('Collapse code blocks by default.')} -

+
+
+
+ {$i18n.t('Auto-Copy Response to Clipboard')}
-
-
-
- {$i18n.t('Always Expand Details')} -
+
+ { + toggleResponseAutoCopy(); + }} + /> +
+
+

+ {$i18n.t('Copy the latest assistant response when it completes.')} +

+
-
- { - saveSettings({ expandDetails }); - }} - /> -
-
-

- {$i18n.t('Open detail blocks by default.')} -

+
+
+
+ {$i18n.t('Response Auto-Scroll')}
-
-
-
- {$i18n.t('Chat Hover Previews')} -
+
+ { + saveSettings({ scrollOnResponseGeneration }); + }} + /> +
+
+

+ {$i18n.t('Follow assistant responses as they are generated.')} +

+
-
- { - saveSettings({ chatHoverPreview }); - }} - /> -
-
-

- {$i18n.t( - 'Show a floating preview of recent messages when hovering a chat in the sidebar.' - )} -

+
+
+
+ {$i18n.t('Scroll On Branch Change')}
-
-
-
- {$i18n.t('Display Multi-model Responses in Tabs')} -
+
+ { + saveSettings({ scrollOnBranchChange }); + }} + /> +
+
+

+ {$i18n.t('Scroll to the active branch when switching response branches.')} +

+
-
- { - saveSettings({ displayMultiModelResponsesInTabs }); - }} - /> -
-
-

- {$i18n.t('Group multi-model responses into tabs.')} -

+
+
+
+ {$i18n.t('Insert Suggestion Prompt to Input')}
-
-
-
- {$i18n.t('Terminal File Display')} -
+
+ { + saveSettings({ insertSuggestionPrompt }); + }} + /> +
+
+

+ {$i18n.t('Place selected suggestion text into the composer.')} +

+
+
+
+
+ {$i18n.t('Keep Follow-Up Prompts in Chat')} +
+ +
+ { + saveSettings({ keepFollowUpPrompts }); + }} + /> +
+
+

+ {$i18n.t('Keep generated follow-up prompts visible in the chat.')} +

+
+ +
+
+
+ {$i18n.t('Insert Follow-Up Prompt to Input')} +
+ +
+ { + saveSettings({ insertFollowUpPrompt }); + }} + /> +
+
+

+ {$i18n.t('Insert selected follow-up prompts directly into the composer.')} +

+
+ +
+
+
+ {$i18n.t('Regenerate Menu')} +
+ +
+ { + saveSettings({ regenerateMenu }); + }} + /> +
+
+

+ {$i18n.t('Show the regenerate action menu for assistant responses.')} +

+
+ +
+
+
+ {$i18n.t('Always Collapse Code Blocks')} +
+ +
+ { + saveSettings({ collapseCodeBlocks }); + }} + /> +
+
+

+ {$i18n.t('Collapse code blocks by default.')} +

+
+ +
+
+
+ {$i18n.t('Always Expand Details')} +
+ +
+ { + saveSettings({ expandDetails }); + }} + /> +
+
+

+ {$i18n.t('Open detail blocks by default.')} +

+
+ +
+
+
+ {$i18n.t('Chat Hover Previews')} +
+ +
+ { + saveSettings({ chatHoverPreview }); + }} + /> +
+
+

+ {$i18n.t('Show a floating preview of recent messages when hovering a chat in the sidebar.')} +

+
+ +
+
+
+ {$i18n.t('Display Multi-model Responses in Tabs')} +
+ +
+ { + saveSettings({ displayMultiModelResponsesInTabs }); + }} + /> +
+
+

+ {$i18n.t('Group multi-model responses into tabs.')} +

+
+ +
+
+
+ {$i18n.t('Terminal File Display')} +
+ + +
+

+ {$i18n.t('Choose where terminal display_file results appear by default.')} +

+
+ +
+
+
+ {$i18n.t('Show Files on Terminal Select')} +
+ +
+ { + saveSettings({ showFilesOnTerminalSelect }); + }} + /> +
+
+

+ {$i18n.t('Open the file browser after selecting a terminal.')} +

+
+ +
+
+
+ {$i18n.t('Terminal Preview Allow Same Origin')} +
+ +
+ { + saveSettings({ terminalPreviewAllowSameOrigin }); + }} + /> +
+
+

+ {$i18n.t('Allow terminal previews to access same-origin browser APIs.')} +

+
+ +
+
+
+ {$i18n.t('Stylized PDF Export')} +
+ +
+ { + saveSettings({ stylizedPdfExport }); + }} + /> +
+
+

+ {$i18n.t('Use styled formatting when exporting chats to PDF.')} +

+
+ +
+
+
+ {$i18n.t('Floating Quick Actions')} +
+ +
+ {#if showFloatingActionButtons} -
-

- {$i18n.t('Choose where terminal display_file results appear by default.')} -

+ {/if} + + { + saveSettings({ showFloatingActionButtons }); + }} + /> +
+
+

+ {$i18n.t('Show the floating quick-action toolbar in chat.')} +

+
+ +
+
+
+ {$i18n.t('Web Search in Chat')}
-
-
-
- {$i18n.t('Show Files on Terminal Select')} -
+ +
+

+ {$i18n.t('Set web search availability for new chats.')} +

+
-
- { - saveSettings({ showFilesOnTerminalSelect }); - }} - /> -
-
-

- {$i18n.t('Open the file browser after selecting a terminal.')} -

+
{$i18n.t('Input')}
+ +
+
+
+ {$i18n.t('Enter Key Behavior')}
-
-
-
- {$i18n.t('Terminal Preview Allow Same Origin')} -
+ +
+

+ {$i18n.t('Choose whether Enter sends immediately or uses Ctrl+Enter.')} +

+
-
- { - saveSettings({ terminalPreviewAllowSameOrigin }); - }} - /> -
-
-

- {$i18n.t('Allow terminal previews to access same-origin browser APIs.')} -

+
+
+
+ {$i18n.t('Rich Text Input for Chat')}
-
-
-
- {$i18n.t('Stylized PDF Export')} -
+
+ { + saveSettings({ richTextInput }); + }} + /> +
+
+

+ {$i18n.t('Use the rich composer instead of a plain textarea.')} +

+
-
- { - saveSettings({ stylizedPdfExport }); - }} - /> -
+ {#if $config?.features?.enable_autocomplete_generation} +
+
+
+ {$i18n.t('Prompt Autocompletion')}
-

- {$i18n.t('Use styled formatting when exporting chats to PDF.')} -

+ +
+ { + saveSettings({ promptAutocomplete }); + }} + /> +
+
+

+ {$i18n.t('Suggest completions while composing prompts.')} +

+
+ {/if} + + {#if richTextInput} +
+
+
+ {$i18n.t('Show Formatting Toolbar')} +
+ +
+ { + saveSettings({ showFormattingToolbar }); + }} + /> +
+
+

+ {$i18n.t('Show formatting controls in the rich text composer.')} +

+
+ +
+
+
+ {$i18n.t('Insert Prompt as Rich Text')} +
+ +
+ { + saveSettings({ insertPromptAsRichText }); + }} + /> +
+
+

+ {$i18n.t('Paste inserted prompts as rich text when possible.')} +

+
+ {/if} + +
+
+
+ {$i18n.t('Paste Large Text as File')}
-
-
-
- {$i18n.t('Floating Quick Actions')} -
+
+ { + saveSettings({ largeTextAsFile }); + }} + /> +
+
+

+ {$i18n.t('Convert long pasted text into a file attachment.')} +

+
-
- {#if showFloatingActionButtons} - - {/if} +
{$i18n.t('Artifacts')}
- { - saveSettings({ showFloatingActionButtons }); - }} - /> -
-
-

- {$i18n.t('Show the floating quick-action toolbar in chat.')} -

+
+
+
+ {$i18n.t('Detect Artifacts Automatically')}
-
-
-
- {$i18n.t('Web Search in Chat')} -
+
+ { + saveSettings({ detectArtifacts }); + }} + /> +
+
+

+ {$i18n.t('Detect generated artifacts and show them in the artifact workspace.')} +

+
+
+
+
+ {$i18n.t('iframe Sandbox Allow Scripts')} +
+ +
+ { + saveSettings({ iframeSandboxAllowScripts }); + }} + /> +
+
+

+ {$i18n.t('Allow scripts inside sandboxed iframes.')} +

+
+ +
+
+
+ {$i18n.t('iframe Sandbox Allow Same Origin')} +
+ +
+ { + saveSettings({ iframeSandboxAllowSameOrigin }); + }} + /> +
+
+

+ {$i18n.t('Allow artifacts to access same-origin browser APIs inside the sandbox.')} +

+
+ +
+
+
+ {$i18n.t('iframe Sandbox Allow Forms')} +
+ +
+ { + saveSettings({ iframeSandboxAllowForms }); + }} + /> +
+
+

+ {$i18n.t('Allow forms inside sandboxed artifact iframes.')} +

+
+ +
+
+
+ {$i18n.t('iframe Sandbox Allow Downloads')} +
+ +
+ { + saveSettings({ iframeSandboxAllowDownloads }); + }} + /> +
+
+

+ {$i18n.t('Allow downloads inside sandboxed iframes.')} +

+
+ +
{$i18n.t('Voice')}
+ +
+
+
+ {$i18n.t('Allow Voice Interruption in Call')} +
+ +
+ { + saveSettings({ voiceInterruption }); + }} + /> +
+
+

+ {$i18n.t('Let speech interrupt the assistant during a voice call.')} +

+
+ +
+
+
+ {$i18n.t('Display Emoji in Call')} +
+ +
+ { + saveSettings({ showEmojiInCall }); + }} + /> +
+
+

+ {$i18n.t('Show emoji feedback in the call interface.')} +

+
+ +
{$i18n.t('File')}
+ +
+
+
+ {$i18n.t('Default Upload Mode')} +
+ + +
+

+ {$i18n.t('Attach files with full content or focused retrieval by default.')} +

+
+ +
+
+
+ {$i18n.t('Image Compression')} +
+ +
+ {#if imageCompression} -
-

- {$i18n.t('Set web search availability for new chats.')} -

-
- -
{$i18n.t('Input')}
- -
-
-
- {$i18n.t('Enter Key Behavior')} -
- - -
-

- {$i18n.t('Choose whether Enter sends immediately or uses Ctrl+Enter.')} -

+ {/if} + + { + saveSettings({ imageCompression }); + }} + />
+
+

+ {$i18n.t('Compress uploaded images before sending or storage.')} +

+
-
-
-
- {$i18n.t('Rich Text Input for Chat')} -
- -
- { - saveSettings({ richTextInput }); - }} - /> -
-
-

- {$i18n.t('Use the rich composer instead of a plain textarea.')} -

-
- - {#if $config?.features?.enable_autocomplete_generation} -
-
-
- {$i18n.t('Prompt Autocompletion')} -
- -
- { - saveSettings({ promptAutocomplete }); - }} - /> -
-
-

- {$i18n.t('Suggest completions while composing prompts.')} -

-
- {/if} - - {#if richTextInput} -
-
-
- {$i18n.t('Show Formatting Toolbar')} -
- -
- { - saveSettings({ showFormattingToolbar }); - }} - /> -
-
-

- {$i18n.t('Show formatting controls in the rich text composer.')} -

+ {#if imageCompression} +
+
+
+ {$i18n.t('Compress Images in Channels')}
-
-
-
- {$i18n.t('Insert Prompt as Rich Text')} -
- -
- { - saveSettings({ insertPromptAsRichText }); - }} - /> -
-
-

- {$i18n.t('Paste inserted prompts as rich text when possible.')} -

-
- {/if} - -
-
-
- {$i18n.t('Paste Large Text as File')} -
- -
- { - saveSettings({ largeTextAsFile }); - }} - /> -
-
-

- {$i18n.t('Convert long pasted text into a file attachment.')} -

-
- -
{$i18n.t('Artifacts')}
- -
-
-
- {$i18n.t('Detect Artifacts Automatically')} -
- -
- { - saveSettings({ detectArtifacts }); - }} - /> -
-
-

- {$i18n.t('Detect generated artifacts and show them in the artifact workspace.')} -

-
- -
-
-
- {$i18n.t('iframe Sandbox Allow Scripts')} -
- -
- { - saveSettings({ iframeSandboxAllowScripts }); - }} - /> -
-
-

- {$i18n.t('Allow scripts inside sandboxed iframes.')} -

-
- -
-
-
- {$i18n.t('iframe Sandbox Allow Same Origin')} -
- -
- { - saveSettings({ iframeSandboxAllowSameOrigin }); - }} - /> -
-
-

- {$i18n.t('Allow artifacts to access same-origin browser APIs inside the sandbox.')} -

-
- -
-
-
- {$i18n.t('iframe Sandbox Allow Forms')} -
- -
- { - saveSettings({ iframeSandboxAllowForms }); - }} - /> -
-
-

- {$i18n.t('Allow forms inside sandboxed artifact iframes.')} -

-
- -
-
-
- {$i18n.t('iframe Sandbox Allow Downloads')} -
- -
- { - saveSettings({ iframeSandboxAllowDownloads }); - }} - /> -
-
-

- {$i18n.t('Allow downloads inside sandboxed iframes.')} -

-
- -
{$i18n.t('Voice')}
- -
-
-
- {$i18n.t('Allow Voice Interruption in Call')} -
- -
- { - saveSettings({ voiceInterruption }); - }} - /> -
-
-

- {$i18n.t('Let speech interrupt the assistant during a voice call.')} -

-
- -
-
-
- {$i18n.t('Display Emoji in Call')} -
- -
- { - saveSettings({ showEmojiInCall }); - }} - /> -
-
-

- {$i18n.t('Show emoji feedback in the call interface.')} -

-
- -
{$i18n.t('File')}
- -
-
-
- {$i18n.t('Default Upload Mode')} -
- - + />
-

- {$i18n.t('Attach files with full content or focused retrieval by default.')} -

- -
-
-
- {$i18n.t('Image Compression')} -
- -
- {#if imageCompression} - - {/if} - - { - saveSettings({ imageCompression }); - }} - /> -
-
-

- {$i18n.t('Compress uploaded images before sending or storage.')} -

-
- - {#if imageCompression} -
-
-
- {$i18n.t('Compress Images in Channels')} -
- -
- { - saveSettings({ imageCompressionInChannels }); - }} - /> -
-
-

- {$i18n.t('Apply image compression to channel uploads too.')} -

-
- {/if} +

+ {$i18n.t('Apply image compression to channel uploads too.')} +

+
+ {/if}
diff --git a/src/lib/components/common/PDFViewer.svelte b/src/lib/components/common/PDFViewer.svelte index 0836efe81c..e409b24a7d 100644 --- a/src/lib/components/common/PDFViewer.svelte +++ b/src/lib/components/common/PDFViewer.svelte @@ -107,7 +107,8 @@ await tick(); const pageWrapper = sceneElement.querySelectorAll('.pdf-page-wrapper')[page - 1] as - HTMLElement | undefined; + | HTMLElement + | undefined; pageWrapper?.scrollIntoView({ block: 'start' }); }; diff --git a/src/lib/components/layout/Sidebar/ChatHoverPreview.svelte b/src/lib/components/layout/Sidebar/ChatHoverPreview.svelte index 554098e6d1..69d7fc1233 100644 --- a/src/lib/components/layout/Sidebar/ChatHoverPreview.svelte +++ b/src/lib/components/layout/Sidebar/ChatHoverPreview.svelte @@ -100,7 +100,9 @@ {sideOffset} >
-
+
{title || $i18n.t('Chat')}
diff --git a/src/lib/components/workspace/Skills/SkillEditor.svelte b/src/lib/components/workspace/Skills/SkillEditor.svelte index 06495ac2f5..ae0923dd63 100644 --- a/src/lib/components/workspace/Skills/SkillEditor.svelte +++ b/src/lib/components/workspace/Skills/SkillEditor.svelte @@ -178,7 +178,8 @@
{#if disabled}
-
{content}
+
{content}
{:else}