diff --git a/.gitignore b/.gitignore index 711c8b0cc3..cedb6ac0ad 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,7 @@ junit.xml # meilisearch meilisearch +meilisearch.exe data.ms/* auth.json diff --git a/api/models/schema/messageSchema.js b/api/models/schema/messageSchema.js index 6c0c1490a8..792b2d545a 100644 --- a/api/models/schema/messageSchema.js +++ b/api/models/schema/messageSchema.js @@ -25,7 +25,7 @@ const messageSchema = mongoose.Schema( type: String, }, invocationId: { - type: String, + type: Number, }, parentMessageId: { type: String, diff --git a/client/src/components/Endpoints/EndpointOptionsDialog.tsx b/client/src/components/Endpoints/EndpointOptionsDialog.tsx index 79050829e9..ff3efc51a7 100644 --- a/client/src/components/Endpoints/EndpointOptionsDialog.tsx +++ b/client/src/components/Endpoints/EndpointOptionsDialog.tsx @@ -1,7 +1,7 @@ import exportFromJSON from 'export-from-json'; import { useEffect, useState } from 'react'; import { useRecoilValue, useRecoilState } from 'recoil'; -import { EditPresetProps, SetOption, TPreset } from 'librechat-data-provider'; +import { EditPresetProps, SetOption, tPresetSchema } from 'librechat-data-provider'; import { Dialog, DialogButton } from '~/components/ui'; import DialogTemplate from '~/components/ui/DialogTemplate'; import SaveAsPresetDialog from './SaveAsPresetDialog'; @@ -21,12 +21,11 @@ const EndpointOptionsDialog = ({ open, onOpenChange, preset: _preset, title }: E const setOption: SetOption = (param) => (newValue) => { const update = {}; update[param] = newValue; - setPreset( - (prevState) => - ({ - ...prevState, - ...update, - } as TPreset), + setPreset((prevState) => + tPresetSchema.parse({ + ...prevState, + ...update, + }), ); }; diff --git a/client/src/components/Endpoints/SaveAsPresetDialog.tsx b/client/src/components/Endpoints/SaveAsPresetDialog.tsx index b9b81fb846..cd9f535f4e 100644 --- a/client/src/components/Endpoints/SaveAsPresetDialog.tsx +++ b/client/src/components/Endpoints/SaveAsPresetDialog.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import { useRecoilValue } from 'recoil'; -import { useCreatePresetMutation, EditPresetProps, TPreset } from 'librechat-data-provider'; +import { useCreatePresetMutation, EditPresetProps } from 'librechat-data-provider'; import { Dialog, Input, Label } from '~/components/ui/'; import DialogTemplate from '~/components/ui/DialogTemplate'; import { cn, defaultTextPropsLabel, removeFocusOutlines, cleanupPreset } from '~/utils/'; @@ -20,7 +20,7 @@ const SaveAsPresetDialog = ({ open, onOpenChange, preset }: EditPresetProps) => title, }, endpointsConfig, - }) as TPreset; + }); createPresetMutation.mutate(_preset); }; diff --git a/client/src/components/Endpoints/Settings/Examples.tsx b/client/src/components/Endpoints/Settings/Examples.tsx index fd737bfd56..ee697f75be 100644 --- a/client/src/components/Endpoints/Settings/Examples.tsx +++ b/client/src/components/Endpoints/Settings/Examples.tsx @@ -68,14 +68,14 @@ function Examples({ readonly, examples, setExample, addExample, removeExample }:
); }); diff --git a/client/src/components/Nav/Nav.tsx b/client/src/components/Nav/Nav.tsx index 97cd37e792..00c7eab91c 100644 --- a/client/src/components/Nav/Nav.tsx +++ b/client/src/components/Nav/Nav.tsx @@ -7,6 +7,7 @@ import { import { useCallback, useEffect, useRef, useState } from 'react'; import { useRecoilValue, useSetRecoilState } from 'recoil'; import NewChat from './NewChat'; +import SearchBar from './SearchBar'; import NavLinks from './NavLinks'; import { Panel, Spinner } from '~/components'; import { Conversations, Pages } from '../Conversations'; @@ -166,7 +167,7 @@ export default function Nav({ navVisible, setNavVisible }) {
diff --git a/client/src/components/Nav/NavLinks.jsx b/client/src/components/Nav/NavLinks.jsx index 6d5bd81332..bdb15ea9e1 100644 --- a/client/src/components/Nav/NavLinks.jsx +++ b/client/src/components/Nav/NavLinks.jsx @@ -2,20 +2,19 @@ import { Download } from 'lucide-react'; import { useRecoilValue } from 'recoil'; import { Fragment, useState } from 'react'; import { Menu, Transition } from '@headlessui/react'; -import SearchBar from './SearchBar'; import ClearConvos from './ClearConvos'; import Settings from './Settings'; import NavLink from './NavLink'; import Logout from './Logout'; import { ExportModel } from './ExportConversation'; -import { LinkIcon, DotsIcon, GearIcon, TrashIcon } from '~/components'; +import { LinkIcon, DotsIcon, GearIcon } from '~/components'; import { localize } from '~/localization/Translation'; import { useAuthContext } from '~/hooks/AuthContext'; import { cn } from '~/utils/'; import store from '~/store'; -export default function NavLinks({ clearSearch, isSearchEnabled }) { +export default function NavLinks() { const [showExports, setShowExports] = useState(false); const [showClearConvos, setShowClearConvos] = useState(false); const [showSettings, setShowSettings] = useState(false); @@ -76,11 +75,6 @@ export default function NavLinks({ clearSearch, isSearchEnabled }) { leaveTo="transform opacity-0 scale-95" > - {isSearchEnabled && ( - - - - )}
- - } - text={localize(lang, 'com_nav_clear_conversation')} - clickHandler={() => setShowClearConvos(true)} - /> - { return (
{} - ({ - ...prevState, - tools, - } as TConversation), + setConversation((prevState) => + tConversationSchema.parse({ + ...prevState, + tools, + }), ); }, }, diff --git a/client/src/components/Plugins/Store/PluginTooltip.tsx b/client/src/components/Plugins/Store/PluginTooltip.tsx index 5e0d38dbf2..0a7df905b2 100644 --- a/client/src/components/Plugins/Store/PluginTooltip.tsx +++ b/client/src/components/Plugins/Store/PluginTooltip.tsx @@ -11,9 +11,9 @@ function PluginTooltip({ content, position }: TPluginTooltipProps) {
-

+

-

+
diff --git a/client/src/components/ui/Dropdown.jsx b/client/src/components/ui/Dropdown.jsx index ed0cb9a02a..d31a8cb39a 100644 --- a/client/src/components/ui/Dropdown.jsx +++ b/client/src/components/ui/Dropdown.jsx @@ -12,7 +12,7 @@ function Dropdown({ value, onChange, options, className, containerClassName }) { diff --git a/client/src/components/ui/MultiSelectDropDown.tsx b/client/src/components/ui/MultiSelectDropDown.tsx index 8d727451bb..c4476586c3 100644 --- a/client/src/components/ui/MultiSelectDropDown.tsx +++ b/client/src/components/ui/MultiSelectDropDown.tsx @@ -43,7 +43,7 @@ function MultiSelectDropDown({ <> diff --git a/client/src/components/ui/Tabs.tsx b/client/src/components/ui/Tabs.tsx index db13fde848..83645e9a5b 100644 --- a/client/src/components/ui/Tabs.tsx +++ b/client/src/components/ui/Tabs.tsx @@ -10,7 +10,7 @@ const Tabs = TabsPrimitive.Root; const TabsList = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( +>(({ className = '', ...props }, ref) => ( , React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( +>(({ className = '', ...props }, ref) => ( , React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( +>(({ className = '', ...props }, ref) => ( { const setOption: SetOption = (param) => (newValue) => { const update = {}; update[param] = newValue; - setPreset( - (prevState) => - cleanupPreset({ - preset: { - ...prevState, - ...update, - }, - endpointsConfig, - }) as TPreset, + setPreset((prevState) => + cleanupPreset({ + preset: { + ...prevState, + ...update, + }, + endpointsConfig, + }), ); }; @@ -32,15 +31,14 @@ const usePresetOptions: UsePresetOptions = (_preset) => { currentExample[type] = { content: newValue }; current[i] = currentExample; update['examples'] = current; - setPreset( - (prevState) => - cleanupPreset({ - preset: { - ...prevState, - ...update, - }, - endpointsConfig, - }) as TPreset, + setPreset((prevState) => + cleanupPreset({ + preset: { + ...prevState, + ...update, + }, + endpointsConfig, + }), ); }; @@ -49,15 +47,14 @@ const usePresetOptions: UsePresetOptions = (_preset) => { const current = preset?.examples?.slice() || []; current.push({ input: { content: '' }, output: { content: '' } }); update['examples'] = current; - setPreset( - (prevState) => - cleanupPreset({ - preset: { - ...prevState, - ...update, - }, - endpointsConfig, - }) as TPreset, + setPreset((prevState) => + cleanupPreset({ + preset: { + ...prevState, + ...update, + }, + endpointsConfig, + }), ); }; @@ -66,29 +63,27 @@ const usePresetOptions: UsePresetOptions = (_preset) => { const current = preset?.examples?.slice() || []; if (current.length <= 1) { update['examples'] = [{ input: { content: '' }, output: { content: '' } }]; - setPreset( - (prevState) => - cleanupPreset({ - preset: { - ...prevState, - ...update, - }, - endpointsConfig, - }) as TPreset, - ); - return; - } - current.pop(); - update['examples'] = current; - setPreset( - (prevState) => + setPreset((prevState) => cleanupPreset({ preset: { ...prevState, ...update, }, endpointsConfig, - }) as TPreset, + }), + ); + return; + } + current.pop(); + update['examples'] = current; + setPreset((prevState) => + cleanupPreset({ + preset: { + ...prevState, + ...update, + }, + endpointsConfig, + }), ); }; @@ -96,15 +91,14 @@ const usePresetOptions: UsePresetOptions = (_preset) => { const editablePreset = JSON.parse(JSON.stringify(_preset)); const { agentOptions } = editablePreset; agentOptions[param] = newValue; - setPreset( - (prevState) => - cleanupPreset({ - preset: { - ...prevState, - agentOptions, - }, - endpointsConfig, - }) as TPreset, + setPreset((prevState) => + cleanupPreset({ + preset: { + ...prevState, + agentOptions, + }, + endpointsConfig, + }), ); }; diff --git a/client/src/hooks/useSetOptions.ts b/client/src/hooks/useSetOptions.ts index 83f26741b6..feb357773b 100644 --- a/client/src/hooks/useSetOptions.ts +++ b/client/src/hooks/useSetOptions.ts @@ -4,6 +4,7 @@ import { SetOption, SetExample, TPlugin, + tConversationSchema, } from 'librechat-data-provider'; import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'; import usePresetOptions from './usePresetOptions'; @@ -23,12 +24,11 @@ const useSetOptions: UseSetOptions = (preset = false) => { const setOption: SetOption = (param) => (newValue) => { const update = {}; update[param] = newValue; - setConversation( - (prevState) => - ({ - ...prevState, - ...update, - } as TConversation), + setConversation((prevState) => + tConversationSchema.parse({ + ...prevState, + ...update, + }), ); }; @@ -39,12 +39,11 @@ const useSetOptions: UseSetOptions = (preset = false) => { currentExample[type] = { content: newValue }; current[i] = currentExample; update['examples'] = current; - setConversation( - (prevState) => - ({ - ...prevState, - ...update, - } as TConversation), + setConversation((prevState) => + tConversationSchema.parse({ + ...prevState, + ...update, + }), ); }; @@ -53,12 +52,11 @@ const useSetOptions: UseSetOptions = (preset = false) => { const current = conversation?.examples?.slice() || []; current.push({ input: { content: '' }, output: { content: '' } }); update['examples'] = current; - setConversation( - (prevState) => - ({ - ...prevState, - ...update, - } as TConversation), + setConversation((prevState) => + tConversationSchema.parse({ + ...prevState, + ...update, + }), ); }; @@ -67,23 +65,21 @@ const useSetOptions: UseSetOptions = (preset = false) => { const current = conversation?.examples?.slice() || []; if (current.length <= 1) { update['examples'] = [{ input: { content: '' }, output: { content: '' } }]; - setConversation( - (prevState) => - ({ - ...prevState, - ...update, - } as TConversation), + setConversation((prevState) => + tConversationSchema.parse({ + ...prevState, + ...update, + }), ); return; } current.pop(); update['examples'] = current; - setConversation( - (prevState) => - ({ - ...prevState, - ...update, - } as TConversation), + setConversation((prevState) => + tConversationSchema.parse({ + ...prevState, + ...update, + }), ); }; @@ -101,12 +97,11 @@ const useSetOptions: UseSetOptions = (preset = false) => { const convo = JSON.parse(editableConvo); const { agentOptions } = convo; agentOptions[param] = newValue; - setConversation( - (prevState) => - ({ - ...prevState, - agentOptions, - } as TConversation), + setConversation((prevState) => + tConversationSchema.parse({ + ...prevState, + agentOptions, + }), ); }; @@ -128,12 +123,11 @@ const useSetOptions: UseSetOptions = (preset = false) => { } localStorage.setItem('lastSelectedTools', JSON.stringify(update['tools'])); - setConversation( - (prevState) => - ({ - ...prevState, - ...update, - } as TConversation), + setConversation((prevState) => + tConversationSchema.parse({ + ...prevState, + ...update, + }), ); }; diff --git a/client/src/utils/cleanupPreset.ts b/client/src/utils/cleanupPreset.ts index ace695b591..c02d9b8258 100644 --- a/client/src/utils/cleanupPreset.ts +++ b/client/src/utils/cleanupPreset.ts @@ -1,9 +1,9 @@ -import { CleanupPreset } from 'librechat-data-provider'; +import { CleanupPreset, TPreset } from 'librechat-data-provider'; -const cleanupPreset = ({ preset: _preset, endpointsConfig = {} }: CleanupPreset) => { +const cleanupPreset = ({ preset: _preset, endpointsConfig = {} }: CleanupPreset): TPreset => { const { endpoint } = _preset; - let preset = {}; + let preset = {} as TPreset; let models = []; if (endpoint) { models = endpointsConfig[endpoint]?.availableModels || []; diff --git a/client/src/utils/index.ts b/client/src/utils/index.ts index af53786eb6..53ae0553eb 100644 --- a/client/src/utils/index.ts +++ b/client/src/utils/index.ts @@ -55,7 +55,7 @@ export const removeFocusOutlines = 'focus:outline-none focus:ring-0 focus:ring-opacity-0 focus:ring-offset-0'; export const cardStyle = - 'transition-colors rounded-md min-w-[75px] font-normal bg-white border-black/10 hover:border-black/10 focus:border-black/10 dark:border-black/10 dark:hover:border-black/10 dark:focus:border-black/10 border dark:bg-gray-700 text-black dark:text-white'; + 'transition-colors rounded-md min-w-[75px] border font-normal bg-white hover:bg-slate-50 dark:border-gray-600 dark:hover:bg-gray-700 dark:bg-gray-800 text-black dark:text-gray-600 focus:outline-none data-[state=open]:bg-slate-50 dark:data-[state=open]:bg-gray-700'; export const defaultTextProps = 'rounded-md border border-gray-200 focus:border-slate-400 focus:bg-gray-50 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none placeholder:text-gray-400 focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-500 dark:bg-gray-700 focus:dark:bg-gray-600 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-400 dark:focus:outline-none dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0'; diff --git a/e2e/setup/authenticate.ts b/e2e/setup/authenticate.ts index cb796ae4d0..0b1a3ef1af 100644 --- a/e2e/setup/authenticate.ts +++ b/e2e/setup/authenticate.ts @@ -15,6 +15,10 @@ async function authenticate(config: FullConfig, user: User) { const browser = await chromium.launch(); const page = await browser.newPage(); console.log('🤖: 🗝 authenticating user:', user.username); + + if (!baseURL) { + throw new Error('🤖: baseURL is not defined'); + } await page.goto(baseURL); await login(page, user); await page.locator('h1:has-text("LibreChat")').waitFor(); diff --git a/package-lock.json b/package-lock.json index 91716ff12d..13b8f3ab2c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26948,7 +26948,8 @@ "license": "ISC", "dependencies": { "@tanstack/react-query": "^4.28.0", - "axios": "^1.3.4" + "axios": "^1.3.4", + "zod": "^3.21.4" }, "devDependencies": { "@babel/preset-env": "^7.21.5", @@ -39519,7 +39520,8 @@ "rimraf": "^5.0.1", "rollup": "^3.26.0", "rollup-plugin-typescript2": "^0.35.0", - "typescript": "^5.0.4" + "typescript": "^5.0.4", + "zod": "*" }, "dependencies": { "brace-expansion": { diff --git a/packages/data-provider/package.json b/packages/data-provider/package.json index c80ac17f26..2a870c3cbb 100644 --- a/packages/data-provider/package.json +++ b/packages/data-provider/package.json @@ -1,6 +1,6 @@ { "name": "librechat-data-provider", - "version": "0.1.3", + "version": "0.1.4", "description": "data services for librechat apps", "main": "dist/index.js", "module": "dist/index.es.js", @@ -25,7 +25,8 @@ "homepage": "https://github.com/danny-avila/LibreChat#readme", "dependencies": { "@tanstack/react-query": "^4.28.0", - "axios": "^1.3.4" + "axios": "^1.3.4", + "zod": "^3.21.4" }, "devDependencies": { "@babel/preset-env": "^7.21.5", diff --git a/packages/data-provider/src/createPayload.ts b/packages/data-provider/src/createPayload.ts index 4372416fcd..debe5c6b2e 100644 --- a/packages/data-provider/src/createPayload.ts +++ b/packages/data-provider/src/createPayload.ts @@ -1,8 +1,9 @@ -import type { TConversation, TSubmission, EModelEndpoint } from './types'; +import { tConversationSchema } from './schemas'; +import type { TSubmission, EModelEndpoint } from './types'; export default function createPayload(submission: TSubmission) { const { conversation, message, endpointOption } = submission; - const { conversationId } = conversation as TConversation; + const { conversationId } = tConversationSchema.parse(conversation); const { endpoint } = endpointOption as { endpoint: EModelEndpoint }; const endpointUrlMap = { diff --git a/packages/data-provider/src/data-service.ts b/packages/data-provider/src/data-service.ts index 0f38578019..44d3dea41c 100644 --- a/packages/data-provider/src/data-service.ts +++ b/packages/data-provider/src/data-service.ts @@ -1,4 +1,5 @@ import * as t from './types'; +import * as s from './schemas'; import request from './request'; import * as endpoints from './api-endpoints'; @@ -23,11 +24,11 @@ export function clearAllConversations(): Promise { return request.post(endpoints.deleteConversation(), { arg: {} }); } -export function getMessagesByConvoId(id: string): Promise { +export function getMessagesByConvoId(id: string): Promise { return request.get(endpoints.messages(id)); } -export function getConversationById(id: string): Promise { +export function getConversationById(id: string): Promise { return request.get(endpoints.conversationById(id)); } @@ -37,19 +38,19 @@ export function updateConversation( return request.post(endpoints.updateConversation(), { arg: payload }); } -export function getPresets(): Promise { +export function getPresets(): Promise { return request.get(endpoints.presets()); } -export function createPreset(payload: t.TPreset): Promise { +export function createPreset(payload: s.TPreset): Promise { return request.post(endpoints.presets(), payload); } -export function updatePreset(payload: t.TPreset): Promise { +export function updatePreset(payload: s.TPreset): Promise { return request.post(endpoints.presets(), payload); } -export function deletePreset(arg: t.TPreset | object): Promise { +export function deletePreset(arg: s.TPreset | object): Promise { return request.post(endpoints.deletePreset(), arg); } @@ -106,7 +107,7 @@ export const resetPassword = (payload: t.TResetPassword) => { return request.post(endpoints.resetPassword(), payload); }; -export const getAvailablePlugins = (): Promise => { +export const getAvailablePlugins = (): Promise => { return request.get(endpoints.plugins()); }; diff --git a/packages/data-provider/src/react-query-service.ts b/packages/data-provider/src/react-query-service.ts index d6f3db1959..3bcbffc7d9 100644 --- a/packages/data-provider/src/react-query-service.ts +++ b/packages/data-provider/src/react-query-service.ts @@ -7,6 +7,7 @@ import { QueryObserverResult, } from '@tanstack/react-query'; import * as t from './types'; +import * as s from './schemas'; import * as dataService from './data-service'; export enum QueryKeys { @@ -47,9 +48,9 @@ export const useGetUserQuery = ( export const useGetMessagesByConvoId = ( id: string, - config?: UseQueryOptions, -): QueryObserverResult => { - return useQuery( + config?: UseQueryOptions, +): QueryObserverResult => { + return useQuery( [QueryKeys.messages, id], () => dataService.getMessagesByConvoId(id), { @@ -63,9 +64,9 @@ export const useGetMessagesByConvoId = ( export const useGetConversationByIdQuery = ( id: string, - config?: UseQueryOptions, -): QueryObserverResult => { - return useQuery( + config?: UseQueryOptions, +): QueryObserverResult => { + return useQuery( [QueryKeys.conversation, id], () => dataService.getConversationById(id), { @@ -79,10 +80,10 @@ export const useGetConversationByIdQuery = ( //This isn't ideal because its just a query and we're using mutation, but it was the only way //to make it work with how the Chat component is structured -export const useGetConversationByIdMutation = (id: string): UseMutationResult => { +export const useGetConversationByIdMutation = (id: string): UseMutationResult => { const queryClient = useQueryClient(); return useMutation(() => dataService.getConversationById(id), { - // onSuccess: (res: t.TConversation) => { + // onSuccess: (res: s.TConversation) => { onSuccess: () => { queryClient.invalidateQueries([QueryKeys.conversation, id]); }, @@ -174,13 +175,13 @@ export const useGetEndpointsQuery = (): QueryObserverResult }; export const useCreatePresetMutation = (): UseMutationResult< - t.TPreset[], + s.TPreset[], unknown, - t.TPreset, + s.TPreset, unknown > => { const queryClient = useQueryClient(); - return useMutation((payload: t.TPreset) => dataService.createPreset(payload), { + return useMutation((payload: s.TPreset) => dataService.createPreset(payload), { onSuccess: () => { queryClient.invalidateQueries([QueryKeys.presets]); }, @@ -188,13 +189,13 @@ export const useCreatePresetMutation = (): UseMutationResult< }; export const useUpdatePresetMutation = (): UseMutationResult< - t.TPreset[], + s.TPreset[], unknown, - t.TPreset, + s.TPreset, unknown > => { const queryClient = useQueryClient(); - return useMutation((payload: t.TPreset) => dataService.updatePreset(payload), { + return useMutation((payload: s.TPreset) => dataService.updatePreset(payload), { onSuccess: () => { queryClient.invalidateQueries([QueryKeys.presets]); }, @@ -202,9 +203,9 @@ export const useUpdatePresetMutation = (): UseMutationResult< }; export const useGetPresetsQuery = ( - config?: UseQueryOptions, -): QueryObserverResult => { - return useQuery([QueryKeys.presets], () => dataService.getPresets(), { + config?: UseQueryOptions, +): QueryObserverResult => { + return useQuery([QueryKeys.presets], () => dataService.getPresets(), { refetchOnWindowFocus: false, refetchOnReconnect: false, refetchOnMount: false, @@ -213,13 +214,13 @@ export const useGetPresetsQuery = ( }; export const useDeletePresetMutation = (): UseMutationResult< - t.TPreset[], + s.TPreset[], unknown, - t.TPreset | object, + s.TPreset | object, unknown > => { const queryClient = useQueryClient(); - return useMutation((payload: t.TPreset | object) => dataService.deletePreset(payload), { + return useMutation((payload: s.TPreset | object) => dataService.deletePreset(payload), { onSuccess: () => { queryClient.invalidateQueries([QueryKeys.presets]); }, @@ -323,8 +324,8 @@ export const useResetPasswordMutation = (): UseMutationResult< return useMutation((payload: t.TResetPassword) => dataService.resetPassword(payload)); }; -export const useAvailablePluginsQuery = (): QueryObserverResult => { - return useQuery( +export const useAvailablePluginsQuery = (): QueryObserverResult => { + return useQuery( [QueryKeys.availablePlugins], () => dataService.getAvailablePlugins(), { diff --git a/packages/data-provider/src/schemas.ts b/packages/data-provider/src/schemas.ts new file mode 100644 index 0000000000..dda6ad22b7 --- /dev/null +++ b/packages/data-provider/src/schemas.ts @@ -0,0 +1,121 @@ +import { z } from 'zod'; + +export enum EModelEndpoint { + azureOpenAI = 'azureOpenAI', + openAI = 'openAI', + bingAI = 'bingAI', + chatGPT = 'chatGPT', + chatGPTBrowser = 'chatGPTBrowser', + google = 'google', + gptPlugins = 'gptPlugins', + anthropic = 'anthropic', +} + +export const eModelEndpointSchema = z.nativeEnum(EModelEndpoint); + +export const tMessageSchema = z.object({ + messageId: z.string(), + conversationId: z.string(), + clientId: z.string(), + parentMessageId: z.string(), + sender: z.string(), + text: z.string(), + isCreatedByUser: z.boolean(), + error: z.boolean(), + createdAt: z.string(), + updatedAt: z.string(), +}); + +export type TMessage = z.infer; + +export const tPluginAuthConfigSchema = z.object({ + authField: z.string(), + label: z.string(), + description: z.string(), +}); + +export type TPluginAuthConfig = z.infer; + +export const tPluginSchema = z.object({ + name: z.string(), + pluginKey: z.string(), + description: z.string(), + icon: z.string(), + authConfig: z.array(tPluginAuthConfigSchema), + authenticated: z.boolean().optional(), + isButton: z.boolean().optional(), +}); + +export type TPlugin = z.infer; + +export const tExampleSchema = z.object({ + input: z.object({ + content: z.string(), + }), + output: z.object({ + content: z.string(), + }), +}); + +export type TExample = z.infer; + +export const tAgentOptionsSchema = z.object({ + agent: z.string(), + skipCompletion: z.boolean(), + model: z.string(), + temperature: z.number(), +}); + +export const tConversationSchema = z.object({ + conversationId: z.string().nullable(), + title: z.string(), + user: z.string().optional(), + endpoint: eModelEndpointSchema.nullable(), + suggestions: z.array(z.string()).optional(), + messages: z.array(z.string()).optional(), + tools: z.array(tPluginSchema).optional(), + createdAt: z.string(), + updatedAt: z.string(), + systemMessage: z.string().nullable().optional(), + modelLabel: z.string().nullable().optional(), + examples: z.array(tExampleSchema).optional(), + chatGptLabel: z.string().nullable().optional(), + userLabel: z.string().optional(), + model: z.string().optional(), + promptPrefix: z.string().nullable().optional(), + temperature: z.number().optional(), + topP: z.number().optional(), + topK: z.number().optional(), + context: z.string().nullable().optional(), + top_p: z.number().optional(), + frequency_penalty: z.number().optional(), + presence_penalty: z.number().optional(), + jailbreak: z.boolean().optional(), + jailbreakConversationId: z.string().nullable().optional(), + conversationSignature: z.string().nullable().optional(), + parentMessageId: z.string().optional(), + clientId: z.string().nullable().optional(), + invocationId: z.number().nullable().optional(), + toneStyle: z.string().nullable().optional(), + maxOutputTokens: z.number().optional(), + agentOptions: tAgentOptionsSchema.nullable().optional(), +}); + +export type TConversation = z.infer; + +export const tPresetSchema = tConversationSchema + .omit({ + conversationId: true, + createdAt: true, + updatedAt: true, + title: true, + }) + .merge( + z.object({ + conversationId: z.string().optional(), + presetId: z.string().nullable().optional(), + title: z.string().nullable().optional(), + }), + ); + +export type TPreset = z.infer; diff --git a/packages/data-provider/src/types.ts b/packages/data-provider/src/types.ts index 23eac7f1f5..95f4496fcb 100644 --- a/packages/data-provider/src/types.ts +++ b/packages/data-provider/src/types.ts @@ -1,42 +1,12 @@ import * as React from 'react'; +import { TExample, TMessage, EModelEndpoint, TPlugin, TConversation, TPreset } from './schemas'; -export type TMessage = { - messageId: string; - conversationId: string; - clientId: string; - parentMessageId: string; - sender: string; - text: string; - isCreatedByUser: boolean; - error: boolean; - createdAt: string; - updatedAt: string; -}; +export * from './schemas'; export type TMessages = TMessage[]; export type TMessagesAtom = TMessages | null; -export type TExample = { - input: { - content: string; - }; - output: { - content: string; - }; -}; - -export enum EModelEndpoint { - azureOpenAI = 'azureOpenAI', - openAI = 'openAI', - bingAI = 'bingAI', - chatGPT = 'chatGPT', - chatGPTBrowser = 'chatGPTBrowser', - google = 'google', - gptPlugins = 'gptPlugins', - anthropic = 'anthropic', -} - export type TSubmission = { clientId?: string; context?: string; @@ -73,22 +43,6 @@ export type TEndpointOption = { temperature?: number; }; -export type TPluginAuthConfig = { - authField: string; - label: string; - description: string; -}; - -export type TPlugin = { - name: string; - pluginKey: string; - description: string; - icon: string; - authConfig: TPluginAuthConfig[]; - authenticated: boolean; - isButton?: boolean; -}; - export type TPluginAction = { pluginKey: string; action: 'install' | 'uninstall'; @@ -105,91 +59,6 @@ export type TUpdateUserPlugins = { auth?: unknown; }; -export type TAgentOptions = { - agent: string; - skipCompletion: boolean; - model: string; - temperature: number; -}; - -export type TConversation = { - conversationId: string | null; - title: string; - user?: string; - endpoint: EModelEndpoint | null; - suggestions?: string[]; - messages?: TMessage[]; - tools?: TPlugin[]; - createdAt: string; - updatedAt: string; - // google only - systemMessage?: string; - modelLabel?: string; - examples?: TExample[]; - // for azureOpenAI, openAI only - chatGptLabel?: string; - userLabel?: string; - model?: string; - promptPrefix?: string; - temperature?: number; - topP?: number; - topK?: number; - // bing and google - context?: string; - top_p?: number; - frequency_penalty?: number; - presence_penalty?: number; - // for bingAI only - jailbreak?: boolean; - jailbreakConversationId?: string; - conversationSignature?: string; - parentMessageId?: string; - clientId?: string; - invocationId?: string; - toneStyle?: string; - maxOutputTokens?: number; - // plugins only - agentOptions?: TAgentOptions; -}; - -export type TPreset = { - title: string; - conversationId?: string; - endpoint: EModelEndpoint | null; - conversationSignature?: string; - createdAt?: string; - updatedAt?: string; - presetId?: string; - tools?: TPlugin[]; - user?: string; - modelLabel?: string; - maxOutputTokens?: number; - topP?: number; - topK?: number; - context?: string; - systemMessage?: string; - // for azureOpenAI, openAI only - chatGptLabel?: string; - frequence_penalty?: number; - model?: string; - presence_penalty?: number; - frequency_penalty?: number; - promptPrefix?: string; - temperature?: number; - top_p?: number; - //for BingAI - clientId?: string; - invocationId?: number; - jailbreak?: boolean; - jailbreakPresetId?: string; - presetSignature?: string; - toneStyle?: string; - // plugins only - agentOptions?: TAgentOptions; - // google only - examples?: TExample[]; -}; - export type TOptionSettings = { showExamples?: boolean; isCodeChat?: boolean;