This commit is contained in:
Timothy Jaeryang Baek
2026-07-15 22:45:00 -04:00
parent 9e2536aa57
commit 588f129695
17 changed files with 54 additions and 33 deletions
+1 -1
View File
@@ -580,7 +580,7 @@ async def update_note_by_id(
note.is_pinned = note.id in pinned_note_ids
await sio.emit(
'note-events',
'events:note',
note.model_dump(),
to=f'note:{note.id}',
)
+1 -1
View File
@@ -75,7 +75,7 @@ async def _has_write_access_to_note(note, user_id: str) -> bool:
async def _emit_note_updated(request: Request, user: dict, note) -> None:
await sio.emit('note-events', note.model_dump(), to=f'note:{note.id}')
await sio.emit('events:note', note.model_dump(), to=f'note:{note.id}')
await publish_event(
request,
EVENTS.NOTE_UPDATED,
+9 -3
View File
@@ -2523,10 +2523,16 @@ async def process_chat_payload(request, form_data, user, metadata, model):
)
available_skills = []
view_skill_ids = []
chat = None
if metadata.get('chat_id') and not metadata['chat_id'].startswith(('local:', 'channel:')):
chat = await Chats.get_chat_by_id(metadata['chat_id'])
use_builtin_tools = (
bool(metadata.get('session_id'))
and metadata.get('params', {}).get('function_calling') != 'legacy'
and (model.get('info', {}).get('meta', {}).get('capabilities') or {}).get('builtin_tools', True)
(chat and (chat.meta or {}).get('internal') is True and (chat.meta or {}).get('type') == 'note')
or (
bool(metadata.get('session_id'))
and metadata.get('params', {}).get('function_calling') != 'legacy'
and (model.get('info', {}).get('meta', {}).get('capabilities') or {}).get('builtin_tools', True)
)
)
if skill_ids:
+15 -3
View File
@@ -41,6 +41,7 @@ from open_webui.env import (
REDIS_KEY_PREFIX,
)
from open_webui.models.access_grants import AccessGrants
from open_webui.models.chats import Chats
from open_webui.models.config import Config
from open_webui.models.groups import Groups
from open_webui.models.tools import Tools
@@ -606,7 +607,8 @@ async def get_builtin_tools(
):
builtin_functions.extend([search_web, fetch_url])
# Add image generation/edit tools if builtin category enabled AND enabled globally AND model has image_generation capability
# Add image generation/edit tools if builtin category enabled,
# globally enabled, and allowed by model capability.
if (
is_builtin_tool_enabled('image_generation')
and config.get('image_generation.enable')
@@ -624,7 +626,8 @@ async def get_builtin_tools(
):
builtin_functions.append(edit_image)
# Add code interpreter tool if builtin category enabled AND enabled globally AND model has code_interpreter capability
# Add code interpreter tool if builtin category enabled,
# globally enabled, and allowed by model capability.
if (
is_builtin_tool_enabled('code_interpreter')
and config.get('code_interpreter.enable')
@@ -634,8 +637,17 @@ async def get_builtin_tools(
):
builtin_functions.append(execute_code)
metadata = extra_params.get('__metadata__') or {}
chat_id = metadata.get('chat_id') or ''
chat = None
if chat_id and not chat_id.startswith(('local:', 'channel:')):
chat = await Chats.get_chat_by_id(chat_id)
# Notes tools - search, view, create, and update user's notes
if is_builtin_tool_enabled('notes') and config.get('notes.enable') and await has_user_permission('notes'):
if (
(chat and (chat.meta or {}).get('internal') is True and (chat.meta or {}).get('type') == 'note')
or (is_builtin_tool_enabled('notes') and config.get('notes.enable') and await has_user_permission('notes'))
):
builtin_functions.extend([search_notes, view_note, write_note, replace_note_content, replace_note_text])
# Channels tools - search channels and messages
+1 -1
View File
@@ -122,7 +122,7 @@ textarea::-webkit-scrollbar-corner {
}
.markdown-prose {
@apply prose prose-sm dark:prose-invert max-w-none break-words font-normal leading-relaxed prose-p:mt-0 prose-p:mb-2 prose-p:font-normal prose-p:leading-relaxed prose-headings:mt-2 prose-headings:mb-1 prose-headings:font-normal prose-headings:leading-snug prose-h1:text-xl prose-h2:text-lg prose-h3:text-base prose-strong:font-medium prose-code:before:content-none prose-code:after:content-none prose-ul:my-2 prose-ol:my-2 prose-li:my-0.5 prose-li:font-normal prose-pre:my-3 prose-table:my-0 prose-blockquote:my-3 prose-blockquote:font-normal prose-hr:my-4 prose-hr:border-gray-50 prose-hr:dark:border-gray-850/30 prose-img:my-2 [&>:first-child]:mt-0 [&>:last-child]:mb-0 [&_p:first-child]:mt-0 [&_h1:first-child]:mt-0 [&_h2:first-child]:mt-0 [&_h3:first-child]:mt-0 [&_h4:first-child]:mt-0 [&_h5:first-child]:mt-0 [&_h6:first-child]:mt-0;
@apply prose prose-sm dark:prose-invert max-w-none break-words !text-[0.9375rem] font-normal leading-relaxed prose-p:mt-0 prose-p:mb-2 prose-p:font-normal prose-p:leading-relaxed prose-headings:mt-2 prose-headings:mb-1 prose-headings:font-normal prose-headings:leading-snug prose-h1:text-xl prose-h2:text-lg prose-h3:text-base prose-strong:font-medium prose-code:before:content-none prose-code:after:content-none prose-ul:my-2 prose-ol:my-2 prose-li:my-0.5 prose-li:font-normal prose-pre:my-3 prose-table:my-0 prose-blockquote:my-3 prose-blockquote:font-normal prose-hr:my-4 prose-hr:border-gray-50 prose-hr:dark:border-gray-850/30 prose-img:my-2 [&>:first-child]:mt-0 [&>:last-child]:mb-0 [&_p:first-child]:mt-0 [&_h1:first-child]:mt-0 [&_h2:first-child]:mt-0 [&_h3:first-child]:mt-0 [&_h4:first-child]:mt-0 [&_h5:first-child]:mt-0 [&_h6:first-child]:mt-0;
}
.markdown-prose-sm {
@@ -311,7 +311,7 @@
</div>
{/if}
{#if extracted.plainContent}
<div class="whitespace-pre-wrap text-sm">{extracted.plainContent}</div>
<div class="whitespace-pre-wrap text-[0.9375rem]">{extracted.plainContent}</div>
{/if}
{/if}
</div>
@@ -112,7 +112,7 @@
<div {id} class="w-full">
<!-- svelte-ignore a11y-no-static-element-interactions -->
<button
class="w-fit py-1 text-left text-sm text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition cursor-pointer"
class="w-fit py-1 text-left text-[0.9375rem] text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition cursor-pointer"
aria-label={$i18n.t('Toggle details')}
aria-expanded={open}
on:click={() => {
+1 -1
View File
@@ -1,3 +1,3 @@
<div class=" self-center text-sm font-normal line-clamp-1 flex gap-1 items-center">
<div class=" self-center text-[0.9375rem] font-normal line-clamp-1 flex gap-1 items-center">
<slot />
</div>
@@ -270,7 +270,7 @@
{#if di.type === 'message'}
<textarea
use:fitContent
class="w-full bg-transparent outline-hidden resize-none overflow-hidden text-sm p-1.5 rounded-lg"
class="w-full bg-transparent outline-hidden resize-none overflow-hidden text-[0.9375rem] p-1.5 rounded-lg"
value={getMessageText(di.item)}
on:input={(e) => {
updateMessageText(di.indices[0], e.target.value);
@@ -282,7 +282,7 @@
{:else if di.type === 'reasoning'}
<textarea
use:fitContent
class="w-full bg-transparent outline-hidden resize-none overflow-hidden text-sm text-gray-500 dark:text-gray-400 p-1.5 rounded-lg"
class="w-full bg-transparent outline-hidden resize-none overflow-hidden text-[0.9375rem] text-gray-500 dark:text-gray-400 p-1.5 rounded-lg"
value={getReasoningText(di.item)}
on:input={(e) => {
updateReasoningText(di.indices[0], e.target.value);
@@ -292,7 +292,7 @@
rows="1"
/>
{:else if di.type === 'function_call'}
<div class="text-sm p-1.5 text-gray-500 dark:text-gray-400">
<div class="text-[0.9375rem] p-1.5 text-gray-500 dark:text-gray-400">
{#if di.item.arguments}
<pre
class="text-xs font-mono whitespace-pre-wrap overflow-x-auto pb-0.5">{formatArgs(
@@ -309,7 +309,7 @@
{/if}
</div>
{:else if di.type === 'code_interpreter'}
<div class="text-sm p-1.5 text-gray-500 dark:text-gray-400">
<div class="text-[0.9375rem] p-1.5 text-gray-500 dark:text-gray-400">
{#if di.item.code}
<pre class="text-xs font-mono whitespace-pre overflow-x-auto">{di.item.code}</pre>
{/if}
@@ -322,7 +322,7 @@
{/if}
</div>
{:else if di.type === 'openai_tool'}
<div class="text-sm p-1.5 text-gray-500 dark:text-gray-400">
<div class="text-[0.9375rem] p-1.5 text-gray-500 dark:text-gray-400">
{#if di.item.action?.queries || di.item.queries}
<span class="text-xs"
>{(di.item.action?.queries ?? di.item.queries ?? []).join(', ')}</span
@@ -736,7 +736,7 @@
<textarea
id="message-edit-{message.id}"
bind:this={editTextAreaElement}
class=" bg-transparent outline-hidden w-full resize-none"
class=" bg-transparent outline-hidden w-full resize-none text-[0.9375rem]"
bind:value={editedContent}
on:input={(e) => {
const messagesContainer = document.getElementById('messages-container');
@@ -29,7 +29,7 @@
{#if history && history.length > 0}
{#if status?.hidden !== true}
<div class="text-sm flex flex-col w-full">
<div class="text-[0.9375rem] flex flex-col w-full">
<button
class="w-full"
aria-label={$i18n.t('Toggle status history')}
@@ -17,7 +17,7 @@
<div
class="{(done || status?.done) === false
? 'shimmer'
: ''} text-base line-clamp-1 text-wrap"
: ''} text-[0.9375rem] line-clamp-1 text-wrap"
>
<!-- $i18n.t("Generating search query") -->
<!-- $i18n.t("No search query generated") -->
@@ -41,7 +41,7 @@
<div
class="{(done || status?.done) === false
? 'shimmer'
: ''} text-gray-500 dark:text-gray-500 text-base line-clamp-1 text-wrap"
: ''} text-gray-500 dark:text-gray-500 text-[0.9375rem] line-clamp-1 text-wrap"
>
{$i18n.t(`Searching Knowledge for "{{searchQuery}}"`, {
searchQuery: status.query
@@ -53,7 +53,7 @@
<div
class="{(done || status?.done) === false
? 'shimmer'
: ''} text-gray-500 dark:text-gray-500 text-base line-clamp-1 text-wrap"
: ''} text-gray-500 dark:text-gray-500 text-[0.9375rem] line-clamp-1 text-wrap"
>
{$i18n.t(`Searching`)}
</div>
@@ -79,7 +79,7 @@
<div
class="{(done || status?.done) === false
? 'shimmer'
: ''} text-gray-500 dark:text-gray-500 text-base line-clamp-1 text-wrap"
: ''} text-gray-500 dark:text-gray-500 text-[0.9375rem] line-clamp-1 text-wrap"
>
{$i18n.t(`Querying`)}
</div>
@@ -105,7 +105,7 @@
<div
class="{(done || status?.done) === false
? 'shimmer'
: ''} text-gray-500 dark:text-gray-500 text-base line-clamp-1 text-wrap"
: ''} text-gray-500 dark:text-gray-500 text-[0.9375rem] line-clamp-1 text-wrap"
>
{#if status.count === 0}
{$i18n.t('No sources found')}
@@ -127,7 +127,7 @@
<div
class="{(done || status?.done) === false
? 'shimmer'
: ''} text-gray-500 dark:text-gray-500 text-base line-clamp-1 text-wrap"
: ''} text-gray-500 dark:text-gray-500 text-[0.9375rem] line-clamp-1 text-wrap"
>
<!-- $i18n.t(`Searching "{{searchQuery}}"`) -->
{#if status?.description?.includes('{{searchQuery}}')}
@@ -57,7 +57,7 @@
/>
</div>
{:else}
<div class="whitespace-pre-wrap text-sm">{displayItem.text}</div>
<div class="whitespace-pre-wrap text-[0.9375rem]">{displayItem.text}</div>
{/if}
{:else if displayItem.type === 'detail_group'}
<ConsecutiveDetailsGroup
@@ -159,7 +159,7 @@
<Name>
{#if message.user}
{$i18n.t('You')}
<span class=" text-gray-500 text-sm font-normal">{message?.user ?? ''}</span>
<span class=" text-gray-500 text-[0.9375rem] font-normal">{message?.user ?? ''}</span>
{:else if $settings.showUsername || $_user?.name !== user?.name}
{user?.name ?? $i18n.t('You')}
{:else}
@@ -271,7 +271,7 @@
<textarea
id="message-edit-{message.id}"
bind:this={messageEditTextAreaElement}
class=" bg-transparent outline-hidden w-full resize-none text-sm"
class=" bg-transparent outline-hidden w-full resize-none text-[0.9375rem]"
bind:value={editedContent}
on:input={(e) => {
const messagesContainer = document.getElementById('messages-container');
@@ -358,7 +358,10 @@
/>
</div>
{:else}
<div class="whitespace-pre-wrap text-sm" dir={$settings?.chatDirection ?? 'auto'}>
<div
class="whitespace-pre-wrap text-[0.9375rem]"
dir={$settings?.chatDirection ?? 'auto'}
>
{message.content}
</div>
{/if}
+1 -1
View File
@@ -40,7 +40,7 @@
export let className = '';
export let buttonClassName =
'w-fit py-1 text-sm text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition';
'w-fit py-1 text-[0.9375rem] text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition';
export let id = '';
export let title = null;
@@ -38,7 +38,7 @@
$: if (!open) expandedResult = false;
export let buttonClassName =
'w-fit py-1 text-sm text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition';
'w-fit py-1 text-[0.9375rem] text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition';
const componentId = id || uuidv4();
+2 -2
View File
@@ -193,7 +193,7 @@
token: localStorage.token
}
});
$socket?.on('note-events', noteEventHandler);
$socket?.on('events:note', noteEventHandler);
}
} else {
goto('/');
@@ -829,7 +829,7 @@ ${content}
onDestroy(() => {
console.log('destroy');
$socket?.off('note-events', noteEventHandler);
$socket?.off('events:note', noteEventHandler);
const dropzoneElement = document.getElementById('note-editor');