From 1630e2eb77e71a2d817a0f1da5fa8898d6ac2a5d Mon Sep 17 00:00:00 2001 From: Louis Date: Wed, 23 Apr 2025 20:22:07 +0700 Subject: [PATCH] feat: allow users to enable and disable tools --- .../ToolCallApprovalModal/index.tsx | 10 ++++-- web/helpers/atoms/Thread.atom.ts | 11 +++++- web/hooks/useSendChatMessage.ts | 22 +++++++----- .../ThreadCenterPanel/ChatInput/index.tsx | 34 +++++++++++++++---- 4 files changed, 59 insertions(+), 18 deletions(-) diff --git a/web/containers/ToolCallApprovalModal/index.tsx b/web/containers/ToolCallApprovalModal/index.tsx index 9981e439e..9b93f3cbf 100644 --- a/web/containers/ToolCallApprovalModal/index.tsx +++ b/web/containers/ToolCallApprovalModal/index.tsx @@ -63,7 +63,8 @@ export function useTollCallPromiseModal() {
- diff --git a/web/helpers/atoms/Thread.atom.ts b/web/helpers/atoms/Thread.atom.ts index d60e9dded..578ec6ac6 100644 --- a/web/helpers/atoms/Thread.atom.ts +++ b/web/helpers/atoms/Thread.atom.ts @@ -24,6 +24,7 @@ enum ThreadStorageAtomKeys { ThreadStates = 'threadStates', ThreadList = 'threadList', ThreadListReady = 'threadListReady', + DisabledTools = 'disabledTools', } //// Threads Atom @@ -73,10 +74,18 @@ export const threadDataReadyAtom = atomWithStorage( export const threadModelParamsAtom = atom>({}) /** - * Store the tool call approval thread id + * Store the tool call approval for thread id */ export const approvedThreadToolsAtom = atom>({}) +/** + * Store the tool call disabled for thread id + */ +export const disabledThreadToolsAtom = atomWithStorage( + ThreadStorageAtomKeys.DisabledTools, + [] +) + //// End Thread Atom /// Active Thread Atom diff --git a/web/hooks/useSendChatMessage.ts b/web/hooks/useSendChatMessage.ts index 7a25ba797..58a1ebfcc 100644 --- a/web/hooks/useSendChatMessage.ts +++ b/web/hooks/useSendChatMessage.ts @@ -56,6 +56,7 @@ import { selectedModelAtom } from '@/helpers/atoms/Model.atom' import { activeThreadAtom, approvedThreadToolsAtom, + disabledThreadToolsAtom, engineParamsUpdateAtom, getActiveThreadModelParamsAtom, isGeneratingResponseAtom, @@ -78,6 +79,7 @@ export default function useSendChatMessage( const deleteMessage = useSetAtom(deleteMessageAtom) const setEditPrompt = useSetAtom(editPromptAtom) const approvedTools = useAtomValue(approvedThreadToolsAtom) + const disabledTools = useAtomValue(disabledThreadToolsAtom) const currentMessages = useAtomValue(getCurrentChatMessagesAtom) const selectedModel = useAtomValue(selectedModelAtom) @@ -196,15 +198,17 @@ export default function useSendChatMessage( }, activeThread, messages ?? currentMessages, - (await window.core.api.getTools())?.map((tool: ModelTool) => ({ - type: 'function' as const, - function: { - name: tool.name, - description: tool.description?.slice(0, 1024), - parameters: tool.inputSchema, - strict: false, - }, - })) + (await window.core.api.getTools()) + ?.filter((tool: ModelTool) => !disabledTools.includes(tool.name)) + .map((tool: ModelTool) => ({ + type: 'function' as const, + function: { + name: tool.name, + description: tool.description?.slice(0, 1024), + parameters: tool.inputSchema, + strict: false, + }, + })) ).addSystemMessage(activeAssistant.instructions) requestBuilder.pushMessage(prompt, base64Blob, fileUpload) diff --git a/web/screens/Thread/ThreadCenterPanel/ChatInput/index.tsx b/web/screens/Thread/ThreadCenterPanel/ChatInput/index.tsx index 5224f79b3..4ba27ace6 100644 --- a/web/screens/Thread/ThreadCenterPanel/ChatInput/index.tsx +++ b/web/screens/Thread/ThreadCenterPanel/ChatInput/index.tsx @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { useContext, useEffect, useRef, useState } from 'react' +import { useContext, useEffect, useMemo, useRef, useState } from 'react' import { InferenceEngine } from '@janhq/core' @@ -11,6 +11,7 @@ import { badgeVariants, Badge, Modal, + Switch, } from '@janhq/joi' import { useAtom, useAtomValue } from 'jotai' import { @@ -51,6 +52,7 @@ import { spellCheckAtom } from '@/helpers/atoms/Setting.atom' import { activeSettingInputBoxAtom, activeThreadAtom, + disabledThreadToolsAtom, getActiveThreadIdAtom, isBlockingSendAtom, } from '@/helpers/atoms/Thread.atom' @@ -69,6 +71,7 @@ const ChatInput = () => { const { showApprovalModal } = useContext(ChatContext) const { sendChatMessage } = useSendChatMessage(showApprovalModal) const selectedModel = useAtomValue(selectedModelAtom) + const [disabledTools, setDisableTools] = useAtom(disabledThreadToolsAtom) const activeThreadId = useAtomValue(getActiveThreadIdAtom) const [fileUpload, setFileUpload] = useAtom(fileUploadAtom) @@ -89,6 +92,10 @@ const ChatInput = () => { activeTabThreadRightPanelAtom ) + const availableTools = useMemo(() => { + return tools.filter((tool: ModelTool) => !disabledTools.includes(tool.name)) + }, [tools, disabledTools]) + const refAttachmentMenus = useClickOutside(() => setShowAttachmentMenus(false) ) @@ -420,7 +427,7 @@ const ChatInput = () => { size={16} className="flex-shrink-0 cursor-pointer text-[hsla(var(--text-secondary))]" /> - {tools.length} + {availableTools.length} { size={16} className="flex-shrink-0 text-[hsla(var(--text-secondary))]" /> -
-
{tool.name}
-
- {tool.description} +
+
+
{tool.name}
+
+ {tool.description} +
+ { + if (e.target.checked) { + setDisableTools((prev) => + prev.filter((t) => t !== tool.name) + ) + } else { + setDisableTools([...disabledTools, tool.name]) + } + }} + className="flex-shrink-0" + />
))}