@@ -7,17 +7,15 @@ import { enqueueSnackbar } from 'notistack'
7
7
import { useCallback , useEffect , useRef , useState } from 'react'
8
8
import { useTranslation } from 'react-i18next'
9
9
import { useParams , useSearchParams } from 'react-router-dom'
10
- import { DEFAULT_MODEL , DEFAULT_MODEL_TEMPERATURE , FREE_MODEL , inProduction , validModels } from '../../../config'
10
+ import { DEFAULT_MODEL , DEFAULT_MODEL_TEMPERATURE , FREE_MODEL , inProduction , ValidModelName , ValidModelNameSchema , validModels } from '../../../config'
11
11
import type { ChatMessage , MessageGenerationInfo , ToolCallResultEvent } from '../../../shared/chat'
12
- import type { RagIndexAttributes } from '../../../shared/types'
13
12
import { getLanguageValue } from '../../../shared/utils'
14
13
import { useIsEmbedded } from '../../contexts/EmbeddedContext'
15
14
import { useChatScroll } from './useChatScroll'
16
15
import useCourse from '../../hooks/useCourse'
17
16
import useCurrentUser from '../../hooks/useCurrentUser'
18
17
import useInfoTexts from '../../hooks/useInfoTexts'
19
18
import useLocalStorageState from '../../hooks/useLocalStorageState'
20
- import { useCourseRagIndices } from '../../hooks/useRagIndices'
21
19
import useRetryTimeout from '../../hooks/useRetryTimeout'
22
20
import useUserStatus from '../../hooks/useUserStatus'
23
21
import { useAnalyticsDispatch } from '../../stores/analytics'
@@ -31,31 +29,37 @@ import { handleCompletionStreamError } from './error'
31
29
import ToolResult from './ToolResult'
32
30
import { OutlineButtonBlack } from './general/Buttons'
33
31
import { ChatInfo } from './general/ChatInfo'
34
- import RagSelector , { RagSelectorDescription } from './RagSelector'
35
32
import { SettingsModal } from './SettingsModal'
36
33
import { useChatStream } from './useChatStream'
37
34
import { postCompletionStreamV3 } from './api'
38
35
import PromptSelector from './PromptSelector'
39
36
import ModelSelector from './ModelSelector'
40
37
import { ConversationSplash } from './general/ConversationSplash'
41
38
import { PromptStateProvider , usePromptState } from './PromptState'
39
+ import z from 'zod/v4'
42
40
43
- function useLocalStorageStateWithURLDefault ( key : string , defaultValue : string , urlKey : string ) {
41
+ function useLocalStorageStateWithURLDefault < T > ( key : string , defaultValue : string , urlKey : string , schema : z . ZodType < T > ) {
44
42
const [ value , setValue ] = useLocalStorageState ( key , defaultValue )
45
43
const [ searchParams , setSearchParams ] = useSearchParams ( )
46
44
const urlValue = searchParams . get ( urlKey )
47
45
48
46
// If urlValue is defined, it overrides the localStorage setting.
49
47
// However if user changes the setting, the urlValue is removed.
50
- const modifiedSetValue = ( newValue : string ) => {
48
+ const modifiedSetValue = ( newValue : T ) => {
51
49
if ( newValue !== urlValue ) {
52
- setValue ( newValue )
50
+ if ( typeof newValue === 'string' ) {
51
+ setValue ( newValue )
52
+ } else {
53
+ setValue ( String ( newValue ) )
54
+ }
53
55
searchParams . delete ( urlKey )
54
56
setSearchParams ( searchParams )
55
57
}
56
58
}
57
59
58
- return [ urlValue ?? value , modifiedSetValue ] as const
60
+ const parsedValue = schema . parse ( urlValue ?? value )
61
+
62
+ return [ parsedValue , modifiedSetValue ] as const
59
63
}
60
64
61
65
const ChatV2Content = ( ) => {
@@ -65,7 +69,6 @@ const ChatV2Content = () => {
65
69
const isMobile = useMediaQuery ( theme . breakpoints . down ( 'md' ) )
66
70
67
71
const { data : course } = useCourse ( courseId )
68
- const { ragIndices } = useCourseRagIndices ( course ?. id )
69
72
const { infoTexts } = useInfoTexts ( )
70
73
71
74
const { userStatus, isLoading : statusLoading , refetch : refetchStatus } = useUserStatus ( courseId )
@@ -74,12 +77,13 @@ const ChatV2Content = () => {
74
77
75
78
// local storage states
76
79
const localStoragePrefix = courseId ? `course-${ courseId } ` : 'general'
77
- const [ activeModel , setActiveModel ] = useLocalStorageStateWithURLDefault ( 'model-v2' , DEFAULT_MODEL , 'model' )
80
+ const [ activeModel , setActiveModel ] = useLocalStorageStateWithURLDefault ( 'model-v2' , DEFAULT_MODEL , 'model' , ValidModelNameSchema )
78
81
const [ disclaimerStatus , setDisclaimerStatus ] = useLocalStorageState < boolean > ( 'disclaimer-status' , true )
79
82
const [ modelTemperature , setModelTemperature ] = useLocalStorageStateWithURLDefault (
80
83
`${ localStoragePrefix } -chat-model-temperature` ,
81
84
String ( DEFAULT_MODEL_TEMPERATURE ) ,
82
85
'temperature' ,
86
+ z . number ( ) ,
83
87
)
84
88
85
89
const [ messages , setMessages ] = useLocalStorageState ( `${ localStoragePrefix } -chat-messages` , [ ] as ChatMessage [ ] )
@@ -90,12 +94,9 @@ const ChatV2Content = () => {
90
94
const [ fileName , setFileName ] = useState < string > ( '' )
91
95
const [ tokenUsageWarning , setTokenUsageWarning ] = useState < string > ( '' )
92
96
const [ tokenUsageAlertOpen , setTokenUsageAlertOpen ] = useState < boolean > ( false )
93
- const [ allowedModels , setAllowedModels ] = useState < string [ ] > ( [ ] )
97
+ const [ allowedModels , setAllowedModels ] = useState < ValidModelName [ ] > ( [ ] )
94
98
const [ chatLeftSidePanelOpen , setChatLeftSidePanelOpen ] = useState < boolean > ( false )
95
- // RAG states
96
- const [ ragIndexId , _setRagIndexId ] = useState < number | undefined > ( )
97
99
const [ activeToolResult , setActiveToolResult0 ] = useState < ToolCallResultEvent | undefined > ( )
98
- const ragIndex = ragIndices ?. find ( ( index ) => index . id === ragIndexId )
99
100
100
101
// Analytics
101
102
const dispatchAnalytics = useAnalyticsDispatch ( )
@@ -106,11 +107,9 @@ const ChatV2Content = () => {
106
107
model : activeModel ,
107
108
courseId,
108
109
nMessages : messages . length ,
109
- ragIndexId,
110
- ragIndexName : ragIndex ?. metadata . name ,
111
110
} ,
112
111
} )
113
- } , [ messages , courseId , ragIndexId , activeModel , dispatchAnalytics ] )
112
+ } , [ messages , courseId , activeModel , dispatchAnalytics ] )
114
113
115
114
// Refs
116
115
const chatContainerRef = useRef < HTMLDivElement | null > ( null )
@@ -194,16 +193,23 @@ const ChatV2Content = () => {
194
193
}
195
194
196
195
try {
197
- const { tokenUsageAnalysis, stream } = await postCompletionStreamV3 ( {
198
- generationInfo,
199
- messages : newMessages ,
200
- ragIndexId,
196
+ if ( ! streamController ) {
197
+ throw new Error ( 'streamController is not defined' )
198
+ }
199
+
200
+ const { tokenUsageAnalysis, stream } = await postCompletionStreamV3 (
201
201
formData ,
202
- modelTemperature : parseFloat ( modelTemperature ) ,
203
- courseId,
204
- abortController : streamController ,
205
- saveConsent,
206
- } )
202
+ {
203
+ options : {
204
+ generationInfo,
205
+ chatMessages : newMessages ,
206
+ modelTemperature,
207
+ saveConsent,
208
+ } ,
209
+ courseId,
210
+ } ,
211
+ streamController ,
212
+ )
207
213
208
214
if ( ! stream && ! tokenUsageAnalysis ) {
209
215
console . error ( 'getCompletionStream did not return a stream or token usage analysis' )
@@ -263,7 +269,7 @@ const ChatV2Content = () => {
263
269
264
270
const { usage, limit, model : defaultCourseModel , models : courseModels } = userStatus
265
271
266
- let allowedModels : string [ ] = [ ]
272
+ let allowedModels : ValidModelName [ ] = [ ]
267
273
268
274
if ( course && courseModels ) {
269
275
allowedModels = courseModels
@@ -558,8 +564,8 @@ const ChatV2Content = () => {
558
564
< SettingsModal
559
565
open = { settingsModalOpen }
560
566
setOpen = { setSettingsModalOpen }
561
- modelTemperature = { parseFloat ( modelTemperature ) }
562
- setModelTemperature = { ( updatedTemperature ) => setModelTemperature ( String ( updatedTemperature ) ) }
567
+ modelTemperature = { modelTemperature }
568
+ setModelTemperature = { ( updatedTemperature ) => setModelTemperature ( updatedTemperature ) }
563
569
/>
564
570
565
571
< DisclaimerModal disclaimer = { disclaimerInfo } disclaimerStatus = { disclaimerStatus } setDisclaimerStatus = { setDisclaimerStatus } />
@@ -586,9 +592,9 @@ const LeftMenu = ({
586
592
setSettingsModalOpen : React . Dispatch < React . SetStateAction < boolean > >
587
593
setDisclaimerStatus : React . Dispatch < React . SetStateAction < boolean > >
588
594
messages : ChatMessage [ ]
589
- currentModel : string
590
- setModel : ( model : string ) => void
591
- availableModels : string [ ]
595
+ currentModel : ValidModelName
596
+ setModel : ( model : ValidModelName ) => void
597
+ availableModels : ValidModelName [ ]
592
598
} ) => {
593
599
const { t } = useTranslation ( )
594
600
const { courseId } = useParams ( )
0 commit comments