@stack-spot/ai-chat-widget 1.13.2-beta.0 → 1.13.2
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 +35 -0
- package/dist/StackspotAIWidget.d.ts.map +1 -1
- package/dist/StackspotAIWidget.js +5 -2
- package/dist/StackspotAIWidget.js.map +1 -1
- package/dist/app-metadata.json +3 -3
- package/dist/chat-interceptors/send-message.d.ts.map +1 -1
- package/dist/chat-interceptors/send-message.js +2 -0
- package/dist/chat-interceptors/send-message.js.map +1 -1
- package/dist/components/Markdown.d.ts.map +1 -1
- package/dist/components/Markdown.js +1 -1
- package/dist/components/Markdown.js.map +1 -1
- package/dist/components/StackedBadge.d.ts +14 -0
- package/dist/components/StackedBadge.d.ts.map +1 -0
- package/dist/components/StackedBadge.js +56 -0
- package/dist/components/StackedBadge.js.map +1 -0
- package/dist/components/ToolBadge.d.ts +14 -0
- package/dist/components/ToolBadge.d.ts.map +1 -0
- package/dist/components/ToolBadge.js +108 -0
- package/dist/components/ToolBadge.js.map +1 -0
- package/dist/state/ChatEntry.d.ts +9 -16
- package/dist/state/ChatEntry.d.ts.map +1 -1
- package/dist/state/ChatEntry.js.map +1 -1
- package/dist/state/ChatState.d.ts +0 -1
- package/dist/state/ChatState.d.ts.map +1 -1
- package/dist/state/WidgetState.d.ts +3 -4
- package/dist/state/WidgetState.d.ts.map +1 -1
- package/dist/state/WidgetState.js +1 -12
- package/dist/state/WidgetState.js.map +1 -1
- package/dist/utils/check-is-trial.d.ts +2 -0
- package/dist/utils/check-is-trial.d.ts.map +1 -0
- package/dist/utils/check-is-trial.js +6 -0
- package/dist/utils/check-is-trial.js.map +1 -0
- package/dist/utils/tools.d.ts +7 -0
- package/dist/utils/tools.d.ts.map +1 -0
- package/dist/utils/tools.js +9 -0
- package/dist/utils/tools.js.map +1 -0
- package/dist/views/Agents/AgentDescription.d.ts.map +1 -1
- package/dist/views/Agents/AgentDescription.js +11 -1
- package/dist/views/Agents/AgentDescription.js.map +1 -1
- package/dist/views/Agents/AgentsPanel.d.ts.map +1 -1
- package/dist/views/Agents/AgentsPanel.js +13 -6
- package/dist/views/Agents/AgentsPanel.js.map +1 -1
- package/dist/views/Agents/AgentsTab.d.ts.map +1 -1
- package/dist/views/Agents/AgentsTab.js +10 -8
- package/dist/views/Agents/AgentsTab.js.map +1 -1
- package/dist/views/Agents/dictionary.d.ts +1 -1
- package/dist/views/Agents/dictionary.d.ts.map +1 -1
- package/dist/views/Agents/dictionary.js +2 -0
- package/dist/views/Agents/dictionary.js.map +1 -1
- package/dist/views/Agents/styled.js +1 -1
- package/dist/views/Chat/AgentInfo.js +3 -3
- package/dist/views/Chat/AgentInfo.js.map +1 -1
- package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
- package/dist/views/Chat/ChatMessage.js +19 -4
- package/dist/views/Chat/ChatMessage.js.map +1 -1
- package/dist/views/Chat/StepsList.d.ts +2 -2
- package/dist/views/Chat/StepsList.d.ts.map +1 -1
- package/dist/views/Chat/StepsList.js +2 -2
- package/dist/views/Chat/StepsList.js.map +1 -1
- package/dist/views/Chat/styled.d.ts.map +1 -1
- package/dist/views/Chat/styled.js +21 -12
- package/dist/views/Chat/styled.js.map +1 -1
- package/dist/views/ChatTabSelection.d.ts.map +1 -1
- package/dist/views/ChatTabSelection.js +16 -2
- package/dist/views/ChatTabSelection.js.map +1 -1
- package/dist/views/KnowledgeSources.d.ts.map +1 -1
- package/dist/views/KnowledgeSources.js +10 -5
- package/dist/views/KnowledgeSources.js.map +1 -1
- package/dist/views/MessageInput/AgentSelector.d.ts +2 -1
- package/dist/views/MessageInput/AgentSelector.d.ts.map +1 -1
- package/dist/views/MessageInput/AgentSelector.js +15 -8
- package/dist/views/MessageInput/AgentSelector.js.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.d.ts +2 -1
- package/dist/views/MessageInput/QuickCommandSelector.d.ts.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.js +2 -2
- package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -1
- package/dist/views/MessageInput/index.d.ts.map +1 -1
- package/dist/views/MessageInput/index.js +4 -2
- package/dist/views/MessageInput/index.js.map +1 -1
- package/dist/views/Stacks.d.ts.map +1 -1
- package/dist/views/Stacks.js +10 -5
- package/dist/views/Stacks.js.map +1 -1
- package/dist/views/{Tools → Steps}/FlowChart/HandleGroup.d.ts.map +1 -1
- package/dist/views/{Tools → Steps}/FlowChart/HandleGroup.js.map +1 -1
- package/dist/views/{Tools → Steps}/FlowChart/NodeStep.d.ts.map +1 -1
- package/dist/views/Steps/FlowChart/NodeStep.js +13 -0
- package/dist/views/Steps/FlowChart/NodeStep.js.map +1 -0
- package/dist/views/Steps/FlowChart/index.d.ts +10 -0
- package/dist/views/Steps/FlowChart/index.d.ts.map +1 -0
- package/dist/views/{Tools → Steps}/FlowChart/index.js +1 -5
- package/dist/views/{Tools → Steps}/FlowChart/index.js.map +1 -1
- package/dist/views/{Tools → Steps}/FlowChart/layout.d.ts.map +1 -1
- package/dist/views/{Tools → Steps}/FlowChart/layout.js.map +1 -1
- package/dist/views/{Tools → Steps}/FlowChart/styled.d.ts.map +1 -1
- package/dist/views/{Tools → Steps}/FlowChart/styled.js +0 -49
- package/dist/views/{Tools → Steps}/FlowChart/styled.js.map +1 -1
- package/dist/views/{Tools → Steps}/FlowChart/types.d.ts +3 -3
- package/dist/views/Steps/FlowChart/types.d.ts.map +1 -0
- package/dist/views/Steps/FlowChart/types.js.map +1 -0
- package/dist/views/Steps/StepModal.d.ts +9 -0
- package/dist/views/Steps/StepModal.d.ts.map +1 -0
- package/dist/views/Steps/StepModal.js +124 -0
- package/dist/views/Steps/StepModal.js.map +1 -0
- package/dist/views/Steps/StepsPanel.d.ts +6 -0
- package/dist/views/Steps/StepsPanel.d.ts.map +1 -0
- package/dist/views/{Tools/ToolsPanel.js → Steps/StepsPanel.js} +3 -3
- package/dist/views/{Tools/ToolsPanel.js.map → Steps/StepsPanel.js.map} +1 -1
- package/dist/views/{Tools → Steps}/dictionary.d.ts +9 -11
- package/dist/views/Steps/dictionary.d.ts.map +1 -0
- package/dist/views/{Tools → Steps}/dictionary.js +9 -11
- package/dist/views/Steps/dictionary.js.map +1 -0
- package/dist/views/{Tools → Steps}/index.d.ts +1 -1
- package/dist/views/Steps/index.d.ts.map +1 -0
- package/dist/views/{Tools → Steps}/index.js +10 -10
- package/dist/views/{Tools → Steps}/index.js.map +1 -1
- package/dist/views/Steps/utils.d.ts +6 -0
- package/dist/views/Steps/utils.d.ts.map +1 -0
- package/dist/views/{Tools → Steps}/utils.js.map +1 -1
- package/dist/views/Tools.d.ts +2 -0
- package/dist/views/Tools.d.ts.map +1 -0
- package/dist/views/Tools.js +51 -0
- package/dist/views/Tools.js.map +1 -0
- package/package.json +2 -2
- package/src/StackspotAIWidget.tsx +8 -3
- package/src/app-metadata.json +3 -3
- package/src/chat-interceptors/send-message.ts +2 -0
- package/src/components/Markdown.tsx +1 -0
- package/src/components/StackedBadge.tsx +77 -0
- package/src/components/ToolBadge.tsx +146 -0
- package/src/state/ChatEntry.ts +9 -17
- package/src/state/ChatState.ts +1 -1
- package/src/state/WidgetState.ts +4 -16
- package/src/utils/check-is-trial.ts +6 -0
- package/src/utils/tools.ts +11 -0
- package/src/views/Agents/AgentDescription.tsx +14 -0
- package/src/views/Agents/AgentsPanel.tsx +11 -3
- package/src/views/Agents/AgentsTab.tsx +11 -10
- package/src/views/Agents/dictionary.ts +2 -0
- package/src/views/Agents/styled.ts +1 -1
- package/src/views/Chat/AgentInfo.tsx +4 -4
- package/src/views/Chat/ChatMessage.tsx +30 -4
- package/src/views/Chat/StepsList.tsx +6 -6
- package/src/views/Chat/styled.ts +21 -12
- package/src/views/ChatTabSelection.tsx +22 -4
- package/src/views/KnowledgeSources.tsx +9 -3
- package/src/views/MessageInput/AgentSelector.tsx +19 -8
- package/src/views/MessageInput/QuickCommandSelector.tsx +3 -2
- package/src/views/MessageInput/index.tsx +5 -4
- package/src/views/Stacks.tsx +10 -4
- package/src/views/{Tools → Steps}/FlowChart/NodeStep.tsx +11 -23
- package/src/views/{Tools → Steps}/FlowChart/index.tsx +3 -7
- package/src/views/{Tools → Steps}/FlowChart/styled.ts +0 -49
- package/src/views/{Tools → Steps}/FlowChart/types.ts +3 -3
- package/src/views/Steps/StepModal.tsx +216 -0
- package/src/views/{Tools/ToolsPanel.tsx → Steps/StepsPanel.tsx} +2 -2
- package/src/views/{Tools → Steps}/dictionary.ts +9 -11
- package/src/views/{Tools → Steps}/index.tsx +10 -10
- package/src/views/{Tools → Steps}/utils.tsx +4 -4
- package/src/views/Tools.tsx +71 -0
- package/dist/utils/agent.d.ts +0 -2
- package/dist/utils/agent.d.ts.map +0 -1
- package/dist/utils/agent.js +0 -2
- package/dist/utils/agent.js.map +0 -1
- package/dist/views/Tools/FlowChart/NodeStep.js +0 -15
- package/dist/views/Tools/FlowChart/NodeStep.js.map +0 -1
- package/dist/views/Tools/FlowChart/index.d.ts +0 -9
- package/dist/views/Tools/FlowChart/index.d.ts.map +0 -1
- package/dist/views/Tools/FlowChart/types.d.ts.map +0 -1
- package/dist/views/Tools/FlowChart/types.js.map +0 -1
- package/dist/views/Tools/StepModal.d.ts +0 -9
- package/dist/views/Tools/StepModal.d.ts.map +0 -1
- package/dist/views/Tools/StepModal.js +0 -156
- package/dist/views/Tools/StepModal.js.map +0 -1
- package/dist/views/Tools/ToolsPanel.d.ts +0 -6
- package/dist/views/Tools/ToolsPanel.d.ts.map +0 -1
- package/dist/views/Tools/dictionary.d.ts.map +0 -1
- package/dist/views/Tools/dictionary.js.map +0 -1
- package/dist/views/Tools/index.d.ts.map +0 -1
- package/dist/views/Tools/utils.d.ts +0 -6
- package/dist/views/Tools/utils.d.ts.map +0 -1
- package/src/utils/agent.ts +0 -1
- package/src/views/Tools/StepModal.tsx +0 -247
- /package/dist/views/{Tools → Steps}/FlowChart/HandleGroup.d.ts +0 -0
- /package/dist/views/{Tools → Steps}/FlowChart/HandleGroup.js +0 -0
- /package/dist/views/{Tools → Steps}/FlowChart/NodeStep.d.ts +0 -0
- /package/dist/views/{Tools → Steps}/FlowChart/layout.d.ts +0 -0
- /package/dist/views/{Tools → Steps}/FlowChart/layout.js +0 -0
- /package/dist/views/{Tools → Steps}/FlowChart/styled.d.ts +0 -0
- /package/dist/views/{Tools → Steps}/FlowChart/types.js +0 -0
- /package/dist/views/{Tools → Steps}/utils.js +0 -0
- /package/src/views/{Tools → Steps}/FlowChart/HandleGroup.tsx +0 -0
- /package/src/views/{Tools → Steps}/FlowChart/layout.ts +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { IconBox, Text } from '@citric/core'
|
|
2
|
+
import { ChevronDown, Cog } from '@citric/icons'
|
|
3
|
+
import { IconButton } from '@citric/ui'
|
|
4
|
+
import { AnimatedHeight } from '@stack-spot/portal-components/AnimatedHeight'
|
|
5
|
+
import { ColorSchemeKey, listToClass, theme } from '@stack-spot/portal-theme'
|
|
6
|
+
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
7
|
+
import { get } from 'lodash'
|
|
8
|
+
import { DetailedHTMLProps, HTMLAttributes, useState } from 'react'
|
|
9
|
+
import { styled } from 'styled-components'
|
|
10
|
+
import { FastOmit } from 'styled-components/dist/types'
|
|
11
|
+
import { toPrecision } from '../views/Steps/utils'
|
|
12
|
+
|
|
13
|
+
interface Props extends FastOmit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never> {
|
|
14
|
+
name: string,
|
|
15
|
+
duration?: number,
|
|
16
|
+
image?: string,
|
|
17
|
+
description?: string,
|
|
18
|
+
appearance?: 'round' | 'square',
|
|
19
|
+
backgroundColor?: ColorSchemeKey,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const Styled = styled.div<{ $backgroundColor: ColorSchemeKey }>`
|
|
23
|
+
.tool-header-wrapper {
|
|
24
|
+
background-color: ${({ $backgroundColor }) => get(theme.color, $backgroundColor)};
|
|
25
|
+
border-radius: 8px;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.tool-header {
|
|
29
|
+
padding: 4px 8px 4px 4px;
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: column;
|
|
32
|
+
gap: 12px;
|
|
33
|
+
position: relative;
|
|
34
|
+
|
|
35
|
+
.title {
|
|
36
|
+
display: flex;
|
|
37
|
+
gap: 8px;
|
|
38
|
+
align-items: center;
|
|
39
|
+
.tool-image {
|
|
40
|
+
width: 24px;
|
|
41
|
+
height: 24px;
|
|
42
|
+
border-radius: 50%;
|
|
43
|
+
overflow: hidden;
|
|
44
|
+
flex-shrink: 0;
|
|
45
|
+
}
|
|
46
|
+
.name {
|
|
47
|
+
flex: 1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.btn-expand {
|
|
52
|
+
display: none;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.duration {
|
|
56
|
+
opacity: 0.7;
|
|
57
|
+
text-align: right;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&.with-description {
|
|
62
|
+
.tool-header {
|
|
63
|
+
&:before {
|
|
64
|
+
content: '';
|
|
65
|
+
top: 32px;
|
|
66
|
+
bottom: 8px;
|
|
67
|
+
left: 15px;
|
|
68
|
+
width: 1px;
|
|
69
|
+
background-color: ${theme.color.light[700]};
|
|
70
|
+
opacity: 0.3;
|
|
71
|
+
position: absolute;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.btn-expand {
|
|
75
|
+
display: flex;
|
|
76
|
+
transition: transform 0.3s ease-in-out;
|
|
77
|
+
&.open {
|
|
78
|
+
transform: rotate(180deg);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.description {
|
|
83
|
+
padding: 0 0 10px 20px;
|
|
84
|
+
opacity: 0.7;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
&.round {
|
|
90
|
+
.tool-header-wrapper {
|
|
91
|
+
border-radius: 30px;
|
|
92
|
+
}
|
|
93
|
+
&:not(.with-description) {
|
|
94
|
+
.tool-header-wrapper {
|
|
95
|
+
padding-right: 10px;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
`
|
|
100
|
+
|
|
101
|
+
export const ToolBadge = (
|
|
102
|
+
{ name, duration, image, description, appearance = 'square', backgroundColor = 'light.300', className, ...props }: Props,
|
|
103
|
+
) => {
|
|
104
|
+
const t = useTranslate(dictionary)
|
|
105
|
+
const [showDescription, setShowDescription] = useState(false)
|
|
106
|
+
const rootClass = listToClass([className, appearance, description && 'with-description'])
|
|
107
|
+
const wrapperClass = 'tool-header-wrapper'
|
|
108
|
+
|
|
109
|
+
const content = (
|
|
110
|
+
<div className="tool-header">
|
|
111
|
+
<div className="title">
|
|
112
|
+
{image ? <img src={image} className="tool-image" /> : <IconBox className="tool-image"><Cog /></IconBox>}
|
|
113
|
+
<Text colorScheme="light.700" className="name">{name}</Text>
|
|
114
|
+
{duration !== undefined && <Text colorScheme="light.700" className="duration">
|
|
115
|
+
{toPrecision(duration)}s
|
|
116
|
+
</Text>}
|
|
117
|
+
<IconButton
|
|
118
|
+
size="xs"
|
|
119
|
+
className={listToClass(['btn-expand', showDescription && 'open'])}
|
|
120
|
+
onClick={() => setShowDescription(v => !v)}
|
|
121
|
+
aria-label={showDescription ? t.close : t.open}
|
|
122
|
+
>
|
|
123
|
+
<ChevronDown />
|
|
124
|
+
</IconButton>
|
|
125
|
+
</div>
|
|
126
|
+
{showDescription && <Text className="description" colorScheme="light.700">{description}</Text>}
|
|
127
|
+
</div>
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<Styled {...props} $backgroundColor={backgroundColor} className={rootClass}>
|
|
132
|
+
{description ? <AnimatedHeight className={wrapperClass}>{content}</AnimatedHeight> : <div className={wrapperClass}>{content}</div>}
|
|
133
|
+
</Styled>
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const dictionary = {
|
|
138
|
+
en: {
|
|
139
|
+
open: 'Open',
|
|
140
|
+
close: 'Close',
|
|
141
|
+
},
|
|
142
|
+
pt: {
|
|
143
|
+
open: 'Abrir',
|
|
144
|
+
close: 'Fechar',
|
|
145
|
+
},
|
|
146
|
+
} satisfies Dictionary
|
package/src/state/ChatEntry.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { OneOfColorSchemes } from '@citric/core'
|
|
2
|
+
import { ChatStep } from '@stack-spot/portal-network'
|
|
2
3
|
import { ColorPaletteName } from '@stack-spot/portal-theme'
|
|
3
4
|
import { pull } from 'lodash'
|
|
4
5
|
import { LabeledWithImage } from './types'
|
|
@@ -57,24 +58,11 @@ export interface KnowledgeSource {
|
|
|
57
58
|
documentId: string,
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
export interface
|
|
61
|
+
export interface ChatTool {
|
|
61
62
|
id: string,
|
|
62
|
-
name: string,
|
|
63
|
-
description?: string,
|
|
64
63
|
image?: string,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
output?: string,
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export interface ChatEntryStep {
|
|
71
|
-
id: string,
|
|
72
|
-
type: 'planning' | 'step' | 'answer',
|
|
73
|
-
input?: string,
|
|
74
|
-
output?: string,
|
|
75
|
-
status: 'pending' | 'running' | 'success' | 'error',
|
|
76
|
-
duration?: number,
|
|
77
|
-
tools?: AgentTool[],
|
|
64
|
+
name: string,
|
|
65
|
+
description: string,
|
|
78
66
|
}
|
|
79
67
|
|
|
80
68
|
export interface TextChatEntry {
|
|
@@ -131,7 +119,11 @@ export interface TextChatEntry {
|
|
|
131
119
|
/**
|
|
132
120
|
* This entry may contain steps. If so, specify them in this array.
|
|
133
121
|
*/
|
|
134
|
-
steps?:
|
|
122
|
+
steps?: ChatStep[],
|
|
123
|
+
/**
|
|
124
|
+
* If any tool was used to generate the response, its id is returned in this list.
|
|
125
|
+
*/
|
|
126
|
+
tools?: string[],
|
|
135
127
|
/*
|
|
136
128
|
* Options for radio, checkbox or button type.
|
|
137
129
|
*/
|
package/src/state/ChatState.ts
CHANGED
package/src/state/WidgetState.ts
CHANGED
|
@@ -13,15 +13,15 @@ export interface WidgetProperties {
|
|
|
13
13
|
/**
|
|
14
14
|
* Current content of the right panel. Undefined for closed right panel.
|
|
15
15
|
*/
|
|
16
|
-
panel?: 'stack' | 'workspace' | 'agent' | 'ks' | 'editor' | 'history' | 'ks-details' | 'tools',
|
|
16
|
+
panel?: 'stack' | 'workspace' | 'agent' | 'ks' | 'editor' | 'history' | 'ks-details' | 'steps' | 'tools',
|
|
17
17
|
/**
|
|
18
18
|
* KS to use when the right panel "ks-details" is open.
|
|
19
19
|
*/
|
|
20
20
|
currentKSInPanel?: { name: string, slug: string, score: number, documentId: string },
|
|
21
21
|
/**
|
|
22
|
-
* The message to show in the tools panel.
|
|
22
|
+
* The message to show in the tools panel or the steps panel.
|
|
23
23
|
*/
|
|
24
|
-
|
|
24
|
+
currentMessageInPanel?: { chatId: string, messageId: number },
|
|
25
25
|
/**
|
|
26
26
|
* Whether or not the widget is in its minimized version.
|
|
27
27
|
*/
|
|
@@ -58,8 +58,6 @@ interface Options {
|
|
|
58
58
|
chatTabs?: ChatTabsController,
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
const untitledChatPrefix = 'Chat '
|
|
62
|
-
|
|
63
61
|
/**
|
|
64
62
|
* Holds the full state of the AI Chat Widget.
|
|
65
63
|
*
|
|
@@ -90,16 +88,6 @@ export class WidgetState extends ObservableState<WidgetProperties> {
|
|
|
90
88
|
this.createChat()
|
|
91
89
|
}
|
|
92
90
|
|
|
93
|
-
private getNextUntitledChatIndex() {
|
|
94
|
-
let max = 0
|
|
95
|
-
for (const chat of this.chatTabs.getAll()) {
|
|
96
|
-
const [, match] = chat.get('label').match(`${untitledChatPrefix}(\\d+)`) ?? []
|
|
97
|
-
const index = parseInt(match)
|
|
98
|
-
if (index > max) max = index
|
|
99
|
-
}
|
|
100
|
-
return max + 1
|
|
101
|
-
}
|
|
102
|
-
|
|
103
91
|
/**
|
|
104
92
|
* Utility function for adding a new chat to the chat tabs. This also selects the new tab.
|
|
105
93
|
* @param properties the chat properties (initial state).
|
|
@@ -109,7 +97,7 @@ export class WidgetState extends ObservableState<WidgetProperties> {
|
|
|
109
97
|
createChat({ label, ...properties }: Partial<ChatPropertiesWithOptionalFeatures> = {}, entries: ChatEntry[] = []) {
|
|
110
98
|
const chat = new ChatState({
|
|
111
99
|
id: ulid(),
|
|
112
|
-
initial: { label: label ||
|
|
100
|
+
initial: { label: label || 'Chat', features: this.chatFeatures, ...properties },
|
|
113
101
|
entries,
|
|
114
102
|
interceptors: this.interceptors,
|
|
115
103
|
untitled: !label,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BuiltinToolResponse, ToolkitsInAgentResponse } from '@stack-spot/portal-network/api/agent'
|
|
2
|
+
|
|
3
|
+
export type ToolWithImage = BuiltinToolResponse & { id: string, image?: string }
|
|
4
|
+
|
|
5
|
+
export function toolById(id: string, toolkits: ToolkitsInAgentResponse | undefined): ToolWithImage | undefined {
|
|
6
|
+
for (const toolkit of toolkits?.builtins ?? []) {
|
|
7
|
+
for (const tool of toolkit.tools ?? []) {
|
|
8
|
+
if (tool.id === id) return { ...tool, id, image: toolkit.image_url }
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -2,6 +2,7 @@ import { Text } from '@citric/core'
|
|
|
2
2
|
import { Badge, Skeleton } from '@citric/ui'
|
|
3
3
|
import { agentClient } from '@stack-spot/portal-network'
|
|
4
4
|
import { useMemo } from 'react'
|
|
5
|
+
import { ToolBadge } from '../../components/ToolBadge'
|
|
5
6
|
import { useAgentsDictionary } from './dictionary'
|
|
6
7
|
import { AgentDescriptionBox } from './styled'
|
|
7
8
|
|
|
@@ -28,6 +29,15 @@ export const AgentDescription = ({ agentId, llm, description, numberOfKnowledgeS
|
|
|
28
29
|
}
|
|
29
30
|
return loadingKS
|
|
30
31
|
}, [numberOfKnowledgeSources])
|
|
32
|
+
const tools = useMemo(() => {
|
|
33
|
+
const result: React.ReactElement[] = []
|
|
34
|
+
for (const kit of agent?.toolkits?.builtins ?? []) {
|
|
35
|
+
for (const tool of kit.tools ?? []) {
|
|
36
|
+
result.push(<li key={tool.id}><ToolBadge name={tool.name || tool.id || 'unknown'} image={kit.image_url} /></li>)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return result
|
|
40
|
+
}, [agent])
|
|
31
41
|
|
|
32
42
|
return (
|
|
33
43
|
<AgentDescriptionBox>
|
|
@@ -39,6 +49,10 @@ export const AgentDescription = ({ agentId, llm, description, numberOfKnowledgeS
|
|
|
39
49
|
<Text appearance="microtext1" className="title">Knowledge sources</Text>
|
|
40
50
|
<ul>{isLoading ? skeleton : knowledgeSources}</ul>
|
|
41
51
|
</section>}
|
|
52
|
+
{!!tools.length && <section>
|
|
53
|
+
<Text appearance="microtext1" className="title">{t.tools}</Text>
|
|
54
|
+
<ul>{tools}</ul>
|
|
55
|
+
</section>}
|
|
42
56
|
{llm && <section>
|
|
43
57
|
<Text appearance="microtext1" className="title">LLM</Text>
|
|
44
58
|
<Badge palette="orange" appearance="square">{llm}</Badge>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { useMemo } from 'react'
|
|
1
2
|
import { RightPanelTabs } from '../../components/RightPanelTabs'
|
|
2
3
|
import { useCurrentChat } from '../../context/hooks'
|
|
4
|
+
import { checkIsTrial } from '../../utils/check-is-trial'
|
|
3
5
|
import { AgentsTab } from './AgentsTab'
|
|
4
6
|
import { useAgentsDictionary } from './dictionary'
|
|
5
7
|
|
|
@@ -9,11 +11,17 @@ import { useAgentsDictionary } from './dictionary'
|
|
|
9
11
|
export const AgentsPanel = () => {
|
|
10
12
|
const t = useAgentsDictionary()
|
|
11
13
|
const chat = useCurrentChat()
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
const isTrial = checkIsTrial()
|
|
15
|
+
|
|
16
|
+
const tabs= useMemo(() => isTrial ? [
|
|
17
|
+
{ title: t.builtin, content: <AgentsTab key="builtin" visibility="BUILT-IN" /> },
|
|
18
|
+
{ title: t.personal, content: <AgentsTab key="personal" visibility="PERSONAL" /> },
|
|
19
|
+
]: [
|
|
14
20
|
{ title: t.builtin, content: <AgentsTab key="builtin" visibility="BUILT-IN" /> },
|
|
15
21
|
{ title: t.personal, content: <AgentsTab key="personal" visibility="PERSONAL" /> },
|
|
16
22
|
{ title: t.shared, content: <AgentsTab key="shared" visibility="SHARED" /> },
|
|
17
23
|
{ title: t.account, content: <AgentsTab key="account" visibility="ACCOUNT" /> },
|
|
18
|
-
]
|
|
24
|
+
], [t, isTrial])
|
|
25
|
+
|
|
26
|
+
return <RightPanelTabs key={chat.id} tabs={tabs} />
|
|
19
27
|
}
|
|
@@ -9,7 +9,6 @@ import { DescribedRadioGroup } from '../../components/form/DescribedRadioGroup'
|
|
|
9
9
|
import { IconInput } from '../../components/IconInput'
|
|
10
10
|
import { useCurrentChat } from '../../context/hooks'
|
|
11
11
|
import { useRightPanel } from '../../right-panel/hooks'
|
|
12
|
-
import { isAgentDefault } from '../../utils/agent'
|
|
13
12
|
import { AgentDescription } from './AgentDescription'
|
|
14
13
|
import { useAgentsDictionary } from './dictionary'
|
|
15
14
|
import { AgentLabel } from './styled'
|
|
@@ -19,25 +18,27 @@ export const AgentsTab = ({ visibility }: { visibility: VisibilityLevel | 'BUILT
|
|
|
19
18
|
const { close } = useRightPanel()
|
|
20
19
|
const chat = useCurrentChat()
|
|
21
20
|
const [filter, setFilter] = useState('')
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
const defaultAgent = useMemo(() => ({
|
|
22
|
+
id: '',
|
|
23
|
+
name: 'StackSpot AI',
|
|
24
|
+
description: t.defaultAgentDescription,
|
|
25
|
+
llm_config: { model_slug: 'gpt4o' },
|
|
26
|
+
} as AgentResponse), [])
|
|
27
|
+
const agents = visibility === 'BUILT-IN' ? agentClient.publicAgents.useQuery({}) : agentClient.agents.useQuery({ visibility })
|
|
25
28
|
const [value, setValue] = useState<AgentResponse | undefined>(
|
|
26
29
|
chat.get('agent') ? agents.find(a => a.id === chat.get('agent')?.id) : defaultAgent,
|
|
27
30
|
)
|
|
28
31
|
const filtered = useMemo(
|
|
29
|
-
() => {
|
|
30
|
-
|
|
32
|
+
() => {
|
|
33
|
+
const ags = visibility === 'BUILT-IN' ? [defaultAgent as AgentResponse, ...agents] : agents
|
|
34
|
+
return filter ? ags.filter(a => a === value || a.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase())) : ags
|
|
31
35
|
},
|
|
32
36
|
[agents, filter, value],
|
|
33
37
|
)
|
|
34
38
|
|
|
35
39
|
function submit() {
|
|
36
40
|
if (value) {
|
|
37
|
-
chat.set('agent',
|
|
38
|
-
? { id: value.id, label: value.name, image: value.avatar, builtIn: visibility === 'BUILT-IN', slug: value.slug }
|
|
39
|
-
: undefined
|
|
40
|
-
)
|
|
41
|
+
chat.set('agent', value.id ? { id: value.id, label: value.name, image: value.avatar, builtIn: visibility === 'BUILT-IN' } : undefined)
|
|
41
42
|
}
|
|
42
43
|
close()
|
|
43
44
|
}
|
|
@@ -15,6 +15,7 @@ const dictionary = {
|
|
|
15
15
|
noDataDescription: 'Use the tabs above to try other categories or use the AI portal to create new agents.',
|
|
16
16
|
defaultAgentDescription: 'The StackSpot CodeGen is an advanced artificial intelligence agent designed to optimize and accelerate software development. Integrated directly into your integrated development environment, StackSpot CodeGen offers real-time code suggestions, helping developers write high-quality code more efficiently. With robust features such as creating Stacks AI, customized knowledge sources, and quick commands, StackSpot CodeGen contextualizes your development needs to provide the best answers and code suggestions.',
|
|
17
17
|
description: 'Description',
|
|
18
|
+
tools: 'Tools',
|
|
18
19
|
},
|
|
19
20
|
pt: {
|
|
20
21
|
title: 'Agentes',
|
|
@@ -30,6 +31,7 @@ const dictionary = {
|
|
|
30
31
|
noDataDescription: 'Use as abas acima para tentar outras categorias ou use o Portal AI para criar novos agentes.',
|
|
31
32
|
defaultAgentDescription: 'O StackSpot CodeGen é um agente de inteligência artificial avançado projetado para otimizar e acelerar o desenvolvimento de software. Integrado diretamente ao seu ambiente de desenvolvimento, o StackSpot CodeGen oferece sugestões de código em tempo real, ajudando os desenvolvedores a escreverem código de alta qualidade de forma mais eficiente. Com recursos robustos, como a criação de Stacks AI, Knowledge Sources personalizadas e comandos rápidos, o StackSpot CodeGen contextualiza suas necessidades de desenvolvimento para fornecer as melhores respostas e sugestões de código.',
|
|
32
33
|
description: 'Descrição',
|
|
34
|
+
tools: 'Ferramentas',
|
|
33
35
|
},
|
|
34
36
|
} satisfies Dictionary
|
|
35
37
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Text } from '@citric/core'
|
|
2
|
-
import {
|
|
1
|
+
import { IconBox, Text } from '@citric/core'
|
|
2
|
+
import { Agent } from '@citric/icons'
|
|
3
3
|
import { LabeledWithImage } from '../../state/types'
|
|
4
4
|
|
|
5
5
|
interface Props {
|
|
@@ -13,8 +13,8 @@ export const AgentInfo = ({ agent }: Props) => (
|
|
|
13
13
|
<>
|
|
14
14
|
{agent?.image
|
|
15
15
|
? <img src={agent.image} className="custom-agent-image" />
|
|
16
|
-
: <
|
|
16
|
+
: <IconBox className="default-image-wrapper" colorIcon="light.700"><Agent className="agent-image" /></IconBox>
|
|
17
17
|
}
|
|
18
|
-
<Text appearance="body2">{agent?.label || 'StackSpot AI
|
|
18
|
+
<Text appearance="body2">{agent?.label || 'StackSpot AI'}</Text>
|
|
19
19
|
</>
|
|
20
20
|
)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/* eslint-disable semi */
|
|
2
2
|
import { Box, Button, Checkbox, Flex, IconBox, Input, Label, Radio, Text } from '@citric/core'
|
|
3
|
-
import { Copy, Dislike, DislikeFill, Like, LikeFill, TimesCircle } from '@citric/icons'
|
|
3
|
+
import { Cog, Copy, Dislike, DislikeFill, Like, LikeFill, TimesCircle } from '@citric/icons'
|
|
4
4
|
import { Avatar, Badge, IconButton } from '@citric/ui'
|
|
5
|
+
import { agentClient } from '@stack-spot/portal-network'
|
|
5
6
|
import { listToClass } from '@stack-spot/portal-theme'
|
|
6
7
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
7
8
|
import { debounce } from 'lodash'
|
|
@@ -9,9 +10,11 @@ import { Dispatch, useCallback, useEffect, useMemo, useRef, useState } from 'rea
|
|
|
9
10
|
import { PhoneInput } from 'react-international-phone'
|
|
10
11
|
import 'react-international-phone/style.css'
|
|
11
12
|
import { Markdown } from '../../components/Markdown'
|
|
13
|
+
import { StackedBadge } from '../../components/StackedBadge'
|
|
12
14
|
import { useChatEntry, useCurrentChat, useWidget } from '../../context/hooks'
|
|
13
15
|
import { ChatEntry, SerializableAction, TextChatEntry } from '../../state/ChatEntry'
|
|
14
16
|
import { useDateFormatter } from '../../utils/date'
|
|
17
|
+
import { toolById } from '../../utils/tools'
|
|
15
18
|
import { AgentInfo } from './AgentInfo'
|
|
16
19
|
import { useChatScrollToBottomEffect } from './chat-scroll'
|
|
17
20
|
import { onCopyAll, onCopyCode, onLikeOrDislike } from './events'
|
|
@@ -82,7 +85,7 @@ const RenderInputsEntry = ({ isLast, entry, value, setValue, labels, setLabels }
|
|
|
82
85
|
{option.hasInput && option.value && labels.findIndex((label) => label === option.value) !== -1 &&
|
|
83
86
|
<Box w={4} ml={2}>
|
|
84
87
|
<Input name={entry.name} onChange={(data) => setValue([data.target.value])}
|
|
85
|
-
required={true} />
|
|
88
|
+
required={true} sx={{ height: '30px' }} />
|
|
86
89
|
</Box>
|
|
87
90
|
}
|
|
88
91
|
</Flex>
|
|
@@ -120,7 +123,7 @@ const RenderInputsEntry = ({ isLast, entry, value, setValue, labels, setLabels }
|
|
|
120
123
|
{option.hasInput && option.value && labels.findIndex((label) => label === option.value)!== -1 &&
|
|
121
124
|
<Box w={4} ml={2}>
|
|
122
125
|
<Input name={entry.name} {...entry.validations} onChange={(data) => handleChange(data)}
|
|
123
|
-
required={true}
|
|
126
|
+
required={true} sx={{ height: '30px' }} />
|
|
124
127
|
</Box>
|
|
125
128
|
}
|
|
126
129
|
</Flex>
|
|
@@ -163,6 +166,7 @@ export const ChatMessage = ({ message, username, isLast }: Props) => {
|
|
|
163
166
|
const chatRef = useRef<HTMLDivElement>(null)
|
|
164
167
|
const widget = useWidget()
|
|
165
168
|
const chat = useCurrentChat()
|
|
169
|
+
const [agent] = agentClient.agent.useStatefulQuery({ agentId: entry.agent?.id ?? '' }, { enabled: !!entry.agent?.id })
|
|
166
170
|
useChatScrollToBottomEffect(ref, [entry])
|
|
167
171
|
|
|
168
172
|
const detailKS = useCallback(({ name, slug, documentScore, documentId }: Required<TextChatEntry>['knowledgeSources'][number]) => {
|
|
@@ -249,10 +253,15 @@ export const ChatMessage = ({ message, username, isLast }: Props) => {
|
|
|
249
253
|
</form>
|
|
250
254
|
}
|
|
251
255
|
|
|
256
|
+
function openToolsPanel() {
|
|
257
|
+
widget.set('currentMessageInPanel', { chatId: chat.id, messageId: message.id })
|
|
258
|
+
widget.set('panel', 'tools')
|
|
259
|
+
}
|
|
260
|
+
|
|
252
261
|
return (entry.content || entry.error || !!entry.steps?.length) && (
|
|
253
262
|
<li className={entry.agentType} ref={ref}>
|
|
254
263
|
<div className="chat-message" ref={chatRef} onKeyDown={handleKeyDown} tabIndex={0}>
|
|
255
|
-
<div className=
|
|
264
|
+
<div className={`user-info ${entry.agentType}`}>{userInfo}</div>
|
|
256
265
|
{(entry.content || entry.steps) && <div className={listToClass(['message-content', entry.card && 'card'])}>
|
|
257
266
|
{!!entry.badges?.length && <div className="badges">
|
|
258
267
|
{entry.badges.map((b, index) => <Badge key={index} palette={b.color ?? 'cyan'} appearance="square">{b.label}</Badge>)}
|
|
@@ -268,6 +277,19 @@ export const ChatMessage = ({ message, username, isLast }: Props) => {
|
|
|
268
277
|
<Text appearance="microtext1">{entry.error}</Text>
|
|
269
278
|
</div>
|
|
270
279
|
)}
|
|
280
|
+
{!!entry.tools?.length && <StackedBadge
|
|
281
|
+
aria-label={t.openToolsPanel}
|
|
282
|
+
title={t.openToolsPanel}
|
|
283
|
+
tabIndex={0}
|
|
284
|
+
role="button"
|
|
285
|
+
className="tools-badge"
|
|
286
|
+
label={t.tools}
|
|
287
|
+
images={entry.tools.slice(0, 3).map((id) => {
|
|
288
|
+
const tool = toolById(id, agent?.toolkits)
|
|
289
|
+
return { key: id, name: tool?.name || id, icon: <Cog />, url: tool?.image }
|
|
290
|
+
})}
|
|
291
|
+
onClick={openToolsPanel}
|
|
292
|
+
/>}
|
|
271
293
|
{!!entry.knowledgeSources?.length && <div className="ks-box">
|
|
272
294
|
<Text appearance="microtext1" colorScheme="light.700">Knowledge Sources:</Text>
|
|
273
295
|
<ul>{entry.knowledgeSources.map((ks, index) => (
|
|
@@ -307,10 +329,14 @@ const dictionary = {
|
|
|
307
329
|
copy: 'Copy',
|
|
308
330
|
like: 'Like',
|
|
309
331
|
dislike: 'Dislike',
|
|
332
|
+
tools: 'Tools',
|
|
333
|
+
openToolsPanel: 'Open the tools panel to see more details.',
|
|
310
334
|
},
|
|
311
335
|
pt: {
|
|
312
336
|
copy: 'Copiar',
|
|
313
337
|
like: 'Gostei',
|
|
314
338
|
dislike: 'Não gostei',
|
|
339
|
+
tools: 'Ferramentas',
|
|
340
|
+
openToolsPanel: 'Abrir o painel de ferramentas para ver mais detalhes.',
|
|
315
341
|
},
|
|
316
342
|
} satisfies Dictionary
|
|
@@ -2,27 +2,27 @@ import { Button, IconBox, Text } from '@citric/core'
|
|
|
2
2
|
import { CheckCircleFill, Circle, PlayFill, TimesCircleFill } from '@citric/icons'
|
|
3
3
|
import { LoadingCircular } from '@citric/ui'
|
|
4
4
|
import { AnimatedHeight } from '@stack-spot/portal-components/AnimatedHeight'
|
|
5
|
+
import { ChatStep, StepChatStep } from '@stack-spot/portal-network'
|
|
5
6
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
6
7
|
import { findLastIndex } from 'lodash'
|
|
7
8
|
import { useState } from 'react'
|
|
8
9
|
import { useWidget } from '../../context/hooks'
|
|
9
|
-
import { ChatEntryStep } from '../../state/ChatEntry'
|
|
10
10
|
import { PropsOf } from '../../types'
|
|
11
11
|
|
|
12
12
|
interface Props {
|
|
13
|
-
steps:
|
|
13
|
+
steps: ChatStep[],
|
|
14
14
|
messageId: number,
|
|
15
15
|
chatId: string,
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
interface StepProps {
|
|
19
|
-
step:
|
|
19
|
+
step: StepChatStep,
|
|
20
20
|
index: number,
|
|
21
21
|
total: number,
|
|
22
22
|
onClick?: () => void,
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
function getStatusIcon(status:
|
|
25
|
+
function getStatusIcon(status: ChatStep['status']) {
|
|
26
26
|
const iconBoxProps: PropsOf<typeof IconBox> = { colorIcon: 'light.700', size: 'xs' }
|
|
27
27
|
switch (status) {
|
|
28
28
|
case 'error': return <IconBox {...iconBoxProps}><TimesCircleFill /></IconBox>
|
|
@@ -53,8 +53,8 @@ export const StepsList = ({ steps, chatId, messageId }: Props) => {
|
|
|
53
53
|
const widget = useWidget()
|
|
54
54
|
|
|
55
55
|
function openToolsPanel() {
|
|
56
|
-
widget.set('
|
|
57
|
-
widget.set('panel', '
|
|
56
|
+
widget.set('currentMessageInPanel', { chatId, messageId })
|
|
57
|
+
widget.set('panel', 'steps')
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
return (
|
package/src/views/Chat/styled.ts
CHANGED
|
@@ -38,6 +38,10 @@ export const ChatList: IStyledComponentBase<
|
|
|
38
38
|
display: flex;
|
|
39
39
|
flex-direction: row;
|
|
40
40
|
gap: 10px;
|
|
41
|
+
|
|
42
|
+
&.bot {
|
|
43
|
+
align-items: center;
|
|
44
|
+
}
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
.chat-message {
|
|
@@ -82,23 +86,19 @@ export const ChatList: IStyledComponentBase<
|
|
|
82
86
|
gap: 4px;
|
|
83
87
|
|
|
84
88
|
.default-image-wrapper {
|
|
85
|
-
width:
|
|
86
|
-
height:
|
|
87
|
-
border-radius:
|
|
89
|
+
width: 32px;
|
|
90
|
+
height: 32px;
|
|
91
|
+
border-radius: 50%;
|
|
88
92
|
background-color: ${theme.color.light[300]};
|
|
89
93
|
display: flex;
|
|
90
94
|
align-items: center;
|
|
91
95
|
justify-content: center;
|
|
92
|
-
|
|
93
|
-
.agent-image {
|
|
94
|
-
width: 18px;
|
|
95
|
-
height: 18px;
|
|
96
|
-
}
|
|
96
|
+
border: 1px solid ${theme.color.light[600]};
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
.custom-agent-image {
|
|
100
|
-
width:
|
|
101
|
-
height:
|
|
100
|
+
width: 32px;
|
|
101
|
+
height: 32px;
|
|
102
102
|
border-radius: 50%;
|
|
103
103
|
}
|
|
104
104
|
}
|
|
@@ -149,11 +149,11 @@ export const ChatList: IStyledComponentBase<
|
|
|
149
149
|
background-color: ${theme.color.light[500]};
|
|
150
150
|
border-radius: 4px;
|
|
151
151
|
|
|
152
|
-
> p:first-child {
|
|
152
|
+
.markdown > p:first-child {
|
|
153
153
|
margin-top: 0;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
> p:last-child {
|
|
156
|
+
.markdown > p:last-child {
|
|
157
157
|
margin-bottom: 0;
|
|
158
158
|
}
|
|
159
159
|
}
|
|
@@ -244,4 +244,13 @@ export const ChatList: IStyledComponentBase<
|
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
|
+
|
|
248
|
+
.markdown img {
|
|
249
|
+
max-width: 70%;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.tools-badge {
|
|
253
|
+
align-self: start;
|
|
254
|
+
cursor: pointer;
|
|
255
|
+
}
|
|
247
256
|
`
|