@stack-spot/ai-chat-widget 0.11.0 → 1.1.0
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/CHANGELOG.md +9 -0
- package/dist/StackspotAIWidget.d.ts +20 -0
- package/dist/StackspotAIWidget.d.ts.map +1 -1
- package/dist/StackspotAIWidget.js +7 -3
- package/dist/StackspotAIWidget.js.map +1 -1
- package/dist/chat-interceptors/CustomInputs.d.ts +4 -1
- package/dist/chat-interceptors/CustomInputs.d.ts.map +1 -1
- package/dist/chat-interceptors/CustomInputs.js +10 -1
- package/dist/chat-interceptors/CustomInputs.js.map +1 -1
- package/dist/chat-interceptors/quick-command-questions.d.ts +10 -0
- package/dist/chat-interceptors/quick-command-questions.d.ts.map +1 -1
- package/dist/chat-interceptors/quick-command-questions.js +12 -2
- package/dist/chat-interceptors/quick-command-questions.js.map +1 -1
- package/dist/chat-interceptors/quick-commands.d.ts +11 -0
- package/dist/chat-interceptors/quick-commands.d.ts.map +1 -1
- package/dist/chat-interceptors/quick-commands.js +65 -25
- package/dist/chat-interceptors/quick-commands.js.map +1 -1
- package/dist/chat-interceptors/send-message.d.ts +10 -0
- package/dist/chat-interceptors/send-message.d.ts.map +1 -1
- package/dist/chat-interceptors/send-message.js +32 -10
- package/dist/chat-interceptors/send-message.js.map +1 -1
- package/dist/components/Accordion.d.ts +10 -0
- package/dist/components/Accordion.d.ts.map +1 -1
- package/dist/components/Accordion.js +3 -0
- package/dist/components/Accordion.js.map +1 -1
- package/dist/components/AdaptiveTextArea.d.ts +13 -1
- package/dist/components/AdaptiveTextArea.d.ts.map +1 -1
- package/dist/components/AdaptiveTextArea.js +9 -4
- package/dist/components/AdaptiveTextArea.js.map +1 -1
- package/dist/components/AutoFocus.d.ts +23 -0
- package/dist/components/AutoFocus.d.ts.map +1 -0
- package/dist/components/AutoFocus.js +16 -0
- package/dist/components/AutoFocus.js.map +1 -0
- package/dist/components/Fading.d.ts +32 -0
- package/dist/components/Fading.d.ts.map +1 -0
- package/dist/components/Fading.js +33 -0
- package/dist/components/Fading.js.map +1 -0
- package/dist/components/FadingOverflow.d.ts +25 -0
- package/dist/components/FadingOverflow.d.ts.map +1 -1
- package/dist/components/FadingOverflow.js +11 -2
- package/dist/components/FadingOverflow.js.map +1 -1
- package/dist/components/FallbackBoundary/ErrorBoundary.d.ts +3 -0
- package/dist/components/FallbackBoundary/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/FallbackBoundary/ErrorBoundary.js +18 -4
- package/dist/components/FallbackBoundary/ErrorBoundary.js.map +1 -1
- package/dist/components/FallbackBoundary/Loading.js +1 -1
- package/dist/components/FallbackBoundary/Loading.js.map +1 -1
- package/dist/components/FallbackBoundary/index.d.ts +12 -1
- package/dist/components/FallbackBoundary/index.d.ts.map +1 -1
- package/dist/components/FallbackBoundary/index.js +1 -1
- package/dist/components/FallbackBoundary/index.js.map +1 -1
- package/dist/components/HistoryList.d.ts +15 -0
- package/dist/components/HistoryList.d.ts.map +1 -1
- package/dist/components/HistoryList.js +3 -1
- package/dist/components/HistoryList.js.map +1 -1
- package/dist/components/IconInput.d.ts +3 -0
- package/dist/components/IconInput.d.ts.map +1 -1
- package/dist/components/IconInput.js +3 -0
- package/dist/components/IconInput.js.map +1 -1
- package/dist/components/OverlayMenu.d.ts +12 -1
- package/dist/components/OverlayMenu.d.ts.map +1 -1
- package/dist/components/OverlayMenu.js +31 -10
- package/dist/components/OverlayMenu.js.map +1 -1
- package/dist/components/ProgressBar.d.ts +22 -0
- package/dist/components/ProgressBar.d.ts.map +1 -1
- package/dist/components/ProgressBar.js +5 -0
- package/dist/components/ProgressBar.js.map +1 -1
- package/dist/components/QuickStartButton.d.ts.map +1 -1
- package/dist/components/QuickStartButton.js +3 -0
- package/dist/components/QuickStartButton.js.map +1 -1
- package/dist/components/RightPanelForm.d.ts +3 -0
- package/dist/components/RightPanelForm.d.ts.map +1 -1
- package/dist/components/RightPanelForm.js +8 -4
- package/dist/components/RightPanelForm.js.map +1 -1
- package/dist/components/RightPanelTabs.d.ts +3 -0
- package/dist/components/RightPanelTabs.d.ts.map +1 -1
- package/dist/components/RightPanelTabs.js +3 -0
- package/dist/components/RightPanelTabs.js.map +1 -1
- package/dist/components/TabManager.d.ts +6 -0
- package/dist/components/TabManager.d.ts.map +1 -1
- package/dist/components/TabManager.js +8 -0
- package/dist/components/TabManager.js.map +1 -1
- package/dist/components/Tooltip/Tooltip.d.ts +26 -1
- package/dist/components/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/components/Tooltip/Tooltip.js +18 -5
- package/dist/components/Tooltip/Tooltip.js.map +1 -1
- package/dist/components/Tooltip/TooltipAPI.d.ts +18 -2
- package/dist/components/Tooltip/TooltipAPI.d.ts.map +1 -1
- package/dist/components/Tooltip/TooltipAPI.js +68 -51
- package/dist/components/Tooltip/TooltipAPI.js.map +1 -1
- package/dist/components/Tooltip/types.d.ts +13 -0
- package/dist/components/Tooltip/types.d.ts.map +1 -1
- package/dist/components/form/DescribedCheckboxGroup.d.ts +4 -0
- package/dist/components/form/DescribedCheckboxGroup.d.ts.map +1 -1
- package/dist/components/form/DescribedCheckboxGroup.js +4 -0
- package/dist/components/form/DescribedCheckboxGroup.js.map +1 -1
- package/dist/components/form/DescribedRadioGroup.d.ts +4 -0
- package/dist/components/form/DescribedRadioGroup.d.ts.map +1 -1
- package/dist/components/form/DescribedRadioGroup.js +4 -0
- package/dist/components/form/DescribedRadioGroup.js.map +1 -1
- package/dist/components/form/types.d.ts +34 -0
- package/dist/components/form/types.d.ts.map +1 -1
- package/dist/context/AIWidgetProvider.d.ts +19 -0
- package/dist/context/AIWidgetProvider.d.ts.map +1 -1
- package/dist/context/AIWidgetProvider.js +19 -0
- package/dist/context/AIWidgetProvider.js.map +1 -1
- package/dist/context/hooks.d.ts +56 -0
- package/dist/context/hooks.d.ts.map +1 -1
- package/dist/context/hooks.js +56 -1
- package/dist/context/hooks.js.map +1 -1
- package/dist/features.d.ts +28 -0
- package/dist/features.d.ts.map +1 -1
- package/dist/features.js +1 -0
- package/dist/features.js.map +1 -1
- package/dist/layout.css +5 -0
- package/dist/regex.d.ts +2 -0
- package/dist/regex.d.ts.map +1 -0
- package/dist/regex.js +2 -0
- package/dist/regex.js.map +1 -0
- package/dist/right-panel/DefaultPanel.d.ts +3 -0
- package/dist/right-panel/DefaultPanel.d.ts.map +1 -1
- package/dist/right-panel/DefaultPanel.js +3 -0
- package/dist/right-panel/DefaultPanel.js.map +1 -1
- package/dist/right-panel/RightPanel.d.ts +3 -0
- package/dist/right-panel/RightPanel.d.ts.map +1 -1
- package/dist/right-panel/RightPanel.js +3 -0
- package/dist/right-panel/RightPanel.js.map +1 -1
- package/dist/right-panel/RightPanelProvider.d.ts +15 -0
- package/dist/right-panel/RightPanelProvider.d.ts.map +1 -1
- package/dist/right-panel/RightPanelProvider.js.map +1 -1
- package/dist/right-panel/constants.d.ts +2 -0
- package/dist/right-panel/constants.d.ts.map +1 -0
- package/dist/right-panel/constants.js +2 -0
- package/dist/right-panel/constants.js.map +1 -0
- package/dist/right-panel/hooks.d.ts +6 -0
- package/dist/right-panel/hooks.d.ts.map +1 -1
- package/dist/right-panel/hooks.js +8 -1
- package/dist/right-panel/hooks.js.map +1 -1
- package/dist/state/ChatEntry.d.ts +58 -2
- package/dist/state/ChatEntry.d.ts.map +1 -1
- package/dist/state/ChatEntry.js +20 -1
- package/dist/state/ChatEntry.js.map +1 -1
- package/dist/state/ChatState.d.ts +73 -8
- package/dist/state/ChatState.d.ts.map +1 -1
- package/dist/state/ChatState.js +24 -7
- package/dist/state/ChatState.js.map +1 -1
- package/dist/state/ChatTabsController.d.ts +31 -0
- package/dist/state/ChatTabsController.d.ts.map +1 -1
- package/dist/state/ChatTabsController.js +31 -0
- package/dist/state/ChatTabsController.js.map +1 -1
- package/dist/state/ObservableState.d.ts +14 -0
- package/dist/state/ObservableState.d.ts.map +1 -1
- package/dist/state/ObservableState.js +14 -0
- package/dist/state/ObservableState.js.map +1 -1
- package/dist/state/WidgetState.d.ts +5 -0
- package/dist/state/WidgetState.d.ts.map +1 -1
- package/dist/state/WidgetState.js +5 -0
- package/dist/state/WidgetState.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/chat.d.ts +13 -0
- package/dist/utils/chat.d.ts.map +1 -1
- package/dist/utils/chat.js +15 -1
- package/dist/utils/chat.js.map +1 -1
- package/dist/utils/date.d.ts +25 -0
- package/dist/utils/date.d.ts.map +1 -1
- package/dist/utils/date.js +25 -0
- package/dist/utils/date.js.map +1 -1
- package/dist/utils/download.d.ts +5 -0
- package/dist/utils/download.d.ts.map +1 -1
- package/dist/utils/download.js +5 -0
- package/dist/utils/download.js.map +1 -1
- package/dist/utils/knowledge-source.d.ts +10 -0
- package/dist/utils/knowledge-source.d.ts.map +1 -1
- package/dist/utils/knowledge-source.js +16 -0
- package/dist/utils/knowledge-source.js.map +1 -1
- package/dist/utils/string.d.ts +5 -0
- package/dist/utils/string.d.ts.map +1 -1
- package/dist/utils/string.js +5 -1
- package/dist/utils/string.js.map +1 -1
- package/dist/utils/url.d.ts +2 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/dist/utils/url.js +8 -0
- package/dist/utils/url.js.map +1 -0
- package/dist/views/Agents.js +3 -0
- package/dist/views/Agents.js.map +1 -1
- package/dist/views/Chat/AgentInfo.d.ts +3 -0
- package/dist/views/Chat/AgentInfo.d.ts.map +1 -1
- package/dist/views/Chat/AgentInfo.js +3 -0
- package/dist/views/Chat/AgentInfo.js.map +1 -1
- package/dist/views/Chat/ChatMessage.d.ts +17 -2
- package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
- package/dist/views/Chat/ChatMessage.js +9 -13
- package/dist/views/Chat/ChatMessage.js.map +1 -1
- package/dist/views/Chat/ChatMessages.d.ts +3 -0
- package/dist/views/Chat/ChatMessages.d.ts.map +1 -1
- package/dist/views/Chat/ChatMessages.js +3 -0
- package/dist/views/Chat/ChatMessages.js.map +1 -1
- package/dist/views/Chat/chat-scroll.d.ts +1 -1
- package/dist/views/Chat/chat-scroll.js +1 -1
- package/dist/views/Chat/events.d.ts +22 -0
- package/dist/views/Chat/events.d.ts.map +1 -0
- package/dist/views/Chat/events.js +66 -0
- package/dist/views/Chat/events.js.map +1 -0
- package/dist/views/Chat/index.d.ts +6 -0
- package/dist/views/Chat/index.d.ts.map +1 -1
- package/dist/views/Chat/index.js +3 -0
- package/dist/views/Chat/index.js.map +1 -1
- package/dist/views/ChatHistory/ChatHistoryPanel.d.ts +3 -0
- package/dist/views/ChatHistory/ChatHistoryPanel.d.ts.map +1 -1
- package/dist/views/ChatHistory/ChatHistoryPanel.js +5 -1
- package/dist/views/ChatHistory/ChatHistoryPanel.js.map +1 -1
- package/dist/views/ChatHistory/HistoryItem.d.ts +3 -0
- package/dist/views/ChatHistory/HistoryItem.d.ts.map +1 -1
- package/dist/views/ChatHistory/HistoryItem.js +13 -1
- package/dist/views/ChatHistory/HistoryItem.js.map +1 -1
- package/dist/views/ChatHistory/index.d.ts +10 -2
- package/dist/views/ChatHistory/index.d.ts.map +1 -1
- package/dist/views/ChatHistory/index.js +3 -0
- package/dist/views/ChatHistory/index.js.map +1 -1
- package/dist/views/ChatHistory/utils.d.ts +14 -0
- package/dist/views/ChatHistory/utils.d.ts.map +1 -1
- package/dist/views/ChatHistory/utils.js +14 -0
- package/dist/views/ChatHistory/utils.js.map +1 -1
- package/dist/views/ChatTabSelection.d.ts +3 -0
- package/dist/views/ChatTabSelection.d.ts.map +1 -1
- package/dist/views/ChatTabSelection.js +3 -0
- package/dist/views/ChatTabSelection.js.map +1 -1
- package/dist/views/Editor.d.ts +3 -0
- package/dist/views/Editor.d.ts.map +1 -1
- package/dist/views/Editor.js +4 -0
- package/dist/views/Editor.js.map +1 -1
- package/dist/views/Home.d.ts +8 -0
- package/dist/views/Home.d.ts.map +1 -1
- package/dist/views/Home.js +5 -0
- package/dist/views/Home.js.map +1 -1
- package/dist/views/KSDocument.d.ts +3 -0
- package/dist/views/KSDocument.d.ts.map +1 -1
- package/dist/views/KSDocument.js +3 -0
- package/dist/views/KSDocument.js.map +1 -1
- package/dist/views/KnowledgeSources.js +3 -0
- package/dist/views/KnowledgeSources.js.map +1 -1
- package/dist/views/MessageInput/ButtonGroup.d.ts +22 -0
- package/dist/views/MessageInput/ButtonGroup.d.ts.map +1 -1
- package/dist/views/MessageInput/ButtonGroup.js +4 -0
- package/dist/views/MessageInput/ButtonGroup.js.map +1 -1
- package/dist/views/MessageInput/InfoBar.d.ts +7 -0
- package/dist/views/MessageInput/InfoBar.d.ts.map +1 -1
- package/dist/views/MessageInput/InfoBar.js +7 -0
- package/dist/views/MessageInput/InfoBar.js.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.d.ts +13 -0
- package/dist/views/MessageInput/QuickCommandSelector.d.ts.map +1 -0
- package/dist/views/MessageInput/QuickCommandSelector.js +141 -0
- package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -0
- package/dist/views/MessageInput/index.d.ts +8 -0
- package/dist/views/MessageInput/index.d.ts.map +1 -1
- package/dist/views/MessageInput/index.js +11 -4
- package/dist/views/MessageInput/index.js.map +1 -1
- package/dist/views/MessageInput/styled.d.ts.map +1 -1
- package/dist/views/MessageInput/styled.js +137 -0
- package/dist/views/MessageInput/styled.js.map +1 -1
- package/dist/views/MinimizedHeader.d.ts +4 -0
- package/dist/views/MinimizedHeader.d.ts.map +1 -1
- package/dist/views/MinimizedHeader.js +4 -0
- package/dist/views/MinimizedHeader.js.map +1 -1
- package/dist/views/Stacks.d.ts +3 -0
- package/dist/views/Stacks.d.ts.map +1 -1
- package/dist/views/Stacks.js +3 -0
- package/dist/views/Stacks.js.map +1 -1
- package/dist/views/Workspaces.d.ts +3 -0
- package/dist/views/Workspaces.d.ts.map +1 -1
- package/dist/views/Workspaces.js +3 -0
- package/dist/views/Workspaces.js.map +1 -1
- package/package.json +6 -6
- package/src/StackspotAIWidget.tsx +23 -2
- package/src/chat-interceptors/CustomInputs.ts +14 -1
- package/src/chat-interceptors/quick-command-questions.ts +12 -2
- package/src/chat-interceptors/quick-commands.ts +66 -26
- package/src/chat-interceptors/send-message.ts +41 -11
- package/src/components/Accordion.tsx +10 -0
- package/src/components/AdaptiveTextArea.tsx +21 -4
- package/src/components/AutoFocus.tsx +34 -0
- package/src/components/Fading.tsx +66 -0
- package/src/components/FadingOverflow.tsx +31 -3
- package/src/components/FallbackBoundary/ErrorBoundary.tsx +26 -3
- package/src/components/FallbackBoundary/Loading.tsx +1 -1
- package/src/components/FallbackBoundary/index.tsx +13 -2
- package/src/components/HistoryList.tsx +15 -1
- package/src/components/IconInput.tsx +3 -0
- package/src/components/OverlayMenu.tsx +76 -20
- package/src/components/ProgressBar.tsx +23 -0
- package/src/components/QuickStartButton.tsx +3 -0
- package/src/components/RightPanelForm.tsx +15 -9
- package/src/components/RightPanelTabs.tsx +3 -0
- package/src/components/TabManager.tsx +8 -0
- package/src/components/Tooltip/Tooltip.tsx +47 -5
- package/src/components/Tooltip/TooltipAPI.ts +59 -42
- package/src/components/Tooltip/types.ts +13 -0
- package/src/components/form/DescribedCheckboxGroup.tsx +4 -0
- package/src/components/form/DescribedRadioGroup.tsx +4 -0
- package/src/components/form/types.ts +34 -0
- package/src/context/AIWidgetProvider.tsx +19 -0
- package/src/context/hooks.ts +56 -1
- package/src/features.ts +29 -0
- package/src/layout.css +5 -0
- package/src/regex.ts +1 -0
- package/src/right-panel/DefaultPanel.tsx +4 -0
- package/src/right-panel/RightPanel.tsx +3 -0
- package/src/right-panel/RightPanelProvider.tsx +15 -0
- package/src/right-panel/constants.ts +1 -0
- package/src/right-panel/hooks.tsx +8 -1
- package/src/state/ChatEntry.ts +60 -2
- package/src/state/ChatState.ts +74 -9
- package/src/state/ChatTabsController.ts +31 -0
- package/src/state/ObservableState.ts +14 -0
- package/src/state/WidgetState.ts +5 -0
- package/src/types.ts +10 -0
- package/src/utils/chat.ts +15 -1
- package/src/utils/date.ts +25 -1
- package/src/utils/download.ts +5 -0
- package/src/utils/knowledge-source.ts +16 -0
- package/src/utils/string.ts +5 -1
- package/src/utils/url.ts +8 -0
- package/src/views/Agents.tsx +3 -0
- package/src/views/Chat/AgentInfo.tsx +3 -0
- package/src/views/Chat/ChatMessage.tsx +31 -18
- package/src/views/Chat/ChatMessages.tsx +3 -0
- package/src/views/Chat/chat-scroll.ts +1 -1
- package/src/views/Chat/events.ts +69 -0
- package/src/views/Chat/index.tsx +6 -0
- package/src/views/ChatHistory/ChatHistoryPanel.tsx +6 -2
- package/src/views/ChatHistory/HistoryItem.tsx +14 -2
- package/src/views/ChatHistory/index.tsx +11 -1
- package/src/views/ChatHistory/utils.ts +14 -0
- package/src/views/ChatTabSelection.tsx +3 -0
- package/src/views/Editor.tsx +4 -0
- package/src/views/Home.tsx +8 -0
- package/src/views/KSDocument.tsx +3 -0
- package/src/views/KnowledgeSources.tsx +3 -0
- package/src/views/MessageInput/ButtonGroup.tsx +22 -0
- package/src/views/MessageInput/InfoBar.tsx +7 -0
- package/src/views/MessageInput/QuickCommandSelector.tsx +217 -0
- package/src/views/MessageInput/index.tsx +16 -4
- package/src/views/MessageInput/styled.ts +137 -0
- package/src/views/MinimizedHeader.tsx +4 -0
- package/src/views/Stacks.tsx +3 -0
- package/src/views/Workspaces.tsx +3 -0
package/src/state/ChatEntry.ts
CHANGED
|
@@ -3,10 +3,16 @@ import { pull } from 'lodash'
|
|
|
3
3
|
import { LabeledWithImage } from './types'
|
|
4
4
|
|
|
5
5
|
export interface SerializableAction {
|
|
6
|
+
/**
|
|
7
|
+
* The text for the button or anchor.
|
|
8
|
+
*/
|
|
6
9
|
title: string,
|
|
10
|
+
/**
|
|
11
|
+
* Links open new tabs with urls, while commands send text commands in the chat as if they were written by the user.
|
|
12
|
+
*/
|
|
7
13
|
type: 'link' | 'command',
|
|
8
14
|
/**
|
|
9
|
-
* The URL if the action is a link
|
|
15
|
+
* The URL if the action is a link. The content of the user message otherwise.
|
|
10
16
|
*/
|
|
11
17
|
exec: string,
|
|
12
18
|
}
|
|
@@ -26,23 +32,61 @@ export interface KnowledgeSource {
|
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
export interface TextChatEntry {
|
|
35
|
+
/**
|
|
36
|
+
* "text" for simple unformatted paragraphs. "md" for markdown.
|
|
37
|
+
*/
|
|
29
38
|
type: 'text' | 'md',
|
|
39
|
+
/**
|
|
40
|
+
* If the message was typed by the AI agent (bot), the user or the system (not currently in use).
|
|
41
|
+
*/
|
|
30
42
|
agentType: 'bot' | 'user' | 'system',
|
|
43
|
+
/**
|
|
44
|
+
* A set of buttons to go after the message.
|
|
45
|
+
*/
|
|
31
46
|
actions?: ChatAction[],
|
|
47
|
+
/**
|
|
48
|
+
* The content of the message.
|
|
49
|
+
*/
|
|
32
50
|
content: string,
|
|
51
|
+
/**
|
|
52
|
+
* The knowledge sources used to create the message.
|
|
53
|
+
*/
|
|
33
54
|
knowledgeSources?: KnowledgeSource[],
|
|
55
|
+
/**
|
|
56
|
+
* The date and time of the message. ISO string.
|
|
57
|
+
*/
|
|
34
58
|
updated?: string,
|
|
59
|
+
/**
|
|
60
|
+
* The agent who wrote the message. Undefined for the default agent or if the agentType is "user".
|
|
61
|
+
*/
|
|
35
62
|
agent?: LabeledWithImage,
|
|
63
|
+
/**
|
|
64
|
+
* The unique identifier of the message.
|
|
65
|
+
*/
|
|
36
66
|
messageId?: string,
|
|
67
|
+
/**
|
|
68
|
+
* If this is set, only an error message is rendered.
|
|
69
|
+
*/
|
|
37
70
|
error?: string,
|
|
71
|
+
/**
|
|
72
|
+
* A series of badges to display before the content.
|
|
73
|
+
*/
|
|
38
74
|
badges?: { color?: ColorPaletteName, label: string }[],
|
|
75
|
+
/**
|
|
76
|
+
* Whether or not to show this chat entry as a card.
|
|
77
|
+
*/
|
|
39
78
|
card?: boolean,
|
|
40
79
|
}
|
|
41
80
|
|
|
42
81
|
type ChatEntryListener = (value: TextChatEntry) => void
|
|
43
82
|
|
|
83
|
+
// this id is unique for each message and used for rendering. The `messageId`, which comes from the backend, is not always available and,
|
|
84
|
+
// therefore, can't be used for this purpose.
|
|
44
85
|
let nextId = 0
|
|
45
86
|
|
|
87
|
+
/**
|
|
88
|
+
* A message (entry) in the chat.
|
|
89
|
+
*/
|
|
46
90
|
export class ChatEntry {
|
|
47
91
|
readonly id: number
|
|
48
92
|
private value: TextChatEntry
|
|
@@ -50,13 +94,18 @@ export class ChatEntry {
|
|
|
50
94
|
|
|
51
95
|
/**
|
|
52
96
|
* @param value the value of the entry.
|
|
53
|
-
* @param isStreamed whether or not this entry is streamed. Defaults to false.
|
|
54
97
|
*/
|
|
55
98
|
constructor(value: TextChatEntry) {
|
|
56
99
|
this.id = nextId++
|
|
57
100
|
this.value = value
|
|
58
101
|
}
|
|
59
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Utility function to create a user entry.
|
|
105
|
+
* @param content the message's content.
|
|
106
|
+
* @param isMd whether or not this should be rendered as markdown.
|
|
107
|
+
* @returns a new ChatEntry.
|
|
108
|
+
*/
|
|
60
109
|
static createUserEntry(content: string, isMd = false) {
|
|
61
110
|
return new ChatEntry({
|
|
62
111
|
agentType: 'user',
|
|
@@ -66,6 +115,10 @@ export class ChatEntry {
|
|
|
66
115
|
})
|
|
67
116
|
}
|
|
68
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Utility function to create a streamed entry from the AI agent.
|
|
120
|
+
* @returns a new ChatEntry.
|
|
121
|
+
*/
|
|
69
122
|
static createStreamedBotEntry() {
|
|
70
123
|
return new ChatEntry({ agentType: 'bot', type: 'md', content: '' })
|
|
71
124
|
}
|
|
@@ -79,6 +132,11 @@ export class ChatEntry {
|
|
|
79
132
|
return this.value
|
|
80
133
|
}
|
|
81
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Watches the value of this ChatEntry.
|
|
137
|
+
* @param listener a function to call whenever the value changes.
|
|
138
|
+
* @returns a function that removes the listener.
|
|
139
|
+
*/
|
|
82
140
|
onChange(listener: ChatEntryListener) {
|
|
83
141
|
this.listeners.push(listener)
|
|
84
142
|
return () => {
|
package/src/state/ChatState.ts
CHANGED
|
@@ -6,12 +6,33 @@ import { ObservableState } from './ObservableState'
|
|
|
6
6
|
import { Labeled, LabeledWithImage } from './types'
|
|
7
7
|
|
|
8
8
|
export interface ChatProperties {
|
|
9
|
+
/**
|
|
10
|
+
* The name of the chat.
|
|
11
|
+
*/
|
|
9
12
|
label: string,
|
|
13
|
+
/**
|
|
14
|
+
* The current AI agent.
|
|
15
|
+
*/
|
|
10
16
|
agent?: LabeledWithImage & { builtIn: boolean },
|
|
17
|
+
/**
|
|
18
|
+
* The current workspace.
|
|
19
|
+
*/
|
|
11
20
|
workspace?: Labeled,
|
|
21
|
+
/**
|
|
22
|
+
* The current stack.
|
|
23
|
+
*/
|
|
12
24
|
stack?: Labeled,
|
|
25
|
+
/**
|
|
26
|
+
* The current knowledge sources.
|
|
27
|
+
*/
|
|
13
28
|
knowledgeSources?: Labeled[],
|
|
29
|
+
/**
|
|
30
|
+
* Whether or not the chat is in a loading state.
|
|
31
|
+
*/
|
|
14
32
|
isLoading?: boolean,
|
|
33
|
+
/**
|
|
34
|
+
* The value of the next message. This is the value of the text typed in the textarea below the chat.
|
|
35
|
+
*/
|
|
15
36
|
nextMessage?: string,
|
|
16
37
|
/**
|
|
17
38
|
* The current code in the editor.
|
|
@@ -22,7 +43,7 @@ export interface ChatProperties {
|
|
|
22
43
|
*/
|
|
23
44
|
codeLanguage?: string,
|
|
24
45
|
/**
|
|
25
|
-
* The current selection in the editor
|
|
46
|
+
* The current selection in the editor.
|
|
26
47
|
*/
|
|
27
48
|
codeSelection?: string,
|
|
28
49
|
}
|
|
@@ -34,28 +55,56 @@ export type MessageInterceptor = (
|
|
|
34
55
|
) => boolean | undefined | void | Promise<boolean | undefined | void>
|
|
35
56
|
|
|
36
57
|
interface Options {
|
|
58
|
+
/**
|
|
59
|
+
* The unique identifier for this chat (conversationId).
|
|
60
|
+
*/
|
|
37
61
|
id: string,
|
|
62
|
+
/**
|
|
63
|
+
* The initial value for the state of this chat.
|
|
64
|
+
*/
|
|
38
65
|
initial: ChatProperties,
|
|
66
|
+
/**
|
|
67
|
+
* The interceptors to use for the messages pushed to this chat.
|
|
68
|
+
*
|
|
69
|
+
* The interceptors are run whenever a new message (chat entry) is added to the chat. They're always run in the order of the array and if
|
|
70
|
+
* any returns a promise, the promise is awaited before running the next.
|
|
71
|
+
*
|
|
72
|
+
* If an interceptor returns false or resolves to false (if a promise), the execution is interrupted, i.e. the next interceptors are not
|
|
73
|
+
* run.
|
|
74
|
+
*
|
|
75
|
+
* An interceptor receives three parameters:
|
|
76
|
+
* 1. the chat entry added;
|
|
77
|
+
* 2. the chat state;
|
|
78
|
+
* 3. an AbortSignal that can be aborted by calling `abort()` on the ChatState. Once the signal is aborted, the interceptor must abort all
|
|
79
|
+
* of its operations.
|
|
80
|
+
*
|
|
81
|
+
* Attention: when multiple messages are added at once, only the last goes through the interceptors. Furthermore, messages created by the
|
|
82
|
+
* constructor don't go through the interceptors, only messages added via `pushMessage` do.
|
|
83
|
+
*/
|
|
39
84
|
interceptors?: MessageInterceptor[],
|
|
85
|
+
/**
|
|
86
|
+
* The content of this chat, i.e. its messages.
|
|
87
|
+
*/
|
|
40
88
|
entries?: ChatEntry[],
|
|
41
89
|
}
|
|
42
90
|
|
|
91
|
+
/**
|
|
92
|
+
* A chat. Each chat tab is a different ChatState.
|
|
93
|
+
*/
|
|
43
94
|
export class ChatState extends ObservableState<ChatProperties> {
|
|
44
95
|
readonly id: string
|
|
45
96
|
private entries: ChatEntry[]
|
|
46
97
|
private messagesListeners: ChatMessagesListener[] = []
|
|
47
98
|
private readonly interceptors: MessageInterceptor[]
|
|
99
|
+
/**
|
|
100
|
+
* A memory space (map) to be used by interceptors.
|
|
101
|
+
*/
|
|
48
102
|
interceptorMemory = new Map<string, any>()
|
|
49
|
-
private abortions: AbortController[] = []
|
|
50
|
-
|
|
51
103
|
/**
|
|
52
|
-
*
|
|
53
|
-
* @param initial the initial state.
|
|
54
|
-
* @param interceptors a list of interceptors to run whenever a new message (entry) is added to the chat. If an interception function
|
|
55
|
-
* returns false, the next interceptors are not run. Attention: when multiple messages are added at once, only the last goes through the
|
|
56
|
-
* interceptors. Furthermore, messages created by the constructor don't go through the interceptors, only messages added via `pushMessage`
|
|
57
|
-
* do.
|
|
104
|
+
* Abort signals currently active.
|
|
58
105
|
*/
|
|
106
|
+
private abortions: AbortController[] = []
|
|
107
|
+
|
|
59
108
|
constructor({ id, initial, entries = [], interceptors = [] }: Options) {
|
|
60
109
|
super(initial)
|
|
61
110
|
this.id = id
|
|
@@ -82,6 +131,10 @@ export class ChatState extends ObservableState<ChatProperties> {
|
|
|
82
131
|
pull(this.abortions, abort)
|
|
83
132
|
}
|
|
84
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Adds one or more messages to the chat. Messages are appended to the end of the chat.
|
|
136
|
+
* @param entries the messages to add.
|
|
137
|
+
*/
|
|
85
138
|
pushMessage(...entries: ChatEntry[]) {
|
|
86
139
|
if (!entries.length) return
|
|
87
140
|
this.entries = [...this.entries, ...entries]
|
|
@@ -89,15 +142,27 @@ export class ChatState extends ObservableState<ChatProperties> {
|
|
|
89
142
|
this.runInterceptors(last(entries)!)
|
|
90
143
|
}
|
|
91
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Removes one or more messages from the end of the chat.
|
|
147
|
+
* @param quantity the number of messages to remove. Defaults to 1.
|
|
148
|
+
*/
|
|
92
149
|
popMessage(quantity = 1) {
|
|
93
150
|
this.entries = dropRight(this.entries, quantity)
|
|
94
151
|
this.runMessagesListeners()
|
|
95
152
|
}
|
|
96
153
|
|
|
154
|
+
/**
|
|
155
|
+
* @returns the current list of messages.
|
|
156
|
+
*/
|
|
97
157
|
getMessages() {
|
|
98
158
|
return this.entries
|
|
99
159
|
}
|
|
100
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Watches this chat for changes in the list of messages.
|
|
163
|
+
* @param listener the function to call whenever the list of messages changes.
|
|
164
|
+
* @returns a function that removes the listener.
|
|
165
|
+
*/
|
|
101
166
|
onChangeMessages(listener: ChatMessagesListener) {
|
|
102
167
|
this.messagesListeners.push(listener)
|
|
103
168
|
return () => {
|
|
@@ -3,6 +3,9 @@ import { ChatState } from './ChatState'
|
|
|
3
3
|
|
|
4
4
|
type TabChangeListener = (chats: ChatState[], activeId: string) => void
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Controls the chat tabs.
|
|
8
|
+
*/
|
|
6
9
|
export class ChatTabsController {
|
|
7
10
|
private chats: ChatState[] = []
|
|
8
11
|
private activeChatId = ''
|
|
@@ -12,12 +15,20 @@ export class ChatTabsController {
|
|
|
12
15
|
this.listeners.forEach(l => l(this.chats, this.activeChatId))
|
|
13
16
|
}
|
|
14
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Adds new chats to the tab view.
|
|
20
|
+
* @param chats the chats to add.
|
|
21
|
+
*/
|
|
15
22
|
add(...chats: ChatState[]) {
|
|
16
23
|
if (!chats.length) return
|
|
17
24
|
this.chats = [...this.chats, ...chats]
|
|
18
25
|
this.runListeners()
|
|
19
26
|
}
|
|
20
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Removes chats from the tab view.
|
|
30
|
+
* @param ids the ids of the chats to remove.
|
|
31
|
+
*/
|
|
21
32
|
remove(...ids: string[]) {
|
|
22
33
|
if (this.chats.length <= 1 || !ids.length) return
|
|
23
34
|
const currentActiveIndex = this.chats.findIndex(c => c.id === this.activeChatId)
|
|
@@ -29,18 +40,34 @@ export class ChatTabsController {
|
|
|
29
40
|
this.runListeners()
|
|
30
41
|
}
|
|
31
42
|
|
|
43
|
+
/**
|
|
44
|
+
* @param id the id of the chat to retrieve.
|
|
45
|
+
* @returns a ChatState corresponding to the id.
|
|
46
|
+
*/
|
|
32
47
|
get(id: string) {
|
|
33
48
|
return this.chats.find(c => c.id === id)
|
|
34
49
|
}
|
|
35
50
|
|
|
51
|
+
/**
|
|
52
|
+
* @returns the if of the chat corresponding to the tab that is currently active.
|
|
53
|
+
*/
|
|
36
54
|
getActiveChatId() {
|
|
37
55
|
return this.activeChatId
|
|
38
56
|
}
|
|
39
57
|
|
|
58
|
+
/**
|
|
59
|
+
* @returns all chats in tab view.
|
|
60
|
+
*/
|
|
40
61
|
getAll() {
|
|
41
62
|
return this.chats
|
|
42
63
|
}
|
|
43
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Watches for changes in the tab view.
|
|
67
|
+
* @param listener a function called whenever a tab is added, removed or selected. This function receives the list of chats as the first
|
|
68
|
+
* parameter and the id of the active chat as the second parameter.
|
|
69
|
+
* @returns a function to remove the listener.
|
|
70
|
+
*/
|
|
44
71
|
onChange(listener: TabChangeListener) {
|
|
45
72
|
this.listeners.push(listener)
|
|
46
73
|
return () => {
|
|
@@ -48,6 +75,10 @@ export class ChatTabsController {
|
|
|
48
75
|
}
|
|
49
76
|
}
|
|
50
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Changes the chat (tab) that is currently active.
|
|
80
|
+
* @param id the id of the chat to select.
|
|
81
|
+
*/
|
|
51
82
|
select(id: string) {
|
|
52
83
|
this.activeChatId = id
|
|
53
84
|
this.runListeners()
|
|
@@ -6,6 +6,14 @@ type Listeners<T> = {
|
|
|
6
6
|
[K in keyof T]?: ((value: T[K]) => void)[]
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* A generic representation of a state that can be observed for changes.
|
|
11
|
+
*
|
|
12
|
+
* Building our own state instead of using React is important because:
|
|
13
|
+
* 1. We need to be able to control it even outside the react context.
|
|
14
|
+
* 2. We need performance, we can't have everything re-rendering because something changes. We need to be careful to watch only the
|
|
15
|
+
* properties we need in a component.
|
|
16
|
+
*/
|
|
9
17
|
export class ObservableState<T> {
|
|
10
18
|
protected state: T
|
|
11
19
|
private listeners: Listeners<T> = {}
|
|
@@ -25,6 +33,12 @@ export class ObservableState<T> {
|
|
|
25
33
|
return this.state[key]
|
|
26
34
|
}
|
|
27
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Watches for changes in the state referred by the provided key.
|
|
38
|
+
* @param key the key of the state to watch.
|
|
39
|
+
* @param listener a function called whenever the value of the state referred by `key` changes.
|
|
40
|
+
* @returns a function to remove the listener.
|
|
41
|
+
*/
|
|
28
42
|
onChange<K extends keyof T>(key: K, listener: (value: T[K]) => void) {
|
|
29
43
|
this.listeners[key] ??= []
|
|
30
44
|
this.listeners[key]!.push(listener)
|
package/src/state/WidgetState.ts
CHANGED
|
@@ -16,6 +16,11 @@ export interface WidgetProperties {
|
|
|
16
16
|
isMinimized?: boolean,
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Holds the full state of the AI Chat Widget.
|
|
21
|
+
*
|
|
22
|
+
* This can be used to fully control the chat widget. This is the model of what gets rendered to the screen.
|
|
23
|
+
*/
|
|
19
24
|
export class WidgetState extends ObservableState<WidgetProperties> {
|
|
20
25
|
readonly chatTabs: ChatTabsController
|
|
21
26
|
|
package/src/types.ts
CHANGED
|
@@ -14,7 +14,17 @@ export interface ButtonAction extends WithStyle {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export interface MinimizedActions {
|
|
17
|
+
/**
|
|
18
|
+
* When the chat is minimized, a button to collapse the window is rendered. This function is called whenever this button is clicked.
|
|
19
|
+
*/
|
|
17
20
|
onCollapse?: () => void,
|
|
21
|
+
/**
|
|
22
|
+
* If `onCollapse` is clicked, the button to collapse is replaced by a button to expand. This function is called whenever the expand
|
|
23
|
+
* button is clicked.
|
|
24
|
+
*/
|
|
18
25
|
onExpand?: () => void,
|
|
26
|
+
/**
|
|
27
|
+
* When the chat is minimized, a button to close the window is rendered. This function is called whenever this button is clicked.
|
|
28
|
+
*/
|
|
19
29
|
onClose?: () => void,
|
|
20
30
|
}
|
package/src/utils/chat.ts
CHANGED
|
@@ -4,8 +4,14 @@ import { ChatState, MessageInterceptor } from '../state/ChatState'
|
|
|
4
4
|
import { WidgetState } from '../state/WidgetState'
|
|
5
5
|
import { defaultLanguage } from './programming-languages'
|
|
6
6
|
|
|
7
|
+
// helps with naming new chats
|
|
7
8
|
let next = 1
|
|
8
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Utility for creating a new chat in the chat tabs.
|
|
12
|
+
* @param widget the widget state.
|
|
13
|
+
* @param interceptors the interceptors to add the chat.
|
|
14
|
+
*/
|
|
9
15
|
export function createNewChat(widget: WidgetState, interceptors: MessageInterceptor[]) {
|
|
10
16
|
const id = ulid()
|
|
11
17
|
widget.chatTabs.add(new ChatState({ id, initial: { label: `Chat ${next}` }, interceptors }))
|
|
@@ -13,6 +19,14 @@ export function createNewChat(widget: WidgetState, interceptors: MessageIntercep
|
|
|
13
19
|
next++
|
|
14
20
|
}
|
|
15
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Builds a conversation context from a ChatState.
|
|
24
|
+
*
|
|
25
|
+
* The conversation context is needed by most backend services.
|
|
26
|
+
*
|
|
27
|
+
* @param state the ChatState to build the context from.
|
|
28
|
+
* @returns the conversation context ready to be sent to the backend.
|
|
29
|
+
*/
|
|
16
30
|
export function buildConversationContext(state: ChatState): FixedChatRequest['context'] {
|
|
17
31
|
return {
|
|
18
32
|
workspace: state.get('workspace')?.id,
|
|
@@ -25,6 +39,6 @@ export function buildConversationContext(state: ChatState): FixedChatRequest['co
|
|
|
25
39
|
os: navigator.userAgent,
|
|
26
40
|
platform: 'web-widget',
|
|
27
41
|
platform_version: navigator.userAgent,
|
|
28
|
-
stackspot_ai_version: '
|
|
42
|
+
stackspot_ai_version: '1.0.0',
|
|
29
43
|
}
|
|
30
44
|
}
|
package/src/utils/date.ts
CHANGED
|
@@ -8,7 +8,17 @@ const fullFormatOptions: Intl.DateTimeFormatOptions = {
|
|
|
8
8
|
month: 'long',
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Formats a date to show at the footer of a chat message.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* - Today, 14:11
|
|
16
|
+
* - Yesterday, 09:00
|
|
17
|
+
* - October 26 at 10:53
|
|
18
|
+
* @param date the Date to format.
|
|
19
|
+
* @param language the language to use.
|
|
20
|
+
* @returns the formatted date.
|
|
21
|
+
*/
|
|
12
22
|
export function formatDateForChatMessage(date: Date, language: Language = getLanguage()) {
|
|
13
23
|
const formatted: string[] = []
|
|
14
24
|
const now = new Date()
|
|
@@ -21,13 +31,27 @@ export function formatDateForChatMessage(date: Date, language: Language = getLan
|
|
|
21
31
|
return formatted.join(', ')
|
|
22
32
|
}
|
|
23
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Uses the current language to format dates.
|
|
36
|
+
* @returns an object containing functions for formatting dates.
|
|
37
|
+
*/
|
|
24
38
|
export function useDateFormatter() {
|
|
25
39
|
const language = useLanguage()
|
|
26
40
|
return {
|
|
41
|
+
/**
|
|
42
|
+
* @param date the date to format using {@link formatDateForChatMessage}.
|
|
43
|
+
* @returns the formatted date according to the current language. If the language changes, this result also changes.
|
|
44
|
+
*/
|
|
27
45
|
formatForChatMessage: (date: Date) => formatDateForChatMessage(date, language),
|
|
28
46
|
}
|
|
29
47
|
}
|
|
30
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Subtracts `numberOfDays` from `date`.
|
|
51
|
+
* @param date
|
|
52
|
+
* @param numberOfDays
|
|
53
|
+
* @returns the resulting Date object.
|
|
54
|
+
*/
|
|
31
55
|
export function subtractDays(date: Date, numberOfDays: number) {
|
|
32
56
|
return new Date(date.getTime() - 24 * numberOfDays * 60 * 60000)
|
|
33
57
|
}
|
package/src/utils/download.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Downloads `text` as a file named `filename`.
|
|
3
|
+
* @param filename the name of the file.
|
|
4
|
+
* @param text the content of the file.
|
|
5
|
+
*/
|
|
1
6
|
export function download(filename: string, text: string) {
|
|
2
7
|
const element = document.createElement('a')
|
|
3
8
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text))
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { DocumentResponse, SourceKnowledgeSource, SourceProjectFile4, SourceStackAi } from '@stack-spot/portal-network/api/ai'
|
|
2
2
|
import { KnowledgeSource } from '../state/ChatEntry'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* A document can come from the backend as something that resembles a JSON, but it is not. This function attempts to solve some issues and
|
|
6
|
+
* still interpret as a JSON.
|
|
7
|
+
* @param str the malformed JSON.
|
|
8
|
+
* @returns the object corresponding to parsed JSON or undefined if it wasn't possible to fix it.
|
|
9
|
+
*/
|
|
4
10
|
function attemptToParseMalFormedJson(str: string) {
|
|
5
11
|
try {
|
|
6
12
|
return JSON.parse(str)
|
|
@@ -21,6 +27,11 @@ function attemptToParseMalFormedJson(str: string) {
|
|
|
21
27
|
}
|
|
22
28
|
}
|
|
23
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Extracts the important part of a KS document to show for the user.
|
|
32
|
+
* @param document the document to parse.
|
|
33
|
+
* @returns an object containing the programming language of the KS, its code snippet and a textual description.
|
|
34
|
+
*/
|
|
24
35
|
export function extractCodeFromKSDocument(document: DocumentResponse): { language?: string, snippet: string, text?: string } {
|
|
25
36
|
const language = (document?.metadata as any)?.language
|
|
26
37
|
if (language) {
|
|
@@ -43,6 +54,11 @@ export function extractCodeFromKSDocument(document: DocumentResponse): { languag
|
|
|
43
54
|
return typeof document === 'object' ? { language: 'json', snippet: JSON.stringify(document, null, 2) } : { snippet: String(document) }
|
|
44
55
|
}
|
|
45
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Extracts all knowledge sources from a mix of sources that can be used to shape an AI agent's answer.
|
|
59
|
+
* @param sources a list with sources of any kind.
|
|
60
|
+
* @returns a list of knowledge sources in the format expected by the chat.
|
|
61
|
+
*/
|
|
46
62
|
export function genericSourcesToKnowledgeSources(
|
|
47
63
|
sources: (SourceStackAi | SourceKnowledgeSource | SourceProjectFile4)[] | undefined,
|
|
48
64
|
): KnowledgeSource[] | undefined {
|
package/src/utils/string.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Gets the size of a string removing control characters and spaces
|
|
3
|
+
* @param str the string to count.
|
|
4
|
+
* @returns the count value.
|
|
5
|
+
*/
|
|
2
6
|
export function getSizeOfString(str: string): number {
|
|
3
7
|
// eslint-disable-next-line no-control-regex
|
|
4
8
|
const withoutSpacesAndControls = str.replace(/[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069\s]/g, '')
|
package/src/utils/url.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const stkAIDomain = /^https:\/\/ai(\.\w+)?\.stackspot\.com$/
|
|
2
|
+
const localhostDomain = /^http:\/\/localhost:\d+$/
|
|
3
|
+
const aiPrd = 'https://ai.stackspot.com'
|
|
4
|
+
|
|
5
|
+
export function getUrlToStackSpotAI() {
|
|
6
|
+
const current = location.origin
|
|
7
|
+
return stkAIDomain.test(current) || localhostDomain.test(current) ? current : aiPrd
|
|
8
|
+
}
|
package/src/views/Agents.tsx
CHANGED
|
@@ -82,6 +82,9 @@ export const Agents = () => {
|
|
|
82
82
|
return null
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Renders the Agent selection form in the Right Panel if this is the panel that is currently opened.
|
|
87
|
+
*/
|
|
85
88
|
const AgentsPanel = () => {
|
|
86
89
|
const t = useTranslate(dictionary)
|
|
87
90
|
const chat = useCurrentChat()
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Button, IconBox, Text } from '@citric/core'
|
|
2
2
|
import { Copy, Dislike, DislikeFill, Like, LikeFill, TimesCircle } from '@citric/icons'
|
|
3
3
|
import { Avatar, Badge, IconButton } from '@citric/ui'
|
|
4
|
-
import { aiClient } from '@stack-spot/portal-network'
|
|
5
4
|
import { listToClass } from '@stack-spot/portal-theme'
|
|
6
5
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
7
6
|
import { useCallback, useMemo, useRef, useState } from 'react'
|
|
@@ -11,15 +10,35 @@ import { ChatEntry, SerializableAction, TextChatEntry } from '../../state/ChatEn
|
|
|
11
10
|
import { useDateFormatter } from '../../utils/date'
|
|
12
11
|
import { AgentInfo } from './AgentInfo'
|
|
13
12
|
import { useChatScrollToBottomEffect } from './chat-scroll'
|
|
13
|
+
import { onCopyAll, onCopyCode, onLikeOrDislike } from './events'
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
interface Props {
|
|
16
|
+
/**
|
|
17
|
+
* The ChatEntry to render.
|
|
18
|
+
*/
|
|
19
|
+
message: ChatEntry,
|
|
20
|
+
/**
|
|
21
|
+
* The name of the user currently logged in (will be used if the agent type of the message is "user").
|
|
22
|
+
*/
|
|
23
|
+
username: string,
|
|
24
|
+
/**
|
|
25
|
+
* Whether or not this is the last message in the chat. This is important for disabling action buttons in messages that are no longer
|
|
26
|
+
* relevant.
|
|
27
|
+
*/
|
|
28
|
+
isLast: boolean,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Renders a message (ChatEntry) in the chat.
|
|
33
|
+
*/
|
|
34
|
+
export const ChatMessage = ({ message, username, isLast }: Props) => {
|
|
16
35
|
const t = useTranslate(dictionary)
|
|
17
36
|
const [liked, setLiked] = useState<boolean | undefined>()
|
|
18
37
|
const entry = useChatEntry(message)
|
|
19
38
|
const dateFormatter = useDateFormatter()
|
|
20
39
|
const userInfo = entry.agentType === 'user' ? <Avatar size="xs">{username}</Avatar> : <AgentInfo agent={entry.agent} />
|
|
21
40
|
const date = new Date(entry.updated ?? '')
|
|
22
|
-
const
|
|
41
|
+
const shouldShowFooter = entry.updated && !isNaN(date.getTime())
|
|
23
42
|
const ref = useRef<HTMLLIElement>(null)
|
|
24
43
|
const widget = useWidget()
|
|
25
44
|
const chat = useCurrentChat()
|
|
@@ -43,16 +62,7 @@ export const ChatMessage = ({ message, username, isLast }: { message: ChatEntry,
|
|
|
43
62
|
if (!entry.messageId || like === liked) return
|
|
44
63
|
setLiked(like)
|
|
45
64
|
try {
|
|
46
|
-
await
|
|
47
|
-
body: [{
|
|
48
|
-
feedback: like ? 'LIKE' : 'DISLIKE',
|
|
49
|
-
message_id: entry.messageId,
|
|
50
|
-
type: 'user_feedback_provided',
|
|
51
|
-
code: '',
|
|
52
|
-
generated_at: Math.floor(new Date().getTime() / 1000),
|
|
53
|
-
size: 0,
|
|
54
|
-
}],
|
|
55
|
-
})
|
|
65
|
+
await onLikeOrDislike(entry.messageId, like)
|
|
56
66
|
} catch {
|
|
57
67
|
setLiked(liked)
|
|
58
68
|
}
|
|
@@ -72,7 +82,10 @@ export const ChatMessage = ({ message, username, isLast }: { message: ChatEntry,
|
|
|
72
82
|
{entry.badges?.length && <div className="badges">
|
|
73
83
|
{entry.badges.map((b, index) => <Badge key={index} palette={b.color ?? 'cyan'} appearance="square">{b.label}</Badge>)}
|
|
74
84
|
</div>}
|
|
75
|
-
{entry.type === 'md'
|
|
85
|
+
{entry.type === 'md'
|
|
86
|
+
? <Markdown onCopyCode={(code) => onCopyCode(code, entry.messageId ?? '', chat)}>{entry.content}</Markdown>
|
|
87
|
+
: <p className="plain-text">{entry.content}</p>
|
|
88
|
+
}
|
|
76
89
|
{entry.actions?.length && <div className="actions">
|
|
77
90
|
{entry.actions.map(
|
|
78
91
|
(a, index) => (
|
|
@@ -104,10 +117,10 @@ export const ChatMessage = ({ message, username, isLast }: { message: ChatEntry,
|
|
|
104
117
|
</li>
|
|
105
118
|
))}</ul>
|
|
106
119
|
</div>}
|
|
107
|
-
<div className="message-footer">
|
|
120
|
+
{shouldShowFooter && <div className="message-footer">
|
|
108
121
|
{entry.agentType === 'bot' && !entry.error && <div className="message-actions">
|
|
109
122
|
{entry.type === 'md' && (
|
|
110
|
-
<IconButton title={t.copy} aria-label={t.copy} onClick={() =>
|
|
123
|
+
<IconButton title={t.copy} aria-label={t.copy} onClick={() => onCopyAll(entry, chat)}>
|
|
111
124
|
<Copy />
|
|
112
125
|
</IconButton>
|
|
113
126
|
)}
|
|
@@ -122,8 +135,8 @@ export const ChatMessage = ({ message, username, isLast }: { message: ChatEntry,
|
|
|
122
135
|
</>
|
|
123
136
|
)}
|
|
124
137
|
</div>}
|
|
125
|
-
|
|
126
|
-
</div>
|
|
138
|
+
<Text appearance="microtext1" className="chat-date">{dateFormatter.formatForChatMessage(date)}</Text>
|
|
139
|
+
</div>}
|
|
127
140
|
</li>
|
|
128
141
|
)
|
|
129
142
|
}
|