This commit is contained in:
Timothy Jaeryang Baek
2026-03-25 05:13:41 -05:00
parent 15ae3f588b
commit f2f4baa89a
3 changed files with 54 additions and 1 deletions
+28 -1
View File
@@ -144,6 +144,7 @@
let selectedToolIds = []; let selectedToolIds = [];
let selectedFilterIds = []; let selectedFilterIds = [];
let pendingOAuthTools = [];
let imageGenerationEnabled = false; let imageGenerationEnabled = false;
let webSearchEnabled = false; let webSearchEnabled = false;
@@ -274,6 +275,7 @@
const resetInput = () => { const resetInput = () => {
selectedToolIds = []; selectedToolIds = [];
selectedFilterIds = []; selectedFilterIds = [];
pendingOAuthTools = [];
webSearchEnabled = false; webSearchEnabled = false;
imageGenerationEnabled = false; imageGenerationEnabled = false;
codeInterpreterEnabled = false; codeInterpreterEnabled = false;
@@ -298,11 +300,28 @@
if (model) { if (model) {
// Set Default Tools // Set Default Tools
if (model?.info?.meta?.toolIds) { if (model?.info?.meta?.toolIds) {
selectedToolIds = [ const defaultIds = [
...new Set( ...new Set(
[...(model?.info?.meta?.toolIds ?? [])].filter((id) => $tools.find((t) => t.id === id)) [...(model?.info?.meta?.toolIds ?? [])].filter((id) => $tools.find((t) => t.id === id))
) )
]; ];
// Separate unauthenticated OAuth tools
const unauthed = [];
const authed = [];
for (const id of defaultIds) {
const tool = $tools.find((t) => t.id === id);
if (tool && tool.authenticated === false) {
const parts = id.split(':');
const serverId = parts.at(-1) ?? id;
const authType = parts.length > 1 ? parts[0] === 'server' ? parts[1] : parts[0] : null;
unauthed.push({ id, name: tool.name ?? id, serverId, authType });
} else {
authed.push(id);
}
}
selectedToolIds = authed;
pendingOAuthTools = unauthed;
} else if ($settings?.tools) { } else if ($settings?.tools) {
selectedToolIds = $settings.tools; selectedToolIds = $settings.tools;
} else { } else {
@@ -1765,6 +1784,12 @@
selectedModels = _selectedModels; selectedModels = _selectedModels;
} }
if (pendingOAuthTools.length > 0) {
toast.warning(
$i18n.t('Please connect all required integrations before sending a message')
);
return;
}
if (userPrompt === '' && files.length === 0) { if (userPrompt === '' && files.length === 0) {
toast.error($i18n.t('Please enter a prompt')); toast.error($i18n.t('Please enter a prompt'));
return; return;
@@ -2843,6 +2868,7 @@
bind:selectedFilterIds bind:selectedFilterIds
bind:imageGenerationEnabled bind:imageGenerationEnabled
bind:codeInterpreterEnabled bind:codeInterpreterEnabled
{pendingOAuthTools}
bind:webSearchEnabled bind:webSearchEnabled
bind:atSelectedModel bind:atSelectedModel
bind:showCommands bind:showCommands
@@ -2930,6 +2956,7 @@
bind:atSelectedModel bind:atSelectedModel
bind:showCommands bind:showCommands
bind:dragged bind:dragged
{pendingOAuthTools}
toolServers={$toolServers} toolServers={$toolServers}
{stopResponse} {stopResponse}
{createMessagePair} {createMessagePair}
@@ -60,6 +60,7 @@
import { getTools } from '$lib/apis/tools'; import { getTools } from '$lib/apis/tools';
import { WEBUI_BASE_URL, WEBUI_API_BASE_URL, PASTED_TEXT_CHARACTER_LIMIT } from '$lib/constants'; import { WEBUI_BASE_URL, WEBUI_API_BASE_URL, PASTED_TEXT_CHARACTER_LIMIT } from '$lib/constants';
import { getOAuthClientAuthorizationUrl } from '$lib/apis/configs';
import { createNoteHandler } from '../notes/utils'; import { createNoteHandler } from '../notes/utils';
import { getSuggestionRenderer } from '../common/RichTextInput/suggestions'; import { getSuggestionRenderer } from '../common/RichTextInput/suggestions';
@@ -130,6 +131,8 @@
export let webSearchEnabled = false; export let webSearchEnabled = false;
export let codeInterpreterEnabled = false; export let codeInterpreterEnabled = false;
export let pendingOAuthTools = [];
let showTerminalMenu = false; let showTerminalMenu = false;
export let messageQueue: { id: string; prompt: string; files: any[] }[] = []; export let messageQueue: { id: string; prompt: string; files: any[] }[] = [];
@@ -1800,6 +1803,27 @@
</button> </button>
</Tooltip> </Tooltip>
{/if} {/if}
{#each pendingOAuthTools as pendingTool (pendingTool.id)}
<Tooltip content={$i18n.t('Click to connect')} placement="top">
<button
on:click|preventDefault={() => {
sessionStorage.setItem('pendingOAuthToolId', pendingTool.id);
const authUrl = getOAuthClientAuthorizationUrl(
pendingTool.serverId,
pendingTool.authType ?? 'mcp'
);
window.open(authUrl, '_self', 'noopener');
}}
type="button"
class="group px-2 py-[5px] flex gap-1.5 items-center text-xs rounded-full transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden
text-amber-600 dark:text-amber-400 bg-amber-50 hover:bg-amber-100 dark:bg-amber-400/10 dark:hover:bg-amber-600/10 border border-amber-200/40 dark:border-amber-500/20"
>
<Wrench className="size-3.5" strokeWidth="1.75" />
<span class="truncate">{pendingTool.name}</span>
</button>
</Tooltip>
{/each}
</div> </div>
</div> </div>
@@ -47,6 +47,7 @@
export let selectedToolIds = []; export let selectedToolIds = [];
export let selectedFilterIds = []; export let selectedFilterIds = [];
export let pendingOAuthTools = [];
export let showCommands = false; export let showCommands = false;
@@ -218,6 +219,7 @@
bind:atSelectedModel bind:atSelectedModel
bind:showCommands bind:showCommands
bind:dragged bind:dragged
{pendingOAuthTools}
{toolServers} {toolServers}
{stopResponse} {stopResponse}
{createMessagePair} {createMessagePair}