From 8bfa236c1f86f983fe43eecab2f6035e2b281a68 Mon Sep 17 00:00:00 2001 From: Alfredo Gallardo Date: Wed, 11 Oct 2023 08:39:47 -0500 Subject: [PATCH 1/6] - fix: removed unused resources --- apps/shinkai-visor/public/manifest.json | 2 +- .../src/components/popup/popup.html | 15 -- .../src/store/agents/agents-actions.ts | 82 --------- .../src/store/agents/agents-reducer.ts | 50 ------ .../src/store/agents/agents-types.ts | 12 -- .../src/store/auth/auth-actions.ts | 3 - .../src/store/auth/auth-reducer.ts | 15 -- .../src/store/auth/auth-types.ts | 3 - .../src/store/inbox/inbox-actions.ts | 163 ------------------ .../src/store/inbox/inbox-reducer.ts | 135 --------------- .../src/store/inbox/inbox-types.ts | 21 --- apps/shinkai-visor/src/store/index.ts | 64 ------- .../src/store/jobs/jobs-actions.ts | 65 ------- .../src/store/jobs/jobs-reducer.ts | 30 ---- .../src/store/jobs/jobs-types.ts | 9 - .../src/store/node/node-actions.ts | 46 ----- .../src/store/node/node-reducer.ts | 30 ---- .../src/store/node/node-types.ts | 31 ---- 18 files changed, 1 insertion(+), 775 deletions(-) delete mode 100644 apps/shinkai-visor/src/components/popup/popup.html delete mode 100644 apps/shinkai-visor/src/store/agents/agents-actions.ts delete mode 100644 apps/shinkai-visor/src/store/agents/agents-reducer.ts delete mode 100644 apps/shinkai-visor/src/store/agents/agents-types.ts delete mode 100644 apps/shinkai-visor/src/store/auth/auth-actions.ts delete mode 100644 apps/shinkai-visor/src/store/auth/auth-reducer.ts delete mode 100644 apps/shinkai-visor/src/store/auth/auth-types.ts delete mode 100644 apps/shinkai-visor/src/store/inbox/inbox-actions.ts delete mode 100644 apps/shinkai-visor/src/store/inbox/inbox-reducer.ts delete mode 100644 apps/shinkai-visor/src/store/inbox/inbox-types.ts delete mode 100644 apps/shinkai-visor/src/store/index.ts delete mode 100644 apps/shinkai-visor/src/store/jobs/jobs-actions.ts delete mode 100644 apps/shinkai-visor/src/store/jobs/jobs-reducer.ts delete mode 100644 apps/shinkai-visor/src/store/jobs/jobs-types.ts delete mode 100644 apps/shinkai-visor/src/store/node/node-actions.ts delete mode 100644 apps/shinkai-visor/src/store/node/node-reducer.ts delete mode 100644 apps/shinkai-visor/src/store/node/node-types.ts diff --git a/apps/shinkai-visor/public/manifest.json b/apps/shinkai-visor/public/manifest.json index 9d54d42f7..d5ff606c4 100644 --- a/apps/shinkai-visor/public/manifest.json +++ b/apps/shinkai-visor/public/manifest.json @@ -15,7 +15,7 @@ "16": "icon16.png", "48": "icon48.png" }, - "default_popup": "src/components/popup/popup.html" + "default_popup": "" }, "background": { "service_worker": "src/service-worker/service-worker.ts" diff --git a/apps/shinkai-visor/src/components/popup/popup.html b/apps/shinkai-visor/src/components/popup/popup.html deleted file mode 100644 index 60f8a7f11..000000000 --- a/apps/shinkai-visor/src/components/popup/popup.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - Shinkai Visor - - - - - - -
- - - diff --git a/apps/shinkai-visor/src/store/agents/agents-actions.ts b/apps/shinkai-visor/src/store/agents/agents-actions.ts deleted file mode 100644 index c7dd6593a..000000000 --- a/apps/shinkai-visor/src/store/agents/agents-actions.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { createAsyncThunk } from '@reduxjs/toolkit'; -import { - addAgent as addAgentApi, - ApiConfig, - getProfileAgents, -} from '@shinkai_network/shinkai-message-ts/api'; -import { - AgentAPIModel, - SerializedAgent, -} from '@shinkai_network/shinkai-message-ts/models'; -import { extractReceiverShinkaiName } from '@shinkai_network/shinkai-message-ts/utils'; - -import { RootState } from '..'; - -export const addAgent = createAsyncThunk< - { agent: SerializedAgent }, - { - agent: { - agentName: string; - externalUrl: string; - apiKey: string; - model: AgentAPIModel; - }; - } ->('agents/add', async (args, { getState }) => { - const state = getState() as RootState; - const node = state.node.data; - if (!node) throw new Error('missing node data'); - - ApiConfig.getInstance().setEndpoint(node.nodeData.nodeAddress); - - const result = await addAgentApi( - node.nodeData.profile, - node.nodeData.shinkaiIdentity, - { - id: args.agent.agentName, - full_identity_name: `${node.nodeData.shinkaiIdentity}/${node.nodeData.profile}/agent/${args.agent.agentName}`, - perform_locally: false, - toolkit_permissions: [], - storage_bucket_permissions: [], - allowed_message_senders: [], - external_url: args.agent.externalUrl, - api_key: args.agent.apiKey, - model: args.agent.model, - }, - { - my_device_encryption_sk: node.credentials.myDeviceEncryptionSharedKey, - my_device_identity_sk: node.credentials.myDeviceIdentitySharedKey, - node_encryption_pk: node.nodeData.nodeEncryptionPublicKey, - profile_encryption_sk: node.credentials.profileEncryptionSharedKey, - profile_identity_sk: node.credentials.profileSignatureSharedKey, - } - ); - return { agent: result }; -}); - -export const getAgents = createAsyncThunk<{ agents: SerializedAgent[] }, void>( - 'agents/all', - async (args, { getState }) => { - const state = getState() as RootState; - const node = state.node.data; - if (!node) throw new Error('missing node data'); - - ApiConfig.getInstance().setEndpoint(node.nodeData.nodeAddress); - const sender = node.nodeData.shinkaiIdentity; - const senderSubidentity = `${node.nodeData.profile}`; - - const result = await getProfileAgents( - sender + '/' + senderSubidentity, - '', - node.nodeData.shinkaiIdentity, - { - my_device_encryption_sk: node.credentials.myDeviceEncryptionSharedKey, - my_device_identity_sk: node.credentials.myDeviceIdentitySharedKey, - profile_encryption_sk: node.credentials.profileEncryptionSharedKey, - profile_identity_sk: node.credentials.profileSignatureSharedKey, - node_encryption_pk: node.nodeData.nodeEncryptionPublicKey, - } - ); - return { agents: result }; - } -); diff --git a/apps/shinkai-visor/src/store/agents/agents-reducer.ts b/apps/shinkai-visor/src/store/agents/agents-reducer.ts deleted file mode 100644 index 1b188e5b8..000000000 --- a/apps/shinkai-visor/src/store/agents/agents-reducer.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; - -import { addAgent, getAgents } from './agents-actions'; -import { AgentsState } from './agents-types'; - -const initialState: AgentsState = { - agents: { - status: 'idle', - }, - add: { - status: 'idle', - }, -}; - -export const agentsSlice = createSlice({ - name: 'agents', - initialState, - reducers: {}, - extraReducers(builder) { - builder - .addCase(addAgent.pending, (state, action) => { - state.add.status = 'loading'; - }) - .addCase(addAgent.fulfilled, (state, action) => { - state.add.status = 'succeeded'; - state.add.data = action.payload; - state.agents.data = [ - ...(state.agents.data || []), - action.payload.agent, - ]; - }) - .addCase(addAgent.rejected, (state, action) => { - state.add.status = 'failed'; - state.add.error = action.error.message; - }); - - builder - .addCase(getAgents.pending, (state, action) => { - state.agents.status = 'loading'; - }) - .addCase(getAgents.fulfilled, (state, action) => { - state.agents.status = 'succeeded'; - state.agents.data = action.payload.agents; - }) - .addCase(getAgents.rejected, (state, action) => { - state.agents.status = 'failed'; - state.agents.error = action.error.message; - }); - }, -}); diff --git a/apps/shinkai-visor/src/store/agents/agents-types.ts b/apps/shinkai-visor/src/store/agents/agents-types.ts deleted file mode 100644 index 707386192..000000000 --- a/apps/shinkai-visor/src/store/agents/agents-types.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { SerializedAgent } from "@shinkai_network/shinkai-message-ts/models"; - -import { AsyncData } from "../helpers/async-data"; - -export type Inbox = { - id: string; -}; - -export interface AgentsState { - agents: AsyncData, - add: AsyncData<{ agent: SerializedAgent }>, -} diff --git a/apps/shinkai-visor/src/store/auth/auth-actions.ts b/apps/shinkai-visor/src/store/auth/auth-actions.ts deleted file mode 100644 index ffa57c902..000000000 --- a/apps/shinkai-visor/src/store/auth/auth-actions.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { createAction } from '@reduxjs/toolkit'; - -export const authenticated = createAction('auth/authenticated'); diff --git a/apps/shinkai-visor/src/store/auth/auth-reducer.ts b/apps/shinkai-visor/src/store/auth/auth-reducer.ts deleted file mode 100644 index a3e3dc95a..000000000 --- a/apps/shinkai-visor/src/store/auth/auth-reducer.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; - -import { AuthStore } from './auth-types'; - -export const authSlice = createSlice({ - name: 'auth', - initialState: { - status: 'unauthenticated', - } as AuthStore, - reducers: { - authenticated: (state, action) => { - state.status = action.payload ? 'authenticated' : 'unauthenticated'; - }, - }, -}); diff --git a/apps/shinkai-visor/src/store/auth/auth-types.ts b/apps/shinkai-visor/src/store/auth/auth-types.ts deleted file mode 100644 index 50c15f53f..000000000 --- a/apps/shinkai-visor/src/store/auth/auth-types.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface AuthStore { - status: 'authenticated' | 'unauthenticated', -} diff --git a/apps/shinkai-visor/src/store/inbox/inbox-actions.ts b/apps/shinkai-visor/src/store/inbox/inbox-actions.ts deleted file mode 100644 index 6eafb372b..000000000 --- a/apps/shinkai-visor/src/store/inbox/inbox-actions.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { createAsyncThunk } from '@reduxjs/toolkit'; -import { - ApiConfig, - createChatWithMessage, - getAllInboxesForProfile, - getLastMessagesFromInbox, - sendMessageToJob, - sendTextMessageWithInbox, -} from '@shinkai_network/shinkai-message-ts/api'; -import { ShinkaiMessage } from '@shinkai_network/shinkai-message-ts/models'; -import { - extractJobIdFromInbox, - extractReceiverShinkaiName, - isJobInbox, -} from '@shinkai_network/shinkai-message-ts/utils'; - -import { RootState } from '..'; -import { Inbox } from './inbox-types'; - -export const getAllInboxes = createAsyncThunk( - 'inbox/all', - async (_, { getState }) => { - const state = getState() as RootState; - const node = state.node.data; - if (!node) throw new Error('missing node data'); - - ApiConfig.getInstance().setEndpoint(node.nodeData.nodeAddress); - - // Local identity - const sender = node?.nodeData.shinkaiIdentity; - const senderSubidentity = `${node.nodeData.profile}/device/${node?.userData.registrationName}`; - - // Assuming receiver and target_shinkai_name_profile are the same as sender - const receiver = sender; - const targetShinkaiNameProfile = `${sender}/${node.nodeData.profile}`; - - // TODO: Improve this async call to be react friendly - const inboxes = await getAllInboxesForProfile( - sender, - senderSubidentity, - receiver, - targetShinkaiNameProfile, - { - my_device_encryption_sk: node.credentials.myDeviceEncryptionSharedKey, - my_device_identity_sk: node.credentials.myDeviceIdentitySharedKey, - profile_encryption_sk: node.credentials.profileEncryptionSharedKey, - profile_identity_sk: node.credentials.profileSignatureSharedKey, - node_encryption_pk: node.nodeData.nodeEncryptionPublicKey, - } - ); - return inboxes.map((inboxId) => ({ id: inboxId })); - } -); - -export const createInbox = createAsyncThunk< - { inbox: Inbox; message: ShinkaiMessage }, - { receiverIdentity: string; message: string } ->('inbox/create', async (args, { getState }) => { - const state = getState() as RootState; - const node = state.node.data; - if (!node) throw new Error('missing node data'); - - ApiConfig.getInstance().setEndpoint(node.nodeData.nodeAddress); - - const [receiver, ...rest] = args.receiverIdentity.split('/'); - // Join the rest back together to form sender_subidentity - const receiverSubIdentity = rest.join('/'); - - const sender = node.nodeData.shinkaiIdentity; - const senderSubidentity = `${node.nodeData.profile}/device/${node.userData.registrationName}`; - - // Send a message to someone - const { inboxId, message } = await createChatWithMessage( - sender, - senderSubidentity, - receiver, - receiverSubIdentity, - args.message, - { - my_device_encryption_sk: node.credentials.myDeviceEncryptionSharedKey, - my_device_identity_sk: node.credentials.myDeviceIdentitySharedKey, - node_encryption_pk: node.nodeData.nodeEncryptionPublicKey, - } - ); - return { inbox: { id: inboxId }, message }; -}); - -export const getLastsMessagesForInbox = createAsyncThunk< - { inboxId: string; messages: ShinkaiMessage[] }, - { inboxId: string; count?: number | undefined; lastKey?: string | undefined } ->('inbox/messages/get-last-messages-for-inbox', async (args, { getState }) => { - const defaultMessageCount = 10; - const state = getState() as RootState; - const node = state.node.data; - if (!node) throw new Error('missing node data'); - - ApiConfig.getInstance().setEndpoint(node.nodeData.nodeAddress); - - const data: ShinkaiMessage[] = await getLastMessagesFromInbox( - args.inboxId, - args.count || defaultMessageCount, - args.lastKey, - { - shinkai_identity: node.nodeData.shinkaiIdentity, - profile: node.nodeData.profile, - profile_encryption_sk: node.credentials.profileEncryptionSharedKey, - profile_identity_sk: node.credentials.profileSignatureSharedKey, - node_encryption_pk: node.nodeData.nodeEncryptionPublicKey, - } - ); - return { inboxId: args.inboxId, messages: data }; -}); - -export const sendMessage = createAsyncThunk< - { inbox: Inbox; message?: ShinkaiMessage }, - { inboxId: string; message: string } ->('inbox/messages/send', async (args, { getState }) => { - const state = getState() as RootState; - const node = state.node.data; - if (!node) throw new Error('missing node data'); - - ApiConfig.getInstance().setEndpoint(node.nodeData.nodeAddress); - - if (isJobInbox(args.inboxId)) { - const jobId = extractJobIdFromInbox(args.inboxId); - await sendMessageToJob( - jobId, - args.message, - '', - node.nodeData.shinkaiIdentity, - node.nodeData.profile, - node.nodeData.shinkaiIdentity, - '', - { - my_device_encryption_sk: node.credentials.myDeviceEncryptionSharedKey, - my_device_identity_sk: node.credentials.myDeviceIdentitySharedKey, - node_encryption_pk: node.nodeData.nodeEncryptionPublicKey, - profile_encryption_sk: node.credentials.profileEncryptionSharedKey, - profile_identity_sk: node.credentials.profileSignatureSharedKey, - } - ); - // TODO: jobs didn't reply with the shinkai message you sent. fix it - return { inbox: { id: args.inboxId }, message: undefined }; - } - - const sender = `${node.nodeData.shinkaiIdentity}/${node.nodeData.profile}/device/${node.userData.registrationName}`; - const receiver = extractReceiverShinkaiName(args.inboxId, sender); - const { inboxId, message } = await sendTextMessageWithInbox( - sender, - '', - receiver, - args.message, - args.inboxId, - { - my_device_encryption_sk: node.credentials.myDeviceEncryptionSharedKey, - my_device_identity_sk: node.credentials.myDeviceIdentitySharedKey, - profile_encryption_sk: node.credentials.profileEncryptionSharedKey, - profile_identity_sk: node.credentials.profileSignatureSharedKey, - node_encryption_pk: node.nodeData.nodeEncryptionPublicKey, - } - ); - return { inbox: { id: inboxId }, message }; -}); diff --git a/apps/shinkai-visor/src/store/inbox/inbox-reducer.ts b/apps/shinkai-visor/src/store/inbox/inbox-reducer.ts deleted file mode 100644 index 3e0f1db79..000000000 --- a/apps/shinkai-visor/src/store/inbox/inbox-reducer.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { ShinkaiMessage } from '@shinkai_network/shinkai-message-ts/models'; -import { calculateMessageHash } from '@shinkai_network/shinkai-message-ts/utils'; - -import { - createInbox, - getAllInboxes, - getLastsMessagesForInbox, - sendMessage, -} from './inbox-actions'; -import { InboxState } from './inbox-types'; - -const initialState: InboxState = { - all: { - status: 'idle', - }, - create: { - status: 'idle', - }, - messages: {}, - messagesHashes: {}, - sendMessage: {}, -}; - -export const inboxSlice = createSlice({ - name: 'inbox', - initialState, - reducers: {}, - extraReducers(builder) { - builder - .addCase(getAllInboxes.pending, (state, action) => { - state.all.status = 'loading'; - }) - .addCase(getAllInboxes.fulfilled, (state, action) => { - state.all.status = 'succeeded'; - state.all.data = action.payload; - }) - .addCase(getAllInboxes.rejected, (state, action) => { - state.all.status = 'failed'; - state.all.error = action.error.message; - }); - - builder - .addCase(createInbox.pending, (state, action) => { - state.create.status = 'loading'; - }) - .addCase(createInbox.fulfilled, (state, action) => { - state.create.status = 'succeeded'; - state.create.data = action.payload; - state.all.data = [...(state.all.data || []), action.payload.inbox]; - }) - .addCase(createInbox.rejected, (state, action) => { - state.create.status = 'failed'; - state.create.error = action.error.message; - }); - - builder - .addCase(getLastsMessagesForInbox.pending, (state, action) => { - state.messages[action.meta.arg.inboxId] = { - ...state.messages[action.meta.arg.inboxId], - status: 'loading', - }; - }) - .addCase(getLastsMessagesForInbox.fulfilled, (state, action) => { - state.messages[action.meta.arg.inboxId] = { - ...state.messages[action.meta.arg.inboxId], - status: 'succeeded', - }; - const inboxId = action.payload.inboxId; - const currentMessages = state.messages[inboxId]?.data || []; - const currentMessagesHashes = state.messagesHashes[inboxId] || {}; - const newMessages = action.payload.messages.filter( - (msg: ShinkaiMessage) => { - const hash = calculateMessageHash(msg); - if (currentMessagesHashes[hash]) { - return false; - } else { - currentMessagesHashes[hash] = true; - return true; - } - } - ); - state.messages[inboxId].data = [...currentMessages, ...newMessages]; - state.messagesHashes[inboxId] = currentMessagesHashes; - }) - .addCase(getLastsMessagesForInbox.rejected, (state, action) => { - state.messages[action.meta.arg.inboxId] = { - ...state.messages[action.meta.arg.inboxId], - status: 'failed', - error: action.error.message, - }; - }); - - builder - .addCase(sendMessage.pending, (state, action) => { - state.sendMessage[action.meta.arg.inboxId] = { - ...state.sendMessage[action.meta.arg.inboxId], - status: 'loading', - }; - }) - .addCase(sendMessage.fulfilled, (state, action) => { - state.sendMessage[action.meta.arg.inboxId] = { - ...state.sendMessage[action.meta.arg.inboxId], - status: 'succeeded', - }; - // At this moment, jobs message response is just a string - if (!action.payload.message) { - return; - } - const inboxId = action.payload.inbox.id; - const currentMessages = state.messages[inboxId]?.data || []; - const currentMessagesHashes = state.messagesHashes[inboxId] || {}; - const newMessages = [action.payload.message].filter( - (msg: ShinkaiMessage) => { - const hash = calculateMessageHash(msg); - if (currentMessagesHashes[hash]) { - return false; - } else { - currentMessagesHashes[hash] = true; - return true; - } - } - ); - state.messages[inboxId].data = [...currentMessages, ...newMessages]; - state.messagesHashes[inboxId] = currentMessagesHashes; - }) - .addCase(sendMessage.rejected, (state, action) => { - state.sendMessage[action.meta.arg.inboxId] = { - ...state.sendMessage[action.meta.arg.inboxId], - status: 'failed', - error: action.error.message, - }; - }); - }, -}); diff --git a/apps/shinkai-visor/src/store/inbox/inbox-types.ts b/apps/shinkai-visor/src/store/inbox/inbox-types.ts deleted file mode 100644 index 4e8472138..000000000 --- a/apps/shinkai-visor/src/store/inbox/inbox-types.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { ShinkaiMessage } from "@shinkai_network/shinkai-message-ts/models"; - -import { AsyncData } from "../helpers/async-data"; - -export type Inbox = { - id: string; -}; - -export interface InboxState { - all: AsyncData, - create: AsyncData<{ inbox: Inbox }>, - messages: { - [inboxId: string]: AsyncData, - }, - messagesHashes: { - [inboxId: string]: { [messageHask: string]: boolean }, - }, - sendMessage: { - [inboxId: string]: AsyncData<{ text: string }>, - }, -} diff --git a/apps/shinkai-visor/src/store/index.ts b/apps/shinkai-visor/src/store/index.ts deleted file mode 100644 index 456f89f59..000000000 --- a/apps/shinkai-visor/src/store/index.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { combineReducers, configureStore } from '@reduxjs/toolkit'; -import { useDispatch } from 'react-redux'; -import { - FLUSH, - PAUSE, - PERSIST, - persistReducer, - persistStore, - PURGE, - REGISTER, - REHYDRATE, -} from 'redux-persist'; -import localStorage from 'redux-persist/es/storage'; - -import * as agentsActions from './agents/agents-actions'; -import { agentsSlice } from './agents/agents-reducer'; -import * as authActions from './auth/auth-actions'; -import { authSlice } from './auth/auth-reducer'; -import { inboxSlice } from './inbox/inbox-reducer'; -import * as jobsActions from './jobs/jobs-actions'; -import { jobsSlice } from './jobs/jobs-reducer'; -import * as nodeActions from './node/node-actions'; -import { nodeSlice } from './node/node-reducer'; -import { ChromeStorage } from './persistor/chrome-storage'; - -const reducer = combineReducers({ - node: nodeSlice.reducer, - auth: authSlice.reducer, - inbox: inboxSlice.reducer, - agents: agentsSlice.reducer, - jobs: jobsSlice.reducer, -}); - -const persistedReducer = persistReducer( - { - key: 'root', - storage: chrome?.runtime ? new ChromeStorage('local') : localStorage, - whitelist: ['node', 'auth'] - }, - reducer -); - -export const store = configureStore({ - reducer: persistedReducer, - middleware: (getDefaultMiddleware) => - getDefaultMiddleware({ - serializableCheck: { - ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], - }, - }), -}); - -export const storePersistor = persistStore(store); - -export const actions = { - ...nodeActions, - ...authActions, - ...agentsActions, - ...jobsActions, -}; - -export type RootState = ReturnType; - -export const useTypedDispatch = () => useDispatch(); diff --git a/apps/shinkai-visor/src/store/jobs/jobs-actions.ts b/apps/shinkai-visor/src/store/jobs/jobs-actions.ts deleted file mode 100644 index 0fa84efde..000000000 --- a/apps/shinkai-visor/src/store/jobs/jobs-actions.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { createAsyncThunk } from '@reduxjs/toolkit'; -import { - ApiConfig, - createJob as createJobApi, - sendMessageToJob, -} from '@shinkai_network/shinkai-message-ts/api'; -import { JobCreationWrapper,JobScopeWrapper } from "@shinkai_network/shinkai-message-ts/wasm"; - -import { RootState } from '..'; -import { Job } from './jobs-types'; - -export const createJob = createAsyncThunk< - { job: Job }, - { - agentId: string, - content: string, - } ->('jobs/create', async (args, { getState }) => { - const state = getState() as RootState; - const node = state.node.data; - if (!node) throw new Error('missing node data'); - - ApiConfig.getInstance().setEndpoint(node.nodeData.nodeAddress); - - const receiver_subidentity = `${node.nodeData.profile}/agent/${args.agentId}`; - - const job_creation = JobCreationWrapper.empty().get_scope; - const scope = new JobScopeWrapper( - job_creation.buckets, - job_creation.documents - ); - - const jobId = await createJobApi( - scope.to_jsvalue(), - node.nodeData.shinkaiIdentity, - node.nodeData.profile, - node.nodeData.shinkaiIdentity, - receiver_subidentity, - { - my_device_encryption_sk: node.credentials.myDeviceEncryptionSharedKey, - my_device_identity_sk: node.credentials.myDeviceIdentitySharedKey, - node_encryption_pk: node.nodeData.nodeEncryptionPublicKey, - profile_encryption_sk: node.credentials.profileEncryptionSharedKey, - profile_identity_sk: node.credentials.profileSignatureSharedKey, - } - ); - - await sendMessageToJob( - jobId, - args.content, - '', - node.nodeData.shinkaiIdentity, - node.nodeData.profile, - node.nodeData.shinkaiIdentity, - receiver_subidentity, - { - my_device_encryption_sk: node.credentials.myDeviceEncryptionSharedKey, - my_device_identity_sk: node.credentials.myDeviceIdentitySharedKey, - node_encryption_pk: node.nodeData.nodeEncryptionPublicKey, - profile_encryption_sk: node.credentials.profileEncryptionSharedKey, - profile_identity_sk: node.credentials.profileSignatureSharedKey, - } - ); - return { job: { id: jobId } }; -}); diff --git a/apps/shinkai-visor/src/store/jobs/jobs-reducer.ts b/apps/shinkai-visor/src/store/jobs/jobs-reducer.ts deleted file mode 100644 index bee4682bc..000000000 --- a/apps/shinkai-visor/src/store/jobs/jobs-reducer.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; - -import { createJob } from './jobs-actions'; -import { JobsState } from './jobs-types'; - -const initialState: JobsState = { - create: { - status: 'idle', - }, -}; - -export const jobsSlice = createSlice({ - name: 'jobs', - initialState, - reducers: {}, - extraReducers(builder) { - builder - .addCase(createJob.pending, (state, action) => { - state.create.status = 'loading'; - }) - .addCase(createJob.fulfilled, (state, action) => { - state.create.status = 'succeeded'; - state.create.data = action.payload; - }) - .addCase(createJob.rejected, (state, action) => { - state.create.status = 'failed'; - state.create.error = action.error.message; - }); - }, -}); diff --git a/apps/shinkai-visor/src/store/jobs/jobs-types.ts b/apps/shinkai-visor/src/store/jobs/jobs-types.ts deleted file mode 100644 index 9395f8602..000000000 --- a/apps/shinkai-visor/src/store/jobs/jobs-types.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { AsyncData } from "../helpers/async-data"; - -export type Job = { - id: string; -}; - -export interface JobsState { - create: AsyncData<{ job: Job }>, -} diff --git a/apps/shinkai-visor/src/store/node/node-actions.ts b/apps/shinkai-visor/src/store/node/node-actions.ts deleted file mode 100644 index c284726be..000000000 --- a/apps/shinkai-visor/src/store/node/node-actions.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { createAsyncThunk } from '@reduxjs/toolkit'; -import { submitRegistrationCode } from '@shinkai_network/shinkai-message-ts/api'; - -import { authenticated } from '../auth/auth-actions'; -import { NodeConnectionData } from './node-types'; - -export const connectNode = createAsyncThunk( - 'node/connect', - async (nodeConnectPayload, { dispatch }) => { - const success = await submitRegistrationCode({ - // Node data - registration_code: nodeConnectPayload.nodeData.registrationCode, - identity_type: nodeConnectPayload.nodeData.identityType, - permission_type: nodeConnectPayload.nodeData.permissionType, - profile: nodeConnectPayload.nodeData.profile, - shinkai_identity: nodeConnectPayload.nodeData.identityType, - node_address: nodeConnectPayload.nodeData.nodeAddress, - - // User device / profile data - registration_name: nodeConnectPayload.userData.registrationName, - - // User keypairs - my_device_encryption_sk: - nodeConnectPayload.credentials.myDeviceEncryptionSharedKey, - my_device_identity_sk: - nodeConnectPayload.credentials.myDeviceIdentitySharedKey, - profile_encryption_sk: - nodeConnectPayload.credentials.profileEncryptionSharedKey, - profile_identity_sk: - nodeConnectPayload.credentials.profileSignatureSharedKey, - node_encryption_pk: nodeConnectPayload.nodeData.nodeEncryptionPublicKey, - }); - if (success) { - dispatch(authenticated(true)); - return nodeConnectPayload; - } - throw new Error('unknown'); - } -); - -export const disconnectNode = createAsyncThunk( - 'node/disconnect', - async (_, { dispatch }) => { - dispatch(authenticated(false)); - } -); diff --git a/apps/shinkai-visor/src/store/node/node-reducer.ts b/apps/shinkai-visor/src/store/node/node-reducer.ts deleted file mode 100644 index 557349c13..000000000 --- a/apps/shinkai-visor/src/store/node/node-reducer.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { createSlice } from "@reduxjs/toolkit"; - -import { connectNode } from "./node-actions"; -import { NodeStore } from "./node-types"; - -const initialState: NodeStore = { - status: 'idle', - error: undefined, - data: undefined, -} - -export const nodeSlice = createSlice({ - name: 'node', - initialState, - reducers: {}, - extraReducers(builder) { - builder - .addCase(connectNode.pending, (state, action) => { - state.status = 'loading' - }) - .addCase(connectNode.fulfilled, (state, action) => { - state.status = 'succeeded'; - state.data = action.payload; - }) - .addCase(connectNode.rejected, (state, action) => { - state.status = 'failed' - state.error = action.error.message; - }) - } -}); diff --git a/apps/shinkai-visor/src/store/node/node-types.ts b/apps/shinkai-visor/src/store/node/node-types.ts deleted file mode 100644 index 1bbd780e1..000000000 --- a/apps/shinkai-visor/src/store/node/node-types.ts +++ /dev/null @@ -1,31 +0,0 @@ -export type NodeConnectionData = { - nodeData: { - registrationCode: string; - permissionType: 'admin'; - identityType: 'device'; - profile: 'main'; - nodeAddress: string; - shinkaiIdentity: string; - nodeEncryptionPublicKey: string; - nodeSignaturePublicKey: string; - }; - userData: { - registrationName: string; - }; - credentials: { - profileEncryptionPublicKey: string; - profileSignaturePublicKey: string; - myDeviceEncryptionPublicKey: string; - myDeviceIdentityPublicKey: string; - profileEncryptionSharedKey: string; - profileSignatureSharedKey: string; - myDeviceEncryptionSharedKey: string; - myDeviceIdentitySharedKey: string; - }; -}; - -export interface NodeStore { - status: 'idle' | 'loading' | 'succeeded' | 'failed'; - error: string | undefined; - data: NodeConnectionData | undefined; -} From 25a31002542f0f1147819425b0eaec43cb4a81d5 Mon Sep 17 00:00:00 2001 From: Alfredo Gallardo Date: Wed, 11 Oct 2023 08:44:24 -0500 Subject: [PATCH 2/6] - feature: Added send page to agent --- apps/shinkai-visor/public/manifest.json | 3 +- .../action-button/action-button.tsx | 38 ++-- .../src/components/add-agent/add-agent.tsx | 39 ++-- .../src/components/create-job/create-job.tsx | 32 +++- apps/shinkai-visor/src/components/nav/nav.tsx | 132 +++++++------- .../src/components/popup/popup.tsx | 139 +++++++++++--- .../src/components/ui/dropdown-menu.tsx | 4 +- .../src/components/ui/select.tsx | 7 +- .../src/helpers/pdf-generator.ts | 30 ++++ ...use-global-action-button-chrome-message.ts | 5 +- .../hooks/use-global-popup-chrome-message.ts | 13 +- .../service-worker-message-type.ts | 2 + .../communication/service-worker-messages.ts | 14 +- .../src/service-worker/context-menu.ts | 25 ++- .../src/store/ui-container/ui-container.ts | 24 +++ apps/shinkai-visor/src/theme/styles.css | 4 +- .../src/lib/mutations/createJob/index.ts | 54 ++++-- .../src/lib/mutations/createJob/types.ts | 1 + .../lib/mutations/sendTextMessage/index.ts | 25 ++- .../lib/mutations/sendTextMessage/types.ts | 8 + .../useSendMessageWithFilesToInbox.ts | 14 ++ package-lock.json | 169 +++++++++++++++++- package.json | 1 + 23 files changed, 597 insertions(+), 186 deletions(-) create mode 100644 apps/shinkai-visor/src/helpers/pdf-generator.ts create mode 100644 apps/shinkai-visor/src/store/ui-container/ui-container.ts create mode 100644 libs/shinkai-node-state/src/lib/mutations/sendTextMessage/useSendMessageWithFilesToInbox.ts diff --git a/apps/shinkai-visor/public/manifest.json b/apps/shinkai-visor/public/manifest.json index d5ff606c4..118709b85 100644 --- a/apps/shinkai-visor/public/manifest.json +++ b/apps/shinkai-visor/public/manifest.json @@ -37,7 +37,8 @@ "description": "Open/Close Shinkai popup" } }, - "permissions": ["storage", "contextMenus"], + "permissions": ["storage", "contextMenus", "offscreen", "scripting"], + "host_permissions": [""], "content_security_policy": { "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';" }, diff --git a/apps/shinkai-visor/src/components/action-button/action-button.tsx b/apps/shinkai-visor/src/components/action-button/action-button.tsx index a4b969141..be6bcba1d 100644 --- a/apps/shinkai-visor/src/components/action-button/action-button.tsx +++ b/apps/shinkai-visor/src/components/action-button/action-button.tsx @@ -2,8 +2,6 @@ import { motion } from 'framer-motion'; import * as React from 'react'; import { createRoot } from 'react-dom/client'; import { IntlProvider } from 'react-intl'; -import { Provider } from 'react-redux'; -import { PersistGate } from 'redux-persist/integration/react'; import shinkaiLogo from '../../assets/icons/shinkai-min.svg'; import { cn } from '../../helpers/cn-utils'; @@ -12,21 +10,16 @@ import { useGlobalActionButtonChromeMessage } from '../../hooks/use-global-actio import { langMessages, locale } from '../../lang/intl'; import { ContentScriptMessageType } from '../../service-worker/communication/content-script-message-type'; import { sendContentScriptMessage } from '../../service-worker/communication/content-script-messages'; -import { store, storePersistor } from '../../store'; import themeStyle from '../../theme/styles.css?inline'; import popupStyle from './action-button.css?inline'; -let container = document.getElementById('shinkai-action-button-root'); -let shadow: ShadowRoot | undefined = undefined; -if (!container) { - const baseContainer = document.createElement('shinkai-action-button-root'); - shadow = baseContainer.attachShadow({ mode: 'open' }); - container = document.createElement('div'); - container.id = 'shinkai-action-button-root'; - shadow.appendChild(container); - const htmlRoot = document.getElementsByTagName('html')[0]; - htmlRoot.prepend(baseContainer); -} +const baseContainer = document.createElement('shinkai-action-button-root'); +const shadow = baseContainer.attachShadow({ mode: 'open' }); +const container = document.createElement('div'); +container.id = 'root'; +shadow.appendChild(container); +const htmlRoot = document.getElementsByTagName('html')[0]; +htmlRoot.prepend(baseContainer); export const ActionButton = () => { const [popupVisibility] = useGlobalActionButtonChromeMessage(); @@ -51,7 +44,7 @@ export const ActionButton = () => { > shinkai-app-logo @@ -59,20 +52,15 @@ export const ActionButton = () => { ); }; - const root = createRoot(container); root.render( - - - -
- -
-
-
-
+ +
+ +
+
); diff --git a/apps/shinkai-visor/src/components/add-agent/add-agent.tsx b/apps/shinkai-visor/src/components/add-agent/add-agent.tsx index 312595570..033d82545 100644 --- a/apps/shinkai-visor/src/components/add-agent/add-agent.tsx +++ b/apps/shinkai-visor/src/components/add-agent/add-agent.tsx @@ -1,5 +1,5 @@ import { zodResolver } from '@hookform/resolvers/zod'; -import { useCreateAgent } from "@shinkai_network/shinkai-node-state/lib/mutations/createAgent/useCreateAgent"; +import { useCreateAgent } from '@shinkai_network/shinkai-node-state/lib/mutations/createAgent/useCreateAgent'; import { Loader2 } from 'lucide-react'; import { useForm } from 'react-hook-form'; import { FormattedMessage, useIntl } from 'react-intl'; @@ -7,6 +7,7 @@ import { useHistory } from 'react-router-dom'; import { z } from 'zod'; import { useAuth } from '../../store/auth/auth'; +import { useUIContainer } from '../../store/ui-container/ui-container'; import { Button } from '../ui/button'; import { Form, @@ -21,6 +22,7 @@ import { Select, SelectContent, SelectItem, + SelectPortal, SelectTrigger, SelectValue, } from '../ui/select'; @@ -42,6 +44,7 @@ type FormSchemaType = z.infer; export const AddAgent = () => { const history = useHistory(); const auth = useAuth((state) => state.auth); + const uiContainer = useUIContainer((state) => state.uiContainer); const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { @@ -52,10 +55,7 @@ export const AddAgent = () => { }, }); const intl = useIntl(); - const { - mutateAsync: createAgent, - isLoading, - } = useCreateAgent({ + const { mutateAsync: createAgent, isLoading } = useCreateAgent({ onSuccess: (data) => { history.replace({ pathname: '/inboxes/create-job' }); }, @@ -85,9 +85,10 @@ export const AddAgent = () => { perform_locally: false, storage_bucket_permissions: [], toolkit_permissions: [], - model: values.model === Models.OpenAI - ? { OpenAI: { model_type: 'gpt-3.5-turbo' } } - : { SleepAPI: {} }, + model: + values.model === Models.OpenAI + ? { OpenAI: { model_type: 'gpt-3.5-turbo' } } + : { SleepAPI: {} }, }, setupDetailsState: { my_device_encryption_sk: auth.my_device_encryption_sk, @@ -171,16 +172,18 @@ export const AddAgent = () => { - - {modelOptions.map((model) => ( - - {model.label} - - ))} - + + + {modelOptions.map((model) => ( + + {model.label} + + ))} + + diff --git a/apps/shinkai-visor/src/components/create-job/create-job.tsx b/apps/shinkai-visor/src/components/create-job/create-job.tsx index 82e96f144..49956dae6 100644 --- a/apps/shinkai-visor/src/components/create-job/create-job.tsx +++ b/apps/shinkai-visor/src/components/create-job/create-job.tsx @@ -4,11 +4,12 @@ import { useAgents } from '@shinkai_network/shinkai-node-state/lib/queries/getAg import { Loader2 } from 'lucide-react'; import { useForm } from 'react-hook-form'; import { FormattedMessage } from 'react-intl'; -import { useHistory } from 'react-router-dom'; +import { useHistory, useLocation } from 'react-router-dom'; import { z } from 'zod'; import { useQuery } from '../../hooks/use-query'; import { useAuth } from '../../store/auth/auth'; +import { useUIContainer } from '../../store/ui-container/ui-container'; import { Button } from '../ui/button'; import { Form, @@ -23,6 +24,7 @@ import { Select, SelectContent, SelectItem, + SelectPortal, SelectTrigger, SelectValue, } from '../ui/select'; @@ -36,8 +38,10 @@ type FormSchemaType = z.infer; export const CreateJob = () => { const history = useHistory(); + const location = useLocation<{ files: File[] }>(); const query = useQuery(); const auth = useAuth((state) => state.auth); + const uiContainer = useUIContainer((state) => state.uiContainer); const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { @@ -74,6 +78,7 @@ export const CreateJob = () => { agentId: values.agent, content: content, files_inbox: '', + files: location.state?.files, my_device_encryption_sk: auth.my_device_encryption_sk, my_device_identity_sk: auth.my_device_identity_sk, node_encryption_pk: auth.node_encryption_pk, @@ -106,13 +111,15 @@ export const CreateJob = () => { - - {agents?.map((model) => ( - - {(model.full_identity_name as any)?.subidentity_name} - - ))} - + + + {agents?.map((model) => ( + + {(model.full_identity_name as any)?.subidentity_name} + + ))} + + @@ -127,6 +134,15 @@ export const CreateJob = () => { )} + {location.state?.files?.length && ( +
+

+ {location.state.files[0].name} -{' '} + {(location.state.files[0].size / 1024 ** 2).toFixed(2)}Mb +

+
+ )} + state.setLogout); + const uiContainer = useUIContainer((state) => state.uiContainer); + const [isMenuOpened, setMenuOpened] = useState(false); const isRootPage = ['/welcome', '/inboxes', '/agents', '/jobs'].includes( - location.pathname, + location.pathname ); function goBack() { @@ -50,8 +54,8 @@ export default function NavBar() { history.replace('/inboxes'); break; case MenuOption.CreateInbox: - history.replace('/inboxes/create-inbox'); - break; + history.replace('/inboxes/create-inbox'); + break; case MenuOption.CreateJob: history.replace('/inboxes/create-job'); break; @@ -68,7 +72,7 @@ export default function NavBar() { break; } }; - + console.log('ELEMENT', uiContainer?.shadowRoot ? { container: uiContainer.rootElement }: {}); return ( diff --git a/apps/shinkai-visor/src/components/popup/popup.tsx b/apps/shinkai-visor/src/components/popup/popup.tsx index f423821c5..208d10672 100644 --- a/apps/shinkai-visor/src/components/popup/popup.tsx +++ b/apps/shinkai-visor/src/components/popup/popup.tsx @@ -1,46 +1,133 @@ +import { ApiConfig } from '@shinkai_network/shinkai-message-ts/api/api_config'; import { queryClient } from '@shinkai_network/shinkai-node-state/lib/constants'; import { QueryClientProvider } from '@tanstack/react-query'; +import { AnimatePresence, motion } from 'framer-motion'; import * as React from 'react'; +import { useEffect } from 'react'; import { createRoot } from 'react-dom/client'; import { IntlProvider } from 'react-intl'; -import { Provider } from 'react-redux'; import { MemoryRouter as Router } from 'react-router-dom'; -import { PersistGate } from 'redux-persist/integration/react'; +import { Route, Switch, useHistory, useLocation } from 'react-router-dom'; +import { useGlobalPopupChromeMessage } from '../../hooks/use-global-popup-chrome-message'; import { langMessages, locale } from '../../lang/intl'; -import { store, storePersistor } from '../../store'; +import { useAuth } from '../../store/auth/auth'; +import { useUIContainer } from '../../store/ui-container/ui-container'; import globalStyle from '../../theme/styles.css?inline'; -import { PopupRouting } from '../popup-routing/popup-routing'; +import { AddAgent } from '../add-agent/add-agent'; +import { AddNode } from '../add-node/add-node'; +import { Agents } from '../agents/agents'; +import { CreateInbox } from '../create-inbox/create-inbox'; +import { CreateJob } from '../create-job/create-job'; +import { Inbox } from '../inbox/inbox'; +import { Inboxes } from '../inboxes/inboxes'; +import { NotFound } from '../not-found/not-found'; +import { SplashScreen } from '../splash-screen/splash-screen'; +import Welcome from '../welcome/welcome'; +import { WithNav } from '../with-nav/with-nav'; import popupStyle from './popup.css?inline'; -let container = document.getElementById('shinkai-popup-root'); -let shadowRoot: ShadowRoot | undefined = undefined; -if (!container) { - const baseContainer = document.createElement('shinkai-popup-root'); - shadowRoot = baseContainer.attachShadow({ mode: 'closed' }); - container = document.createElement('div'); - container.id = 'shinkai-popup-root'; - shadowRoot.appendChild(container); - const htmlRoot = document.getElementsByTagName('html')[0]; - htmlRoot.prepend(shadowRoot); -} +export const Popup = ({ container }: { container: { shadowRoot: ShadowRoot, rootElement: HTMLElement }}) => { + const history = useHistory(); + const auth = useAuth((state) => state.auth); + const location = useLocation(); + const [popupVisibility] = useGlobalPopupChromeMessage(); + const setUIContainer = useUIContainer((state) => state.setUIContainer); + setUIContainer({ shadowRoot: container.shadowRoot, rootElement: container.rootElement }); + useEffect(() => { + const isAuthenticated = !!auth; + if (isAuthenticated) { + ApiConfig.getInstance().setEndpoint(auth.node_address); + history.replace('/inboxes'); + return; + } else { + history.replace('/welcome'); + } + }, [history, auth]); + + return ( + + {popupVisibility && ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )} + + ); +}; + +const baseContainer = document.createElement('shinkai-popup-root'); +const shadowRoot = baseContainer.attachShadow({ mode: 'closed' }); +const container = document.createElement('div'); +container.id = 'root'; +shadowRoot.appendChild(container); +const htmlRoot = document.getElementsByTagName('html')[0]; +htmlRoot.prepend(baseContainer); const root = createRoot(container); + root.render( - - - -
- - - -
-
-
-
+ +
+ + + +
+
); diff --git a/apps/shinkai-visor/src/components/ui/dropdown-menu.tsx b/apps/shinkai-visor/src/components/ui/dropdown-menu.tsx index 944aa24b0..a410ef1cc 100644 --- a/apps/shinkai-visor/src/components/ui/dropdown-menu.tsx +++ b/apps/shinkai-visor/src/components/ui/dropdown-menu.tsx @@ -61,7 +61,7 @@ const DropdownMenuContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, sideOffset = 4, ...props }, ref) => ( - + // - + // )) DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName diff --git a/apps/shinkai-visor/src/components/ui/select.tsx b/apps/shinkai-visor/src/components/ui/select.tsx index 8320f2ed8..12f417594 100644 --- a/apps/shinkai-visor/src/components/ui/select.tsx +++ b/apps/shinkai-visor/src/components/ui/select.tsx @@ -12,6 +12,8 @@ const SelectGroup = SelectPrimitive.Group; const SelectValue = SelectPrimitive.Value; +const SelectPortal = SelectPrimitive.Portal + const SelectTrigger = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef @@ -36,7 +38,7 @@ const SelectContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, position = 'popper', ...props }, ref) => ( - + // - + // )); SelectContent.displayName = SelectPrimitive.Content.displayName; @@ -114,6 +116,7 @@ export { SelectGroup, SelectValue, SelectTrigger, + SelectPortal, SelectContent, SelectLabel, SelectItem, diff --git a/apps/shinkai-visor/src/helpers/pdf-generator.ts b/apps/shinkai-visor/src/helpers/pdf-generator.ts new file mode 100644 index 000000000..f07277af1 --- /dev/null +++ b/apps/shinkai-visor/src/helpers/pdf-generator.ts @@ -0,0 +1,30 @@ +import { jsPDF } from 'jspdf'; + +export const generatePdfFromCurrentPage = async (fileName: string): Promise => { + try { + const pdf = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4', compress: true }); + const getPdfFromHtml = async (html: HTMLElement | string): Promise => { + return new Promise((resolve, reject) => { + pdf.html(html, { + html2canvas: { + windowWidth: 1920, + windowHeight: 1080, + }, + image: { type: 'jpeg', quality: 0.5 }, + margin: 10, + callback: (doc) => { + doc.save(fileName); + const output = doc.output('blob'); + resolve(output); + }, + }); + }); + }; + const siteAsPdfBlob = await getPdfFromHtml(document.body.innerHTML); + const siteAsPdfFile = new File([siteAsPdfBlob], fileName, { type: siteAsPdfBlob.type }); + return siteAsPdfFile; + } catch (e) { + console.log('errror generating pdf', e); + return undefined; + } +}; diff --git a/apps/shinkai-visor/src/hooks/use-global-action-button-chrome-message.ts b/apps/shinkai-visor/src/hooks/use-global-action-button-chrome-message.ts index fc59b6350..6bbf416a9 100644 --- a/apps/shinkai-visor/src/hooks/use-global-action-button-chrome-message.ts +++ b/apps/shinkai-visor/src/hooks/use-global-action-button-chrome-message.ts @@ -1,16 +1,13 @@ import { useState } from "react"; import { ContentScriptMessageType } from "../service-worker/communication/content-script-message-type"; -import { sendContentScriptMessage } from "../service-worker/communication/content-script-messages"; import { ServiceWorkerMessageType } from "../service-worker/communication/service-worker-message-type"; import { useChromeMessage } from "./use-chrome-message"; export const useGlobalActionButtonChromeMessage = () => { const [popupVisibility, setPopupVisibility] = useState(false); useChromeMessage((message, sender) => { - if (message.type === ServiceWorkerMessageType.SendToAgent) { - sendContentScriptMessage({ type: ContentScriptMessageType.TogglePopupVisibility, data: true }); - } else if (message.type === ServiceWorkerMessageType.ContentScript) { + if (message.type === ServiceWorkerMessageType.ContentScript) { if (message.data.type === ContentScriptMessageType.TogglePopupVisibility) { setPopupVisibility(message.data.data !== undefined ? message.data.data : !popupVisibility); } diff --git a/apps/shinkai-visor/src/hooks/use-global-popup-chrome-message.ts b/apps/shinkai-visor/src/hooks/use-global-popup-chrome-message.ts index ae38c80e5..f3abdd9e7 100644 --- a/apps/shinkai-visor/src/hooks/use-global-popup-chrome-message.ts +++ b/apps/shinkai-visor/src/hooks/use-global-popup-chrome-message.ts @@ -1,17 +1,28 @@ import { useState } from "react"; import { useHistory } from "react-router-dom"; +import { generatePdfFromCurrentPage } from '../helpers/pdf-generator'; import { ContentScriptMessageType } from "../service-worker/communication/content-script-message-type"; +import { sendContentScriptMessage } from '../service-worker/communication/content-script-messages'; import { ServiceWorkerMessageType } from "../service-worker/communication/service-worker-message-type"; import { useChromeMessage } from "./use-chrome-message"; export const useGlobalPopupChromeMessage = () => { const history = useHistory(); const [popupVisibility, setPopupVisibility] = useState(false); - useChromeMessage((message, sender) => { + useChromeMessage(async (message, sender) => { if (message.type === ServiceWorkerMessageType.SendToAgent) { const params = new URLSearchParams({ context: message?.data?.textContent }); history.replace({ pathname: '/inboxes/create-job', search: params.toString() }); + sendContentScriptMessage({ type: ContentScriptMessageType.TogglePopupVisibility, data: true }); + } else if (message.type === ServiceWorkerMessageType.SendPageToAgent) { + const pageAsPdf = await generatePdfFromCurrentPage(`${encodeURIComponent(window.location.href)}.pdf`); + if (!pageAsPdf) { + return; + } + history.replace({ pathname: '/inboxes/create-job', state: { files: [pageAsPdf]} }); + sendContentScriptMessage({ type: ContentScriptMessageType.TogglePopupVisibility, data: true }); + } else if (message.type === ServiceWorkerMessageType.ContentScript) { if (message.data.type === ContentScriptMessageType.TogglePopupVisibility) { setPopupVisibility(message.data.data !== undefined ? message.data.data : !popupVisibility); diff --git a/apps/shinkai-visor/src/service-worker/communication/service-worker-message-type.ts b/apps/shinkai-visor/src/service-worker/communication/service-worker-message-type.ts index e265808fb..648bc58fc 100644 --- a/apps/shinkai-visor/src/service-worker/communication/service-worker-message-type.ts +++ b/apps/shinkai-visor/src/service-worker/communication/service-worker-message-type.ts @@ -1,4 +1,6 @@ export enum ServiceWorkerMessageType { ContentScript = 'content-script', SendToAgent = 'send-to-agent', + SendPageToAgent = 'send-page-to-agent', + OffscreenMessageType = 'offscreen', } diff --git a/apps/shinkai-visor/src/service-worker/communication/service-worker-messages.ts b/apps/shinkai-visor/src/service-worker/communication/service-worker-messages.ts index c21afcdcc..d44e155e9 100644 --- a/apps/shinkai-visor/src/service-worker/communication/service-worker-messages.ts +++ b/apps/shinkai-visor/src/service-worker/communication/service-worker-messages.ts @@ -1,11 +1,17 @@ import { ContentScriptMessage } from './content-script-message'; +import { OffscreenMessage } from './offscreen-message'; import { ServiceWorkerMessageType } from './service-worker-message-type'; export type ServiceWorkerMessage = | { type: ServiceWorkerMessageType.ContentScript; data: ContentScriptMessage } | { - type: ServiceWorkerMessageType.SendToAgent; - data: { - textContent: string; - }; + type: ServiceWorkerMessageType.SendToAgent; + data: { + textContent: string; }; + } + | { + type: ServiceWorkerMessageType.SendPageToAgent; + } + | { type: ServiceWorkerMessageType.OffscreenMessageType; data: OffscreenMessage }; + diff --git a/apps/shinkai-visor/src/service-worker/context-menu.ts b/apps/shinkai-visor/src/service-worker/context-menu.ts index 192f9912d..9f9f25448 100644 --- a/apps/shinkai-visor/src/service-worker/context-menu.ts +++ b/apps/shinkai-visor/src/service-worker/context-menu.ts @@ -2,20 +2,19 @@ import { ServiceWorkerMessageType } from "./communication/service-worker-message import { ServiceWorkerMessage } from "./communication/service-worker-messages"; enum ContextMenu { - SaveToShinkaiNode = 'save-on-shinkai-node', + SendPageToAgent = 'send-page-to-agent', SendToAgent = 'send-to-agent', } -const saveToShinkaiNode = (info: chrome.contextMenus.OnClickData, tab: chrome.tabs.Tab | undefined) => { +const sendPageToAgent = async (info: chrome.contextMenus.OnClickData, tab: chrome.tabs.Tab | undefined) => { + // At this point, agents can just process text if (!tab?.id) { return; } - chrome.pageCapture.saveAsMHTML( - { tabId: tab?.id }, - (mhtml) => { - console.log('saveToShinkaiNode - generated mhtml', mhtml); - }, - ) + const message: ServiceWorkerMessage = { + type: ServiceWorkerMessageType.SendPageToAgent, + }; + chrome.tabs.sendMessage(tab.id, message); } const sendToAgent = (info: chrome.contextMenus.OnClickData, tab: chrome.tabs.Tab | undefined) => { @@ -33,22 +32,22 @@ const sendToAgent = (info: chrome.contextMenus.OnClickData, tab: chrome.tabs.Tab } const menuActions = new Map void>([ - [ContextMenu.SaveToShinkaiNode, saveToShinkaiNode], + [ContextMenu.SendPageToAgent, sendPageToAgent], [ContextMenu.SendToAgent, sendToAgent], ]); const registerMenu = () => { chrome.contextMenus.create( { - id: ContextMenu.SaveToShinkaiNode, - title: 'Save this page in my Shinkai Node', + id: ContextMenu.SendPageToAgent, + title: 'Send page to agent', contexts: ['all'] } ); chrome.contextMenus.create({ id: ContextMenu.SendToAgent, - title: 'Ask to agent', - contexts: ['all'] + title: 'Send selection to agent', + contexts: ['selection'] }); } diff --git a/apps/shinkai-visor/src/store/ui-container/ui-container.ts b/apps/shinkai-visor/src/store/ui-container/ui-container.ts new file mode 100644 index 000000000..66fbc0083 --- /dev/null +++ b/apps/shinkai-visor/src/store/ui-container/ui-container.ts @@ -0,0 +1,24 @@ +import { create } from "zustand"; +import { devtools } from "zustand/middleware"; + +export type UIContainerData = { + shadowRoot: ShadowRoot; + rootElement: HTMLElement; +}; + +type UIContainerStore = { + uiContainer: UIContainerData | null; + setUIContainer: (uiContainer: UIContainerData) => void; +}; + +export const useUIContainer = create()( + devtools( + (set) => ({ + uiContainer: null, + setUIContainer: (uiContainer: UIContainerData) => set({ uiContainer }), + }), + { + name: "ui-container", + } + ) +); diff --git a/apps/shinkai-visor/src/theme/styles.css b/apps/shinkai-visor/src/theme/styles.css index afdeec8b5..320293396 100644 --- a/apps/shinkai-visor/src/theme/styles.css +++ b/apps/shinkai-visor/src/theme/styles.css @@ -3,7 +3,7 @@ @import "tailwindcss/components"; @layer base { - :root { + :host { --background: 0 0% 100%; --foreground: 222.2 84% 4.9%; @@ -70,7 +70,7 @@ * { @apply border-border; } - body { + :host { @apply bg-background text-foreground; } } diff --git a/libs/shinkai-node-state/src/lib/mutations/createJob/index.ts b/libs/shinkai-node-state/src/lib/mutations/createJob/index.ts index 368ea992e..8fe10d83d 100644 --- a/libs/shinkai-node-state/src/lib/mutations/createJob/index.ts +++ b/libs/shinkai-node-state/src/lib/mutations/createJob/index.ts @@ -1,6 +1,7 @@ import { createJob as createJobApi, sendMessageToJob, + sendTextMessageWithFilesForInbox, } from "@shinkai_network/shinkai-message-ts/api"; import { JobCreationWrapper, @@ -15,6 +16,7 @@ export const createJob = async ({ agentId, content, files_inbox, + files, my_device_encryption_sk, my_device_identity_sk, node_encryption_pk, @@ -42,22 +44,40 @@ export const createJob = async ({ } ); - const response = await sendMessageToJob( - jobId, - content, - files_inbox, - shinkaiIdentity, - profile, - receiver, - receiver_subidentity, - { - my_device_encryption_sk: my_device_encryption_sk, - my_device_identity_sk: my_device_identity_sk, - node_encryption_pk: node_encryption_pk, - profile_encryption_sk, - profile_identity_sk, - } - ); - + let response: any; + if (files?.length) { + response = await sendTextMessageWithFilesForInbox( + shinkaiIdentity, + profile, // sender subidentity + receiver, + content, + `job_inbox::${jobId}::false`, + files[0], + { + my_device_encryption_sk: my_device_encryption_sk, + my_device_identity_sk: my_device_identity_sk, + node_encryption_pk: node_encryption_pk, + profile_encryption_sk, + profile_identity_sk, + } + ); + } else { + response = await sendMessageToJob( + jobId, + content, + files_inbox, + shinkaiIdentity, + profile, + receiver, + receiver_subidentity, + { + my_device_encryption_sk: my_device_encryption_sk, + my_device_identity_sk: my_device_identity_sk, + node_encryption_pk: node_encryption_pk, + profile_encryption_sk, + profile_identity_sk, + } + ); + } return { jobId, response }; }; diff --git a/libs/shinkai-node-state/src/lib/mutations/createJob/types.ts b/libs/shinkai-node-state/src/lib/mutations/createJob/types.ts index 9630e9c6e..6da8c528b 100644 --- a/libs/shinkai-node-state/src/lib/mutations/createJob/types.ts +++ b/libs/shinkai-node-state/src/lib/mutations/createJob/types.ts @@ -6,6 +6,7 @@ export type CreateJobInput = JobCredentialsPayload & { agentId: string; content: string; files_inbox: string; + files: File[]; }; export type CreateJobOutput = { diff --git a/libs/shinkai-node-state/src/lib/mutations/sendTextMessage/index.ts b/libs/shinkai-node-state/src/lib/mutations/sendTextMessage/index.ts index a07168449..467eb7fe2 100644 --- a/libs/shinkai-node-state/src/lib/mutations/sendTextMessage/index.ts +++ b/libs/shinkai-node-state/src/lib/mutations/sendTextMessage/index.ts @@ -1,6 +1,6 @@ -import { sendTextMessageWithInbox } from "@shinkai_network/shinkai-message-ts/api"; +import { sendTextMessageWithFilesForInbox, sendTextMessageWithInbox } from "@shinkai_network/shinkai-message-ts/api"; -import { SendMessageToInboxInput } from "./types"; +import { SendMessageToInboxInput, SendMessageWithFilesToInboxInput } from "./types"; export const sendMessageToInbox = async ({ sender, @@ -22,3 +22,24 @@ export const sendMessageToInbox = async ({ profile_identity_sk, }); }; + +export const sendMessageWithFilesToInbox = async ({ + sender, + receiver, + message, + inboxId, + file, + my_device_encryption_sk, + my_device_identity_sk, + node_encryption_pk, + profile_encryption_sk, + profile_identity_sk, +}: SendMessageWithFilesToInboxInput) => { + return await sendTextMessageWithFilesForInbox(sender, "", receiver, message, inboxId, file, { + my_device_encryption_sk, + my_device_identity_sk, + node_encryption_pk, + profile_encryption_sk, + profile_identity_sk, + }); +}; diff --git a/libs/shinkai-node-state/src/lib/mutations/sendTextMessage/types.ts b/libs/shinkai-node-state/src/lib/mutations/sendTextMessage/types.ts index ec3b77b52..9f5833fd7 100644 --- a/libs/shinkai-node-state/src/lib/mutations/sendTextMessage/types.ts +++ b/libs/shinkai-node-state/src/lib/mutations/sendTextMessage/types.ts @@ -7,3 +7,11 @@ export type SendMessageToInboxInput = CredentialsPayload & { message: string; inboxId: string; }; + +export type SendMessageWithFilesToInboxInput = CredentialsPayload & { + sender: string; + receiver: string; + message: string; + inboxId: string; + file: File; +}; diff --git a/libs/shinkai-node-state/src/lib/mutations/sendTextMessage/useSendMessageWithFilesToInbox.ts b/libs/shinkai-node-state/src/lib/mutations/sendTextMessage/useSendMessageWithFilesToInbox.ts new file mode 100644 index 000000000..bc727b89e --- /dev/null +++ b/libs/shinkai-node-state/src/lib/mutations/sendTextMessage/useSendMessageWithFilesToInbox.ts @@ -0,0 +1,14 @@ +import { useMutation } from "@tanstack/react-query"; + +import { FunctionKey, queryClient } from "../../constants"; +import { sendMessageWithFilesToInbox } from "."; + +export const useSendMessageToInbox = () => { + return useMutation({ + mutationFn: sendMessageWithFilesToInbox, + onSuccess: () => { + queryClient.invalidateQueries([FunctionKey.GET_CHAT_CONVERSATION_PAGINATION]); + queryClient.invalidateQueries([FunctionKey.GET_UNREAD_CHAT_CONVERSATION]); + }, + }); +}; diff --git a/package-lock.json b/package-lock.json index 7d3efa81c..d87cb4f47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,6 +55,7 @@ "framer-motion": "^10.16.3", "ionicons": "^7.0.0", "jsbi": "^4.3.0", + "jspdf": "^2.5.1", "lucide-react": "^0.263.1", "node-forge": ">=1.0.0", "react": "18.2.0", @@ -7798,6 +7799,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-1jJ3OO8FXHCcuVXCuO1EMC/MjDuT6/cxgsMw/UebkO9afnL99Y5QTpUjk7+flK4G5FzBVJEgDKL5eFtoxJs9MQ==", + "optional": true + }, "node_modules/@types/range-parser": { "version": "1.2.4", "dev": true, @@ -9231,6 +9238,17 @@ "node": ">= 4.0.0" } }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, "node_modules/autoprefixer": { "version": "10.4.16", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", @@ -9548,6 +9566,15 @@ "version": "1.0.2", "license": "MIT" }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "optional": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "funding": [ @@ -9954,6 +9981,17 @@ "node-int64": "^0.4.0" } }, + "node_modules/btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", + "bin": { + "btoa": "bin/btoa.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/buffer": { "version": "5.7.1", "funding": [ @@ -10216,6 +10254,31 @@ } ] }, + "node_modules/canvg": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz", + "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@types/raf": "^3.4.0", + "core-js": "^3.8.3", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.7", + "rgbcolor": "^1.0.1", + "stackblur-canvas": "^2.0.0", + "svg-pathdata": "^6.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/canvg/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "optional": true + }, "node_modules/case-anything": { "version": "2.1.13", "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.13.tgz", @@ -11283,6 +11346,15 @@ "postcss": "^8.0.9" } }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/css-loader": { "version": "6.8.1", "dev": true, @@ -12112,6 +12184,12 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, + "node_modules/dompurify": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.7.tgz", + "integrity": "sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ==", + "optional": true + }, "node_modules/domutils": { "version": "3.1.0", "dev": true, @@ -14593,6 +14671,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "optional": true, + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/htmlparser2": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", @@ -16509,6 +16600,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/jspdf": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz", + "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==", + "dependencies": { + "@babel/runtime": "^7.14.0", + "atob": "^2.1.2", + "btoa": "^1.2.1", + "fflate": "^0.4.8" + }, + "optionalDependencies": { + "canvg": "^3.0.6", + "core-js": "^3.6.0", + "dompurify": "^2.2.0", + "html2canvas": "^1.0.0-rc.5" + } + }, + "node_modules/jspdf/node_modules/fflate": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", + "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" + }, "node_modules/jsprim": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", @@ -19409,7 +19522,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true + "devOptional": true }, "node_modules/picocolors": { "version": "1.0.0", @@ -20546,6 +20659,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "optional": true, + "dependencies": { + "performance-now": "^2.1.0" + } + }, "node_modules/randombytes": { "version": "2.1.0", "dev": true, @@ -21366,6 +21488,15 @@ "dev": true, "license": "MIT" }, + "node_modules/rgbcolor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", + "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==", + "optional": true, + "engines": { + "node": ">= 0.8.15" + } + }, "node_modules/rimraf": { "version": "3.0.2", "dev": true, @@ -22343,6 +22474,15 @@ "dev": true, "license": "MIT" }, + "node_modules/stackblur-canvas": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.6.0.tgz", + "integrity": "sha512-8S1aIA+UoF6erJYnglGPug6MaHYGo1Ot7h5fuXx4fUPvcvQfcdw2o/ppCse63+eZf8PPidSu4v1JnmEVtEDnpg==", + "optional": true, + "engines": { + "node": ">=0.1.14" + } + }, "node_modules/stackframe": { "version": "1.3.4", "dev": true, @@ -22839,6 +22979,15 @@ "dev": true, "license": "MIT" }, + "node_modules/svg-pathdata": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", + "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", + "optional": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/svgo": { "version": "3.0.2", "dev": true, @@ -23148,6 +23297,15 @@ "node": ">=8" } }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/text-table": { "version": "0.2.0", "dev": true, @@ -24096,6 +24254,15 @@ "node": ">= 0.4.0" } }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "optional": true, + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, "node_modules/uuid": { "version": "9.0.0", "license": "MIT", diff --git a/package.json b/package.json index dd9f91bb3..d354224e7 100644 --- a/package.json +++ b/package.json @@ -130,6 +130,7 @@ "framer-motion": "^10.16.3", "ionicons": "^7.0.0", "jsbi": "^4.3.0", + "jspdf": "^2.5.1", "lucide-react": "^0.263.1", "node-forge": ">=1.0.0", "react": "18.2.0", From c870fef2cd67c0e671a3aa69158d73319e9cc1a3 Mon Sep 17 00:00:00 2001 From: Alfredo Gallardo Date: Wed, 11 Oct 2023 11:13:38 -0500 Subject: [PATCH 3/6] - feature: added file list component --- .../src/components/agents/agents.tsx | 13 +++---- .../src/components/create-job/create-job.tsx | 10 +++--- .../src/components/file-list/file-list.tsx | 34 +++++++++++++++++++ .../src/components/inboxes/inboxes.tsx | 17 ++++++++-- .../src/helpers/file-name-utils.ts | 9 +++++ .../src/utils/inbox_name_handler.ts | 5 +++ .../src/lib/mutations/createJob/index.ts | 3 +- 7 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 apps/shinkai-visor/src/components/file-list/file-list.tsx create mode 100644 apps/shinkai-visor/src/helpers/file-name-utils.ts diff --git a/apps/shinkai-visor/src/components/agents/agents.tsx b/apps/shinkai-visor/src/components/agents/agents.tsx index 2927f038b..a80252b17 100644 --- a/apps/shinkai-visor/src/components/agents/agents.tsx +++ b/apps/shinkai-visor/src/components/agents/agents.tsx @@ -1,4 +1,5 @@ import { useAgents } from "@shinkai_network/shinkai-node-state/lib/queries/getAgents/useGetAgents"; +import { Fragment } from "react"; import { useAuth } from '../../store/auth/auth'; import { ScrollArea } from '../ui/scroll-area'; @@ -17,17 +18,17 @@ export const Agents = () => { profile_identity_sk: auth?.profile_identity_sk ?? "", }); return ( -
+
{agents?.map((agent) => ( -
-
+

{agent.id} -

+

-
+ ))}
diff --git a/apps/shinkai-visor/src/components/create-job/create-job.tsx b/apps/shinkai-visor/src/components/create-job/create-job.tsx index 49956dae6..b4fab4c23 100644 --- a/apps/shinkai-visor/src/components/create-job/create-job.tsx +++ b/apps/shinkai-visor/src/components/create-job/create-job.tsx @@ -1,4 +1,5 @@ import { zodResolver } from '@hookform/resolvers/zod'; +import { buildInboxIdFromJobId } from '@shinkai_network/shinkai-message-ts/utils'; import { useCreateJob } from '@shinkai_network/shinkai-node-state/lib/mutations/createJob/useCreateJob'; import { useAgents } from '@shinkai_network/shinkai-node-state/lib/queries/getAgents/useGetAgents'; import { Loader2 } from 'lucide-react'; @@ -10,6 +11,7 @@ import { z } from 'zod'; import { useQuery } from '../../hooks/use-query'; import { useAuth } from '../../store/auth/auth'; import { useUIContainer } from '../../store/ui-container/ui-container'; +import { FileList } from '../file-list/file-list'; import { Button } from '../ui/button'; import { Form, @@ -61,8 +63,7 @@ export const CreateJob = () => { }); const { isLoading, mutateAsync: createJob } = useCreateJob({ onSuccess: (data) => { - // TODO: job_inbox, false is hardcoded - const jobId = encodeURIComponent(`job_inbox::${data.jobId}::false`); + const jobId = encodeURIComponent(buildInboxIdFromJobId(data.jobId)); history.replace(`/inboxes/${jobId}`); }, }); @@ -136,10 +137,7 @@ export const CreateJob = () => { {location.state?.files?.length && (
-

- {location.state.files[0].name} -{' '} - {(location.state.files[0].size / 1024 ** 2).toFixed(2)}Mb -

+
)} diff --git a/apps/shinkai-visor/src/components/file-list/file-list.tsx b/apps/shinkai-visor/src/components/file-list/file-list.tsx new file mode 100644 index 000000000..4fca5723c --- /dev/null +++ b/apps/shinkai-visor/src/components/file-list/file-list.tsx @@ -0,0 +1,34 @@ +import { Paperclip } from 'lucide-react'; + +import { getFileExt, getFileName } from '../../helpers/file-name-utils'; + +export const FileList = ({ files }: { files: File[] }) => { + return ( +
    + {files?.map((file, index) => ( +
  • +
    + +
    +
    + + {getFileName(decodeURIComponent(file.name))} + + . + + {getFileExt(decodeURIComponent(file.name))} + +
    + + {(file.size / 1024 ** 2).toFixed(3)}mb + +
    +
    +
  • + ))} +
+ ); +}; diff --git a/apps/shinkai-visor/src/components/inboxes/inboxes.tsx b/apps/shinkai-visor/src/components/inboxes/inboxes.tsx index 0b9055bb9..6bafad383 100644 --- a/apps/shinkai-visor/src/components/inboxes/inboxes.tsx +++ b/apps/shinkai-visor/src/components/inboxes/inboxes.tsx @@ -52,8 +52,11 @@ export const Inboxes = () => {

-
@@ -61,7 +64,15 @@ export const Inboxes = () => { {inboxIds?.map((inboxId) => ( - + ))} diff --git a/apps/shinkai-visor/src/helpers/file-name-utils.ts b/apps/shinkai-visor/src/helpers/file-name-utils.ts new file mode 100644 index 000000000..fe8bf2689 --- /dev/null +++ b/apps/shinkai-visor/src/helpers/file-name-utils.ts @@ -0,0 +1,9 @@ +export const getFileName = (fileName: string): string => { + const nameParts = fileName.split('.'); + console.log('nameparts', nameParts, nameParts.slice(0, -1), 'asdsd'); + return nameParts.slice(0, -1).join('.'); +}; +export const getFileExt = (fileName: string): string => { + const nameParts = fileName.split('.'); + return nameParts.pop() || ''; +}; diff --git a/libs/shinkai-message-ts/src/utils/inbox_name_handler.ts b/libs/shinkai-message-ts/src/utils/inbox_name_handler.ts index b73440e40..42faafd9a 100644 --- a/libs/shinkai-message-ts/src/utils/inbox_name_handler.ts +++ b/libs/shinkai-message-ts/src/utils/inbox_name_handler.ts @@ -66,3 +66,8 @@ export const isJobInbox = (inboxId: string): boolean => { } return parts[0] === 'job_inbox'; } + +export const buildInboxIdFromJobId = (jobId: string): string => { + // TODO: job_inbox, false is hardcoded + return `job_inbox::${jobId}::false` +} diff --git a/libs/shinkai-node-state/src/lib/mutations/createJob/index.ts b/libs/shinkai-node-state/src/lib/mutations/createJob/index.ts index 8fe10d83d..faffe7a8f 100644 --- a/libs/shinkai-node-state/src/lib/mutations/createJob/index.ts +++ b/libs/shinkai-node-state/src/lib/mutations/createJob/index.ts @@ -3,6 +3,7 @@ import { sendMessageToJob, sendTextMessageWithFilesForInbox, } from "@shinkai_network/shinkai-message-ts/api"; +import { buildInboxIdFromJobId } from "@shinkai_network/shinkai-message-ts/utils"; import { JobCreationWrapper, JobScopeWrapper, @@ -51,7 +52,7 @@ export const createJob = async ({ profile, // sender subidentity receiver, content, - `job_inbox::${jobId}::false`, + buildInboxIdFromJobId(jobId), files[0], { my_device_encryption_sk: my_device_encryption_sk, From 3b0f0940fb3576a8bd27e910b7d06b90ee2fdc4d Mon Sep 17 00:00:00 2001 From: Alfredo Gallardo Date: Wed, 11 Oct 2023 11:32:24 -0500 Subject: [PATCH 4/6] - fix: removed logs --- apps/shinkai-visor/src/components/nav/nav.tsx | 1 - apps/shinkai-visor/src/helpers/file-name-utils.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/apps/shinkai-visor/src/components/nav/nav.tsx b/apps/shinkai-visor/src/components/nav/nav.tsx index a5fe42f5c..60e9c6d24 100644 --- a/apps/shinkai-visor/src/components/nav/nav.tsx +++ b/apps/shinkai-visor/src/components/nav/nav.tsx @@ -72,7 +72,6 @@ export default function NavBar() { break; } }; - console.log('ELEMENT', uiContainer?.shadowRoot ? { container: uiContainer.rootElement }: {}); return (