@sweetoburrito/backstage-plugin-ai-assistant 0.7.1 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/chat.esm.js +4 -2
- package/dist/api/chat.esm.js.map +1 -1
- package/dist/api/mcp.esm.js +30 -19
- package/dist/api/mcp.esm.js.map +1 -1
- package/dist/components/AiAssistantChatModal/AiAssistantChatModal.esm.js +4 -23
- package/dist/components/AiAssistantChatModal/AiAssistantChatModal.esm.js.map +1 -1
- package/dist/components/AiAssistantPage/AiAssistantPage.esm.js +7 -25
- package/dist/components/AiAssistantPage/AiAssistantPage.esm.js.map +1 -1
- package/dist/components/Conversation/Conversation.esm.js +9 -3
- package/dist/components/Conversation/Conversation.esm.js.map +1 -1
- package/dist/components/{Conversation → SettingsModal}/SettingsModal.esm.js +21 -36
- package/dist/components/SettingsModal/SettingsModal.esm.js.map +1 -0
- package/dist/components/SettingsModal/TabPanel.esm.js +42 -0
- package/dist/components/SettingsModal/TabPanel.esm.js.map +1 -0
- package/dist/components/{Conversation/McpServersTab.esm.js → SettingsModal/tabs/McpServers/McpServers.esm.js} +7 -19
- package/dist/components/SettingsModal/tabs/McpServers/McpServers.esm.js.map +1 -0
- package/dist/components/SettingsModal/tabs/McpServers/index.esm.js +14 -0
- package/dist/components/SettingsModal/tabs/McpServers/index.esm.js.map +1 -0
- package/dist/components/SettingsModal/tabs/Tools/Tools.esm.js +163 -0
- package/dist/components/SettingsModal/tabs/Tools/Tools.esm.js.map +1 -0
- package/dist/components/SettingsModal/tabs/Tools/index.esm.js +14 -0
- package/dist/components/SettingsModal/tabs/Tools/index.esm.js.map +1 -0
- package/dist/components/SettingsModal/tabs/index.esm.js +7 -0
- package/dist/components/SettingsModal/tabs/index.esm.js.map +1 -0
- package/dist/hooks/use-chat-settings.esm.js +49 -2
- package/dist/hooks/use-chat-settings.esm.js.map +1 -1
- package/package.json +6 -3
- package/dist/components/Conversation/McpServersTab.esm.js.map +0 -1
- package/dist/components/Conversation/SettingsModal.esm.js.map +0 -1
package/dist/api/chat.esm.js
CHANGED
|
@@ -24,7 +24,8 @@ const createChatService = ({
|
|
|
24
24
|
conversationId,
|
|
25
25
|
modelId,
|
|
26
26
|
messages,
|
|
27
|
-
stream
|
|
27
|
+
stream,
|
|
28
|
+
tools
|
|
28
29
|
}) => {
|
|
29
30
|
const assistantBaseUrl = await discoveryApi.getBaseUrl("ai-assistant");
|
|
30
31
|
const response = await fetchApi.fetch(`${assistantBaseUrl}/chat/message`, {
|
|
@@ -33,7 +34,8 @@ const createChatService = ({
|
|
|
33
34
|
conversationId,
|
|
34
35
|
modelId,
|
|
35
36
|
messages,
|
|
36
|
-
stream
|
|
37
|
+
stream,
|
|
38
|
+
tools
|
|
37
39
|
}),
|
|
38
40
|
headers: {
|
|
39
41
|
"Content-Type": "application/json"
|
package/dist/api/chat.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.esm.js","sources":["../../src/api/chat.ts"],"sourcesContent":["import { createApiRef } from '@backstage/core-plugin-api';\nimport { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport {\n Conversation,\n Message,\n} from '@sweetoburrito/backstage-plugin-ai-assistant-common';\n\ntype SendMessageOptions = {\n conversationId?: string;\n modelId: string;\n messages: Message[];\n stream?: boolean;\n};\n\nexport type ChatApi = {\n getModels: () => Promise<string[]>;\n getConversation: (id?: string) => Promise<Message[]>;\n sendMessage: (options: SendMessageOptions) => Promise<{\n messages: Message[];\n conversationId: string;\n }>;\n getConversations: () => Promise<Conversation[]>;\n scoreMessage: (messageId: string, score: number) => Promise<void>;\n};\n\ntype ChatApiOptions = {\n fetchApi: FetchApi;\n discoveryApi: DiscoveryApi;\n};\n\nexport const chatApiRef = createApiRef<ChatApi>({\n id: 'plugin.ai-assistant.chat',\n});\n\nexport const createChatService = ({\n fetchApi,\n discoveryApi,\n}: ChatApiOptions): ChatApi => {\n const getModels: ChatApi['getModels'] = async (): Promise<string[]> => {\n const assistantBaseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n const response = await fetchApi.fetch(`${assistantBaseUrl}/models`);\n const data = await response.json();\n return data.models;\n };\n\n const getConversation: ChatApi['getConversation'] = async id => {\n if (!id) return [];\n const assistantBaseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n const response = await fetchApi.fetch(`${assistantBaseUrl}/chat/${id}`);\n\n const data = await response.json();\n\n return data.conversation as Message[];\n };\n\n const sendMessage: ChatApi['sendMessage'] = async ({\n conversationId,\n modelId,\n messages,\n stream,\n }) => {\n const assistantBaseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n const response = await fetchApi.fetch(`${assistantBaseUrl}/chat/message`, {\n method: 'POST',\n body: JSON.stringify({\n conversationId,\n modelId,\n messages,\n stream,\n }),\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n const data = await response.json();\n\n return {\n messages: data.messages as Message[],\n conversationId: data.conversationId as string,\n };\n };\n\n const getConversations: ChatApi['getConversations'] = async () => {\n const assistantBaseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n const response = await fetchApi.fetch(\n `${assistantBaseUrl}/chat/conversations`,\n );\n\n const data = await response.json();\n\n return data.conversations as Conversation[];\n };\n\n const scoreMessage: ChatApi['scoreMessage'] = async (messageId, score) => {\n const assistantBaseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n await fetchApi.fetch(\n `${assistantBaseUrl}/chat/message/${messageId}/score`,\n {\n method: 'POST',\n body: JSON.stringify({ score }),\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n );\n };\n\n return {\n getModels,\n getConversation,\n sendMessage,\n getConversations,\n scoreMessage,\n };\n};\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"chat.esm.js","sources":["../../src/api/chat.ts"],"sourcesContent":["import { createApiRef } from '@backstage/core-plugin-api';\nimport { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport {\n Conversation,\n EnabledTool,\n Message,\n} from '@sweetoburrito/backstage-plugin-ai-assistant-common';\n\ntype SendMessageOptions = {\n conversationId?: string;\n modelId: string;\n messages: Message[];\n stream?: boolean;\n tools?: EnabledTool[];\n};\n\nexport type ChatApi = {\n getModels: () => Promise<string[]>;\n getConversation: (id?: string) => Promise<Message[]>;\n sendMessage: (options: SendMessageOptions) => Promise<{\n messages: Message[];\n conversationId: string;\n }>;\n getConversations: () => Promise<Conversation[]>;\n scoreMessage: (messageId: string, score: number) => Promise<void>;\n};\n\ntype ChatApiOptions = {\n fetchApi: FetchApi;\n discoveryApi: DiscoveryApi;\n};\n\nexport const chatApiRef = createApiRef<ChatApi>({\n id: 'plugin.ai-assistant.chat',\n});\n\nexport const createChatService = ({\n fetchApi,\n discoveryApi,\n}: ChatApiOptions): ChatApi => {\n const getModels: ChatApi['getModels'] = async (): Promise<string[]> => {\n const assistantBaseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n const response = await fetchApi.fetch(`${assistantBaseUrl}/models`);\n const data = await response.json();\n return data.models;\n };\n\n const getConversation: ChatApi['getConversation'] = async id => {\n if (!id) return [];\n const assistantBaseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n const response = await fetchApi.fetch(`${assistantBaseUrl}/chat/${id}`);\n\n const data = await response.json();\n\n return data.conversation as Message[];\n };\n\n const sendMessage: ChatApi['sendMessage'] = async ({\n conversationId,\n modelId,\n messages,\n stream,\n tools,\n }) => {\n const assistantBaseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n const response = await fetchApi.fetch(`${assistantBaseUrl}/chat/message`, {\n method: 'POST',\n body: JSON.stringify({\n conversationId,\n modelId,\n messages,\n stream,\n tools,\n }),\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n const data = await response.json();\n\n return {\n messages: data.messages as Message[],\n conversationId: data.conversationId as string,\n };\n };\n\n const getConversations: ChatApi['getConversations'] = async () => {\n const assistantBaseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n const response = await fetchApi.fetch(\n `${assistantBaseUrl}/chat/conversations`,\n );\n\n const data = await response.json();\n\n return data.conversations as Conversation[];\n };\n\n const scoreMessage: ChatApi['scoreMessage'] = async (messageId, score) => {\n const assistantBaseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n await fetchApi.fetch(\n `${assistantBaseUrl}/chat/message/${messageId}/score`,\n {\n method: 'POST',\n body: JSON.stringify({ score }),\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n );\n };\n\n return {\n getModels,\n getConversation,\n sendMessage,\n getConversations,\n scoreMessage,\n };\n};\n"],"names":[],"mappings":"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"}
|
package/dist/api/mcp.esm.js
CHANGED
|
@@ -6,19 +6,24 @@ const mcpApiRef = createApiRef({
|
|
|
6
6
|
const createMcpService = ({ fetchApi, discoveryApi }) => {
|
|
7
7
|
const getUserDefinedMcpConfigs = async () => {
|
|
8
8
|
const assistantBaseUrl = await discoveryApi.getBaseUrl("ai-assistant");
|
|
9
|
-
const response = await fetchApi.fetch(
|
|
9
|
+
const response = await fetchApi.fetch(
|
|
10
|
+
`${assistantBaseUrl}/settings/mcp/config`
|
|
11
|
+
);
|
|
10
12
|
const data = await response.json();
|
|
11
13
|
return data;
|
|
12
14
|
};
|
|
13
15
|
const createMcpConfig = async (config) => {
|
|
14
16
|
const assistantBaseUrl = await discoveryApi.getBaseUrl("ai-assistant");
|
|
15
|
-
const res = await fetchApi.fetch(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
const res = await fetchApi.fetch(
|
|
18
|
+
`${assistantBaseUrl}/settings/mcp/config`,
|
|
19
|
+
{
|
|
20
|
+
method: "POST",
|
|
21
|
+
body: JSON.stringify(config),
|
|
22
|
+
headers: {
|
|
23
|
+
"Content-Type": "application/json"
|
|
24
|
+
}
|
|
20
25
|
}
|
|
21
|
-
|
|
26
|
+
);
|
|
22
27
|
if (!res.ok) {
|
|
23
28
|
const errorData = await res.json();
|
|
24
29
|
const { error } = errorData;
|
|
@@ -29,13 +34,16 @@ const createMcpService = ({ fetchApi, discoveryApi }) => {
|
|
|
29
34
|
};
|
|
30
35
|
const updateMcpConfig = async (config) => {
|
|
31
36
|
const assistantBaseUrl = await discoveryApi.getBaseUrl("ai-assistant");
|
|
32
|
-
const res = await fetchApi.fetch(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
const res = await fetchApi.fetch(
|
|
38
|
+
`${assistantBaseUrl}/settings/mcp/config`,
|
|
39
|
+
{
|
|
40
|
+
method: "PATCH",
|
|
41
|
+
body: JSON.stringify(config),
|
|
42
|
+
headers: {
|
|
43
|
+
"Content-Type": "application/json"
|
|
44
|
+
}
|
|
37
45
|
}
|
|
38
|
-
|
|
46
|
+
);
|
|
39
47
|
if (!res.ok) {
|
|
40
48
|
const errorData = await res.json();
|
|
41
49
|
const { error } = errorData;
|
|
@@ -46,13 +54,16 @@ const createMcpService = ({ fetchApi, discoveryApi }) => {
|
|
|
46
54
|
};
|
|
47
55
|
const deleteMcpConfig = async (configName) => {
|
|
48
56
|
const assistantBaseUrl = await discoveryApi.getBaseUrl("ai-assistant");
|
|
49
|
-
const res = await fetchApi.fetch(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
const res = await fetchApi.fetch(
|
|
58
|
+
`${assistantBaseUrl}/settings/mcp/config`,
|
|
59
|
+
{
|
|
60
|
+
method: "DELETE",
|
|
61
|
+
body: JSON.stringify({ name: configName }),
|
|
62
|
+
headers: {
|
|
63
|
+
"Content-Type": "application/json"
|
|
64
|
+
}
|
|
54
65
|
}
|
|
55
|
-
|
|
66
|
+
);
|
|
56
67
|
if (!res.ok) {
|
|
57
68
|
const errorData = await res.json();
|
|
58
69
|
const { error } = errorData;
|
package/dist/api/mcp.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.esm.js","sources":["../../src/api/mcp.ts"],"sourcesContent":["import { createApiRef } from '@backstage/core-plugin-api';\nimport { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport { McpServerConfig } from '@sweetoburrito/backstage-plugin-ai-assistant-common';\n\nexport type McpApi = Awaited<ReturnType<typeof createMcpService>>;\n\ntype McpApiOptions = {\n fetchApi: FetchApi;\n discoveryApi: DiscoveryApi;\n};\n\nexport const mcpApiRef = createApiRef<McpApi>({\n id: 'plugin.ai-assistant.mcp',\n});\n\nexport const createMcpService = ({ fetchApi, discoveryApi }: McpApiOptions) => {\n const getUserDefinedMcpConfigs = async (): Promise<{ names: string[] }> => {\n const assistantBaseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n const response = await fetchApi.fetch(`${assistantBaseUrl}/mcp/config
|
|
1
|
+
{"version":3,"file":"mcp.esm.js","sources":["../../src/api/mcp.ts"],"sourcesContent":["import { createApiRef } from '@backstage/core-plugin-api';\nimport { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport { McpServerConfig } from '@sweetoburrito/backstage-plugin-ai-assistant-common';\n\nexport type McpApi = Awaited<ReturnType<typeof createMcpService>>;\n\ntype McpApiOptions = {\n fetchApi: FetchApi;\n discoveryApi: DiscoveryApi;\n};\n\nexport const mcpApiRef = createApiRef<McpApi>({\n id: 'plugin.ai-assistant.mcp',\n});\n\nexport const createMcpService = ({ fetchApi, discoveryApi }: McpApiOptions) => {\n const getUserDefinedMcpConfigs = async (): Promise<{ names: string[] }> => {\n const assistantBaseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n const response = await fetchApi.fetch(\n `${assistantBaseUrl}/settings/mcp/config`,\n );\n const data = await response.json();\n return data;\n };\n\n const createMcpConfig = async (config: McpServerConfig): Promise<void> => {\n const assistantBaseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n const res = await fetchApi.fetch(\n `${assistantBaseUrl}/settings/mcp/config`,\n {\n method: 'POST',\n body: JSON.stringify(config),\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n );\n\n if (!res.ok) {\n const errorData = await res.json();\n\n const { error } = errorData;\n\n throw new Error(\n `Failed to create MCP config: ${error || res.statusText}`,\n );\n }\n };\n\n const updateMcpConfig = async (config: McpServerConfig): Promise<void> => {\n const assistantBaseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n const res = await fetchApi.fetch(\n `${assistantBaseUrl}/settings/mcp/config`,\n {\n method: 'PATCH',\n body: JSON.stringify(config),\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n );\n\n if (!res.ok) {\n const errorData = await res.json();\n\n const { error } = errorData;\n\n throw new Error(\n `Failed to update MCP config: ${error || res.statusText}`,\n );\n }\n };\n\n const deleteMcpConfig = async (configName: string): Promise<void> => {\n const assistantBaseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n const res = await fetchApi.fetch(\n `${assistantBaseUrl}/settings/mcp/config`,\n {\n method: 'DELETE',\n body: JSON.stringify({ name: configName }),\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n );\n\n if (!res.ok) {\n const errorData = await res.json();\n\n const { error } = errorData;\n\n throw new Error(\n `Failed to delete MCP config: ${error || res.statusText}`,\n );\n }\n };\n\n return {\n getUserDefinedMcpConfigs,\n createMcpConfig,\n updateMcpConfig,\n deleteMcpConfig,\n };\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,34 +1,15 @@
|
|
|
1
1
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import { useState, useEffect, useMemo } from 'react';
|
|
3
3
|
import { Conversation } from '../Conversation/Conversation.esm.js';
|
|
4
|
-
import '@mui/material/Dialog';
|
|
5
|
-
import '@mui/material/DialogTitle';
|
|
6
|
-
import '@mui/material/DialogContent';
|
|
7
|
-
import '@mui/material/DialogActions';
|
|
8
|
-
import Button from '@mui/material/Button';
|
|
9
|
-
import '@mui/material/Tab';
|
|
10
|
-
import '@mui/material/Tabs';
|
|
11
|
-
import Box from '@mui/material/Box';
|
|
12
|
-
import Typography from '@mui/material/Typography';
|
|
13
4
|
import Stack from '@mui/material/Stack';
|
|
14
5
|
import IconButton from '@mui/material/IconButton';
|
|
15
|
-
import '@mui/icons-material/Close';
|
|
16
|
-
import '@mui/icons-material/Settings';
|
|
17
|
-
import '@backstage/core-plugin-api';
|
|
18
|
-
import 'react-use';
|
|
19
|
-
import '@mui/material/TextField';
|
|
20
|
-
import '@mui/material/Paper';
|
|
21
|
-
import '@mui/material/Divider';
|
|
22
|
-
import '@mui/material/Card';
|
|
23
|
-
import '@mui/material/CardContent';
|
|
24
|
-
import '@mui/material/CardActions';
|
|
25
|
-
import '@mui/material/Alert';
|
|
26
|
-
import '@mui/icons-material/Delete';
|
|
27
|
-
import AddIcon from '@mui/icons-material/Add';
|
|
28
6
|
import Tooltip from '@mui/material/Tooltip';
|
|
29
|
-
import '
|
|
7
|
+
import Box from '@mui/material/Box';
|
|
8
|
+
import Typography from '@mui/material/Typography';
|
|
30
9
|
import Modal from '@mui/material/Modal';
|
|
10
|
+
import Button from '@mui/material/Button';
|
|
31
11
|
import Chip from '@mui/material/Chip';
|
|
12
|
+
import AddIcon from '@mui/icons-material/Add';
|
|
32
13
|
import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome';
|
|
33
14
|
import { useChatSettings } from '../../hooks/use-chat-settings.esm.js';
|
|
34
15
|
import { useLocation } from 'react-router-dom';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiAssistantChatModal.esm.js","sources":["../../../src/components/AiAssistantChatModal/AiAssistantChatModal.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { Conversation } from '../Conversation';\nimport Stack from '@mui/material/Stack';\nimport IconButton from '@mui/material/IconButton';\nimport Tooltip from '@mui/material/Tooltip';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Modal from '@mui/material/Modal';\nimport Button from '@mui/material/Button';\nimport Chip from '@mui/material/Chip';\nimport AddIcon from '@mui/icons-material/Add';\nimport AutoAwesomeIcon from '@mui/icons-material/AutoAwesome';\nimport { useChatSettings } from '../../hooks/use-chat-settings';\nimport { useLocation } from 'react-router-dom';\nimport { usePageSummary } from '../../hooks/use-page-summary';\nimport { Message } from '@sweetoburrito/backstage-plugin-ai-assistant-common';\n\nexport interface AiAssistantChatModalProps {\n open?: boolean;\n onClose?: () => void;\n conversationId?: string;\n setConversationId?: (id: string | undefined) => void;\n}\n\nexport const AiAssistantChatModal = ({\n open: controlledOpen,\n onClose: controlledOnClose,\n conversationId: controlledConversationId,\n setConversationId: controlledSetConversationId,\n}: AiAssistantChatModalProps) => {\n const [modalOpen, setModalOpen] = useState(false);\n const [modalConversationId, setModalConversationId] = useState<string>();\n\n const { modalVisible, setModalVisible, setSummaryEnabled, summaryEnabled } =\n useChatSettings();\n\n const location = useLocation();\n\n const { summary, loading, error } = usePageSummary();\n\n // Update visibility based on route changes\n useEffect(() => {\n setModalVisible(true);\n }, [location, setModalVisible, setSummaryEnabled]);\n\n useEffect(() => {\n if (!modalOpen) return;\n setSummaryEnabled(true);\n }, [modalOpen, setSummaryEnabled]);\n\n const additionalSystemMessages: Message[] = useMemo(() => {\n if (!summaryEnabled || !summary) return [];\n\n const path = location.pathname;\n const title = document.title;\n const content = `The user is currently on the page titled \"${title}\" located at \"${path}\". The page has the following context: ${summary}. Use this context to inform your responses where relevant.`;\n\n return [\n {\n role: 'system',\n content,\n metadata: {},\n score: 0,\n },\n ];\n }, [summaryEnabled, summary, location.pathname]);\n\n // If the context says the modal is not visible, don't render anything\n if (!modalVisible) {\n return <></>;\n }\n\n const getChipColor = () => {\n if (loading) return 'primary';\n if (error) return 'error';\n if (summary) return 'success';\n return undefined;\n };\n\n const getChipLabel = () => {\n if (loading) return 'Loading page context...';\n if (error) return 'Error loading page context';\n if (summary) return 'Page Context Loaded';\n return 'No page context available';\n };\n\n // Use controlled props if provided, otherwise use internal state\n const isOpen = controlledOpen !== undefined ? controlledOpen : modalOpen;\n const conversationId =\n controlledConversationId !== undefined\n ? controlledConversationId\n : modalConversationId;\n const setConversationId =\n controlledSetConversationId || setModalConversationId;\n\n const handleModalOpen = () => {\n if (controlledOpen === undefined) {\n setModalOpen(true);\n }\n };\n\n const handleModalClose = () => {\n if (controlledOnClose) {\n controlledOnClose();\n } else {\n setModalOpen(false);\n }\n };\n\n const openNewModalChat = () => {\n setConversationId(undefined);\n };\n\n return (\n <>\n <Box\n sx={{\n position: 'absolute',\n bottom: theme => theme.spacing(2),\n right: theme => theme.spacing(2),\n borderRadius: '50%',\n boxShadow: theme => theme.shadows[4],\n bgcolor: theme => theme.palette.background.paper,\n border: theme => `1px solid ${theme.palette.primary.main}`,\n width: 50,\n height: 50,\n padding: theme => theme.spacing(1),\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n zIndex: theme => theme.zIndex.modal - 1,\n ':hover': {\n cursor: 'pointer',\n boxShadow: theme => theme.shadows[6],\n bgcolor: theme => theme.palette.background.default,\n },\n }}\n onClick={handleModalOpen}\n >\n <AutoAwesomeIcon />\n </Box>\n\n <Modal open={isOpen} onClose={handleModalClose}>\n <Box\n sx={{\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n width: '60vw',\n height: '60vh',\n bgcolor: 'background.paper',\n border: '1px solid #000',\n padding: 2,\n display: 'flex',\n flexDirection: 'column',\n }}\n >\n <Stack spacing={2} flex={1} height=\"100%\">\n <Stack\n direction=\"row\"\n spacing={2}\n justifyContent=\"space-between\"\n alignItems=\"center\"\n >\n <Typography variant=\"h6\" component=\"h2\">\n AI Assistant\n </Typography>\n {summaryEnabled && (\n <Tooltip\n title={summary ?? 'No summary available'}\n placement=\"bottom\"\n >\n <Chip\n label={getChipLabel()}\n color={getChipColor()}\n variant=\"outlined\"\n />\n </Tooltip>\n )}\n <Stack direction=\"row\" spacing={1}>\n <Tooltip title=\"New Chat\" placement=\"bottom\">\n <IconButton onClick={openNewModalChat}>\n <AddIcon />\n </IconButton>\n </Tooltip>\n <Button variant=\"outlined\" onClick={handleModalClose}>\n Close\n </Button>\n </Stack>\n </Stack>\n <Conversation\n conversationId={conversationId}\n setConversationId={setConversationId}\n additionalSystemMessages={additionalSystemMessages}\n />\n </Stack>\n </Box>\n </Modal>\n </>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwBO,MAAM,uBAAuB,CAAC;AAAA,EACnC,IAAA,EAAM,cAAA;AAAA,EACN,OAAA,EAAS,iBAAA;AAAA,EACT,cAAA,EAAgB,wBAAA;AAAA,EAChB,iBAAA,EAAmB;AACrB,CAAA,KAAiC;AAC/B,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAS,KAAK,CAAA;AAChD,EAAA,MAAM,CAAC,mBAAA,EAAqB,sBAAsB,CAAA,GAAI,QAAA,EAAiB;AAEvE,EAAA,MAAM,EAAE,YAAA,EAAc,eAAA,EAAiB,iBAAA,EAAmB,cAAA,KACxD,eAAA,EAAgB;AAElB,EAAA,MAAM,WAAW,WAAA,EAAY;AAE7B,EAAA,MAAM,EAAE,OAAA,EAAS,OAAA,EAAS,KAAA,KAAU,cAAA,EAAe;AAGnD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,eAAA,CAAgB,IAAI,CAAA;AAAA,EACtB,CAAA,EAAG,CAAC,QAAA,EAAU,eAAA,EAAiB,iBAAiB,CAAC,CAAA;AAEjD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,SAAA,EAAW;AAChB,IAAA,iBAAA,CAAkB,IAAI,CAAA;AAAA,EACxB,CAAA,EAAG,CAAC,SAAA,EAAW,iBAAiB,CAAC,CAAA;AAEjC,EAAA,MAAM,wBAAA,GAAsC,QAAQ,MAAM;AACxD,IAAA,IAAI,CAAC,cAAA,IAAkB,CAAC,OAAA,SAAgB,EAAC;AAEzC,IAAA,MAAM,OAAO,QAAA,CAAS,QAAA;AACtB,IAAA,MAAM,QAAQ,QAAA,CAAS,KAAA;AACvB,IAAA,MAAM,UAAU,CAAA,0CAAA,EAA6C,KAAK,CAAA,cAAA,EAAiB,IAAI,0CAA0C,OAAO,CAAA,2DAAA,CAAA;AAExI,IAAA,OAAO;AAAA,MACL;AAAA,QACE,IAAA,EAAM,QAAA;AAAA,QACN,OAAA;AAAA,QACA,UAAU,EAAC;AAAA,QACX,KAAA,EAAO;AAAA;AACT,KACF;AAAA,EACF,GAAG,CAAC,cAAA,EAAgB,OAAA,EAAS,QAAA,CAAS,QAAQ,CAAC,CAAA;AAG/C,EAAA,IAAI,CAAC,YAAA,EAAc;AACjB,IAAA,uBAAO,GAAA,CAAA,QAAA,EAAA,EAAE,CAAA;AAAA,EACX;AAEA,EAAA,MAAM,eAAe,MAAM;AACzB,IAAA,IAAI,SAAS,OAAO,SAAA;AACpB,IAAA,IAAI,OAAO,OAAO,OAAA;AAClB,IAAA,IAAI,SAAS,OAAO,SAAA;AACpB,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,eAAe,MAAM;AACzB,IAAA,IAAI,SAAS,OAAO,yBAAA;AACpB,IAAA,IAAI,OAAO,OAAO,4BAAA;AAClB,IAAA,IAAI,SAAS,OAAO,qBAAA;AACpB,IAAA,OAAO,2BAAA;AAAA,EACT,CAAA;AAGA,EAAA,MAAM,MAAA,GAAS,cAAA,KAAmB,MAAA,GAAY,cAAA,GAAiB,SAAA;AAC/D,EAAA,MAAM,cAAA,GACJ,wBAAA,KAA6B,MAAA,GACzB,wBAAA,GACA,mBAAA;AACN,EAAA,MAAM,oBACJ,2BAAA,IAA+B,sBAAA;AAEjC,EAAA,MAAM,kBAAkB,MAAM;AAC5B,IAAA,IAAI,mBAAmB,MAAA,EAAW;AAChC,MAAA,YAAA,CAAa,IAAI,CAAA;AAAA,IACnB;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,mBAAmB,MAAM;AAC7B,IAAA,IAAI,iBAAA,EAAmB;AACrB,MAAA,iBAAA,EAAkB;AAAA,IACpB,CAAA,MAAO;AACL,MAAA,YAAA,CAAa,KAAK,CAAA;AAAA,IACpB;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,mBAAmB,MAAM;AAC7B,IAAA,iBAAA,CAAkB,MAAS,CAAA;AAAA,EAC7B,CAAA;AAEA,EAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,EAAA,EAAI;AAAA,UACF,QAAA,EAAU,UAAA;AAAA,UACV,MAAA,EAAQ,CAAA,KAAA,KAAS,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,UAChC,KAAA,EAAO,CAAA,KAAA,KAAS,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,UAC/B,YAAA,EAAc,KAAA;AAAA,UACd,SAAA,EAAW,CAAA,KAAA,KAAS,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,UACnC,OAAA,EAAS,CAAA,KAAA,KAAS,KAAA,CAAM,OAAA,CAAQ,UAAA,CAAW,KAAA;AAAA,UAC3C,QAAQ,CAAA,KAAA,KAAS,CAAA,UAAA,EAAa,KAAA,CAAM,OAAA,CAAQ,QAAQ,IAAI,CAAA,CAAA;AAAA,UACxD,KAAA,EAAO,EAAA;AAAA,UACP,MAAA,EAAQ,EAAA;AAAA,UACR,OAAA,EAAS,CAAA,KAAA,KAAS,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,UACjC,OAAA,EAAS,MAAA;AAAA,UACT,cAAA,EAAgB,QAAA;AAAA,UAChB,UAAA,EAAY,QAAA;AAAA,UACZ,MAAA,EAAQ,CAAA,KAAA,KAAS,KAAA,CAAM,MAAA,CAAO,KAAA,GAAQ,CAAA;AAAA,UACtC,QAAA,EAAU;AAAA,YACR,MAAA,EAAQ,SAAA;AAAA,YACR,SAAA,EAAW,CAAA,KAAA,KAAS,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,YACnC,OAAA,EAAS,CAAA,KAAA,KAAS,KAAA,CAAM,OAAA,CAAQ,UAAA,CAAW;AAAA;AAC7C,SACF;AAAA,QACA,OAAA,EAAS,eAAA;AAAA,QAET,8BAAC,eAAA,EAAA,EAAgB;AAAA;AAAA,KACnB;AAAA,oBAEA,GAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAM,MAAA,EAAQ,SAAS,gBAAA,EAC5B,QAAA,kBAAA,GAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,EAAA,EAAI;AAAA,UACF,QAAA,EAAU,UAAA;AAAA,UACV,GAAA,EAAK,KAAA;AAAA,UACL,IAAA,EAAM,KAAA;AAAA,UACN,SAAA,EAAW,uBAAA;AAAA,UACX,KAAA,EAAO,MAAA;AAAA,UACP,MAAA,EAAQ,MAAA;AAAA,UACR,OAAA,EAAS,kBAAA;AAAA,UACT,MAAA,EAAQ,gBAAA;AAAA,UACR,OAAA,EAAS,CAAA;AAAA,UACT,OAAA,EAAS,MAAA;AAAA,UACT,aAAA,EAAe;AAAA,SACjB;AAAA,QAEA,+BAAC,KAAA,EAAA,EAAM,OAAA,EAAS,GAAG,IAAA,EAAM,CAAA,EAAG,QAAO,MAAA,EACjC,QAAA,EAAA;AAAA,0BAAA,IAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAU,KAAA;AAAA,cACV,OAAA,EAAS,CAAA;AAAA,cACT,cAAA,EAAe,eAAA;AAAA,cACf,UAAA,EAAW,QAAA;AAAA,cAEX,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,UAAA,EAAA,EAAW,OAAA,EAAQ,IAAA,EAAK,SAAA,EAAU,MAAK,QAAA,EAAA,cAAA,EAExC,CAAA;AAAA,gBACC,cAAA,oBACC,GAAA;AAAA,kBAAC,OAAA;AAAA,kBAAA;AAAA,oBACC,OAAO,OAAA,IAAW,sBAAA;AAAA,oBAClB,SAAA,EAAU,QAAA;AAAA,oBAEV,QAAA,kBAAA,GAAA;AAAA,sBAAC,IAAA;AAAA,sBAAA;AAAA,wBACC,OAAO,YAAA,EAAa;AAAA,wBACpB,OAAO,YAAA,EAAa;AAAA,wBACpB,OAAA,EAAQ;AAAA;AAAA;AACV;AAAA,iBACF;AAAA,gCAEF,IAAA,CAAC,KAAA,EAAA,EAAM,SAAA,EAAU,KAAA,EAAM,SAAS,CAAA,EAC9B,QAAA,EAAA;AAAA,kCAAA,GAAA,CAAC,OAAA,EAAA,EAAQ,KAAA,EAAM,UAAA,EAAW,SAAA,EAAU,QAAA,EAClC,QAAA,kBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,OAAA,EAAS,gBAAA,EACnB,QAAA,kBAAA,GAAA,CAAC,OAAA,EAAA,EAAQ,CAAA,EACX,CAAA,EACF,CAAA;AAAA,sCACC,MAAA,EAAA,EAAO,OAAA,EAAQ,UAAA,EAAW,OAAA,EAAS,kBAAkB,QAAA,EAAA,OAAA,EAEtD;AAAA,iBAAA,EACF;AAAA;AAAA;AAAA,WACF;AAAA,0BACA,GAAA;AAAA,YAAC,YAAA;AAAA,YAAA;AAAA,cACC,cAAA;AAAA,cACA,iBAAA;AAAA,cACA;AAAA;AAAA;AACF,SAAA,EACF;AAAA;AAAA,KACF,EACF;AAAA,GAAA,EACF,CAAA;AAEJ;;;;"}
|
|
1
|
+
{"version":3,"file":"AiAssistantChatModal.esm.js","sources":["../../../src/components/AiAssistantChatModal/AiAssistantChatModal.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { Conversation } from '../Conversation';\nimport Stack from '@mui/material/Stack';\nimport IconButton from '@mui/material/IconButton';\nimport Tooltip from '@mui/material/Tooltip';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Modal from '@mui/material/Modal';\nimport Button from '@mui/material/Button';\nimport Chip from '@mui/material/Chip';\nimport AddIcon from '@mui/icons-material/Add';\nimport AutoAwesomeIcon from '@mui/icons-material/AutoAwesome';\nimport { useChatSettings } from '../../hooks/use-chat-settings';\nimport { useLocation } from 'react-router-dom';\nimport { usePageSummary } from '../../hooks/use-page-summary';\nimport { Message } from '@sweetoburrito/backstage-plugin-ai-assistant-common';\n\nexport interface AiAssistantChatModalProps {\n open?: boolean;\n onClose?: () => void;\n conversationId?: string;\n setConversationId?: (id: string | undefined) => void;\n}\n\nexport const AiAssistantChatModal = ({\n open: controlledOpen,\n onClose: controlledOnClose,\n conversationId: controlledConversationId,\n setConversationId: controlledSetConversationId,\n}: AiAssistantChatModalProps) => {\n const [modalOpen, setModalOpen] = useState(false);\n const [modalConversationId, setModalConversationId] = useState<string>();\n\n const { modalVisible, setModalVisible, setSummaryEnabled, summaryEnabled } =\n useChatSettings();\n\n const location = useLocation();\n\n const { summary, loading, error } = usePageSummary();\n\n // Update visibility based on route changes\n useEffect(() => {\n setModalVisible(true);\n }, [location, setModalVisible, setSummaryEnabled]);\n\n useEffect(() => {\n if (!modalOpen) return;\n setSummaryEnabled(true);\n }, [modalOpen, setSummaryEnabled]);\n\n const additionalSystemMessages: Message[] = useMemo(() => {\n if (!summaryEnabled || !summary) return [];\n\n const path = location.pathname;\n const title = document.title;\n const content = `The user is currently on the page titled \"${title}\" located at \"${path}\". The page has the following context: ${summary}. Use this context to inform your responses where relevant.`;\n\n return [\n {\n role: 'system',\n content,\n metadata: {},\n score: 0,\n },\n ];\n }, [summaryEnabled, summary, location.pathname]);\n\n // If the context says the modal is not visible, don't render anything\n if (!modalVisible) {\n return <></>;\n }\n\n const getChipColor = () => {\n if (loading) return 'primary';\n if (error) return 'error';\n if (summary) return 'success';\n return undefined;\n };\n\n const getChipLabel = () => {\n if (loading) return 'Loading page context...';\n if (error) return 'Error loading page context';\n if (summary) return 'Page Context Loaded';\n return 'No page context available';\n };\n\n // Use controlled props if provided, otherwise use internal state\n const isOpen = controlledOpen !== undefined ? controlledOpen : modalOpen;\n const conversationId =\n controlledConversationId !== undefined\n ? controlledConversationId\n : modalConversationId;\n const setConversationId =\n controlledSetConversationId || setModalConversationId;\n\n const handleModalOpen = () => {\n if (controlledOpen === undefined) {\n setModalOpen(true);\n }\n };\n\n const handleModalClose = () => {\n if (controlledOnClose) {\n controlledOnClose();\n } else {\n setModalOpen(false);\n }\n };\n\n const openNewModalChat = () => {\n setConversationId(undefined);\n };\n\n return (\n <>\n <Box\n sx={{\n position: 'absolute',\n bottom: theme => theme.spacing(2),\n right: theme => theme.spacing(2),\n borderRadius: '50%',\n boxShadow: theme => theme.shadows[4],\n bgcolor: theme => theme.palette.background.paper,\n border: theme => `1px solid ${theme.palette.primary.main}`,\n width: 50,\n height: 50,\n padding: theme => theme.spacing(1),\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n zIndex: theme => theme.zIndex.modal - 1,\n ':hover': {\n cursor: 'pointer',\n boxShadow: theme => theme.shadows[6],\n bgcolor: theme => theme.palette.background.default,\n },\n }}\n onClick={handleModalOpen}\n >\n <AutoAwesomeIcon />\n </Box>\n\n <Modal open={isOpen} onClose={handleModalClose}>\n <Box\n sx={{\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n width: '60vw',\n height: '60vh',\n bgcolor: 'background.paper',\n border: '1px solid #000',\n padding: 2,\n display: 'flex',\n flexDirection: 'column',\n }}\n >\n <Stack spacing={2} flex={1} height=\"100%\">\n <Stack\n direction=\"row\"\n spacing={2}\n justifyContent=\"space-between\"\n alignItems=\"center\"\n >\n <Typography variant=\"h6\" component=\"h2\">\n AI Assistant\n </Typography>\n {summaryEnabled && (\n <Tooltip\n title={summary ?? 'No summary available'}\n placement=\"bottom\"\n >\n <Chip\n label={getChipLabel()}\n color={getChipColor()}\n variant=\"outlined\"\n />\n </Tooltip>\n )}\n <Stack direction=\"row\" spacing={1}>\n <Tooltip title=\"New Chat\" placement=\"bottom\">\n <IconButton onClick={openNewModalChat}>\n <AddIcon />\n </IconButton>\n </Tooltip>\n <Button variant=\"outlined\" onClick={handleModalClose}>\n Close\n </Button>\n </Stack>\n </Stack>\n <Conversation\n conversationId={conversationId}\n setConversationId={setConversationId}\n additionalSystemMessages={additionalSystemMessages}\n />\n </Stack>\n </Box>\n </Modal>\n </>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,39 +1,21 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
3
|
import { Conversation } from '../Conversation/Conversation.esm.js';
|
|
4
|
-
import '@mui/material/Dialog';
|
|
5
|
-
import '@mui/material/DialogTitle';
|
|
6
|
-
import '@mui/material/DialogContent';
|
|
7
|
-
import '@mui/material/DialogActions';
|
|
8
|
-
import '@mui/material/Button';
|
|
9
|
-
import '@mui/material/Tab';
|
|
10
|
-
import '@mui/material/Tabs';
|
|
11
|
-
import Box from '@mui/material/Box';
|
|
12
|
-
import Typography from '@mui/material/Typography';
|
|
13
|
-
import Stack from '@mui/material/Stack';
|
|
14
|
-
import IconButton from '@mui/material/IconButton';
|
|
15
|
-
import '@mui/icons-material/Close';
|
|
16
|
-
import '@mui/icons-material/Settings';
|
|
17
|
-
import { useApi } from '@backstage/core-plugin-api';
|
|
18
4
|
import { useAsync, useList } from 'react-use';
|
|
19
|
-
import '@mui/material/TextField';
|
|
20
|
-
import '@mui/material/Paper';
|
|
21
|
-
import '@mui/material/Divider';
|
|
22
|
-
import '@mui/material/Card';
|
|
23
|
-
import '@mui/material/CardContent';
|
|
24
|
-
import '@mui/material/CardActions';
|
|
25
|
-
import '@mui/material/Alert';
|
|
26
|
-
import '@mui/icons-material/Delete';
|
|
27
|
-
import AddIcon from '@mui/icons-material/Add';
|
|
28
|
-
import Tooltip from '@mui/material/Tooltip';
|
|
29
|
-
import '../../api/mcp.esm.js';
|
|
30
5
|
import { chatApiRef } from '../../api/chat.esm.js';
|
|
31
6
|
import { useTheme } from '@mui/material/styles';
|
|
7
|
+
import Stack from '@mui/material/Stack';
|
|
8
|
+
import IconButton from '@mui/material/IconButton';
|
|
9
|
+
import Tooltip from '@mui/material/Tooltip';
|
|
32
10
|
import Drawer from '@mui/material/Drawer';
|
|
33
11
|
import List from '@mui/material/List';
|
|
34
12
|
import ListItemButton from '@mui/material/ListItemButton';
|
|
35
13
|
import ListItem from '@mui/material/ListItem';
|
|
14
|
+
import Box from '@mui/material/Box';
|
|
15
|
+
import Typography from '@mui/material/Typography';
|
|
36
16
|
import MenuIcon from '@mui/icons-material/Menu';
|
|
17
|
+
import AddIcon from '@mui/icons-material/Add';
|
|
18
|
+
import { useApi } from '@backstage/core-plugin-api';
|
|
37
19
|
import { signalApiRef } from '@backstage/plugin-signals-react';
|
|
38
20
|
import { useChatSettings } from '../../hooks/use-chat-settings.esm.js';
|
|
39
21
|
import { Page, Header, Content } from '@backstage/core-components';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiAssistantPage.esm.js","sources":["../../../src/components/AiAssistantPage/AiAssistantPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { Conversation } from '../Conversation';\nimport type { Conversation as ConversationType } from '@sweetoburrito/backstage-plugin-ai-assistant-common';\nimport { useAsync, useList } from 'react-use';\nimport { chatApiRef } from '../../api/chat';\nimport { useTheme } from '@mui/material/styles';\n\nimport Stack from '@mui/material/Stack';\nimport IconButton from '@mui/material/IconButton';\nimport Tooltip from '@mui/material/Tooltip';\nimport Drawer from '@mui/material/Drawer';\nimport List from '@mui/material/List';\nimport ListItemButton from '@mui/material/ListItemButton';\nimport ListItem from '@mui/material/ListItem';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\n\nimport MenuIcon from '@mui/icons-material/Menu';\nimport AddIcon from '@mui/icons-material/Add';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { signalApiRef } from '@backstage/plugin-signals-react';\nimport { useChatSettings } from '../../hooks/use-chat-settings';\nimport { Page, Content, Header } from '@backstage/core-components';\n\nimport { makeStyles } from 'tss-react/mui';\n\nexport type AiAssistantPageProps = {\n title?: string;\n subtitle?: string;\n};\n\nconst useStyles = makeStyles()(() => ({\n page: {\n height: '100vh',\n maxHeight: '100vh',\n overflow: 'hidden',\n display: 'flex',\n flexDirection: 'column',\n },\n content: {\n flex: 1,\n minHeight: 0,\n display: 'flex',\n flexDirection: 'column',\n },\n}));\n\nexport const AiAssistantPage = ({\n title = 'AI Assistant',\n subtitle,\n}: AiAssistantPageProps) => {\n const chatApi = useApi(chatApiRef);\n const signalApi = useApi(signalApiRef);\n\n const theme = useTheme();\n const { classes } = useStyles();\n\n const chatSettings = useChatSettings();\n\n useEffect(() => {\n chatSettings.setModalVisible(false);\n }, [chatSettings]);\n\n const [conversationId, setConversationId] = useState<string>();\n\n const { value: conversationHistory } = useAsync(\n () => chatApi.getConversations(),\n [chatApi],\n );\n\n const [conversations, { set, updateAt }] = useList<ConversationType>([]);\n\n useEffect(() => {\n if (!conversationHistory) {\n return;\n }\n\n set(conversationHistory);\n }, [conversationHistory, set]);\n\n useEffect(() => {\n const subscription = signalApi.subscribe<{\n conversation: ConversationType;\n }>(`ai-assistant.chat.conversation-details-update`, ({ conversation }) => {\n set(currentConversations => {\n const index = currentConversations.findIndex(\n c => c.id === conversation.id,\n );\n\n if (index !== -1) {\n const newConversations = [...currentConversations];\n newConversations[index] = conversation;\n return newConversations;\n }\n return [conversation, ...currentConversations];\n });\n });\n\n return () => subscription.unsubscribe();\n }, [signalApi, set, updateAt]);\n\n const [open, setOpen] = useState(false);\n\n const toggleDrawer = (drawerOpen: boolean) => () => {\n setOpen(drawerOpen);\n };\n\n const openNewChat = () => {\n setConversationId(undefined);\n };\n\n return (\n <Page themeId=\"tool\" className={classes.page}>\n <Header title={title} subtitle={subtitle} />\n <Content className={classes.content}>\n <Stack spacing={2} flex={1} boxSizing=\"border-box\" height=\"100%\">\n <Stack direction=\"row\" spacing={2} justifyContent=\"flex-end\">\n <Tooltip title=\"New Chat\">\n <IconButton onClick={openNewChat}>\n <AddIcon />\n </IconButton>\n </Tooltip>\n\n {conversations.length > 0 && (\n <Tooltip title=\"Chat History\">\n <IconButton onClick={toggleDrawer(true)}>\n <MenuIcon />\n </IconButton>\n </Tooltip>\n )}\n </Stack>\n <Conversation\n conversationId={conversationId}\n setConversationId={setConversationId}\n />\n </Stack>\n <Drawer anchor=\"right\" open={open} onClose={toggleDrawer(false)}>\n <Box\n sx={{ width: 300 }}\n role=\"presentation\"\n onClick={toggleDrawer(false)}\n >\n <List>\n {conversations.map(conversation => (\n <ListItem\n key={conversation.id}\n sx={{\n fontSize: theme.typography.body1.fontSize,\n }}\n >\n <ListItemButton\n sx={{\n justifyContent: 'flex-start !important',\n padding: `${theme.spacing(1)} !important`,\n borderRadius: `${theme.spacing(1)} !important`,\n backgroundColor:\n conversationId === conversation.id\n ? `${theme.palette.action.selected} !important`\n : 'transparent !important',\n }}\n onClick={() => setConversationId(conversation.id)}\n >\n <Typography\n variant=\"body1\"\n sx={{\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n width: '100%',\n }}\n >\n {conversation.title}\n </Typography>\n </ListItemButton>\n </ListItem>\n ))}\n </List>\n </Box>\n </Drawer>\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AiAssistantPage.esm.js","sources":["../../../src/components/AiAssistantPage/AiAssistantPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { Conversation } from '../Conversation';\nimport type { Conversation as ConversationType } from '@sweetoburrito/backstage-plugin-ai-assistant-common';\nimport { useAsync, useList } from 'react-use';\nimport { chatApiRef } from '../../api/chat';\nimport { useTheme } from '@mui/material/styles';\n\nimport Stack from '@mui/material/Stack';\nimport IconButton from '@mui/material/IconButton';\nimport Tooltip from '@mui/material/Tooltip';\nimport Drawer from '@mui/material/Drawer';\nimport List from '@mui/material/List';\nimport ListItemButton from '@mui/material/ListItemButton';\nimport ListItem from '@mui/material/ListItem';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\n\nimport MenuIcon from '@mui/icons-material/Menu';\nimport AddIcon from '@mui/icons-material/Add';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { signalApiRef } from '@backstage/plugin-signals-react';\nimport { useChatSettings } from '../../hooks/use-chat-settings';\nimport { Page, Content, Header } from '@backstage/core-components';\n\nimport { makeStyles } from 'tss-react/mui';\n\nexport type AiAssistantPageProps = {\n title?: string;\n subtitle?: string;\n};\n\nconst useStyles = makeStyles()(() => ({\n page: {\n height: '100vh',\n maxHeight: '100vh',\n overflow: 'hidden',\n display: 'flex',\n flexDirection: 'column',\n },\n content: {\n flex: 1,\n minHeight: 0,\n display: 'flex',\n flexDirection: 'column',\n },\n}));\n\nexport const AiAssistantPage = ({\n title = 'AI Assistant',\n subtitle,\n}: AiAssistantPageProps) => {\n const chatApi = useApi(chatApiRef);\n const signalApi = useApi(signalApiRef);\n\n const theme = useTheme();\n const { classes } = useStyles();\n\n const chatSettings = useChatSettings();\n\n useEffect(() => {\n chatSettings.setModalVisible(false);\n }, [chatSettings]);\n\n const [conversationId, setConversationId] = useState<string>();\n\n const { value: conversationHistory } = useAsync(\n () => chatApi.getConversations(),\n [chatApi],\n );\n\n const [conversations, { set, updateAt }] = useList<ConversationType>([]);\n\n useEffect(() => {\n if (!conversationHistory) {\n return;\n }\n\n set(conversationHistory);\n }, [conversationHistory, set]);\n\n useEffect(() => {\n const subscription = signalApi.subscribe<{\n conversation: ConversationType;\n }>(`ai-assistant.chat.conversation-details-update`, ({ conversation }) => {\n set(currentConversations => {\n const index = currentConversations.findIndex(\n c => c.id === conversation.id,\n );\n\n if (index !== -1) {\n const newConversations = [...currentConversations];\n newConversations[index] = conversation;\n return newConversations;\n }\n return [conversation, ...currentConversations];\n });\n });\n\n return () => subscription.unsubscribe();\n }, [signalApi, set, updateAt]);\n\n const [open, setOpen] = useState(false);\n\n const toggleDrawer = (drawerOpen: boolean) => () => {\n setOpen(drawerOpen);\n };\n\n const openNewChat = () => {\n setConversationId(undefined);\n };\n\n return (\n <Page themeId=\"tool\" className={classes.page}>\n <Header title={title} subtitle={subtitle} />\n <Content className={classes.content}>\n <Stack spacing={2} flex={1} boxSizing=\"border-box\" height=\"100%\">\n <Stack direction=\"row\" spacing={2} justifyContent=\"flex-end\">\n <Tooltip title=\"New Chat\">\n <IconButton onClick={openNewChat}>\n <AddIcon />\n </IconButton>\n </Tooltip>\n\n {conversations.length > 0 && (\n <Tooltip title=\"Chat History\">\n <IconButton onClick={toggleDrawer(true)}>\n <MenuIcon />\n </IconButton>\n </Tooltip>\n )}\n </Stack>\n <Conversation\n conversationId={conversationId}\n setConversationId={setConversationId}\n />\n </Stack>\n <Drawer anchor=\"right\" open={open} onClose={toggleDrawer(false)}>\n <Box\n sx={{ width: 300 }}\n role=\"presentation\"\n onClick={toggleDrawer(false)}\n >\n <List>\n {conversations.map(conversation => (\n <ListItem\n key={conversation.id}\n sx={{\n fontSize: theme.typography.body1.fontSize,\n }}\n >\n <ListItemButton\n sx={{\n justifyContent: 'flex-start !important',\n padding: `${theme.spacing(1)} !important`,\n borderRadius: `${theme.spacing(1)} !important`,\n backgroundColor:\n conversationId === conversation.id\n ? `${theme.palette.action.selected} !important`\n : 'transparent !important',\n }}\n onClick={() => setConversationId(conversation.id)}\n >\n <Typography\n variant=\"body1\"\n sx={{\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n width: '100%',\n }}\n >\n {conversation.title}\n </Typography>\n </ListItemButton>\n </ListItem>\n ))}\n </List>\n </Box>\n </Drawer>\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -13,7 +13,10 @@ import NorthIcon from '@mui/icons-material/North';
|
|
|
13
13
|
import SettingsIcon from '@mui/icons-material/Settings';
|
|
14
14
|
import Button from '@mui/material/Button';
|
|
15
15
|
import { MessageCard } from '../MessageCard/MessageCard.esm.js';
|
|
16
|
-
import { SettingsModal } from '
|
|
16
|
+
import { SettingsModal } from '../SettingsModal/SettingsModal.esm.js';
|
|
17
|
+
import { useChatSettings } from '../../hooks/use-chat-settings.esm.js';
|
|
18
|
+
import '../../api/summarizer.esm.js';
|
|
19
|
+
import 'react-router-dom';
|
|
17
20
|
|
|
18
21
|
const Conversation = ({
|
|
19
22
|
conversationId,
|
|
@@ -39,6 +42,7 @@ const Conversation = ({
|
|
|
39
42
|
[chatApi, conversationId]
|
|
40
43
|
);
|
|
41
44
|
const [messages, setMessages] = useState([]);
|
|
45
|
+
const { toolsEnabled } = useChatSettings();
|
|
42
46
|
useEffect(() => {
|
|
43
47
|
if (!history || !history.length) {
|
|
44
48
|
return;
|
|
@@ -103,7 +107,8 @@ const Conversation = ({
|
|
|
103
107
|
const response = await chatApi.sendMessage({
|
|
104
108
|
conversationId,
|
|
105
109
|
modelId,
|
|
106
|
-
messages: additionalSystemMessages ? [...additionalSystemMessages, ...newMessages] : newMessages
|
|
110
|
+
messages: additionalSystemMessages ? [...additionalSystemMessages, ...newMessages] : newMessages,
|
|
111
|
+
tools: toolsEnabled
|
|
107
112
|
});
|
|
108
113
|
setConversationId(response.conversationId);
|
|
109
114
|
return response;
|
|
@@ -115,7 +120,8 @@ const Conversation = ({
|
|
|
115
120
|
conversationId,
|
|
116
121
|
modelId,
|
|
117
122
|
errorApi,
|
|
118
|
-
setInput
|
|
123
|
+
setInput,
|
|
124
|
+
toolsEnabled
|
|
119
125
|
]);
|
|
120
126
|
const messageEndRef = useRef(null);
|
|
121
127
|
useEffect(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Conversation.esm.js","sources":["../../../src/components/Conversation/Conversation.tsx"],"sourcesContent":["import { useApi, errorApiRef } from '@backstage/core-plugin-api';\nimport { chatApiRef } from '../../api/chat';\nimport { useAsync, useAsyncFn, useLocalStorage } from 'react-use';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { signalApiRef } from '@backstage/plugin-signals-react';\n\nimport Typography from '@mui/material/Typography';\nimport TextField from '@mui/material/TextField';\nimport Stack from '@mui/material/Stack';\nimport Autocomplete from '@mui/material/Autocomplete';\nimport Paper from '@mui/material/Paper';\nimport NorthIcon from '@mui/icons-material/North';\nimport SettingsIcon from '@mui/icons-material/Settings';\nimport Button from '@mui/material/Button';\nimport { Message } from '@sweetoburrito/backstage-plugin-ai-assistant-common';\nimport { MessageCard } from '../MessageCard';\nimport { SettingsModal } from './SettingsModal';\n\ntype ConversationOptions = {\n conversationId: string | undefined;\n setConversationId: (id: string) => void;\n additionalSystemMessages?: Message[];\n};\n\nexport const Conversation = ({\n conversationId,\n setConversationId,\n additionalSystemMessages,\n}: ConversationOptions) => {\n const chatApi = useApi(chatApiRef);\n const errorApi = useApi(errorApiRef);\n const signalApi = useApi(signalApiRef);\n\n const [input, setInput] = useState('');\n const inputRef = useRef<HTMLInputElement>(null);\n\n const [modelId, setModelId] = useLocalStorage<string | undefined>(\n 'modelId',\n undefined,\n );\n\n const [settingsModalOpen, setSettingsModalOpen] = useState(false);\n\n const { value: models, loading: loadingModels } = useAsync(\n () => chatApi.getModels(),\n [chatApi],\n );\n\n const { value: history, loading: loadingHistory } = useAsync(\n () => chatApi.getConversation(conversationId),\n [chatApi, conversationId],\n );\n\n const [messages, setMessages] = useState<Message[]>([]);\n\n useEffect(() => {\n if (!history || !history.length) {\n return;\n }\n\n setMessages(history);\n }, [history, setMessages]);\n\n const handleMessageUpdate = useCallback(\n (newMessages: Required<Message>[]) => {\n setMessages(prev => {\n const updated = [...prev];\n\n newMessages.forEach(message => {\n const index = updated.findIndex(m => m.id === message.id);\n\n if (index === -1) {\n updated.push(message);\n } else {\n updated[index] = message;\n }\n });\n\n return updated;\n });\n },\n [setMessages],\n );\n\n useEffect(() => {\n if (!conversationId) {\n return undefined;\n }\n\n const subscriber = signalApi.subscribe(\n `ai-assistant.chat.conversation-stream:${conversationId}`,\n (event: { messages: Required<Message>[] }) => {\n handleMessageUpdate(event.messages);\n },\n );\n\n return () => {\n subscriber.unsubscribe();\n };\n }, [conversationId, signalApi, handleMessageUpdate]);\n\n useEffect(() => {\n if (!conversationId) {\n setMessages([]);\n }\n }, [conversationId]);\n\n useEffect(() => {\n if (models && models.length && !modelId) {\n setModelId(models[0]);\n }\n }, [models, modelId, setModelId]);\n\n const [{ loading: sending }, sendMessage] = useAsyncFn(async () => {\n const newMessages: Message[] = [\n { role: 'human', content: input, metadata: {}, score: 0 },\n ];\n\n if (!modelId) {\n errorApi.post({\n name: 'NoModelError',\n message:\n 'No model has been selected for this conversation. Please select a model before sending a message',\n });\n return undefined;\n }\n\n setInput('');\n inputRef.current?.focus();\n\n setMessages(prev => [...prev, ...newMessages]);\n\n const response = await chatApi.sendMessage({\n conversationId,\n modelId,\n messages: additionalSystemMessages\n ? [...additionalSystemMessages, ...newMessages]\n : newMessages,\n });\n\n setConversationId(response.conversationId);\n\n return response;\n }, [\n input,\n inputRef,\n chatApi,\n setConversationId,\n conversationId,\n modelId,\n errorApi,\n setInput,\n ]);\n\n const messageEndRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n messageEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n }, [messages]);\n\n if (loadingHistory && loadingModels) {\n return <Typography>Loading...</Typography>;\n }\n\n if (!models) {\n return <Typography>No models available</Typography>;\n }\n\n return (\n <Stack\n padding={2}\n spacing={2}\n flex={1}\n boxSizing=\"border-box\"\n height=\"100%\"\n minHeight={0}\n >\n {messages && (\n <Stack\n spacing={1}\n flex={1}\n sx={{\n overflowY: 'auto',\n pr: 1,\n '&::-webkit-scrollbar': {\n background: 'transparent',\n },\n '&::-webkit-scrollbar-track': {\n background: 'transparent',\n },\n }}\n >\n {messages.map((message, idx) => (\n <MessageCard\n key={message.id ?? idx}\n message={message}\n loading={false}\n />\n ))}\n {messages[messages.length - 1] &&\n messages[messages.length - 1]?.role !== 'ai' && (\n <MessageCard\n message={{ content: '', role: 'ai', metadata: {}, score: 0 }}\n loading\n />\n )}\n <div ref={messageEndRef} />\n </Stack>\n )}\n\n <Paper elevation={2} sx={{ padding: 1 }}>\n <Stack\n direction=\"row\"\n spacing={1}\n alignItems=\"center\"\n justifyContent=\"start\"\n >\n <TextField\n multiline\n maxRows={3}\n variant=\"standard\"\n sx={{ flex: 1 }}\n value={input}\n onChange={e => setInput(e.target.value)}\n inputRef={inputRef}\n onKeyDown={e => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n sendMessage();\n }\n }}\n />\n <Autocomplete\n options={models}\n defaultValue={modelId}\n onChange={(_, value) => setModelId(value || undefined)}\n sx={{ width: 180 }}\n size=\"small\"\n renderInput={params => <TextField {...params} label=\"Models\" />}\n />\n <Button\n disabled={sending}\n variant=\"contained\"\n color=\"info\"\n title=\"Settings\"\n onClick={() => setSettingsModalOpen(true)}\n >\n <SettingsIcon />\n </Button>\n <Button\n variant=\"contained\"\n disabled={sending || !input.trim()}\n onClick={sendMessage}\n >\n <NorthIcon />\n </Button>\n </Stack>\n </Paper>\n\n <SettingsModal\n open={settingsModalOpen}\n onClose={() => setSettingsModalOpen(false)}\n />\n </Stack>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Conversation.esm.js","sources":["../../../src/components/Conversation/Conversation.tsx"],"sourcesContent":["import { useApi, errorApiRef } from '@backstage/core-plugin-api';\nimport { chatApiRef } from '../../api/chat';\nimport { useAsync, useAsyncFn, useLocalStorage } from 'react-use';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { signalApiRef } from '@backstage/plugin-signals-react';\n\nimport Typography from '@mui/material/Typography';\nimport TextField from '@mui/material/TextField';\nimport Stack from '@mui/material/Stack';\nimport Autocomplete from '@mui/material/Autocomplete';\nimport Paper from '@mui/material/Paper';\nimport NorthIcon from '@mui/icons-material/North';\nimport SettingsIcon from '@mui/icons-material/Settings';\nimport Button from '@mui/material/Button';\nimport { Message } from '@sweetoburrito/backstage-plugin-ai-assistant-common';\nimport { MessageCard } from '../MessageCard';\nimport { SettingsModal } from '../SettingsModal';\nimport { useChatSettings } from '../../hooks';\n\ntype ConversationOptions = {\n conversationId: string | undefined;\n setConversationId: (id: string) => void;\n additionalSystemMessages?: Message[];\n};\n\nexport const Conversation = ({\n conversationId,\n setConversationId,\n additionalSystemMessages,\n}: ConversationOptions) => {\n const chatApi = useApi(chatApiRef);\n const errorApi = useApi(errorApiRef);\n const signalApi = useApi(signalApiRef);\n\n const [input, setInput] = useState('');\n const inputRef = useRef<HTMLInputElement>(null);\n\n const [modelId, setModelId] = useLocalStorage<string | undefined>(\n 'modelId',\n undefined,\n );\n\n const [settingsModalOpen, setSettingsModalOpen] = useState(false);\n\n const { value: models, loading: loadingModels } = useAsync(\n () => chatApi.getModels(),\n [chatApi],\n );\n\n const { value: history, loading: loadingHistory } = useAsync(\n () => chatApi.getConversation(conversationId),\n [chatApi, conversationId],\n );\n\n const [messages, setMessages] = useState<Message[]>([]);\n\n const { toolsEnabled } = useChatSettings();\n\n useEffect(() => {\n if (!history || !history.length) {\n return;\n }\n\n setMessages(history);\n }, [history, setMessages]);\n\n const handleMessageUpdate = useCallback(\n (newMessages: Required<Message>[]) => {\n setMessages(prev => {\n const updated = [...prev];\n\n newMessages.forEach(message => {\n const index = updated.findIndex(m => m.id === message.id);\n\n if (index === -1) {\n updated.push(message);\n } else {\n updated[index] = message;\n }\n });\n\n return updated;\n });\n },\n [setMessages],\n );\n\n useEffect(() => {\n if (!conversationId) {\n return undefined;\n }\n\n const subscriber = signalApi.subscribe(\n `ai-assistant.chat.conversation-stream:${conversationId}`,\n (event: { messages: Required<Message>[] }) => {\n handleMessageUpdate(event.messages);\n },\n );\n\n return () => {\n subscriber.unsubscribe();\n };\n }, [conversationId, signalApi, handleMessageUpdate]);\n\n useEffect(() => {\n if (!conversationId) {\n setMessages([]);\n }\n }, [conversationId]);\n\n useEffect(() => {\n if (models && models.length && !modelId) {\n setModelId(models[0]);\n }\n }, [models, modelId, setModelId]);\n\n const [{ loading: sending }, sendMessage] = useAsyncFn(async () => {\n const newMessages: Message[] = [\n { role: 'human', content: input, metadata: {}, score: 0 },\n ];\n\n if (!modelId) {\n errorApi.post({\n name: 'NoModelError',\n message:\n 'No model has been selected for this conversation. Please select a model before sending a message',\n });\n return undefined;\n }\n\n setInput('');\n inputRef.current?.focus();\n\n setMessages(prev => [...prev, ...newMessages]);\n\n const response = await chatApi.sendMessage({\n conversationId,\n modelId,\n messages: additionalSystemMessages\n ? [...additionalSystemMessages, ...newMessages]\n : newMessages,\n tools: toolsEnabled,\n });\n\n setConversationId(response.conversationId);\n\n return response;\n }, [\n input,\n inputRef,\n chatApi,\n setConversationId,\n conversationId,\n modelId,\n errorApi,\n setInput,\n toolsEnabled,\n ]);\n\n const messageEndRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n messageEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n }, [messages]);\n\n if (loadingHistory && loadingModels) {\n return <Typography>Loading...</Typography>;\n }\n\n if (!models) {\n return <Typography>No models available</Typography>;\n }\n\n return (\n <Stack\n padding={2}\n spacing={2}\n flex={1}\n boxSizing=\"border-box\"\n height=\"100%\"\n minHeight={0}\n >\n {messages && (\n <Stack\n spacing={1}\n flex={1}\n sx={{\n overflowY: 'auto',\n pr: 1,\n '&::-webkit-scrollbar': {\n background: 'transparent',\n },\n '&::-webkit-scrollbar-track': {\n background: 'transparent',\n },\n }}\n >\n {messages.map((message, idx) => (\n <MessageCard\n key={message.id ?? idx}\n message={message}\n loading={false}\n />\n ))}\n {messages[messages.length - 1] &&\n messages[messages.length - 1]?.role !== 'ai' && (\n <MessageCard\n message={{ content: '', role: 'ai', metadata: {}, score: 0 }}\n loading\n />\n )}\n <div ref={messageEndRef} />\n </Stack>\n )}\n\n <Paper elevation={2} sx={{ padding: 1 }}>\n <Stack\n direction=\"row\"\n spacing={1}\n alignItems=\"center\"\n justifyContent=\"start\"\n >\n <TextField\n multiline\n maxRows={3}\n variant=\"standard\"\n sx={{ flex: 1 }}\n value={input}\n onChange={e => setInput(e.target.value)}\n inputRef={inputRef}\n onKeyDown={e => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n sendMessage();\n }\n }}\n />\n <Autocomplete\n options={models}\n defaultValue={modelId}\n onChange={(_, value) => setModelId(value || undefined)}\n sx={{ width: 180 }}\n size=\"small\"\n renderInput={params => <TextField {...params} label=\"Models\" />}\n />\n <Button\n disabled={sending}\n variant=\"contained\"\n color=\"info\"\n title=\"Settings\"\n onClick={() => setSettingsModalOpen(true)}\n >\n <SettingsIcon />\n </Button>\n <Button\n variant=\"contained\"\n disabled={sending || !input.trim()}\n onClick={sendMessage}\n >\n <NorthIcon />\n </Button>\n </Stack>\n </Paper>\n\n <SettingsModal\n open={settingsModalOpen}\n onClose={() => setSettingsModalOpen(false)}\n />\n </Stack>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -13,28 +13,9 @@ import Stack from '@mui/material/Stack';
|
|
|
13
13
|
import IconButton from '@mui/material/IconButton';
|
|
14
14
|
import CloseIcon from '@mui/icons-material/Close';
|
|
15
15
|
import SettingsIcon from '@mui/icons-material/Settings';
|
|
16
|
-
import {
|
|
16
|
+
import { TabPanel } from './TabPanel.esm.js';
|
|
17
|
+
import tabs from './tabs/index.esm.js';
|
|
17
18
|
|
|
18
|
-
function TabPanel(props) {
|
|
19
|
-
const { children, value, index, ...other } = props;
|
|
20
|
-
return /* @__PURE__ */ jsx(
|
|
21
|
-
Box,
|
|
22
|
-
{
|
|
23
|
-
role: "tabpanel",
|
|
24
|
-
hidden: value !== index,
|
|
25
|
-
id: `vertical-tabpanel-${index}`,
|
|
26
|
-
"aria-labelledby": `vertical-tab-${index}`,
|
|
27
|
-
...other,
|
|
28
|
-
sx: {
|
|
29
|
-
width: "100%",
|
|
30
|
-
height: "100%",
|
|
31
|
-
overflow: "auto"
|
|
32
|
-
// Allow content to scroll independently
|
|
33
|
-
},
|
|
34
|
-
children: value === index && /* @__PURE__ */ jsx(Box, { sx: { p: 3 }, children })
|
|
35
|
-
}
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
19
|
const SettingsModal = ({
|
|
39
20
|
open,
|
|
40
21
|
onClose
|
|
@@ -50,8 +31,10 @@ const SettingsModal = ({
|
|
|
50
31
|
onClose,
|
|
51
32
|
maxWidth: "lg",
|
|
52
33
|
fullWidth: true,
|
|
53
|
-
|
|
54
|
-
|
|
34
|
+
slotProps: {
|
|
35
|
+
paper: {
|
|
36
|
+
sx: { height: "80vh", maxHeight: 800 }
|
|
37
|
+
}
|
|
55
38
|
},
|
|
56
39
|
children: [
|
|
57
40
|
/* @__PURE__ */ jsx(DialogTitle, { children: /* @__PURE__ */ jsxs(
|
|
@@ -102,25 +85,27 @@ const SettingsModal = ({
|
|
|
102
85
|
"& .MuiTab-root": {
|
|
103
86
|
alignItems: "flex-start",
|
|
104
87
|
textAlign: "left",
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
//
|
|
88
|
+
pl: 1,
|
|
89
|
+
minHeight: (theme) => theme.spacing(5)
|
|
90
|
+
// Increase minHeight for better spacing
|
|
108
91
|
}
|
|
109
92
|
},
|
|
110
|
-
children: /* @__PURE__ */ jsx(Tab, { label:
|
|
93
|
+
children: tabs.map((tab, index) => /* @__PURE__ */ jsx(Tab, { label: tab.name, "aria-label": tab.title }, index))
|
|
111
94
|
}
|
|
112
95
|
)
|
|
113
96
|
}
|
|
114
97
|
),
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
98
|
+
tabs.map((tab, index) => /* @__PURE__ */ jsx(
|
|
99
|
+
TabPanel,
|
|
100
|
+
{
|
|
101
|
+
value: selectedTab,
|
|
102
|
+
index,
|
|
103
|
+
title: tab.title,
|
|
104
|
+
description: tab.description,
|
|
105
|
+
children: /* @__PURE__ */ jsx(tab.Tab, {})
|
|
106
|
+
},
|
|
107
|
+
index
|
|
108
|
+
))
|
|
124
109
|
]
|
|
125
110
|
}
|
|
126
111
|
) }),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SettingsModal.esm.js","sources":["../../../src/components/SettingsModal/SettingsModal.tsx"],"sourcesContent":["import { useState } from 'react';\nimport Dialog from '@mui/material/Dialog';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogActions from '@mui/material/DialogActions';\nimport Button from '@mui/material/Button';\nimport Tab from '@mui/material/Tab';\nimport Tabs from '@mui/material/Tabs';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Stack from '@mui/material/Stack';\nimport IconButton from '@mui/material/IconButton';\nimport CloseIcon from '@mui/icons-material/Close';\nimport SettingsIcon from '@mui/icons-material/Settings';\nimport { TabPanel } from './TabPanel';\nimport tabs from './tabs';\n\ninterface SettingsModalProps {\n open: boolean;\n onClose: () => void;\n}\n\nexport const SettingsModal: React.FC<SettingsModalProps> = ({\n open,\n onClose,\n}) => {\n const [selectedTab, setSelectedTab] = useState(0);\n\n const handleTabChange = (_: React.SyntheticEvent, newValue: number) => {\n setSelectedTab(newValue);\n };\n\n return (\n <Dialog\n open={open}\n onClose={onClose}\n maxWidth=\"lg\"\n fullWidth\n slotProps={{\n paper: {\n sx: { height: '80vh', maxHeight: 800 },\n },\n }}\n >\n <DialogTitle>\n <Stack\n direction=\"row\"\n alignItems=\"center\"\n justifyContent=\"space-between\"\n >\n <Stack direction=\"row\" alignItems=\"center\" spacing={1}>\n <SettingsIcon />\n <Typography variant=\"h6\">Settings</Typography>\n </Stack>\n <IconButton onClick={onClose} size=\"small\">\n <CloseIcon />\n </IconButton>\n </Stack>\n </DialogTitle>\n\n <DialogContent dividers sx={{ p: 0 }}>\n <Box\n sx={{\n flexGrow: 1,\n bgcolor: 'background.paper',\n display: 'flex',\n height: '100%',\n }}\n >\n <Box\n sx={{\n borderRight: 1,\n borderColor: 'divider',\n minWidth: 200,\n flexShrink: 0, // Prevent tabs from shrinking\n }}\n >\n <Tabs\n orientation=\"vertical\"\n variant=\"standard\"\n value={selectedTab}\n onChange={handleTabChange}\n sx={{\n pl: 2, // Add left padding to the tabs container\n '& .MuiTab-root': {\n alignItems: 'flex-start',\n textAlign: 'left',\n pl: 1,\n minHeight: theme => theme.spacing(5), // Increase minHeight for better spacing\n },\n }}\n >\n {tabs.map((tab, index) => (\n <Tab key={index} label={tab.name} aria-label={tab.title} />\n ))}\n </Tabs>\n </Box>\n\n {tabs.map((tab, index) => (\n <TabPanel\n key={index}\n value={selectedTab}\n index={index}\n title={tab.title}\n description={tab.description}\n >\n <tab.Tab />\n </TabPanel>\n ))}\n </Box>\n </DialogContent>\n\n <DialogActions>\n <Button onClick={onClose}>Close</Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAsBO,MAAM,gBAA8C,CAAC;AAAA,EAC1D,IAAA;AAAA,EACA;AACF,CAAA,KAAM;AACJ,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAS,CAAC,CAAA;AAEhD,EAAA,MAAM,eAAA,GAAkB,CAAC,CAAA,EAAyB,QAAA,KAAqB;AACrE,IAAA,cAAA,CAAe,QAAQ,CAAA;AAAA,EACzB,CAAA;AAEA,EAAA,uBACE,IAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,IAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAA,EAAS,IAAA;AAAA,MACT,SAAA,EAAS,IAAA;AAAA,MACT,SAAA,EAAW;AAAA,QACT,KAAA,EAAO;AAAA,UACL,EAAA,EAAI,EAAE,MAAA,EAAQ,MAAA,EAAQ,WAAW,GAAA;AAAI;AACvC,OACF;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,WAAA,EAAA,EACC,QAAA,kBAAA,IAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,KAAA;AAAA,YACV,UAAA,EAAW,QAAA;AAAA,YACX,cAAA,EAAe,eAAA;AAAA,YAEf,QAAA,EAAA;AAAA,8BAAA,IAAA,CAAC,SAAM,SAAA,EAAU,KAAA,EAAM,UAAA,EAAW,QAAA,EAAS,SAAS,CAAA,EAClD,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,YAAA,EAAA,EAAa,CAAA;AAAA,gCACd,GAAA,CAAC,UAAA,EAAA,EAAW,OAAA,EAAQ,IAAA,EAAK,QAAA,EAAA,UAAA,EAAQ;AAAA,eAAA,EACnC,CAAA;AAAA,8BACA,GAAA,CAAC,cAAW,OAAA,EAAS,OAAA,EAAS,MAAK,OAAA,EACjC,QAAA,kBAAA,GAAA,CAAC,aAAU,CAAA,EACb;AAAA;AAAA;AAAA,SACF,EACF,CAAA;AAAA,wBAEA,GAAA,CAAC,iBAAc,QAAA,EAAQ,IAAA,EAAC,IAAI,EAAE,CAAA,EAAG,GAAE,EACjC,QAAA,kBAAA,IAAA;AAAA,UAAC,GAAA;AAAA,UAAA;AAAA,YACC,EAAA,EAAI;AAAA,cACF,QAAA,EAAU,CAAA;AAAA,cACV,OAAA,EAAS,kBAAA;AAAA,cACT,OAAA,EAAS,MAAA;AAAA,cACT,MAAA,EAAQ;AAAA,aACV;AAAA,YAEA,QAAA,EAAA;AAAA,8BAAA,GAAA;AAAA,gBAAC,GAAA;AAAA,gBAAA;AAAA,kBACC,EAAA,EAAI;AAAA,oBACF,WAAA,EAAa,CAAA;AAAA,oBACb,WAAA,EAAa,SAAA;AAAA,oBACb,QAAA,EAAU,GAAA;AAAA,oBACV,UAAA,EAAY;AAAA;AAAA,mBACd;AAAA,kBAEA,QAAA,kBAAA,GAAA;AAAA,oBAAC,IAAA;AAAA,oBAAA;AAAA,sBACC,WAAA,EAAY,UAAA;AAAA,sBACZ,OAAA,EAAQ,UAAA;AAAA,sBACR,KAAA,EAAO,WAAA;AAAA,sBACP,QAAA,EAAU,eAAA;AAAA,sBACV,EAAA,EAAI;AAAA,wBACF,EAAA,EAAI,CAAA;AAAA;AAAA,wBACJ,gBAAA,EAAkB;AAAA,0BAChB,UAAA,EAAY,YAAA;AAAA,0BACZ,SAAA,EAAW,MAAA;AAAA,0BACX,EAAA,EAAI,CAAA;AAAA,0BACJ,SAAA,EAAW,CAAA,KAAA,KAAS,KAAA,CAAM,OAAA,CAAQ,CAAC;AAAA;AAAA;AACrC,uBACF;AAAA,sBAEC,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,EAAK,0BACd,GAAA,CAAC,GAAA,EAAA,EAAgB,KAAA,EAAO,GAAA,CAAI,IAAA,EAAM,YAAA,EAAY,GAAA,CAAI,KAAA,EAAA,EAAxC,KAA+C,CAC1D;AAAA;AAAA;AACH;AAAA,eACF;AAAA,cAEC,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,EAAK,KAAA,qBACd,GAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBAEC,KAAA,EAAO,WAAA;AAAA,kBACP,KAAA;AAAA,kBACA,OAAO,GAAA,CAAI,KAAA;AAAA,kBACX,aAAa,GAAA,CAAI,WAAA;AAAA,kBAEjB,QAAA,kBAAA,GAAA,CAAC,GAAA,CAAI,GAAA,EAAJ,EAAQ;AAAA,iBAAA;AAAA,gBANJ;AAAA,eAQR;AAAA;AAAA;AAAA,SACH,EACF,CAAA;AAAA,4BAEC,aAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,UAAO,OAAA,EAAS,OAAA,EAAS,mBAAK,CAAA,EACjC;AAAA;AAAA;AAAA,GACF;AAEJ;;;;"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import Typography from '@mui/material/Typography';
|
|
3
|
+
import Stack from '@mui/material/Stack';
|
|
4
|
+
import Divider from '@mui/material/Divider';
|
|
5
|
+
import Box from '@mui/material/Box';
|
|
6
|
+
|
|
7
|
+
const TabPanelHeader = ({
|
|
8
|
+
title,
|
|
9
|
+
description
|
|
10
|
+
}) => {
|
|
11
|
+
return /* @__PURE__ */ jsxs(Stack, { direction: "column", justifyContent: "space-between", alignItems: "start", children: [
|
|
12
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h6", children: title }),
|
|
13
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", children: description })
|
|
14
|
+
] });
|
|
15
|
+
};
|
|
16
|
+
const TabPanel = (props) => {
|
|
17
|
+
const { children, value, index } = props;
|
|
18
|
+
return /* @__PURE__ */ jsx(
|
|
19
|
+
Box,
|
|
20
|
+
{
|
|
21
|
+
role: "tabpanel",
|
|
22
|
+
hidden: value !== index,
|
|
23
|
+
id: `vertical-tabpanel-${index}`,
|
|
24
|
+
"aria-labelledby": `vertical-tab-${index}`,
|
|
25
|
+
sx: {
|
|
26
|
+
width: "100%",
|
|
27
|
+
height: "100%",
|
|
28
|
+
overflow: "auto",
|
|
29
|
+
// Allow content to scroll independently
|
|
30
|
+
padding: 2
|
|
31
|
+
},
|
|
32
|
+
children: value === index && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Stack, { spacing: 2, children: [
|
|
33
|
+
/* @__PURE__ */ jsx(TabPanelHeader, { ...props }),
|
|
34
|
+
/* @__PURE__ */ jsx(Divider, {}),
|
|
35
|
+
/* @__PURE__ */ jsx(Box, { children })
|
|
36
|
+
] }) })
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export { TabPanel };
|
|
42
|
+
//# sourceMappingURL=TabPanel.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TabPanel.esm.js","sources":["../../../src/components/SettingsModal/TabPanel.tsx"],"sourcesContent":["import Typography from '@mui/material/Typography';\nimport Stack from '@mui/material/Stack';\nimport Divider from '@mui/material/Divider';\nimport Box from '@mui/material/Box';\n\nimport { ReactNode } from 'react';\n\nexport type TabPanelProps = {\n title: string;\n description: string;\n children: ReactNode;\n index: number;\n value: number;\n};\n\nconst TabPanelHeader = ({\n title,\n description,\n}: Pick<TabPanelProps, 'title' | 'description'>) => {\n return (\n <Stack direction=\"column\" justifyContent=\"space-between\" alignItems=\"start\">\n <Typography variant=\"h6\">{title}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {description}\n </Typography>\n </Stack>\n );\n};\n\nexport const TabPanel = (props: TabPanelProps) => {\n const { children, value, index } = props;\n return (\n <Box\n role=\"tabpanel\"\n hidden={value !== index}\n id={`vertical-tabpanel-${index}`}\n aria-labelledby={`vertical-tab-${index}`}\n sx={{\n width: '100%',\n height: '100%',\n overflow: 'auto', // Allow content to scroll independently\n padding: 2,\n }}\n >\n {value === index && (\n <Box>\n <Stack spacing={2}>\n <TabPanelHeader {...props} />\n <Divider />\n <Box>{children}</Box>\n </Stack>\n </Box>\n )}\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;AAeA,MAAM,iBAAiB,CAAC;AAAA,EACtB,KAAA;AAAA,EACA;AACF,CAAA,KAAoD;AAClD,EAAA,4BACG,KAAA,EAAA,EAAM,SAAA,EAAU,UAAS,cAAA,EAAe,eAAA,EAAgB,YAAW,OAAA,EAClE,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,OAAA,EAAQ,IAAA,EAAM,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,wBAC/B,UAAA,EAAA,EAAW,OAAA,EAAQ,OAAA,EAAQ,KAAA,EAAM,kBAC/B,QAAA,EAAA,WAAA,EACH;AAAA,GAAA,EACF,CAAA;AAEJ,CAAA;AAEO,MAAM,QAAA,GAAW,CAAC,KAAA,KAAyB;AAChD,EAAA,MAAM,EAAE,QAAA,EAAU,KAAA,EAAO,KAAA,EAAM,GAAI,KAAA;AACnC,EAAA,uBACE,GAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,UAAA;AAAA,MACL,QAAQ,KAAA,KAAU,KAAA;AAAA,MAClB,EAAA,EAAI,qBAAqB,KAAK,CAAA,CAAA;AAAA,MAC9B,iBAAA,EAAiB,gBAAgB,KAAK,CAAA,CAAA;AAAA,MACtC,EAAA,EAAI;AAAA,QACF,KAAA,EAAO,MAAA;AAAA,QACP,MAAA,EAAQ,MAAA;AAAA,QACR,QAAA,EAAU,MAAA;AAAA;AAAA,QACV,OAAA,EAAS;AAAA,OACX;AAAA,MAEC,oBAAU,KAAA,oBACT,GAAA,CAAC,OACC,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAM,SAAS,CAAA,EACd,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,cAAA,EAAA,EAAgB,GAAG,KAAA,EAAO,CAAA;AAAA,4BAC1B,OAAA,EAAA,EAAQ,CAAA;AAAA,wBACT,GAAA,CAAC,OAAK,QAAA,EAAS;AAAA,OAAA,EACjB,CAAA,EACF;AAAA;AAAA,GAEJ;AAEJ;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import { useState, useRef, useCallback } from 'react';
|
|
3
3
|
import { useApi, alertApiRef } from '@backstage/core-plugin-api';
|
|
4
4
|
import { useAsync, useAsyncFn } from 'react-use';
|
|
@@ -8,7 +8,6 @@ import Typography from '@mui/material/Typography';
|
|
|
8
8
|
import Stack from '@mui/material/Stack';
|
|
9
9
|
import Paper from '@mui/material/Paper';
|
|
10
10
|
import IconButton from '@mui/material/IconButton';
|
|
11
|
-
import Divider from '@mui/material/Divider';
|
|
12
11
|
import Card from '@mui/material/Card';
|
|
13
12
|
import CardContent from '@mui/material/CardContent';
|
|
14
13
|
import CardActions from '@mui/material/CardActions';
|
|
@@ -18,9 +17,9 @@ import DeleteIcon from '@mui/icons-material/Delete';
|
|
|
18
17
|
import CloseIcon from '@mui/icons-material/Close';
|
|
19
18
|
import AddIcon from '@mui/icons-material/Add';
|
|
20
19
|
import Tooltip from '@mui/material/Tooltip';
|
|
21
|
-
import { mcpApiRef } from '
|
|
20
|
+
import { mcpApiRef } from '../../../../api/mcp.esm.js';
|
|
22
21
|
|
|
23
|
-
const
|
|
22
|
+
const Tab = () => {
|
|
24
23
|
const mcpApi = useApi(mcpApiRef);
|
|
25
24
|
const alertApi = useApi(alertApiRef);
|
|
26
25
|
const [configs, setConfigs] = useState([]);
|
|
@@ -157,22 +156,12 @@ const McpServersTab = () => {
|
|
|
157
156
|
[configs, editingIndex, mcpApi, alertApi, resetForm]
|
|
158
157
|
);
|
|
159
158
|
if (loading) {
|
|
160
|
-
return /* @__PURE__ */
|
|
161
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h6", children: "Model Context Protocol (MCP) Servers" }),
|
|
162
|
-
/* @__PURE__ */ jsx(Alert, { severity: "info", children: "Loading MCP server configurations..." })
|
|
163
|
-
] });
|
|
159
|
+
return /* @__PURE__ */ jsx(Alert, { severity: "info", children: "Loading MCP server configurations..." });
|
|
164
160
|
}
|
|
165
161
|
if (fetchError) {
|
|
166
|
-
return /* @__PURE__ */
|
|
167
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h6", children: "Model Context Protocol (MCP) Servers" }),
|
|
168
|
-
/* @__PURE__ */ jsx(Alert, { severity: "error", children: "Failed to load MCP server configurations. Please try refreshing the page." })
|
|
169
|
-
] });
|
|
162
|
+
return /* @__PURE__ */ jsx(Alert, { severity: "error", children: "Failed to load MCP server configurations. Please try refreshing the page." });
|
|
170
163
|
}
|
|
171
164
|
return /* @__PURE__ */ jsxs(Stack, { spacing: 3, children: [
|
|
172
|
-
/* @__PURE__ */ jsx(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
173
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h6", children: "Model Context Protocol (MCP) Servers" }),
|
|
174
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", children: "Configure MCP servers to extend the AI assistant with additional tools and capabilities." })
|
|
175
|
-
] }) }),
|
|
176
165
|
showForm && /* @__PURE__ */ jsxs(Paper, { variant: "outlined", sx: { p: 3 }, ref: formRef, children: [
|
|
177
166
|
/* @__PURE__ */ jsx(Typography, { variant: "subtitle1", gutterBottom: true, children: editingIndex !== null ? "Edit Server" : "Add New Server" }),
|
|
178
167
|
error && /* @__PURE__ */ jsx(Alert, { severity: "error", sx: { mb: 2 }, children: error }),
|
|
@@ -237,7 +226,6 @@ const McpServersTab = () => {
|
|
|
237
226
|
] })
|
|
238
227
|
] })
|
|
239
228
|
] }),
|
|
240
|
-
/* @__PURE__ */ jsx(Divider, {}),
|
|
241
229
|
/* @__PURE__ */ jsxs(Stack, { spacing: 2, children: [
|
|
242
230
|
/* @__PURE__ */ jsxs(
|
|
243
231
|
Stack,
|
|
@@ -299,5 +287,5 @@ const McpServersTab = () => {
|
|
|
299
287
|
] });
|
|
300
288
|
};
|
|
301
289
|
|
|
302
|
-
export {
|
|
303
|
-
//# sourceMappingURL=
|
|
290
|
+
export { Tab };
|
|
291
|
+
//# sourceMappingURL=McpServers.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"McpServers.esm.js","sources":["../../../../../src/components/SettingsModal/tabs/McpServers/McpServers.tsx"],"sourcesContent":["import { useState, useCallback, useRef } from 'react';\nimport { useApi, alertApiRef } from '@backstage/core-plugin-api';\nimport { useAsync, useAsyncFn } from 'react-use';\nimport Box from '@mui/material/Box';\nimport TextField from '@mui/material/TextField';\nimport Typography from '@mui/material/Typography';\nimport Stack from '@mui/material/Stack';\nimport Paper from '@mui/material/Paper';\nimport IconButton from '@mui/material/IconButton';\nimport Card from '@mui/material/Card';\nimport CardContent from '@mui/material/CardContent';\nimport CardActions from '@mui/material/CardActions';\nimport Alert from '@mui/material/Alert';\nimport Button from '@mui/material/Button';\nimport DeleteIcon from '@mui/icons-material/Delete';\nimport CloseIcon from '@mui/icons-material/Close';\nimport AddIcon from '@mui/icons-material/Add';\nimport Tooltip from '@mui/material/Tooltip';\nimport { McpServerConfig } from '@sweetoburrito/backstage-plugin-ai-assistant-common';\nimport { mcpApiRef } from '../../../../api/mcp';\n\ntype McpConfigFormData = {\n name: string;\n options: string;\n};\n\nexport const Tab = () => {\n const mcpApi = useApi(mcpApiRef);\n const alertApi = useApi(alertApiRef);\n\n const [configs, setConfigs] = useState<string[]>([]);\n\n // Fetch configs using useAsync hook\n const { loading, error: fetchError } = useAsync(async () => {\n try {\n const mcpConfigs = await mcpApi.getUserDefinedMcpConfigs();\n\n setConfigs(mcpConfigs.names);\n } catch (error) {\n alertApi.post({\n message: 'Failed to fetch MCP configurations',\n display: 'transient',\n severity: 'error',\n });\n throw error;\n }\n }, [mcpApi]);\n\n const [currentConfig, setCurrentConfig] = useState<McpConfigFormData>({\n name: '',\n options: JSON.stringify({}, null, 2),\n });\n\n const [editingIndex, setEditingIndex] = useState<number | null>(null);\n const [showForm, setShowForm] = useState<boolean>(false);\n const [error, setError] = useState<string>('');\n const jsonConfigRef = useRef<HTMLTextAreaElement>(null);\n const formRef = useRef<HTMLDivElement>(null);\n\n const resetForm = useCallback(() => {\n setCurrentConfig({\n name: '',\n options: JSON.stringify({}, null, 2),\n });\n setEditingIndex(null);\n setShowForm(false);\n setError('');\n }, []);\n\n const validateConfig = (config: McpConfigFormData): boolean => {\n if (!config.name.trim()) {\n setError('Server name is required');\n return false;\n }\n\n try {\n const parsedConfig = JSON.parse(config.options);\n\n if (\n Object.keys(parsedConfig).length === 0 &&\n parsedConfig.constructor === Object\n ) {\n setError('Server configuration cannot be empty');\n return false;\n }\n } catch (e) {\n setError('Invalid JSON configuration. Please check your syntax.');\n return false;\n }\n\n // Check for duplicate names (excluding current editing item)\n const isDuplicate = configs.some(\n (c, index) => c === config.name.trim() && index !== editingIndex,\n );\n\n if (isDuplicate) {\n setError('Server name must be unique');\n return false;\n }\n\n setError('');\n return true;\n };\n\n const [{ loading: saving }, handleAddConfig] = useAsyncFn(async () => {\n if (!validateConfig(currentConfig)) return;\n\n try {\n const parsedOptions = JSON.parse(currentConfig.options);\n\n const newConfig: McpServerConfig = {\n name: currentConfig.name.trim(),\n options: parsedOptions,\n };\n\n if (editingIndex !== null) {\n // Update existing config\n await mcpApi.updateMcpConfig(newConfig);\n const updated = [...configs];\n updated[editingIndex] = newConfig.name;\n setConfigs(updated);\n } else {\n // Create new config\n await mcpApi.createMcpConfig(newConfig);\n setConfigs([...configs, newConfig.name]);\n }\n\n resetForm();\n\n alertApi.post({\n message: `MCP server \"${newConfig.name}\" ${\n editingIndex !== null ? 'updated' : 'created'\n } successfully`,\n display: 'transient',\n });\n } catch (err) {\n setError(\n `Failed to ${\n editingIndex !== null ? 'update' : 'create'\n } MCP configuration. Please try again.`,\n );\n alertApi.post({\n message: (err as Error).message,\n display: 'transient',\n severity: 'error',\n });\n }\n }, [currentConfig, editingIndex, configs, mcpApi, validateConfig, resetForm]);\n\n const handleEditConfig = (index: number) => {\n const config = configs[index];\n\n setCurrentConfig({\n name: config,\n options: JSON.stringify({}, null, 2),\n });\n setEditingIndex(index);\n setShowForm(true);\n\n // Smooth scroll to form and focus the JSON config field after a short delay\n setTimeout(() => {\n formRef.current?.scrollIntoView({\n behavior: 'smooth',\n block: 'start',\n });\n\n // Focus after scrolling is initiated\n setTimeout(() => {\n jsonConfigRef.current?.focus();\n }, 300);\n }, 100);\n };\n\n const [{ loading: deleting }, handleDeleteConfig] = useAsyncFn(\n async (index: number) => {\n const configToDelete = configs[index];\n\n try {\n await mcpApi.deleteMcpConfig(configToDelete);\n const updated = configs.filter((_, i) => i !== index);\n setConfigs(updated);\n\n if (editingIndex === index) {\n resetForm();\n }\n\n alertApi.post({\n message: `MCP server \"${configToDelete}\" deleted successfully`,\n display: 'transient',\n severity: 'info',\n });\n } catch (err) {\n alertApi.post({\n message: `Failed to delete MCP server \"${configToDelete}\". Please try again.`,\n display: 'transient',\n severity: 'error',\n });\n }\n },\n [configs, editingIndex, mcpApi, alertApi, resetForm],\n );\n\n if (loading) {\n return <Alert severity=\"info\">Loading MCP server configurations...</Alert>;\n }\n\n if (fetchError) {\n return (\n <Alert severity=\"error\">\n Failed to load MCP server configurations. Please try refreshing the\n page.\n </Alert>\n );\n }\n\n return (\n <Stack spacing={3}>\n {showForm && (\n <Paper variant=\"outlined\" sx={{ p: 3 }} ref={formRef}>\n <Typography variant=\"subtitle1\" gutterBottom>\n {editingIndex !== null ? 'Edit Server' : 'Add New Server'}\n </Typography>\n\n {error && (\n <Alert severity=\"error\" sx={{ mb: 2 }}>\n {error}\n </Alert>\n )}\n\n <Stack spacing={3}>\n <TextField\n label=\"Server Name\"\n fullWidth\n value={currentConfig.name}\n disabled={editingIndex !== null}\n onChange={e =>\n setCurrentConfig({\n ...currentConfig,\n name: e.target.value,\n })\n }\n placeholder=\"my-mcp-server\"\n required\n />\n\n <Box>\n <Typography variant=\"subtitle2\" gutterBottom>\n Server Configuration\n </Typography>\n\n {editingIndex !== null && (\n <Alert severity=\"info\" sx={{ mb: 1 }}>\n <Typography variant=\"caption\">\n Please re-enter the full JSON configuration below to update\n it. Existing configurations cannot be edited directly for\n security reasons.\n </Typography>\n </Alert>\n )}\n\n <Typography variant=\"body2\" color=\"text.secondary\" gutterBottom>\n Define your MCP server configuration as JSON. This is similar to\n how VS Code MCP extensions are configured.\n </Typography>\n <TextField\n multiline\n rows={12}\n fullWidth\n value={currentConfig.options}\n onChange={e =>\n setCurrentConfig({\n ...currentConfig,\n options: e.target.value,\n })\n }\n placeholder=\"Enter JSON configuration...\"\n inputRef={jsonConfigRef}\n sx={{\n '& .MuiInputBase-input': {\n fontFamily: 'Consolas, \"Courier New\", monospace',\n fontSize: '0.875rem',\n },\n }}\n />\n </Box>\n\n <Stack direction=\"row\" spacing={2} justifyContent=\"flex-end\">\n <Button onClick={resetForm}>Cancel</Button>\n <Button\n variant=\"contained\"\n onClick={handleAddConfig}\n disabled={!currentConfig.name.trim() || saving}\n >\n {(() => {\n if (saving) {\n return editingIndex !== null ? 'Updating...' : 'Adding...';\n }\n return editingIndex !== null ? 'Update Server' : 'Add Server';\n })()}\n </Button>\n </Stack>\n </Stack>\n </Paper>\n )}\n\n {/* Existing Configurations */}\n <Stack spacing={2}>\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n >\n <Typography variant=\"subtitle1\">Configured Servers</Typography>\n <IconButton\n onClick={() => {\n if (showForm) {\n resetForm();\n } else {\n resetForm();\n setShowForm(true);\n }\n }}\n >\n <Tooltip title={showForm ? 'Close' : 'Add'}>\n {showForm ? <CloseIcon /> : <AddIcon />}\n </Tooltip>\n </IconButton>\n </Stack>\n {configs.length === 0 ? (\n <Alert severity=\"info\">\n No MCP servers configured. Add one above to get started.\n </Alert>\n ) : (\n configs.map((config, index) => (\n <Card key={index} variant=\"outlined\">\n <CardContent>\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n >\n <Typography variant=\"subtitle2\">{config}</Typography>\n <CardActions>\n <Button\n size=\"small\"\n onClick={() => handleEditConfig(index)}\n >\n Edit\n </Button>\n <IconButton\n size=\"small\"\n color=\"error\"\n onClick={() => handleDeleteConfig(index)}\n disabled={deleting}\n >\n <DeleteIcon />\n </IconButton>\n </CardActions>\n </Stack>\n </CardContent>\n </Card>\n ))\n )}\n </Stack>\n </Stack>\n );\n};\n"],"names":["error"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Tab } from './McpServers.esm.js';
|
|
2
|
+
|
|
3
|
+
const name = "MCP Servers";
|
|
4
|
+
const title = "Model Context Protocol (MCP) Servers";
|
|
5
|
+
const description = "Configure MCP servers to extend the AI assistant with additional tools and capabilities.";
|
|
6
|
+
var McpServers = {
|
|
7
|
+
name,
|
|
8
|
+
title,
|
|
9
|
+
description,
|
|
10
|
+
Tab
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export { McpServers as default };
|
|
14
|
+
//# sourceMappingURL=index.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../../../../../src/components/SettingsModal/tabs/McpServers/index.ts"],"sourcesContent":["const name = 'MCP Servers';\nconst title = 'Model Context Protocol (MCP) Servers';\nconst description =\n 'Configure MCP servers to extend the AI assistant with additional tools and capabilities.';\n\nimport { Tab } from './McpServers';\n\nexport default {\n name,\n title,\n description,\n Tab,\n};\n"],"names":[],"mappings":";;AAAA,MAAM,IAAA,GAAO,aAAA;AACb,MAAM,KAAA,GAAQ,sCAAA;AACd,MAAM,WAAA,GACJ,0FAAA;AAIF,iBAAe;AAAA,EACb,IAAA;AAAA,EACA,KAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAA;;;;"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { useMemo, useState } from 'react';
|
|
3
|
+
import { useAsync } from 'react-use';
|
|
4
|
+
import { useApi, fetchApiRef, discoveryApiRef } from '@backstage/core-plugin-api';
|
|
5
|
+
import Alert from '@mui/material/Alert';
|
|
6
|
+
import { styled } from '@mui/material/styles';
|
|
7
|
+
import ArrowForwardIosSharpIcon from '@mui/icons-material/ArrowForwardIosSharp';
|
|
8
|
+
import Accordion$1 from '@mui/material/Accordion';
|
|
9
|
+
import AccordionSummary$1, { accordionSummaryClasses } from '@mui/material/AccordionSummary';
|
|
10
|
+
import AccordionDetails$1 from '@mui/material/AccordionDetails';
|
|
11
|
+
import Typography from '@mui/material/Typography';
|
|
12
|
+
import FormGroup from '@mui/material/FormGroup';
|
|
13
|
+
import FormControlLabel from '@mui/material/FormControlLabel';
|
|
14
|
+
import Checkbox from '@mui/material/Checkbox';
|
|
15
|
+
import Tooltip from '@mui/material/Tooltip';
|
|
16
|
+
import { useChatSettings } from '../../../../hooks/use-chat-settings.esm.js';
|
|
17
|
+
import '../../../../api/summarizer.esm.js';
|
|
18
|
+
import 'react-router-dom';
|
|
19
|
+
|
|
20
|
+
const Accordion = styled((props) => /* @__PURE__ */ jsx(Accordion$1, { disableGutters: true, elevation: 0, square: true, ...props }))(({ theme }) => ({
|
|
21
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
22
|
+
"&:not(:last-child)": {
|
|
23
|
+
borderBottom: 0
|
|
24
|
+
},
|
|
25
|
+
"&::before": {
|
|
26
|
+
display: "none"
|
|
27
|
+
}
|
|
28
|
+
}));
|
|
29
|
+
const AccordionSummary = styled((props) => /* @__PURE__ */ jsx(
|
|
30
|
+
AccordionSummary$1,
|
|
31
|
+
{
|
|
32
|
+
expandIcon: /* @__PURE__ */ jsx(ArrowForwardIosSharpIcon, { sx: { fontSize: "0.9rem", ml: 1 } }),
|
|
33
|
+
...props
|
|
34
|
+
}
|
|
35
|
+
))(({ theme }) => ({
|
|
36
|
+
backgroundColor: "rgba(0, 0, 0, .03)",
|
|
37
|
+
flexDirection: "row-reverse",
|
|
38
|
+
[`& .${accordionSummaryClasses.expandIconWrapper}.${accordionSummaryClasses.expanded}`]: {
|
|
39
|
+
transform: "rotate(90deg)"
|
|
40
|
+
},
|
|
41
|
+
[`& .${accordionSummaryClasses.content}`]: {
|
|
42
|
+
marginLeft: theme.spacing(1)
|
|
43
|
+
},
|
|
44
|
+
...theme.applyStyles("dark", {
|
|
45
|
+
backgroundColor: "rgba(255, 255, 255, .05)"
|
|
46
|
+
})
|
|
47
|
+
}));
|
|
48
|
+
const AccordionDetails = styled(AccordionDetails$1)(({ theme }) => ({
|
|
49
|
+
padding: theme.spacing(2),
|
|
50
|
+
borderTop: `1px solid ${theme.palette.divider}`
|
|
51
|
+
}));
|
|
52
|
+
const Tab = () => {
|
|
53
|
+
const fetchApi = useApi(fetchApiRef);
|
|
54
|
+
const discoveryApi = useApi(discoveryApiRef);
|
|
55
|
+
const { toolsEnabled, setToolsEnabled } = useChatSettings();
|
|
56
|
+
const {
|
|
57
|
+
loading: availableUserToolsLoading,
|
|
58
|
+
error: availableUserToolsError,
|
|
59
|
+
value: availableUserTools
|
|
60
|
+
} = useAsync(async () => {
|
|
61
|
+
const baseUrl = await discoveryApi.getBaseUrl("ai-assistant");
|
|
62
|
+
const response = await fetchApi.fetch(`${baseUrl}/chat/tools`);
|
|
63
|
+
const { tools } = await response.json();
|
|
64
|
+
return tools;
|
|
65
|
+
}, [discoveryApi, fetchApi]);
|
|
66
|
+
const providers = useMemo(() => {
|
|
67
|
+
if (availableUserToolsLoading || availableUserToolsError || !availableUserTools) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
return availableUserTools.map((tool) => tool.provider).filter((v, i, a) => a.indexOf(v) === i);
|
|
71
|
+
}, [availableUserTools, availableUserToolsError, availableUserToolsLoading]);
|
|
72
|
+
const [expanded, setExpanded] = useState(false);
|
|
73
|
+
const handleChange = (panel) => (_event, newExpanded) => {
|
|
74
|
+
setExpanded(newExpanded ? panel : false);
|
|
75
|
+
};
|
|
76
|
+
const handleProviderClick = (provider, checked) => {
|
|
77
|
+
if (!availableUserTools) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const providerTools = availableUserTools.filter((tool) => tool.provider === provider).map((tool) => ({ name: tool.name, provider: tool.provider }));
|
|
81
|
+
if (checked) {
|
|
82
|
+
const combined = [...toolsEnabled, ...providerTools];
|
|
83
|
+
const unique = Array.from(
|
|
84
|
+
new Map(combined.map((tool) => [JSON.stringify(tool), tool])).values()
|
|
85
|
+
);
|
|
86
|
+
setToolsEnabled(unique);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const providerToolStrings = new Set(
|
|
90
|
+
providerTools.map((t) => JSON.stringify(t))
|
|
91
|
+
);
|
|
92
|
+
setToolsEnabled(
|
|
93
|
+
toolsEnabled.filter(
|
|
94
|
+
(tool) => !providerToolStrings.has(JSON.stringify(tool))
|
|
95
|
+
)
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
const handleToolClick = (tool, checked) => {
|
|
99
|
+
if (checked) {
|
|
100
|
+
const toolMap = new Map(
|
|
101
|
+
[...toolsEnabled, { name: tool.name, provider: tool.provider }].map(
|
|
102
|
+
(t) => [`${t.provider}-${t.name}`, t]
|
|
103
|
+
)
|
|
104
|
+
);
|
|
105
|
+
setToolsEnabled(Array.from(toolMap.values()));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
setToolsEnabled(
|
|
109
|
+
toolsEnabled.filter(
|
|
110
|
+
(t) => !(t.name === tool.name && t.provider === tool.provider)
|
|
111
|
+
)
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
if (availableUserToolsLoading) {
|
|
115
|
+
return /* @__PURE__ */ jsx(Alert, { severity: "info", children: "Loading Tool configurations..." });
|
|
116
|
+
}
|
|
117
|
+
if (availableUserToolsError) {
|
|
118
|
+
return /* @__PURE__ */ jsx(Alert, { severity: "error", children: "Failed to load Tool configurations. Please try refreshing the page." });
|
|
119
|
+
}
|
|
120
|
+
if (!providers.length) {
|
|
121
|
+
return /* @__PURE__ */ jsx(Alert, { severity: "info", children: "No tools available." });
|
|
122
|
+
}
|
|
123
|
+
return /* @__PURE__ */ jsx("div", { children: providers.map((provider) => /* @__PURE__ */ jsxs(
|
|
124
|
+
Accordion,
|
|
125
|
+
{
|
|
126
|
+
expanded: expanded === provider,
|
|
127
|
+
onChange: handleChange(provider),
|
|
128
|
+
children: [
|
|
129
|
+
/* @__PURE__ */ jsx(AccordionSummary, { children: /* @__PURE__ */ jsx(Typography, { component: "span", children: provider }) }),
|
|
130
|
+
/* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsxs(FormGroup, { children: [
|
|
131
|
+
/* @__PURE__ */ jsx(
|
|
132
|
+
FormControlLabel,
|
|
133
|
+
{
|
|
134
|
+
control: /* @__PURE__ */ jsx(Checkbox, {}),
|
|
135
|
+
label: "All",
|
|
136
|
+
onChange: (_e, checked) => handleProviderClick(provider, checked),
|
|
137
|
+
checked: availableUserTools.filter((tool) => tool.provider === provider).every(
|
|
138
|
+
(tool) => toolsEnabled?.some(
|
|
139
|
+
(t) => t.name === tool.name && t.provider === tool.provider
|
|
140
|
+
)
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
),
|
|
144
|
+
availableUserTools.filter((tool) => tool.provider === provider).map((tool) => /* @__PURE__ */ jsx(Tooltip, { title: tool.description, arrow: true, children: /* @__PURE__ */ jsx(
|
|
145
|
+
FormControlLabel,
|
|
146
|
+
{
|
|
147
|
+
control: /* @__PURE__ */ jsx(Checkbox, {}),
|
|
148
|
+
label: tool.name,
|
|
149
|
+
checked: toolsEnabled?.some(
|
|
150
|
+
(t) => t.name === tool.name && t.provider === tool.provider
|
|
151
|
+
) || false,
|
|
152
|
+
onChange: (_e, checked) => handleToolClick(tool, checked)
|
|
153
|
+
}
|
|
154
|
+
) }, tool.name))
|
|
155
|
+
] }) })
|
|
156
|
+
]
|
|
157
|
+
},
|
|
158
|
+
provider
|
|
159
|
+
)) });
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export { Tab };
|
|
163
|
+
//# sourceMappingURL=Tools.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tools.esm.js","sources":["../../../../../src/components/SettingsModal/tabs/Tools/Tools.tsx"],"sourcesContent":["import { SyntheticEvent, useMemo, useState } from 'react';\nimport { useAsync } from 'react-use';\nimport {\n fetchApiRef,\n useApi,\n discoveryApiRef,\n} from '@backstage/core-plugin-api';\nimport {\n EnabledTool,\n UserTool,\n} from '@sweetoburrito/backstage-plugin-ai-assistant-common';\nimport Alert from '@mui/material/Alert';\n\nimport { styled } from '@mui/material/styles';\nimport ArrowForwardIosSharpIcon from '@mui/icons-material/ArrowForwardIosSharp';\nimport MuiAccordion, { AccordionProps } from '@mui/material/Accordion';\nimport MuiAccordionSummary, {\n AccordionSummaryProps,\n accordionSummaryClasses,\n} from '@mui/material/AccordionSummary';\nimport MuiAccordionDetails from '@mui/material/AccordionDetails';\nimport Typography from '@mui/material/Typography';\nimport FormGroup from '@mui/material/FormGroup';\nimport FormControlLabel from '@mui/material/FormControlLabel';\nimport Checkbox from '@mui/material/Checkbox';\nimport Tooltip from '@mui/material/Tooltip';\nimport { useChatSettings } from '../../../../hooks';\n\nconst Accordion = styled((props: AccordionProps) => (\n <MuiAccordion disableGutters elevation={0} square {...props} />\n))(({ theme }) => ({\n border: `1px solid ${theme.palette.divider}`,\n '&:not(:last-child)': {\n borderBottom: 0,\n },\n '&::before': {\n display: 'none',\n },\n}));\n\nconst AccordionSummary = styled((props: AccordionSummaryProps) => (\n <MuiAccordionSummary\n expandIcon={<ArrowForwardIosSharpIcon sx={{ fontSize: '0.9rem', ml: 1 }} />}\n {...props}\n />\n))(({ theme }) => ({\n backgroundColor: 'rgba(0, 0, 0, .03)',\n flexDirection: 'row-reverse',\n [`& .${accordionSummaryClasses.expandIconWrapper}.${accordionSummaryClasses.expanded}`]:\n {\n transform: 'rotate(90deg)',\n },\n [`& .${accordionSummaryClasses.content}`]: {\n marginLeft: theme.spacing(1),\n },\n ...theme.applyStyles('dark', {\n backgroundColor: 'rgba(255, 255, 255, .05)',\n }),\n}));\n\nconst AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({\n padding: theme.spacing(2),\n borderTop: `1px solid ${theme.palette.divider}`,\n}));\n\nexport const Tab = () => {\n const fetchApi = useApi(fetchApiRef);\n const discoveryApi = useApi(discoveryApiRef);\n const { toolsEnabled, setToolsEnabled } = useChatSettings();\n\n const {\n loading: availableUserToolsLoading,\n error: availableUserToolsError,\n value: availableUserTools,\n } = useAsync(async () => {\n const baseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n const response = await fetchApi.fetch(`${baseUrl}/chat/tools`);\n\n const { tools } = (await response.json()) as {\n tools: UserTool[];\n };\n\n return tools;\n }, [discoveryApi, fetchApi]);\n\n const providers = useMemo(() => {\n if (\n availableUserToolsLoading ||\n availableUserToolsError ||\n !availableUserTools\n ) {\n return [];\n }\n return availableUserTools\n .map(tool => tool.provider)\n .filter((v, i, a) => a.indexOf(v) === i);\n }, [availableUserTools, availableUserToolsError, availableUserToolsLoading]);\n\n const [expanded, setExpanded] = useState<string | false>(false);\n\n const handleChange =\n (panel: string) => (_event: SyntheticEvent, newExpanded: boolean) => {\n setExpanded(newExpanded ? panel : false);\n };\n\n const handleProviderClick = (provider: string, checked: boolean) => {\n if (!availableUserTools) {\n return;\n }\n const providerTools: EnabledTool[] = availableUserTools\n .filter(tool => tool.provider === provider)\n .map(tool => ({ name: tool.name, provider: tool.provider }));\n\n if (checked) {\n const combined = [...toolsEnabled, ...providerTools];\n const unique = Array.from(\n new Map(combined.map(tool => [JSON.stringify(tool), tool])).values(),\n );\n setToolsEnabled(unique);\n return;\n }\n\n const providerToolStrings = new Set(\n providerTools.map(t => JSON.stringify(t)),\n );\n setToolsEnabled(\n toolsEnabled.filter(\n tool => !providerToolStrings.has(JSON.stringify(tool)),\n ),\n );\n };\n\n const handleToolClick = (tool: UserTool, checked: boolean) => {\n if (checked) {\n const toolMap = new Map(\n [...toolsEnabled, { name: tool.name, provider: tool.provider }].map(\n t => [`${t.provider}-${t.name}`, t],\n ),\n );\n setToolsEnabled(Array.from(toolMap.values()));\n return;\n }\n\n setToolsEnabled(\n toolsEnabled.filter(\n t => !(t.name === tool.name && t.provider === tool.provider),\n ),\n );\n };\n\n if (availableUserToolsLoading) {\n return <Alert severity=\"info\">Loading Tool configurations...</Alert>;\n }\n\n if (availableUserToolsError) {\n return (\n <Alert severity=\"error\">\n Failed to load Tool configurations. Please try refreshing the page.\n </Alert>\n );\n }\n\n if (!providers.length) {\n return <Alert severity=\"info\">No tools available.</Alert>;\n }\n\n return (\n <div>\n {providers.map(provider => (\n <Accordion\n key={provider}\n expanded={expanded === provider}\n onChange={handleChange(provider)}\n >\n <AccordionSummary>\n <Typography component=\"span\">{provider}</Typography>\n </AccordionSummary>\n <AccordionDetails>\n <FormGroup>\n <FormControlLabel\n control={<Checkbox />}\n label=\"All\"\n onChange={(_e, checked) =>\n handleProviderClick(provider, checked)\n }\n checked={availableUserTools!\n .filter(tool => tool.provider === provider)\n .every(tool =>\n toolsEnabled?.some(\n t => t.name === tool.name && t.provider === tool.provider,\n ),\n )}\n />\n {availableUserTools!\n .filter(tool => tool.provider === provider)\n .map(tool => (\n <Tooltip title={tool.description} key={tool.name} arrow>\n <FormControlLabel\n control={<Checkbox />}\n label={tool.name}\n checked={\n toolsEnabled?.some(\n t =>\n t.name === tool.name &&\n t.provider === tool.provider,\n ) || false\n }\n onChange={(_e, checked) => handleToolClick(tool, checked)}\n />\n </Tooltip>\n ))}\n </FormGroup>\n </AccordionDetails>\n </Accordion>\n ))}\n </div>\n );\n};\n"],"names":["MuiAccordion","MuiAccordionSummary","MuiAccordionDetails"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Tab } from './Tools.esm.js';
|
|
2
|
+
|
|
3
|
+
const name = "Tools";
|
|
4
|
+
const title = "Tools";
|
|
5
|
+
const description = "Configure the tools used by the AI Assistant when responding to your queries.";
|
|
6
|
+
var Tools = {
|
|
7
|
+
name,
|
|
8
|
+
title,
|
|
9
|
+
description,
|
|
10
|
+
Tab
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export { Tools as default };
|
|
14
|
+
//# sourceMappingURL=index.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../../../../../src/components/SettingsModal/tabs/Tools/index.ts"],"sourcesContent":["const name = 'Tools';\nconst title = 'Tools';\nconst description =\n 'Configure the tools used by the AI Assistant when responding to your queries.';\n\nimport { Tab } from './Tools';\n\nexport default {\n name,\n title,\n description,\n Tab,\n};\n"],"names":[],"mappings":";;AAAA,MAAM,IAAA,GAAO,OAAA;AACb,MAAM,KAAA,GAAQ,OAAA;AACd,MAAM,WAAA,GACJ,+EAAA;AAIF,YAAe;AAAA,EACb,IAAA;AAAA,EACA,KAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAA;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../../../../src/components/SettingsModal/tabs/index.ts"],"sourcesContent":["import Tools from './Tools';\nimport McpServers from './McpServers';\n\nexport default [McpServers, Tools];\n"],"names":[],"mappings":";;;AAGA,WAAe,CAAC,YAAY,KAAK,CAAA;;;;"}
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { create } from 'zustand';
|
|
2
|
+
import { useApi, fetchApiRef, discoveryApiRef } from '@backstage/core-plugin-api';
|
|
3
|
+
import { useCallback, useEffect } from 'react';
|
|
2
4
|
|
|
3
5
|
const useChatModalSettingsStore = create((set) => ({
|
|
4
6
|
modalVisible: true,
|
|
5
7
|
setModalVisible: (visible) => set({ modalVisible: visible }),
|
|
6
8
|
summaryEnabled: false,
|
|
7
|
-
setSummaryEnabled: (summaryEnabled) => set({ summaryEnabled })
|
|
9
|
+
setSummaryEnabled: (summaryEnabled) => set({ summaryEnabled }),
|
|
10
|
+
toolsEnabled: [],
|
|
11
|
+
setToolsEnabled: (toolsEnabled) => set({ toolsEnabled })
|
|
8
12
|
}));
|
|
9
13
|
const useChatSettings = () => {
|
|
14
|
+
const fetchApi = useApi(fetchApiRef);
|
|
15
|
+
const discoveryApi = useApi(discoveryApiRef);
|
|
10
16
|
const modalVisible = useChatModalSettingsStore((state) => state.modalVisible);
|
|
11
17
|
const setModalVisible = useChatModalSettingsStore(
|
|
12
18
|
(state) => state.setModalVisible
|
|
@@ -17,7 +23,48 @@ const useChatSettings = () => {
|
|
|
17
23
|
const setSummaryEnabled = useChatModalSettingsStore(
|
|
18
24
|
(state) => state.setSummaryEnabled
|
|
19
25
|
);
|
|
20
|
-
|
|
26
|
+
const toolsEnabled = useChatModalSettingsStore((state) => state.toolsEnabled);
|
|
27
|
+
const setToolsEnabledState = useChatModalSettingsStore(
|
|
28
|
+
(state) => state.setToolsEnabled
|
|
29
|
+
);
|
|
30
|
+
const setToolsEnabled = useCallback(
|
|
31
|
+
async (tools) => {
|
|
32
|
+
setToolsEnabledState(tools);
|
|
33
|
+
const baseUrl = await discoveryApi.getBaseUrl("ai-assistant");
|
|
34
|
+
await fetchApi.fetch(`${baseUrl}/settings`, {
|
|
35
|
+
method: "PATCH",
|
|
36
|
+
body: JSON.stringify({ type: "user-tools", settings: { tools } }),
|
|
37
|
+
headers: {
|
|
38
|
+
"Content-Type": "application/json"
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
[discoveryApi, fetchApi, setToolsEnabledState]
|
|
43
|
+
);
|
|
44
|
+
const fetchUserEnabledTools = useCallback(async () => {
|
|
45
|
+
const baseUrl = await discoveryApi.getBaseUrl("ai-assistant");
|
|
46
|
+
const query = new URLSearchParams({
|
|
47
|
+
type: "user-tools"
|
|
48
|
+
});
|
|
49
|
+
const response = await fetchApi.fetch(
|
|
50
|
+
`${baseUrl}/settings?${query.toString()}`
|
|
51
|
+
);
|
|
52
|
+
const {
|
|
53
|
+
settings: { tools }
|
|
54
|
+
} = await response.json();
|
|
55
|
+
setToolsEnabledState(tools ?? []);
|
|
56
|
+
}, [discoveryApi, fetchApi, setToolsEnabledState]);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
fetchUserEnabledTools();
|
|
59
|
+
}, [fetchUserEnabledTools]);
|
|
60
|
+
return {
|
|
61
|
+
modalVisible,
|
|
62
|
+
setModalVisible,
|
|
63
|
+
summaryEnabled,
|
|
64
|
+
setSummaryEnabled,
|
|
65
|
+
toolsEnabled,
|
|
66
|
+
setToolsEnabled
|
|
67
|
+
};
|
|
21
68
|
};
|
|
22
69
|
|
|
23
70
|
export { useChatSettings };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-chat-settings.esm.js","sources":["../../src/hooks/use-chat-settings.ts"],"sourcesContent":["import { create } from 'zustand';\n\ninterface ChatModalSettings {\n modalVisible: boolean;\n setModalVisible: (visible: boolean) => void;\n summaryEnabled: boolean;\n setSummaryEnabled: (enable: boolean) => void;\n}\n\nconst useChatModalSettingsStore = create<ChatModalSettings>(set => ({\n modalVisible: true,\n setModalVisible: (visible: boolean) => set({ modalVisible: visible }),\n summaryEnabled: false,\n setSummaryEnabled: (summaryEnabled: boolean) => set({ summaryEnabled }),\n}));\n\nexport const useChatSettings = () => {\n const modalVisible = useChatModalSettingsStore(state => state.modalVisible);\n const setModalVisible = useChatModalSettingsStore(\n state => state.setModalVisible,\n );\n\n const summaryEnabled = useChatModalSettingsStore(\n state => state.summaryEnabled,\n );\n const setSummaryEnabled = useChatModalSettingsStore(\n state => state.setSummaryEnabled,\n );\n\n
|
|
1
|
+
{"version":3,"file":"use-chat-settings.esm.js","sources":["../../src/hooks/use-chat-settings.ts"],"sourcesContent":["import { create } from 'zustand';\nimport {\n fetchApiRef,\n useApi,\n discoveryApiRef,\n} from '@backstage/core-plugin-api';\nimport { useCallback, useEffect } from 'react';\nimport { EnabledTool } from '@sweetoburrito/backstage-plugin-ai-assistant-common';\n\ninterface ChatModalSettings {\n modalVisible: boolean;\n setModalVisible: (visible: boolean) => void;\n summaryEnabled: boolean;\n setSummaryEnabled: (enable: boolean) => void;\n toolsEnabled: EnabledTool[];\n setToolsEnabled: (tools: EnabledTool[]) => void;\n}\n\nconst useChatModalSettingsStore = create<ChatModalSettings>(set => ({\n modalVisible: true,\n setModalVisible: (visible: boolean) => set({ modalVisible: visible }),\n summaryEnabled: false,\n setSummaryEnabled: (summaryEnabled: boolean) => set({ summaryEnabled }),\n toolsEnabled: [],\n setToolsEnabled: (toolsEnabled: EnabledTool[]) => set({ toolsEnabled }),\n}));\n\nexport const useChatSettings = () => {\n const fetchApi = useApi(fetchApiRef);\n const discoveryApi = useApi(discoveryApiRef);\n\n const modalVisible = useChatModalSettingsStore(state => state.modalVisible);\n const setModalVisible = useChatModalSettingsStore(\n state => state.setModalVisible,\n );\n\n const summaryEnabled = useChatModalSettingsStore(\n state => state.summaryEnabled,\n );\n const setSummaryEnabled = useChatModalSettingsStore(\n state => state.setSummaryEnabled,\n );\n\n const toolsEnabled = useChatModalSettingsStore(state => state.toolsEnabled);\n\n const setToolsEnabledState = useChatModalSettingsStore(\n state => state.setToolsEnabled,\n );\n\n const setToolsEnabled = useCallback(\n async (tools: EnabledTool[]) => {\n setToolsEnabledState(tools);\n const baseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n await fetchApi.fetch(`${baseUrl}/settings`, {\n method: 'PATCH',\n body: JSON.stringify({ type: 'user-tools', settings: { tools } }),\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n },\n [discoveryApi, fetchApi, setToolsEnabledState],\n );\n\n const fetchUserEnabledTools = useCallback(async () => {\n const baseUrl = await discoveryApi.getBaseUrl('ai-assistant');\n\n const query = new URLSearchParams({\n type: 'user-tools',\n });\n\n const response = await fetchApi.fetch(\n `${baseUrl}/settings?${query.toString()}`,\n );\n\n const {\n settings: { tools },\n } = (await response.json()) as {\n settings: { tools?: EnabledTool[] };\n };\n\n setToolsEnabledState(tools ?? []);\n }, [discoveryApi, fetchApi, setToolsEnabledState]);\n\n useEffect(() => {\n fetchUserEnabledTools();\n }, [fetchUserEnabledTools]);\n\n return {\n modalVisible,\n setModalVisible,\n summaryEnabled,\n setSummaryEnabled,\n toolsEnabled,\n setToolsEnabled,\n };\n};\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sweetoburrito/backstage-plugin-ai-assistant",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "dist/index.esm.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@backstage/theme": "backstage:^",
|
|
38
38
|
"@mui/icons-material": "^6.5.0",
|
|
39
39
|
"@mui/material": "^6.5.0",
|
|
40
|
-
"@sweetoburrito/backstage-plugin-ai-assistant-common": "^0.
|
|
40
|
+
"@sweetoburrito/backstage-plugin-ai-assistant-common": "^0.7.0",
|
|
41
41
|
"react-markdown": "^10.1.0",
|
|
42
42
|
"react-use": "^17.2.4",
|
|
43
43
|
"tss-react": "^4.9.19",
|
|
@@ -51,7 +51,10 @@
|
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@backstage/cli": "backstage:^",
|
|
53
53
|
"@backstage/core-app-api": "backstage:^",
|
|
54
|
-
"@backstage/dev-utils": "backstage:^"
|
|
54
|
+
"@backstage/dev-utils": "backstage:^",
|
|
55
|
+
"@backstage/plugin-api-docs": "backstage:^",
|
|
56
|
+
"@backstage/plugin-catalog": "backstage:^",
|
|
57
|
+
"@backstage/plugin-org": "backstage:^"
|
|
55
58
|
},
|
|
56
59
|
"files": [
|
|
57
60
|
"dist"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"McpServersTab.esm.js","sources":["../../../src/components/Conversation/McpServersTab.tsx"],"sourcesContent":["import { useState, useCallback, useRef } from 'react';\nimport { useApi, alertApiRef } from '@backstage/core-plugin-api';\nimport { useAsync, useAsyncFn } from 'react-use';\nimport Box from '@mui/material/Box';\nimport TextField from '@mui/material/TextField';\nimport Typography from '@mui/material/Typography';\nimport Stack from '@mui/material/Stack';\nimport Paper from '@mui/material/Paper';\nimport IconButton from '@mui/material/IconButton';\nimport Divider from '@mui/material/Divider';\nimport Card from '@mui/material/Card';\nimport CardContent from '@mui/material/CardContent';\nimport CardActions from '@mui/material/CardActions';\nimport Alert from '@mui/material/Alert';\nimport Button from '@mui/material/Button';\nimport DeleteIcon from '@mui/icons-material/Delete';\nimport CloseIcon from '@mui/icons-material/Close';\nimport AddIcon from '@mui/icons-material/Add';\nimport Tooltip from '@mui/material/Tooltip';\nimport { McpServerConfig } from '@sweetoburrito/backstage-plugin-ai-assistant-common';\nimport { mcpApiRef } from '../../api/mcp';\n\ninterface McpConfigFormData {\n name: string;\n options: string;\n}\n\ninterface McpServersTabProps {}\n\nexport const McpServersTab: React.FC<McpServersTabProps> = () => {\n const mcpApi = useApi(mcpApiRef);\n const alertApi = useApi(alertApiRef);\n\n const [configs, setConfigs] = useState<string[]>([]);\n\n // Fetch configs using useAsync hook\n const { loading, error: fetchError } = useAsync(async () => {\n try {\n const mcpConfigs = await mcpApi.getUserDefinedMcpConfigs();\n\n setConfigs(mcpConfigs.names);\n } catch (error) {\n alertApi.post({\n message: 'Failed to fetch MCP configurations',\n display: 'transient',\n severity: 'error',\n });\n throw error;\n }\n }, [mcpApi]);\n\n const [currentConfig, setCurrentConfig] = useState<McpConfigFormData>({\n name: '',\n options: JSON.stringify({}, null, 2),\n });\n\n const [editingIndex, setEditingIndex] = useState<number | null>(null);\n const [showForm, setShowForm] = useState<boolean>(false);\n const [error, setError] = useState<string>('');\n const jsonConfigRef = useRef<HTMLTextAreaElement>(null);\n const formRef = useRef<HTMLDivElement>(null);\n\n const resetForm = useCallback(() => {\n setCurrentConfig({\n name: '',\n options: JSON.stringify({}, null, 2),\n });\n setEditingIndex(null);\n setShowForm(false);\n setError('');\n }, []);\n\n const validateConfig = (config: McpConfigFormData): boolean => {\n if (!config.name.trim()) {\n setError('Server name is required');\n return false;\n }\n\n try {\n const parsedConfig = JSON.parse(config.options);\n\n if (\n Object.keys(parsedConfig).length === 0 &&\n parsedConfig.constructor === Object\n ) {\n setError('Server configuration cannot be empty');\n return false;\n }\n } catch (e) {\n setError('Invalid JSON configuration. Please check your syntax.');\n return false;\n }\n\n // Check for duplicate names (excluding current editing item)\n const isDuplicate = configs.some(\n (c, index) => c === config.name.trim() && index !== editingIndex,\n );\n\n if (isDuplicate) {\n setError('Server name must be unique');\n return false;\n }\n\n setError('');\n return true;\n };\n\n const [{ loading: saving }, handleAddConfig] = useAsyncFn(async () => {\n if (!validateConfig(currentConfig)) return;\n\n try {\n const parsedOptions = JSON.parse(currentConfig.options);\n\n const newConfig: McpServerConfig = {\n name: currentConfig.name.trim(),\n options: parsedOptions,\n };\n\n if (editingIndex !== null) {\n // Update existing config\n await mcpApi.updateMcpConfig(newConfig);\n const updated = [...configs];\n updated[editingIndex] = newConfig.name;\n setConfigs(updated);\n } else {\n // Create new config\n await mcpApi.createMcpConfig(newConfig);\n setConfigs([...configs, newConfig.name]);\n }\n\n resetForm();\n\n alertApi.post({\n message: `MCP server \"${newConfig.name}\" ${\n editingIndex !== null ? 'updated' : 'created'\n } successfully`,\n display: 'transient',\n });\n } catch (err) {\n setError(\n `Failed to ${\n editingIndex !== null ? 'update' : 'create'\n } MCP configuration. Please try again.`,\n );\n alertApi.post({\n message: (err as Error).message,\n display: 'transient',\n severity: 'error',\n });\n }\n }, [currentConfig, editingIndex, configs, mcpApi, validateConfig, resetForm]);\n\n const handleEditConfig = (index: number) => {\n const config = configs[index];\n\n setCurrentConfig({\n name: config,\n options: JSON.stringify({}, null, 2),\n });\n setEditingIndex(index);\n setShowForm(true);\n\n // Smooth scroll to form and focus the JSON config field after a short delay\n setTimeout(() => {\n formRef.current?.scrollIntoView({\n behavior: 'smooth',\n block: 'start',\n });\n\n // Focus after scrolling is initiated\n setTimeout(() => {\n jsonConfigRef.current?.focus();\n }, 300);\n }, 100);\n };\n\n const [{ loading: deleting }, handleDeleteConfig] = useAsyncFn(\n async (index: number) => {\n const configToDelete = configs[index];\n\n try {\n await mcpApi.deleteMcpConfig(configToDelete);\n const updated = configs.filter((_, i) => i !== index);\n setConfigs(updated);\n\n if (editingIndex === index) {\n resetForm();\n }\n\n alertApi.post({\n message: `MCP server \"${configToDelete}\" deleted successfully`,\n display: 'transient',\n severity: 'info',\n });\n } catch (err) {\n alertApi.post({\n message: `Failed to delete MCP server \"${configToDelete}\". Please try again.`,\n display: 'transient',\n severity: 'error',\n });\n }\n },\n [configs, editingIndex, mcpApi, alertApi, resetForm],\n );\n\n if (loading) {\n return (\n <Stack spacing={3}>\n <Typography variant=\"h6\">\n Model Context Protocol (MCP) Servers\n </Typography>\n <Alert severity=\"info\">Loading MCP server configurations...</Alert>\n </Stack>\n );\n }\n\n if (fetchError) {\n return (\n <Stack spacing={3}>\n <Typography variant=\"h6\">\n Model Context Protocol (MCP) Servers\n </Typography>\n <Alert severity=\"error\">\n Failed to load MCP server configurations. Please try refreshing the\n page.\n </Alert>\n </Stack>\n );\n }\n\n return (\n <Stack spacing={3}>\n <Stack direction=\"row\" justifyContent=\"space-between\" alignItems=\"center\">\n <Box>\n <Typography variant=\"h6\">\n Model Context Protocol (MCP) Servers\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n Configure MCP servers to extend the AI assistant with additional\n tools and capabilities.\n </Typography>\n </Box>\n </Stack>\n\n {showForm && (\n <Paper variant=\"outlined\" sx={{ p: 3 }} ref={formRef}>\n <Typography variant=\"subtitle1\" gutterBottom>\n {editingIndex !== null ? 'Edit Server' : 'Add New Server'}\n </Typography>\n\n {error && (\n <Alert severity=\"error\" sx={{ mb: 2 }}>\n {error}\n </Alert>\n )}\n\n <Stack spacing={3}>\n <TextField\n label=\"Server Name\"\n fullWidth\n value={currentConfig.name}\n disabled={editingIndex !== null}\n onChange={e =>\n setCurrentConfig({\n ...currentConfig,\n name: e.target.value,\n })\n }\n placeholder=\"my-mcp-server\"\n required\n />\n\n <Box>\n <Typography variant=\"subtitle2\" gutterBottom>\n Server Configuration\n </Typography>\n\n {editingIndex !== null && (\n <Alert severity=\"info\" sx={{ mb: 1 }}>\n <Typography variant=\"caption\">\n Please re-enter the full JSON configuration below to update\n it. Existing configurations cannot be edited directly for\n security reasons.\n </Typography>\n </Alert>\n )}\n\n <Typography variant=\"body2\" color=\"text.secondary\" gutterBottom>\n Define your MCP server configuration as JSON. This is similar to\n how VS Code MCP extensions are configured.\n </Typography>\n <TextField\n multiline\n rows={12}\n fullWidth\n value={currentConfig.options}\n onChange={e =>\n setCurrentConfig({\n ...currentConfig,\n options: e.target.value,\n })\n }\n placeholder=\"Enter JSON configuration...\"\n inputRef={jsonConfigRef}\n sx={{\n '& .MuiInputBase-input': {\n fontFamily: 'Consolas, \"Courier New\", monospace',\n fontSize: '0.875rem',\n },\n }}\n />\n </Box>\n\n <Stack direction=\"row\" spacing={2} justifyContent=\"flex-end\">\n <Button onClick={resetForm}>Cancel</Button>\n <Button\n variant=\"contained\"\n onClick={handleAddConfig}\n disabled={!currentConfig.name.trim() || saving}\n >\n {(() => {\n if (saving) {\n return editingIndex !== null ? 'Updating...' : 'Adding...';\n }\n return editingIndex !== null ? 'Update Server' : 'Add Server';\n })()}\n </Button>\n </Stack>\n </Stack>\n </Paper>\n )}\n\n <Divider />\n\n {/* Existing Configurations */}\n <Stack spacing={2}>\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n >\n <Typography variant=\"subtitle1\">Configured Servers</Typography>\n <IconButton\n onClick={() => {\n if (showForm) {\n resetForm();\n } else {\n resetForm();\n setShowForm(true);\n }\n }}\n >\n <Tooltip title={showForm ? 'Close' : 'Add'}>\n {showForm ? <CloseIcon /> : <AddIcon />}\n </Tooltip>\n </IconButton>\n </Stack>\n {configs.length === 0 ? (\n <Alert severity=\"info\">\n No MCP servers configured. Add one above to get started.\n </Alert>\n ) : (\n configs.map((config, index) => (\n <Card key={index} variant=\"outlined\">\n <CardContent>\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n >\n <Typography variant=\"subtitle2\">{config}</Typography>\n <CardActions>\n <Button\n size=\"small\"\n onClick={() => handleEditConfig(index)}\n >\n Edit\n </Button>\n <IconButton\n size=\"small\"\n color=\"error\"\n onClick={() => handleDeleteConfig(index)}\n disabled={deleting}\n >\n <DeleteIcon />\n </IconButton>\n </CardActions>\n </Stack>\n </CardContent>\n </Card>\n ))\n )}\n </Stack>\n </Stack>\n );\n};\n"],"names":["error"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SettingsModal.esm.js","sources":["../../../src/components/Conversation/SettingsModal.tsx"],"sourcesContent":["import { useState } from 'react';\nimport Dialog from '@mui/material/Dialog';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogActions from '@mui/material/DialogActions';\nimport Button from '@mui/material/Button';\nimport Tab from '@mui/material/Tab';\nimport Tabs from '@mui/material/Tabs';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Stack from '@mui/material/Stack';\nimport IconButton from '@mui/material/IconButton';\nimport CloseIcon from '@mui/icons-material/Close';\nimport SettingsIcon from '@mui/icons-material/Settings';\nimport { McpServersTab } from './McpServersTab';\n\ninterface TabPanelProps {\n children?: React.ReactNode;\n index: number;\n value: number;\n}\n\nfunction TabPanel(props: TabPanelProps) {\n const { children, value, index, ...other } = props;\n\n return (\n <Box\n role=\"tabpanel\"\n hidden={value !== index}\n id={`vertical-tabpanel-${index}`}\n aria-labelledby={`vertical-tab-${index}`}\n {...other}\n sx={{\n width: '100%',\n height: '100%',\n overflow: 'auto', // Allow content to scroll independently\n }}\n >\n {value === index && <Box sx={{ p: 3 }}>{children}</Box>}\n </Box>\n );\n}\n\ninterface SettingsModalProps {\n open: boolean;\n onClose: () => void;\n}\n\nexport const SettingsModal: React.FC<SettingsModalProps> = ({\n open,\n onClose,\n}) => {\n const [selectedTab, setSelectedTab] = useState(0);\n\n const handleTabChange = (_: React.SyntheticEvent, newValue: number) => {\n setSelectedTab(newValue);\n };\n\n return (\n <Dialog\n open={open}\n onClose={onClose}\n maxWidth=\"lg\"\n fullWidth\n PaperProps={{\n sx: { height: '80vh', maxHeight: 800 },\n }}\n >\n <DialogTitle>\n <Stack\n direction=\"row\"\n alignItems=\"center\"\n justifyContent=\"space-between\"\n >\n <Stack direction=\"row\" alignItems=\"center\" spacing={1}>\n <SettingsIcon />\n <Typography variant=\"h6\">Settings</Typography>\n </Stack>\n <IconButton onClick={onClose} size=\"small\">\n <CloseIcon />\n </IconButton>\n </Stack>\n </DialogTitle>\n\n <DialogContent dividers sx={{ p: 0 }}>\n <Box\n sx={{\n flexGrow: 1,\n bgcolor: 'background.paper',\n display: 'flex',\n height: '100%',\n }}\n >\n <Box\n sx={{\n borderRight: 1,\n borderColor: 'divider',\n minWidth: 200,\n flexShrink: 0, // Prevent tabs from shrinking\n }}\n >\n <Tabs\n orientation=\"vertical\"\n variant=\"standard\"\n value={selectedTab}\n onChange={handleTabChange}\n sx={{\n pl: 2, // Add left padding to the tabs container\n '& .MuiTab-root': {\n alignItems: 'flex-start',\n textAlign: 'left',\n minHeight: 48,\n pl: 1, // Add additional left padding to individual tabs\n },\n }}\n >\n <Tab label=\"MCP Servers\" />\n </Tabs>\n </Box>\n\n <TabPanel value={selectedTab} index={0}>\n <McpServersTab />\n </TabPanel>\n\n <TabPanel value={selectedTab} index={1}>\n <Typography variant=\"h6\">Other Settings</Typography>\n <Typography color=\"text.secondary\" sx={{ mt: 1 }}>\n Additional configuration options will be available here.\n </Typography>\n </TabPanel>\n\n <TabPanel value={selectedTab} index={2}>\n <Typography variant=\"h6\">Advanced Settings</Typography>\n <Typography color=\"text.secondary\" sx={{ mt: 1 }}>\n Advanced configuration options will be available here.\n </Typography>\n </TabPanel>\n </Box>\n </DialogContent>\n\n <DialogActions>\n <Button onClick={onClose}>Close</Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":[],"mappings":"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"}
|