diff --git a/apps/shinkai-desktop/src/components/agent/agents.tsx b/apps/shinkai-desktop/src/components/agent/agents.tsx index ed3a5754e..c65d26c96 100644 --- a/apps/shinkai-desktop/src/components/agent/agents.tsx +++ b/apps/shinkai-desktop/src/components/agent/agents.tsx @@ -188,7 +188,7 @@ const AgentCard = ({ name: t('common.edit'), icon: , onClick: () => { - navigate(`/edit/${agentId}`); + navigate(`/agents/edit/${agentId}`); }, }, { diff --git a/apps/shinkai-desktop/src/components/chat/chat-action-bar/ai-update-selection-action-bar.tsx b/apps/shinkai-desktop/src/components/chat/chat-action-bar/ai-update-selection-action-bar.tsx index a45d50156..ab9acb2ef 100644 --- a/apps/shinkai-desktop/src/components/chat/chat-action-bar/ai-update-selection-action-bar.tsx +++ b/apps/shinkai-desktop/src/components/chat/chat-action-bar/ai-update-selection-action-bar.tsx @@ -19,7 +19,8 @@ import { } from '@shinkai_network/shinkai-ui'; import { AIAgentIcon } from '@shinkai_network/shinkai-ui/assets'; import { cn } from '@shinkai_network/shinkai-ui/utils'; -import { BotIcon, ChevronDownIcon } from 'lucide-react'; +import { BoltIcon, BotIcon, ChevronDownIcon } from 'lucide-react'; +import { Link } from 'react-router-dom'; import { toast } from 'sonner'; import { useGetCurrentInbox } from '../../../hooks/use-current-inbox'; @@ -80,14 +81,39 @@ export function AIModelSelector({ {isAgentsSuccess && agents.map((agent) => ( - -
- {agent.name} +
+ +
+ {agent.name} +
+ + + + + + + + +

Configure Agent

+
+
+
))} {isAgentsSuccess && agents.length > 0 && ( diff --git a/apps/shinkai-desktop/src/components/playground-tool/hooks/use-tool-metadata.ts b/apps/shinkai-desktop/src/components/playground-tool/hooks/use-tool-metadata.ts index 75d2ceb37..3923cfa28 100644 --- a/apps/shinkai-desktop/src/components/playground-tool/hooks/use-tool-metadata.ts +++ b/apps/shinkai-desktop/src/components/playground-tool/hooks/use-tool-metadata.ts @@ -1,6 +1,5 @@ import { ToolMetadata } from '@shinkai_network/shinkai-message-ts/api/tools/types'; -import { useMemo, useRef, useState } from 'react'; -import { z } from 'zod'; +import { useEffect, useRef, useState } from 'react'; import { useChatConversationWithOptimisticUpdates } from '../../../pages/chat/chat-conversation'; import { useAuth } from '../../../store/auth'; @@ -14,17 +13,20 @@ export const useToolMetadata = ({ code?: string; initialState?: { metadata: ToolMetadata | null; - isMetadataGenerationPending?: boolean; - isMetadataGenerationSuccess?: boolean; - isMetadataGenerationIdle?: boolean; - isMetadataGenerationError?: boolean; - metadataGenerationError?: string | null; + state?: 'idle' | 'pending' | 'success' | 'error'; + error?: string | null; }; }) => { const [metadataData, setMetadataData] = useState( initialState?.metadata ?? null, ); const auth = useAuth((state) => state.auth); + const [error, setError] = useState( + initialState?.error ?? null, + ); + const [metadataState, setMetadataState] = useState< + 'idle' | 'pending' | 'success' | 'error' + >(initialState?.state ?? 'idle'); const forceGenerateMetadata = useRef(false); @@ -34,83 +36,64 @@ export const useToolMetadata = ({ forceRefetchInterval: true, }); - const { - isMetadataGenerationPending, - isMetadataGenerationSuccess, - isMetadataGenerationIdle, - metadataGenerationData, - metadataGenerationError, - isMetadataGenerationError, - } = useMemo(() => { + useEffect(() => { + setMetadataData(initialState?.metadata ?? null); + setError(initialState?.error ?? null); + setMetadataState(initialState?.state ?? 'idle'); + }, [initialState?.error, initialState?.metadata, initialState?.state]); + + useEffect(() => { const metadata = metadataChatConversation?.pages?.at(-1)?.at(-1); - if (initialState && !metadata) { - return { - isMetadataGenerationPending: - initialState.isMetadataGenerationPending ?? false, - isMetadataGenerationSuccess: - initialState.isMetadataGenerationSuccess ?? false, - isMetadataGenerationIdle: initialState.isMetadataGenerationIdle ?? true, - metadataGenerationData: metadataData, - isMetadataGenerationError: - initialState.isMetadataGenerationError ?? false, - metadataGenerationError: initialState.metadataGenerationError ?? null, - }; + if (!metadata) { + return; + } + + if (metadata?.role === 'assistant' && metadata?.status.type === 'running') { + setMetadataState('pending'); + return; } - const isMetadataGenerationIdle = metadata == null; - const isMetadataGenerationPending = - metadata?.role === 'assistant' && metadata?.status.type === 'running'; - const isMetadataGenerationSuccess = - metadata?.role === 'assistant' && metadata?.status.type === 'complete'; - let metadataGenerationData = null; - let metadataGenerationError: null | string = null; - if (isMetadataGenerationSuccess) { + + if ( + metadata?.role === 'assistant' && + metadata?.status.type === 'complete' + ) { const jsonCodeMatch = metadata.content.match(/```json\n([\s\S]*?)\n```/); if (jsonCodeMatch) { try { const parsedJson = JSON.parse(jsonCodeMatch[1].trim()); - const parsedmetadataGenerationData = ToolMetadataSchema.parse( + const parsedMetadata = ToolMetadataSchema.parse( parsedJson, ) as ToolMetadata; - metadataGenerationData = { - ...parsedmetadataGenerationData, + setMetadataData({ + ...parsedMetadata, author: auth?.shinkai_identity ?? '', - }; - setMetadataData(metadataGenerationData); + }); + setMetadataState('success'); + setError(null); } catch (error) { - if (error instanceof Error) { - metadataGenerationError = 'Invalid Metadata: ' + error.message; - } - if (error instanceof z.ZodError) { - metadataGenerationError = - 'Invalid Metadata: ' + - error.issues.map((issue) => issue.message).join(', '); - } + setMetadataState('error'); + setError( + error instanceof Error + ? 'Invalid Metadata: ' + error.message + : 'Invalid Metadata: Unknown Error', + ); } } else { - metadataGenerationError = 'No JSON code found'; + setMetadataState('error'); + setError('No JSON code found'); } + return; } - - return { - metadataMessageContent: metadata?.content, - isMetadataGenerationPending, - isMetadataGenerationSuccess, - isMetadataGenerationIdle, - metadataGenerationData, - isMetadataGenerationError: metadataGenerationError != null, - metadataGenerationError, - }; - }, [initialState, metadataChatConversation?.pages]); + }, [auth?.shinkai_identity, metadataChatConversation?.pages]); return { - isMetadataGenerationPending, - isMetadataGenerationSuccess, - isMetadataGenerationIdle, - metadataGenerationData, - metadataGenerationError, - isMetadataGenerationError, + isMetadataGenerationIdle: metadataState === 'idle', + isMetadataGenerationPending: metadataState === 'pending', + isMetadataGenerationSuccess: metadataState === 'success', + isMetadataGenerationError: metadataState === 'error', + metadataGenerationError: error, + metadataGenerationData: metadataData, forceGenerateMetadata, - setMetadataData, }; }; diff --git a/apps/shinkai-desktop/src/pages/edit-tool.tsx b/apps/shinkai-desktop/src/pages/edit-tool.tsx index 79ca4df52..593b175a6 100644 --- a/apps/shinkai-desktop/src/pages/edit-tool.tsx +++ b/apps/shinkai-desktop/src/pages/edit-tool.tsx @@ -44,7 +44,7 @@ import { Save, } from 'lucide-react'; import { PrismEditor } from 'prism-react-editor'; -import { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useForm } from 'react-hook-form'; import { Link, To, useNavigate, useParams } from 'react-router-dom'; import { toast } from 'sonner'; @@ -91,7 +91,11 @@ function EditToolPage() { const [isDirty, setIsDirty] = useState(false); const [toolResult, setToolResult] = useState(null); - const [chatInboxId, setChatInboxId] = useState(undefined); + + const chatInboxId = playgroundTool + ? buildInboxIdFromJobId(playgroundTool.job_id) + : ''; + const [chatInboxIdMetadata, setChatInboxIdMetadata] = useState< string | undefined >(undefined); @@ -121,6 +125,27 @@ function EditToolPage() { playgroundTool?.metadata?.parameters ?? {}, ); + const initialState = useMemo( + () => ({ + metadata: playgroundTool?.metadata ?? null, + state: isPlaygroundToolPending + ? 'pending' + : isPlaygroundToolError || !isValidSchema + ? 'error' + : isPlaygroundToolSuccess + ? 'success' + : ('idle' as 'idle' | 'pending' | 'success' | 'error'), + error: isValidSchema ? null : 'Tool Metadata doesnt follow the schema', + }), + [ + playgroundTool?.metadata, + isPlaygroundToolPending, + isPlaygroundToolSuccess, + isPlaygroundToolError, + isValidSchema, + ], + ); + const { isMetadataGenerationPending, isMetadataGenerationSuccess, @@ -129,20 +154,10 @@ function EditToolPage() { metadataGenerationError, isMetadataGenerationError, forceGenerateMetadata, - // setMetadataData, } = useToolMetadata({ chatInboxIdMetadata, code: toolCode, - initialState: { - metadata: playgroundTool?.metadata ?? null, - isMetadataGenerationPending: isPlaygroundToolPending, - isMetadataGenerationSuccess: isPlaygroundToolSuccess, - isMetadataGenerationIdle: false, - isMetadataGenerationError: isPlaygroundToolError || !isValidSchema, - metadataGenerationError: isValidSchema - ? null - : 'Tool Metadata doesnt follow the schema', - }, + initialState, }); const form = useForm({ @@ -215,13 +230,6 @@ function EditToolPage() { form.setValue('llmProviderId', defaultAgentId); }, [form, defaultAgentId]); - useEffect(() => { - if (playgroundTool) { - setToolCode(playgroundTool.code); - setChatInboxId(buildInboxIdFromJobId(playgroundTool.job_id)); - } - }, [playgroundTool]); - useEffect(() => { if (!toolCode || !forceGenerateMetadata.current) return; const run = async () => { @@ -250,7 +258,7 @@ function EditToolPage() { ]); const onSubmit = async (data: CreateToolCodeFormSchema) => { - if (!auth) return; + if (!auth || !chatInboxId) return; await createToolCode( { nodeAddress: auth.node_address, @@ -258,10 +266,10 @@ function EditToolPage() { message: data.message, llmProviderId: data.llmProviderId, tools: data.tools, + jobId: playgroundTool?.job_id, }, { - onSuccess: (data) => { - setChatInboxId(data.inbox); + onSuccess: () => { setToolCode(''); forceGenerateMetadata.current = true; baseToolCodeRef.current = ''; @@ -647,7 +655,7 @@ function EditToolPage() {
-
+

@@ -682,36 +690,35 @@ function EditToolPage() { Generating...

)} - {!isMetadataGenerationPending && - !isToolCodeGenerationPending && + {!isToolCodeGenerationPending && isMetadataGenerationError && ( )} - {isMetadataGenerationSuccess && - !isToolCodeGenerationPending && - !isMetadataGenerationError && - isValidSchema && ( + {!isToolCodeGenerationPending && + isMetadataGenerationSuccess && (
- setFormData(e.formData)} - onSubmit={handleRunCode} - schema={ - metadataGenerationData?.parameters as RJSFSchema - } - uiSchema={{ - 'ui:submitButtonOptions': { - norender: true, - }, - }} - validator={validator} - /> + {!isMetadataGenerationPending && ( + setFormData(e.formData)} + onSubmit={handleRunCode} + schema={ + metadataGenerationData?.parameters as RJSFSchema + } + uiSchema={{ + 'ui:submitButtonOptions': { + norender: true, + }, + }} + validator={validator} + /> + )} {(isExecutingCode || isCodeExecutionError || diff --git a/apps/shinkai-desktop/src/routes/index.tsx b/apps/shinkai-desktop/src/routes/index.tsx index ce2d1250a..895c98e76 100644 --- a/apps/shinkai-desktop/src/routes/index.tsx +++ b/apps/shinkai-desktop/src/routes/index.tsx @@ -270,7 +270,7 @@ const AppRoutes = () => { } path="ais" /> } path="add-ai" /> } path="add-agent" /> - } path="edit/:agentId" /> + } path="/agents/edit/:agentId" /> { mutationFn: createToolCode, ...options, onSuccess: (response, variables, context) => { + queryClient.invalidateQueries({ + queryKey: [ + FunctionKeyV2.GET_CHAT_CONVERSATION_PAGINATION, + { inboxId: response.inbox }, + ], + }); if (options?.onSuccess) { - queryClient.invalidateQueries({ - queryKey: [ - FunctionKeyV2.GET_CHAT_CONVERSATION_PAGINATION, - { inboxId: response.inbox }, - ], - }); options.onSuccess(response, variables, context); } },