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 42e89fede..75d2ceb37 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 @@ -3,6 +3,7 @@ import { useMemo, useRef, useState } from 'react'; import { z } from 'zod'; import { useChatConversationWithOptimisticUpdates } from '../../../pages/chat/chat-conversation'; +import { useAuth } from '../../../store/auth'; import { ToolMetadataSchema } from '../schemas'; export const useToolMetadata = ({ @@ -23,6 +24,7 @@ export const useToolMetadata = ({ const [metadataData, setMetadataData] = useState( initialState?.metadata ?? null, ); + const auth = useAuth((state) => state.auth); const forceGenerateMetadata = useRef(false); @@ -67,9 +69,13 @@ export const useToolMetadata = ({ if (jsonCodeMatch) { try { const parsedJson = JSON.parse(jsonCodeMatch[1].trim()); - metadataGenerationData = ToolMetadataSchema.parse( + const parsedmetadataGenerationData = ToolMetadataSchema.parse( parsedJson, ) as ToolMetadata; + metadataGenerationData = { + ...parsedmetadataGenerationData, + author: auth?.shinkai_identity ?? '', + }; setMetadataData(metadataGenerationData); } catch (error) { if (error instanceof Error) { diff --git a/apps/shinkai-desktop/src/components/playground-tool/schemas.ts b/apps/shinkai-desktop/src/components/playground-tool/schemas.ts index 15174dd87..a6a913623 100644 --- a/apps/shinkai-desktop/src/components/playground-tool/schemas.ts +++ b/apps/shinkai-desktop/src/components/playground-tool/schemas.ts @@ -1,14 +1,6 @@ import { z } from 'zod'; export const ToolMetadataSchema = z.object({ - id: z - .string({ message: 'Tool ID is required' }) - .min(1, 'Tool ID is required') - .regex( - /^[a-z0-9-]+$/, - 'Tool ID must contain only lowercase letters, numbers, and hyphens', - ), - name: z .string({ message: 'Tool name is required' }) .min(1, 'Tool name is required') @@ -19,14 +11,9 @@ export const ToolMetadataSchema = z.object({ .min(1, 'Tool description is required') .max(500, 'Tool description must be less than 500 characters'), - author: z - .string({ message: 'Author is required' }) - .min(1, 'Author is required'), + author: z.string(), - keywords: z - .array(z.string(), { message: 'Keywords is required' }) - .min(1, { message: 'At least one keyword is required' }) - .max(10, { message: 'Maximum 10 keywords allowed' }), + keywords: z.array(z.string()).default([]), configurations: z .object( diff --git a/apps/shinkai-desktop/src/pages/create-tool.tsx b/apps/shinkai-desktop/src/pages/create-tool.tsx index 59bc5ef56..dab2e826f 100644 --- a/apps/shinkai-desktop/src/pages/create-tool.tsx +++ b/apps/shinkai-desktop/src/pages/create-tool.tsx @@ -60,7 +60,7 @@ import { } from 'lucide-react'; import { InfoCircleIcon } from 'primereact/icons/infocircle'; import { PrismEditor } from 'prism-react-editor'; -import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { useForm, UseFormReturn } from 'react-hook-form'; import { Link, To, useNavigate } from 'react-router-dom'; import { toast } from 'sonner'; @@ -91,7 +91,6 @@ export function extractTypeScriptCode(message: string) { } function CreateToolPage() { - const [tab, setTab] = useState<'code' | 'preview'>('code'); const auth = useAuth((state) => state.auth); const { t } = useTranslation(); const toolResultBoxRef = useRef(null); @@ -134,6 +133,7 @@ function CreateToolPage() { } = useToolMetadata({ chatInboxIdMetadata, code: toolCode }); const codeEditorRef = useRef(null); + const metadataEditorRef = useRef(null); const [resetCounter, setResetCounter] = useState(0); const form = useForm({ @@ -151,6 +151,7 @@ function CreateToolPage() { isSuccess: isCodeExecutionSuccess, isError: isCodeExecutionError, error: codeExecutionError, + reset: resetCodeExecution, } = useExecuteToolCode({ onSuccess: (data) => { setToolResult(data); @@ -204,6 +205,7 @@ function CreateToolPage() { forceGenerateMetadata.current = true; baseToolCodeRef.current = ''; setToolResult(null); + resetCodeExecution(); }, }); @@ -283,11 +285,14 @@ function CreateToolPage() { }); }; - const handleSaveTool = async (e: React.FormEvent) => { - e.preventDefault(); + const handleSaveTool = async () => { + if (!chatInboxId) return; + + const metadataCode = metadataEditorRef.current?.value; + const toolCode = codeEditorRef.current?.value; - const metadataCode = new FormData(e.currentTarget).get('editor'); let parsedMetadata: ToolMetadata; + try { const parseResult = JSON.parse(metadataCode as string) as ToolMetadata; parsedMetadata = ToolMetadataSchema.parse(parseResult); @@ -306,13 +311,9 @@ function CreateToolPage() { return; } - if (!chatInboxId) return; await saveToolCode({ code: toolCode, - metadata: { - ...parsedMetadata, - author: auth?.shinkai_identity ?? '', - }, + metadata: parsedMetadata, jobId: extractJobIdFromInbox(chatInboxId), token: auth?.api_v2_key ?? '', nodeAddress: auth?.node_address ?? '', @@ -470,8 +471,7 @@ function CreateToolPage() { rightElement={ setTab(value as 'preview' | 'code')} - value={tab} + defaultValue="code" >
@@ -641,10 +641,9 @@ function CreateToolPage() { !chatInboxId || isSavingTool } - form="metadata-form" isLoading={isSavingTool} + onClick={handleSaveTool} size="sm" - type="submit" variant="outline" > @@ -653,7 +652,8 @@ function CreateToolPage() {
@@ -808,13 +808,31 @@ function CreateToolPage() {
-
-

- Run -

- {metadataGenerationData && ( -

Fill in the options above to run your tool.

- )} +
+
+

+ Run +

+ {metadataGenerationData && ( +

Fill in the options above to run your tool.

+ )} +
+ {isMetadataGenerationSuccess && + !isToolCodeGenerationPending && + !isMetadataGenerationError && ( + + )}
{(isMetadataGenerationPending || @@ -839,6 +857,7 @@ function CreateToolPage() { setFormData(e.formData)} onSubmit={handleRunCode} @@ -847,23 +866,7 @@ function CreateToolPage() { } uiSchema={{ 'ui:submitButtonOptions': { - props: { - disabled: isExecutingCode, - isLoading: isExecutingCode, - }, - // @ts-expect-error string type - submitText: ( -
- {!isExecutingCode && ( - - )} - Run -
- ), + norender: true, }, }} validator={validator} @@ -929,7 +932,8 @@ function CreateToolPage() {
@@ -972,30 +976,22 @@ function CreateToolPage() { {isMetadataGenerationSuccess && !isMetadataGenerationError && (
-
-
- -
-
+
+ +
)} {isMetadataGenerationIdle && ( diff --git a/apps/shinkai-desktop/src/pages/edit-tool.tsx b/apps/shinkai-desktop/src/pages/edit-tool.tsx index 40dc9bfb1..79ca4df52 100644 --- a/apps/shinkai-desktop/src/pages/edit-tool.tsx +++ b/apps/shinkai-desktop/src/pages/edit-tool.tsx @@ -43,7 +43,8 @@ import { Play, Save, } from 'lucide-react'; -import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { PrismEditor } from 'prism-react-editor'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { useForm } from 'react-hook-form'; import { Link, To, useNavigate, useParams } from 'react-router-dom'; import { toast } from 'sonner'; @@ -69,7 +70,6 @@ export const createToolCodeFormSchema = z.object({ export type CreateToolCodeFormSchema = z.infer; function EditToolPage() { - const [tab, setTab] = useState<'code' | 'preview'>('code'); const auth = useAuth((state) => state.auth); const { toolRouterKey } = useParams(); @@ -95,6 +95,8 @@ function EditToolPage() { const [chatInboxIdMetadata, setChatInboxIdMetadata] = useState< string | undefined >(undefined); + const codeEditorRef = useRef(null); + const metadataEditorRef = useRef(null); const [resetCounter, setResetCounter] = useState(0); @@ -260,7 +262,6 @@ function EditToolPage() { { onSuccess: (data) => { setChatInboxId(data.inbox); - setTab('code'); setToolCode(''); forceGenerateMetadata.current = true; baseToolCodeRef.current = ''; @@ -285,10 +286,12 @@ function EditToolPage() { }); }; - const handleSaveTool = async (e: React.FormEvent) => { - e.preventDefault(); + const handleSaveTool = async () => { + if (!chatInboxId) return; + + const metadataCode = metadataEditorRef.current?.value; + const toolCode = codeEditorRef.current?.value; - const metadataCode = new FormData(e.currentTarget).get('editor'); let parsedMetadata: ToolMetadata; try { const parseResult = JSON.parse(metadataCode as string) as ToolMetadata; @@ -308,14 +311,9 @@ function EditToolPage() { return; } - if (!chatInboxId) return; - await saveToolCode({ code: toolCode, - metadata: { - ...parsedMetadata, - author: auth?.shinkai_identity ?? '', - }, + metadata: parsedMetadata, jobId: extractJobIdFromInbox(chatInboxId), token: auth?.api_v2_key ?? '', nodeAddress: auth?.node_address ?? '', @@ -467,8 +465,7 @@ function EditToolPage() { rightElement={ setTab(value as 'preview' | 'code')} - value={tab} + defaultValue="code" >
@@ -496,10 +493,9 @@ function EditToolPage() { !chatInboxId || isSavingTool } - form="metadata-form" isLoading={isSavingTool} + onClick={handleSaveTool} size="sm" - type="submit" variant="outline" > @@ -509,7 +505,8 @@ function EditToolPage() {
@@ -651,129 +648,135 @@ function EditToolPage() {
-

- Run -

-
- {metadataGenerationData && ( -

Fill in the options above to run your tool.

- )} -
- {(isMetadataGenerationPending || - isToolCodeGenerationPending) && ( -
- - Generating... +
+
+

+ Run +

+ {metadataGenerationData && ( +

Fill in the options above to run your tool.

+ )}
- )} - {!isMetadataGenerationPending && - !isToolCodeGenerationPending && - isMetadataGenerationError && ( - - )} - {isMetadataGenerationSuccess && - !isToolCodeGenerationPending && - !isMetadataGenerationError && - isValidSchema && ( -
- setFormData(e.formData)} - onSubmit={handleRunCode} - schema={ - metadataGenerationData?.parameters as RJSFSchema - } - uiSchema={{ - 'ui:submitButtonOptions': { - props: { - disabled: isExecutingCode, - isLoading: isExecutingCode, - }, - // @ts-expect-error string type - submitText: ( -
- {!isExecutingCode && ( - - )} - Run -
- ), - }, - }} - validator={validator} - /> - - {(isExecutingCode || - isCodeExecutionError || - isCodeExecutionSuccess) && ( - - {isExecutingCode && ( -
- - Running Tool... -
- )} - {isCodeExecutionError && ( -
-

- Tool execution failed. Try generating - the tool code again. -

-
-                                          {codeExecutionError?.response?.data
-                                            ?.message ??
-                                            codeExecutionError?.message}
-                                        
-
- )} - {isCodeExecutionSuccess && toolResult && ( -
- -
- )} -
+ {isMetadataGenerationSuccess && + !isToolCodeGenerationPending && + !isMetadataGenerationError && ( +
- )} - {isMetadataGenerationIdle && - !isToolCodeGenerationPending && ( -
-

- No metadata generated yet. -

+ Run + + )} +
+
+ {(isMetadataGenerationPending || + isToolCodeGenerationPending) && ( +
+ + Generating...
)} + {!isMetadataGenerationPending && + !isToolCodeGenerationPending && + isMetadataGenerationError && ( + + )} + {isMetadataGenerationSuccess && + !isToolCodeGenerationPending && + !isMetadataGenerationError && + isValidSchema && ( +
+ setFormData(e.formData)} + onSubmit={handleRunCode} + schema={ + metadataGenerationData?.parameters as RJSFSchema + } + uiSchema={{ + 'ui:submitButtonOptions': { + norender: true, + }, + }} + validator={validator} + /> + + {(isExecutingCode || + isCodeExecutionError || + isCodeExecutionSuccess) && ( + + {isExecutingCode && ( +
+ + Running Tool... +
+ )} + {isCodeExecutionError && ( +
+

+ Tool execution failed. Try + generating the tool code again. +

+
+                                            {codeExecutionError?.response?.data
+                                              ?.message ??
+                                              codeExecutionError?.message}
+                                          
+
+ )} + {isCodeExecutionSuccess && toolResult && ( +
+ +
+ )} +
+ )} +
+
+ )} + {isMetadataGenerationIdle && + !isToolCodeGenerationPending && ( +
+

+ No metadata generated yet. +

+
+ )} +
@@ -815,30 +818,22 @@ function EditToolPage() { {isMetadataGenerationSuccess && !isMetadataGenerationError && (
-
-
- -
-
+
+ +
)} diff --git a/libs/shinkai-message-ts/src/api/tools/types.ts b/libs/shinkai-message-ts/src/api/tools/types.ts index aeb293c56..0ba48033f 100644 --- a/libs/shinkai-message-ts/src/api/tools/types.ts +++ b/libs/shinkai-message-ts/src/api/tools/types.ts @@ -215,7 +215,6 @@ export type SaveToolCodeRequest = { }; export type ToolMetadata = { - id: string; name: string; description: string; author: string;