add switch mode tool
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
||||
} from 'react'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
import { ModeSelect } from './chat-input/ModeSelect'
|
||||
import { ApplyViewState } from '../../ApplyView'
|
||||
import { APPLY_VIEW_TYPE } from '../../constants'
|
||||
import { useApp } from '../../contexts/AppContext'
|
||||
@@ -90,7 +91,7 @@ export type ChatProps = {
|
||||
|
||||
const Chat = forwardRef<ChatRef, ChatProps>((props, ref) => {
|
||||
const app = useApp()
|
||||
const { settings } = useSettings()
|
||||
const { settings, setSettings } = useSettings()
|
||||
const { getRAGEngine } = useRAG()
|
||||
|
||||
const {
|
||||
@@ -565,6 +566,25 @@ const Chat = forwardRef<ChatRef, ChatProps>((props, ref) => {
|
||||
mentionables: [],
|
||||
}
|
||||
}
|
||||
} else if (toolArgs.type === 'switch_mode') {
|
||||
setSettings({
|
||||
...settings,
|
||||
mode: toolArgs.mode,
|
||||
})
|
||||
const formattedContent = `[switch_mode to ${toolArgs.mode}] Result: successfully switched to ${toolArgs.mode}\n`
|
||||
return {
|
||||
type: 'switch_mode',
|
||||
applyMsgId,
|
||||
applyStatus: ApplyStatus.Applied,
|
||||
returnMsg: {
|
||||
role: 'user',
|
||||
applyStatus: ApplyStatus.Idle,
|
||||
content: null,
|
||||
promptContent: formattedContent,
|
||||
id: uuidv4(),
|
||||
mentionables: [],
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to apply changes', error)
|
||||
@@ -745,7 +765,7 @@ const Chat = forwardRef<ChatRef, ChatProps>((props, ref) => {
|
||||
return (
|
||||
<div className="infio-chat-container">
|
||||
<div className="infio-chat-header">
|
||||
<h1 className="infio-chat-header-title"> CHAT </h1>
|
||||
<ModeSelect />
|
||||
<div className="infio-chat-header-buttons">
|
||||
<button
|
||||
onClick={() => handleNewChat()}
|
||||
|
||||
82
src/components/chat-view/MarkdownSwitchModeBlock.tsx
Normal file
82
src/components/chat-view/MarkdownSwitchModeBlock.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Check, Loader2, Settings2, X } from 'lucide-react'
|
||||
import { PropsWithChildren, useState } from 'react'
|
||||
|
||||
import { useDarkModeContext } from '../../contexts/DarkModeContext'
|
||||
import { ApplyStatus, ToolArgs } from '../../types/apply'
|
||||
|
||||
import { MemoizedSyntaxHighlighterWrapper } from './SyntaxHighlighterWrapper'
|
||||
|
||||
export default function MarkdownSwitchModeBlock({
|
||||
mode,
|
||||
applyStatus,
|
||||
onApply,
|
||||
reason,
|
||||
finish,
|
||||
}: PropsWithChildren<{
|
||||
mode: string
|
||||
applyStatus: ApplyStatus
|
||||
onApply: (args: ToolArgs) => void
|
||||
reason: string
|
||||
finish: boolean
|
||||
}>) {
|
||||
const [applying, setApplying] = useState(false)
|
||||
const { isDarkMode } = useDarkModeContext()
|
||||
|
||||
const handleApply = async () => {
|
||||
if (applyStatus !== ApplyStatus.Idle) {
|
||||
return
|
||||
}
|
||||
setApplying(true)
|
||||
onApply({
|
||||
type: 'switch_mode',
|
||||
mode: mode,
|
||||
reason: reason,
|
||||
finish: finish,
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`infio-chat-code-block has-filename`}>
|
||||
<div className={'infio-chat-code-block-header'}>
|
||||
<div className={'infio-chat-code-block-header-filename'}>
|
||||
<Settings2 size={10} className="infio-chat-code-block-header-icon" />
|
||||
Switch to "{mode.charAt(0).toUpperCase() + mode.slice(1)}" mode
|
||||
</div>
|
||||
<div className={'infio-chat-code-block-header-button'}>
|
||||
<button
|
||||
onClick={handleApply}
|
||||
style={{ color: '#008000' }}
|
||||
disabled={applyStatus !== ApplyStatus.Idle || applying}
|
||||
>
|
||||
{applyStatus === ApplyStatus.Idle ? (
|
||||
applying ? (
|
||||
<>
|
||||
<Loader2 className="spinner" size={14} /> Allowing...
|
||||
</>
|
||||
) : (
|
||||
'Allow'
|
||||
)
|
||||
) : applyStatus === ApplyStatus.Applied ? (
|
||||
<>
|
||||
<Check size={14} /> Success
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<X size={14} /> Failed
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<MemoizedSyntaxHighlighterWrapper
|
||||
isDarkMode={isDarkMode}
|
||||
language="markdown"
|
||||
hasFilename={true}
|
||||
wrapLines={true}
|
||||
isOpen={true}
|
||||
>
|
||||
{reason}
|
||||
</MemoizedSyntaxHighlighterWrapper>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import MarkdownRegexSearchFilesBlock from './MarkdownRegexSearchFilesBlock'
|
||||
import MarkdownSearchAndReplace from './MarkdownSearchAndReplace'
|
||||
import MarkdownSearchWebBlock from './MarkdownSearchWebBlock'
|
||||
import MarkdownSemanticSearchFilesBlock from './MarkdownSemanticSearchFilesBlock'
|
||||
import MarkdownSwitchModeBlock from './MarkdownSwitchModeBlock'
|
||||
import MarkdownWithIcons from './MarkdownWithIcon'
|
||||
function ReactMarkdown({
|
||||
applyStatus,
|
||||
@@ -132,6 +133,15 @@ function ReactMarkdown({
|
||||
markdownContent={
|
||||
`<icon name='ask_followup_question' size={14} className="infio-markdown-icon" />
|
||||
${block.question && block.question.trimStart()}`} />
|
||||
) : block.type === 'switch_mode' ? (
|
||||
<MarkdownSwitchModeBlock
|
||||
key={"switch-mode-" + index}
|
||||
applyStatus={applyStatus}
|
||||
onApply={onApply}
|
||||
mode={block.mode}
|
||||
reason={block.reason}
|
||||
finish={block.finish}
|
||||
/>
|
||||
) : block.type === 'search_web' ? (
|
||||
<MarkdownSearchWebBlock
|
||||
key={"search-web-" + index}
|
||||
|
||||
53
src/components/chat-view/chat-input/ModeSelect.tsx
Normal file
53
src/components/chat-view/chat-input/ModeSelect.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
|
||||
import { ChevronDown, ChevronUp } from 'lucide-react'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import { useSettings } from '../../../contexts/SettingsContext'
|
||||
import { modes } from '../../../utils/modes'
|
||||
|
||||
export function ModeSelect() {
|
||||
const { settings, setSettings } = useSettings()
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const [mode, setMode] = useState(settings.mode)
|
||||
|
||||
useEffect(() => {
|
||||
setMode(settings.mode)
|
||||
}, [settings.mode])
|
||||
|
||||
|
||||
return (
|
||||
<DropdownMenu.Root open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DropdownMenu.Trigger className="infio-chat-input-model-select">
|
||||
<div className="infio-chat-input-model-select__icon">
|
||||
{isOpen ? <ChevronUp size={12} /> : <ChevronDown size={12} />}
|
||||
</div>
|
||||
<div className="infio-chat-input-model-select__model-name">
|
||||
{modes.find((m) => m.slug === mode)?.name}
|
||||
</div>
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content
|
||||
className="infio-popover">
|
||||
<ul>
|
||||
{modes.map((mode) => (
|
||||
<DropdownMenu.Item
|
||||
key={mode.slug}
|
||||
onSelect={() => {
|
||||
setMode(mode.slug)
|
||||
setSettings({
|
||||
...settings,
|
||||
mode: mode.slug,
|
||||
})
|
||||
}}
|
||||
asChild
|
||||
>
|
||||
<li>{mode.name}</li>
|
||||
</DropdownMenu.Item>
|
||||
))}
|
||||
</ul>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Portal>
|
||||
</DropdownMenu.Root>
|
||||
)
|
||||
}
|
||||
@@ -18,15 +18,16 @@ export function ModelSelect() {
|
||||
try {
|
||||
const models = await GetProviderModelIds(settings.chatModelProvider)
|
||||
setProviderModels(models)
|
||||
setChatModelId(settings.chatModelId)
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch provider models:', error)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fetchModels()
|
||||
}, [settings.chatModelProvider])
|
||||
}, [settings])
|
||||
|
||||
return (
|
||||
<DropdownMenu.Root open={isOpen} onOpenChange={setIsOpen}>
|
||||
|
||||
@@ -30,6 +30,7 @@ import { ImageUploadButton } from './ImageUploadButton'
|
||||
import LexicalContentEditable from './LexicalContentEditable'
|
||||
import MentionableBadge from './MentionableBadge'
|
||||
import { ModelSelect } from './ModelSelect'
|
||||
import { ModeSelect } from './ModeSelect'
|
||||
import { MentionNode } from './plugins/mention/MentionNode'
|
||||
import { NodeMutations } from './plugins/on-mutation/OnMutationPlugin'
|
||||
import { SubmitButton } from './SubmitButton'
|
||||
|
||||
Reference in New Issue
Block a user