feat: Adding proactive button as experimental feature
This commit is contained in:
parent
2561fcd78a
commit
c773abb688
@ -10,6 +10,7 @@ import {
|
||||
IconAtom,
|
||||
IconWorld,
|
||||
IconCodeCircle2,
|
||||
IconSparkles,
|
||||
} from '@tabler/icons-react'
|
||||
import { Fragment } from 'react/jsx-runtime'
|
||||
|
||||
@ -29,6 +30,8 @@ const Capabilities = ({ capabilities }: CapabilitiesProps) => {
|
||||
icon = <IconEye className="size-4" />
|
||||
} else if (capability === 'tools') {
|
||||
icon = <IconTool className="size-3.5" />
|
||||
} else if (capability === 'proactive') {
|
||||
icon = <IconSparkles className="size-3.5" />
|
||||
} else if (capability === 'reasoning') {
|
||||
icon = <IconAtom className="size-3.5" />
|
||||
} else if (capability === 'embeddings') {
|
||||
@ -54,7 +57,11 @@ const Capabilities = ({ capabilities }: CapabilitiesProps) => {
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>
|
||||
{capability === 'web_search' ? 'Web Search' : capability}
|
||||
{capability === 'web_search'
|
||||
? 'Web Search'
|
||||
: capability === 'proactive'
|
||||
? 'Proactive'
|
||||
: capability}
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
@ -108,6 +108,7 @@ const ChatInput = ({
|
||||
const [connectedServers, setConnectedServers] = useState<string[]>([])
|
||||
const [isDragOver, setIsDragOver] = useState(false)
|
||||
const [hasMmproj, setHasMmproj] = useState(false)
|
||||
const [hasProactive, setHasProactive] = useState(false)
|
||||
const [hasActiveModels, setHasActiveModels] = useState(false)
|
||||
const attachmentsEnabled = useAttachments((s) => s.enabled)
|
||||
// Determine whether to show the Attach documents button (simple gating)
|
||||
@ -206,6 +207,29 @@ const ChatInput = ({
|
||||
checkMmprojSupport()
|
||||
}, [selectedModel, selectedModel?.capabilities, selectedProvider, serviceHub])
|
||||
|
||||
// Check for proactive capability when model changes
|
||||
useEffect(() => {
|
||||
const checkProactiveSupport = () => {
|
||||
if (selectedModel && selectedModel?.id) {
|
||||
// Proactive mode requires both tools and vision capabilities
|
||||
const hasTools = selectedModel?.capabilities?.includes('tools')
|
||||
const hasVision = selectedModel?.capabilities?.includes('vision')
|
||||
const hasProactiveCapability = selectedModel?.capabilities?.includes('proactive')
|
||||
|
||||
if (hasTools && hasVision && hasProactiveCapability) {
|
||||
setHasProactive(true)
|
||||
// TODO: Implement proactive mode template insertion
|
||||
// This is where we'll add the proactive mode prompt/template
|
||||
// when sending messages with models that have proactive capability enabled
|
||||
} else {
|
||||
setHasProactive(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkProactiveSupport()
|
||||
}, [selectedModel, selectedModel?.capabilities])
|
||||
|
||||
// Check if there are active MCP servers
|
||||
const hasActiveMCPServers = connectedServers.length > 0 || tools.length > 0
|
||||
|
||||
|
||||
@ -152,12 +152,19 @@ export const ModelInfoHoverCard = ({
|
||||
</div>
|
||||
|
||||
{/* Features Section */}
|
||||
{(model.num_mmproj > 0 || model.tools) && (
|
||||
{(model.num_mmproj > 0 || model.tools || (model.num_mmproj > 0 && model.tools)) && (
|
||||
<div className="border-t border-main-view-fg/10 pt-3">
|
||||
<h5 className="text-xs font-medium text-main-view-fg/70 mb-2">
|
||||
Features
|
||||
</h5>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{model.tools && (
|
||||
<div className="flex items-center gap-1.5 px-2 py-1 bg-main-view-fg/10 rounded-md">
|
||||
<span className="text-xs text-main-view-fg font-medium">
|
||||
Tools
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{model.num_mmproj > 0 && (
|
||||
<div className="flex items-center gap-1.5 px-2 py-1 bg-main-view-fg/10 rounded-md">
|
||||
<span className="text-xs text-main-view-fg font-medium">
|
||||
@ -165,10 +172,10 @@ export const ModelInfoHoverCard = ({
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{model.tools && (
|
||||
{model.num_mmproj > 0 && model.tools && (
|
||||
<div className="flex items-center gap-1.5 px-2 py-1 bg-main-view-fg/10 rounded-md">
|
||||
<span className="text-xs text-main-view-fg font-medium">
|
||||
Tools
|
||||
Proactive
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -82,6 +82,7 @@ vi.mock('@tabler/icons-react', () => ({
|
||||
IconEye: () => <div data-testid="eye-icon" />,
|
||||
IconTool: () => <div data-testid="tool-icon" />,
|
||||
IconLoader2: () => <div data-testid="loader-icon" />,
|
||||
IconSparkles: () => <div data-testid="sparkles-icon" />,
|
||||
}))
|
||||
|
||||
describe('DialogEditModel - Basic Component Tests', () => {
|
||||
@ -189,7 +190,7 @@ describe('DialogEditModel - Basic Component Tests', () => {
|
||||
{
|
||||
id: 'test-model.gguf',
|
||||
displayName: 'Test Model',
|
||||
capabilities: ['vision', 'tools'],
|
||||
capabilities: ['vision', 'tools', 'proactive'],
|
||||
},
|
||||
],
|
||||
settings: [],
|
||||
@ -226,7 +227,7 @@ describe('DialogEditModel - Basic Component Tests', () => {
|
||||
{
|
||||
id: 'test-model.gguf',
|
||||
displayName: 'Test Model',
|
||||
capabilities: ['vision', 'tools', 'completion', 'embeddings', 'web_search', 'reasoning'],
|
||||
capabilities: ['vision', 'tools', 'proactive', 'completion', 'embeddings', 'web_search', 'reasoning'],
|
||||
},
|
||||
],
|
||||
settings: [],
|
||||
@ -240,7 +241,7 @@ describe('DialogEditModel - Basic Component Tests', () => {
|
||||
)
|
||||
|
||||
// Component should render without errors even with extra capabilities
|
||||
// The capabilities helper should only extract vision and tools
|
||||
// The capabilities helper should only extract vision, tools, and proactive
|
||||
expect(container).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@ -17,6 +17,7 @@ import {
|
||||
IconTool,
|
||||
IconAlertTriangle,
|
||||
IconLoader2,
|
||||
IconSparkles,
|
||||
} from '@tabler/icons-react'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useTranslation } from '@/i18n/react-i18next-compat'
|
||||
@ -45,6 +46,7 @@ export const DialogEditModel = ({
|
||||
const [capabilities, setCapabilities] = useState<Record<string, boolean>>({
|
||||
vision: false,
|
||||
tools: false,
|
||||
proactive: false,
|
||||
})
|
||||
|
||||
// Initialize with the provided model ID or the first model if available
|
||||
@ -67,6 +69,7 @@ export const DialogEditModel = ({
|
||||
const capabilitiesToObject = (capabilitiesList: string[]) => ({
|
||||
vision: capabilitiesList.includes('vision'),
|
||||
tools: capabilitiesList.includes('tools'),
|
||||
proactive: capabilitiesList.includes('proactive'),
|
||||
})
|
||||
|
||||
// Initialize capabilities and display name from selected model
|
||||
@ -268,6 +271,23 @@ export const DialogEditModel = ({
|
||||
disabled={isLoading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<IconSparkles className="size-4 text-main-view-fg/70" />
|
||||
<span className="text-sm">
|
||||
{t('providers:editModel.proactive')}
|
||||
</span>
|
||||
</div>
|
||||
<Switch
|
||||
id="proactive-capability"
|
||||
checked={capabilities.proactive}
|
||||
onCheckedChange={(checked) =>
|
||||
handleCapabilityChange('proactive', checked)
|
||||
}
|
||||
disabled={isLoading || !(capabilities.tools && capabilities.vision)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -61,6 +61,7 @@
|
||||
"capabilities": "Fähigkeiten",
|
||||
"tools": "Werkzeuge",
|
||||
"vision": "Vision",
|
||||
"proactive": "Proaktiv (Experimentell)",
|
||||
"embeddings": "Einbettungen",
|
||||
"notAvailable": "Noch nicht verfügbar",
|
||||
"warning": {
|
||||
|
||||
@ -61,6 +61,7 @@
|
||||
"capabilities": "Capabilities",
|
||||
"tools": "Tools",
|
||||
"vision": "Vision",
|
||||
"proactive": "Proactive (Experimental)",
|
||||
"embeddings": "Embeddings",
|
||||
"notAvailable": "Not available yet",
|
||||
"warning": {
|
||||
|
||||
@ -61,6 +61,7 @@
|
||||
"capabilities": "Kemampuan",
|
||||
"tools": "Alat",
|
||||
"vision": "Visi",
|
||||
"proactive": "Proaktif (Eksperimental)",
|
||||
"embeddings": "Embedding",
|
||||
"notAvailable": "Belum tersedia",
|
||||
"warning": {
|
||||
|
||||
@ -61,6 +61,7 @@
|
||||
"capabilities": "Możliwości",
|
||||
"tools": "Narzędzia",
|
||||
"vision": "Wizja",
|
||||
"proactive": "Proaktywny (Eksperymentalny)",
|
||||
"embeddings": "Osadzenia",
|
||||
"notAvailable": "Jeszcze niedostępne",
|
||||
"warning": {
|
||||
|
||||
@ -61,6 +61,7 @@
|
||||
"capabilities": "Khả năng",
|
||||
"tools": "Công cụ",
|
||||
"vision": "Thị giác",
|
||||
"proactive": "Chủ động (Thử nghiệm)",
|
||||
"embeddings": "Nhúng",
|
||||
"notAvailable": "Chưa có",
|
||||
"warning": {
|
||||
|
||||
@ -61,6 +61,7 @@
|
||||
"capabilities": "功能",
|
||||
"tools": "工具",
|
||||
"vision": "视觉",
|
||||
"proactive": "主动模式(实验性)",
|
||||
"embeddings": "嵌入",
|
||||
"notAvailable": "尚不可用",
|
||||
"warning": {
|
||||
|
||||
@ -61,6 +61,7 @@
|
||||
"capabilities": "功能",
|
||||
"tools": "工具",
|
||||
"vision": "視覺",
|
||||
"proactive": "主動模式(實驗性)",
|
||||
"embeddings": "嵌入",
|
||||
"notAvailable": "尚不可用",
|
||||
"warning": {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user