Merge pull request #5542 from menloresearch/fix/increase-context-window-could-not-popup
This commit is contained in:
commit
0af271b05f
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 =
|
||||||
|
|||||||
@ -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 AI’s 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 computer’s 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 AI’s 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 computer’s 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 }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
]
|
]
|
||||||
|
|||||||
53
web-app/src/hooks/useModelContextApproval.ts
Normal file
53
web-app/src/hooks/useModelContextApproval.ts
Normal 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()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}))
|
||||||
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user