feat: allow users to enable and disable tools

This commit is contained in:
Louis 2025-04-23 20:22:07 +07:00
parent 5e80587138
commit 1630e2eb77
No known key found for this signature in database
GPG Key ID: 44FA9F4D33C37DE2
4 changed files with 59 additions and 18 deletions

View File

@ -63,7 +63,8 @@ export function useTollCallPromiseModal() {
<div className="mt-4 flex justify-end gap-x-2">
<ModalClose asChild>
<Button
theme="ghost" variant="outline"
theme="ghost"
variant="outline"
onClick={() => {
setApprovedToolsAtom((prev) => {
const newState = { ...prev }
@ -87,7 +88,12 @@ export function useTollCallPromiseModal() {
</Button>
</ModalClose>
<ModalClose asChild>
<Button theme="ghost" variant="outline" onClick={handleConfirm} autoFocus>
<Button
theme="ghost"
variant="outline"
onClick={handleConfirm}
autoFocus
>
Allow once
</Button>
</ModalClose>

View File

@ -24,6 +24,7 @@ enum ThreadStorageAtomKeys {
ThreadStates = 'threadStates',
ThreadList = 'threadList',
ThreadListReady = 'threadListReady',
DisabledTools = 'disabledTools',
}
//// Threads Atom
@ -73,10 +74,18 @@ export const threadDataReadyAtom = atomWithStorage<boolean>(
export const threadModelParamsAtom = atom<Record<string, ModelParams>>({})
/**
* Store the tool call approval thread id
* Store the tool call approval for thread id
*/
export const approvedThreadToolsAtom = atom<Record<string, string[]>>({})
/**
* Store the tool call disabled for thread id
*/
export const disabledThreadToolsAtom = atomWithStorage<string[]>(
ThreadStorageAtomKeys.DisabledTools,
[]
)
//// End Thread Atom
/// Active Thread Atom

View File

@ -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,7 +198,9 @@ export default function useSendChatMessage(
},
activeThread,
messages ?? currentMessages,
(await window.core.api.getTools())?.map((tool: ModelTool) => ({
(await window.core.api.getTools())
?.filter((tool: ModelTool) => !disabledTools.includes(tool.name))
.map((tool: ModelTool) => ({
type: 'function' as const,
function: {
name: tool.name,

View File

@ -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))]"
/>
<span className="text-xs">{tools.length}</span>
<span className="text-xs">{availableTools.length}</span>
</Badge>
<Modal
@ -449,12 +456,27 @@ const ChatInput = () => {
size={16}
className="flex-shrink-0 text-[hsla(var(--text-secondary))]"
/>
<div className="flex w-full flex-1 flex-row justify-between">
<div>
<div className="font-medium">{tool.name}</div>
<div className="text-sm text-[hsla(var(--text-secondary))]">
{tool.description}
</div>
</div>
<Switch
checked={!disabledTools.includes(tool.name)}
onChange={(e) => {
if (e.target.checked) {
setDisableTools((prev) =>
prev.filter((t) => t !== tool.name)
)
} else {
setDisableTools([...disabledTools, tool.name])
}
}}
className="flex-shrink-0"
/>
</div>
</div>
))}
</div>