@@ -29,6 +29,7 @@ import { stopModel, startModel, stopAllModels } from '@/services/models'
2929import { useToolApproval } from '@/hooks/useToolApproval'
3030import { useToolAvailable } from '@/hooks/useToolAvailable'
3131import { OUT_OF_CONTEXT_SIZE } from '@/utils/error'
32+ import { updateSettings } from '@/services/providers'
3233
3334export const useChat = ( ) => {
3435 const { prompt, setPrompt } = usePrompt ( )
@@ -110,19 +111,41 @@ export const useChat = () => {
110111 currentAssistant ,
111112 ] )
112113
114+ const restartModel = useCallback (
115+ async (
116+ provider : ProviderObject ,
117+ modelId : string ,
118+ abortController : AbortController
119+ ) => {
120+ await stopAllModels ( )
121+ await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) )
122+ updateLoadingModel ( true )
123+ await startModel ( provider , modelId , abortController ) . catch ( console . error )
124+ updateLoadingModel ( false )
125+ await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) )
126+ } ,
127+ [ updateLoadingModel ]
128+ )
129+
113130 const increaseModelContextSize = useCallback (
114- ( model : Model , provider : ProviderObject ) => {
131+ async (
132+ modelId : string ,
133+ provider : ProviderObject ,
134+ controller : AbortController
135+ ) => {
115136 /**
116137 * Should increase the context size of the model by 2x
117138 * If the context size is not set or too low, it defaults to 8192.
118139 */
140+ const model = provider . models . find ( ( m ) => m . id === modelId )
141+ if ( ! model ) return undefined
119142 const ctxSize = Math . max (
120143 model . settings ?. ctx_len ?. controller_props . value
121144 ? typeof model . settings . ctx_len . controller_props . value === 'string'
122145 ? parseInt ( model . settings . ctx_len . controller_props . value as string )
123146 : ( model . settings . ctx_len . controller_props . value as number )
124- : 8192 ,
125- 8192
147+ : 16384 ,
148+ 16384
126149 )
127150 const updatedModel = {
128151 ...model ,
@@ -153,9 +176,54 @@ export const useChat = () => {
153176 models : updatedModels ,
154177 } )
155178 }
156- stopAllModels ( )
179+ const updatedProvider = getProviderByName ( provider . provider )
180+ if ( updatedProvider )
181+ await restartModel ( updatedProvider , model . id , controller )
182+
183+ console . log (
184+ updatedProvider ?. models . find ( ( e ) => e . id === model . id ) ?. settings
185+ ?. ctx_len ?. controller_props . value
186+ )
187+ return updatedProvider
157188 } ,
158- [ updateProvider ]
189+ [ getProviderByName , restartModel , updateProvider ]
190+ )
191+ const toggleOnContextShifting = useCallback (
192+ async (
193+ modelId : string ,
194+ provider : ProviderObject ,
195+ controller : AbortController
196+ ) => {
197+ const providerName = provider . provider
198+ const newSettings = [ ...provider . settings ]
199+ const settingKey = 'context_shift'
200+ // Handle different value types by forcing the type
201+ // Use type assertion to bypass type checking
202+ const settingIndex = provider . settings . findIndex (
203+ ( s ) => s . key === settingKey
204+ )
205+ ; (
206+ newSettings [ settingIndex ] . controller_props as {
207+ value : string | boolean | number
208+ }
209+ ) . value = true
210+
211+ // Create update object with updated settings
212+ const updateObj : Partial < ModelProvider > = {
213+ settings : newSettings ,
214+ }
215+
216+ await updateSettings ( providerName , updateObj . settings ?? [ ] )
217+ updateProvider ( providerName , {
218+ ...provider ,
219+ ...updateObj ,
220+ } )
221+ const updatedProvider = getProviderByName ( providerName )
222+ if ( updatedProvider )
223+ await restartModel ( updatedProvider , modelId , controller )
224+ return updatedProvider
225+ } ,
226+ [ updateProvider , getProviderByName , restartModel ]
159227 )
160228
161229 const sendMessage = useCallback (
@@ -167,7 +235,7 @@ export const useChat = () => {
167235 const activeThread = await getCurrentThread ( )
168236
169237 resetTokenSpeed ( )
170- const activeProvider = currentProviderId
238+ let activeProvider = currentProviderId
171239 ? getProviderByName ( currentProviderId )
172240 : provider
173241 if ( ! activeThread || ! activeProvider ) return
@@ -210,7 +278,11 @@ export const useChat = () => {
210278
211279 // TODO: Later replaced by Agent setup?
212280 const followUpWithToolUse = true
213- while ( ! isCompleted && ! abortController . signal . aborted ) {
281+ while (
282+ ! isCompleted &&
283+ ! abortController . signal . aborted &&
284+ activeProvider
285+ ) {
214286 const completion = await sendCompletion (
215287 activeThread ,
216288 activeProvider ,
@@ -229,56 +301,90 @@ export const useChat = () => {
229301 let accumulatedText = ''
230302 const currentCall : ChatCompletionMessageToolCall | null = null
231303 const toolCalls : ChatCompletionMessageToolCall [ ] = [ ]
232- if ( isCompletionResponse ( completion ) ) {
233- accumulatedText = completion . choices [ 0 ] ?. message ?. content || ''
234- if ( completion . choices [ 0 ] ?. message ?. tool_calls ) {
235- toolCalls . push ( ...completion . choices [ 0 ] . message . tool_calls )
236- }
237- } else {
238- for await ( const part of completion ) {
239- // Error message
240- if ( ! part . choices ) {
241- throw new Error (
242- 'message' in part
243- ? ( part . message as string )
244- : ( JSON . stringify ( part ) ?? '' )
245- )
304+ try {
305+ if ( isCompletionResponse ( completion ) ) {
306+ accumulatedText = completion . choices [ 0 ] ?. message ?. content || ''
307+ if ( completion . choices [ 0 ] ?. message ?. tool_calls ) {
308+ toolCalls . push ( ...completion . choices [ 0 ] . message . tool_calls )
246309 }
247- const delta = part . choices [ 0 ] ?. delta ?. content || ''
248-
249- if ( part . choices [ 0 ] ?. delta ?. tool_calls ) {
250- const calls = extractToolCall ( part , currentCall , toolCalls )
251- const currentContent = newAssistantThreadContent (
252- activeThread . id ,
253- accumulatedText ,
254- {
255- tool_calls : calls . map ( ( e ) => ( {
256- ...e ,
257- state : 'pending' ,
258- } ) ) ,
259- }
260- )
261- updateStreamingContent ( currentContent )
262- await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) )
310+ } else {
311+ for await ( const part of completion ) {
312+ // Error message
313+ if ( ! part . choices ) {
314+ throw new Error (
315+ 'message' in part
316+ ? ( part . message as string )
317+ : ( JSON . stringify ( part ) ?? '' )
318+ )
319+ }
320+ const delta = part . choices [ 0 ] ?. delta ?. content || ''
321+
322+ if ( part . choices [ 0 ] ?. delta ?. tool_calls ) {
323+ const calls = extractToolCall ( part , currentCall , toolCalls )
324+ const currentContent = newAssistantThreadContent (
325+ activeThread . id ,
326+ accumulatedText ,
327+ {
328+ tool_calls : calls . map ( ( e ) => ( {
329+ ...e ,
330+ state : 'pending' ,
331+ } ) ) ,
332+ }
333+ )
334+ updateStreamingContent ( currentContent )
335+ await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) )
336+ }
337+ if ( delta ) {
338+ accumulatedText += delta
339+ // Create a new object each time to avoid reference issues
340+ // Use a timeout to prevent React from batching updates too quickly
341+ const currentContent = newAssistantThreadContent (
342+ activeThread . id ,
343+ accumulatedText ,
344+ {
345+ tool_calls : toolCalls . map ( ( e ) => ( {
346+ ...e ,
347+ state : 'pending' ,
348+ } ) ) ,
349+ }
350+ )
351+ updateStreamingContent ( currentContent )
352+ updateTokenSpeed ( currentContent )
353+ await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) )
354+ }
263355 }
264- if ( delta ) {
265- accumulatedText += delta
266- // Create a new object each time to avoid reference issues
267- // Use a timeout to prevent React from batching updates too quickly
268- const currentContent = newAssistantThreadContent (
269- activeThread . id ,
270- accumulatedText ,
271- {
272- tool_calls : toolCalls . map ( ( e ) => ( {
273- ...e ,
274- state : 'pending' ,
275- } ) ) ,
276- }
356+ }
357+ } catch ( error ) {
358+ const errorMessage =
359+ error && typeof error === 'object' && 'message' in error
360+ ? error . message
361+ : error
362+ if (
363+ typeof errorMessage === 'string' &&
364+ errorMessage . includes ( OUT_OF_CONTEXT_SIZE ) &&
365+ selectedModel &&
366+ troubleshooting
367+ ) {
368+ const method = await showModal ?.( )
369+ if ( method === 'ctx_len' ) {
370+ /// Increase context size
371+ activeProvider = await increaseModelContextSize (
372+ selectedModel . id ,
373+ activeProvider ,
374+ abortController
277375 )
278- updateStreamingContent ( currentContent )
279- updateTokenSpeed ( currentContent )
280- await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) )
281- }
376+ continue
377+ } else if ( method === 'context_shift' && selectedModel ?. id ) {
378+ /// Enable context_shift
379+ activeProvider = await toggleOnContextShifting (
380+ selectedModel ?. id ,
381+ activeProvider ,
382+ abortController
383+ )
384+ continue
385+ } else throw error
386+ } else {
387+ throw error
282388 }
283389 }
284390 // TODO: Remove this check when integrating new llama.cpp extension
@@ -320,21 +426,7 @@ export const useChat = () => {
320426 error && typeof error === 'object' && 'message' in error
321427 ? error . message
322428 : error
323- if (
324- typeof errorMessage === 'string' &&
325- errorMessage . includes ( OUT_OF_CONTEXT_SIZE ) &&
326- selectedModel &&
327- troubleshooting
328- ) {
329- showModal ?.( ) . then ( ( confirmed ) => {
330- if ( confirmed ) {
331- increaseModelContextSize ( selectedModel , activeProvider )
332- setTimeout ( ( ) => {
333- sendMessage ( message , showModal , false ) // Retry sending the message without troubleshooting
334- } , 1000 )
335- }
336- } )
337- }
429+
338430 toast . error ( `Error sending message: ${ errorMessage } ` )
339431 console . error ( 'Error sending message:' , error )
340432 } finally {
@@ -355,7 +447,8 @@ export const useChat = () => {
355447 updateThreadTimestamp ,
356448 setPrompt ,
357449 selectedModel ,
358- currentAssistant ,
450+ currentAssistant ?. instructions ,
451+ currentAssistant . parameters ,
359452 tools ,
360453 updateLoadingModel ,
361454 getDisabledToolsForThread ,
@@ -364,6 +457,7 @@ export const useChat = () => {
364457 showApprovalModal ,
365458 updateTokenSpeed ,
366459 increaseModelContextSize ,
460+ toggleOnContextShifting ,
367461 ]
368462 )
369463
0 commit comments