Merge pull request #7376 from janhq/fix/update-renderer-using-plugins
fix: update renderer using plugins
This commit is contained in:
@@ -96,7 +96,8 @@ jobs:
|
||||
- name: Build app
|
||||
run: |
|
||||
make build
|
||||
env:
|
||||
env:
|
||||
NODE_OPTIONS: "--max-old-space-size=4196"
|
||||
APP_PATH: '.'
|
||||
|
||||
- name: Upload Artifact
|
||||
|
||||
@@ -173,6 +173,7 @@ jobs:
|
||||
run: |
|
||||
make build
|
||||
env:
|
||||
NODE_OPTIONS: "--max-old-space-size=4196"
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
APP_PATH: '.'
|
||||
POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }}
|
||||
|
||||
@@ -39,6 +39,10 @@
|
||||
"@radix-ui/react-slot": "1.2.0",
|
||||
"@radix-ui/react-switch": "1.2.2",
|
||||
"@radix-ui/react-tooltip": "1.2.4",
|
||||
"@streamdown/cjk": "^1.0.1",
|
||||
"@streamdown/code": "^1.0.1",
|
||||
"@streamdown/math": "^1.0.1",
|
||||
"@streamdown/mermaid": "^1.0.1",
|
||||
"@tabler/icons-react": "3.34.0",
|
||||
"@tailwindcss/vite": "4.1.4",
|
||||
"@tanstack/react-router": "^1.121.34",
|
||||
@@ -86,7 +90,7 @@
|
||||
"remark-math": "6.0.0",
|
||||
"shiki": "^3.19.0",
|
||||
"sonner": "2.0.5",
|
||||
"streamdown": "npm:@janhq/streamdown@^2.0.2",
|
||||
"streamdown": "npm:@janhq/streamdown@^2.1.1",
|
||||
"tailwindcss": "4.1.17",
|
||||
"token.js": "npm:token.js-fork@0.7.31",
|
||||
"tw-animate-css": "1.2.8",
|
||||
|
||||
@@ -154,12 +154,6 @@ const ChatInput = ({
|
||||
const [isDragOver, setIsDragOver] = useState(false)
|
||||
const [hasMmproj, setHasMmproj] = useState(false)
|
||||
const activeModels = useAppState(useShallow((state) => state.activeModels))
|
||||
const hasActiveModels = useMemo(
|
||||
() =>
|
||||
activeModels.length > 0 &&
|
||||
activeModels.some((e) => e === selectedModel?.id),
|
||||
[activeModels, selectedModel?.id]
|
||||
)
|
||||
|
||||
// Jan Browser Extension hook
|
||||
const {
|
||||
@@ -1694,7 +1688,6 @@ const ChatInput = ({
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
{selectedProvider === 'llamacpp' &&
|
||||
hasActiveModels &&
|
||||
tokenCounterCompact &&
|
||||
!initialMessage &&
|
||||
(threadMessages?.length > 0 || prompt.trim().length > 0) && (
|
||||
@@ -1762,7 +1755,6 @@ const ChatInput = ({
|
||||
)}
|
||||
|
||||
{selectedProvider === 'llamacpp' &&
|
||||
hasActiveModels &&
|
||||
!tokenCounterCompact &&
|
||||
!initialMessage &&
|
||||
(threadMessages?.length > 0 || prompt.trim().length > 0) && (
|
||||
|
||||
@@ -357,7 +357,7 @@ export const MessageItem = memo(
|
||||
|
||||
{/* Message actions for assistant messages (non-tool) */}
|
||||
{message.role === 'assistant' &&
|
||||
message.parts.some((p) => p.type === 'text') && (
|
||||
message.parts.some((p) => p.type === 'text' && p.text.length > 0) && (
|
||||
<div className="flex items-center gap-2 text-main-view-fg/60 text-xs">
|
||||
<div
|
||||
className={cn(
|
||||
|
||||
@@ -4,6 +4,11 @@ import { memo, useMemo } from 'react'
|
||||
import { cn } from '@/lib/utils'
|
||||
// import 'katex/dist/katex.min.css'
|
||||
import { defaultRehypePlugins, Streamdown } from 'streamdown'
|
||||
import { cjk } from '@streamdown/cjk'
|
||||
import { code } from '@streamdown/code'
|
||||
import { math } from '@streamdown/math'
|
||||
import { mermaid } from '@streamdown/mermaid'
|
||||
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import remarkMath from 'remark-math'
|
||||
import rehypeKatex from 'rehype-katex'
|
||||
@@ -107,6 +112,12 @@ function RenderMarkdownComponent({
|
||||
defaultRehypePlugins.harden,
|
||||
]}
|
||||
components={components}
|
||||
plugins={{
|
||||
code: code,
|
||||
mermaid: mermaid,
|
||||
math: math,
|
||||
cjk: cjk,
|
||||
}}
|
||||
mermaid={
|
||||
messageId
|
||||
? {
|
||||
|
||||
@@ -578,118 +578,4 @@ describe('useMCPServers', () => {
|
||||
expect(result.current.deletedServerKeys).toContain('lifecycle-server')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Proactive Mode Settings', () => {
|
||||
it('should have proactiveMode in default settings', () => {
|
||||
expect(DEFAULT_MCP_SETTINGS.proactiveMode).toBeDefined()
|
||||
expect(DEFAULT_MCP_SETTINGS.proactiveMode).toBe(false)
|
||||
})
|
||||
|
||||
it('should initialize proactiveMode as false', () => {
|
||||
const { result } = renderHook(() => useMCPServers())
|
||||
|
||||
expect(result.current.settings.proactiveMode).toBe(false)
|
||||
})
|
||||
|
||||
it('should update proactiveMode using updateSettings', () => {
|
||||
const { result } = renderHook(() => useMCPServers())
|
||||
|
||||
act(() => {
|
||||
result.current.updateSettings({ proactiveMode: true })
|
||||
})
|
||||
|
||||
expect(result.current.settings.proactiveMode).toBe(true)
|
||||
})
|
||||
|
||||
it('should toggle proactiveMode on and off', () => {
|
||||
const { result } = renderHook(() => useMCPServers())
|
||||
|
||||
// Initially false
|
||||
expect(result.current.settings.proactiveMode).toBe(false)
|
||||
|
||||
// Toggle to true
|
||||
act(() => {
|
||||
result.current.updateSettings({ proactiveMode: true })
|
||||
})
|
||||
|
||||
expect(result.current.settings.proactiveMode).toBe(true)
|
||||
|
||||
// Toggle back to false
|
||||
act(() => {
|
||||
result.current.updateSettings({ proactiveMode: false })
|
||||
})
|
||||
|
||||
expect(result.current.settings.proactiveMode).toBe(false)
|
||||
})
|
||||
|
||||
it('should not affect other settings when updating proactiveMode', () => {
|
||||
const { result } = renderHook(() => useMCPServers())
|
||||
|
||||
const originalSettings = { ...result.current.settings }
|
||||
|
||||
act(() => {
|
||||
result.current.updateSettings({ proactiveMode: true })
|
||||
})
|
||||
|
||||
expect(result.current.settings.toolCallTimeoutSeconds).toBe(
|
||||
originalSettings.toolCallTimeoutSeconds
|
||||
)
|
||||
expect(result.current.settings.baseRestartDelayMs).toBe(
|
||||
originalSettings.baseRestartDelayMs
|
||||
)
|
||||
expect(result.current.settings.maxRestartDelayMs).toBe(
|
||||
originalSettings.maxRestartDelayMs
|
||||
)
|
||||
expect(result.current.settings.backoffMultiplier).toBe(
|
||||
originalSettings.backoffMultiplier
|
||||
)
|
||||
})
|
||||
|
||||
it('should update proactiveMode along with other settings', () => {
|
||||
const { result } = renderHook(() => useMCPServers())
|
||||
|
||||
act(() => {
|
||||
result.current.updateSettings({
|
||||
proactiveMode: true,
|
||||
toolCallTimeoutSeconds: 60,
|
||||
})
|
||||
})
|
||||
|
||||
expect(result.current.settings.proactiveMode).toBe(true)
|
||||
expect(result.current.settings.toolCallTimeoutSeconds).toBe(60)
|
||||
})
|
||||
|
||||
it('should call syncServers with proactiveMode included in settings', async () => {
|
||||
const { result } = renderHook(() => useMCPServers())
|
||||
|
||||
act(() => {
|
||||
result.current.updateSettings({ proactiveMode: true })
|
||||
})
|
||||
|
||||
await act(async () => {
|
||||
await result.current.syncServers()
|
||||
})
|
||||
|
||||
expect(mockUpdateMCPConfig).toHaveBeenCalledWith(
|
||||
expect.stringContaining('proactiveMode')
|
||||
)
|
||||
})
|
||||
|
||||
it('should persist proactiveMode setting through setSettings', () => {
|
||||
const { result } = renderHook(() => useMCPServers())
|
||||
|
||||
const newSettings = {
|
||||
...DEFAULT_MCP_SETTINGS,
|
||||
proactiveMode: true,
|
||||
toolCallTimeoutSeconds: 45,
|
||||
}
|
||||
|
||||
act(() => {
|
||||
result.current.setSettings(newSettings)
|
||||
})
|
||||
|
||||
expect(result.current.settings.proactiveMode).toBe(true)
|
||||
expect(result.current.settings.toolCallTimeoutSeconds).toBe(45)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -176,10 +176,6 @@ export function useJanBrowserExtension() {
|
||||
} catch (error) {
|
||||
// Don't show error if cancelled
|
||||
if (cancelledRef.current) return
|
||||
|
||||
toast.error('Failed to toggle Jan Browser MCP', {
|
||||
description: error instanceof Error ? error.message : String(error),
|
||||
})
|
||||
console.error('Error toggling Jan Browser MCP:', error)
|
||||
setDialogOpen(false)
|
||||
setDialogState('closed')
|
||||
|
||||
@@ -24,7 +24,6 @@ export type MCPSettings = {
|
||||
baseRestartDelayMs: number
|
||||
maxRestartDelayMs: number
|
||||
backoffMultiplier: number
|
||||
proactiveMode: boolean
|
||||
}
|
||||
|
||||
export const DEFAULT_MCP_SETTINGS: MCPSettings = {
|
||||
@@ -32,7 +31,6 @@ export const DEFAULT_MCP_SETTINGS: MCPSettings = {
|
||||
baseRestartDelayMs: 1000,
|
||||
maxRestartDelayMs: 30000,
|
||||
backoffMultiplier: 2,
|
||||
proactiveMode: false,
|
||||
}
|
||||
|
||||
type MCPServerStoreState = {
|
||||
|
||||
@@ -41,9 +41,6 @@ export type ServiceHub = {
|
||||
Array<{ name: string; description: string; inputSchema: unknown }>
|
||||
>
|
||||
}
|
||||
models(): {
|
||||
startModel(provider: ProviderObject, model: string): Promise<unknown>
|
||||
}
|
||||
}
|
||||
|
||||
export class CustomChatTransport implements ChatTransport<UIMessage> {
|
||||
@@ -225,20 +222,17 @@ export class CustomChatTransport implements ChatTransport<UIMessage> {
|
||||
const updatedProvider = useModelProvider
|
||||
.getState()
|
||||
.getProviderByName(this.provider.provider)
|
||||
// Start the model (this will be a no-op for remote providers)
|
||||
await this.serviceHub
|
||||
.models()
|
||||
.startModel(updatedProvider ?? this.provider, this.modelId)
|
||||
|
||||
// Create the model using the factory
|
||||
// For llamacpp provider, startModel is called internally in ModelFactory.createLlamaCppModel
|
||||
this.model = await ModelFactory.createModel(
|
||||
this.modelId,
|
||||
updatedProvider ?? this.provider
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('Failed to start model:', error)
|
||||
console.error('Failed to create model:', error)
|
||||
throw new Error(
|
||||
`Failed to start model: ${error instanceof Error ? error.message : String(error)}`
|
||||
`Failed to create model: ${error instanceof Error ? error.message : JSON.stringify(error)}`
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -106,7 +106,7 @@ export class ModelFactory {
|
||||
|
||||
switch (providerName) {
|
||||
case 'llamacpp':
|
||||
return this.createLlamaCppModel(modelId)
|
||||
return this.createLlamaCppModel(modelId, provider)
|
||||
|
||||
case 'anthropic':
|
||||
return this.createAnthropicModel(modelId, provider)
|
||||
@@ -131,11 +131,29 @@ export class ModelFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a llamacpp model by finding the running session
|
||||
* Create a llamacpp model by starting the model and finding the running session
|
||||
*/
|
||||
private static async createLlamaCppModel(
|
||||
modelId: string
|
||||
modelId: string,
|
||||
provider?: ProviderObject
|
||||
): Promise<LanguageModel> {
|
||||
// Start the model first if provider is available
|
||||
if (provider) {
|
||||
try {
|
||||
const { useServiceStore } = await import('@/hooks/useServiceHub')
|
||||
const serviceHub = useServiceStore.getState().serviceHub
|
||||
|
||||
if (serviceHub) {
|
||||
await serviceHub.models().startModel(provider, modelId)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to start llamacpp model:', error)
|
||||
throw new Error(
|
||||
`Failed to start model: ${error instanceof Error ? error.message : JSON.stringify(error)}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Get session info which includes port and api_key
|
||||
const sessionInfo = await invoke<SessionInfo | null>(
|
||||
'plugin:llamacpp|find_session_by_model',
|
||||
|
||||
@@ -59,7 +59,5 @@
|
||||
"description": "Nakonfigurujte, jak Jan spravuje a opakuje pokusy se servery MCP.",
|
||||
"toolCallTimeout": "Časový limit volání nástroje (sekundy)",
|
||||
"toolCallTimeoutDesc": "Maximální doba čekání na odpověď nástroje MCP před vypršením časového limitu."
|
||||
},
|
||||
"proactiveMode": "Proaktivní režim používání prohlížeče",
|
||||
"proactiveModeDesc": "Pokud je povoleno, automaticky zachytává snímky obrazovky prohlížeče, aby poskytl další kontext pro úlohy automatizace prohlížeče. Vyžaduje Jan Browser MCP s modelem pro vidění a použití nástrojů."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,5 @@
|
||||
"description": "Konfiguriere, wie Jan MCP-Server verwaltet und erneut versucht.",
|
||||
"toolCallTimeout": "Zeitlimit für Tool-Aufruf (Sekunden)",
|
||||
"toolCallTimeoutDesc": "Maximale Wartezeit auf eine Antwort eines MCP-Tools, bevor abgebrochen wird."
|
||||
},
|
||||
"proactiveMode": "Browser Use Proaktiv-Modus",
|
||||
"proactiveModeDesc": "Wenn aktiviert, werden automatisch Browser-Screenshots erfasst, um zusätzlichen Kontext für Browser-Automatisierungsaufgaben bereitzustellen. Erfordert Jan Browser MCP mit Vision- und Tool-Nutzungsmodell."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,5 @@
|
||||
"description": "Configure how Jan manages and retries MCP servers.",
|
||||
"toolCallTimeout": "Tool call timeout (seconds)",
|
||||
"toolCallTimeoutDesc": "Maximum time to wait for an MCP tool response before timing out."
|
||||
},
|
||||
"proactiveMode": "Browser Use Proactive Mode",
|
||||
"proactiveModeDesc": "When enabled, automatically captures browser screenshots to provide additional context for browser automation tasks. Requires Jan Browser MCP with vision and tool use model."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,5 @@
|
||||
"description": "Configurez comment Jan gère et réessaye les serveurs MCP.",
|
||||
"toolCallTimeout": "Délai d'appel d'outil (secondes)",
|
||||
"toolCallTimeoutDesc": "Temps maximum d'attente pour une réponse d'outil MCP avant l'expiration du délai."
|
||||
},
|
||||
"proactiveMode": "Mode Proactif d'Utilisation du Navigateur",
|
||||
"proactiveModeDesc": "Lorsqu'activé, capture automatiquement des captures d'écran du navigateur pour fournir un contexte supplémentaire pour les tâches d'automatisation du navigateur. Nécessite Jan Browser MCP avec un modèle de vision et d'utilisation d'outils."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,5 @@
|
||||
"description": "Atur bagaimana Jan mengelola dan mencoba ulang server MCP.",
|
||||
"toolCallTimeout": "Batas waktu pemanggilan alat (detik)",
|
||||
"toolCallTimeoutDesc": "Waktu maksimum menunggu respons alat MCP sebelum waktu habis."
|
||||
},
|
||||
"proactiveMode": "Mode Proaktif Penggunaan Browser",
|
||||
"proactiveModeDesc": "Jika diaktifkan, secara otomatis menangkap tangkapan layar browser untuk memberikan konteks tambahan untuk tugas otomasi browser. Memerlukan Jan Browser MCP dengan model vision dan penggunaan tool."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,5 @@
|
||||
"description": "JanがMCPサーバーを管理し再試行する方法を設定します。",
|
||||
"toolCallTimeout": "ツール呼び出しタイムアウト(秒)",
|
||||
"toolCallTimeoutDesc": "MCPツールの応答を待機する最大時間(タイムアウトまで)。"
|
||||
},
|
||||
"proactiveMode": "ブラウザ使用プロアクティブモード",
|
||||
"proactiveModeDesc": "有効にすると、ブラウザの自動化タスクに追加のコンテキストを提供するために、ブラウザのスクリーンショットを自動的にキャプチャします。VisionとToolを使用するモデルを備えたJan Browser MCPが必要です。"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,5 @@
|
||||
"description": "Skonfiguruj, jak Jan zarządza i ponawia próby połączenia z serwerami MCP.",
|
||||
"toolCallTimeout": "Limit czasu wywołania narzędzia (sekundy)",
|
||||
"toolCallTimeoutDesc": "Maksymalny czas oczekiwania na odpowiedź narzędzia MCP przed przekroczeniem limitu czasu."
|
||||
},
|
||||
"proactiveMode": "Tryb Proaktywnego Użycia Przeglądarki",
|
||||
"proactiveModeDesc": "Po włączeniu automatycznie przechwytuje zrzuty ekranu przeglądarki, aby zapewnić dodatkowy kontekst dla zadań automatyzacji przeglądarki. Wymaga Jan Browser MCP z modelem vision i narzędzi."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,5 @@
|
||||
"description": "Configure como o Jan gerencia e tenta novamente os servidores MCP.",
|
||||
"toolCallTimeout": "Tempo limite de chamada da ferramenta (segundos)",
|
||||
"toolCallTimeoutDesc": "Tempo máximo de espera por uma resposta da ferramenta MCP antes de atingir o tempo limite."
|
||||
},
|
||||
"proactiveMode": "Modo Proativo de Uso do Navegador",
|
||||
"proactiveModeDesc": "Quando habilitado, captura automaticamente capturas de tela do navegador para fornecer contexto adicional para tarefas de automação do navegador. Requer Jan Browser MCP com modelo de visão e uso de ferramentas."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,5 @@
|
||||
"description": "Настройте, как Jan управляет и перезапускает серверы MCP.",
|
||||
"toolCallTimeout": "Время ожидания вызова инструмента (секунды)",
|
||||
"toolCallTimeoutDesc": "Максимальное время ожидания ответа от инструмента MCP."
|
||||
},
|
||||
"proactiveMode": "Режим проактивного использования браузера",
|
||||
"proactiveModeDesc": "При включении автоматически создаёт снимки экрана браузера для предоставления дополнительного контекста задачам автоматизации браузера. Требуется браузер Jan MCP и модель с поддержкой зрения и использования инструментов."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,5 @@
|
||||
"description": "Cấu hình cách Jan quản lý và thử lại các máy chủ MCP.",
|
||||
"toolCallTimeout": "Thời gian chờ lệnh (giây)",
|
||||
"toolCallTimeoutDesc": "Thời gian tối đa chờ phản hồi từ công cụ MCP trước khi hết thời gian."
|
||||
},
|
||||
"proactiveMode": "Chế độ Chủ động Sử dụng Trình duyệt",
|
||||
"proactiveModeDesc": "Khi được bật, tự động chụp ảnh màn hình trình duyệt để cung cấp ngữ cảnh bổ sung cho các tác vụ tự động hóa trình duyệt. Yêu cầu Jan Browser MCP với mô hình vision và sử dụng công cụ."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,5 @@
|
||||
"description": "配置 Jan 如何管理和重试 MCP 服务器。",
|
||||
"toolCallTimeout": "工具调用超时时间(秒)",
|
||||
"toolCallTimeoutDesc": "在超时前等待 MCP 工具响应的最长时间。"
|
||||
},
|
||||
"proactiveMode": "浏览器使用主动模式",
|
||||
"proactiveModeDesc": "启用后,会自动捕获浏览器截图,为浏览器自动化任务提供额外的上下文信息。需要具备视觉和工具使用模型的 Jan Browser MCP。"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,5 @@
|
||||
"description": "設定 Jan 如何管理及重試 MCP 伺服器。",
|
||||
"toolCallTimeout": "工具呼叫逾時(秒)",
|
||||
"toolCallTimeoutDesc": "等待 MCP 工具回應的最長時間,超過即逾時。"
|
||||
},
|
||||
"proactiveMode": "瀏覽器使用主動模式",
|
||||
"proactiveModeDesc": "啟用後,會自動擷取瀏覽器螢幕截圖,為瀏覽器自動化工作提供額外的情境資訊。需要具備視覺與工具使用模型的 Jan Browser MCP。"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,28 +456,6 @@ function MCPServersDesktop() {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<CardItem
|
||||
title={
|
||||
<div className="flex items-center gap-2">
|
||||
<span>{t('mcp-servers:proactiveMode')}</span>
|
||||
<div className="text-xs bg-main-view-fg/10 border border-main-view-fg/20 text-main-view-fg/70 rounded-full py-0.5 px-2">
|
||||
<span>{t('mcp-servers:experimental')}</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
description={t('mcp-servers:proactiveModeDesc')}
|
||||
actions={
|
||||
<div className="flex-shrink-0 ml-4">
|
||||
<Switch
|
||||
checked={settings.proactiveMode}
|
||||
onCheckedChange={(checked) => {
|
||||
updateSettings({ proactiveMode: checked })
|
||||
void syncServers()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
{Object.keys(mcpServers).length === 0 ? (
|
||||
|
||||
@@ -45,6 +45,9 @@ import { processAttachmentsForSend } from '@/lib/attachmentProcessing'
|
||||
import { useAttachments } from '@/hooks/useAttachments'
|
||||
import { PromptProgress } from '@/components/PromptProgress'
|
||||
import { useToolAvailable } from '@/hooks/useToolAvailable'
|
||||
import { OUT_OF_CONTEXT_SIZE } from '@/utils/error'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { IconAlertCircle } from '@tabler/icons-react'
|
||||
|
||||
const CHAT_STATUS = {
|
||||
STREAMING: 'streaming',
|
||||
@@ -151,6 +154,7 @@ function ThreadDetail() {
|
||||
const {
|
||||
messages: chatMessages,
|
||||
status,
|
||||
error,
|
||||
sendMessage,
|
||||
regenerate,
|
||||
setMessages: setChatMessages,
|
||||
@@ -533,12 +537,7 @@ function ThreadDetail() {
|
||||
}
|
||||
})()
|
||||
}
|
||||
}, [
|
||||
threadId,
|
||||
languageModelId,
|
||||
languageModelProvider,
|
||||
processAndSendMessage,
|
||||
])
|
||||
}, [threadId, languageModelId, languageModelProvider, processAndSendMessage])
|
||||
|
||||
// Handle submit from ChatInput
|
||||
const handleSubmit = useCallback(
|
||||
@@ -600,6 +599,60 @@ function ThreadDetail() {
|
||||
// and generating a new response from the selected message
|
||||
regenerate(messageId ? { messageId } : undefined)
|
||||
}
|
||||
|
||||
// Handler for increasing context size
|
||||
const handleContextSizeIncrease = useCallback(async () => {
|
||||
if (!selectedModel) return
|
||||
|
||||
const updateProvider = useModelProvider.getState().updateProvider
|
||||
const provider = getProviderByName(selectedProvider)
|
||||
if (!provider) return
|
||||
|
||||
const modelIndex = provider.models.findIndex(
|
||||
(m) => m.id === selectedModel.id
|
||||
)
|
||||
if (modelIndex === -1) return
|
||||
|
||||
const model = provider.models[modelIndex]
|
||||
|
||||
// Increase context length by 50%
|
||||
const currentCtxLen =
|
||||
(model.settings?.ctx_len?.controller_props?.value as number) ?? 8192
|
||||
const newCtxLen = Math.round(Math.max(8192, currentCtxLen) * 1.5)
|
||||
|
||||
const updatedModel = {
|
||||
...model,
|
||||
settings: {
|
||||
...model.settings,
|
||||
ctx_len: {
|
||||
...(model.settings?.ctx_len ?? {}),
|
||||
controller_props: {
|
||||
...(model.settings?.ctx_len?.controller_props ?? {}),
|
||||
value: newCtxLen,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const updatedModels = [...provider.models]
|
||||
updatedModels[modelIndex] = updatedModel as Model
|
||||
|
||||
updateProvider(provider.provider, {
|
||||
models: updatedModels,
|
||||
})
|
||||
|
||||
await serviceHub.models().stopModel(selectedModel.id)
|
||||
|
||||
setTimeout(() => {
|
||||
handleRegenerate()
|
||||
}, 1000)
|
||||
}, [
|
||||
selectedModel,
|
||||
selectedProvider,
|
||||
getProviderByName,
|
||||
serviceHub,
|
||||
])
|
||||
|
||||
const threadModel = useMemo(() => thread?.model, [thread])
|
||||
|
||||
if (!threadModel) return null
|
||||
@@ -657,6 +710,36 @@ function ThreadDetail() {
|
||||
)
|
||||
})}
|
||||
{status === CHAT_STATUS.SUBMITTED && <PromptProgress />}
|
||||
{error && (
|
||||
<div className="px-4 py-3 mx-4 my-2 rounded-lg border border-destructive/50 bg-destructive/10">
|
||||
<div className="flex items-start gap-3">
|
||||
<IconAlertCircle className="size-5 text-destructive flex-shrink-0 mt-0.5" />
|
||||
<div className="flex-1">
|
||||
<p className="text-sm font-medium text-destructive mb-1">
|
||||
Error generating response
|
||||
</p>
|
||||
<p className="text-sm text-main-view-fg/70">
|
||||
{error.message}
|
||||
</p>
|
||||
{(error.message.toLowerCase().includes('context') &&
|
||||
(error.message.toLowerCase().includes('size') ||
|
||||
error.message.toLowerCase().includes('length') ||
|
||||
error.message.toLowerCase().includes('limit'))) ||
|
||||
error.message === OUT_OF_CONTEXT_SIZE ? (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="mt-3"
|
||||
onClick={handleContextSizeIncrease}
|
||||
>
|
||||
<IconAlertCircle className="size-4 mr-2" />
|
||||
Increase Context Size
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</ConversationContent>
|
||||
<ConversationScrollButton />
|
||||
</Conversation>
|
||||
|
||||
Reference in New Issue
Block a user