From 8bcc0b973ebd8323f7ec751fdd0e46b3e242d1a4 Mon Sep 17 00:00:00 2001 From: Alfredo Gallardo Date: Tue, 14 May 2024 12:51:33 -0400 Subject: [PATCH] - refactor: use axios in place of fetch so we can handle timeouts --- libs/shinkai-message-ts/src/api.ts | 2 +- libs/shinkai-message-ts/src/api/methods.ts | 1949 ++++++++--------- .../cryptography/shinkai-encryption.test.ts | 19 +- .../src/cryptography/shinkai-encryption.ts | 28 +- libs/shinkai-message-ts/src/http-client.ts | 5 + libs/shinkai-message-ts/src/index.ts | 10 +- libs/shinkai-message-ts/src/models.ts | 2 +- .../src/utils/inbox_name_handler.test.ts | 53 +- .../src/utils/inbox_name_handler.ts | 47 +- .../src/utils/shinkai_message_handler.test.ts | 26 +- .../src/utils/url-join.test.ts | 41 +- libs/shinkai-message-ts/src/utils/url-join.ts | 5 +- .../src/utils/wasm_helpers.test.ts | 10 +- .../src/utils/wasm_helpers.ts | 63 +- libs/shinkai-message-ts/src/wasm.ts | 16 +- .../FileUploaderUsingSymmetricKeyManager.ts | 266 +-- .../src/wasm/InboxNameWrapper.test.ts | 86 +- .../src/wasm/JobMessageWrapper.ts | 7 +- .../src/wasm/SerializedAgentWrapper.test.ts | 38 +- .../src/wasm/ShinkaiMessageWrapper.test.ts | 1 - .../src/wasm/ShinkaiNameWrapper.test.ts | 63 +- libs/shinkai-message-ts/vite.config.ts | 4 +- 22 files changed, 1313 insertions(+), 1428 deletions(-) create mode 100644 libs/shinkai-message-ts/src/http-client.ts diff --git a/libs/shinkai-message-ts/src/api.ts b/libs/shinkai-message-ts/src/api.ts index 0308e5590..3fd1d409b 100644 --- a/libs/shinkai-message-ts/src/api.ts +++ b/libs/shinkai-message-ts/src/api.ts @@ -1 +1 @@ -export * from "./api/methods"; +export * from './api/methods'; diff --git a/libs/shinkai-message-ts/src/api/methods.ts b/libs/shinkai-message-ts/src/api/methods.ts index d32b8b28d..e1793ee05 100644 --- a/libs/shinkai-message-ts/src/api/methods.ts +++ b/libs/shinkai-message-ts/src/api/methods.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import { httpClient } from '../http-client'; import { Agent, AgentCredentialsPayload, @@ -23,31 +24,13 @@ import { SerializedAgentWrapper } from '../wasm/SerializedAgentWrapper'; import { ShinkaiMessageBuilderWrapper } from '../wasm/ShinkaiMessageBuilderWrapper'; import { ShinkaiNameWrapper } from '../wasm/ShinkaiNameWrapper'; -// Helper function to handle HTTP errors -export const handleHttpError = async (response: Response): Promise => { - if (response.status < 200 || response.status >= 300) { - let error: { code: string; error: string; message: string } | undefined; - try { - error = await response.json(); - } catch (e) { - console.error(`Error parsing http error response ${response.body}`); - error = undefined; - } - throw new Error( - `HTTP error: ${response.status} ${error?.code}, ${error?.error}, ${error?.message}`, - ); - } -}; - export const fetchPublicKey = (nodeAddress: string) => async (): Promise => { - try { - const response = await fetch(urlJoin(nodeAddress, '/get_public_key')); - return response.json(); - } catch (error) { - console.error('Error fetching public key:', error); - throw error; - } + const response = await httpClient.get( + urlJoin(nodeAddress, '/get_public_key'), + ); + const data = await response.data; + return data; }; export const createChatWithMessage = async ( @@ -77,39 +60,35 @@ export const createChatWithMessage = async ( true, ); - try { - const messageStr = ShinkaiMessageBuilderWrapper.create_chat_with_message( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - text_message, - inbox.get_value, - ); + const messageStr = ShinkaiMessageBuilderWrapper.create_chat_with_message( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + text_message, + inbox.get_value, + ); - const message: ShinkaiMessage = JSON.parse(messageStr); + const message: ShinkaiMessage = JSON.parse(messageStr); - const response = await fetch(urlJoin(nodeAddress, '/v1/send'), { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }); - const data: CreateChatInboxResponse = await response.json(); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/send'), + message, - await handleHttpError(response); + { + responseType: 'json', + }, + ); + const data = response.data; - if (message.body && 'unencrypted' in message.body) { - const inboxId = message.body.unencrypted.internal_metadata.inbox; - return { inboxId }; - } else { - return { inboxId: data.data.inbox }; - } - } catch (error) { - console.error('Error sending text message:', error); - throw error; + if (message.body && 'unencrypted' in message.body) { + const inboxId = message.body.unencrypted.internal_metadata.inbox; + return { inboxId }; + } else { + return { inboxId: data.data.inbox }; } }; @@ -122,46 +101,41 @@ export const sendTextMessageWithInbox = async ( inbox_name: string, setupDetailsState: CredentialsPayload, ): Promise<{ inboxId: string }> => { - try { - // Note(Nico): we are forcing to send messages from profiles by removing device related stuff - const senderShinkaiName = new ShinkaiNameWrapper( - sender + '/' + sender_subidentity, - ); - const senderProfile = senderShinkaiName.get_profile_name; - - const messageStr = - ShinkaiMessageBuilderWrapper.send_text_message_with_inbox( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - sender, - senderProfile, - receiver, - '', - inbox_name, - text_message, - ); + // Note(Nico): we are forcing to send messages from profiles by removing device related stuff + const senderShinkaiName = new ShinkaiNameWrapper( + sender + '/' + sender_subidentity, + ); + const senderProfile = senderShinkaiName.get_profile_name; + + const messageStr = ShinkaiMessageBuilderWrapper.send_text_message_with_inbox( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + sender, + senderProfile, + receiver, + '', + inbox_name, + text_message, + ); - const message: ShinkaiMessage = JSON.parse(messageStr); + const message: ShinkaiMessage = JSON.parse(messageStr); - const response = await fetch(urlJoin(nodeAddress, '/v1/send'), { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }); - const data: CreateChatInboxResponse = await response.json(); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/send'), + message, - await handleHttpError(response); + { + responseType: 'json', + }, + ); + const data: CreateChatInboxResponse = response.data; - if (message.body && 'unencrypted' in message.body) { - const inboxId = message.body.unencrypted.internal_metadata.inbox; - return { inboxId }; - } else { - return { inboxId: data.data.inbox }; - } - } catch (error) { - console.error('Error sending text message:', error); - throw error; + if (message.body && 'unencrypted' in message.body) { + const inboxId = message.body.unencrypted.internal_metadata.inbox; + return { inboxId }; + } else { + return { inboxId: data.data.inbox }; } }; @@ -175,36 +149,30 @@ export const sendTextMessageWithFilesForInbox = async ( files: File[], setupDetailsState: CredentialsPayload, ): Promise<{ inboxId: string; message: ShinkaiMessage }> => { - try { - const fileUploader = new FileUploader( - nodeAddress, - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - job_inbox, - sender, - sender_subidentity, - receiver, - ); + const fileUploader = new FileUploader( + nodeAddress, + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + job_inbox, + sender, + sender_subidentity, + receiver, + ); - await fileUploader.createFolder(); - for (const fileToUpload of files) { - await fileUploader.uploadEncryptedFile(fileToUpload); - } - const responseText = await fileUploader.finalizeAndSend(text_message, null); - const message: ShinkaiMessage = JSON.parse(responseText); - - if (message.body && 'unencrypted' in message.body) { - const inboxId = message.body.unencrypted.internal_metadata.inbox; - return { inboxId, message }; - } else { - console.warn('message body is null or encrypted'); - // TODO: workaround to skip error reading encrypted message - return { inboxId: job_inbox, message }; - } - } catch (error) { - console.error('Error sending text message with file:', error); - throw error; + await fileUploader.createFolder(); + for (const fileToUpload of files) { + await fileUploader.uploadEncryptedFile(fileToUpload); + } + const message = await fileUploader.finalizeAndSend(text_message, null); + + if (message.body && 'unencrypted' in message.body) { + const inboxId = message.body.unencrypted.internal_metadata.inbox; + return { inboxId, message }; + } else { + console.warn('message body is null or encrypted'); + // TODO: workaround to skip error reading encrypted message + return { inboxId: job_inbox, message }; } }; @@ -216,35 +184,29 @@ export const getAllInboxesForProfile = async ( target_shinkai_name_profile: string, setupDetailsState: CredentialsPayload, ): Promise => { - try { - const messageString = - ShinkaiMessageBuilderWrapper.get_all_inboxes_for_profile( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - sender, - sender_subidentity, - receiver, - target_shinkai_name_profile, - ); + const messageString = + ShinkaiMessageBuilderWrapper.get_all_inboxes_for_profile( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + sender, + sender_subidentity, + receiver, + target_shinkai_name_profile, + ); - const message = JSON.parse(messageString); + const message = JSON.parse(messageString); - const response = await fetch( - urlJoin(nodeAddress, '/v1/get_all_smart_inboxes_for_profile'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); - const data = await response.json(); - await handleHttpError(response); - return data.data; - } catch (error) { - console.error('Error getting all inboxes for profile:', error); - throw error; - } + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/get_all_smart_inboxes_for_profile'), + message, + + { + responseType: 'json', + }, + ); + const data = response.data; + return data.data; }; export const updateInboxName = async ( @@ -256,37 +218,28 @@ export const updateInboxName = async ( inboxName: string, inboxId: string, ): Promise<{ success: string; data: null }> => { - try { - const messageString = - ShinkaiMessageBuilderWrapper.update_shinkai_inbox_name( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - sender, - sender_subidentity, - receiver, - '', - inboxId, - inboxName, - ); + const messageString = ShinkaiMessageBuilderWrapper.update_shinkai_inbox_name( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + sender, + sender_subidentity, + receiver, + '', + inboxId, + inboxName, + ); - const message = JSON.parse(messageString); + const message = JSON.parse(messageString); - const response = await fetch( - urlJoin(nodeAddress, '/v1/update_smart_inbox_name'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); - const data = await response.json(); - await handleHttpError(response); - return data; - } catch (error) { - console.error('Error updating inbox name:', error); - throw error; - } + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/update_smart_inbox_name'), + message, + + { responseType: 'json' }, + ); + const data = response.data; + return data; }; export const getLastMessagesFromInbox = async ( @@ -296,37 +249,30 @@ export const getLastMessagesFromInbox = async ( lastKey: string | undefined, setupDetailsState: LastMessagesFromInboxCredentialsPayload, ): Promise => { - try { - const messageStr = - ShinkaiMessageBuilderWrapper.get_last_messages_from_inbox( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - inbox, - count, - lastKey, - setupDetailsState.shinkai_identity, - setupDetailsState.profile, - setupDetailsState.shinkai_identity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.get_last_messages_from_inbox( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + inbox, + count, + lastKey, + setupDetailsState.shinkai_identity, + setupDetailsState.profile, + setupDetailsState.shinkai_identity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/last_messages_from_inbox'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); - await handleHttpError(response); - const data = await response.json(); - return data.data; - } catch (error) { - console.error('Error getting last messages from inbox:', error); - throw error; - } + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/last_messages_from_inbox'), + message, + + { + responseType: 'json', + }, + ); + const data = response.data; + return data.data; }; export const submitRequestRegistrationCode = async ( @@ -335,42 +281,36 @@ export const submitRequestRegistrationCode = async ( code_type = 'profile', setupDetailsState: SetupPayload, ): Promise => { - try { - // TODO: refactor the profile name to be a constant - // maybe we should add ShinkaiName and InboxName to the wasm library (just ADDED them this needs refactor) - const sender_profile_name = - setupDetailsState.profile + - '/device/' + - setupDetailsState.registration_name; - - const messageStr = ShinkaiMessageBuilderWrapper.request_code_registration( - setupDetailsState.my_device_encryption_sk, - setupDetailsState.my_device_identity_sk, - setupDetailsState.node_encryption_pk, - identity_permissions, - code_type, - sender_profile_name, - setupDetailsState.shinkai_identity, - ); + // TODO: refactor the profile name to be a constant + // maybe we should add ShinkaiName and InboxName to the wasm library (just ADDED them this needs refactor) + const sender_profile_name = + setupDetailsState.profile + + '/device/' + + setupDetailsState.registration_name; + + const messageStr = ShinkaiMessageBuilderWrapper.request_code_registration( + setupDetailsState.my_device_encryption_sk, + setupDetailsState.my_device_identity_sk, + setupDetailsState.node_encryption_pk, + identity_permissions, + code_type, + sender_profile_name, + setupDetailsState.shinkai_identity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/create_registration_code'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/create_registration_code'), + message, - await handleHttpError(response); - const data = await response.json(); - return data.code; - } catch (error) { - console.error('Error creating registration code:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return data.code; }; export const submitRegistrationCode = async ( @@ -397,20 +337,16 @@ export const submitRegistrationCode = async ( const message = JSON.parse(messageStr); // Use node_address from setupData for API endpoint - const response = await fetch( + const response = await httpClient.post( urlJoin(setupData.node_address, '/v1/use_registration_code'), + message, { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, + responseType: 'json', }, ); - - await handleHttpError(response); - // Update the API_ENDPOINT after successful registration setupData.node_address; - return response.json(); + return response.data; } catch (error) { console.error('Error using registration code:', error); return undefined; @@ -425,15 +361,13 @@ export const health = async (payload: { is_pristine: boolean; version: string; }> => { - const healthResponse = await fetch( + const healthResponse = await httpClient.get( urlJoin(payload.node_address, '/v1/shinkai_health'), { - method: 'GET', - headers: { 'Content-Type': 'application/json' }, + responseType: 'json', }, ); - await handleHttpError(healthResponse); - const responseData = await healthResponse.json(); + const responseData = healthResponse.data; return responseData; }; @@ -445,15 +379,11 @@ export const submitInitialRegistrationNoCode = async ( }> => { try { // Used to fetch the shinkai identity - const healthResponse = await fetch( + const healthResponse = await httpClient.get( urlJoin(payload.node_address, '/v1/shinkai_health'), - { - method: 'GET', - }, ); - await handleHttpError(healthResponse); const { status, node_name }: { status: 'ok'; node_name: string } = - await healthResponse.json(); + healthResponse.data; if (status !== 'ok') { throw new Error( `Node status error, can't fetch shinkai identity from health ${status} ${node_name}`, @@ -474,19 +404,15 @@ export const submitInitialRegistrationNoCode = async ( const message = JSON.parse(messageStr); // Use node_address from setupData for API endpoint - const response = await fetch( + const response = await httpClient.post( urlJoin(payload.node_address, '/v1/use_registration_code'), + message, { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, + responseType: 'json', }, ); - - await handleHttpError(response); - // Update the API_ENDPOINT after successful registration - const data = await response.json(); + const data = response.data; return { success: true, data }; } catch (error) { console.error('Error in initial registration:', error); @@ -495,17 +421,9 @@ export const submitInitialRegistrationNoCode = async ( }; export const pingAllNodes = async (nodeAddress: string): Promise => { - try { - const response = await fetch(urlJoin(nodeAddress, '/ping_all'), { - method: 'POST', - }); - await handleHttpError(response); - const data = await response.json(); - return data.result; - } catch (error) { - console.error('Error pinging all nodes:', error); - throw error; - } + const response = await httpClient.post(urlJoin(nodeAddress, '/ping_all')); + const data = response.data; + return data.result; }; export const createJob = async ( @@ -518,33 +436,30 @@ export const createJob = async ( receiver_subidentity: string, setupDetailsState: JobCredentialsPayload, ): Promise => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.job_creation( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - scope, - is_hidden, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.job_creation( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + scope, + is_hidden, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch(urlJoin(nodeAddress, '/v1/create_job'), { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }); - await handleHttpError(response); - const data = await response.json(); - return data.data; - } catch (error) { - console.error('Error creating job:', error); - throw error; - } + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/create_job'), + message, + + { + responseType: 'json', + }, + ); + const data = response.data; + return data.data; }; export const sendMessageToJob = async ( nodeAddress: string, @@ -563,35 +478,32 @@ export const sendMessageToJob = async ( inbox: string; scheduled_time: string; }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.job_message( - jobId, - content, - files_inbox, - parent || '', - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.job_message( + jobId, + content, + files_inbox, + parent || '', + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch(urlJoin(nodeAddress, '/v1/job_message'), { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }); - await handleHttpError(response); - const data = await response.json(); - return data.data; - } catch (error) { - console.error('Error sending message to job:', error); - throw error; - } + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/job_message'), + message, + + { + responseType: 'json', + }, + ); + const data = response.data; + return data.data; }; export const getProfileAgents = async ( @@ -601,33 +513,29 @@ export const getProfileAgents = async ( receiver: string, setupDetailsState: CredentialsPayload, ): Promise => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.get_profile_agents( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - sender, - sender_subidentity, - receiver, - ); + const messageStr = ShinkaiMessageBuilderWrapper.get_profile_agents( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + sender, + sender_subidentity, + receiver, + ); - const message = JSON.parse(messageStr); - console.log('Get Profile Agents Message:', message); - const messageHash = calculateMessageHash(message); - console.log('Get Profile Agents Message Hash:', messageHash); - - const response = await fetch(urlJoin(nodeAddress, '/v1/available_agents'), { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }); - await handleHttpError(response); - const data = await response.json(); - return data.data; - } catch (error) { - console.error('Error sending message to job:', error); - throw error; - } + const message = JSON.parse(messageStr); + console.log('Get Profile Agents Message:', message); + const messageHash = calculateMessageHash(message); + console.log('Get Profile Agents Message Hash:', messageHash); + + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/available_agents'), + message, + { + responseType: 'json', + }, + ); + const data = response.data; + return data.data; }; export const addAgent = async ( @@ -637,32 +545,29 @@ export const addAgent = async ( agent: SerializedAgent, setupDetailsState: AgentCredentialsPayload, ) => { - try { - const agent_wrapped = SerializedAgentWrapper.fromSerializedAgent(agent); - const messageStr = ShinkaiMessageBuilderWrapper.request_add_agent( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - node_name, - sender_subidentity, - node_name, - agent_wrapped, - ); + const agent_wrapped = SerializedAgentWrapper.fromSerializedAgent(agent); + const messageStr = ShinkaiMessageBuilderWrapper.request_add_agent( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + node_name, + sender_subidentity, + node_name, + agent_wrapped, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch(urlJoin(nodeAddress, '/v1/add_agent'), { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }); - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error sending message to add agent:', error); - throw error; - } + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/add_agent'), + message, + + { + responseType: 'json', + }, + ); + const data = response.data; + return data; }; export const getFileNames = async ( @@ -678,37 +583,31 @@ export const getFileNames = async ( inboxId: string, fileInbox: string, ): Promise<{ success: string; data: string[] }> => { - try { - const messageString = - ShinkaiMessageBuilderWrapper.get_filenames_for_file_inbox( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - sender, - sender_subidentity, - receiver, - '', - inboxId, - fileInbox, - ); + const messageString = + ShinkaiMessageBuilderWrapper.get_filenames_for_file_inbox( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + sender, + sender_subidentity, + receiver, + '', + inboxId, + fileInbox, + ); - const message = JSON.parse(messageString); + const message = JSON.parse(messageString); - const response = await fetch( - urlJoin(nodeAddress, '/v1/get_filenames_for_file_inbox'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); - const data = await response.json(); - await handleHttpError(response); - return data; - } catch (error) { - console.error('Error updating inbox name:', error); - throw error; - } + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/get_filenames_for_file_inbox'), + message, + + { + responseType: 'json', + }, + ); + const data = response.data; + return data; }; export const archiveJob = async ( nodeAddress: string, @@ -719,36 +618,30 @@ export const archiveJob = async ( inbox: string, setupDetailsState: CredentialsPayload, ): Promise<{ status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.archive_job( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - inbox, - ); + const messageStr = ShinkaiMessageBuilderWrapper.archive_job( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + inbox, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/update_job_to_finished'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/update_job_to_finished'), + message, - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error archiving job:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return data; }; export const createVRFolder = async ( nodeAddress: string, @@ -760,37 +653,31 @@ export const createVRFolder = async ( path: string = '/', setupDetailsState: CredentialsPayload, ): Promise<{ status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.createFolder( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - folderName, - path, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.createFolder( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + folderName, + path, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/vec_fs/create_folder'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/vec_fs/create_folder'), + message, - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error createVRFolder:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return data; }; export const retrieveVRPathSimplified = async ( nodeAddress: string, @@ -801,41 +688,35 @@ export const retrieveVRPathSimplified = async ( path: string = '/', setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.retrievePathSimplified( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - path, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.retrievePathSimplified( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + path, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/vec_fs/retrieve_path_simplified_json'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/vec_fs/retrieve_path_simplified_json'), + message, - await handleHttpError(response); - const data = await response.json(); - return typeof data?.data === 'string' - ? { - data: JSON.parse(data.data), - status: data.status, - } - : data; - } catch (error) { - console.error('Error retrieveVRPathSimplified:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return typeof data?.data === 'string' + ? { + data: JSON.parse(data.data), + status: data.status, + } + : data; }; export const retrieveVectorSearchSimplified = async ( nodeAddress: string, @@ -847,40 +728,34 @@ export const retrieveVectorSearchSimplified = async ( path: string | null = null, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = - ShinkaiMessageBuilderWrapper.retrieveVectorSearchSimplified( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - searchQuery, - path, - 10, - null, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = + ShinkaiMessageBuilderWrapper.retrieveVectorSearchSimplified( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + searchQuery, + path, + 10, + null, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/vec_fs/retrieve_vector_search_simplified_json'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/vec_fs/retrieve_vector_search_simplified_json'), + message, - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error retrieveVectorSearchSimplified:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return data; }; export const uploadFilesToVR = async ( @@ -928,41 +803,36 @@ export const retrieveVectorResource = async ( path: string = '/', setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.retrieveResource( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - path, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.retrieveResource( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + path, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/vec_fs/retrieve_vector_resource'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/vec_fs/retrieve_vector_resource'), - await handleHttpError(response); - const data = await response.json(); - return typeof data?.data === 'string' - ? { - data: JSON.parse(data.data), - status: data.status, - } - : data; - } catch (error) { - console.error('Error retrieveVectorResource:', error); - throw error; - } + message, + + { + responseType: 'json', + }, + ); + + const data = response.data; + return typeof data?.data === 'string' + ? { + data: JSON.parse(data.data), + status: data.status, + } + : data; }; export const moveFolderVR = async ( nodeAddress: string, @@ -974,37 +844,31 @@ export const moveFolderVR = async ( destionationPath: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.moveFolder( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - originPath, - destionationPath, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.moveFolder( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + originPath, + destionationPath, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/vec_fs/move_folder'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/vec_fs/move_folder'), + message, - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error moveFolderVR:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return data; }; export const copyFolderVR = async ( nodeAddress: string, @@ -1016,37 +880,31 @@ export const copyFolderVR = async ( destionationPath: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.copyFolder( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - originPath, - destionationPath, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.copyFolder( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + originPath, + destionationPath, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/vec_fs/copy_folder'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/vec_fs/copy_folder'), + message, - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error copyFolderVR:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return data; }; export const deleteFolderVR = async ( nodeAddress: string, @@ -1057,36 +915,30 @@ export const deleteFolderVR = async ( folderPath: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.deleteFolder( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - folderPath, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.deleteFolder( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + folderPath, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/vec_fs/remove_folder'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/vec_fs/remove_folder'), + message, - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error deleteFolderVR:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return data; }; export const moveItemVR = async ( nodeAddress: string, @@ -1098,34 +950,31 @@ export const moveItemVR = async ( destionationPath: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.moveItem( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - originPath, - destionationPath, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.moveItem( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + originPath, + destionationPath, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch(urlJoin(nodeAddress, '/v1/vec_fs/move_item'), { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/vec_fs/move_item'), + message, - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error moveItemVR:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return data; }; export const copyItemVR = async ( nodeAddress: string, @@ -1137,34 +986,31 @@ export const copyItemVR = async ( destionationPath: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.copyItem( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - originPath, - destionationPath, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.copyItem( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + originPath, + destionationPath, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch(urlJoin(nodeAddress, '/v1/vec_fs/copy_item'), { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/vec_fs/copy_item'), + message, - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error copyItemVR:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return data; }; export const deleteItemVR = async ( nodeAddress: string, @@ -1175,36 +1021,30 @@ export const deleteItemVR = async ( itemPath: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.deleteItem( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - itemPath, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.deleteItem( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + itemPath, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/vec_fs/remove_item'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/vec_fs/remove_item'), + message, - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error deleteItemVR:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return data; }; export const searchItemsVR = async ( nodeAddress: string, @@ -1216,39 +1056,33 @@ export const searchItemsVR = async ( path: string = '/', setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.searchItems( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - search, - path, - null, - null, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.searchItems( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + search, + path, + null, + null, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/vec_fs/search_items'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/vec_fs/search_items'), + message, - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error retrieveVectorSearchSimplified:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return data; }; export const getAvailableSharedFolders = async ( pageSize?: number, @@ -1256,29 +1090,22 @@ export const getAvailableSharedFolders = async ( priceFilter?: 'paid' | 'free' | 'all', search?: string, ): Promise => { - try { - const queryParams = new URLSearchParams(); - if (pageSize != null) queryParams.append('pageSize', pageSize.toString()); - if (page != null) queryParams.append('page', page.toString()); - if (priceFilter && priceFilter !== 'all') - queryParams.append('price', priceFilter); - if (search) queryParams.append('search', search); - - const response = await fetch( - `https://sepolia-subscription-indexer.shinkai.com/api/v1/shared-items?${queryParams.toString()}`, - { - method: 'GET', - headers: { 'Content-Type': 'application/json' }, - }, - ); + const queryParams = new URLSearchParams(); + if (pageSize != null) queryParams.append('pageSize', pageSize.toString()); + if (page != null) queryParams.append('page', page.toString()); + if (priceFilter && priceFilter !== 'all') + queryParams.append('price', priceFilter); + if (search) queryParams.append('search', search); + + const response = await httpClient.get( + `https://sepolia-subscription-indexer.shinkai.com/api/v1/shared-items?${queryParams.toString()}`, + { + responseType: 'json', + }, + ); - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error getAvailableSharedFolders:', error); - throw error; - } + const data = response.data; + return data; }; export const getMySharedFolders = async ( nodeAddress: string, @@ -1290,42 +1117,36 @@ export const getMySharedFolders = async ( streamer_profile_name: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.getMySharedFolders( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - streamer_node_name, - streamer_profile_name, - ); + const messageStr = ShinkaiMessageBuilderWrapper.getMySharedFolders( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + streamer_node_name, + streamer_profile_name, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/available_shared_items'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/available_shared_items'), + message, - await handleHttpError(response); - const data = await response.json(); - return typeof data?.data === 'string' - ? { - data: JSON.parse(data.data), - status: data.status, - } - : data; - } catch (error) { - console.error('Error getMySharedFolders:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return typeof data?.data === 'string' + ? { + data: JSON.parse(data.data), + status: data.status, + } + : data; }; export const createShareableFolder = async ( @@ -1338,37 +1159,31 @@ export const createShareableFolder = async ( folderDescription: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.createShareableFolder( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - folderPath, - folderDescription, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.createShareableFolder( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + folderPath, + folderDescription, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/create_shareable_folder'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/create_shareable_folder'), + message, - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error createShareableFolder:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return data; }; export const unshareFolder = async ( nodeAddress: string, @@ -1379,33 +1194,30 @@ export const unshareFolder = async ( folderPath: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.unshareFolder( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - folderPath, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.unshareFolder( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + folderPath, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch(urlJoin(nodeAddress, '/v1/unshare_folder'), { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/unshare_folder'), + message, - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error createShareableFolder:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return data; }; export const subscribeToSharedFolder = async ( nodeAddress: string, @@ -1418,38 +1230,32 @@ export const subscribeToSharedFolder = async ( streamer_profile_name: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.subscribeToSharedFolder( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - path, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - streamer_node_name, - streamer_profile_name, - ); + const messageStr = ShinkaiMessageBuilderWrapper.subscribeToSharedFolder( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + path, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + streamer_node_name, + streamer_profile_name, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/subscribe_to_shared_folder'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/subscribe_to_shared_folder'), + message, - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error createShareableFolder:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return data; }; export const unsubscribeToSharedFolder = async ( nodeAddress: string, @@ -1462,35 +1268,32 @@ export const unsubscribeToSharedFolder = async ( streamer_profile_name: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.unsubscribeToSharedFolder( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - path, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - streamer_node_name, - streamer_profile_name, - ); + const messageStr = ShinkaiMessageBuilderWrapper.unsubscribeToSharedFolder( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + path, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + streamer_node_name, + streamer_profile_name, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch(urlJoin(nodeAddress, '/v1/unsubscribe'), { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/unsubscribe'), + message, - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error createShareableFolder:', error); - throw error; - } + { + responseType: 'json', + }, + ); + + const data = response.data; + return data; }; export const getMySubscriptions = async ( nodeAddress: string, @@ -1500,37 +1303,34 @@ export const getMySubscriptions = async ( receiver_subidentity: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.getMySubscriptions( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.getMySubscriptions( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch(urlJoin(nodeAddress, '/v1/my_subscriptions'), { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }); - - await handleHttpError(response); - const data = await response.json(); - return typeof data?.data === 'string' - ? { - data: JSON.parse(data.data), - status: data.status, - } - : data; - } catch (error) { - console.error('Error getMySubscriptions:', error); - throw error; - } + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/my_subscriptions'), + message, + + { + responseType: 'json', + }, + ); + + const data = response.data; + return typeof data?.data === 'string' + ? { + data: JSON.parse(data.data), + status: data.status, + } + : data; }; export const updateNodeName = async ( @@ -1542,35 +1342,29 @@ export const updateNodeName = async ( receiver_subidentity: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.updateNodeName( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - newNodeName, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.updateNodeName( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + newNodeName, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/change_nodes_name'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error updateNodeName:', error); - throw error; - } + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/change_nodes_name'), + message, + + { + responseType: 'json', + }, + ); + const data = response.data; + return data; }; export const downloadVectorResource = async ( nodeAddress: string, @@ -1581,32 +1375,29 @@ export const downloadVectorResource = async ( receiver_subidentity: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.downloadVectorResource( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - path, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.downloadVectorResource( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + path, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch(urlJoin(nodeAddress, '/v1/retrieve_vrkai'), { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }); - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error downloadVectorResource:', error); - throw error; - } + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/retrieve_vrkai'), + message, + + { + responseType: 'json', + }, + ); + const data = response.data; + return data; }; export const updateAgent = async ( nodeAddress: string, @@ -1617,34 +1408,31 @@ export const updateAgent = async ( receiver_subidentity: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const agent_wrapped = SerializedAgentWrapper.fromSerializedAgent(agent); + const agent_wrapped = SerializedAgentWrapper.fromSerializedAgent(agent); + + const messageStr = ShinkaiMessageBuilderWrapper.modifyAgent( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + agent_wrapped, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const messageStr = ShinkaiMessageBuilderWrapper.modifyAgent( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - agent_wrapped, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const message = JSON.parse(messageStr); - const message = JSON.parse(messageStr); + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/modify_agent'), + message, - const response = await fetch(urlJoin(nodeAddress, '/v1/modify_agent'), { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }); - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error modifyAgent:', error); - throw error; - } + { + responseType: 'json', + }, + ); + const data = response.data; + return data; }; export const deleteAgent = async ( nodeAddress: string, @@ -1655,32 +1443,29 @@ export const deleteAgent = async ( receiver_subidentity: string, setupDetailsState: CredentialsPayload, ): Promise<{ data: any; status: string }> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.deleteAgent( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - agentId, - sender, - sender_subidentity, - receiver, - receiver_subidentity, - ); + const messageStr = ShinkaiMessageBuilderWrapper.deleteAgent( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + agentId, + sender, + sender_subidentity, + receiver, + receiver_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch(urlJoin(nodeAddress, '/v1/remove_agent'), { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }); - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error modifyAgent:', error); - throw error; - } + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/remove_agent'), + message, + + { + responseType: 'json', + }, + ); + const data = response.data; + return data; }; export const scanOllamaModels = async ( @@ -1689,34 +1474,28 @@ export const scanOllamaModels = async ( node_name: string, setupDetailsState: CredentialsPayload, ): Promise<{ model: string }[]> => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.scanOllamaModels( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - node_name, - sender_subidentity, - node_name, - '', - ); + const messageStr = ShinkaiMessageBuilderWrapper.scanOllamaModels( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + node_name, + sender_subidentity, + node_name, + '', + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/scan_ollama_models'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error sending message to add agent:', error); - throw error; - } + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/scan_ollama_models'), + message, + + { + responseType: 'json', + }, + ); + const data = response.data; + return data; }; export const addOllamaModels = async ( @@ -1726,33 +1505,27 @@ export const addOllamaModels = async ( setupDetailsState: CredentialsPayload, payload: { models: string[] }, ) => { - try { - const messageStr = ShinkaiMessageBuilderWrapper.addOllamaModels( - setupDetailsState.profile_encryption_sk, - setupDetailsState.profile_identity_sk, - setupDetailsState.node_encryption_pk, - nodeName, - senderSubidentity, - nodeName, - senderSubidentity, - payload, - ); + const messageStr = ShinkaiMessageBuilderWrapper.addOllamaModels( + setupDetailsState.profile_encryption_sk, + setupDetailsState.profile_identity_sk, + setupDetailsState.node_encryption_pk, + nodeName, + senderSubidentity, + nodeName, + senderSubidentity, + payload, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch( - urlJoin(nodeAddress, '/v1/add_ollama_models'), - { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }, - ); - await handleHttpError(response); - const data = await response.json(); - return data; - } catch (error) { - console.error('Error sending message to add agent:', error); - throw error; - } + const response = await httpClient.post( + urlJoin(nodeAddress, '/v1/add_ollama_models'), + message, + + { + responseType: 'json', + }, + ); + const data = response.data; + return data; }; diff --git a/libs/shinkai-message-ts/src/cryptography/shinkai-encryption.test.ts b/libs/shinkai-message-ts/src/cryptography/shinkai-encryption.test.ts index 20c14147f..a42b500e0 100644 --- a/libs/shinkai-message-ts/src/cryptography/shinkai-encryption.test.ts +++ b/libs/shinkai-message-ts/src/cryptography/shinkai-encryption.test.ts @@ -1,25 +1,28 @@ -import * as sodium from "libsodium-wrappers-sumo"; +import * as sodium from 'libsodium-wrappers-sumo'; -import { decryptMessageWithPassphrase,encryptMessageWithPassphrase } from './shinkai-encryption'; +import { + decryptMessageWithPassphrase, + encryptMessageWithPassphrase, +} from './shinkai-encryption'; -test("encrypt and decrypt message with passphrase", async () => { +test('encrypt and decrypt message with passphrase', async () => { await sodium.ready; // Ensure sodium is fully loaded - const originalMessage = "Hello, world!"; - const passphrase = "my secret passphrase"; + const originalMessage = 'Hello, world!'; + const passphrase = 'my secret passphrase'; // Encrypt the message const encryptedMessage = await encryptMessageWithPassphrase( originalMessage, - passphrase + passphrase, ); // Decrypt the message const decryptedMessage = await decryptMessageWithPassphrase( encryptedMessage, - passphrase + passphrase, ); // The decrypted message should be the same as the original message expect(decryptedMessage).toBe(originalMessage); -}); \ No newline at end of file +}); diff --git a/libs/shinkai-message-ts/src/cryptography/shinkai-encryption.ts b/libs/shinkai-message-ts/src/cryptography/shinkai-encryption.ts index 3eedbac88..b86364a74 100644 --- a/libs/shinkai-message-ts/src/cryptography/shinkai-encryption.ts +++ b/libs/shinkai-message-ts/src/cryptography/shinkai-encryption.ts @@ -1,8 +1,8 @@ -import * as sodium from "libsodium-wrappers-sumo"; +import * as sodium from 'libsodium-wrappers-sumo'; export async function encryptMessageWithPassphrase( message: string, - passphrase: string + passphrase: string, ): Promise { await sodium.ready; @@ -13,18 +13,18 @@ export async function encryptMessageWithPassphrase( salt, sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE, - sodium.crypto_pwhash_ALG_DEFAULT + sodium.crypto_pwhash_ALG_DEFAULT, ); const nonce = sodium.randombytes_buf( - sodium.crypto_aead_chacha20poly1305_IETF_NPUBBYTES + sodium.crypto_aead_chacha20poly1305_IETF_NPUBBYTES, ); const ciphertext = sodium.crypto_aead_chacha20poly1305_ietf_encrypt( message, null, null, nonce, - key + key, ); const encrypted_body = @@ -34,13 +34,13 @@ export async function encryptMessageWithPassphrase( export async function decryptMessageWithPassphrase( encryptedBody: string, - passphrase: string + passphrase: string, ): Promise { await sodium.ready; - const parts: string[] = encryptedBody.split(":"); - if (parts[0] !== "encrypted") { - throw new Error("Unexpected variant"); + const parts: string[] = encryptedBody.split(':'); + if (parts[0] !== 'encrypted') { + throw new Error('Unexpected variant'); } const content = parts[1]; @@ -51,7 +51,7 @@ export async function decryptMessageWithPassphrase( salt, sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE, - sodium.crypto_pwhash_ALG_DEFAULT + sodium.crypto_pwhash_ALG_DEFAULT, ); const nonce = sodium.from_hex(content.slice(32, 56)); @@ -63,16 +63,16 @@ export async function decryptMessageWithPassphrase( ciphertext, null, nonce, - key + key, ); const decrypted_body = sodium.to_string(plaintext_bytes); return decrypted_body; } catch (e) { if (e instanceof Error) { console.error(e.message); - throw new Error("Decryption failure!: " + e.message); + throw new Error('Decryption failure!: ' + e.message); } else { - throw new Error("Decryption failure!"); + throw new Error('Decryption failure!'); } } -} \ No newline at end of file +} diff --git a/libs/shinkai-message-ts/src/http-client.ts b/libs/shinkai-message-ts/src/http-client.ts new file mode 100644 index 000000000..d8cff502e --- /dev/null +++ b/libs/shinkai-message-ts/src/http-client.ts @@ -0,0 +1,5 @@ +import axios from "axios"; + +export const httpClient = axios.create({ + timeout: 2 * 60 * 1000, // 2 minutes +}); diff --git a/libs/shinkai-message-ts/src/index.ts b/libs/shinkai-message-ts/src/index.ts index 262a96c5d..9c442e41e 100644 --- a/libs/shinkai-message-ts/src/index.ts +++ b/libs/shinkai-message-ts/src/index.ts @@ -1,6 +1,6 @@ -import * as api from "./api"; -import * as cryptography from "./cryptography/shinkai-encryption"; -import * as models from "./models"; -import * as utils from "./utils"; -import * as wasm from "./utils"; +import * as api from './api'; +import * as cryptography from './cryptography/shinkai-encryption'; +import * as models from './models'; +import * as utils from './utils'; +import * as wasm from './utils'; export { api, models, utils, wasm, cryptography }; diff --git a/libs/shinkai-message-ts/src/models.ts b/libs/shinkai-message-ts/src/models.ts index de6838373..778805492 100644 --- a/libs/shinkai-message-ts/src/models.ts +++ b/libs/shinkai-message-ts/src/models.ts @@ -1,4 +1,4 @@ export * from './models/SchemaTypes'; export * from './models/Payloads'; export * from './models/ShinkaiMessage'; -export * from './models/QRSetupData'; \ No newline at end of file +export * from './models/QRSetupData'; diff --git a/libs/shinkai-message-ts/src/utils/inbox_name_handler.test.ts b/libs/shinkai-message-ts/src/utils/inbox_name_handler.test.ts index 9d846d4b4..7e95a159a 100644 --- a/libs/shinkai-message-ts/src/utils/inbox_name_handler.test.ts +++ b/libs/shinkai-message-ts/src/utils/inbox_name_handler.test.ts @@ -1,38 +1,65 @@ import { assert, suite } from 'vitest'; -import { extractReceiverShinkaiName, getOtherPersonIdentity, ShinkaiNameError } from './inbox_name_handler'; +import { + extractReceiverShinkaiName, + getOtherPersonIdentity, + ShinkaiNameError, +} from './inbox_name_handler'; suite('extractReceiverShinkaiName', () => { test('returns correct receiver name', () => { const result = extractReceiverShinkaiName( 'inbox::@@node1.shinkai/main::@@node1.shinkai/main/device/main_device::false', - '@@node1.shinkai' + '@@node1.shinkai', + ); + assert.equal( + result, + '@@node1.shinkai', + 'Returned the correct receiver name', ); - assert.equal(result, '@@node1.shinkai', 'Returned the correct receiver name'); }); test('throws error for invalid format (too few parts)', () => { - assert.throws(() => { - extractReceiverShinkaiName('inbox::@@node1.shinkai', '@@node1.shinkai'); - }, ShinkaiNameError, 'InvalidFormat'); + assert.throws( + () => { + extractReceiverShinkaiName('inbox::@@node1.shinkai', '@@node1.shinkai'); + }, + ShinkaiNameError, + 'InvalidFormat', + ); }); test('throws error for invalid format (too many parts)', () => { - assert.throws(() => { - extractReceiverShinkaiName('inbox::' + '@@node1.shinkai::'.repeat(100), '@@node1.shinkai'); - }, ShinkaiNameError, 'InvalidFormat'); + assert.throws( + () => { + extractReceiverShinkaiName( + 'inbox::' + '@@node1.shinkai::'.repeat(100), + '@@node1.shinkai', + ); + }, + ShinkaiNameError, + 'InvalidFormat', + ); }); test('throws error for invalid format (regex mismatch)', () => { - assert.throws(() => { - extractReceiverShinkaiName('inbox::@@invalid_node/main::@@node1.shinkai/main/device/main_device::false', '@@node1.shinkai'); - }, ShinkaiNameError, 'InvalidFormat'); + assert.throws( + () => { + extractReceiverShinkaiName( + 'inbox::@@invalid_node/main::@@node1.shinkai/main/device/main_device::false', + '@@node1.shinkai', + ); + }, + ShinkaiNameError, + 'InvalidFormat', + ); }); }); describe('getOtherPersonIdentity', () => { it('should return the other person identity', () => { - const inboxName = 'inbox::@@node1.shinkai/main::@@node1.shinkai/main/device/main_device::false'; + const inboxName = + 'inbox::@@node1.shinkai/main::@@node1.shinkai/main/device/main_device::false'; const myIdentity = '@@node1.shinkai/main/device/main_device'; const expectedIdentity = '@@node1.shinkai/main'; 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 9390dac40..62eb522b0 100644 --- a/libs/shinkai-message-ts/src/utils/inbox_name_handler.ts +++ b/libs/shinkai-message-ts/src/utils/inbox_name_handler.ts @@ -1,40 +1,45 @@ export class ShinkaiNameError extends Error { - constructor(public type: "InvalidFormat" | "ReceiverNotFound") { + constructor(public type: 'InvalidFormat' | 'ReceiverNotFound') { super(`Shinkai Name Error: ${type}`); - this.name = "ShinkaiNameError"; + this.name = 'ShinkaiNameError'; Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain } } -export const getOtherPersonIdentity = (inboxName: string, myIdentity: string) => { - const parts = inboxName.split("::"); - const otherPersonIdentity = parts.filter(part => part !== myIdentity && part !== 'inbox' && part !== 'false'); +export const getOtherPersonIdentity = ( + inboxName: string, + myIdentity: string, +) => { + const parts = inboxName.split('::'); + const otherPersonIdentity = parts.filter( + (part) => part !== myIdentity && part !== 'inbox' && part !== 'false', + ); return otherPersonIdentity[0]; }; export const extractReceiverShinkaiName = ( deserializedId: string, - senderShinkaiName: string + senderShinkaiName: string, ): string => { - const parts: string[] = deserializedId.split("::"); + const parts: string[] = deserializedId.split('::'); if (parts.length < 3 || parts.length > 101) { - throw new ShinkaiNameError("InvalidFormat"); + throw new ShinkaiNameError('InvalidFormat'); } const nodeRegex = /^@@[a-zA-Z0-9_]+\.shinkai.*$/; - let receiverShinkaiName = ""; + let receiverShinkaiName = ''; let hasSeenSender = false; for (let i = 1; i < parts.length - 1; i++) { - const part = parts[i].split("/")[0]; // Extract base part of the shinkai name + const part = parts[i].split('/')[0]; // Extract base part of the shinkai name if (!nodeRegex.test(part)) { - throw new ShinkaiNameError("InvalidFormat"); + throw new ShinkaiNameError('InvalidFormat'); } // Skip the sender's shinkai name if (part === senderShinkaiName && hasSeenSender === false) { - hasSeenSender = true; - continue; + hasSeenSender = true; + continue; } // Assign the receiver's shinkai name and break the loop @@ -42,17 +47,17 @@ export const extractReceiverShinkaiName = ( break; } - if (receiverShinkaiName === "") { - throw new ShinkaiNameError("ReceiverNotFound"); + if (receiverShinkaiName === '') { + throw new ShinkaiNameError('ReceiverNotFound'); } return receiverShinkaiName; }; export const extractJobIdFromInbox = (deserializedId: string): string => { - const parts: string[] = deserializedId.split("::"); + const parts: string[] = deserializedId.split('::'); if (parts.length < 3 || !isJobInbox(deserializedId)) { - throw new ShinkaiNameError("InvalidFormat"); + throw new ShinkaiNameError('InvalidFormat'); } const jobId = parts[1]; @@ -60,14 +65,14 @@ export const extractJobIdFromInbox = (deserializedId: string): string => { }; export const isJobInbox = (inboxId: string): boolean => { - const parts: string[] = inboxId.split("::"); + const parts: string[] = inboxId.split('::'); if (parts.length < 3) { - throw new ShinkaiNameError("InvalidFormat"); + throw new ShinkaiNameError('InvalidFormat'); } 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-message-ts/src/utils/shinkai_message_handler.test.ts b/libs/shinkai-message-ts/src/utils/shinkai_message_handler.test.ts index fc0313b42..750e577b2 100644 --- a/libs/shinkai-message-ts/src/utils/shinkai_message_handler.test.ts +++ b/libs/shinkai-message-ts/src/utils/shinkai_message_handler.test.ts @@ -58,7 +58,7 @@ describe('shinkai_messag_handler isLocalMessage', () => { "encryption": "None", "version": "V1_0" }`; - + const messageSentByNode1AgentGpt = `{ "body": { "unencrypted": { @@ -123,25 +123,41 @@ describe('shinkai_messag_handler isLocalMessage', () => { }; it('false when message was sent by agent', () => { const message = JSON.parse(messageSentByNode1AgentGpt); - const isLocal = isLocalMessage(message, myNodeSetup.myNodeIdentity, myNodeSetup.myProfile); + const isLocal = isLocalMessage( + message, + myNodeSetup.myNodeIdentity, + myNodeSetup.myProfile, + ); expect(isLocal).toBe(false); }); it('false when message was sent by a different node', () => { const message = JSON.parse(messageSentByNode2MainDevice); - const isLocal = isLocalMessage(message, myNodeSetup.myNodeIdentity, myNodeSetup.myProfile); + const isLocal = isLocalMessage( + message, + myNodeSetup.myNodeIdentity, + myNodeSetup.myProfile, + ); expect(isLocal).toBe(false); }); it('true when message was sent by same node', () => { const message = JSON.parse(messageSentByNode1MainDevice); - const isLocal = isLocalMessage(message, myNodeSetup.myNodeIdentity, myNodeSetup.myProfile); + const isLocal = isLocalMessage( + message, + myNodeSetup.myNodeIdentity, + myNodeSetup.myProfile, + ); expect(isLocal).toBe(true); }); it('true when message was sent by same node but different device', () => { const message = JSON.parse(messageSentByNode1SecondaryDevice); - const isLocal = isLocalMessage(message, myNodeSetup.myNodeIdentity, myNodeSetup.myProfile); + const isLocal = isLocalMessage( + message, + myNodeSetup.myNodeIdentity, + myNodeSetup.myProfile, + ); expect(isLocal).toBe(true); }); }); diff --git a/libs/shinkai-message-ts/src/utils/url-join.test.ts b/libs/shinkai-message-ts/src/utils/url-join.test.ts index b541fdafd..4e65e7b9f 100644 --- a/libs/shinkai-message-ts/src/utils/url-join.test.ts +++ b/libs/shinkai-message-ts/src/utils/url-join.test.ts @@ -3,17 +3,38 @@ import { urlJoin } from './url-join'; describe('url join', () => { const sharedExpectedValue = 'localhost:5555/api/v1/send'; const cases = [ - { data: ['localhost:5555', 'api', 'v1/send'], expectedValue: sharedExpectedValue }, - { data: ['localhost:5555/', '/api/', 'v1/send/'], expectedValue: sharedExpectedValue }, - { data: ['localhost:5555///', 'api//', '/v1/send'], expectedValue: sharedExpectedValue }, - { data: ['localhost:5555', 'api//', '//v1/send/'], expectedValue: sharedExpectedValue }, - { data: ['localhost:5555', 'api//', '//v1/send?foo=bar/bar2'], expectedValue: `${sharedExpectedValue}?foo=bar/bar2` }, + { + data: ['localhost:5555', 'api', 'v1/send'], + expectedValue: sharedExpectedValue, + }, + { + data: ['localhost:5555/', '/api/', 'v1/send/'], + expectedValue: sharedExpectedValue, + }, + { + data: ['localhost:5555///', 'api//', '/v1/send'], + expectedValue: sharedExpectedValue, + }, + { + data: ['localhost:5555', 'api//', '//v1/send/'], + expectedValue: sharedExpectedValue, + }, + { + data: ['localhost:5555', 'api//', '//v1/send?foo=bar/bar2'], + expectedValue: `${sharedExpectedValue}?foo=bar/bar2`, + }, { data: ['localhost:5555', '/', ''], expectedValue: 'localhost:5555' }, { data: ['localhost:5555'], expectedValue: 'localhost:5555' }, - { data: ['https://google.com/', 'auth/', 'foo'], expectedValue: 'https://google.com/auth/foo' }, + { + data: ['https://google.com/', 'auth/', 'foo'], + expectedValue: 'https://google.com/auth/foo', + }, ]; - test.each(cases)('should generate a valid url', async ({ data, expectedValue }) => { - const url = urlJoin(...data); - expect(url).toBe(expectedValue); - }); + test.each(cases)( + 'should generate a valid url', + async ({ data, expectedValue }) => { + const url = urlJoin(...data); + expect(url).toBe(expectedValue); + }, + ); }); diff --git a/libs/shinkai-message-ts/src/utils/url-join.ts b/libs/shinkai-message-ts/src/utils/url-join.ts index d9fef3980..99835bbe3 100644 --- a/libs/shinkai-message-ts/src/utils/url-join.ts +++ b/libs/shinkai-message-ts/src/utils/url-join.ts @@ -1,5 +1,8 @@ // It safe join url chunks avoiding double '/' between paths // Warning: It doesn't supports all cases but it's enough for join shinkai-node api urls export const urlJoin = (...chunks: string[]): string => { - return chunks.map(chunk => chunk.replace(/(^\/+|\/+$)/mg, '')).filter(chunk => !!chunk).join('/') + return chunks + .map((chunk) => chunk.replace(/(^\/+|\/+$)/gm, '')) + .filter((chunk) => !!chunk) + .join('/'); }; diff --git a/libs/shinkai-message-ts/src/utils/wasm_helpers.test.ts b/libs/shinkai-message-ts/src/utils/wasm_helpers.test.ts index 871ec9cb5..f47e0683e 100644 --- a/libs/shinkai-message-ts/src/utils/wasm_helpers.test.ts +++ b/libs/shinkai-message-ts/src/utils/wasm_helpers.test.ts @@ -1,8 +1,12 @@ import * as ed from '@noble/ed25519'; import { sha512 } from '@noble/hashes/sha512'; -import { Crypto } from "@peculiar/webcrypto"; +import { Crypto } from '@peculiar/webcrypto'; -import { generateEncryptionKeys, generateSignatureKeys, test_util_generateKeys } from './wasm_helpers'; +import { + generateEncryptionKeys, + generateSignatureKeys, + test_util_generateKeys, +} from './wasm_helpers'; // Enable synchronous methods ed.etc.sha512Sync = (...m) => sha512(ed.etc.concatBytes(...m)); @@ -11,7 +15,6 @@ const crypto = new Crypto(); globalThis.crypto = crypto; describe('Key generation functions', () => { - test('should generate valid encryption keys', async () => { const seed = new Uint8Array(32); const keys = await generateEncryptionKeys(seed); @@ -48,5 +51,4 @@ describe('Key generation functions', () => { expect(typeof keys.my_identity_sk_string).toBe('string'); expect(typeof keys.my_identity_pk_string).toBe('string'); }); - }); diff --git a/libs/shinkai-message-ts/src/utils/wasm_helpers.ts b/libs/shinkai-message-ts/src/utils/wasm_helpers.ts index 765d69450..97eed3e08 100644 --- a/libs/shinkai-message-ts/src/utils/wasm_helpers.ts +++ b/libs/shinkai-message-ts/src/utils/wasm_helpers.ts @@ -1,4 +1,3 @@ - import * as ed from '@noble/ed25519'; import { generateKeyPair } from 'curve25519-js'; @@ -7,12 +6,17 @@ import { calculate_blake3_hash } from '../pkg/shinkai_message_wasm'; type HexString = string; export function toHexString(byteArray: Uint8Array) { - return Array.from(byteArray, function(byte) { - return ('0' + (byte & 0xFF).toString(16)).slice(-2); - }).join('') + return Array.from(byteArray, function (byte) { + return ('0' + (byte & 0xff).toString(16)).slice(-2); + }).join(''); } -export const generateEncryptionKeys = async (seed: Uint8Array): Promise<{my_encryption_sk_string: HexString, my_encryption_pk_string: HexString}> => { +export const generateEncryptionKeys = async ( + seed: Uint8Array, +): Promise<{ + my_encryption_sk_string: HexString; + my_encryption_pk_string: HexString; +}> => { const encryptionKeys = generateKeyPair(seed); const my_encryption_sk_string: string = toHexString(encryptionKeys.private); const my_encryption_pk_string: string = toHexString(encryptionKeys.public); @@ -20,10 +24,13 @@ export const generateEncryptionKeys = async (seed: Uint8Array): Promise<{my_encr return { my_encryption_sk_string, my_encryption_pk_string, - } -} + }; +}; -export const generateSignatureKeys = async (): Promise<{my_identity_sk_string: HexString, my_identity_pk_string: HexString}> => { +export const generateSignatureKeys = async (): Promise<{ + my_identity_sk_string: HexString; + my_identity_pk_string: HexString; +}> => { const privKey = ed.utils.randomPrivateKey(); const pubKey = await ed.getPublicKeyAsync(privKey); @@ -33,10 +40,16 @@ export const generateSignatureKeys = async (): Promise<{my_identity_sk_string: H return { my_identity_sk_string, my_identity_pk_string, - } -} + }; +}; -export const test_util_generateKeys = async (): Promise<{my_encryption_sk_string: HexString, my_encryption_pk_string: HexString, receiver_public_key_string: HexString, my_identity_sk_string: HexString, my_identity_pk_string: HexString}> => { +export const test_util_generateKeys = async (): Promise<{ + my_encryption_sk_string: HexString; + my_encryption_pk_string: HexString; + receiver_public_key_string: HexString; + my_identity_sk_string: HexString; + my_identity_pk_string: HexString; +}> => { const seed = new Uint8Array(32); const encryptionKeys = await generateEncryptionKeys(seed); @@ -45,21 +58,21 @@ export const test_util_generateKeys = async (): Promise<{my_encryption_sk_string return { ...encryptionKeys, receiver_public_key_string: encryptionKeys.my_encryption_pk_string, - ...signatureKeys - } -} + ...signatureKeys, + }; +}; export function mapEncryptionMethod(encryption: string): number { - switch (encryption) { - case "DiffieHellmanChaChaPoly1305": - return 0; - case "None": - return 1; - default: - throw new Error("Unknown encryption method"); - } + switch (encryption) { + case 'DiffieHellmanChaChaPoly1305': + return 0; + case 'None': + return 1; + default: + throw new Error('Unknown encryption method'); } +} - export function calculateBlake3Hash(input: string): string { - return calculate_blake3_hash(input); - } +export function calculateBlake3Hash(input: string): string { + return calculate_blake3_hash(input); +} diff --git a/libs/shinkai-message-ts/src/wasm.ts b/libs/shinkai-message-ts/src/wasm.ts index c2967c48c..2becc0457 100644 --- a/libs/shinkai-message-ts/src/wasm.ts +++ b/libs/shinkai-message-ts/src/wasm.ts @@ -1,8 +1,8 @@ -export * from "./wasm/InboxNameWrapper"; -export * from "./wasm/JobCreationWrapper"; -export * from "./wasm/JobMessageWrapper"; -export * from "./wasm/JobScopeWrapper"; -export * from "./wasm/SerializedAgentWrapper"; -export * from "./wasm/ShinkaiMessageBuilderWrapper"; -export * from "./wasm/ShinkaiMessageWrapper"; -export * from "./wasm/ShinkaiNameWrapper"; +export * from './wasm/InboxNameWrapper'; +export * from './wasm/JobCreationWrapper'; +export * from './wasm/JobMessageWrapper'; +export * from './wasm/JobScopeWrapper'; +export * from './wasm/SerializedAgentWrapper'; +export * from './wasm/ShinkaiMessageBuilderWrapper'; +export * from './wasm/ShinkaiMessageWrapper'; +export * from './wasm/ShinkaiNameWrapper'; diff --git a/libs/shinkai-message-ts/src/wasm/FileUploaderUsingSymmetricKeyManager.ts b/libs/shinkai-message-ts/src/wasm/FileUploaderUsingSymmetricKeyManager.ts index 2dacbd824..be345d392 100644 --- a/libs/shinkai-message-ts/src/wasm/FileUploaderUsingSymmetricKeyManager.ts +++ b/libs/shinkai-message-ts/src/wasm/FileUploaderUsingSymmetricKeyManager.ts @@ -1,5 +1,7 @@ import axios from 'axios'; +import { httpClient } from '../http-client'; +import { ShinkaiMessage } from '../models'; import { calculate_blake3_hash } from '../pkg/shinkai_message_wasm'; import { urlJoin } from '../utils/url-join'; import { InboxNameWrapper } from './InboxNameWrapper'; @@ -63,60 +65,51 @@ export class FileUploader { } async createFolder(): Promise { - try { - const keyData = window.crypto.getRandomValues(new Uint8Array(32)); - this.symmetric_key = await window.crypto.subtle.importKey( - 'raw', - keyData, - 'AES-GCM', - true, - ['encrypt', 'decrypt'], - ); + const keyData = window.crypto.getRandomValues(new Uint8Array(32)); + this.symmetric_key = await window.crypto.subtle.importKey( + 'raw', + keyData, + 'AES-GCM', + true, + ['encrypt', 'decrypt'], + ); - // Export symmetric key - const exportedKey = await window.crypto.subtle.exportKey( - 'raw', - this.symmetric_key, - ); - const exportedKeyArray = new Uint8Array(exportedKey); - const exportedKeyString = Array.from(exportedKeyArray) - .map((b) => b.toString(16).padStart(2, '0')) - .join(''); - - const message = - ShinkaiMessageBuilderWrapper.send_create_files_inbox_with_sym_key( - this.my_encryption_secret_key, - this.my_signature_secret_key, - this.receiver_public_key, - this.job_inbox, - exportedKeyString, - this.sender, - this.sender_subidentity, - this.receiver, - ); - - const response = await fetch( - urlJoin(this.base_url, '/v1/create_files_inbox_with_symmetric_key'), - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: message, - }, + // Export symmetric key + const exportedKey = await window.crypto.subtle.exportKey( + 'raw', + this.symmetric_key, + ); + const exportedKeyArray = new Uint8Array(exportedKey); + const exportedKeyString = Array.from(exportedKeyArray) + .map((b) => b.toString(16).padStart(2, '0')) + .join(''); + + const message = + ShinkaiMessageBuilderWrapper.send_create_files_inbox_with_sym_key( + this.my_encryption_secret_key, + this.my_signature_secret_key, + this.receiver_public_key, + this.job_inbox, + exportedKeyString, + this.sender, + this.sender_subidentity, + this.receiver, ); - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - this.folder_id = await this.calculateHashFromSymmetricKey(); - // return response.text(); + await httpClient.post( + urlJoin(this.base_url, '/v1/create_files_inbox_with_symmetric_key'), + message, + { + headers: { + 'Content-Type': 'application/json', + }, + responseType: 'json', + timeout: 5 * 60 * 1000, // 5 minutes + }, + ); - return this.folder_id; - } catch (error) { - console.error('Error creating folder:', error); - throw error; - } + this.folder_id = await this.calculateHashFromSymmetricKey(); + return this.folder_id; } async uploadEncryptedFile(file: File, filename?: string): Promise { @@ -124,118 +117,97 @@ export class FileUploader { throw new Error('Symmetric key is not set'); } - try { - const iv = window.crypto.getRandomValues(new Uint8Array(12)); - const algorithm = { - name: 'AES-GCM', - iv, - }; - const fileData = await file.arrayBuffer(); - const encryptedFileData = await window.crypto.subtle.encrypt( - algorithm, - this.symmetric_key, - fileData, - ); + const iv = window.crypto.getRandomValues(new Uint8Array(12)); + const algorithm = { + name: 'AES-GCM', + iv, + }; + const fileData = await file.arrayBuffer(); + const encryptedFileData = await window.crypto.subtle.encrypt( + algorithm, + this.symmetric_key, + fileData, + ); - const hash = await this.calculateHashFromSymmetricKey(); - const nonce = Array.from(iv) - .map((b) => b.toString(16).padStart(2, '0')) - .join(''); + const hash = await this.calculateHashFromSymmetricKey(); + const nonce = Array.from(iv) + .map((b) => b.toString(16).padStart(2, '0')) + .join(''); - const formData = new FormData(); - formData.append( - 'file', - new Blob([encryptedFileData]), - filename || file.name, - ); + const formData = new FormData(); + formData.append( + 'file', + new Blob([encryptedFileData]), + filename || file.name, + ); - await fetch( - urlJoin( - this.base_url, - '/v1/add_file_to_inbox_with_symmetric_key', - hash, - nonce, - ), - { - method: 'POST', - body: formData, - }, - ); - } catch (error) { - console.error('Error uploading encrypted file:', error); - throw error; - } + await httpClient.post( + urlJoin( + this.base_url, + '/v1/add_file_to_inbox_with_symmetric_key', + hash, + nonce, + ), + formData, + ); } async finalizeAndSend( content: string, parent: string | null, - ): Promise { - try { - if (!this.job_id) { - throw new Error(`finalizeAndSend: job_id not found`); - } - const messageStr = ShinkaiMessageBuilderWrapper.job_message( - this.job_id, - content, - this.folder_id || '', - parent, - this.my_encryption_secret_key, - this.my_signature_secret_key, - this.receiver_public_key, - this.sender, - this.sender_subidentity, - this.receiver, - this.sender_subidentity, - ); + ): Promise { + if (!this.job_id) { + throw new Error(`finalizeAndSend: job_id not found`); + } + const messageStr = ShinkaiMessageBuilderWrapper.job_message( + this.job_id, + content, + this.folder_id || '', + parent, + this.my_encryption_secret_key, + this.my_signature_secret_key, + this.receiver_public_key, + this.sender, + this.sender_subidentity, + this.receiver, + this.sender_subidentity, + ); - const message = JSON.parse(messageStr); + const message = JSON.parse(messageStr); - const response = await fetch(urlJoin(this.base_url, '/v1/job_message'), { - method: 'POST', - body: JSON.stringify(message), - headers: { 'Content-Type': 'application/json' }, - }); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - return response.text(); - } catch (error) { - console.error('Error finalizing and sending:', error); - throw error; - } + const response = await httpClient.post( + urlJoin(this.base_url, '/v1/job_message'), + message, + { + responseType: 'json', + }, + ); + return response.data; } async finalizeAndAddItemsToDb( destinationPath: string = '/', ): Promise<{ status: string }> { - try { - const messageStr = ShinkaiMessageBuilderWrapper.createItems( - this.my_encryption_secret_key, - this.my_signature_secret_key, - this.receiver_public_key, - destinationPath, - this.folder_id || '', - this.sender, - this.sender_subidentity, - this.receiver, - ); - - const message = JSON.parse(messageStr); + const messageStr = ShinkaiMessageBuilderWrapper.createItems( + this.my_encryption_secret_key, + this.my_signature_secret_key, + this.receiver_public_key, + destinationPath, + this.folder_id || '', + this.sender, + this.sender_subidentity, + this.receiver, + ); - const response = await axios.post( - urlJoin(this.base_url, '/v1/vec_fs/convert_files_and_save_to_folder'), - message, - { - timeout: Number.MAX_SAFE_INTEGER, - headers: { 'Content-Type': 'application/json' }, - }, - ); + const message = JSON.parse(messageStr); - return response.data; - } catch (error) { - console.error('Error finalizing and adding items to DB:', error); - throw error; - } + const response = await axios.post( + urlJoin(this.base_url, '/v1/vec_fs/convert_files_and_save_to_folder'), + message, + { + timeout: Number.MAX_SAFE_INTEGER, + headers: { 'Content-Type': 'application/json' }, + }, + ); + return response.data; } } diff --git a/libs/shinkai-message-ts/src/wasm/InboxNameWrapper.test.ts b/libs/shinkai-message-ts/src/wasm/InboxNameWrapper.test.ts index 2f9241af0..f361a1dd9 100644 --- a/libs/shinkai-message-ts/src/wasm/InboxNameWrapper.test.ts +++ b/libs/shinkai-message-ts/src/wasm/InboxNameWrapper.test.ts @@ -1,27 +1,27 @@ -import { test } from "vitest"; +import { test } from 'vitest'; -import { InboxNameWrapper } from "./InboxNameWrapper"; +import { InboxNameWrapper } from './InboxNameWrapper'; -test("InboxNameWrapper", () => { +test('InboxNameWrapper', () => { const validNames = [ - "inbox::@@node.shinkai::true", - "inbox::@@node1.shinkai/subidentity::false", - "inbox::@@alice.shinkai/profileName/agent/myChatGPTAgent::true", - "inbox::@@alice.shinkai/profileName/device/myPhone::true", - "inbox::@@node1.shinkai/subidentity::@@node2.shinkai/subidentity2::false", - "inbox::@@node1.shinkai/subidentity::@@node2.shinkai/subidentity::@@node3.shinkai/subidentity2::false", + 'inbox::@@node.shinkai::true', + 'inbox::@@node1.shinkai/subidentity::false', + 'inbox::@@alice.shinkai/profileName/agent/myChatGPTAgent::true', + 'inbox::@@alice.shinkai/profileName/device/myPhone::true', + 'inbox::@@node1.shinkai/subidentity::@@node2.shinkai/subidentity2::false', + 'inbox::@@node1.shinkai/subidentity::@@node2.shinkai/subidentity::@@node3.shinkai/subidentity2::false', ]; const invalidNames = [ - "@@node1.shinkai::false", - "inbox::@@node1.shinkai::falsee", - "@@node1.shinkai", - "inbox::@@node1.shinkai", - "inbox::node1::false", - "inbox::node1.shinkai::false", - "inbox::@@node1::false", - "inbox::@@node1.shinkai//subidentity::@@node2.shinkai::false", - "inbox::@@node1/subidentity::false", + '@@node1.shinkai::false', + 'inbox::@@node1.shinkai::falsee', + '@@node1.shinkai', + 'inbox::@@node1.shinkai', + 'inbox::node1::false', + 'inbox::node1.shinkai::false', + 'inbox::@@node1::false', + 'inbox::@@node1.shinkai//subidentity::@@node2.shinkai::false', + 'inbox::@@node1/subidentity::false', ]; for (const name of validNames) { @@ -34,19 +34,19 @@ test("InboxNameWrapper", () => { } }); -test("InboxNameWrapper get_identities", () => { +test('InboxNameWrapper get_identities', () => { const namesWithIdentities = [ { - name: "inbox::@@alice.shinkai/profileName::true", - identity: "@@alice.shinkai/profileName", + name: 'inbox::@@alice.shinkai/profileName::true', + identity: '@@alice.shinkai/profileName', }, { - name: "inbox::@@alice.shinkai/profileName/agent/myChatGPTAgent::true", - identity: "@@alice.shinkai/profilename/agent/mychatgptagent", + name: 'inbox::@@alice.shinkai/profileName/agent/myChatGPTAgent::true', + identity: '@@alice.shinkai/profilename/agent/mychatgptagent', }, { - name: "inbox::@@alice.shinkai/profileName/device/myPhone::true", - identity: "@@alice.shinkai/profilename/device/myphone", + name: 'inbox::@@alice.shinkai/profileName/device/myPhone::true', + identity: '@@alice.shinkai/profilename/device/myphone', }, ]; @@ -56,29 +56,43 @@ test("InboxNameWrapper get_identities", () => { } }); -test("InboxNameWrapper get_regular_inbox_name_from_params", () => { +test('InboxNameWrapper get_regular_inbox_name_from_params', () => { const params = [ { - sender: "@@alice.shinkai", - sender_subidentity: "profileName", - recipient: "@@bob.shinkai", - recipient_subidentity: "profileName", + sender: '@@alice.shinkai', + sender_subidentity: 'profileName', + recipient: '@@bob.shinkai', + recipient_subidentity: 'profileName', is_e2e: true, - expected: "inbox::@@alice.shinkai/profilename::@@bob.shinkai/profilename::true", + expected: + 'inbox::@@alice.shinkai/profilename::@@bob.shinkai/profilename::true', }, ]; - for (const { sender, sender_subidentity, recipient, recipient_subidentity, is_e2e, expected } of params) { - const wrapper = InboxNameWrapper.get_regular_inbox_name_from_params(sender, sender_subidentity, recipient, recipient_subidentity, is_e2e); + for (const { + sender, + sender_subidentity, + recipient, + recipient_subidentity, + is_e2e, + expected, + } of params) { + const wrapper = InboxNameWrapper.get_regular_inbox_name_from_params( + sender, + sender_subidentity, + recipient, + recipient_subidentity, + is_e2e, + ); expect(wrapper.get_value).toBe(expected.toLowerCase()); } }); -test("InboxNameWrapper get_job_inbox_name_from_params", () => { +test('InboxNameWrapper get_job_inbox_name_from_params', () => { const params = [ { - unique_id: "123", - expected: "job_inbox::123::false", + unique_id: '123', + expected: 'job_inbox::123::false', }, ]; diff --git a/libs/shinkai-message-ts/src/wasm/JobMessageWrapper.ts b/libs/shinkai-message-ts/src/wasm/JobMessageWrapper.ts index c52c6c7e4..4484db716 100644 --- a/libs/shinkai-message-ts/src/wasm/JobMessageWrapper.ts +++ b/libs/shinkai-message-ts/src/wasm/JobMessageWrapper.ts @@ -5,7 +5,12 @@ import { JobMessageWrapper as JobMessageWrapperWASM } from '../pkg/shinkai_messa export class JobMessageWrapper { private wasmWrapper: JobMessageWrapperWASM; - constructor(job_id_js: any, content_js: any, files_inbox_js: any, parent: any) { + constructor( + job_id_js: any, + content_js: any, + files_inbox_js: any, + parent: any, + ) { this.wasmWrapper = new JobMessageWrapperWASM( job_id_js, content_js, diff --git a/libs/shinkai-message-ts/src/wasm/SerializedAgentWrapper.test.ts b/libs/shinkai-message-ts/src/wasm/SerializedAgentWrapper.test.ts index ca2875f63..0e32dbec2 100644 --- a/libs/shinkai-message-ts/src/wasm/SerializedAgentWrapper.test.ts +++ b/libs/shinkai-message-ts/src/wasm/SerializedAgentWrapper.test.ts @@ -164,9 +164,18 @@ test('SerializedAgentWrapper with Groq model type', async () => { `groq:${serializedAgent.model['groq'].model_type}`, ); } - expect(agent.toolkit_permissions).toEqual(['groq_permission1', 'groq_permission2']); - expect(agent.storage_bucket_permissions).toEqual(['groq_bucket1', 'groq_bucket2']); - expect(agent.allowed_message_senders).toEqual(['groq_sender1', 'groq_sender2']); + expect(agent.toolkit_permissions).toEqual([ + 'groq_permission1', + 'groq_permission2', + ]); + expect(agent.storage_bucket_permissions).toEqual([ + 'groq_bucket1', + 'groq_bucket2', + ]); + expect(agent.allowed_message_senders).toEqual([ + 'groq_sender1', + 'groq_sender2', + ]); }); test('SerializedAgentWrapper serialization to string for Groq model', async () => { @@ -184,7 +193,8 @@ test('SerializedAgentWrapper serialization to string for Groq model', async () = }; // Convert the SerializedAgent to a SerializedAgentWrapper - const serializedAgentWrapper = SerializedAgentWrapper.fromSerializedAgent(serializedAgent); + const serializedAgentWrapper = + SerializedAgentWrapper.fromSerializedAgent(serializedAgent); // Serialize the SerializedAgentWrapper to a string const serializedString = serializedAgentWrapper.to_json_str(); @@ -194,14 +204,24 @@ test('SerializedAgentWrapper serialization to string for Groq model', async () = // Check that the common fields are correctly serialized expect(parsedObject.id).toBe(serializedAgent.id); - expect(parsedObject.full_identity_name).toBe(serializedAgent.full_identity_name); + expect(parsedObject.full_identity_name).toBe( + serializedAgent.full_identity_name, + ); expect(parsedObject.perform_locally).toBe(serializedAgent.perform_locally); expect(parsedObject.external_url).toBe(serializedAgent.external_url); expect(parsedObject.api_key).toBe(serializedAgent.api_key); if (serializedAgent.model && serializedAgent.model['groq']) { - expect(parsedObject.model).toBe(`groq:${serializedAgent.model['groq'].model_type}`); + expect(parsedObject.model).toBe( + `groq:${serializedAgent.model['groq'].model_type}`, + ); } - expect(parsedObject.toolkit_permissions).toEqual(serializedAgent.toolkit_permissions); - expect(parsedObject.storage_bucket_permissions).toEqual(serializedAgent.storage_bucket_permissions); - expect(parsedObject.allowed_message_senders).toEqual(serializedAgent.allowed_message_senders); + expect(parsedObject.toolkit_permissions).toEqual( + serializedAgent.toolkit_permissions, + ); + expect(parsedObject.storage_bucket_permissions).toEqual( + serializedAgent.storage_bucket_permissions, + ); + expect(parsedObject.allowed_message_senders).toEqual( + serializedAgent.allowed_message_senders, + ); }); diff --git a/libs/shinkai-message-ts/src/wasm/ShinkaiMessageWrapper.test.ts b/libs/shinkai-message-ts/src/wasm/ShinkaiMessageWrapper.test.ts index fd3d2008b..d9c973ef5 100644 --- a/libs/shinkai-message-ts/src/wasm/ShinkaiMessageWrapper.test.ts +++ b/libs/shinkai-message-ts/src/wasm/ShinkaiMessageWrapper.test.ts @@ -31,7 +31,6 @@ const messageJson = `{ "version": "V1_0" }`; - describe('ShinkaiMessageWrapper', () => { it('should correctly convert from and to JSON string', () => { const wrapper = ShinkaiMessageWrapper.from_json_str(messageJson); diff --git a/libs/shinkai-message-ts/src/wasm/ShinkaiNameWrapper.test.ts b/libs/shinkai-message-ts/src/wasm/ShinkaiNameWrapper.test.ts index 6e331581d..859e0cb54 100644 --- a/libs/shinkai-message-ts/src/wasm/ShinkaiNameWrapper.test.ts +++ b/libs/shinkai-message-ts/src/wasm/ShinkaiNameWrapper.test.ts @@ -1,25 +1,25 @@ -import { test } from "vitest"; +import { test } from 'vitest'; -import { ShinkaiNameWrapper } from "./ShinkaiNameWrapper"; +import { ShinkaiNameWrapper } from './ShinkaiNameWrapper'; -test("ShinkaiNameWrapper", () => { +test('ShinkaiNameWrapper', () => { const validNames = [ - "@@alice.shinkai", - "@@alice.shinkai/profileName", - "@@alice.shinkai/profileName/agent/myChatGPTAgent", - "@@alice.shinkai/profileName/device/myPhone", - "@@alice.sepolia-shinkai", - "@@alice.sepolia-shinkai/profileName", - "@@alice.sepolia-shinkai/profileName/agent/myChatGPTAgent", - "@@alice.sepolia-shinkai/profileName/device/myPhone", + '@@alice.shinkai', + '@@alice.shinkai/profileName', + '@@alice.shinkai/profileName/agent/myChatGPTAgent', + '@@alice.shinkai/profileName/device/myPhone', + '@@alice.sepolia-shinkai', + '@@alice.sepolia-shinkai/profileName', + '@@alice.sepolia-shinkai/profileName/agent/myChatGPTAgent', + '@@alice.sepolia-shinkai/profileName/device/myPhone', ]; const invalidNames = [ - "@@alice.shinkai/profileName/myPhone", - "@@al!ce.shinkai", - "@@alice.shinkai//", - "@@node1.shinkai/profile_1.shinkai", - "@@alice.sepolia--shinkai", + '@@alice.shinkai/profileName/myPhone', + '@@al!ce.shinkai', + '@@alice.shinkai//', + '@@node1.shinkai/profile_1.shinkai', + '@@alice.sepolia--shinkai', ]; for (const name of validNames) { @@ -32,19 +32,19 @@ test("ShinkaiNameWrapper", () => { } }); -test("ShinkaiNameWrapper get_profile_name", () => { +test('ShinkaiNameWrapper get_profile_name', () => { const namesWithProfiles = [ { - name: "@@alice.shinkai/profileName", - profile: "@@alice.shinkai/profileName", + name: '@@alice.shinkai/profileName', + profile: '@@alice.shinkai/profileName', }, { - name: "@@alice.shinkai/profileName/agent/myChatGPTAgent", - profile: "@@alice.shinkai/profileName", + name: '@@alice.shinkai/profileName/agent/myChatGPTAgent', + profile: '@@alice.shinkai/profileName', }, { - name: "@@alice.shinkai/profileName/device/myPhone", - profile: "@@alice.shinkai/profileName", + name: '@@alice.shinkai/profileName/device/myPhone', + profile: '@@alice.shinkai/profileName', }, ]; @@ -54,7 +54,7 @@ test("ShinkaiNameWrapper get_profile_name", () => { } }); -test("ShinkaiNameWrapper from_shinkai_message_sender", () => { +test('ShinkaiNameWrapper from_shinkai_message_sender', () => { it('should fail when message is first level encrypted', () => { const encryptedMessage = `{ "body": { @@ -73,7 +73,9 @@ test("ShinkaiNameWrapper from_shinkai_message_sender", () => { "version": "V1_0" }`; const message = JSON.parse(encryptedMessage); - expect(ShinkaiNameWrapper.from_shinkai_message_sender(message)).toThrowError(); + expect( + ShinkaiNameWrapper.from_shinkai_message_sender(message), + ).toThrowError(); }); it('should parse node_name, full_name, subidentity_name and subidentity_type when message is unepcrypted', () => { @@ -106,10 +108,15 @@ test("ShinkaiNameWrapper from_shinkai_message_sender", () => { "version": "V1_0" }`; const message = JSON.parse(messageJson); - const messageNameWrapper = ShinkaiNameWrapper.from_shinkai_message_sender(message); + const messageNameWrapper = + ShinkaiNameWrapper.from_shinkai_message_sender(message); expect(messageNameWrapper.get_node_name).toBe('@@node1.shinkai'); - expect(messageNameWrapper.get_full_name).toBe('@@node1.shinkai/main/device/main_device'); - expect(messageNameWrapper.get_subidentity_name).toBe('main/device/main_device'); + expect(messageNameWrapper.get_full_name).toBe( + '@@node1.shinkai/main/device/main_device', + ); + expect(messageNameWrapper.get_subidentity_name).toBe( + 'main/device/main_device', + ); expect(messageNameWrapper.get_subidentity_type).toBe('device'); }); }); diff --git a/libs/shinkai-message-ts/vite.config.ts b/libs/shinkai-message-ts/vite.config.ts index e8c3cdf87..69af44f58 100644 --- a/libs/shinkai-message-ts/vite.config.ts +++ b/libs/shinkai-message-ts/vite.config.ts @@ -2,7 +2,7 @@ import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'; import { defineConfig } from 'vite'; import dts from 'vite-plugin-dts'; -import topLevelAwait from "vite-plugin-top-level-await"; +import topLevelAwait from 'vite-plugin-top-level-await'; import wasm from 'vite-plugin-wasm'; export default defineConfig({ @@ -15,7 +15,7 @@ export default defineConfig({ models: './src/models.ts', utils: './src/utils.ts', wasm: './src/wasm.ts', - cryptography: './src/cryptography.ts' + cryptography: './src/cryptography.ts', }, formats: ['es'], },