From 398718d5059ce2a5614e9e124f20ef48b843ce42 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 17 Apr 2026 10:44:29 +0900 Subject: [PATCH] refac --- backend/open_webui/utils/middleware.py | 5 ++++- src/lib/components/chat/Chat.svelte | 5 ++++- src/lib/components/chat/MessageInput.svelte | 15 ++++++++++++++- .../workspace/Models/Capabilities.svelte | 7 +++++++ .../workspace/Models/ModelEditor.svelte | 2 ++ src/lib/constants.ts | 1 + 6 files changed, 32 insertions(+), 3 deletions(-) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 89f8e8109..058a8cb13 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -2618,7 +2618,10 @@ async def process_chat_payload(request, form_data, user, metadata, model): # Resolve terminal tools if terminal_id is set (outside tool_ids check # so system terminals work even when no other tools are selected) - if terminal_id: + terminal_capability = (model.get('info', {}).get('meta', {}).get('capabilities') or {}).get( + 'terminal', True + ) + if terminal_id and terminal_capability: try: terminal_result = await get_terminal_tools( request, diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index a3fd62d3b..55d88c1f3 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -2306,6 +2306,9 @@ // Use the user-selected terminal from the dropdown const activeTerminalId = $selectedTerminalId ?? null; + // Only send terminal_id if the model has terminal capability enabled + const terminalEnabled = model.info?.meta?.capabilities?.terminal ?? true; + const res = await generateOpenAIChatCompletion( localStorage.token, { @@ -2323,7 +2326,7 @@ filter_ids: selectedFilterIds.length > 0 ? selectedFilterIds : undefined, tool_ids: toolIds.length > 0 ? toolIds : undefined, skill_ids: skillIds.length > 0 ? skillIds : undefined, - terminal_id: activeTerminalId ?? undefined, + terminal_id: terminalEnabled ? (activeTerminalId ?? undefined) : undefined, tool_servers: [ ...($toolServers ?? []).filter( (server, idx) => toolServerIds.includes(idx) || toolServerIds.includes(server?.id) diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index ef8d2d4cb..b9bb534d8 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -495,6 +495,14 @@ $models.find((m) => m.id === model)?.info?.meta?.capabilities?.code_interpreter ?? true ); + let terminalCapableModels = []; + $: terminalCapableModels = ( + atSelectedModel?.id ? [atSelectedModel.id] : selectedModels + ).filter( + (model) => + $models.find((m) => m.id === model)?.info?.meta?.capabilities?.terminal ?? true + ); + let toggleFilters = []; $: toggleFilters = (atSelectedModel?.id ? [atSelectedModel.id] : selectedModels) .map((id) => ($models.find((model) => model.id === id) || {})?.filters ?? []) @@ -530,6 +538,11 @@ codeInterpreterEnabled = false; } + // Clear selected terminal when model doesn't support terminal + $: if ($selectedTerminalId && terminalCapableModels.length === 0) { + selectedTerminalId.set(null); + } + const scrollToBottom = () => { const element = document.getElementById('messages-container'); element.scrollTo({ @@ -1908,7 +1921,7 @@ {#if !history?.currentId || history.messages[history.currentId]?.done == true} - {#if ($terminalServers ?? []).length > 0 || ($settings?.terminalServers ?? []).some((s) => s.url)} + {#if terminalCapableModels.length > 0 && (($terminalServers ?? []).length > 0 || ($settings?.terminalServers ?? []).some((s) => s.url))} {/if} diff --git a/src/lib/components/workspace/Models/Capabilities.svelte b/src/lib/components/workspace/Models/Capabilities.svelte index 57810c230..627a1b0b3 100644 --- a/src/lib/components/workspace/Models/Capabilities.svelte +++ b/src/lib/components/workspace/Models/Capabilities.svelte @@ -31,6 +31,12 @@ label: $i18n.t('Code Interpreter'), description: $i18n.t('Model can execute code and perform calculations') }, + terminal: { + label: $i18n.t('Terminal'), + description: $i18n.t( + 'Model can access Open Terminal for command execution and file management' + ) + }, usage: { label: $i18n.t('Usage'), description: $i18n.t( @@ -60,6 +66,7 @@ web_search?: boolean; image_generation?: boolean; code_interpreter?: boolean; + terminal?: boolean; usage?: boolean; citations?: boolean; status_updates?: boolean; diff --git a/src/lib/components/workspace/Models/ModelEditor.svelte b/src/lib/components/workspace/Models/ModelEditor.svelte index c41f51495..489478aec 100644 --- a/src/lib/components/workspace/Models/ModelEditor.svelte +++ b/src/lib/components/workspace/Models/ModelEditor.svelte @@ -839,9 +839,11 @@ {/if} + {#if capabilities.terminal}
+ {/if}
diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 006304bbb..b25ec0f84 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -104,6 +104,7 @@ export const DEFAULT_CAPABILITIES = { web_search: true, image_generation: true, code_interpreter: true, + terminal: true, citations: true, status_updates: true, usage: undefined,