diff --git a/apps/shinkai-desktop/src/components/chat/components/message.tsx b/apps/shinkai-desktop/src/components/chat/components/message.tsx index 8916ef681..35faf6213 100644 --- a/apps/shinkai-desktop/src/components/chat/components/message.tsx +++ b/apps/shinkai-desktop/src/components/chat/components/message.tsx @@ -310,7 +310,9 @@ export const MessageBase = ({ svg]:hidden [&[data-state=open]]:bg-gray-500', + 'transition-colors hover:bg-gray-500 [&[data-state=open]]:bg-gray-500', + tool.status !== ToolStatusType.Complete && + '[&>svg]:hidden', )} > - + {Object.keys(tool.args).length > 0 && ( {tool.name}( {Object.keys(tool.args).length > 0 && ( - + {JSON.stringify(tool.args)} )} ) )} + {tool.result && ( + + Response: + + {JSON.stringify(tool.result, null, 2)} + + + )} ); diff --git a/apps/shinkai-desktop/src/components/chat/conversation-footer.tsx b/apps/shinkai-desktop/src/components/chat/conversation-footer.tsx index 11b6ed836..b1ca9b9ff 100644 --- a/apps/shinkai-desktop/src/components/chat/conversation-footer.tsx +++ b/apps/shinkai-desktop/src/components/chat/conversation-footer.tsx @@ -54,7 +54,6 @@ import { cn } from '@shinkai_network/shinkai-ui/utils'; import { partial } from 'filesize'; import { AnimatePresence, motion } from 'framer-motion'; import { Paperclip, X, XIcon } from 'lucide-react'; -import { InfoCircleIcon } from 'primereact/icons/infocircle'; import { useEffect, useMemo, useRef } from 'react'; import { useDropzone } from 'react-dropzone'; import { useForm, useWatch } from 'react-hook-form'; @@ -421,42 +420,14 @@ function ConversationEmptyFooter() { <> {isDragActive && } {selectedTool && ( - - - - - - - - {formatText(selectedTool.name)}{' '} - - - - - - - - {selectedTool.description} - - - - - { - chatForm.setValue('tool', undefined); - }} - type="button" - > - - - + { + chatForm.setValue('tool', undefined); + }} + /> )} {!isDragActive && currentFiles && @@ -504,6 +475,9 @@ function ConversationEmptyFooter() { key: tool.tool_router_key, name: tool.name, description: tool.description, + args: Object.keys( + tool.input_args.properties ?? {}, + ), }); }} type="button" @@ -513,7 +487,11 @@ function ConversationEmptyFooter() { - + {tool.description} @@ -538,7 +516,6 @@ function ConversationEmptyFooter() { ); } - function ConversationChatFooter({ inboxId }: { inboxId: string }) { const { t } = useTranslation(); @@ -665,6 +642,7 @@ function ConversationChatFooter({ inboxId }: { inboxId: string }) { message: data.message, parent: '', // Note: we should set the parent if we want to retry or branch out files: currentFiles, + toolKey: selectedTool?.key, }); } else { const sender = `${auth.shinkai_identity}/${auth.profile}/device/${auth.registration_name}`; @@ -778,42 +756,14 @@ function ConversationChatFooter({ inboxId }: { inboxId: string }) { <> {isDragActive && } {selectedTool && ( - - - - - - - - {formatText(selectedTool.name)}{' '} - - - - - - - - {selectedTool.description} - - - - - { - chatForm.setValue('tool', undefined); - }} - type="button" - > - - - + { + chatForm.setValue('tool', undefined); + }} + /> )} {!isDragActive && currentFiles && @@ -861,6 +811,9 @@ function ConversationChatFooter({ inboxId }: { inboxId: string }) { key: tool.tool_router_key, name: tool.name, description: tool.description, + args: Object.keys( + tool.input_args.properties ?? {}, + ), }); }} type="button" @@ -1013,3 +966,62 @@ const DropFileActive = () => ( ); + +const SelectedToolChat = ({ + name, + description, + args, + remove, +}: { + name: string; + description: string; + args: string[]; + remove: () => void; +}) => { + return ( + + + + + + + + {name} -{' '} + {description} + + {args.length > 0 && ( + + + Inputs: + + {args.join(', ')} + + + + )} + + + + + + wellelele + + + + + + + + + ); +}; diff --git a/apps/shinkai-desktop/src/components/playground-tool/components/remove-tool-button.tsx b/apps/shinkai-desktop/src/components/playground-tool/components/remove-tool-button.tsx new file mode 100644 index 000000000..9daa278c9 --- /dev/null +++ b/apps/shinkai-desktop/src/components/playground-tool/components/remove-tool-button.tsx @@ -0,0 +1,43 @@ +import { useRemoveTool } from '@shinkai_network/shinkai-node-state/v2/mutations/removeTool/useRemoveTool'; +import { Button } from '@shinkai_network/shinkai-ui'; +import { useNavigate } from 'react-router-dom'; +import { toast } from 'sonner'; + +import { useAuth } from '../../../store/auth'; + +export default function RemoveToolButton({ toolKey }: { toolKey: string }) { + const auth = useAuth((state) => state.auth); + const navigate = useNavigate(); + + const { mutateAsync: removeTool, isPending: isRemoveToolPending } = + useRemoveTool({ + onSuccess: () => { + toast.success('Tool has been removed successfully'); + navigate('/tools'); + }, + onError: (error) => { + toast.error('Failed to remove tool', { + description: error.response?.data?.message ?? error.message, + }); + }, + }); + + return ( + { + await removeTool({ + toolKey: toolKey ?? '', + nodeAddress: auth?.node_address ?? '', + token: auth?.api_v2_key ?? '', + }); + }} + size="sm" + variant={'outline'} + > + Delete Tool + + ); +} diff --git a/apps/shinkai-desktop/src/components/tools/deno-tool.tsx b/apps/shinkai-desktop/src/components/tools/deno-tool.tsx index ff3d7fc63..7112b66d9 100644 --- a/apps/shinkai-desktop/src/components/tools/deno-tool.tsx +++ b/apps/shinkai-desktop/src/components/tools/deno-tool.tsx @@ -27,6 +27,7 @@ import { z } from 'zod'; import { SubpageLayout } from '../../pages/layout/simple-layout'; import { useAuth } from '../../store/auth'; +import RemoveToolButton from '../playground-tool/components/remove-tool-button'; const jsToolSchema = z.object({ config: z.array( z.object({ @@ -241,7 +242,7 @@ export default function DenoTool({ )} - + {isPlaygroundTool && ( )} + diff --git a/apps/shinkai-desktop/src/components/tools/network-tool.tsx b/apps/shinkai-desktop/src/components/tools/network-tool.tsx index a541f2f2c..21296166e 100644 --- a/apps/shinkai-desktop/src/components/tools/network-tool.tsx +++ b/apps/shinkai-desktop/src/components/tools/network-tool.tsx @@ -28,6 +28,7 @@ import { toast } from 'sonner'; // import { z } from 'zod'; import { SubpageLayout } from '../../pages/layout/simple-layout'; import { useAuth } from '../../store/auth'; +import RemoveToolButton from '../playground-tool/components/remove-tool-button'; // const jsToolSchema = z.object({ // config: z.array( @@ -247,6 +248,9 @@ export default function NetworkTool({ {/* Go Playground*/} {/* */} {/*)}*/} + + + ); diff --git a/apps/shinkai-desktop/src/components/tools/python-tool.tsx b/apps/shinkai-desktop/src/components/tools/python-tool.tsx index 641c63007..c62cd26b2 100644 --- a/apps/shinkai-desktop/src/components/tools/python-tool.tsx +++ b/apps/shinkai-desktop/src/components/tools/python-tool.tsx @@ -27,6 +27,7 @@ import { z } from 'zod'; import { SubpageLayout } from '../../pages/layout/simple-layout'; import { useAuth } from '../../store/auth'; +import RemoveToolButton from '../playground-tool/components/remove-tool-button'; const jsToolSchema = z.object({ config: z.array( z.object({ @@ -241,7 +242,7 @@ export default function PythonTool({ )} - + {isPlaygroundTool && ( )} + diff --git a/apps/shinkai-desktop/src/components/tools/rust-tool.tsx b/apps/shinkai-desktop/src/components/tools/rust-tool.tsx index fbf0a875f..d7c8f78c7 100644 --- a/apps/shinkai-desktop/src/components/tools/rust-tool.tsx +++ b/apps/shinkai-desktop/src/components/tools/rust-tool.tsx @@ -22,6 +22,7 @@ import { toast } from 'sonner'; // import { z } from 'zod'; import { SubpageLayout } from '../../pages/layout/simple-layout'; import { useAuth } from '../../store/auth'; +import RemoveToolButton from '../playground-tool/components/remove-tool-button'; // const jsToolSchema = z.object({ // config: z.array( @@ -188,6 +189,9 @@ export default function RustTool({ {/* Go Playground*/} {/* */} {/*)}*/} + + + ); diff --git a/libs/shinkai-message-ts/src/api/jobs/types.ts b/libs/shinkai-message-ts/src/api/jobs/types.ts index 8ba083970..fedf749e8 100644 --- a/libs/shinkai-message-ts/src/api/jobs/types.ts +++ b/libs/shinkai-message-ts/src/api/jobs/types.ts @@ -141,6 +141,7 @@ export type JobMessage = { message: string; }; tool_router_key: string; + response?: string; }[]; }; }; diff --git a/libs/shinkai-message-ts/src/api/tools/index.ts b/libs/shinkai-message-ts/src/api/tools/index.ts index c14afcca9..e2e52739f 100644 --- a/libs/shinkai-message-ts/src/api/tools/index.ts +++ b/libs/shinkai-message-ts/src/api/tools/index.ts @@ -22,6 +22,7 @@ import { ImportToolRequest, ImportToolResponse, PayInvoiceRequest, + RemovePlaygroundToolRequest, SaveToolCodeRequest, SaveToolCodeResponse, SearchPromptsResponse, @@ -316,6 +317,22 @@ export const restoreToolConversation = async ( return response.data as UndoToolImplementationResponse; }; +export const removePlaygroundTool = async ( + nodeAddress: string, + bearerToken: string, + payload: RemovePlaygroundToolRequest, +) => { + const response = await httpClient.delete( + urlJoin(nodeAddress, '/v2/remove_playground_tool'), + { + params: { tool_key: payload.tool_key }, + headers: { Authorization: `Bearer ${bearerToken}` }, + responseType: 'json', + }, + ); + return response.data; +}; + export const updateToolCodeImplementation = async ( nodeAddress: string, bearerToken: string, diff --git a/libs/shinkai-message-ts/src/api/tools/types.ts b/libs/shinkai-message-ts/src/api/tools/types.ts index 0b10cadfe..2dd469c0a 100644 --- a/libs/shinkai-message-ts/src/api/tools/types.ts +++ b/libs/shinkai-message-ts/src/api/tools/types.ts @@ -10,6 +10,9 @@ export type ShinkaiToolHeader = { tool_router_key: string; tool_type: ShinkaiToolType; version: string; + input_args: { + properties: Record; + }; }; export type ToolConfig = { @@ -293,6 +296,10 @@ export type UpdateToolCodeImplementationResponse = { status: string; }; +export type RemovePlaygroundToolRequest = { + tool_key: string; +}; + export type ImportToolRequest = { url: string; }; diff --git a/libs/shinkai-node-state/src/forms/chat/chat-message.ts b/libs/shinkai-node-state/src/forms/chat/chat-message.ts index 51052e669..8f9adaf8f 100644 --- a/libs/shinkai-node-state/src/forms/chat/chat-message.ts +++ b/libs/shinkai-node-state/src/forms/chat/chat-message.ts @@ -8,6 +8,7 @@ export const chatMessageFormSchema = z.object({ key: z.string().min(1), name: z.string().min(1), description: z.string().min(1), + args: z.array(z.string()).optional(), }) .optional(), }); diff --git a/libs/shinkai-node-state/src/forms/chat/create-job.ts b/libs/shinkai-node-state/src/forms/chat/create-job.ts index f24f8a321..3da279946 100644 --- a/libs/shinkai-node-state/src/forms/chat/create-job.ts +++ b/libs/shinkai-node-state/src/forms/chat/create-job.ts @@ -9,6 +9,7 @@ export const createJobFormSchema = z.object({ key: z.string().min(1), name: z.string().min(1), description: z.string().min(1), + args: z.array(z.string()).optional(), }) .optional(), }); diff --git a/libs/shinkai-node-state/src/v2/mutations/removeTool/index.ts b/libs/shinkai-node-state/src/v2/mutations/removeTool/index.ts new file mode 100644 index 000000000..534314ae6 --- /dev/null +++ b/libs/shinkai-node-state/src/v2/mutations/removeTool/index.ts @@ -0,0 +1,13 @@ +import { removePlaygroundTool as removePlaygroundToolApi } from '@shinkai_network/shinkai-message-ts/api/tools/index'; + +import { RemoveToolInput } from './types'; + +export const removeTool = async ({ + nodeAddress, + token, + toolKey, +}: RemoveToolInput) => { + return await removePlaygroundToolApi(nodeAddress, token, { + tool_key: toolKey, + }); +}; diff --git a/libs/shinkai-node-state/src/v2/mutations/removeTool/types.ts b/libs/shinkai-node-state/src/v2/mutations/removeTool/types.ts new file mode 100644 index 000000000..f846e2612 --- /dev/null +++ b/libs/shinkai-node-state/src/v2/mutations/removeTool/types.ts @@ -0,0 +1,10 @@ +import { Token } from '@shinkai_network/shinkai-message-ts/api/general/types'; + +export type RemoveToolOutput = { + status: string; +}; + +export type RemoveToolInput = Token & { + nodeAddress: string; + toolKey: string; +}; diff --git a/libs/shinkai-node-state/src/v2/mutations/removeTool/useRemoveTool.ts b/libs/shinkai-node-state/src/v2/mutations/removeTool/useRemoveTool.ts new file mode 100644 index 000000000..fc51985eb --- /dev/null +++ b/libs/shinkai-node-state/src/v2/mutations/removeTool/useRemoveTool.ts @@ -0,0 +1,35 @@ +import { + useMutation, + type UseMutationOptions, + useQueryClient, +} from '@tanstack/react-query'; + +import { FunctionKeyV2 } from '../../constants'; +import { APIError } from '../../types'; +import { removeTool } from './index'; +import { RemoveToolInput, RemoveToolOutput } from './types'; + +type Options = UseMutationOptions; + +export const useRemoveTool = (options?: Options) => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: removeTool, + ...options, + onSuccess: (response, variables, context) => { + queryClient.invalidateQueries({ + queryKey: [ + FunctionKeyV2.GET_PLAYGROUND_TOOLS, + { + nodeAddress: variables.nodeAddress, + token: variables.token, + }, + ], + }); + + if (options?.onSuccess) { + options.onSuccess(response, variables, context); + } + }, + }); +}; diff --git a/libs/shinkai-node-state/src/v2/queries/getChatConversation/index.ts b/libs/shinkai-node-state/src/v2/queries/getChatConversation/index.ts index 78fb56411..957695737 100644 --- a/libs/shinkai-node-state/src/v2/queries/getChatConversation/index.ts +++ b/libs/shinkai-node-state/src/v2/queries/getChatConversation/index.ts @@ -1,3 +1,4 @@ +import { ToolStatusType } from '@shinkai_network/shinkai-message-ts/api/general/types'; import { downloadFileFromInbox, getFileNames, @@ -84,6 +85,8 @@ const createAssistantMessage = (message: ChatMessage): AssistantMessage => { toolRouterKey: tool.tool_router_key, name: tool.name, args: tool.arguments, + status: ToolStatusType.Complete, + result: tool?.response ?? '', }), ); diff --git a/libs/shinkai-node-state/src/v2/queries/getChatConversation/types.ts b/libs/shinkai-node-state/src/v2/queries/getChatConversation/types.ts index f9c13a66f..37eabfd28 100644 --- a/libs/shinkai-node-state/src/v2/queries/getChatConversation/types.ts +++ b/libs/shinkai-node-state/src/v2/queries/getChatConversation/types.ts @@ -29,7 +29,7 @@ type ToolCall = { toolRouterKey: string; name: string; args: ToolArgs; - result?: unknown; + result?: string; status?: ToolStatusType; // TODO: remove isError?: boolean; }; diff --git a/libs/shinkai-ui/src/components/chat/message.tsx b/libs/shinkai-ui/src/components/chat/message.tsx index 04896245c..3ead83982 100644 --- a/libs/shinkai-ui/src/components/chat/message.tsx +++ b/libs/shinkai-ui/src/components/chat/message.tsx @@ -316,7 +316,9 @@ const MessageBase = ({ svg]:hidden [&[data-state=open]]:bg-gray-500', + 'transition-colors hover:bg-gray-500 [&[data-state=open]]:bg-gray-500', + tool.status !== ToolStatusType.Complete && + '[&>svg]:hidden', )} > - + {Object.keys(tool.args).length > 0 && ( {tool.name}( {Object.keys(tool.args).length > 0 && ( - + {JSON.stringify(tool.args)} )} ) )} + {tool.result && ( + + Response: + + {JSON.stringify(tool.result, null, 2)} + + + )} );