From f0f4106f16fb851303719961d5040af79294e5be Mon Sep 17 00:00:00 2001 From: paulclindo Date: Tue, 17 Dec 2024 18:23:06 -0500 Subject: [PATCH 1/5] fix: language when editing --- .../src/components/playground-tool/utils/code.ts | 11 +++++++++++ apps/shinkai-desktop/src/pages/edit-tool.tsx | 5 ++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/shinkai-desktop/src/components/playground-tool/utils/code.ts b/apps/shinkai-desktop/src/components/playground-tool/utils/code.ts index 6864aaffa..0982173e1 100644 --- a/apps/shinkai-desktop/src/components/playground-tool/utils/code.ts +++ b/apps/shinkai-desktop/src/components/playground-tool/utils/code.ts @@ -34,3 +34,14 @@ export function detectLanguage(code: string): string { if (isTypeScript) return 'TypeScript'; return 'Unknown'; } + +export function getLanguage(language: string): CodeLanguage { + switch (language) { + case 'python': + return CodeLanguage.Python; + case 'typeScript': + return CodeLanguage.Typescript; + default: + return CodeLanguage.Typescript; + } +} diff --git a/apps/shinkai-desktop/src/pages/edit-tool.tsx b/apps/shinkai-desktop/src/pages/edit-tool.tsx index a889896ba..03b8474ae 100644 --- a/apps/shinkai-desktop/src/pages/edit-tool.tsx +++ b/apps/shinkai-desktop/src/pages/edit-tool.tsx @@ -1,12 +1,11 @@ import validator from '@rjsf/validator-ajv8'; -import { CodeLanguage } from '@shinkai_network/shinkai-message-ts/api/tools/types'; import { buildInboxIdFromJobId } from '@shinkai_network/shinkai-message-ts/utils/inbox_name_handler'; import { useGetPlaygroundTool } from '@shinkai_network/shinkai-node-state/v2/queries/getPlaygroundTool/useGetPlaygroundTool'; import { useMemo } from 'react'; import { useParams } from 'react-router-dom'; import PlaygroundToolEditor from '../components/playground-tool/components/tool-playground'; -import { detectLanguage } from '../components/playground-tool/utils/code'; +import { getLanguage } from '../components/playground-tool/utils/code'; import { useAuth } from '../store/auth'; function EditToolPage() { @@ -74,7 +73,7 @@ function EditToolPage() { return ( Date: Tue, 17 Dec 2024 19:35:26 -0500 Subject: [PATCH 2/5] feat: download tool assets --- .../components/tool-playground.tsx | 114 ++++++++++++++++-- .../playground-tool/hooks/use-tool-code.ts | 11 +- .../shinkai-message-ts/src/api/tools/index.ts | 18 +++ .../shinkai-message-ts/src/api/tools/types.ts | 3 + libs/shinkai-node-state/src/v2/constants.ts | 1 + .../queries/getShinkaiFileProtocol/index.ts | 14 +++ .../queries/getShinkaiFileProtocol/types.ts | 9 ++ .../useGetShinkaiFileProtocol.ts | 32 +++++ 8 files changed, 192 insertions(+), 10 deletions(-) create mode 100644 libs/shinkai-node-state/src/v2/queries/getShinkaiFileProtocol/index.ts create mode 100644 libs/shinkai-node-state/src/v2/queries/getShinkaiFileProtocol/types.ts create mode 100644 libs/shinkai-node-state/src/v2/queries/getShinkaiFileProtocol/useGetShinkaiFileProtocol.ts diff --git a/apps/shinkai-desktop/src/components/playground-tool/components/tool-playground.tsx b/apps/shinkai-desktop/src/components/playground-tool/components/tool-playground.tsx index 6a4196d27..cf2ad4c2c 100644 --- a/apps/shinkai-desktop/src/components/playground-tool/components/tool-playground.tsx +++ b/apps/shinkai-desktop/src/components/playground-tool/components/tool-playground.tsx @@ -6,6 +6,7 @@ import { CodeLanguage, ToolMetadata, } from '@shinkai_network/shinkai-message-ts/api/tools/types'; +import { useGetShinkaiFileProtocol } from '@shinkai_network/shinkai-node-state/v2/queries/getShinkaiFileProtocol/useGetShinkaiFileProtocol'; import { Badge, Button, @@ -29,13 +30,21 @@ import { TooltipPortal, TooltipTrigger, } from '@shinkai_network/shinkai-ui'; -import { SendIcon } from '@shinkai_network/shinkai-ui/assets'; +import { + fileIconMap, + FileTypeIcon, + SendIcon, +} from '@shinkai_network/shinkai-ui/assets'; import { cn } from '@shinkai_network/shinkai-ui/utils'; +import { save } from '@tauri-apps/plugin-dialog'; +import * as fs from '@tauri-apps/plugin-fs'; +import { BaseDirectory } from '@tauri-apps/plugin-fs'; import { AnimatePresence, motion } from 'framer-motion'; import { ArrowUpRight, Loader2, LucideArrowLeft, + Paperclip, Play, Redo2Icon, Save, @@ -43,6 +52,7 @@ import { } from 'lucide-react'; import { useEffect, useRef, useState } from 'react'; import { Link, To } from 'react-router-dom'; +import { toast } from 'sonner'; import { useAuth } from '../../../store/auth'; import { AIModelSelector } from '../../chat/chat-action-bar/ai-update-selection-action-bar'; @@ -112,6 +122,7 @@ function PlaygroundToolEditor({ metadataEditorRef, executeToolCodeQuery, toolResult, + toolResultFiles, isDirtyCodeEditor, setIsDirtyCodeEditor, forceGenerateMetadata, @@ -703,15 +714,33 @@ function PlaygroundToolEditor({
{executeToolCodeQuery.isSuccess && toolResult && ( - + {toolResultFiles.length > 0 && ( +
+

Generated Files

+
+ {toolResultFiles?.map( + (file) => ( + + ), + )} +
+
)} - /> + + +
)} @@ -813,3 +842,70 @@ function PlaygroundToolEditor({ } export default PlaygroundToolEditor; + +function ToolResultFileCard({ filePath }: { filePath: string }) { + const auth = useAuth((state) => state.auth); + const { refetch } = useGetShinkaiFileProtocol( + { + nodeAddress: auth?.node_address ?? '', + token: auth?.api_v2_key ?? '', + file: filePath, + }, + { + enabled: false, + }, + ); + + const fileNameBase = filePath.split('/')?.at(-1) ?? 'untitled_tool'; + const fileExtension = fileNameBase.split('.')?.at(-1) ?? ''; + + return ( + + ); +} diff --git a/apps/shinkai-desktop/src/components/playground-tool/hooks/use-tool-code.ts b/apps/shinkai-desktop/src/components/playground-tool/hooks/use-tool-code.ts index 8cc698ea8..c2930ab8e 100644 --- a/apps/shinkai-desktop/src/components/playground-tool/hooks/use-tool-code.ts +++ b/apps/shinkai-desktop/src/components/playground-tool/hooks/use-tool-code.ts @@ -415,6 +415,14 @@ export const useToolCode = ({ }, 0); }; + const { __created_files__: toolResultFiles, ...toolResultWithoutFiles } = + (toolResult || { + __created_files__: [], + }) as { + __created_files__: string[]; + [key: string]: any; + }; + return { chatInboxId, toolCode, @@ -437,7 +445,8 @@ export const useToolCode = ({ metadataEditorRef, createToolCode, executeToolCodeQuery, - toolResult, + toolResult: toolResultWithoutFiles, + toolResultFiles: toolResultFiles, forceGenerateMetadata, isDirtyCodeEditor, setIsDirtyCodeEditor, diff --git a/libs/shinkai-message-ts/src/api/tools/index.ts b/libs/shinkai-message-ts/src/api/tools/index.ts index 7ed0e8648..564bf2fcd 100644 --- a/libs/shinkai-message-ts/src/api/tools/index.ts +++ b/libs/shinkai-message-ts/src/api/tools/index.ts @@ -17,6 +17,8 @@ import { GetPlaygroundToolRequest, GetPlaygroundToolResponse, GetPlaygroundToolsResponse, + GetShinkaiFileProtocolRequest, + GetShinkaiFileProtocolResponse, GetToolResponse, GetToolsResponse, ImportToolRequest, @@ -387,3 +389,19 @@ export const exportTool = async ( ); return response.data as ExportToolResponse; }; + +export const getShinkaiFileProtocol = async ( + nodeAddress: string, + bearerToken: string, + payload: GetShinkaiFileProtocolRequest, +) => { + const response = await httpClient.get( + urlJoin(nodeAddress, '/v2/resolve_shinkai_file_protocol'), + { + headers: { Authorization: `Bearer ${bearerToken}` }, + params: { file: payload.file }, + responseType: 'blob', + }, + ); + return response.data as GetShinkaiFileProtocolResponse; +}; diff --git a/libs/shinkai-message-ts/src/api/tools/types.ts b/libs/shinkai-message-ts/src/api/tools/types.ts index 2dd469c0a..979c3e715 100644 --- a/libs/shinkai-message-ts/src/api/tools/types.ts +++ b/libs/shinkai-message-ts/src/api/tools/types.ts @@ -275,6 +275,7 @@ export type PlaygroundTool = { job_id: string; job_id_history: string[]; code: string; + language: string; }; export type GetPlaygroundToolsResponse = PlaygroundTool[]; export type GetPlaygroundToolRequest = { tool_key: string }; @@ -316,3 +317,5 @@ export type ExportToolRequest = { }; export type ExportToolResponse = Blob; +export type GetShinkaiFileProtocolRequest = { file: string }; +export type GetShinkaiFileProtocolResponse = Blob; diff --git a/libs/shinkai-node-state/src/v2/constants.ts b/libs/shinkai-node-state/src/v2/constants.ts index 9dda0e7a2..b9e7de3b9 100644 --- a/libs/shinkai-node-state/src/v2/constants.ts +++ b/libs/shinkai-node-state/src/v2/constants.ts @@ -38,6 +38,7 @@ export enum FunctionKeyV2 { GET_RECURRING_TASKS = 'GET_RECURRING_TASKS', GET_RECURRING_TASK = 'GET_RECURRING_TASK', GET_RECURRING_TASK_LOGS = 'GET_RECURRING_TASK_LOGS', + GET_SHINKAI_FILE_PROTOCOL = 'GET_SHINKAI_FILE_PROTOCOL', } export const DEFAULT_CHAT_CONFIG = { diff --git a/libs/shinkai-node-state/src/v2/queries/getShinkaiFileProtocol/index.ts b/libs/shinkai-node-state/src/v2/queries/getShinkaiFileProtocol/index.ts new file mode 100644 index 000000000..9cbb45dc4 --- /dev/null +++ b/libs/shinkai-node-state/src/v2/queries/getShinkaiFileProtocol/index.ts @@ -0,0 +1,14 @@ +import { getShinkaiFileProtocol as getShinkaiFileProtocolApi } from '@shinkai_network/shinkai-message-ts/api/tools/index'; + +import type { GetShinkaiFileProtocolInput } from './types'; + +export const getShinkaiFileProtocol = async ({ + nodeAddress, + token, + file, +}: GetShinkaiFileProtocolInput) => { + const result = await getShinkaiFileProtocolApi(nodeAddress, token, { + file, + }); + return result; +}; diff --git a/libs/shinkai-node-state/src/v2/queries/getShinkaiFileProtocol/types.ts b/libs/shinkai-node-state/src/v2/queries/getShinkaiFileProtocol/types.ts new file mode 100644 index 000000000..76196ae5d --- /dev/null +++ b/libs/shinkai-node-state/src/v2/queries/getShinkaiFileProtocol/types.ts @@ -0,0 +1,9 @@ +import { Token } from '@shinkai_network/shinkai-message-ts/api/general/types'; +import { GetShinkaiFileProtocolResponse } from '@shinkai_network/shinkai-message-ts/api/tools/types'; + +export type GetShinkaiFileProtocolInput = Token & { + nodeAddress: string; + file: string; +}; + +export type GetShinkaiFileProtocolOutput = GetShinkaiFileProtocolResponse; diff --git a/libs/shinkai-node-state/src/v2/queries/getShinkaiFileProtocol/useGetShinkaiFileProtocol.ts b/libs/shinkai-node-state/src/v2/queries/getShinkaiFileProtocol/useGetShinkaiFileProtocol.ts new file mode 100644 index 000000000..6ebf0249c --- /dev/null +++ b/libs/shinkai-node-state/src/v2/queries/getShinkaiFileProtocol/useGetShinkaiFileProtocol.ts @@ -0,0 +1,32 @@ +import { QueryObserverOptions, useQuery } from '@tanstack/react-query'; + +import { FunctionKeyV2 } from '../../constants'; +import { getShinkaiFileProtocol } from './index'; +import { + GetShinkaiFileProtocolInput, + GetShinkaiFileProtocolOutput, +} from './types'; + +export type UseGetShinkaiFileProtocol = [ + FunctionKeyV2.GET_SHINKAI_FILE_PROTOCOL, + GetShinkaiFileProtocolInput, +]; +type Options = QueryObserverOptions< + GetShinkaiFileProtocolOutput, + Error, + GetShinkaiFileProtocolOutput, + GetShinkaiFileProtocolOutput, + UseGetShinkaiFileProtocol +>; + +export const useGetShinkaiFileProtocol = ( + input: GetShinkaiFileProtocolInput, + options?: Omit, +) => { + const response = useQuery({ + queryKey: [FunctionKeyV2.GET_SHINKAI_FILE_PROTOCOL, input], + queryFn: () => getShinkaiFileProtocol(input), + ...options, + }); + return response; +}; From 51afe96e3777b24faa056d2ca855085f37331fbf Mon Sep 17 00:00:00 2001 From: paulclindo Date: Wed, 18 Dec 2024 00:11:05 -0500 Subject: [PATCH 3/5] feat: improve cron tasks --- .../cron-task/component/cron-task.tsx | 9 +- apps/shinkai-desktop/src/pages/task-logs.tsx | 321 +++++++++++------- .../src/api/recurring-tasks/types.ts | 1 + .../v2/mutations/createRecurringTask/index.ts | 1 + 4 files changed, 200 insertions(+), 132 deletions(-) diff --git a/apps/shinkai-desktop/src/components/cron-task/component/cron-task.tsx b/apps/shinkai-desktop/src/components/cron-task/component/cron-task.tsx index bb299e951..48ceb2bed 100644 --- a/apps/shinkai-desktop/src/components/cron-task/component/cron-task.tsx +++ b/apps/shinkai-desktop/src/components/cron-task/component/cron-task.tsx @@ -156,7 +156,10 @@ function CronTask({ mode, initialValues }: CronTaskProps) { .tool_router_key : '', }, - llmOrAgentId: defaultAgentId, // TODO: backend doesnt send this atm + llmOrAgentId: + 'CreateJobWithConfigAndMessage' in initialValues.action + ? initialValues.action.CreateJobWithConfigAndMessage.llm_provider + : defaultAgentId, }); } }, [form, initialValues]); @@ -248,7 +251,7 @@ function CronTask({ mode, initialValues }: CronTaskProps) { return (

Schedule recurring tasks at a specified time @@ -317,7 +320,7 @@ function CronTask({ mode, initialValues }: CronTaskProps) {

-
+
AI/Agent { diff --git a/apps/shinkai-desktop/src/pages/task-logs.tsx b/apps/shinkai-desktop/src/pages/task-logs.tsx index 6593f27ae..e79c2df51 100644 --- a/apps/shinkai-desktop/src/pages/task-logs.tsx +++ b/apps/shinkai-desktop/src/pages/task-logs.tsx @@ -8,6 +8,11 @@ import { Badge, Button, buttonVariants, + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, Dialog, DialogContent, DialogDescription, @@ -21,8 +26,16 @@ import { } from '@shinkai_network/shinkai-ui'; import { cn } from '@shinkai_network/shinkai-ui/utils'; import cronstrue from 'cronstrue'; -import { formatDate } from 'date-fns'; -import { Edit, TrashIcon } from 'lucide-react'; +import { format } from 'date-fns'; +import { + Bot, + CheckCircle2, + Clock, + Code2, + Edit, + TrashIcon, + XCircle, +} from 'lucide-react'; import React from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { toast } from 'sonner'; @@ -54,10 +67,10 @@ export const TaskLogs = () => { }); return ( - + {isGetRecurringTaskPending && (
-

Loading cron task details

+

...

)} {isGetRecurringTaskSuccess && ( @@ -65,6 +78,11 @@ export const TaskLogs = () => { cronExpression={task.cron} description={task.description} key={task.task_id} + llmProvider={ + 'CreateJobWithConfigAndMessage' in task.action + ? task.action.CreateJobWithConfigAndMessage.llm_provider + : '' + } name={task.name} prompt={ 'CreateJobWithConfigAndMessage' in task.action @@ -74,10 +92,8 @@ export const TaskLogs = () => { taskId={task.task_id} /> )} -
-

Logs

-
-
+ +
{isPending && Array.from({ length: 8 }).map((_, idx) => (
{
))} - {isSuccess && logs.length === 0 && ( -
-

No runs for this cron task yet

-

- check the schedule for your cron tasks to see when it runs -

-
- )} - {isSuccess && - logs.length > 0 && - logs.map((log) => ( -
- - {formatDate( - new Date(log.execution_time), - 'yyyy-MM-dd HH:mm:ss', - )} - - - {log.success ? 'Success' : 'Failed'} - + +
+

Logs

+ {/**/} + {/* {isRunning ? (*/} + {/* */} + {/* ) : (*/} + {/* */} + {/* )}*/} + {/* {isRunning ? 'Pause Task' : 'Resume Task'}*/} + {/**/} +
+ + + {isSuccess && logs.length === 0 && ( +
+

No runs for this cron task yet

+

+ check the schedule for your cron tasks to see when it runs +

- ))} + )} + {isSuccess && logs.length > 0 && ( +
+
+ Execution Time + Status + Message +
+ {logs.map((log) => ( +
+
+ {format(log.execution_time, 'PPPppp')} +
+ +
+ {log.success ? ( + + ) : ( + + )} +
+ {log.success ? 'Success' : 'Failed'} +
+
+
+ ))} +
+ )} +
); @@ -138,12 +180,16 @@ const TaskCard = ({ description, cronExpression, prompt, + llmProvider, + isRunning = true, }: { taskId: number; name: string; description?: string; cronExpression: string; prompt: string; + llmProvider: string; + isRunning?: boolean; }) => { const navigate = useNavigate(); const { t } = useTranslation(); @@ -155,103 +201,118 @@ const TaskCard = ({ }); return ( -
-
-
- - {name} - -
-

- {description ?? '-'} -

-

- Prompt - {prompt} -

-

- Schedule - {readableCron} -

-
- {/*
*/} - {/* */} - {/* */} - {/*
*/} - - -
{ - event.stopPropagation(); - }} - role="button" - tabIndex={0} - > - {t('common.moreOptions')} - + + +
+
+ + {name} + + {isRunning ? 'Active' : 'Paused'} + + + {description}
- - - {[ - { - name: t('common.edit'), - icon: , - onClick: () => { - navigate(`/tasks/edit/${taskId}`); - }, - }, - { - name: t('common.delete'), - icon: , - onClick: () => { - setIsDeleteTaskDrawerOpen(true); - }, - }, - ].map((option) => ( - - {option.name === 'Delete' && ( - - )} - + +
{ event.stopPropagation(); - option.onClick(); }} + role="button" + tabIndex={0} > - {option.icon} - {option.name} - - - ))} - - - -
+ {t('common.moreOptions')} + +
+ + + {[ + { + name: t('common.edit'), + icon: , + onClick: () => { + navigate(`/tasks/edit/${taskId}`); + }, + }, + { + name: t('common.delete'), + icon: , + onClick: () => { + setIsDeleteTaskDrawerOpen(true); + }, + }, + ].map((option) => ( + + {option.name === 'Delete' && ( + + )} + { + event.stopPropagation(); + option.onClick(); + }} + > + {option.icon} + {option.name} + + + ))} + + + +
+ + +
+
+
+ + Prompt +
+
{prompt}
+
+
+
+
+ + Schedule +
+
+ {readableCron} + ({cronExpression}) +
+
+
+
+ + Agent/AI Model +
+
{llmProvider}
+
+
+
+
+ ); }; @@ -268,10 +329,12 @@ const RemoveTaskDrawer = ({ }) => { const { t } = useTranslation(); const auth = useAuth((state) => state.auth); + const navigate = useNavigate(); const { mutateAsync: removeTask, isPending } = useRemoveRecurringTask({ onSuccess: () => { onOpenChange(false); toast.success('Delete task successfully'); + navigate('/tasks'); }, onError: (error) => { toast.error('Failed remove task', { diff --git a/libs/shinkai-message-ts/src/api/recurring-tasks/types.ts b/libs/shinkai-message-ts/src/api/recurring-tasks/types.ts index e11da49a3..f71209e62 100644 --- a/libs/shinkai-message-ts/src/api/recurring-tasks/types.ts +++ b/libs/shinkai-message-ts/src/api/recurring-tasks/types.ts @@ -16,6 +16,7 @@ export type RecurringTaskAction = CreateJobWithConfigAndMessage: { config: JobConfig; message: JobMessage; + llm_provider: string; job_creation_info: { scope: { network_folders: []; diff --git a/libs/shinkai-node-state/src/v2/mutations/createRecurringTask/index.ts b/libs/shinkai-node-state/src/v2/mutations/createRecurringTask/index.ts index ab2c1aa13..e107db0dc 100644 --- a/libs/shinkai-node-state/src/v2/mutations/createRecurringTask/index.ts +++ b/libs/shinkai-node-state/src/v2/mutations/createRecurringTask/index.ts @@ -48,6 +48,7 @@ export const createRecurringTask = async ({ network_folders: [], }, }, + llm_provider: llmProvider, message: { job_id: jobId, content: message, From 1ae93279827b2c2300f11c8be7368288f8a3deb2 Mon Sep 17 00:00:00 2001 From: paulclindo Date: Wed, 18 Dec 2024 00:12:36 -0500 Subject: [PATCH 4/5] feat: improve cron tasks --- apps/shinkai-desktop/src/pages/task-logs.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/shinkai-desktop/src/pages/task-logs.tsx b/apps/shinkai-desktop/src/pages/task-logs.tsx index e79c2df51..f6dc87006 100644 --- a/apps/shinkai-desktop/src/pages/task-logs.tsx +++ b/apps/shinkai-desktop/src/pages/task-logs.tsx @@ -31,8 +31,8 @@ import { Bot, CheckCircle2, Clock, - Code2, Edit, + Sparkles, TrashIcon, XCircle, } from 'lucide-react'; @@ -286,7 +286,7 @@ const TaskCard = ({
- + Prompt
{prompt}
From 28fdc0e209fc95bc8f0395c9827bfb59b5675efd Mon Sep 17 00:00:00 2001 From: paulclindo Date: Wed, 18 Dec 2024 00:16:39 -0500 Subject: [PATCH 5/5] fix types --- .../src/v2/mutations/updateRecurringTask/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/shinkai-node-state/src/v2/mutations/updateRecurringTask/index.ts b/libs/shinkai-node-state/src/v2/mutations/updateRecurringTask/index.ts index a6c27e4db..045ef37ae 100644 --- a/libs/shinkai-node-state/src/v2/mutations/updateRecurringTask/index.ts +++ b/libs/shinkai-node-state/src/v2/mutations/updateRecurringTask/index.ts @@ -34,6 +34,7 @@ export const updateRecurringTask = async ({ network_folders: [], }, }, + llm_provider: llmProvider, message: { job_id: jobId, content: message,