@stack-spot/ai-chat-widget 0.5.0 → 0.7.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/dist/StackspotAIWidget.d.ts.map +1 -1
- package/dist/StackspotAIWidget.js +3 -2
- package/dist/StackspotAIWidget.js.map +1 -1
- package/dist/features.d.ts +1 -1
- package/dist/features.d.ts.map +1 -1
- package/dist/features.js +1 -0
- package/dist/features.js.map +1 -1
- package/dist/state/ChatEntry.d.ts +1 -1
- package/dist/state/ChatEntry.d.ts.map +1 -1
- package/dist/state/ChatEntry.js +2 -2
- package/dist/state/ChatEntry.js.map +1 -1
- package/dist/state/ChatState.d.ts +15 -1
- package/dist/state/ChatState.d.ts.map +1 -1
- package/dist/state/ChatState.js.map +1 -1
- package/dist/state/WidgetState.d.ts +0 -4
- package/dist/state/WidgetState.d.ts.map +1 -1
- package/dist/state/WidgetState.js.map +1 -1
- package/dist/utils/chat.d.ts.map +1 -1
- package/dist/utils/chat.js +2 -3
- package/dist/utils/chat.js.map +1 -1
- package/dist/utils/programming-languages.d.ts +6 -0
- package/dist/utils/programming-languages.d.ts.map +1 -0
- package/dist/utils/programming-languages.js +463 -0
- package/dist/utils/programming-languages.js.map +1 -0
- package/dist/views/Agents.js +4 -5
- package/dist/views/Agents.js.map +1 -1
- package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
- package/dist/views/Chat/ChatMessage.js +5 -3
- package/dist/views/Chat/ChatMessage.js.map +1 -1
- package/dist/views/Chat/styled.d.ts.map +1 -1
- package/dist/views/Chat/styled.js +8 -0
- package/dist/views/Chat/styled.js.map +1 -1
- package/dist/views/ChatHistory/HistoryItem.d.ts.map +1 -1
- package/dist/views/ChatHistory/HistoryItem.js +4 -2
- package/dist/views/ChatHistory/HistoryItem.js.map +1 -1
- package/dist/views/ChatHistory/utils.d.ts +2 -1
- package/dist/views/ChatHistory/utils.d.ts.map +1 -1
- package/dist/views/ChatHistory/utils.js.map +1 -1
- package/dist/views/Editor.d.ts.map +1 -1
- package/dist/views/Editor.js +87 -1
- package/dist/views/Editor.js.map +1 -1
- package/dist/views/MessageInput/ButtonGroup.d.ts.map +1 -1
- package/dist/views/MessageInput/ButtonGroup.js +2 -2
- package/dist/views/MessageInput/ButtonGroup.js.map +1 -1
- package/dist/views/MessageInput/InfoBar.d.ts.map +1 -1
- package/dist/views/MessageInput/InfoBar.js +9 -2
- package/dist/views/MessageInput/InfoBar.js.map +1 -1
- package/dist/views/MessageInput/dictionary.d.ts +1 -1
- package/dist/views/MessageInput/dictionary.d.ts.map +1 -1
- package/dist/views/MessageInput/dictionary.js +4 -0
- package/dist/views/MessageInput/dictionary.js.map +1 -1
- package/dist/views/MessageInput/index.d.ts.map +1 -1
- package/dist/views/MessageInput/index.js +4 -1
- package/dist/views/MessageInput/index.js.map +1 -1
- package/package.json +3 -1
- package/src/StackspotAIWidget.tsx +3 -1
- package/src/chat-interceptors/send-message.ts +1 -1
- package/src/features.ts +2 -1
- package/src/state/ChatEntry.ts +2 -2
- package/src/state/ChatState.ts +13 -1
- package/src/state/WidgetState.ts +0 -4
- package/src/utils/chat.ts +2 -3
- package/src/utils/programming-languages.ts +462 -0
- package/src/views/Agents.tsx +4 -4
- package/src/views/Chat/ChatMessage.tsx +16 -7
- package/src/views/Chat/styled.ts +8 -0
- package/src/views/ChatHistory/HistoryItem.tsx +4 -2
- package/src/views/ChatHistory/utils.ts +2 -1
- package/src/views/Editor.tsx +126 -1
- package/src/views/MessageInput/ButtonGroup.tsx +6 -1
- package/src/views/MessageInput/InfoBar.tsx +14 -1
- package/src/views/MessageInput/dictionary.ts +4 -0
- package/src/views/MessageInput/index.tsx +4 -1
package/src/views/Editor.tsx
CHANGED
|
@@ -1 +1,126 @@
|
|
|
1
|
-
|
|
1
|
+
import { Text } from '@citric/core'
|
|
2
|
+
import { LoadingCircular } from '@citric/ui'
|
|
3
|
+
import MonacoEditor, { OnMount } from '@monaco-editor/react'
|
|
4
|
+
import { Select } from '@stack-spot/portal-components/Select'
|
|
5
|
+
import { useThemeKind } from '@stack-spot/portal-theme'
|
|
6
|
+
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
7
|
+
import { debounce } from 'lodash'
|
|
8
|
+
import { IDisposable } from 'monaco-editor'
|
|
9
|
+
import { useCallback, useEffect, useMemo, useRef } from 'react'
|
|
10
|
+
import { styled } from 'styled-components'
|
|
11
|
+
import { useCurrentChat, useCurrentChatState, useWidget, useWidgetState } from '../context/hooks'
|
|
12
|
+
import { useRightPanel } from '../right-panel/hooks'
|
|
13
|
+
import { languages } from '../utils/programming-languages'
|
|
14
|
+
|
|
15
|
+
const DEFAULT_LANGUAGE = 'python'
|
|
16
|
+
const MIN_SELECTION_UPDATE_MS = 200
|
|
17
|
+
|
|
18
|
+
const EditorBox = styled.div`
|
|
19
|
+
flex: 1;
|
|
20
|
+
|
|
21
|
+
.monaco-editor {
|
|
22
|
+
--vscode-editor-background: transparent !important;
|
|
23
|
+
--vscode-editorGutter-background: transparent !important;
|
|
24
|
+
}
|
|
25
|
+
`
|
|
26
|
+
|
|
27
|
+
const TitleBox = styled.div`
|
|
28
|
+
.language-selector {
|
|
29
|
+
width: 150px;
|
|
30
|
+
position: absolute;
|
|
31
|
+
top: 21px;
|
|
32
|
+
right: 61px;
|
|
33
|
+
|
|
34
|
+
.options {
|
|
35
|
+
max-height: 250px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.current-value {
|
|
39
|
+
padding: 2px 8px;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
`
|
|
43
|
+
|
|
44
|
+
export const Editor = () => {
|
|
45
|
+
const t = useTranslate(dictionary)
|
|
46
|
+
const panel = useWidgetState('panel')
|
|
47
|
+
const { open } = useRightPanel()
|
|
48
|
+
const widget = useWidget()
|
|
49
|
+
const chat = useCurrentChat()
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (panel === 'editor') open(
|
|
53
|
+
<EditorPanel key={chat.id} />,
|
|
54
|
+
{
|
|
55
|
+
title: <Title key={chat.id} />,
|
|
56
|
+
description: t.description,
|
|
57
|
+
onClose: () => widget.set('panel', undefined),
|
|
58
|
+
},
|
|
59
|
+
)
|
|
60
|
+
}, [panel, t, chat])
|
|
61
|
+
|
|
62
|
+
return null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const Title = () => {
|
|
66
|
+
const languageValue = useCurrentChatState('codeLanguage') || DEFAULT_LANGUAGE
|
|
67
|
+
const language = useMemo(() => languages.find(l => l.value === languageValue), [languageValue])
|
|
68
|
+
const chat = useCurrentChat()
|
|
69
|
+
return (
|
|
70
|
+
<TitleBox>
|
|
71
|
+
<Text appearance="h5">Editor</Text>
|
|
72
|
+
<Select
|
|
73
|
+
options={languages}
|
|
74
|
+
renderLabel={l => l.label}
|
|
75
|
+
renderValue={l => l.value}
|
|
76
|
+
value={language}
|
|
77
|
+
onChange={l => chat.set('codeLanguage', l.value)}
|
|
78
|
+
className="language-selector"
|
|
79
|
+
/>
|
|
80
|
+
</TitleBox>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const EditorPanel = () => {
|
|
85
|
+
const themeKind = useThemeKind()
|
|
86
|
+
const value = useCurrentChatState('code')
|
|
87
|
+
const language = useCurrentChatState('codeLanguage') || DEFAULT_LANGUAGE
|
|
88
|
+
const chat = useCurrentChat()
|
|
89
|
+
const selectionObserver = useRef<IDisposable | undefined>()
|
|
90
|
+
|
|
91
|
+
const setup: OnMount = useCallback((editor) => {
|
|
92
|
+
selectionObserver.current = editor.onDidChangeCursorSelection(debounce((e) => {
|
|
93
|
+
const selectedText = editor.getModel()?.getValueInRange(e.selection)
|
|
94
|
+
chat.set('codeSelection', selectedText?.trim() ? selectedText : undefined)
|
|
95
|
+
}, MIN_SELECTION_UPDATE_MS))
|
|
96
|
+
}, [])
|
|
97
|
+
|
|
98
|
+
useEffect(() => () => {
|
|
99
|
+
chat.set('codeSelection', undefined)
|
|
100
|
+
selectionObserver.current?.dispose()
|
|
101
|
+
}, [])
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<EditorBox>
|
|
105
|
+
<MonacoEditor
|
|
106
|
+
height="100%"
|
|
107
|
+
language={language}
|
|
108
|
+
theme={themeKind === 'dark' ? 'vs-dark' : 'light'}
|
|
109
|
+
options={{ minimap: { enabled: false } }}
|
|
110
|
+
value={value}
|
|
111
|
+
onChange={v => chat.set('code', v)}
|
|
112
|
+
loading={<LoadingCircular />}
|
|
113
|
+
onMount={setup}
|
|
114
|
+
/>
|
|
115
|
+
</EditorBox>
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const dictionary = {
|
|
120
|
+
en: {
|
|
121
|
+
description: 'The selected code in the editor below will be used as part of your questions.',
|
|
122
|
+
},
|
|
123
|
+
pt: {
|
|
124
|
+
description: 'O código selecionado no editor abaixo será usado como parte das suas perguntas.',
|
|
125
|
+
},
|
|
126
|
+
} satisfies Dictionary
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChevronRight, KnowledgeSource, Send, Stack, Times, Workspace } from '@citric/icons'
|
|
1
|
+
import { ChevronRight, Code, KnowledgeSource, Send, Stack, Times, Workspace } from '@citric/icons'
|
|
2
2
|
import { IconButton } from '@citric/ui'
|
|
3
3
|
import { MiniLogo } from '@stack-spot/portal-components/svg'
|
|
4
4
|
import { listToClass } from '@stack-spot/portal-theme'
|
|
@@ -62,6 +62,11 @@ export const ButtonGroup = ({ features, onSend, onCancel, expanded, setExpanded,
|
|
|
62
62
|
<Stack />
|
|
63
63
|
</IconButton>
|
|
64
64
|
)}
|
|
65
|
+
{features.editor && (
|
|
66
|
+
<IconButton aria-label={t.stack} title={t.stack} onClick={() => widget.set('panel', 'editor')}>
|
|
67
|
+
<Code />
|
|
68
|
+
</IconButton>
|
|
69
|
+
)}
|
|
65
70
|
</div>
|
|
66
71
|
<IconButton
|
|
67
72
|
title={expanded ? t.collapse : t.expand}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Times, TimesMini } from '@citric/icons'
|
|
2
2
|
import { Badge, IconButton } from '@citric/ui'
|
|
3
|
+
import { loader } from '@monaco-editor/react'
|
|
3
4
|
import { ColorPaletteName, listToClass } from '@stack-spot/portal-theme'
|
|
4
5
|
import { useCallback, useMemo } from 'react'
|
|
5
6
|
import { FadingOverflow } from '../../components/FadingOverflow'
|
|
@@ -26,7 +27,8 @@ export const InfoBar = () => {
|
|
|
26
27
|
const currentStack = useCurrentChatState('stack')
|
|
27
28
|
const currentWorkspace = useCurrentChatState('workspace')
|
|
28
29
|
const currentKnowledgeSources = useCurrentChatState('knowledgeSources')
|
|
29
|
-
const
|
|
30
|
+
const currentSelection = useCurrentChatState('codeSelection')
|
|
31
|
+
const visible = !!(currentStack || currentWorkspace || currentKnowledgeSources?.length || currentSelection)
|
|
30
32
|
const ksToRender = useMemo(() => currentKnowledgeSources?.map(ks => {
|
|
31
33
|
const onDismiss = () => chat.set('knowledgeSources', currentKnowledgeSources.filter(({ id }) => id !== ks.id))
|
|
32
34
|
return <li key={ks.id}><InfoBadge label={ks.label} dismiss={t.removeKS} color="teal" onDismiss={onDismiss} /></li>
|
|
@@ -36,6 +38,12 @@ export const InfoBar = () => {
|
|
|
36
38
|
chat.set('knowledgeSources', [])
|
|
37
39
|
chat.set('stack', undefined)
|
|
38
40
|
chat.set('workspace', undefined)
|
|
41
|
+
removeCodeSelection()
|
|
42
|
+
}, [])
|
|
43
|
+
|
|
44
|
+
const removeCodeSelection = useCallback(() => {
|
|
45
|
+
const editor = loader.__getMonacoInstance()?.editor
|
|
46
|
+
editor?.getEditors()[0].setSelection({ startLineNumber: 0, endLineNumber: 0, endColumn: 0, startColumn: 0 })
|
|
39
47
|
}, [])
|
|
40
48
|
|
|
41
49
|
return (
|
|
@@ -45,6 +53,11 @@ export const InfoBar = () => {
|
|
|
45
53
|
<IconButton aria-label={t.removeConfig} title={t.removeConfig} onClick={removeAll}><Times /></IconButton>
|
|
46
54
|
<FadingOverflow className="list-overflow" scroll="arrows" enableHorizontalScrollWithVerticalWheel>
|
|
47
55
|
<ul>
|
|
56
|
+
{currentSelection && (
|
|
57
|
+
<li>
|
|
58
|
+
<InfoBadge label={t.selected} dismiss={t.removeSelection} color="blue" onDismiss={removeCodeSelection} />
|
|
59
|
+
</li>
|
|
60
|
+
)}
|
|
48
61
|
{currentStack && (
|
|
49
62
|
<li>
|
|
50
63
|
<InfoBadge label={currentStack.label} dismiss={t.removeStack} color="cyan" onDismiss={() => chat.set('stack', undefined)} />
|
|
@@ -15,6 +15,8 @@ const dictionary = {
|
|
|
15
15
|
removeStack: 'Stop using the current stack',
|
|
16
16
|
removeWorkspace: 'Stop using the current workspace',
|
|
17
17
|
removeKS: 'Stop using this knowledge source',
|
|
18
|
+
selected: 'Selected',
|
|
19
|
+
removeSelection: 'Remove current code selection',
|
|
18
20
|
},
|
|
19
21
|
pt: {
|
|
20
22
|
stack: 'Selecionar stack',
|
|
@@ -30,6 +32,8 @@ const dictionary = {
|
|
|
30
32
|
removeStack: 'Parar de usar a stack atual',
|
|
31
33
|
removeWorkspace: 'Parar de usar o workspace atual',
|
|
32
34
|
removeKS: 'Parar de usar este knowledge source',
|
|
35
|
+
selected: 'Selecionado',
|
|
36
|
+
removeSelection: 'Desfazer seleção de código',
|
|
33
37
|
},
|
|
34
38
|
} satisfies Dictionary
|
|
35
39
|
|
|
@@ -28,7 +28,10 @@ export const MessageInput = ({ features }: Props) => {
|
|
|
28
28
|
const onSend = useCallback(async () => {
|
|
29
29
|
const message = chat.get('nextMessage')
|
|
30
30
|
if (!message) return
|
|
31
|
-
chat.
|
|
31
|
+
const code = chat.get('codeSelection')
|
|
32
|
+
const language = chat.get('codeLanguage')
|
|
33
|
+
const prompt = code ? `${message}\n\`\`\`${language}\n${code}\n\`\`\`` : message
|
|
34
|
+
chat.pushMessage(ChatEntry.createUserEntry(prompt, true))
|
|
32
35
|
chat.set('nextMessage', '')
|
|
33
36
|
setFocused(false)
|
|
34
37
|
}, [chat])
|