fix: increase context size window does not popup first time

This commit is contained in:
Louis 2025-06-26 16:40:55 +07:00
parent 906c539541
commit 16aab0d661
No known key found for this signature in database
GPG Key ID: 44FA9F4D33C37DE2
7 changed files with 133 additions and 133 deletions

View File

@ -35,7 +35,6 @@ import { ModelLoader } from '@/containers/loaders/ModelLoader'
import DropdownToolsAvailable from '@/containers/DropdownToolsAvailable' import DropdownToolsAvailable from '@/containers/DropdownToolsAvailable'
import { getConnectedServers } from '@/services/mcp' import { getConnectedServers } from '@/services/mcp'
import { stopAllModels } from '@/services/models' import { stopAllModels } from '@/services/models'
import { useOutOfContextPromiseModal } from './dialogs/OutOfContextDialog'
type ChatInputProps = { type ChatInputProps = {
className?: string className?: string
@ -55,8 +54,6 @@ const ChatInput = ({ model, className, initialMessage }: ChatInputProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const { spellCheckChatInput } = useGeneralSetting() const { spellCheckChatInput } = useGeneralSetting()
const { showModal, PromiseModal: OutOfContextModal } =
useOutOfContextPromiseModal()
const maxRows = 10 const maxRows = 10
const { selectedModel } = useModelProvider() const { selectedModel } = useModelProvider()
@ -107,7 +104,7 @@ const ChatInput = ({ model, className, initialMessage }: ChatInputProps) => {
return return
} }
setMessage('') setMessage('')
sendMessage(prompt, showModal) sendMessage(prompt)
} }
useEffect(() => { useEffect(() => {
@ -599,7 +596,6 @@ const ChatInput = ({ model, className, initialMessage }: ChatInputProps) => {
</div> </div>
</div> </div>
)} )}
<OutOfContextModal />
</div> </div>
) )
} }

View File

@ -83,7 +83,6 @@ export const ThreadContent = memo(
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
streamTools?: any streamTools?: any
contextOverflowModal?: React.ReactNode | null contextOverflowModal?: React.ReactNode | null
showContextOverflowModal?: () => Promise<unknown>
} }
) => { ) => {
const [message, setMessage] = useState(item.content?.[0]?.text?.value || '') const [message, setMessage] = useState(item.content?.[0]?.text?.value || '')
@ -134,10 +133,7 @@ export const ThreadContent = memo(
} }
if (toSendMessage) { if (toSendMessage) {
deleteMessage(toSendMessage.thread_id, toSendMessage.id ?? '') deleteMessage(toSendMessage.thread_id, toSendMessage.id ?? '')
sendMessage( sendMessage(toSendMessage.content?.[0]?.text?.value || '')
toSendMessage.content?.[0]?.text?.value || '',
item.showContextOverflowModal
)
} }
}, [deleteMessage, getMessages, item, sendMessage]) }, [deleteMessage, getMessages, item, sendMessage])
@ -179,16 +175,9 @@ export const ThreadContent = memo(
deleteMessage(threadMessages[i].thread_id, threadMessages[i].id) deleteMessage(threadMessages[i].thread_id, threadMessages[i].id)
} }
sendMessage(message, item.showContextOverflowModal) sendMessage(message)
}, },
[ [deleteMessage, getMessages, item.thread_id, message, sendMessage]
deleteMessage,
getMessages,
item.thread_id,
message,
sendMessage,
item.showContextOverflowModal,
]
) )
const isToolCalls = const isToolCalls =

View File

@ -8,108 +8,76 @@ import {
DialogTitle, DialogTitle,
} from '@/components/ui/dialog' } from '@/components/ui/dialog'
import { ReactNode, useCallback, useState } from 'react'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { useContextSizeApproval } from '@/hooks/useModelContextApproval'
export function useOutOfContextPromiseModal() { export default function OutOfContextPromiseModal() {
const [isOpen, setIsOpen] = useState(false) const { isModalOpen, modalProps, setModalOpen } = useContextSizeApproval()
const [modalProps, setModalProps] = useState<{ if (!modalProps) {
resolveRef: return null
| ((value: 'ctx_len' | 'context_shift' | undefined) => void) }
| null const { onApprove, onDeny } = modalProps
}>({
resolveRef: null,
})
// Function to open the modal and return a Promise
const showModal = useCallback(() => {
return new Promise((resolve) => {
setModalProps({
resolveRef: resolve,
})
setIsOpen(true)
})
}, [])
const PromiseModal = useCallback((): ReactNode => { const handleContextLength = () => {
if (!isOpen) { onApprove('ctx_len')
return null }
const handleContextShift = () => {
onApprove('context_shift')
}
const handleDialogOpen = (open: boolean) => {
setModalOpen(open)
if (!open) {
onDeny()
} }
}
const handleContextLength = () => { return (
setIsOpen(false) <Dialog open={isModalOpen} onOpenChange={handleDialogOpen}>
if (modalProps.resolveRef) { <DialogContent>
modalProps.resolveRef('ctx_len') <DialogHeader>
} <DialogTitle>
} {t('outOfContextError.title', 'Out of context error')}
</DialogTitle>
const handleContextShift = () => { </DialogHeader>
setIsOpen(false) <DialogDescription>
if (modalProps.resolveRef) { {t(
modalProps.resolveRef('context_shift') 'outOfContextError.description',
} 'This chat is reaching the AIs memory limit, like a whiteboard filling up. We can expand the memory window (called context size) so it remembers more, but it may use more of your computers memory. We can also truncate the input, which means it will forget some of the chat history to make room for new messages.'
} )}
const handleCancel = () => { <br />
setIsOpen(false) <br />
if (modalProps.resolveRef) { {t(
modalProps.resolveRef(undefined) 'outOfContextError.increaseContextSizeDescription',
} 'Do you want to increase the context size?'
} )}
</DialogDescription>
return ( <DialogFooter className="flex gap-2">
<Dialog <Button
open={isOpen} variant="default"
onOpenChange={(open) => { className="bg-transparent border border-main-view-fg/20 hover:bg-main-view-fg/4"
setIsOpen(open) onClick={() => {
if (!open) handleCancel() handleContextShift()
}} }}
> >
<DialogContent> {t('outOfContextError.truncateInput', 'Truncate Input')}
<DialogHeader> </Button>
<DialogTitle> <Button
{t('outOfContextError.title', 'Out of context error')} asChild
</DialogTitle> onClick={() => {
</DialogHeader> handleContextLength()
<DialogDescription> }}
{t( >
'outOfContextError.description', <span className="text-main-view-fg/70">
'This chat is reaching the AIs memory limit, like a whiteboard filling up. We can expand the memory window (called context size) so it remembers more, but it may use more of your computers memory. We can also truncate the input, which means it will forget some of the chat history to make room for new messages.' {t(
)} 'outOfContextError.increaseContextSize',
<br /> 'Increase Context Size'
<br /> )}
{t( </span>
'outOfContextError.increaseContextSizeDescription', </Button>
'Do you want to increase the context size?' </DialogFooter>
)} </DialogContent>
</DialogDescription> </Dialog>
<DialogFooter className="flex gap-2"> )
<Button
variant="default"
className="bg-transparent border border-main-view-fg/20 hover:bg-main-view-fg/4"
onClick={() => {
handleContextShift()
setIsOpen(false)
}}
>
{t('outOfContextError.truncateInput', 'Truncate Input')}
</Button>
<Button
asChild
onClick={() => {
handleContextLength()
setIsOpen(false)
}}
>
<span className="text-main-view-fg/70">
{t(
'outOfContextError.increaseContextSize',
'Increase Context Size'
)}
</span>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}, [isOpen, modalProps])
return { showModal, PromiseModal }
} }

View File

@ -30,6 +30,7 @@ import { useToolApproval } from '@/hooks/useToolApproval'
import { useToolAvailable } from '@/hooks/useToolAvailable' import { useToolAvailable } from '@/hooks/useToolAvailable'
import { OUT_OF_CONTEXT_SIZE } from '@/utils/error' import { OUT_OF_CONTEXT_SIZE } from '@/utils/error'
import { updateSettings } from '@/services/providers' import { updateSettings } from '@/services/providers'
import { useContextSizeApproval } from './useModelContextApproval'
export const useChat = () => { export const useChat = () => {
const { prompt, setPrompt } = usePrompt() const { prompt, setPrompt } = usePrompt()
@ -47,6 +48,8 @@ export const useChat = () => {
const { approvedTools, showApprovalModal, allowAllMCPPermissions } = const { approvedTools, showApprovalModal, allowAllMCPPermissions } =
useToolApproval() useToolApproval()
const { showApprovalModal: showIncreaseContextSizeModal } =
useContextSizeApproval()
const { getDisabledToolsForThread } = useToolAvailable() const { getDisabledToolsForThread } = useToolAvailable()
const { getProviderByName, selectedModel, selectedProvider } = const { getProviderByName, selectedModel, selectedProvider } =
@ -223,11 +226,7 @@ export const useChat = () => {
) )
const sendMessage = useCallback( const sendMessage = useCallback(
async ( async (message: string, troubleshooting = true) => {
message: string,
showModal?: () => Promise<unknown>,
troubleshooting = true
) => {
const activeThread = await getCurrentThread() const activeThread = await getCurrentThread()
resetTokenSpeed() resetTokenSpeed()
@ -361,7 +360,7 @@ export const useChat = () => {
selectedModel && selectedModel &&
troubleshooting troubleshooting
) { ) {
const method = await showModal?.() const method = await showIncreaseContextSizeModal()
if (method === 'ctx_len') { if (method === 'ctx_len') {
/// Increase context size /// Increase context size
activeProvider = await increaseModelContextSize( activeProvider = await increaseModelContextSize(
@ -447,8 +446,7 @@ export const useChat = () => {
updateThreadTimestamp, updateThreadTimestamp,
setPrompt, setPrompt,
selectedModel, selectedModel,
currentAssistant?.instructions, currentAssistant,
currentAssistant.parameters,
tools, tools,
updateLoadingModel, updateLoadingModel,
getDisabledToolsForThread, getDisabledToolsForThread,
@ -456,6 +454,7 @@ export const useChat = () => {
allowAllMCPPermissions, allowAllMCPPermissions,
showApprovalModal, showApprovalModal,
updateTokenSpeed, updateTokenSpeed,
showIncreaseContextSizeModal,
increaseModelContextSize, increaseModelContextSize,
toggleOnContextShifting, toggleOnContextShifting,
] ]

View File

@ -0,0 +1,53 @@
import { create } from 'zustand'
export type ApprovalModalProps = {
onApprove: (method: 'ctx_len' | 'context_shift') => void
onDeny: () => void
}
type ApprovalState = {
// Modal state
isModalOpen: boolean
modalProps: ApprovalModalProps | null
showApprovalModal: () => Promise<'ctx_len' | 'context_shift' | undefined>
closeModal: () => void
setModalOpen: (open: boolean) => void
}
export const useContextSizeApproval = create<ApprovalState>()((set, get) => ({
isModalOpen: false,
modalProps: null,
showApprovalModal: async () => {
return new Promise<'ctx_len' | 'context_shift' | undefined>((resolve) => {
set({
isModalOpen: true,
modalProps: {
onApprove: (method) => {
get().closeModal()
resolve(method)
},
onDeny: () => {
get().closeModal()
resolve(undefined)
},
},
})
})
},
closeModal: () => {
set({
isModalOpen: false,
modalProps: null,
})
},
setModalOpen: (open: boolean) => {
set({ isModalOpen: open })
if (!open) {
get().closeModal()
}
},
}))

View File

@ -18,6 +18,7 @@ import { AnalyticProvider } from '@/providers/AnalyticProvider'
import { useLeftPanel } from '@/hooks/useLeftPanel' import { useLeftPanel } from '@/hooks/useLeftPanel'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import ToolApproval from '@/containers/dialogs/ToolApproval' import ToolApproval from '@/containers/dialogs/ToolApproval'
import OutOfContextPromiseModal from '@/containers/dialogs/OutOfContextDialog'
export const Route = createRootRoute({ export const Route = createRootRoute({
component: RootLayout, component: RootLayout,
@ -94,6 +95,7 @@ function RootLayout() {
{/* <TanStackRouterDevtools position="bottom-right" /> */} {/* <TanStackRouterDevtools position="bottom-right" /> */}
<CortexFailureDialog /> <CortexFailureDialog />
<ToolApproval /> <ToolApproval />
<OutOfContextPromiseModal />
</Fragment> </Fragment>
) )
} }

View File

@ -18,7 +18,6 @@ import { useAppState } from '@/hooks/useAppState'
import DropdownAssistant from '@/containers/DropdownAssistant' import DropdownAssistant from '@/containers/DropdownAssistant'
import { useAssistant } from '@/hooks/useAssistant' import { useAssistant } from '@/hooks/useAssistant'
import { useAppearance } from '@/hooks/useAppearance' import { useAppearance } from '@/hooks/useAppearance'
import { useOutOfContextPromiseModal } from '@/containers/dialogs/OutOfContextDialog'
// as route.threadsDetail // as route.threadsDetail
export const Route = createFileRoute('/threads/$threadId')({ export const Route = createFileRoute('/threads/$threadId')({
@ -48,8 +47,6 @@ function ThreadDetail() {
const scrollContainerRef = useRef<HTMLDivElement>(null) const scrollContainerRef = useRef<HTMLDivElement>(null)
const isFirstRender = useRef(true) const isFirstRender = useRef(true)
const messagesCount = useMemo(() => messages?.length ?? 0, [messages]) const messagesCount = useMemo(() => messages?.length ?? 0, [messages])
const { showModal, PromiseModal: OutOfContextModal } =
useOutOfContextPromiseModal()
// Function to check scroll position and scrollbar presence // Function to check scroll position and scrollbar presence
const checkScrollState = () => { const checkScrollState = () => {
@ -196,8 +193,6 @@ function ThreadDetail() {
if (!messages || !threadModel) return null if (!messages || !threadModel) return null
const contextOverflowModalComponent = <OutOfContextModal />
return ( return (
<div className="flex flex-col h-full"> <div className="flex flex-col h-full">
<HeaderPage> <HeaderPage>
@ -243,8 +238,6 @@ function ThreadDetail() {
)) ))
} }
index={index} index={index}
showContextOverflowModal={showModal}
contextOverflowModal={contextOverflowModalComponent}
/> />
</div> </div>
) )