@stack-spot/ai-chat-widget 1.0.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 +42 -3
- 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 +18 -0
- 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 +12 -0
- package/dist/components/AdaptiveTextArea.d.ts.map +1 -1
- package/dist/components/AdaptiveTextArea.js +3 -0
- package/dist/components/AdaptiveTextArea.js.map +1 -1
- package/dist/components/AutoFocus.d.ts +17 -0
- package/dist/components/AutoFocus.d.ts.map +1 -1
- package/dist/components/AutoFocus.js +6 -5
- package/dist/components/AutoFocus.js.map +1 -1
- package/dist/components/Fading.d.ts +19 -2
- package/dist/components/Fading.d.ts.map +1 -1
- package/dist/components/Fading.js +6 -4
- package/dist/components/Fading.js.map +1 -1
- 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/index.d.ts +6 -0
- package/dist/components/FallbackBoundary/index.d.ts.map +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 +11 -0
- package/dist/components/OverlayMenu.d.ts.map +1 -1
- package/dist/components/OverlayMenu.js +5 -1
- 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 +3 -0
- 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 +23 -0
- package/dist/components/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/components/Tooltip/Tooltip.js +4 -0
- package/dist/components/Tooltip/Tooltip.js.map +1 -1
- package/dist/components/Tooltip/TooltipAPI.d.ts +16 -0
- package/dist/components/Tooltip/TooltipAPI.d.ts.map +1 -1
- package/dist/components/Tooltip/TooltipAPI.js +17 -0
- 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/right-panel/DefaultPanel.d.ts +3 -0
- package/dist/right-panel/DefaultPanel.d.ts.map +1 -1
- package/dist/right-panel/DefaultPanel.js +4 -3
- 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/hooks.d.ts +6 -0
- package/dist/right-panel/hooks.d.ts.map +1 -1
- package/dist/right-panel/hooks.js +6 -0
- 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 +14 -0
- 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/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 +6 -32
- 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 +3 -0
- 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 +3 -0
- 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 +7 -0
- package/dist/views/MessageInput/QuickCommandSelector.d.ts.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.js +4 -0
- package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -1
- 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 +5 -0
- package/dist/views/MessageInput/index.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 +42 -3
- package/src/chat-interceptors/send-message.ts +18 -0
- package/src/components/Accordion.tsx +10 -0
- package/src/components/AdaptiveTextArea.tsx +12 -0
- package/src/components/AutoFocus.tsx +19 -5
- package/src/components/Fading.tsx +25 -5
- package/src/components/FadingOverflow.tsx +31 -3
- package/src/components/FallbackBoundary/index.tsx +6 -0
- package/src/components/HistoryList.tsx +15 -1
- package/src/components/IconInput.tsx +3 -0
- package/src/components/OverlayMenu.tsx +17 -1
- package/src/components/ProgressBar.tsx +23 -0
- package/src/components/QuickStartButton.tsx +3 -0
- package/src/components/RightPanelForm.tsx +3 -0
- package/src/components/RightPanelTabs.tsx +3 -0
- package/src/components/TabManager.tsx +8 -0
- package/src/components/Tooltip/Tooltip.tsx +23 -0
- package/src/components/Tooltip/TooltipAPI.ts +17 -0
- 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/right-panel/DefaultPanel.tsx +12 -13
- package/src/right-panel/RightPanel.tsx +3 -0
- package/src/right-panel/RightPanelProvider.tsx +15 -0
- package/src/right-panel/hooks.tsx +6 -0
- 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 +14 -0
- 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/views/Agents.tsx +3 -0
- package/src/views/Chat/AgentInfo.tsx +3 -0
- package/src/views/Chat/ChatMessage.tsx +21 -32
- 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 +3 -0
- package/src/views/ChatHistory/HistoryItem.tsx +3 -0
- 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 +7 -0
- package/src/views/MessageInput/index.tsx +8 -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/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,
|
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/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,39 +1,37 @@
|
|
|
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'
|
|
8
7
|
import { Markdown } from '../../components/Markdown'
|
|
9
8
|
import { useChatEntry, useCurrentChat, useWidget } from '../../context/hooks'
|
|
10
9
|
import { ChatEntry, SerializableAction, TextChatEntry } from '../../state/ChatEntry'
|
|
11
|
-
import { ChatState } from '../../state/ChatState'
|
|
12
|
-
import { buildConversationContext } from '../../utils/chat'
|
|
13
10
|
import { useDateFormatter } from '../../utils/date'
|
|
14
|
-
import { getSizeOfString } from '../../utils/string'
|
|
15
11
|
import { AgentInfo } from './AgentInfo'
|
|
16
12
|
import { useChatScrollToBottomEffect } from './chat-scroll'
|
|
13
|
+
import { onCopyAll, onCopyCode, onLikeOrDislike } from './events'
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
console.warn('Failed to register event: code copied.')
|
|
33
|
-
}
|
|
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,
|
|
34
29
|
}
|
|
35
30
|
|
|
36
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Renders a message (ChatEntry) in the chat.
|
|
33
|
+
*/
|
|
34
|
+
export const ChatMessage = ({ message, username, isLast }: Props) => {
|
|
37
35
|
const t = useTranslate(dictionary)
|
|
38
36
|
const [liked, setLiked] = useState<boolean | undefined>()
|
|
39
37
|
const entry = useChatEntry(message)
|
|
@@ -64,16 +62,7 @@ export const ChatMessage = ({ message, username, isLast }: { message: ChatEntry,
|
|
|
64
62
|
if (!entry.messageId || like === liked) return
|
|
65
63
|
setLiked(like)
|
|
66
64
|
try {
|
|
67
|
-
await
|
|
68
|
-
body: [{
|
|
69
|
-
feedback: like ? 'LIKE' : 'DISLIKE',
|
|
70
|
-
message_id: entry.messageId,
|
|
71
|
-
type: 'user_feedback_provided',
|
|
72
|
-
code: '',
|
|
73
|
-
generated_at: Math.floor(new Date().getTime() / 1000),
|
|
74
|
-
size: 0,
|
|
75
|
-
}],
|
|
76
|
-
})
|
|
65
|
+
await onLikeOrDislike(entry.messageId, like)
|
|
77
66
|
} catch {
|
|
78
67
|
setLiked(liked)
|
|
79
68
|
}
|
|
@@ -131,7 +120,7 @@ export const ChatMessage = ({ message, username, isLast }: { message: ChatEntry,
|
|
|
131
120
|
{shouldShowFooter && <div className="message-footer">
|
|
132
121
|
{entry.agentType === 'bot' && !entry.error && <div className="message-actions">
|
|
133
122
|
{entry.type === 'md' && (
|
|
134
|
-
<IconButton title={t.copy} aria-label={t.copy} onClick={() =>
|
|
123
|
+
<IconButton title={t.copy} aria-label={t.copy} onClick={() => onCopyAll(entry, chat)}>
|
|
135
124
|
<Copy />
|
|
136
125
|
</IconButton>
|
|
137
126
|
)}
|
|
@@ -2,7 +2,7 @@ import { useEffect, useRef } from 'react'
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Scrolls the closest chat (upwards in the tree) to its bottom.
|
|
5
|
-
* @param ref the reference element.
|
|
5
|
+
* @param ref the reference to the element contained the chat we want to scroll.
|
|
6
6
|
* @param deps when the deps changes, the chat is scrolled.
|
|
7
7
|
*/
|
|
8
8
|
export function useChatScrollToBottomEffect(ref: React.RefObject<HTMLElement>, deps: any[]) {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { aiClient } from '@stack-spot/portal-network'
|
|
2
|
+
import { TextChatEntry } from '../../state/ChatEntry'
|
|
3
|
+
import { ChatState } from '../../state/ChatState'
|
|
4
|
+
import { buildConversationContext } from '../../utils/chat'
|
|
5
|
+
import { getSizeOfString } from '../../utils/string'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates the event of copying a code.
|
|
9
|
+
* @param code the code copied.
|
|
10
|
+
* @param messageId the id of the message containing the code.
|
|
11
|
+
* @param chat the chat state.
|
|
12
|
+
*/
|
|
13
|
+
export async function onCopyCode(code: string, messageId: string, chat: ChatState) {
|
|
14
|
+
try {
|
|
15
|
+
await aiClient.createEvent.mutate({
|
|
16
|
+
body: [{
|
|
17
|
+
type: 'code_copied',
|
|
18
|
+
code,
|
|
19
|
+
context: buildConversationContext(chat),
|
|
20
|
+
size: getSizeOfString(code),
|
|
21
|
+
generated_at: new Date().getTime(),
|
|
22
|
+
message_id: messageId,
|
|
23
|
+
}],
|
|
24
|
+
})
|
|
25
|
+
} catch (error) {
|
|
26
|
+
// eslint-disable-next-line no-console
|
|
27
|
+
console.warn('Failed to register event: code copied.')
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Creates the event of copying a whole message.
|
|
33
|
+
* @param entry the message copied.
|
|
34
|
+
* @param chat the chat state.
|
|
35
|
+
*/
|
|
36
|
+
export function onCopyAll(entry: TextChatEntry, chat: ChatState) {
|
|
37
|
+
navigator.clipboard.writeText(entry.content)
|
|
38
|
+
return aiClient.createEvent.mutate({
|
|
39
|
+
body: [
|
|
40
|
+
{
|
|
41
|
+
code: entry.content,
|
|
42
|
+
size: getSizeOfString(entry.content),
|
|
43
|
+
generated_at: new Date().getTime(),
|
|
44
|
+
type: 'copied_all',
|
|
45
|
+
knowledge_sources: entry.knowledgeSources?.map(ks => ({ slug: ks.slug, type: 'knowledge_source', name: ks.name })),
|
|
46
|
+
context: buildConversationContext(chat),
|
|
47
|
+
message_id: entry.messageId,
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Creates an event of like or dislike for a message.
|
|
55
|
+
* @param messageId the id of the message.
|
|
56
|
+
* @param like true if it's a like, false if it's a dislike.
|
|
57
|
+
*/
|
|
58
|
+
export function onLikeOrDislike(messageId: string, like: boolean) {
|
|
59
|
+
return aiClient.createEvent.mutate({
|
|
60
|
+
body: [{
|
|
61
|
+
feedback: like ? 'LIKE' : 'DISLIKE',
|
|
62
|
+
message_id: messageId,
|
|
63
|
+
type: 'user_feedback_provided',
|
|
64
|
+
code: '',
|
|
65
|
+
generated_at: Math.floor(new Date().getTime() / 1000),
|
|
66
|
+
size: 0,
|
|
67
|
+
}],
|
|
68
|
+
})
|
|
69
|
+
}
|
package/src/views/Chat/index.tsx
CHANGED
|
@@ -2,9 +2,15 @@ import { useChatTabs } from '../../context/hooks'
|
|
|
2
2
|
import { ChatMessages } from './ChatMessages'
|
|
3
3
|
|
|
4
4
|
interface Props {
|
|
5
|
+
/**
|
|
6
|
+
* The name of the user currently logged in.
|
|
7
|
+
*/
|
|
5
8
|
username: string,
|
|
6
9
|
}
|
|
7
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Renders the chat panel, with all of its messages.
|
|
13
|
+
*/
|
|
8
14
|
export const Chat = ({ username }: Props) => {
|
|
9
15
|
const { active } = useChatTabs()
|
|
10
16
|
return <ChatMessages key={active} chatId={active} username={username} />
|
|
@@ -5,6 +5,9 @@ import { HistoryList } from '../../components/HistoryList'
|
|
|
5
5
|
import { MessageInterceptor } from '../../state/ChatState'
|
|
6
6
|
import { HistoryItem } from './HistoryItem'
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Renders the list of conversations (history).
|
|
10
|
+
*/
|
|
8
11
|
export const ChatHistoryPanel = ({ interceptors }: { interceptors: MessageInterceptor[] }) => {
|
|
9
12
|
const [chats, { fetchNextPage, hasNextPage }] = aiClient.chats.useInfiniteQuery({ size: 40 })
|
|
10
13
|
return (
|
|
@@ -18,6 +18,9 @@ import { useHistoryDictionary } from './dictionary'
|
|
|
18
18
|
import { HistoryItemBox } from './styled'
|
|
19
19
|
import { findStack, findWorkspace, getAllAgents } from './utils'
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Renders an item of the list of conversations (history).
|
|
23
|
+
*/
|
|
21
24
|
export const HistoryItem = ({ item, interceptors }: { item: ConversationResponse, interceptors: MessageInterceptor[] }) => {
|
|
22
25
|
const t = useHistoryDictionary()
|
|
23
26
|
const [isLoading, setLoading] = useState(false)
|
|
@@ -6,7 +6,17 @@ import { MessageInterceptor } from '../../state/ChatState'
|
|
|
6
6
|
import { ChatHistoryPanel } from './ChatHistoryPanel'
|
|
7
7
|
import { useHistoryDictionary } from './dictionary'
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
interface Props {
|
|
10
|
+
/**
|
|
11
|
+
* The chat interceptors to use when recreating a ChatState from the history.
|
|
12
|
+
*/
|
|
13
|
+
interceptors: MessageInterceptor[],
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Renders the Chat History in the Right Panel if this is the panel that is currently opened.
|
|
18
|
+
*/
|
|
19
|
+
export const ChatHistory = ({ interceptors }: Props) => {
|
|
10
20
|
const t = useHistoryDictionary()
|
|
11
21
|
const panel = useWidgetState('panel')
|
|
12
22
|
const { open } = useRightPanel()
|