From c6d80496abe7fb5d3a122332025334f04b5a989a Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Sat, 23 Aug 2025 15:08:07 -0400 Subject: [PATCH 001/421] feat: improve ollama model management experience This commit introduces several improvements to the Ollama model management modal: - Adds a cancel button to the model pulling operation, using the existing 'x' button pattern. - Adds a cancel button to the "Update All" models operation, allowing the user to cancel the update for the currently processing model. - Cleans up toast notifications when updating all models. A single toast is now shown at the beginning and a summary toast at the end, preventing notification spam. - Refactors the `ManageOllama.svelte` component to support these new cancellation features. - Adds tooltips to all buttons in the modal to improve clarity. - Disables buttons when their corresponding input fields are empty to prevent accidental clicks. --- .../Models/Manage/ManageOllama.svelte | 374 +++++++++++------- 1 file changed, 225 insertions(+), 149 deletions(-) diff --git a/src/lib/components/admin/Settings/Models/Manage/ManageOllama.svelte b/src/lib/components/admin/Settings/Models/Manage/ManageOllama.svelte index fbfcf93677..29682a7a37 100644 --- a/src/lib/components/admin/Settings/Models/Manage/ManageOllama.svelte +++ b/src/lib/components/admin/Settings/Models/Manage/ManageOllama.svelte @@ -36,6 +36,8 @@ let updateModelId = null; let updateProgress = null; + let updateModelsControllers = {}; + let updateCancelled = false; let showExperimentalOllama = false; const MAX_PARALLEL_DOWNLOADS = 3; @@ -65,17 +67,31 @@ let deleteModelTag = ''; const updateModelsHandler = async () => { + updateCancelled = false; + toast.info('Checking for model updates...'); + for (const model of ollamaModels) { + if (updateCancelled) { + break; + } + console.debug(model); updateModelId = model.id; const [res, controller] = await pullModel(localStorage.token, model.id, urlIdx).catch( (error) => { - toast.error(`${error}`); - return null; + if (error.name !== 'AbortError') { + toast.error(`${error}`); + } + return [null, null]; } ); + updateModelsControllers = { + ...updateModelsControllers, + [model.id]: controller + }; + if (res) { const reader = res.body .pipeThrough(new TextDecoderStream()) @@ -108,19 +124,28 @@ } else { updateProgress = 100; } - } else { - toast.success(data.status); } } } } } catch (err) { - console.error(err); + if (err.name !== 'AbortError') { + console.error(err); + } + break; } } } + + delete updateModelsControllers[model.id]; + updateModelsControllers = { ...updateModelsControllers }; } + if (updateCancelled) { + toast.info('Model update cancelled'); + } else { + toast.success('All models are up to date'); + } updateModelId = null; updateProgress = null; }; @@ -143,10 +168,13 @@ return; } + modelTransferring = true; const [res, controller] = await pullModel(localStorage.token, sanitizedModelTag, urlIdx).catch( (error) => { - toast.error(`${error}`); - return null; + if (error.name !== 'AbortError') { + toast.error(`${error}`); + } + return [null, null]; } ); @@ -202,8 +230,6 @@ } }); } else { - toast.success(data.status); - MODEL_DOWNLOAD_POOL.set({ ...$MODEL_DOWNLOAD_POOL, [sanitizedModelTag]: { @@ -216,19 +242,23 @@ } } } catch (err) { - console.error(err); - if (typeof err !== 'string') { - err = err.message; - } + if (err.name !== 'AbortError') { + console.error(err); + if (typeof err !== 'string') { + err = err.message; + } - toast.error(`${err}`); - // opts.callback({ success: false, error, modelName: opts.modelName }); + toast.error(`${err}`); + // opts.callback({ success: false, error, modelName: opts.modelName }); + } else { + break; + } } } console.log($MODEL_DOWNLOAD_POOL[sanitizedModelTag]); - if ($MODEL_DOWNLOAD_POOL[sanitizedModelTag].done) { + if ($MODEL_DOWNLOAD_POOL[sanitizedModelTag]?.done) { toast.success( $i18n.t(`Model '{{modelName}}' has been successfully downloaded.`, { modelName: sanitizedModelTag @@ -425,6 +455,14 @@ ); }; + const cancelUpdateModelHandler = async (model: string) => { + const controller = updateModelsControllers[model]; + if (controller) { + controller.abort(); + updateCancelled = true; + } + }; + const cancelModelPullHandler = async (model: string) => { const { reader, abortController } = $MODEL_DOWNLOAD_POOL[model]; if (abortController) { @@ -437,7 +475,7 @@ ...$MODEL_DOWNLOAD_POOL }); await deleteModel(localStorage.token, model); - toast.success($i18n.t('{{model}} download has been canceled', { model: model })); + toast.success(`${model} download has been canceled`); } }; @@ -605,59 +643,61 @@ bind:value={modelTag} /> - + {/if} + +
@@ -670,8 +710,35 @@
{#if updateModelId} -
- Updating "{updateModelId}" {updateProgress ? `(${updateProgress}%)` : ''} +
+
Updating "{updateModelId}" {updateProgress ? `(${updateProgress}%)` : ''}
+ + + +
{/if} @@ -754,25 +821,28 @@ {/each}
- + + + + + @@ -799,27 +869,31 @@
- + + + + + +
@@ -936,57 +1010,59 @@ {#if (modelUploadMode === 'file' && modelInputFile && modelInputFile.length > 0) || (modelUploadMode === 'url' && modelFileUrl !== '')} - + {/if} + + {/if} From 8df74dde80271d7b0083e73677c90401910c5516 Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Sat, 23 Aug 2025 15:19:35 -0400 Subject: [PATCH 002/421] fix --- .../components/admin/Settings/Models/Manage/ManageOllama.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/admin/Settings/Models/Manage/ManageOllama.svelte b/src/lib/components/admin/Settings/Models/Manage/ManageOllama.svelte index 29682a7a37..6c73b7a4a0 100644 --- a/src/lib/components/admin/Settings/Models/Manage/ManageOllama.svelte +++ b/src/lib/components/admin/Settings/Models/Manage/ManageOllama.svelte @@ -475,7 +475,7 @@ ...$MODEL_DOWNLOAD_POOL }); await deleteModel(localStorage.token, model); - toast.success(`${model} download has been canceled`); + toast.success($i18n.t('{{model}} download has been canceled', { model: model })); } }; From e214d59d109a11eb61bad1a58208d6ae89d66a5b Mon Sep 17 00:00:00 2001 From: Andrew Baek Date: Wed, 27 Aug 2025 01:04:27 +0900 Subject: [PATCH 003/421] Update groups.py fix issue #16870 --- backend/open_webui/models/groups.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/models/groups.py b/backend/open_webui/models/groups.py index 6615f95142..1c84f4c1ae 100644 --- a/backend/open_webui/models/groups.py +++ b/backend/open_webui/models/groups.py @@ -12,6 +12,7 @@ from open_webui.models.files import FileMetadataResponse from pydantic import BaseModel, ConfigDict from sqlalchemy import BigInteger, Column, String, Text, JSON, func +from sqlalchemy.ext.mutable import MutableList log = logging.getLogger(__name__) @@ -35,7 +36,7 @@ class Group(Base): meta = Column(JSON, nullable=True) permissions = Column(JSON, nullable=True) - user_ids = Column(JSON, nullable=True) + user_ids = Column(MutableList.as_mutable(JSON), nullable=True) created_at = Column(BigInteger) updated_at = Column(BigInteger) From ceaafbbfd21dc3ab766066a1b6253f05560361b1 Mon Sep 17 00:00:00 2001 From: Andrew Baek Date: Wed, 27 Aug 2025 03:22:34 +0900 Subject: [PATCH 004/421] Update groups.py --- backend/open_webui/models/groups.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/open_webui/models/groups.py b/backend/open_webui/models/groups.py index 4c636b4f0f..a09b2b73f9 100644 --- a/backend/open_webui/models/groups.py +++ b/backend/open_webui/models/groups.py @@ -12,7 +12,6 @@ from open_webui.models.files import FileMetadataResponse from pydantic import BaseModel, ConfigDict from sqlalchemy import BigInteger, Column, String, Text, JSON, func -from sqlalchemy.ext.mutable import MutableList log = logging.getLogger(__name__) @@ -36,7 +35,7 @@ class Group(Base): meta = Column(JSON, nullable=True) permissions = Column(JSON, nullable=True) - user_ids = Column(MutableList.as_mutable(JSON), nullable=True) + user_ids = Column(JSON, nullable=True) created_at = Column(BigInteger) updated_at = Column(BigInteger) From b50ae5bf694a070147ea770e27bb1c146dbfacdf Mon Sep 17 00:00:00 2001 From: Andrew Baek Date: Sun, 31 Aug 2025 14:48:37 +0900 Subject: [PATCH 005/421] Update MessageInput.svelte --- src/lib/components/chat/MessageInput.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index adea345ed0..407cb2262f 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -1051,6 +1051,7 @@
{#if files.length > 0}
From 7c0bf59c7c42d882edd9ed001949c65def889945 Mon Sep 17 00:00:00 2001 From: Aleix Dorca Date: Fri, 5 Sep 2025 17:17:20 +0200 Subject: [PATCH 006/421] Update catalan translation.json --- src/lib/i18n/locales/ca-ES/translation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/i18n/locales/ca-ES/translation.json b/src/lib/i18n/locales/ca-ES/translation.json index d83fd1c8c4..0915b05f0a 100644 --- a/src/lib/i18n/locales/ca-ES/translation.json +++ b/src/lib/i18n/locales/ca-ES/translation.json @@ -237,7 +237,7 @@ "Clear memory": "Esborrar la memòria", "Clear Memory": "Esborrar la memòria", "click here": "prem aquí", - "Click here for filter guides.": "Clica aquí per filtrar les guies.", + "Click here for filter guides.": "Clica aquí per l'ajuda dels filtres.", "Click here for help.": "Clica aquí per obtenir ajuda.", "Click here to": "Clic aquí per", "Click here to download user import template file.": "Fes clic aquí per descarregar l'arxiu de plantilla d'importació d'usuaris", From 4ca43004edcb47332aac3dad3817df967ee5817a Mon Sep 17 00:00:00 2001 From: Jesper Kristensen Date: Fri, 5 Sep 2025 12:50:27 +0200 Subject: [PATCH 007/421] feat: Added support for redis as session storage --- backend/open_webui/main.py | 48 ++++++++++++++++++++++++++++++++------ backend/requirements.txt | 1 + 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index a5d55f75ab..1153692fb3 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -50,6 +50,11 @@ from starlette.middleware.sessions import SessionMiddleware from starlette.responses import Response, StreamingResponse from starlette.datastructures import Headers +from starsessions import ( + SessionMiddleware as StarSessionsMiddleware, + SessionAutoloadMiddleware, +) +from starsessions.stores.redis import RedisStore from open_webui.utils import logger from open_webui.utils.audit import AuditLevel, AuditLoggingMiddleware @@ -1897,13 +1902,42 @@ async def get_current_usage(user=Depends(get_verified_user)): # SessionMiddleware is used by authlib for oauth if len(OAUTH_PROVIDERS) > 0: - app.add_middleware( - SessionMiddleware, - secret_key=WEBUI_SECRET_KEY, - session_cookie="oui-session", - same_site=WEBUI_SESSION_COOKIE_SAME_SITE, - https_only=WEBUI_SESSION_COOKIE_SECURE, - ) + try: + # Try to create Redis store for sessions + if REDIS_URL: + redis_session_store = RedisStore( + url=REDIS_URL, + prefix=( + f"{REDIS_KEY_PREFIX}:session:" if REDIS_KEY_PREFIX else "session:" + ), + ) + + # Add SessionAutoloadMiddleware first to handle session loading + app.add_middleware(SessionAutoloadMiddleware) + + app.add_middleware( + StarSessionsMiddleware, + store=redis_session_store, + cookie_name="oui-session", + cookie_same_site=WEBUI_SESSION_COOKIE_SAME_SITE, + cookie_https_only=WEBUI_SESSION_COOKIE_SECURE, + ) + log.info("Using StarSessions with Redis for session management") + else: + raise ValueError("Redis URL not configured") + + except Exception as e: + log.warning( + f"Failed to initialize Redis sessions, falling back to cookie based sessions: {e}" + ) + # Fallback to existing SessionMiddleware + app.add_middleware( + SessionMiddleware, + secret_key=WEBUI_SECRET_KEY, + session_cookie="oui-session", + same_site=WEBUI_SESSION_COOKIE_SAME_SITE, + https_only=WEBUI_SESSION_COOKIE_SECURE, + ) @app.get("/oauth/{provider}/login") diff --git a/backend/requirements.txt b/backend/requirements.txt index 5871015075..f712423631 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -15,6 +15,7 @@ aiocache aiofiles starlette-compress==1.6.0 httpx[socks,http2,zstd,cli,brotli]==0.28.1 +starsessions[redis]==2.2.1 sqlalchemy==2.0.38 alembic==1.14.0 From b1cba685f47e737b23069614b4b4443df1c2d5aa Mon Sep 17 00:00:00 2001 From: _00_ <131402327+rgaricano@users.noreply.github.com> Date: Sat, 13 Sep 2025 00:04:30 +0200 Subject: [PATCH 008/421] UPD: i18n es-ES Translation - dev_v0.6.28 ### UPD: i18n es-ES Translation - dev_v0.6.28 - Translated added strings. --- src/lib/i18n/locales/es-ES/translation.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/i18n/locales/es-ES/translation.json b/src/lib/i18n/locales/es-ES/translation.json index a952fc60fe..04167e0c77 100644 --- a/src/lib/i18n/locales/es-ES/translation.json +++ b/src/lib/i18n/locales/es-ES/translation.json @@ -16,7 +16,7 @@ "{{COUNT}} Replies": "{{COUNT}} Respuestas", "{{COUNT}} Sources": "{{COUNT}} Fuentes", "{{COUNT}} words": "{{COUNT}} palabras", - "{{LOCALIZED_DATE}} at {{LOCALIZED_TIME}}": "", + "{{LOCALIZED_DATE}} at {{LOCALIZED_TIME}}": "{{LOCALIZED_DATE}} a las {{LOCALIZED_TIME}}", "{{model}} download has been canceled": "La descarga de {{model}} ha sido cancelada", "{{user}}'s Chats": "Chats de {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Servidor Requerido", @@ -147,8 +147,8 @@ "Ask a question": "Haz una pregunta", "Assistant": "Asistente", "Attach file from knowledge": "Adjuntar archivo desde conocimiento", - "Attach Knowledge": "", - "Attach Notes": "", + "Attach Knowledge": "Adjuntar Conocimiento", + "Attach Notes": "Adjuntar Notas", "Attention to detail": "Atención al detalle", "Attribute for Mail": "Atributo para Correo", "Attribute for Username": "Atributo para Nombre de Usuario", @@ -854,7 +854,7 @@ "Install from Github URL": "Instalar desde la URL de Github", "Instant Auto-Send After Voice Transcription": "AutoEnvio Instantaneo tras la Transcripción de Voz", "Integration": "Integración", - "Integrations": "", + "Integrations": "Integraciones", "Interface": "Interfaz", "Invalid file content": "Contenido de archivo inválido", "Invalid file format.": "Formato de archivo inválido.", @@ -913,7 +913,7 @@ "Leave empty to include all models or select specific models": "Dejar vacío para incluir todos los modelos o Seleccionar modelos específicos", "Leave empty to use the default prompt, or enter a custom prompt": "Dejar vacío para usar el indicador predeterminado, o Ingresar un indicador personalizado", "Leave model field empty to use the default model.": "Dejar vacío el campo modelo para usar el modelo predeterminado.", - "Legacy": "", + "Legacy": "Heredado", "lexical": "léxica", "License": "Licencia", "Lift List": "Desplegar Lista", @@ -1226,7 +1226,7 @@ "Rename": "Renombrar", "Reorder Models": "Reordenar Modelos", "Reply in Thread": "Responder en Hilo", - "required": "", + "required": "requerido", "Reranking Engine": "Motor de Reclasificación", "Reranking Model": "Modelo de Reclasificación", "Reset": "Reiniciar", @@ -1519,7 +1519,7 @@ "To select toolkits here, add them to the \"Tools\" workspace first.": "Para seleccionar herramientas aquí, primero añadelas a \"Herramientas\" en el área de trabajo.", "Toast notifications for new updates": "Notificaciones emergentes para nuevas actualizaciones", "Today": "Hoy", - "Today at {{LOCALIZED_TIME}}": "", + "Today at {{LOCALIZED_TIME}}": "Hoy a las {{LOCALIZED_TIME}}", "Toggle search": "Alternar busqueda", "Toggle settings": "Alternar Ajustes", "Toggle sidebar": "Alternar Barra Lateral", @@ -1660,7 +1660,7 @@ "Yacy Password": "Contraseña de Yacy", "Yacy Username": "Usuario de Yacy", "Yesterday": "Ayer", - "Yesterday at {{LOCALIZED_TIME}}": "", + "Yesterday at {{LOCALIZED_TIME}}": "Ayer a las {{LOCALIZED_TIME}}", "You": "Tu", "You are currently using a trial license. Please contact support to upgrade your license.": "Actualmente estás utilizando una licencia de prueba. Por favor, para actualizar su licencia contacta con soporte.", "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Solo puedes chatear con un máximo de {{maxCount}} archivo(s) a la vez.", From 7f41bb6118e8529fd03dcfd6d12b73a835bc7e8e Mon Sep 17 00:00:00 2001 From: _00_ <131402327+rgaricano@users.noreply.github.com> Date: Sat, 13 Sep 2025 00:23:53 +0200 Subject: [PATCH 009/421] Update translation.json --- src/lib/i18n/locales/es-ES/translation.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/i18n/locales/es-ES/translation.json b/src/lib/i18n/locales/es-ES/translation.json index 04167e0c77..7f4d57478f 100644 --- a/src/lib/i18n/locales/es-ES/translation.json +++ b/src/lib/i18n/locales/es-ES/translation.json @@ -367,7 +367,9 @@ "Default (Open AI)": "Predeterminado (Open AI)", "Default (SentenceTransformers)": "Predeterminado (SentenceTransformers)", "Default action buttons will be used.": "Se usara la acción predeterminada para el botón", - "Default description enabled": "Descripción por defecto activada", + "Default description enabled": "Descripción predeterminada activada", + "Default Features": "Características Predeterminadas", + "Default Filters": "Filtros Predeterminados", "Default mode works with a wider range of models by calling tools once before execution. Native mode leverages the model's built-in tool-calling capabilities, but requires the model to inherently support this feature.": "El modo predeterminado trabaja con un amplio rango de modelos, llamando a las herramientas una vez antes de la ejecución. El modo nativo aprovecha las capacidades de llamada de herramientas integradas del modelo, pero requiere que el modelo admita inherentemente esta función.", "Default Model": "Modelo Predeterminado", "Default model updated": "El modelo Predeterminado ha sido actualizado", From f9fd22d98e048e380208ab86bdee652e7794724c Mon Sep 17 00:00:00 2001 From: Alexandre Oliveira Date: Sat, 13 Sep 2025 12:57:54 -0300 Subject: [PATCH 010/421] fix: setting file_handler in a filter would generate errors in messages with no files, because a "files: Null" in metadata would trigger an attempt to delete a non existent files object --- backend/open_webui/utils/filter.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/backend/open_webui/utils/filter.py b/backend/open_webui/utils/filter.py index 1986e55b64..663b4e3fb7 100644 --- a/backend/open_webui/utils/filter.py +++ b/backend/open_webui/utils/filter.py @@ -127,8 +127,10 @@ async def process_filter_functions( raise e # Handle file cleanup for inlet - if skip_files and "files" in form_data.get("metadata", {}): - del form_data["files"] - del form_data["metadata"]["files"] + if skip_files: + if "files" in form_data.get("metadata", {}): + del form_data["metadata"]["files"] + if "files" in form_data: + del form_data["files"] return form_data, {} From 4e21e4ba0e75fb32c9227e751b5994efcdb493ef Mon Sep 17 00:00:00 2001 From: Kylapaallikko Date: Sun, 14 Sep 2025 17:40:55 +0300 Subject: [PATCH 011/421] Update fi-FI translation.json Added missing translations --- src/lib/i18n/locales/fi-FI/translation.json | 108 ++++++++++---------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/lib/i18n/locales/fi-FI/translation.json b/src/lib/i18n/locales/fi-FI/translation.json index 91d964ef51..16bd6f81c1 100644 --- a/src/lib/i18n/locales/fi-FI/translation.json +++ b/src/lib/i18n/locales/fi-FI/translation.json @@ -11,17 +11,17 @@ "{{ models }}": "{{ mallit }}", "{{COUNT}} Available Tools": "{{COUNT}} työkalua saatavilla", "{{COUNT}} characters": "{{COUNT}} kirjainta", - "{{COUNT}} extracted lines": "", + "{{COUNT}} extracted lines": "{{COUNT}} poimittua riviä", "{{COUNT}} hidden lines": "{{COUNT}} piilotettua riviä", "{{COUNT}} Replies": "{{COUNT}} vastausta", - "{{COUNT}} Sources": "", + "{{COUNT}} Sources": "{{COUNT}} lähdettä", "{{COUNT}} words": "{{COUNT}} sanaa", "{{LOCALIZED_DATE}} at {{LOCALIZED_TIME}}": "", - "{{model}} download has been canceled": "", + "{{model}} download has been canceled": "{{model}} lataus peruttu", "{{user}}'s Chats": "{{user}}:n keskustelut", "{{webUIName}} Backend Required": "{{webUIName}}-backend vaaditaan", "*Prompt node ID(s) are required for image generation": "Kuvan luomiseen vaaditaan kehote-solmun ID(t)", - "1 Source": "", + "1 Source": "1 lähde", "A new version (v{{LATEST_VERSION}}) is now available.": "Uusi versio (v{{LATEST_VERSION}}) on nyt saatavilla.", "A task model is used when performing tasks such as generating titles for chats and web search queries": "Tehtävämallia käytetään tehtävien suorittamiseen, kuten otsikoiden luomiseen keskusteluille ja verkkohakukyselyille", "a user": "käyttäjä", @@ -32,7 +32,7 @@ "Accessible to all users": "Käytettävissä kaikille käyttäjille", "Account": "Tili", "Account Activation Pending": "Tilin aktivointi odottaa", - "accurate": "", + "accurate": "tarkka", "Accurate information": "Tarkkaa tietoa", "Action": "Toiminto", "Action not found": "Toimintoa ei löytynyt", @@ -87,13 +87,13 @@ "Allow Chat Share": "Salli keskustelujen jako", "Allow Chat System Prompt": "Salli keskustelujen järjestelmä kehoitteet", "Allow Chat Valves": "Salli keskustelu venttiilit", - "Allow Continue Response": "", - "Allow Delete Messages": "", + "Allow Continue Response": "Salli jatka vastausta", + "Allow Delete Messages": "Salli viestien poisto", "Allow File Upload": "Salli tiedostojen lataus", "Allow Multiple Models in Chat": "Salli useampi malli keskustelussa", "Allow non-local voices": "Salli ei-paikalliset äänet", - "Allow Rate Response": "", - "Allow Regenerate Response": "", + "Allow Rate Response": "Salli viestien arviointi", + "Allow Regenerate Response": "Salli uudelleen regenerointi", "Allow Speech to Text": "Salli puhe tekstiksi", "Allow Temporary Chat": "Salli väliaikaiset keskustelut", "Allow Text to Speech": "Salli teksti puheeksi", @@ -147,8 +147,8 @@ "Ask a question": "Kysyä kysymys", "Assistant": "Avustaja", "Attach file from knowledge": "Liitä tiedosto tietokannasta", - "Attach Knowledge": "", - "Attach Notes": "", + "Attach Knowledge": "Liitä tietoa", + "Attach Notes": "Liitä muistiinpanoja", "Attention to detail": "Huomio yksityiskohtiin", "Attribute for Mail": "Attribuutti sähköpostille", "Attribute for Username": "Attribuutti käyttäjätunnukselle", @@ -179,7 +179,7 @@ "Bad Response": "Huono vastaus", "Banners": "Bannerit", "Base Model (From)": "Perusmalli (alkaen)", - "Base Model List Cache speeds up access by fetching base models only at startup or on settings save—faster, but may not show recent base model changes.": "", + "Base Model List Cache speeds up access by fetching base models only at startup or on settings save—faster, but may not show recent base model changes.": "Perusmalliluettelon välimuisti nopeuttaa käyttöä hakemalla perusmallit vain käynnistyksen yhteydessä tai asetusten tallentamisen yhteydessä - nopeampaa, mutta ei välttämättä näytä viimeisimpiä perusmallin muutoksia.", "Bearer": "Bearer", "before": "ennen", "Being lazy": "Oli laiska", @@ -429,18 +429,18 @@ "Display Multi-model Responses in Tabs": "Näytä usean mallin vastaukset välilehdissä", "Display the username instead of You in the Chat": "Näytä käyttäjänimi keskustelussa \"Sinä\" -tekstin sijaan", "Displays citations in the response": "Näyttää lähdeviitteet vastauksessa", - "Displays status updates (e.g., web search progress) in the response": "", + "Displays status updates (e.g., web search progress) in the response": "Näyttä tilapäivityksiä (esim. verkkohaku) vastauksissa", "Dive into knowledge": "Uppoudu tietoon", - "dlparse_v1": "", - "dlparse_v2": "", - "dlparse_v4": "", + "dlparse_v1": "dlparse_v1", + "dlparse_v2": "dlparse_v2", + "dlparse_v4": "dlparse_v4", "Do not install functions from sources you do not fully trust.": "Älä asenna toimintoja lähteistä, joihin et luota täysin.", "Do not install tools from sources you do not fully trust.": "Älä asenna työkaluja lähteistä, joihin et luota täysin.", "Docling": "Docling", "Docling Server URL required.": "Docling palvelimen verkko-osoite vaaditaan.", "Document": "Asiakirja", - "Document Intelligence": "Asiakirja tiedustelu", - "Document Intelligence endpoint required.": "", + "Document Intelligence": "Document Intelligence", + "Document Intelligence endpoint required.": "Document Intelligence pääte vaaditaan", "Documentation": "Dokumentaatio", "Documents": "Asiakirjat", "does not make any external connections, and your data stays securely on your locally hosted server.": "ei tee ulkoisia yhteyksiä, ja tietosi pysyvät turvallisesti paikallisesti isännöidyllä palvelimellasi.", @@ -471,7 +471,7 @@ "e.g. pdf, docx, txt": "esim. pdf, docx, txt", "e.g. Tools for performing various operations": "esim. työkaluja erilaisten toimenpiteiden suorittamiseen", "e.g., 3, 4, 5 (leave blank for default)": "esim. 3, 4, 5 (jätä tyhjäksi, jos haluat oletusarvon)", - "e.g., audio/wav,audio/mpeg,video/* (leave blank for defaults)": "", + "e.g., audio/wav,audio/mpeg,video/* (leave blank for defaults)": "esim. audio/wav,audio/mpeg,video/* (oletusarvot tyhjänä)", "e.g., en-US,ja-JP (leave blank for auto-detect)": "esim. en-US,ja-JP (Tyhjäksi jättämällä, automaattinen tunnistus)", "e.g., westus (leave blank for eastus)": "esim. westus (jätä tyhjäksi eastusta varten)", "Edit": "Muokkaa", @@ -506,7 +506,7 @@ "Enable New Sign Ups": "Salli uudet rekisteröitymiset", "Enable, disable, or customize the reasoning tags used by the model. \"Enabled\" uses default tags, \"Disabled\" turns off reasoning tags, and \"Custom\" lets you specify your own start and end tags.": "", "Enabled": "Käytössä", - "End Tag": "", + "End Tag": "Lopetus tagi", "Endpoint URL": "Päätepiste verkko-osoite", "Enforce Temporary Chat": "Pakota väliaikaiset keskustelut", "Enhance": "Paranna", @@ -529,7 +529,7 @@ "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Syötä pilkulla erottaen \"token:bias_value\" parit (esim. 5432:100, 413:-100)", "Enter Config in JSON format": "Kirjoita konfiguraatio JSON-muodossa", "Enter content for the pending user info overlay. Leave empty for default.": "Kirjoita odottavien käyttäjien infon tekstisisältö. Käytä oletusta jättämällä tyhjäksi.", - "Enter coordinates (e.g. 51.505, -0.09)": "", + "Enter coordinates (e.g. 51.505, -0.09)": "Kirjoita kordinaatit (esim. 51.505, -0.09)", "Enter Datalab Marker API Base URL": "Kirjoita Datalab Marker API verkko-osoite", "Enter Datalab Marker API Key": "Kirjoita Datalab Marker API-avain", "Enter description": "Kirjoita kuvaus", @@ -574,7 +574,7 @@ "Enter Playwright Timeout": "Aseta Playwright aikakatkaisu", "Enter Playwright WebSocket URL": "Aseta Playwright WebSocket-aikakatkaisu", "Enter proxy URL (e.g. https://user:password@host:port)": "Kirjoita välityspalvelimen verkko-osoite (esim. https://käyttäjä:salasana@host:portti)", - "Enter reasoning effort": "", + "Enter reasoning effort": "Kirjoita päättelyn määrä", "Enter Sampler (e.g. Euler a)": "Kirjoita näytteistäjä (esim. Euler a)", "Enter Scheduler (e.g. Karras)": "Kirjoita ajoitin (esim. Karras)", "Enter Score": "Kirjoita pistemäärä", @@ -668,7 +668,7 @@ "External": "Ulkoiset", "External Document Loader URL required.": "Ulkoisen Document Loader:n verkko-osoite on vaaditaan.", "External Task Model": "Ulkoinen työmalli", - "External Tools": "", + "External Tools": "Ulkoiset työkalut", "External Web Loader API Key": "Ulkoinen Web Loader API-avain", "External Web Loader URL": "Ulkoinen Web Loader verkko-osoite", "External Web Search API Key": "Ulkoinen Web Search API-avain", @@ -692,7 +692,7 @@ "Failed to save models configuration": "Mallien määrityksen tallentaminen epäonnistui", "Failed to update settings": "Asetusten päivittäminen epäonnistui", "Failed to upload file.": "Tiedoston lataaminen epäonnistui.", - "fast": "", + "fast": "nopea", "Features": "Ominaisuudet", "Features Permissions": "Ominaisuuksien käyttöoikeudet", "February": "helmikuu", @@ -737,8 +737,8 @@ "Format Lines": "Muotoile rivit", "Format the lines in the output. Defaults to False. If set to True, the lines will be formatted to detect inline math and styles.": "Muotoile rivit. Oletusarvo on False. Jos arvo on True, rivit muotoillaan siten, että ne havaitsevat riviin liitetyn matematiikan ja tyylit.", "Format your variables using brackets like this:": "Muotoile muuttujasi hakasulkeilla tällä tavalla:", - "Formatting may be inconsistent from source.": "", - "Forwards system user OAuth access token to authenticate": "", + "Formatting may be inconsistent from source.": "Muotoilu voi poiketa alkuperäisestä.", + "Forwards system user OAuth access token to authenticate": "Välittää järjestelmä käyttäjän OAuth tunniste todennuksessa", "Forwards system user session credentials to authenticate": "Välittää järjestelmän käyttäjän istunnon tunnistetiedot todennusta varten", "Full Context Mode": "Koko kontekstitila", "Function": "Toiminto", @@ -850,11 +850,11 @@ "Insert": "Lisää", "Insert Follow-Up Prompt to Input": "Lisää jatkokysymys syötteeseen", "Insert Prompt as Rich Text": "Lisää kehote RTF-muodossa", - "Insert Suggestion Prompt to Input": "", + "Insert Suggestion Prompt to Input": "Lisää kehoite ehdotus syötteeseen", "Install from Github URL": "Asenna Github-URL:stä", "Instant Auto-Send After Voice Transcription": "Heti automaattinen lähetys äänitunnistuksen jälkeen", "Integration": "Integrointi", - "Integrations": "", + "Integrations": "Integraatiot", "Interface": "Käyttöliittymä", "Invalid file content": "Virheellinen tiedostosisältö", "Invalid file format.": "Virheellinen tiedostomuoto.", @@ -913,7 +913,7 @@ "Leave empty to include all models or select specific models": "Jätä tyhjäksi, jos haluat sisällyttää kaikki mallit tai valitse tietyt mallit", "Leave empty to use the default prompt, or enter a custom prompt": "Jätä tyhjäksi käyttääksesi oletuskehotetta tai kirjoita mukautettu kehote", "Leave model field empty to use the default model.": "Jätä malli kenttä tyhjäksi käyttääksesi oletus mallia.", - "Legacy": "", + "Legacy": "Legacy", "lexical": "leksikaalinen", "License": "Lisenssi", "Lift List": "Nostolista", @@ -1044,12 +1044,12 @@ "No results found": "Ei tuloksia", "No search query generated": "Hakukyselyä ei luotu", "No source available": "Lähdettä ei saatavilla", - "No sources found": "", + "No sources found": "Lähteitä ei löytynyt", "No suggestion prompts": "Ei ehdotettuja promptteja", "No users were found.": "Käyttäjiä ei löytynyt.", "No valves": "Ei venttiileitä", "No valves to update": "Ei venttiileitä päivitettäväksi", - "Node Ids": "", + "Node Ids": "Node id:t", "None": "Ei mikään", "Not factually correct": "Ei faktuaalisesti oikein", "Not helpful": "Ei hyödyllinen", @@ -1060,7 +1060,7 @@ "Notification Webhook": "Webhook ilmoitus", "Notifications": "Ilmoitukset", "November": "marraskuu", - "OAuth": "", + "OAuth": "OAuth", "OAuth ID": "OAuth-tunnus", "October": "lokakuu", "Off": "Pois päältä", @@ -1117,14 +1117,14 @@ "Password": "Salasana", "Passwords do not match.": "Salasanat eivät täsmää", "Paste Large Text as File": "Liitä suuri teksti tiedostona", - "PDF Backend": "", + "PDF Backend": "PDF taustajärjestelmä", "PDF document (.pdf)": "PDF-asiakirja (.pdf)", "PDF Extract Images (OCR)": "Poimi kuvat PDF:stä (OCR)", "pending": "odottaa", "Pending": "Odottaa", "Pending User Overlay Content": "Odottavien käyttäjien sisältö", "Pending User Overlay Title": "Odottavien käyttäjien otsikko", - "Perform OCR": "", + "Perform OCR": "Suorita OCR", "Permission denied when accessing media devices": "Käyttöoikeus evätty media-laitteille", "Permission denied when accessing microphone": "Käyttöoikeus evätty mikrofonille", "Permission denied when accessing microphone: {{error}}": "Käyttöoikeus evätty mikrofonille: {{error}}", @@ -1140,7 +1140,7 @@ "Pinned": "Kiinnitetty", "Pioneer insights": "Pioneerin oivalluksia", "Pipe": "Putki", - "Pipeline": "", + "Pipeline": "Putki", "Pipeline deleted successfully": "Putki poistettu onnistuneesti", "Pipeline downloaded successfully": "Putki ladattu onnistuneesti", "Pipelines": "Putkistot", @@ -1185,22 +1185,22 @@ "Prompts": "Kehotteet", "Prompts Access": "Kehoitteiden käyttöoikeudet", "Prompts Public Sharing": "Kehoitteiden julkinen jakaminen", - "Provider Type": "", + "Provider Type": "Tarjoajan tyyppi", "Public": "Julkinen", "Pull \"{{searchValue}}\" from Ollama.com": "Lataa \"{{searchValue}}\" Ollama.comista", "Pull a model from Ollama.com": "Lataa malli Ollama.comista", - "pypdfium2": "", + "pypdfium2": "pypdfium2", "Query Generation Prompt": "Kyselytulosten luontikehote", - "Querying": "", + "Querying": "Kysely", "Quick Actions": "Pikatoiminnot", "RAG Template": "RAG-kehote", "Rating": "Arviointi", "Re-rank models by topic similarity": "Uudelleenjärjestä mallit aiheyhteyden mukaan", "Read": "Lue", "Read Aloud": "Lue ääneen", - "Reason": "", - "Reasoning Effort": "", - "Reasoning Tags": "", + "Reason": "Päättely", + "Reasoning Effort": "Päättelyn määrä", + "Reasoning Tags": "Päättely tagit", "Record": "Nauhoita", "Record voice": "Nauhoita ääntä", "Redirecting you to Open WebUI Community": "Ohjataan sinut OpenWebUI-yhteisöön", @@ -1226,7 +1226,7 @@ "Rename": "Nimeä uudelleen", "Reorder Models": "Uudelleenjärjestä malleja", "Reply in Thread": "Vastauksia ", - "required": "", + "required": "vaaditaan", "Reranking Engine": "Uudelleenpisteytymismallin moottori", "Reranking Model": "Uudelleenpisteytymismalli", "Reset": "Palauta", @@ -1243,10 +1243,10 @@ "RESULT": "Tulos", "Retrieval": "Haku", "Retrieval Query Generation": "Hakukyselyn luominen", - "Retrieved {{count}} sources": "", - "Retrieved {{count}} sources_one": "", - "Retrieved {{count}} sources_other": "", - "Retrieved 1 source": "", + "Retrieved {{count}} sources": "Noudettu {{count}} lähdettä", + "Retrieved {{count}} sources_one": "Noudettu {{count}} sources_one", + "Retrieved {{count}} sources_other": "Noudettu {{count}} sources_other", + "Retrieved 1 source": "1 lähde noudettu", "Rich Text Input for Chat": "Rikasteksti-syöte chattiin", "RK": "RK", "Role": "Rooli", @@ -1290,7 +1290,7 @@ "SearchApi API Key": "SearchApi API -avain", "SearchApi Engine": "SearchApi-moottori", "Searched {{count}} sites": "Etsitty {{count}} sivulta", - "Searching": "", + "Searching": "Haetaan", "Searching \"{{searchQuery}}\"": "Haetaan \"{{searchQuery}}\"", "Searching Knowledge for \"{{searchQuery}}\"": "Haetaan tietämystä \"{{searchQuery}}\"", "Searching the web": "Haetaan verkosta...", @@ -1402,10 +1402,10 @@ "Speech recognition error: {{error}}": "Puheentunnistusvirhe: {{error}}", "Speech-to-Text": "Puheentunnistus", "Speech-to-Text Engine": "Puheentunnistusmoottori", - "standard": "", + "standard": "perus", "Start of the channel": "Kanavan alku", - "Start Tag": "", - "Status Updates": "", + "Start Tag": "Aloitus tagi", + "Status Updates": "Tila päivitykset", "STDOUT/STDERR": "STDOUT/STDERR", "Stop": "Pysäytä", "Stop Generating": "Lopeta generointi", @@ -1431,7 +1431,7 @@ "System": "Järjestelmä", "System Instructions": "Järjestelmäohjeet", "System Prompt": "Järjestelmäkehote", - "Table Mode": "", + "Table Mode": "Tablet-moodi", "Tags": "Tagit", "Tags Generation": "Tagien luonti", "Tags Generation Prompt": "Tagien luontikehote", @@ -1518,7 +1518,7 @@ "To select toolkits here, add them to the \"Tools\" workspace first.": "Valitaksesi työkalusettejä tässä, lisää ne ensin \"Työkalut\"-työtilaan.", "Toast notifications for new updates": "Ilmoituspopuppien näyttäminen uusista päivityksistä", "Today": "Tänään", - "Today at {{LOCALIZED_TIME}}": "", + "Today at {{LOCALIZED_TIME}}": "Tänään {{LOCALIZED_TIME}}", "Toggle search": "Kytke haku", "Toggle settings": "Kytke asetukset", "Toggle sidebar": "Kytke sivupalkki", @@ -1614,7 +1614,7 @@ "View Result from **{{NAME}}**": "Näytä **{{NAME}}** tulokset", "Visibility": "Näkyvyys", "Vision": "Visio", - "vlm": "", + "vlm": "vlm", "Voice": "Ääni", "Voice Input": "Äänitulolaitteen käyttö", "Voice mode": "Puhetila", @@ -1659,7 +1659,7 @@ "Yacy Password": "Yacy salasana", "Yacy Username": "Yacy käyttäjänimi", "Yesterday": "Eilen", - "Yesterday at {{LOCALIZED_TIME}}": "", + "Yesterday at {{LOCALIZED_TIME}}": "Eilen {{LOCALIZED_TIME}}", "You": "Sinä", "You are currently using a trial license. Please contact support to upgrade your license.": "Käytät tällä hetkellä kokeiluversiota. Ota yhteyttä tukeen lisenssin päivittämiseksi.", "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Voit keskustella enintään {{maxCount}} tiedoston kanssa kerralla.", From cae7ad8c70997e6280603b064b688430268bcaae Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 14 Sep 2025 17:45:58 -0400 Subject: [PATCH 012/421] refac: styling --- .../ResponseMessage/StatusHistory.svelte | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/lib/components/chat/Messages/ResponseMessage/StatusHistory.svelte b/src/lib/components/chat/Messages/ResponseMessage/StatusHistory.svelte index ea7f67f20d..22bc747650 100644 --- a/src/lib/components/chat/Messages/ResponseMessage/StatusHistory.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage/StatusHistory.svelte @@ -32,19 +32,26 @@ {#if showHistory}
{#if history.length > 1} -
- -
+
{#each history as status, idx} {#if idx !== history.length - 1} -
-
- +
+
+
- + class="relative flex size-1.5 rounded-full justify-center items-center" + > + + +
+ +
+
{/if} @@ -55,7 +62,7 @@ {/if}
From 22e11760a1180f775ed9cef447f0c8d7775b14b7 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 14 Sep 2025 18:08:31 -0400 Subject: [PATCH 013/421] refac --- src/app.css | 16 ++++++++++++++++ .../channel/MessageInput/MentionList.svelte | 2 +- src/lib/components/common/RichTextInput.svelte | 18 +++++++++++++----- .../common/RichTextInput/suggestions.ts | 10 +++++++++- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/app.css b/src/app.css index c48914febf..756b0d9a08 100644 --- a/src/app.css +++ b/src/app.css @@ -420,6 +420,22 @@ input[type='number'] { content: '\200B'; } +.tiptap .suggestion { + border-radius: 0.4rem; + box-decoration-break: clone; + padding: 0.1rem 0.3rem; + @apply bg-purple-100/20 text-purple-900 dark:bg-purple-500/20 dark:text-purple-100; +} + +.tiptap .suggestion::after { + content: '\200B'; +} + +.tiptap .suggestion.is-empty::after { + content: '\00A0'; + border-bottom: 1px dotted rgba(31, 41, 55, 0.12); +} + .input-prose .tiptap ul[data-type='taskList'] { list-style: none; margin-left: 0; diff --git a/src/lib/components/channel/MessageInput/MentionList.svelte b/src/lib/components/channel/MessageInput/MentionList.svelte index 9f6526852a..4bc2b5c8a1 100644 --- a/src/lib/components/channel/MessageInput/MentionList.svelte +++ b/src/lib/components/channel/MessageInput/MentionList.svelte @@ -15,7 +15,7 @@ const select = (index: number) => { const item = filteredItems[index]; - if (item) command(item); + if (item) command({ id: item.id, label: item.name }); }; const onKeyDown = (event: KeyboardEvent) => { diff --git a/src/lib/components/common/RichTextInput.svelte b/src/lib/components/common/RichTextInput.svelte index caa62bb454..c6e2e2c6ff 100644 --- a/src/lib/components/common/RichTextInput.svelte +++ b/src/lib/components/common/RichTextInput.svelte @@ -91,6 +91,18 @@ } }); + // Convert TipTap mention spans -> <@id> + turndownService.addRule('mentions', { + filter: (node) => node.nodeName === 'SPAN' && node.getAttribute('data-type') === 'mention', + replacement: (_content, node: HTMLElement) => { + const id = node.getAttribute('data-id') || ''; + // TipTap stores the trigger char in data-mention-suggestion-char (usually "@") + const ch = node.getAttribute('data-mention-suggestion-char') || '@'; + // Emit <@id> style, e.g. <@llama3.2:latest> + return `<${ch}${id}>`; + } + }); + import { onMount, onDestroy, tick, getContext } from 'svelte'; import { createEventDispatcher } from 'svelte'; @@ -100,7 +112,7 @@ import { Fragment, DOMParser } from 'prosemirror-model'; import { EditorState, Plugin, PluginKey, TextSelection, Selection } from 'prosemirror-state'; import { Decoration, DecorationSet } from 'prosemirror-view'; - import { Editor, Extension } from '@tiptap/core'; + import { Editor, Extension, mergeAttributes } from '@tiptap/core'; // Yjs imports import * as Y from 'yjs'; @@ -142,9 +154,6 @@ import { PASTED_TEXT_CHARACTER_LIMIT } from '$lib/constants'; import { all, createLowlight } from 'lowlight'; - import MentionList from '../channel/MessageInput/MentionList.svelte'; - import { getSuggestionRenderer } from './RichTextInput/suggestions.js'; - export let oncompositionstart = (e) => {}; export let oncompositionend = (e) => {}; export let onChange = (e) => {}; @@ -1054,7 +1063,6 @@ htmlValue = editor.getHTML(); jsonValue = editor.getJSON(); - mdValue = turndownService .turndown( htmlValue diff --git a/src/lib/components/common/RichTextInput/suggestions.ts b/src/lib/components/common/RichTextInput/suggestions.ts index 1af255004e..8d4244700b 100644 --- a/src/lib/components/common/RichTextInput/suggestions.ts +++ b/src/lib/components/common/RichTextInput/suggestions.ts @@ -19,6 +19,7 @@ export function getSuggestionRenderer(Component: any, ComponentProps = {}) { target: container, props: { char: props?.text, + query: props?.query, command: (item) => { props.command({ id: item.id, label: item.label }); }, @@ -54,7 +55,14 @@ export function getSuggestionRenderer(Component: any, ComponentProps = {}) { onUpdate: (props: any) => { if (!component) return; - component.$set({ query: props.query }); + + component.$set({ + query: props.query, + command: (item) => { + props.command({ id: item.id, label: item.label }); + } + }); + if (props.clientRect && popup) { popup.setProps({ getReferenceClientRect: props.clientRect as any }); } From 098f34f40053441260929b495500afcc5c1c818b Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 14 Sep 2025 18:49:01 -0400 Subject: [PATCH 014/421] refac/enh: mention token rendering --- src/app.css | 4 +- .../channel/MessageInput/MentionList.svelte | 3 +- .../components/chat/Messages/Markdown.svelte | 2 + .../Markdown/MarkdownInlineTokens.svelte | 3 + .../MarkdownInlineTokens/MentionToken.svelte | 10 +++ src/lib/components/common/Tooltip.svelte | 8 +- src/lib/utils/marked/mention-extension.ts | 84 +++++++++++++++++++ 7 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/MentionToken.svelte create mode 100644 src/lib/utils/marked/mention-extension.ts diff --git a/src/app.css b/src/app.css index 756b0d9a08..6f40acab32 100644 --- a/src/app.css +++ b/src/app.css @@ -409,14 +409,14 @@ input[type='number'] { } } -.tiptap .mention { +.mention { border-radius: 0.4rem; box-decoration-break: clone; padding: 0.1rem 0.3rem; @apply text-blue-900 dark:text-blue-100 bg-blue-300/20 dark:bg-blue-500/20; } -.tiptap .mention::after { +.mention::after { content: '\200B'; } diff --git a/src/lib/components/channel/MessageInput/MentionList.svelte b/src/lib/components/channel/MessageInput/MentionList.svelte index 4bc2b5c8a1..330ea01fdb 100644 --- a/src/lib/components/channel/MessageInput/MentionList.svelte +++ b/src/lib/components/channel/MessageInput/MentionList.svelte @@ -15,7 +15,8 @@ const select = (index: number) => { const item = filteredItems[index]; - if (item) command({ id: item.id, label: item.name }); + // Add the "A:" prefix to the id to indicate it's an assistant model + if (item) command({ id: `A:${item.id}|${item.name}`, label: item.name }); }; const onKeyDown = (event: KeyboardEvent) => { diff --git a/src/lib/components/chat/Messages/Markdown.svelte b/src/lib/components/chat/Messages/Markdown.svelte index 736c93cb0d..c2ef2b923e 100644 --- a/src/lib/components/chat/Messages/Markdown.svelte +++ b/src/lib/components/chat/Messages/Markdown.svelte @@ -5,6 +5,7 @@ import markedExtension from '$lib/utils/marked/extension'; import markedKatexExtension from '$lib/utils/marked/katex-extension'; + import { mentionExtension } from '$lib/utils/marked/mention-extension'; import MarkdownTokens from './Markdown/MarkdownTokens.svelte'; @@ -37,6 +38,7 @@ marked.use(markedKatexExtension(options)); marked.use(markedExtension(options)); + marked.use({ extensions: [mentionExtension({ triggerChar: '@' })] }); $: (async () => { if (content) { diff --git a/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte index c49d60df69..8a0358a752 100644 --- a/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte +++ b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte @@ -16,6 +16,7 @@ import HtmlToken from './HTMLToken.svelte'; import TextToken from './MarkdownInlineTokens/TextToken.svelte'; import CodespanToken from './MarkdownInlineTokens/CodespanToken.svelte'; + import MentionToken from './MarkdownInlineTokens/MentionToken.svelte'; export let id: string; export let done = true; @@ -60,6 +61,8 @@ frameborder="0" onload="this.style.height=(this.contentWindow.document.body.scrollHeight+20)+'px';" > + {:else if token.type === 'mention'} + {:else if token.type === 'text'} {/if} diff --git a/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/MentionToken.svelte b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/MentionToken.svelte new file mode 100644 index 0000000000..c23307e515 --- /dev/null +++ b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/MentionToken.svelte @@ -0,0 +1,10 @@ + + + + {token.triggerChar}{token.label} + diff --git a/src/lib/components/common/Tooltip.svelte b/src/lib/components/common/Tooltip.svelte index 3d1566e650..59575520e6 100644 --- a/src/lib/components/common/Tooltip.svelte +++ b/src/lib/components/common/Tooltip.svelte @@ -7,10 +7,12 @@ export let elementId = ''; + export let as = 'div'; + export let className = 'flex'; + export let placement = 'top'; export let content = `I'm a tooltip!`; export let touch = true; - export let className = 'flex'; export let theme = ''; export let offset = [0, 4]; export let allowHTML = true; @@ -59,8 +61,8 @@ }); -
+ -
+ diff --git a/src/lib/utils/marked/mention-extension.ts b/src/lib/utils/marked/mention-extension.ts new file mode 100644 index 0000000000..21aa6bc687 --- /dev/null +++ b/src/lib/utils/marked/mention-extension.ts @@ -0,0 +1,84 @@ +// mention-extension.ts +type MentionOptions = { + triggerChar?: string; // default "@" + className?: string; // default "mention" + extraAttrs?: Record; // additional HTML attrs +}; + +function escapeHtml(s: string) { + return s.replace( + /[&<>"']/g, + (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c]! + ); +} + +function mentionStart(src: string) { + // Find the first "<" followed by trigger char + // We'll refine inside tokenizer + return src.indexOf('<'); +} + +function mentionTokenizer(this: any, src: string, options: MentionOptions = {}) { + const trigger = options.triggerChar ?? '@'; + + // Build dynamic regex for `<@id>`, `<@id|label>`, `<@id|>` + const re = new RegExp(`^<\\${trigger}([\\w.\\-:]+)(?:\\|([^>]*))?>`); + const m = re.exec(src); + if (!m) return; + + const [, id, label] = m; + return { + type: 'mention', + raw: m[0], + triggerChar: trigger, + id, + label: label && label.length > 0 ? label : id + }; +} + +function mentionRenderer(token: any, options: MentionOptions = {}) { + const trigger = options.triggerChar ?? '@'; + const cls = options.className ?? 'mention'; + const extra = options.extraAttrs ?? {}; + + const attrs = Object.entries({ + class: cls, + 'data-type': 'mention', + 'data-id': token.id, + 'data-mention-suggestion-char': trigger, + ...extra + }) + .map(([k, v]) => `${k}="${escapeHtml(String(v))}"`) + .join(' '); + + return `${escapeHtml(trigger + token.label)}`; +} + +export function mentionExtension(opts: MentionOptions = {}) { + return { + name: 'mention', + level: 'inline' as const, + start: mentionStart, + tokenizer(src: string) { + return mentionTokenizer.call(this, src, opts); + }, + renderer(token: any) { + return mentionRenderer(token, opts); + } + }; +} + +// Usage: +// import { marked } from 'marked'; +// marked.use({ extensions: [mentionExtension({ triggerChar: '@' })] }); +// +// "<@llama3.2:latest>" → +// @llama3.2:latest +// +// "<@llama3.2:latest|friendly>" → +// @friendly +// +// "<@llama3.2:latest|>" → +// @llama3.2:latest +// +// If triggerChar = "#" From db0379030efbaa88e34d9f8dab5492fdf4e34342 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 14 Sep 2025 18:59:09 -0400 Subject: [PATCH 015/421] refac --- .../Markdown/MarkdownInlineTokens/MentionToken.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/MentionToken.svelte b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/MentionToken.svelte index c23307e515..5c40849df6 100644 --- a/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/MentionToken.svelte +++ b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/MentionToken.svelte @@ -1,10 +1,10 @@ - {token.triggerChar}{token.label} + {token?.triggerChar ?? '@'}{token?.label ?? token?.id} From 3e65109900deea032b9c8921946fde8626cc188d Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 14 Sep 2025 19:00:49 -0400 Subject: [PATCH 016/421] refac --- src/lib/components/channel/MessageInput/MentionList.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/channel/MessageInput/MentionList.svelte b/src/lib/components/channel/MessageInput/MentionList.svelte index 330ea01fdb..48fbdb5db7 100644 --- a/src/lib/components/channel/MessageInput/MentionList.svelte +++ b/src/lib/components/channel/MessageInput/MentionList.svelte @@ -15,7 +15,7 @@ const select = (index: number) => { const item = filteredItems[index]; - // Add the "A:" prefix to the id to indicate it's an assistant model + // Add the "A:" prefix to the id to indicate it's an agent/assistant/ai model if (item) command({ id: `A:${item.id}|${item.name}`, label: item.name }); }; From 530460d711e2291690e06892d6dea2a902d46b55 Mon Sep 17 00:00:00 2001 From: Shirasawa <764798966@qq.com> Date: Mon, 15 Sep 2025 06:37:12 +0000 Subject: [PATCH 017/421] i18n: update translations in zh-CN locale --- src/lib/i18n/locales/zh-CN/translation.json | 28 ++++++++++++--------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/lib/i18n/locales/zh-CN/translation.json b/src/lib/i18n/locales/zh-CN/translation.json index 57f4662152..792c231c46 100644 --- a/src/lib/i18n/locales/zh-CN/translation.json +++ b/src/lib/i18n/locales/zh-CN/translation.json @@ -16,7 +16,7 @@ "{{COUNT}} Replies": "{{COUNT}} 条回复", "{{COUNT}} Sources": "{{COUNT}} 个引用来源", "{{COUNT}} words": "{{COUNT}} 个字", - "{{LOCALIZED_DATE}} at {{LOCALIZED_TIME}}": "", + "{{LOCALIZED_DATE}} at {{LOCALIZED_TIME}}": "{{LOCALIZED_DATE}} {{LOCALIZED_TIME}}", "{{model}} download has been canceled": "已取消模型 {{model}} 的下载", "{{user}}'s Chats": "{{user}} 的对话记录", "{{webUIName}} Backend Required": "{{webUIName}} 需要后端服务", @@ -147,8 +147,8 @@ "Ask a question": "提问", "Assistant": "助手", "Attach file from knowledge": "从知识库中选择文件", - "Attach Knowledge": "", - "Attach Notes": "", + "Attach Knowledge": "引用知识库", + "Attach Notes": "引用笔记", "Attention to detail": "注重细节", "Attribute for Mail": "邮箱属性", "Attribute for Username": "用户名属性", @@ -368,6 +368,8 @@ "Default (SentenceTransformers)": "默认 (SentenceTransformers)", "Default action buttons will be used.": "已启用默认的快捷操作按钮。", "Default description enabled": "默认描述已启用", + "Default Features": "默认功能", + "Default Filters": "默认过滤器", "Default mode works with a wider range of models by calling tools once before execution. Native mode leverages the model's built-in tool-calling capabilities, but requires the model to inherently support this feature.": "“默认”模式会在请求模型前调用工具,因此能兼容更多模型。“原生”模式则依赖模型本身的工具调用能力,但需要模型本身支持该功能。", "Default Model": "默认模型", "Default model updated": "默认模型已更新", @@ -376,7 +378,7 @@ "Default permissions updated successfully": "默认权限更新成功", "Default Prompt Suggestions": "默认提示词建议", "Default to 389 or 636 if TLS is enabled": "启用 TLS 将默认使用 389 或 636 端口", - "Default to ALL": "默认为 ALL", + "Default to ALL": "默认为:ALL", "Default to segmented retrieval for focused and relevant content extraction, this is recommended for most cases.": "默认进行分段检索以提取重点和相关内容(推荐)", "Default User Role": "默认用户角色", "Delete": "删除", @@ -854,7 +856,7 @@ "Install from Github URL": "从 Github URL 安装", "Instant Auto-Send After Voice Transcription": "语音转录文字后即时自动发送", "Integration": "集成", - "Integrations": "", + "Integrations": "扩展功能", "Interface": "界面", "Invalid file content": "文件内容无效", "Invalid file format.": "文件格式无效", @@ -913,14 +915,14 @@ "Leave empty to include all models or select specific models": "留空以包含所有模型或手动选择模型", "Leave empty to use the default prompt, or enter a custom prompt": "留空以使用默认提示词,或输入自定义提示词", "Leave model field empty to use the default model.": "模型字段留空以使用默认模型", - "Legacy": "", + "Legacy": "旧版", "lexical": "关键词", "License": "授权", "Lift List": "上移列表", "Light": "浅色", "Listening...": "正在倾听...", "Llama.cpp": "Llama.cpp", - "LLMs can make mistakes. Verify important information.": "大语言模型可能会出错。请核查重要信息。", + "LLMs can make mistakes. Verify important information.": "大语言模型可能会犯错,请核实关键信息。", "Loader": "加载器", "Loading Kokoro.js...": "加载 Kokoro.js 中...", "Loading...": "加载中...", @@ -1040,6 +1042,7 @@ "No models found": "未找到任何模型", "No models selected": "未选择任何模型", "No Notes": "没有笔记", + "No notes found": "没有任何笔记", "No results": "未找到结果", "No results found": "未找到结果", "No search query generated": "未生成搜索查询", @@ -1053,6 +1056,7 @@ "None": "无", "Not factually correct": "与事实不符", "Not helpful": "没有任何帮助", + "Note": "笔记", "Note deleted successfully": "笔记删除成功", "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "注意:如果设置了最低分数,搜索结果只会返回分数大于或等于最低分数的文档。", "Notes": "笔记", @@ -1085,6 +1089,7 @@ "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "糟糕!您正在使用不受支持的方法(仅运行前端服务)。请通过后端服务提供 WebUI。", "Open file": "打开文件", "Open in full screen": "全屏打开", + "Open link": "打开链接", "Open modal to configure connection": "打开外部连接配置弹窗", "Open Modal To Manage Floating Quick Actions": "管理快捷操作浮窗", "Open new chat": "打开新对话", @@ -1206,6 +1211,7 @@ "Redirecting you to Open WebUI Community": "正在将您重定向到 Open WebUI 社区", "Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative.": "降低生成无意义内容的概率。较高的值(如 100)将生成更多样化的回答,而较低的值(如 10)则更加保守。", "Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "使用\"User\" (用户) 来指代自己(例如:“User 正在学习西班牙语”)", + "Reference Chats": "引用其他聊天", "Refused when it shouldn't have": "拒绝了我的要求", "Regenerate": "重新生成", "Regenerate Menu": "显示重新生成选项菜单", @@ -1226,7 +1232,7 @@ "Rename": "重命名", "Reorder Models": "重新排序模型", "Reply in Thread": "在主题中回复", - "required": "", + "required": "必填", "Reranking Engine": "重新排名引擎", "Reranking Model": "重新排名模型", "Reset": "重置", @@ -1512,12 +1518,10 @@ "To learn more about available endpoints, visit our documentation.": "如需了解更多关于可用端点的信息,请访问我们的文档", "To learn more about powerful prompt variables, click here": "如需了解更多关于强大的提示词变量的信息,请点击此处", "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "为了保护您的隐私,只有评分、模型 ID、标签和元数据会从您的反馈中分享——您的对话记录将保持私密,不会被包含在内。", - "To select actions here, add them to the \"Functions\" workspace first.": "如需在这里选择操作,请先将其添加到工作空间中的“函数”", - "To select filters here, add them to the \"Functions\" workspace first.": "如需在这里选择过滤器,请先将其添加到工作空间中的“函数”", "To select toolkits here, add them to the \"Tools\" workspace first.": "如需在这里选择工具包,请先将其添加到工作空间中的“工具”", "Toast notifications for new updates": "检测到新版本时显示更新通知", "Today": "今天", - "Today at {{LOCALIZED_TIME}}": "", + "Today at {{LOCALIZED_TIME}}": "今天 {{LOCALIZED_TIME}}", "Toggle search": "切换搜索", "Toggle settings": "切换设置", "Toggle sidebar": "切换侧边栏", @@ -1658,7 +1662,7 @@ "Yacy Password": "YaCy 密码", "Yacy Username": "YaCy 用户名", "Yesterday": "昨天", - "Yesterday at {{LOCALIZED_TIME}}": "", + "Yesterday at {{LOCALIZED_TIME}}": "昨天 {{LOCALIZED_TIME}}", "You": "你", "You are currently using a trial license. Please contact support to upgrade your license.": "当前为试用许可证,请联系支持人员升级许可证。", "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "每次对话最多仅能附上 {{maxCount}} 个文件。", From 48ed800d9175ef53abecd7b9e2ce60cce1c263f9 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 15 Sep 2025 11:05:26 -0500 Subject: [PATCH 018/421] refac --- src/app.html | 11 +---------- src/routes/+layout.svelte | 10 ++++++++++ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/app.html b/src/app.html index f7167d42f2..6c1c362005 100644 --- a/src/app.html +++ b/src/app.html @@ -23,8 +23,6 @@ href="/static/apple-touch-icon.png" crossorigin="use-credentials" /> - - - - + diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index d4205bb9ee..b79e1810ad 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -694,6 +694,16 @@ {$WEBUI_NAME} + + + + {#if showRefresh} From d5824b1b495fcf86e57171769bcec2a0f698b070 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 15 Sep 2025 11:18:31 -0500 Subject: [PATCH 019/421] refac: prompt template variable made not required by default --- .../MessageInput/InputVariablesModal.svelte | 30 +++++++------- src/lib/utils/index.ts | 41 +++++++++++++------ 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/lib/components/chat/MessageInput/InputVariablesModal.svelte b/src/lib/components/chat/MessageInput/InputVariablesModal.svelte index 53f4ec02dc..4554ea72d3 100644 --- a/src/lib/components/chat/MessageInput/InputVariablesModal.svelte +++ b/src/lib/components/chat/MessageInput/InputVariablesModal.svelte @@ -84,7 +84,7 @@
{variable} - {#if variables[variable]?.required ?? true} + {#if variables[variable]?.required ?? false} *{$i18n.t('required')} {/if}
@@ -134,7 +134,7 @@ placeholder={$i18n.t('Enter value (true/false)')} bind:value={variableValues[variable]} autocomplete="off" - required + required={variables[variable]?.required ?? false} />
{:else if variables[variable]?.type === 'color'} @@ -159,7 +159,7 @@ placeholder={$i18n.t('Enter hex color (e.g. #FF0000)')} bind:value={variableValues[variable]} autocomplete="off" - required + required={variables[variable]?.required ?? false} />
{:else if variables[variable]?.type === 'date'} @@ -170,7 +170,7 @@ bind:value={variableValues[variable]} autocomplete="off" id="input-variable-{idx}" - required + required={variables[variable]?.required ?? false} {...variableAttributes} /> {:else if variables[variable]?.type === 'datetime-local'} @@ -181,7 +181,7 @@ bind:value={variableValues[variable]} autocomplete="off" id="input-variable-{idx}" - required + required={variables[variable]?.required ?? false} {...variableAttributes} /> {:else if variables[variable]?.type === 'email'} @@ -192,7 +192,7 @@ bind:value={variableValues[variable]} autocomplete="off" id="input-variable-{idx}" - required + required={variables[variable]?.required ?? false} {...variableAttributes} /> {:else if variables[variable]?.type === 'month'} @@ -203,7 +203,7 @@ bind:value={variableValues[variable]} autocomplete="off" id="input-variable-{idx}" - required + required={variables[variable]?.required ?? false} {...variableAttributes} /> {:else if variables[variable]?.type === 'number'} @@ -214,7 +214,7 @@ bind:value={variableValues[variable]} autocomplete="off" id="input-variable-{idx}" - required + required={variables[variable]?.required ?? false} {...variableAttributes} /> {:else if variables[variable]?.type === 'range'} @@ -235,7 +235,7 @@ placeholder={$i18n.t('Enter value')} bind:value={variableValues[variable]} autocomplete="off" - required + required={variables[variable]?.required ?? false} />
@@ -256,7 +256,7 @@ bind:value={variableValues[variable]} autocomplete="off" id="input-variable-{idx}" - required + required={variables[variable]?.required ?? false} {...variableAttributes} /> {:else if variables[variable]?.type === 'text'} @@ -267,7 +267,7 @@ bind:value={variableValues[variable]} autocomplete="off" id="input-variable-{idx}" - required + required={variables[variable]?.required ?? false} {...variableAttributes} /> {:else if variables[variable]?.type === 'time'} @@ -278,7 +278,7 @@ bind:value={variableValues[variable]} autocomplete="off" id="input-variable-{idx}" - required + required={variables[variable]?.required ?? false} {...variableAttributes} /> {:else if variables[variable]?.type === 'url'} @@ -289,7 +289,7 @@ bind:value={variableValues[variable]} autocomplete="off" id="input-variable-{idx}" - required + required={variables[variable]?.required ?? false} {...variableAttributes} /> {:else if variables[variable]?.type === 'map'} @@ -311,7 +311,7 @@ placeholder={$i18n.t('Enter coordinates (e.g. 51.505, -0.09)')} bind:value={variableValues[variable]} autocomplete="off" - required + required={variables[variable]?.required ?? false} />
{:else} @@ -321,7 +321,7 @@ bind:value={variableValues[variable]} autocomplete="off" id="input-variable-{idx}" - required + required={variables[variable]?.required ?? false} /> {/if}
diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts index 85e41d3c38..09bab3cf56 100644 --- a/src/lib/utils/index.ts +++ b/src/lib/utils/index.ts @@ -1408,24 +1408,39 @@ export const parseVariableDefinition = (definition: string): Record // Parse type (explicit or implied) const type = firstPart.startsWith('type=') ? firstPart.slice(5) : firstPart; - // Parse properties using reduce - const properties = propertyParts.reduce((props, part) => { - // Use splitProperties for the equals sign as well, in case there are nested quotes - const equalsParts = splitProperties(part, '='); - const [propertyName, ...valueParts] = equalsParts; - const propertyValue = valueParts.join('='); // Handle values with = signs + // Parse properties; support both key=value and bare flags (e.g., ":required") + const properties = propertyParts.reduce( + (props, part) => { + const trimmed = part.trim(); + if (!trimmed) return props; - return propertyName && propertyValue - ? { - ...props, - [propertyName.trim()]: parseJsonValue(propertyValue.trim()) + // Use splitProperties for the equals sign as well, in case there are nested quotes + const equalsParts = splitProperties(trimmed, '='); + + if (equalsParts.length === 1) { + // It's a flag with no value, e.g. "required" -> true + const flagName = equalsParts[0].trim(); + if (flagName.length > 0) { + return { ...props, [flagName]: true }; } - : props; - }, {}); + return props; + } + + const [propertyName, ...valueParts] = equalsParts; + const propertyValueRaw = valueParts.join('='); // Handle values with extra '=' + + if (!propertyName || propertyValueRaw == null) return props; + + return { + ...props, + [propertyName.trim()]: parseJsonValue(propertyValueRaw.trim()) + }; + }, + {} as Record + ); return { type, ...properties }; }; - export const parseJsonValue = (value: string): any => { // Remove surrounding quotes if present (for string values) if (value.startsWith('"') && value.endsWith('"')) { From a51f0c30ec1472d71487eab3e15d0351a2716b12 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 15 Sep 2025 11:40:31 -0500 Subject: [PATCH 020/421] refac/fix: knowledge permission --- backend/open_webui/retrieval/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/open_webui/retrieval/utils.py b/backend/open_webui/retrieval/utils.py index f5db7521b5..aec8de6846 100644 --- a/backend/open_webui/retrieval/utils.py +++ b/backend/open_webui/retrieval/utils.py @@ -621,6 +621,7 @@ def get_sources_from_items( if knowledge_base and ( user.role == "admin" + or knowledge_base.user_id == user.id or has_access(user.id, "read", knowledge_base.access_control) ): From e4c864de7eb0d577843a80688677ce3659d1f81f Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 15 Sep 2025 12:01:46 -0500 Subject: [PATCH 021/421] fix: connection url edit --- src/lib/components/admin/Settings/Connections.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/components/admin/Settings/Connections.svelte b/src/lib/components/admin/Settings/Connections.svelte index 91926dd6a3..100e440d5d 100644 --- a/src/lib/components/admin/Settings/Connections.svelte +++ b/src/lib/components/admin/Settings/Connections.svelte @@ -261,7 +261,7 @@
{#each OPENAI_API_BASE_URLS as url, idx} {#each OLLAMA_BASE_URLS as url, idx} { From b6a2ca877a2103a0003197844cff78eba8fbe6e5 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 15 Sep 2025 12:07:53 -0500 Subject: [PATCH 022/421] refac --- src/lib/components/chat/SettingsModal.svelte | 2 +- src/lib/components/common/Modal.svelte | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/components/chat/SettingsModal.svelte b/src/lib/components/chat/SettingsModal.svelte index d3da37631c..f822050ebc 100644 --- a/src/lib/components/chat/SettingsModal.svelte +++ b/src/lib/components/chat/SettingsModal.svelte @@ -561,7 +561,7 @@ -
+
{$i18n.t('Settings')}
-
-
- {#if typingUsers.length > 0} -
+ {#if typingUsers.length > 0} +
+
+ + +
{typingUsers.map((user) => user.name).join(', ')} {$i18n.t('is typing...')}
- {/if} +
-
+ {/if}
@@ -811,7 +816,7 @@ json={true} messageInput={true} richText={$settings?.richTextInput ?? true} - {showFormattingToolbar} + showFormattingToolbar={$settings?.showFormattingToolbar ?? false} shiftEnter={!($settings?.ctrlEnterToSend ?? false) && (!$mobile || !( diff --git a/src/lib/components/chat/Messages/Skeleton.svelte b/src/lib/components/chat/Messages/Skeleton.svelte index 90d8a99131..b2631701af 100644 --- a/src/lib/components/chat/Messages/Skeleton.svelte +++ b/src/lib/components/chat/Messages/Skeleton.svelte @@ -2,14 +2,22 @@ export let size = 'md'; - + From 67549dcadd670285d491bd41daf3d081a70fd094 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 15 Sep 2025 13:25:36 -0500 Subject: [PATCH 025/421] refac --- src/lib/components/chat/MessageInput.svelte | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index 2f5bbc490a..45b84c28a7 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -1024,7 +1024,9 @@ }} >
{#if atSelectedModel !== undefined} From 9e50026107e881de8a86088e30046339f0573eb7 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 15 Sep 2025 13:28:29 -0500 Subject: [PATCH 026/421] refac --- src/lib/components/layout/Sidebar.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/layout/Sidebar.svelte b/src/lib/components/layout/Sidebar.svelte index 4a065d9387..4cb20b6940 100644 --- a/src/lib/components/layout/Sidebar.svelte +++ b/src/lib/components/layout/Sidebar.svelte @@ -513,7 +513,7 @@ {#if !$mobile && !$showSidebar}