diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 74d0ce4de..52a7aa925 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -43,7 +43,8 @@ selectedFolder, pinnedChats, showEmbeds, - selectedTerminalId + selectedTerminalId, + showFileNavPath } from '$lib/stores'; import { WEBUI_API_BASE_URL } from '$lib/constants'; @@ -57,7 +58,8 @@ processDetails, removeAllDetails, getCodeBlockContents, - isYoutubeUrl + isYoutubeUrl, + displayFileHandler } from '$lib/utils'; import { AudioQueue } from '$lib/utils/audio'; @@ -576,6 +578,10 @@ eventConfirmationInputPlaceholder = data.placeholder; eventConfirmationInputValue = data?.value ?? ''; eventConfirmationInputType = data?.type ?? ''; + } else if (type === 'display_file') { + if (data?.path) { + displayFileHandler(data.path, { showControls, showFileNavPath }); + } } else { console.log('Unknown message type', data); } diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts index 37389610b..fdd490765 100644 --- a/src/lib/utils/index.ts +++ b/src/lib/utils/index.ts @@ -1,3 +1,4 @@ +import type { Writable } from 'svelte/store'; import { v4 as uuidv4 } from 'uuid'; import sha256 from 'js-sha256'; import { WEBUI_BASE_URL } from '$lib/constants'; @@ -361,9 +362,9 @@ export const generateInitialsImage = (name) => { const initials = sanitizedName.length > 0 ? sanitizedName[0] + - (sanitizedName.split(' ').length > 1 - ? sanitizedName[sanitizedName.lastIndexOf(' ') + 1] - : '') + (sanitizedName.split(' ').length > 1 + ? sanitizedName[sanitizedName.lastIndexOf(' ') + 1] + : '') : ''; ctx.fillText(initials.toUpperCase(), canvas.width / 2, canvas.height / 2); @@ -519,10 +520,10 @@ export const compareVersion = (latest, current) => { return current === '0.0.0' ? false : current.localeCompare(latest, undefined, { - numeric: true, - sensitivity: 'case', - caseFirst: 'upper' - }) < 0; + numeric: true, + sensitivity: 'case', + caseFirst: 'upper' + }) < 0; }; export const extractCurlyBraceWords = (text) => { @@ -1720,3 +1721,20 @@ export const parseFrontmatter = (content) => { export const formatSkillName = (name) => { return name.replace(/[-_]/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()); }; + +/** + * Open the file browser panel to display a specific file. + * Used by both the direct tool execution path (client-side) and the + * backend event path (server-side) so behaviour is consistent. + * + * Stores are passed in by the caller to keep this utility pure. + */ +export const displayFileHandler = ( + path: string, + stores: { showControls: Writable; showFileNavPath: Writable } +) => { + if (path) { + stores.showControls.set(true); + stores.showFileNavPath.set(path); + } +}; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 8598158ef..470ca2d0d 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -52,7 +52,7 @@ import { chatCompletion } from '$lib/apis/openai'; import { WEBUI_API_BASE_URL, WEBUI_BASE_URL, WEBUI_HOSTNAME } from '$lib/constants'; - import { bestMatchingLanguage } from '$lib/utils'; + import { bestMatchingLanguage, displayFileHandler } from '$lib/utils'; import { setTextScale } from '$lib/utils/text-scale'; import NotificationToast from '$lib/components/NotificationToast.svelte'; @@ -331,11 +331,9 @@ console.log('executeToolServer', res); - // Intercept display_file result to handle UI if (data?.name === 'display_file' && data?.params?.path) { if (res?.exists !== false) { - showControls.set(true); - showFileNavPath.set(data.params.path); + displayFileHandler(data.params.path, { showControls, showFileNavPath }); } }