chore: handle many issues with app settings and message actions (#5086)
* chore: handle many issues with app settings and message actions * Update web-app/src/services/mcp.ts Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> --------- Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
This commit is contained in:
parent
634efb9d9d
commit
125104320e
@ -125,10 +125,25 @@ export const ThreadContent = memo(
|
||||
deleteMessage(toSendMessage.thread_id, toSendMessage.id ?? '')
|
||||
toSendMessage = threadMessages.pop()
|
||||
}
|
||||
if (toSendMessage)
|
||||
if (toSendMessage) {
|
||||
deleteMessage(toSendMessage.thread_id, toSendMessage.id ?? '')
|
||||
sendMessage(toSendMessage.content?.[0]?.text?.value || '')
|
||||
}
|
||||
}, [deleteMessage, getMessages, item, sendMessage])
|
||||
|
||||
const removeMessage = useCallback(() => {
|
||||
if (item.role === 'assistant' || item.role === 'tool') {
|
||||
const threadMessages = getMessages(item.thread_id)
|
||||
let toSendMessage = threadMessages.pop()
|
||||
while (toSendMessage && toSendMessage?.role !== 'user') {
|
||||
deleteMessage(toSendMessage.thread_id, toSendMessage.id ?? '')
|
||||
toSendMessage = threadMessages.pop()
|
||||
}
|
||||
} else {
|
||||
deleteMessage(item.thread_id, item.id)
|
||||
}
|
||||
}, [deleteMessage, getMessages, item])
|
||||
|
||||
const editMessage = useCallback(
|
||||
(messageId: string) => {
|
||||
const threadMessages = getMessages(item.thread_id)
|
||||
@ -302,7 +317,7 @@ export const ThreadContent = memo(
|
||||
<button
|
||||
className="flex items-center gap-1 hover:text-accent transition-colors cursor-pointer group relative"
|
||||
onClick={() => {
|
||||
deleteMessage(item.thread_id, item.id)
|
||||
removeMessage()
|
||||
}}
|
||||
>
|
||||
<IconTrash size={16} />
|
||||
|
||||
@ -118,14 +118,16 @@ export default function AddEditMCPServer({
|
||||
if (open && editingKey && initialData) {
|
||||
setServerName(editingKey)
|
||||
setCommand(initialData.command)
|
||||
setArgs(initialData.args.length > 0 ? initialData.args : [''])
|
||||
setArgs(initialData.args?.length > 0 ? initialData.args : [''])
|
||||
|
||||
if (initialData.env) {
|
||||
// Convert env object to arrays of keys and values
|
||||
const keys = Object.keys(initialData.env)
|
||||
const values = keys.map((key) => initialData.env[key])
|
||||
|
||||
setEnvKeys(keys.length > 0 ? keys : [''])
|
||||
setEnvValues(values.length > 0 ? values : [''])
|
||||
}
|
||||
} else if (open) {
|
||||
// Add mode - reset form
|
||||
resetForm()
|
||||
|
||||
@ -98,6 +98,9 @@ export const useChat = () => {
|
||||
let isCompleted = false
|
||||
|
||||
let attempts = 0
|
||||
const availableTools = selectedModel?.capabilities?.includes('tools')
|
||||
? tools
|
||||
: []
|
||||
while (
|
||||
!isCompleted &&
|
||||
!abortController.signal.aborted &&
|
||||
@ -110,9 +113,11 @@ export const useChat = () => {
|
||||
provider,
|
||||
builder.getMessages(),
|
||||
abortController,
|
||||
tools,
|
||||
availableTools,
|
||||
// TODO: replace it with according provider setting later on
|
||||
selectedProvider === 'llama.cpp' && tools.length > 0 ? false : true
|
||||
selectedProvider === 'llama.cpp' && availableTools.length > 0
|
||||
? false
|
||||
: true
|
||||
)
|
||||
|
||||
if (!completion) throw new Error('No completion received')
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
import { create } from 'zustand'
|
||||
import { persist, createJSONStorage } from 'zustand/middleware'
|
||||
import { localStorageKey } from '@/constants/localStorage'
|
||||
import { updateMCPConfig } from '@/services/mcp'
|
||||
|
||||
// Define the structure of an MCP server configuration
|
||||
@ -25,11 +23,10 @@ type MCPServerStoreState = {
|
||||
addServer: (key: string, config: MCPServerConfig) => void
|
||||
editServer: (key: string, config: MCPServerConfig) => void
|
||||
deleteServer: (key: string) => void
|
||||
setServers: (servers: MCPServers) => void
|
||||
}
|
||||
|
||||
export const useMCPServers = create<MCPServerStoreState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
export const useMCPServers = create<MCPServerStoreState>()((set) => ({
|
||||
open: true,
|
||||
mcpServers: {}, // Start with empty object
|
||||
loading: false,
|
||||
@ -54,7 +51,12 @@ export const useMCPServers = create<MCPServerStoreState>()(
|
||||
updateMCPConfig(JSON.stringify({ mcpServers }))
|
||||
return { mcpServers }
|
||||
}),
|
||||
|
||||
setServers: (servers) =>
|
||||
set((state) => {
|
||||
const mcpServers = { ...state.mcpServers, ...servers }
|
||||
updateMCPConfig(JSON.stringify({ mcpServers }))
|
||||
return { mcpServers }
|
||||
}),
|
||||
// Delete an MCP server by key
|
||||
deleteServer: (key) =>
|
||||
set((state) => {
|
||||
@ -75,10 +77,4 @@ export const useMCPServers = create<MCPServerStoreState>()(
|
||||
deletedServerKeys: [...state.deletedServerKeys, key],
|
||||
}
|
||||
}),
|
||||
}),
|
||||
{
|
||||
name: localStorageKey.settingMCPSevers, // Using existing key for now
|
||||
storage: createJSONStorage(() => localStorage),
|
||||
}
|
||||
)
|
||||
)
|
||||
}))
|
||||
|
||||
@ -33,8 +33,8 @@ export const useModelProvider = create<ModelProviderState>()(
|
||||
)
|
||||
const models = existingProvider?.models || []
|
||||
const mergedModels = [
|
||||
...(provider?.models ?? []),
|
||||
...models.filter(
|
||||
...models,
|
||||
...(provider?.models ?? []).filter(
|
||||
(e) => !provider?.models.some((m) => m.id === e.id)
|
||||
),
|
||||
]
|
||||
|
||||
@ -8,18 +8,22 @@ import { getProviders } from '@/services/providers'
|
||||
import { fetchThreads } from '@/services/threads'
|
||||
import { ModelManager } from '@janhq/core'
|
||||
import { useEffect } from 'react'
|
||||
import { useMCPServers } from '@/hooks/useMCPServers'
|
||||
import { getMCPConfig } from '@/services/mcp'
|
||||
|
||||
export function DataProvider() {
|
||||
const { setProviders } = useModelProvider()
|
||||
const { setThreads } = useThreads()
|
||||
const { setMessages } = useMessages()
|
||||
const { checkForUpdate } = useAppUpdater()
|
||||
const { setServers } = useMCPServers()
|
||||
|
||||
useEffect(() => {
|
||||
fetchModels().then((models) => {
|
||||
models?.forEach((model) => ModelManager.instance().register(model))
|
||||
getProviders().then(setProviders)
|
||||
})
|
||||
getMCPConfig().then((data) => setServers(data.mcpServers ?? []))
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
|
||||
@ -225,7 +225,7 @@ function Hardware() {
|
||||
title="Name"
|
||||
actions={
|
||||
<span className="text-main-view-fg/80">
|
||||
{hardwareData.os.name}
|
||||
{hardwareData.os?.name}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
@ -233,7 +233,7 @@ function Hardware() {
|
||||
title="Version"
|
||||
actions={
|
||||
<span className="text-main-view-fg/80">
|
||||
{hardwareData.os.version}
|
||||
{hardwareData.os?.version}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
@ -245,7 +245,7 @@ function Hardware() {
|
||||
title="Model"
|
||||
actions={
|
||||
<span className="text-main-view-fg/80">
|
||||
{hardwareData.cpu.model}
|
||||
{hardwareData.cpu?.model}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
@ -253,7 +253,7 @@ function Hardware() {
|
||||
title="Architecture"
|
||||
actions={
|
||||
<span className="text-main-view-fg/80">
|
||||
{hardwareData.cpu.arch}
|
||||
{hardwareData.cpu?.arch}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
@ -261,16 +261,16 @@ function Hardware() {
|
||||
title="Cores"
|
||||
actions={
|
||||
<span className="text-main-view-fg/80">
|
||||
{hardwareData.cpu.cores}
|
||||
{hardwareData.cpu?.cores}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
{hardwareData.cpu.instructions.join(', ').length > 0 && (
|
||||
{hardwareData.cpu?.instructions.join(', ').length > 0 && (
|
||||
<CardItem
|
||||
title="Instructions"
|
||||
actions={
|
||||
<span className="text-main-view-fg/80">
|
||||
{hardwareData.cpu.instructions.join(', ')}
|
||||
{hardwareData.cpu?.instructions?.join(', ')}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
@ -280,11 +280,11 @@ function Hardware() {
|
||||
actions={
|
||||
<div className="flex items-center gap-2">
|
||||
<Progress
|
||||
value={hardwareData.cpu.usage}
|
||||
value={hardwareData.cpu?.usage}
|
||||
className="h-2 w-10"
|
||||
/>
|
||||
<span className="text-main-view-fg/80">
|
||||
{hardwareData.cpu.usage.toFixed(2)}%
|
||||
{hardwareData.cpu?.usage?.toFixed(2)}%
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
@ -305,7 +305,7 @@ function Hardware() {
|
||||
title="Available RAM"
|
||||
actions={
|
||||
<span className="text-main-view-fg/80">
|
||||
{formatMegaBytes(hardwareData.ram.available)}
|
||||
{formatMegaBytes(hardwareData.ram?.available)}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
@ -315,16 +315,16 @@ function Hardware() {
|
||||
<div className="flex items-center gap-2">
|
||||
<Progress
|
||||
value={
|
||||
((hardwareData.ram.total - hardwareData.ram.available) /
|
||||
hardwareData.ram.total) *
|
||||
((hardwareData.ram?.total - hardwareData.ram?.available) /
|
||||
hardwareData.ram?.total) *
|
||||
100
|
||||
}
|
||||
className="h-2 w-10"
|
||||
/>
|
||||
<span className="text-main-view-fg/80">
|
||||
{(
|
||||
((hardwareData.ram.total - hardwareData.ram.available) /
|
||||
hardwareData.ram.total) *
|
||||
((hardwareData.ram?.total - hardwareData.ram?.available) /
|
||||
hardwareData.ram?.total) *
|
||||
100
|
||||
).toFixed(2)}
|
||||
%
|
||||
|
||||
@ -140,7 +140,7 @@ function MCPServers() {
|
||||
|
||||
const intervalId = setInterval(() => {
|
||||
getConnectedServers().then(setConnectedServers)
|
||||
}, 5000)
|
||||
}, 3000)
|
||||
|
||||
return () => clearInterval(intervalId)
|
||||
}, [setConnectedServers])
|
||||
@ -223,9 +223,9 @@ function MCPServers() {
|
||||
<div className="text-sm text-main-view-fg/70">
|
||||
<div>Command: {config.command}</div>
|
||||
<div className="my-1 break-all">
|
||||
Args: {config.args.join(', ')}
|
||||
Args: {config?.args?.join(', ')}
|
||||
</div>
|
||||
{Object.keys(config.env).length > 0 && (
|
||||
{config.env && Object.keys(config.env).length > 0 && (
|
||||
<div className="break-all">
|
||||
Env:{' '}
|
||||
{Object.entries(config.env)
|
||||
|
||||
@ -10,6 +10,15 @@ export const updateMCPConfig = async (configs: string) => {
|
||||
await window.core?.api?.restartMcpServers()
|
||||
}
|
||||
|
||||
/**
|
||||
* @description This function gets the MCP configuration.
|
||||
* @returns {Promise<object>} The MCP configuration.
|
||||
*/
|
||||
export const getMCPConfig = async () => {
|
||||
const mcpConfig = JSON.parse((await window.core?.api?.getMcpConfigs()) ?? '{}')
|
||||
return mcpConfig
|
||||
}
|
||||
|
||||
/**
|
||||
* @description This function gets the MCP configuration.
|
||||
* @returns {Promise<string>} The MCP configuration.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user