-
{message.status === MessageStatus.Error &&
index === messages.length - 1 && (
{
+const EngineSetting = (props: { form: any }) => {
const activeModelParams = useAtomValue(getActiveThreadModelParamsAtom)
const selectedModel = useAtomValue(selectedModelAtom)
@@ -22,9 +23,9 @@ const EngineSetting: React.FC = () => {
componentData.sort((a, b) => a.title.localeCompare(b.title))
return (
-
+
+ {settingComponentBuilder(componentData, props.form)}
+
)
}
diff --git a/web/screens/Chat/ModelSetting/index.tsx b/web/screens/Chat/ModelSetting/index.tsx
index 97e0d4ecd..1f1be06bf 100644
--- a/web/screens/Chat/ModelSetting/index.tsx
+++ b/web/screens/Chat/ModelSetting/index.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react'
import { useAtomValue } from 'jotai'
@@ -11,7 +12,7 @@ import settingComponentBuilder from './settingComponentBuilder'
import { getActiveThreadModelParamsAtom } from '@/helpers/atoms/Thread.atom'
-const ModelSetting: React.FC = () => {
+const ModelSetting = (props: { form: any }) => {
const activeModelParams = useAtomValue(getActiveThreadModelParamsAtom)
const selectedModel = useAtomValue(selectedModelAtom)
@@ -24,9 +25,9 @@ const ModelSetting: React.FC = () => {
componentData.sort((a, b) => a.title.localeCompare(b.title))
return (
-
+
+ {settingComponentBuilder(componentData, props.form)}
+
)
}
diff --git a/web/screens/Chat/ModelSetting/settingComponentBuilder.tsx b/web/screens/Chat/ModelSetting/settingComponentBuilder.tsx
index a751bfb92..59ebb5af2 100644
--- a/web/screens/Chat/ModelSetting/settingComponentBuilder.tsx
+++ b/web/screens/Chat/ModelSetting/settingComponentBuilder.tsx
@@ -1,4 +1,7 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable no-case-declarations */
+import { FormControl, FormField, FormItem, FormMessage } from '@janhq/uikit'
+
import Checkbox from '@/containers/Checkbox'
import ModelConfigInput from '@/containers/ModelConfigInput'
import Slider from '@/containers/Slider'
@@ -29,51 +32,99 @@ type CheckboxData = {
checked: boolean
}
-const settingComponentBuilder = (componentData: SettingComponentData[]) => {
- const components = componentData.map((data) => {
- switch (data.controllerType) {
- case 'slider':
- const { min, max, step, value } = data.controllerData as SliderData
- return (
-
- )
- case 'input':
- const { placeholder, value: textValue } =
- data.controllerData as InputData
- return (
-
- )
- case 'checkbox':
- const { checked } = data.controllerData as CheckboxData
- return (
-
- )
- default:
- return null
- }
- })
+const settingComponentBuilder = (
+ componentData: SettingComponentData[],
+ form?: any,
+ onlyPrompt?: boolean
+) => {
+ const components = componentData
+ .filter((x) =>
+ onlyPrompt ? x.name === 'prompt_template' : x.name !== 'prompt_template'
+ )
+ .map((data) => {
+ switch (data.controllerType) {
+ case 'slider':
+ const { min, max, step, value } = data.controllerData as SliderData
+ return (
+
(
+ <>
+
+
+
+
+
+
+ >
+ )}
+ />
+ )
+ case 'input':
+ const { placeholder, value: textValue } =
+ data.controllerData as InputData
+ return (
+ (
+
+
+
+
+
+
+ )}
+ />
+ )
+ case 'checkbox':
+ const { checked } = data.controllerData as CheckboxData
+ return (
+ (
+ <>
+
+
+
+
+
+
+ >
+ )}
+ />
+ )
+ default:
+ return null
+ }
+ })
return {components}
}
diff --git a/web/screens/Chat/Sidebar/index.tsx b/web/screens/Chat/Sidebar/index.tsx
index 181abe3b5..adb0e348d 100644
--- a/web/screens/Chat/Sidebar/index.tsx
+++ b/web/screens/Chat/Sidebar/index.tsx
@@ -1,8 +1,18 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
import React, { useContext } from 'react'
+import { FieldValues, useForm } from 'react-hook-form'
import { getUserSpace, openFileExplorer, joinPath } from '@janhq/core'
-import { Input, Textarea } from '@janhq/uikit'
+import {
+ Input,
+ Textarea,
+ Form,
+ Button,
+ FormField,
+ FormItem,
+ FormControl,
+} from '@janhq/uikit'
import { atom, useAtomValue } from 'jotai'
@@ -15,17 +25,21 @@ import DropdownListSidebar, {
selectedModelAtom,
} from '@/containers/DropdownListSidebar'
-import { FeatureToggleContext } from '@/context/FeatureToggle'
-
import { useCreateNewThread } from '@/hooks/useCreateNewThread'
+import useUpdateModelParameters from '@/hooks/useUpdateModelParameters'
+
+import { getConfigurationsData } from '@/utils/componentSettings'
import { toSettingParams } from '@/utils/model_param'
import EngineSetting from '../EngineSetting'
import ModelSetting from '../ModelSetting'
+import settingComponentBuilder from '../ModelSetting/settingComponentBuilder'
+
import {
activeThreadAtom,
+ getActiveThreadIdAtom,
getActiveThreadModelParamsAtom,
threadStatesAtom,
} from '@/helpers/atoms/Thread.atom'
@@ -35,13 +49,15 @@ export const showRightSideBarAtom = atom(true)
const Sidebar: React.FC = () => {
const showing = useAtomValue(showRightSideBarAtom)
const activeThread = useAtomValue(activeThreadAtom)
+ const activeModelParams = useAtomValue(getActiveThreadModelParamsAtom)
const selectedModel = useAtomValue(selectedModelAtom)
const { updateThreadMetadata } = useCreateNewThread()
+ const { updateModelParameter } = useUpdateModelParameters()
const threadStates = useAtomValue(threadStatesAtom)
- const { experimentalFeatureEnabed } = useContext(FeatureToggleContext)
+ const threadId = useAtomValue(getActiveThreadIdAtom)
+ const modelEngineParams = toSettingParams(activeModelParams)
- const activeModelParams = useAtomValue(getActiveThreadModelParamsAtom)
- const modelSettingParams = toSettingParams(activeModelParams)
+ const componentDataEngineSetting = getConfigurationsData(modelEngineParams)
const onReviewInFinderClick = async (type: string) => {
if (!activeThread) return
@@ -109,6 +125,62 @@ const Sidebar: React.FC = () => {
openFileExplorer(fullPath)
}
+ const form = useForm()
+
+ const filterChangedFormFields = (
+ allFields: T,
+ dirtyFields: Partial>
+ ): Partial => {
+ const changedFieldValues = Object.keys(dirtyFields).reduce(
+ (acc, currentField) => {
+ const isDirty = Array.isArray(dirtyFields[currentField])
+ ? (dirtyFields[currentField] as boolean[]).some((value) => {
+ value === true
+ })
+ : dirtyFields[currentField] === true
+ if (isDirty) {
+ return {
+ ...acc,
+ [currentField]: allFields[currentField],
+ }
+ }
+ return acc
+ },
+ {} as Partial
+ )
+
+ return changedFieldValues
+ }
+
+ const onSubmit = async (values: any) => {
+ if (!threadId) return
+ if (!activeThread) return
+
+ if (Object.keys(form.formState.dirtyFields).length) {
+ if (
+ Object.keys(form.formState.dirtyFields).includes('title') ||
+ Object.keys(form.formState.dirtyFields).includes('instructions')
+ ) {
+ updateThreadMetadata({
+ ...activeThread,
+ title: values.title || activeThread.title,
+ assistants: [
+ {
+ ...activeThread.assistants[0],
+ instructions:
+ values.instructions || activeThread?.assistants[0].instructions,
+ },
+ ],
+ })
+ }
+ updateModelParameter(
+ threadId,
+ filterChangedFormFields(values, form.formState.dirtyFields)
+ )
+ form.reset()
+ }
+ }
+
return (
{
: 'w-0 translate-x-full opacity-0'
)}
>
-
-
-
-
- {
- if (activeThread)
- updateThreadMetadata({
- ...activeThread,
- title: e.target.value || '',
- })
- }}
- />
-
-
-
-
- {activeThread?.id || '-'}
-
-
-
+