@stack-spot/ai-chat-widget 2.2.0-beta.1 → 2.3.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -25
- package/dist/StackspotAIWidget.d.ts +5 -1
- package/dist/StackspotAIWidget.d.ts.map +1 -1
- package/dist/StackspotAIWidget.js +2 -2
- package/dist/StackspotAIWidget.js.map +1 -1
- package/dist/app-metadata.json +5 -5
- package/dist/chat-interceptors/send-message.d.ts.map +1 -1
- package/dist/chat-interceptors/send-message.js +1 -125
- package/dist/chat-interceptors/send-message.js.map +1 -1
- package/dist/state/ChatEntry.d.ts.map +1 -1
- package/dist/state/ChatState.d.ts +0 -8
- package/dist/state/ChatState.d.ts.map +1 -1
- package/dist/state/ChatState.js.map +1 -1
- package/dist/utils/chat.d.ts.map +1 -1
- package/dist/utils/chat.js +0 -1
- package/dist/utils/chat.js.map +1 -1
- package/dist/utils/check-is-trial.d.ts.map +1 -1
- package/dist/utils/check-is-trial.js +6 -2
- package/dist/utils/check-is-trial.js.map +1 -1
- package/dist/views/Agents/AgentsTab.d.ts.map +1 -1
- package/dist/views/Agents/AgentsTab.js +4 -3
- package/dist/views/Agents/AgentsTab.js.map +1 -1
- package/dist/views/Agents/useAgentFavorites.d.ts.map +1 -1
- package/dist/views/Agents/useAgentFavorites.js +3 -1
- package/dist/views/Agents/useAgentFavorites.js.map +1 -1
- package/dist/views/Chat/ChatMessage.d.ts +1 -1
- package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
- package/dist/views/Chat/ChatMessage.js +6 -21
- package/dist/views/Chat/ChatMessage.js.map +1 -1
- package/dist/views/Chat/StepsList.d.ts +2 -12
- package/dist/views/Chat/StepsList.d.ts.map +1 -1
- package/dist/views/Chat/StepsList.js +18 -155
- 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 +10 -17
- package/dist/views/Chat/styled.js.map +1 -1
- package/dist/views/MessageInput/AgentSelector.d.ts.map +1 -1
- package/dist/views/MessageInput/AgentSelector.js +8 -2
- package/dist/views/MessageInput/AgentSelector.js.map +1 -1
- package/dist/views/MessageInput/ButtonAgent.js +1 -1
- package/dist/views/MessageInput/ButtonAgent.js.map +1 -1
- package/dist/views/MessageInput/ButtonBar.d.ts +2 -1
- package/dist/views/MessageInput/ButtonBar.d.ts.map +1 -1
- package/dist/views/MessageInput/ButtonBar.js +2 -3
- package/dist/views/MessageInput/ButtonBar.js.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.js +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -1
- package/dist/views/MessageInput/dictionary.d.ts +1 -1
- package/dist/views/MessageInput/index.d.ts +2 -1
- package/dist/views/MessageInput/index.d.ts.map +1 -1
- package/dist/views/MessageInput/index.js +2 -2
- package/dist/views/MessageInput/index.js.map +1 -1
- package/dist/views/MessageInput/styled.d.ts +0 -3
- package/dist/views/MessageInput/styled.d.ts.map +1 -1
- package/dist/views/MessageInput/styled.js +0 -12
- package/dist/views/MessageInput/styled.js.map +1 -1
- package/dist/views/Steps/FlowChart/NodeStep.js +1 -1
- package/dist/views/Steps/FlowChart/NodeStep.js.map +1 -1
- package/dist/views/Steps/FlowChart/layout.d.ts +1 -1
- package/dist/views/Steps/FlowChart/layout.d.ts.map +1 -1
- package/dist/views/Steps/FlowChart/layout.js +0 -1
- package/dist/views/Steps/FlowChart/layout.js.map +1 -1
- package/dist/views/Steps/FlowChart/types.d.ts +1 -1
- package/dist/views/Steps/FlowChart/types.d.ts.map +1 -1
- package/dist/views/Steps/StepModal.js +2 -2
- package/dist/views/Steps/StepModal.js.map +1 -1
- package/dist/views/Steps/dictionary.d.ts +1 -1
- package/dist/views/Steps/utils.d.ts +1 -1
- package/dist/views/Steps/utils.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/StackspotAIWidget.tsx +7 -1
- package/src/app-metadata.json +5 -5
- package/src/chat-interceptors/send-message.ts +2 -137
- package/src/state/ChatEntry.ts +6 -6
- package/src/state/ChatState.ts +0 -8
- package/src/utils/chat.ts +0 -1
- package/src/utils/check-is-trial.ts +5 -2
- package/src/views/Agents/AgentsTab.tsx +4 -3
- package/src/views/Agents/useAgentFavorites.ts +3 -1
- package/src/views/Chat/ChatMessage.tsx +5 -25
- package/src/views/Chat/StepsList.tsx +44 -337
- package/src/views/Chat/styled.ts +10 -17
- package/src/views/MessageInput/AgentSelector.tsx +7 -2
- package/src/views/MessageInput/ButtonAgent.tsx +1 -1
- package/src/views/MessageInput/ButtonBar.tsx +3 -3
- package/src/views/MessageInput/QuickCommandSelector.tsx +1 -1
- package/src/views/MessageInput/index.tsx +4 -4
- package/src/views/MessageInput/styled.ts +0 -12
- package/src/views/Steps/FlowChart/NodeStep.tsx +1 -1
- package/src/views/Steps/FlowChart/layout.ts +0 -1
- package/src/views/Steps/FlowChart/types.ts +1 -1
- package/src/views/Steps/StepModal.tsx +2 -2
- package/dist/utils/planning-tool.d.ts +0 -17
- package/dist/utils/planning-tool.d.ts.map +0 -1
- package/dist/utils/planning-tool.js +0 -32
- package/dist/utils/planning-tool.js.map +0 -1
- package/dist/utils/update-tool-step.d.ts +0 -3
- package/dist/utils/update-tool-step.d.ts.map +0 -1
- package/dist/utils/update-tool-step.js +0 -23
- package/dist/utils/update-tool-step.js.map +0 -1
- package/dist/views/MessageInput/ModelSwitcher.d.ts +0 -2
- package/dist/views/MessageInput/ModelSwitcher.d.ts.map +0 -1
- package/dist/views/MessageInput/ModelSwitcher.js +0 -77
- package/dist/views/MessageInput/ModelSwitcher.js.map +0 -1
- package/src/utils/planning-tool.ts +0 -41
- package/src/utils/update-tool-step.tsx +0 -27
- package/src/views/MessageInput/ModelSwitcher.tsx +0 -127
|
@@ -1,389 +1,96 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Icon } from '@stack-spot/citric-icons'
|
|
2
|
+
import { Button, ProgressCircular, Text } from '@stack-spot/citric-react'
|
|
2
3
|
import { AnimatedHeight } from '@stack-spot/portal-components/AnimatedHeight'
|
|
3
|
-
import { ChatStep, StepChatStep
|
|
4
|
+
import { ChatStep, StepChatStep } from '@stack-spot/portal-network'
|
|
4
5
|
import { theme } from '@stack-spot/portal-theme'
|
|
5
6
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import { Markdown } from '../../components/Markdown'
|
|
10
|
-
import { useChat, useChatMessages, useCurrentChat, useCurrentChatMessages, useWidget } from '../../context/hooks'
|
|
11
|
-
import { ChatEntry } from '../../state/ChatEntry'
|
|
12
|
-
import { planningToolDictionaryHelper } from '../../utils/planning-tool'
|
|
13
|
-
import { updateToolStep } from '../../utils/update-tool-step'
|
|
14
|
-
import { onCopyCode } from './events'
|
|
7
|
+
import { findLastIndex } from 'lodash'
|
|
8
|
+
import { useState } from 'react'
|
|
9
|
+
import { useWidget } from '../../context/hooks'
|
|
15
10
|
|
|
16
11
|
interface Props {
|
|
17
12
|
steps: ChatStep[],
|
|
18
13
|
messageId: number,
|
|
19
14
|
chatId: string,
|
|
20
|
-
userHasAlreadyAnswered?: boolean,
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface StepChatStepWithTarget extends Omit<StepChatStep, 'status' | 'id' | 'type'> {
|
|
24
|
-
status: 'pending' | 'running' | 'success' | 'error' | 'target' | 'awaiting_approval',
|
|
25
15
|
}
|
|
26
16
|
|
|
27
17
|
interface StepProps {
|
|
28
|
-
step:
|
|
18
|
+
step: StepChatStep,
|
|
29
19
|
index: number,
|
|
30
|
-
total
|
|
31
|
-
totalTools?: number,
|
|
32
|
-
isAllDone?: boolean,
|
|
20
|
+
total: number,
|
|
33
21
|
onClick?: () => void,
|
|
34
22
|
}
|
|
35
23
|
|
|
36
|
-
function getStatusIcon(status:
|
|
24
|
+
function getStatusIcon(status: ChatStep['status']) {
|
|
37
25
|
const iconProps = { style: { color: theme.color.light[700] }, size: 'xs' } as const
|
|
38
26
|
switch (status) {
|
|
39
27
|
case 'error': return <Icon group="fill" icon="TimesCircle" {...iconProps} />
|
|
40
28
|
case 'success': return <Icon group="fill" icon="CheckCircle" {...iconProps} />
|
|
41
|
-
case 'pending': return <Icon
|
|
42
|
-
case 'awaiting_approval': return <Icon group="fill" icon="ExclamationTriangle" {...iconProps} />
|
|
43
|
-
case 'target': return <Icon icon="Target" {...iconProps} style={{ color: isDone ? theme.color.light[700] : theme.color.light[600] }} />
|
|
29
|
+
case 'pending': return <Icon icon="Spaces" {...iconProps} />
|
|
44
30
|
case 'running': return <ProgressCircular className="loading" colorScheme="inverse" size="xs" />
|
|
45
31
|
}
|
|
46
32
|
}
|
|
47
33
|
|
|
48
|
-
const
|
|
49
|
-
const t = useTranslate(dictionary)
|
|
50
|
-
return <Row gap="8px">
|
|
51
|
-
{expand}
|
|
52
|
-
{step.status === 'target' ? <Text className="step-title" appearance="body2" color="light.700">{t.planGoal}:</Text> :
|
|
53
|
-
<Badge colorScheme="inverse" appearance="square">
|
|
54
|
-
{t.step} {index}
|
|
55
|
-
</Badge>}
|
|
56
|
-
<Text className="step-title" appearance="body2">
|
|
57
|
-
{step.input}
|
|
58
|
-
</Text>
|
|
59
|
-
{step.status === 'awaiting_approval' &&
|
|
60
|
-
<Badge appearance="square" style={{ backgroundColor: theme.color.gray[800], color: theme.color.gray[50] }}>
|
|
61
|
-
<Icon icon="Security" />
|
|
62
|
-
{t.pendingReview}
|
|
63
|
-
</Badge>}
|
|
64
|
-
</Row>
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const StyledCard = styled(Card)`
|
|
68
|
-
&:hover {
|
|
69
|
-
background-color: ${theme.color.light[500]}
|
|
70
|
-
}
|
|
71
|
-
`
|
|
72
|
-
|
|
73
|
-
const Step = ({ step, index, onClick, total, totalTools, isAllDone }: StepProps) => {
|
|
34
|
+
const Step = ({ step, index, total, onClick }: StepProps) => {
|
|
74
35
|
const t = useTranslate(dictionary)
|
|
75
|
-
const status = getStatusIcon(step.status, isAllDone)
|
|
76
|
-
const hasTools = step.attempts?.[0]?.tools && step.attempts?.[0]?.tools?.length > 0
|
|
77
|
-
|
|
78
36
|
return (
|
|
79
37
|
<li tabIndex={onClick ? 0 : undefined} onClick={onClick} role={onClick ? 'button' : 'listitem'}>
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
<Column pt="12px">
|
|
85
|
-
{total ?
|
|
86
|
-
<Row gap="40px">
|
|
87
|
-
<Row gap="4px">
|
|
88
|
-
<Icon icon="Hashtag" size="sm" color="light.700" />
|
|
89
|
-
<Text color="light.700">{t.totalSteps}</Text>
|
|
90
|
-
{total}
|
|
91
|
-
</Row>
|
|
92
|
-
<Row gap="4px">
|
|
93
|
-
<Icon icon="BorderRadius" size="sm" color="light.700" />
|
|
94
|
-
<Text color="light.700">{t.totalTools}</Text>
|
|
95
|
-
{totalTools ?? 0}
|
|
96
|
-
</Row>
|
|
97
|
-
</Row>
|
|
98
|
-
: <>
|
|
99
|
-
<Row pb="8px">
|
|
100
|
-
<Icon icon="Target" size="sm" color="light.700" />
|
|
101
|
-
<Text color="light.700" tag="span" style={{ margin: '0 4px' }}>{t.stepGoal}:</Text>
|
|
102
|
-
<Text tag="span">
|
|
103
|
-
{step.input}
|
|
104
|
-
</Text>
|
|
105
|
-
</Row>
|
|
106
|
-
{hasTools ? <>
|
|
107
|
-
<Row gap="4px">
|
|
108
|
-
<Icon icon="BorderRadius" size="sm" color="light.700" />
|
|
109
|
-
<Text color="light.700">{t.toolsToBeExecuted}:</Text>
|
|
110
|
-
</Row>
|
|
111
|
-
<ul className="tools-list">
|
|
112
|
-
{step.attempts?.[0]?.tools?.map((tool, index) => (<li key={`${tool.id}-${index}`}>
|
|
113
|
-
<Text>{tool.name}: {tool.goal}</Text>
|
|
114
|
-
</li>))}
|
|
115
|
-
</ul>
|
|
116
|
-
</> : <Row gap="4px">
|
|
117
|
-
<Icon icon="BorderRadius" size="sm" color="light.700" />
|
|
118
|
-
<Text color="light.700">{t.noToolToBeUsed}</Text>
|
|
119
|
-
</Row>
|
|
120
|
-
}
|
|
121
|
-
</>
|
|
122
|
-
}
|
|
123
|
-
</Column>
|
|
124
|
-
</Accordion>
|
|
125
|
-
</StyledCard>
|
|
126
|
-
</Row>
|
|
38
|
+
<div className="step-status-icon">{getStatusIcon(step.status)}</div>
|
|
39
|
+
<Text className="step-title" appearance="microtext1" color="light.700">
|
|
40
|
+
{t.step} {index}/{total}: {step.input}
|
|
41
|
+
</Text>
|
|
127
42
|
</li>
|
|
128
43
|
)
|
|
129
44
|
}
|
|
130
45
|
|
|
131
|
-
export const
|
|
132
|
-
const t = useTranslate(dictionary)
|
|
133
|
-
return <Card gap="8px">
|
|
134
|
-
<Row gap="8px">
|
|
135
|
-
<ProgressCircular colorScheme="inverse" size="xs" />
|
|
136
|
-
<Text color="light.700">{t.generatingPlan}</Text>
|
|
137
|
-
</Row>
|
|
138
|
-
<Text color="light.700">
|
|
139
|
-
{t.analyzingRequirements}
|
|
140
|
-
</Text>
|
|
141
|
-
<Row gap="12px">
|
|
142
|
-
<Skeleton height="31px" width="148px" bgLevel={600} />
|
|
143
|
-
<Skeleton height="31px" width="148px" bgLevel={600} />
|
|
144
|
-
<Skeleton height="31px" width="148px" bgLevel={600} />
|
|
145
|
-
<Skeleton height="31px" width="148px" bgLevel={600} />
|
|
146
|
-
</Row>
|
|
147
|
-
</Card>
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const AwaitingApproval = ({ customApproveText, chatId }: { chatId: string, customApproveText?: string }) => {
|
|
151
|
-
const t = useTranslate(dictionary)
|
|
152
|
-
const chat = useChat(chatId)
|
|
153
|
-
|
|
154
|
-
const onAnswer = (response: string) => {
|
|
155
|
-
chat.pushMessage(ChatEntry.createUserEntry('', false, undefined, undefined, response))
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return <>
|
|
159
|
-
<Row gap="8px">
|
|
160
|
-
<Button colorScheme="light" onClick={() => onAnswer(t.cancel)}>
|
|
161
|
-
<Row gap="8px">
|
|
162
|
-
<Icon icon="Stop" />
|
|
163
|
-
{t.cancel}
|
|
164
|
-
</Row>
|
|
165
|
-
</Button>
|
|
166
|
-
|
|
167
|
-
<Button colorScheme="inverse" onClick={() => onAnswer(customApproveText ?? t.approve)}>
|
|
168
|
-
<Row gap="8px">
|
|
169
|
-
<Icon group="fill" icon="Play" />
|
|
170
|
-
{customApproveText ?? t.approve}
|
|
171
|
-
</Row>
|
|
172
|
-
</Button>
|
|
173
|
-
</Row>
|
|
174
|
-
</>
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
export const ToolStepsList = ({ toolStep, messageId, chatId }: { toolStep: ToolChatStep, messageId: number, chatId: string }) => {
|
|
178
|
-
const t = useTranslate(dictionary)
|
|
179
|
-
const chat = useCurrentChat()
|
|
180
|
-
const messages = useCurrentChatMessages()
|
|
181
|
-
const inputParsed = `\`\`\`json
|
|
182
|
-
${JSON.stringify(toolStep?.input, null, 2)}
|
|
183
|
-
\`\`\``
|
|
184
|
-
|
|
185
|
-
const tool = useMemo(() => {
|
|
186
|
-
if (!toolStep) return undefined
|
|
187
|
-
return toolStep.attempts?.[0].tools?.[0]
|
|
188
|
-
}, [toolStep])
|
|
189
|
-
|
|
190
|
-
useEffect(() => {
|
|
191
|
-
if (!toolStep) return undefined
|
|
192
|
-
const executionId = toolStep.attempts?.[0].tools?.[0].executionId
|
|
193
|
-
if (!executionId) return
|
|
194
|
-
|
|
195
|
-
updateToolStep(messages, executionId, toolStep.status)
|
|
196
|
-
|
|
197
|
-
}, [messages, toolStep, toolStep.status])
|
|
198
|
-
|
|
199
|
-
return <>
|
|
200
|
-
{toolStep && tool ? <AnimatedHeight>
|
|
201
|
-
<div className="steps">
|
|
202
|
-
<Badge colorPalette="yellow" appearance="square">
|
|
203
|
-
<Icon icon="StopWatch" />
|
|
204
|
-
<Text>{tool.name} {t.keepWorking}</Text>
|
|
205
|
-
</Badge>
|
|
206
|
-
<Card mt="16px" gap="8px" bgLevel={500}>
|
|
207
|
-
<Row>
|
|
208
|
-
<ImageWithFallback src={tool.image} width="32px" fallback={<IconBox appearance="circle" icon="StackSpot" />} />
|
|
209
|
-
<Text>{tool.name}</Text>
|
|
210
|
-
</Row>
|
|
211
|
-
|
|
212
|
-
<Text>
|
|
213
|
-
{toolStep.user_question}
|
|
214
|
-
</Text>
|
|
215
|
-
|
|
216
|
-
<Accordion header={expand => <Row gap="8px" mb="4px">
|
|
217
|
-
<Card p="4px" bgLevel={400}>{expand}</Card>
|
|
218
|
-
<Text > {t.viewDetails} </Text>
|
|
219
|
-
</Row>}>
|
|
220
|
-
<Markdown onCopyCode={(code) => onCopyCode(code, `${messageId}`, chat)}>
|
|
221
|
-
{inputParsed}
|
|
222
|
-
</Markdown>
|
|
223
|
-
</Accordion>
|
|
224
|
-
|
|
225
|
-
<AwaitingApproval customApproveText={t.approveTool} chatId={chatId} />
|
|
226
|
-
</Card>
|
|
227
|
-
</div>
|
|
228
|
-
</AnimatedHeight> : null}
|
|
229
|
-
</>
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
export const StepsList = ({ steps, messageId, chatId, userHasAlreadyAnswered }: Props) => {
|
|
46
|
+
export const StepsList = ({ steps, chatId, messageId }: Props) => {
|
|
233
47
|
const t = useTranslate(dictionary)
|
|
234
|
-
|
|
235
|
-
const
|
|
236
|
-
const actualSteps = useMemo(() => filteredSteps.filter((item) => {
|
|
237
|
-
const messageIdForStep = planningToolDictionaryHelper.getMessageIdFromStepId(item.id)
|
|
238
|
-
if (!messageIdForStep) {
|
|
239
|
-
planningToolDictionaryHelper.setMessageIdForStepId(messageId, item.id)
|
|
240
|
-
return true
|
|
241
|
-
} else if (messageIdForStep === messageId) {
|
|
242
|
-
return true
|
|
243
|
-
}
|
|
244
|
-
// If a step is from a planning and it is already inserted in the planningToolDictionaryHelper it means the step is already in a
|
|
245
|
-
// previous message and we do not want to show it again (for instance, when required a approval in the planning, we will have
|
|
246
|
-
// two messages with the same step id one for the planning awaiting and one for the planning end, so we want to show only one)
|
|
247
|
-
return false
|
|
248
|
-
}), [filteredSteps])
|
|
249
|
-
|
|
250
|
-
const planning = steps.filter(s => s.type === 'planning')
|
|
251
|
-
|
|
252
|
-
useEffect(() => {
|
|
253
|
-
actualSteps.map((item) => {
|
|
254
|
-
const executionId = item.attempts[0]?.tools?.[0].executionId
|
|
255
|
-
if (executionId) {
|
|
256
|
-
planningToolDictionaryHelper.setMessageIdPlanningStepToolExecutionId(`${messageId}`, executionId)
|
|
257
|
-
}
|
|
258
|
-
})
|
|
259
|
-
}, [actualSteps, messageId])
|
|
260
|
-
|
|
261
|
-
const toolsStep = findLast(steps, s => s.type === 'tool')
|
|
262
|
-
|
|
263
|
-
useEffect(() => {
|
|
264
|
-
const executionId = toolsStep?.attempts?.[0]?.tools?.[0]?.executionId
|
|
265
|
-
if (executionId) {
|
|
266
|
-
planningToolDictionaryHelper.setMessageIdToolStepToolExecutionId(`${messageId}`, executionId)
|
|
267
|
-
}
|
|
268
|
-
}, [toolsStep, messageId])
|
|
269
|
-
|
|
270
|
-
const planningGoal = planning?.[0]?.goal
|
|
271
|
-
const isLastStepDone = actualSteps[actualSteps.length - 1]?.status !== 'running' &&
|
|
272
|
-
actualSteps[actualSteps.length - 1]?.status !== 'pending'
|
|
273
|
-
const totalTools = useMemo(() => actualSteps?.reduce((sum, step) => {
|
|
274
|
-
const firstAttempt = step.attempts && step.attempts[0]
|
|
275
|
-
const toolsCount = firstAttempt.tools?.length ?? 0
|
|
276
|
-
return sum + toolsCount
|
|
277
|
-
}, 0), [steps])
|
|
278
|
-
|
|
48
|
+
const [isExpanded, setExpanded] = useState(false)
|
|
49
|
+
const actualSteps = steps.filter(s => s.type === 'step')
|
|
279
50
|
let currentStepIndex = findLastIndex(actualSteps, s => s.status === 'running' || s.status === 'success')
|
|
280
51
|
if (currentStepIndex === -1) currentStepIndex = 0
|
|
52
|
+
const widget = useWidget()
|
|
281
53
|
|
|
282
|
-
|
|
283
|
-
|
|
54
|
+
function openToolsPanel() {
|
|
55
|
+
widget.set('currentMessageInPanel', { chatId, messageId })
|
|
56
|
+
widget.set('panel', 'steps')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<AnimatedHeight>
|
|
284
61
|
<div className="steps">
|
|
285
|
-
<
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
index={currentStepIndex + 1}
|
|
296
|
-
total={actualSteps.length}
|
|
297
|
-
totalTools={totalTools}
|
|
298
|
-
isAllDone={isLastStepDone}
|
|
299
|
-
/>
|
|
62
|
+
<ul>
|
|
63
|
+
{isExpanded
|
|
64
|
+
? actualSteps.map((s, i) => <Step step={s} key={i} index={i + 1} total={actualSteps.length} />)
|
|
65
|
+
: <Step
|
|
66
|
+
step={actualSteps[currentStepIndex]}
|
|
67
|
+
index={currentStepIndex + 1}
|
|
68
|
+
total={actualSteps.length}
|
|
69
|
+
onClick={() => setExpanded(true)}
|
|
70
|
+
/>
|
|
71
|
+
}
|
|
300
72
|
</ul>
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
<
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
73
|
+
{isExpanded && <div className="step-actions">
|
|
74
|
+
<Button colorScheme="light" size="sm" onClick={() => setExpanded(false)}>{t.hideSteps}</Button>
|
|
75
|
+
<Button colorScheme="light" size="sm" className="icon-button details" onClick={openToolsPanel}>
|
|
76
|
+
<Icon group="fill" icon="Play" size="xs" />
|
|
77
|
+
{t.detailed}
|
|
78
|
+
</Button>
|
|
79
|
+
</div>}
|
|
308
80
|
</div>
|
|
309
|
-
</AnimatedHeight>
|
|
310
|
-
|
|
311
|
-
{toolsStep && toolsStep.status === 'awaiting_approval' && !userHasAlreadyAnswered &&
|
|
312
|
-
<ToolStepsList toolStep={toolsStep} messageId={messageId} chatId={chatId} />}
|
|
313
|
-
</>
|
|
81
|
+
</AnimatedHeight>
|
|
314
82
|
)
|
|
315
83
|
}
|
|
316
84
|
|
|
317
|
-
export const ViewToolsDetails = ({ chatId }: { chatId: string }) => {
|
|
318
|
-
const t = useTranslate(dictionary)
|
|
319
|
-
const messages = useChatMessages(chatId)
|
|
320
|
-
const messageId = useMemo(() => {
|
|
321
|
-
const messageWithPlanning = findLast(messages, (message) => {
|
|
322
|
-
const steps = message.getValue().steps
|
|
323
|
-
const planningStep = steps?.find((step) => step.type === 'planning' && step.status === 'success')
|
|
324
|
-
return planningStep ? true : false
|
|
325
|
-
})
|
|
326
|
-
return messageWithPlanning?.id
|
|
327
|
-
|
|
328
|
-
}, [messages])
|
|
329
|
-
const widget = useWidget()
|
|
330
|
-
|
|
331
|
-
function openToolsPanel() {
|
|
332
|
-
if (messageId) {
|
|
333
|
-
widget.set('currentMessageInPanel', { chatId, messageId })
|
|
334
|
-
widget.set('panel', 'steps')
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
return <>
|
|
339
|
-
<div className="step-actions">
|
|
340
|
-
<Button colorScheme="light" size="sm" className="icon-button details" onClick={openToolsPanel}>
|
|
341
|
-
<Icon group="fill" icon="Play" size="xs" />
|
|
342
|
-
{t.detailed}
|
|
343
|
-
</Button>
|
|
344
|
-
</div>
|
|
345
|
-
</>
|
|
346
|
-
}
|
|
347
|
-
|
|
348
85
|
const dictionary = {
|
|
349
86
|
en: {
|
|
350
87
|
step: 'Step',
|
|
351
88
|
hideSteps: 'Hide steps',
|
|
352
89
|
detailed: 'View detailed mode',
|
|
353
|
-
generatingPlan: 'Generating execution plan...',
|
|
354
|
-
analyzingRequirements: 'Analyzing task requirements',
|
|
355
|
-
executionPlan: 'Execution Plan',
|
|
356
|
-
planGoal: 'Plan Goal',
|
|
357
|
-
toolsToBeExecuted: 'Tools to be executed',
|
|
358
|
-
totalSteps: 'Total Steps',
|
|
359
|
-
totalTools: 'Total Tools',
|
|
360
|
-
stepGoal: 'Step Goal',
|
|
361
|
-
cancel: 'Cancel execution',
|
|
362
|
-
approve: 'Approve & Execute Plan',
|
|
363
|
-
keepWorking: 'will keep working after your answer',
|
|
364
|
-
viewDetails: 'View details',
|
|
365
|
-
approveTool: 'Approve execution',
|
|
366
|
-
pendingReview: 'Pending review',
|
|
367
|
-
noToolToBeUsed: 'No tool will be needed',
|
|
368
90
|
},
|
|
369
91
|
pt: {
|
|
370
92
|
step: 'Passo',
|
|
371
93
|
hideSteps: 'Esconder passos',
|
|
372
94
|
detailed: 'Ver modo detalhado',
|
|
373
|
-
generatingPlan: 'Gerando plano de execução...',
|
|
374
|
-
analyzingRequirements: 'Analisando os requisitos da task',
|
|
375
|
-
executionPlan: 'Plano de Execução',
|
|
376
|
-
planGoal: 'Finalidade do Plano',
|
|
377
|
-
toolsToBeExecuted: 'Tools a serem executadas',
|
|
378
|
-
totalSteps: 'Total de Passos',
|
|
379
|
-
totalTools: 'Total de Tools',
|
|
380
|
-
stepGoal: 'Objetivo do passo',
|
|
381
|
-
cancel: 'Cancelar execução',
|
|
382
|
-
approve: 'Aprovar & Executar plano',
|
|
383
|
-
keepWorking: 'continuará trabalhando após a sua resposta',
|
|
384
|
-
viewDetails: 'Ver detalhes',
|
|
385
|
-
approveTool: 'Aprovar execução',
|
|
386
|
-
pendingReview: 'Revisão pendente',
|
|
387
|
-
noToolToBeUsed: 'Nenhuma tool será necessária',
|
|
388
95
|
},
|
|
389
96
|
} satisfies Dictionary
|
package/src/views/Chat/styled.ts
CHANGED
|
@@ -243,27 +243,20 @@ export const ChatList: IStyledComponentBase<
|
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
.steps {
|
|
246
|
-
|
|
246
|
+
ul {
|
|
247
247
|
list-style: none;
|
|
248
248
|
margin: 0;
|
|
249
249
|
padding: 0;
|
|
250
250
|
display: flex;
|
|
251
251
|
flex-direction: column;
|
|
252
252
|
gap: 6px;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
.tools-list {
|
|
256
|
-
list-style: disc;
|
|
257
|
-
margin: 0;
|
|
258
|
-
padding-left: 24px;
|
|
259
|
-
display: block;
|
|
260
|
-
::marker {
|
|
261
|
-
color: ${theme.color.light.contrastText};
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
253
|
|
|
265
|
-
ul {
|
|
266
254
|
li {
|
|
255
|
+
display: flex;
|
|
256
|
+
flex-direction: row;
|
|
257
|
+
gap: 4px;
|
|
258
|
+
align-items: center;
|
|
259
|
+
|
|
267
260
|
&[role="button"] {
|
|
268
261
|
cursor: pointer;
|
|
269
262
|
}
|
|
@@ -282,6 +275,7 @@ export const ChatList: IStyledComponentBase<
|
|
|
282
275
|
}
|
|
283
276
|
|
|
284
277
|
.step-title {
|
|
278
|
+
line-height: 0.75rem;
|
|
285
279
|
overflow: hidden;
|
|
286
280
|
text-overflow: ellipsis;
|
|
287
281
|
display: -webkit-box;
|
|
@@ -291,10 +285,8 @@ export const ChatList: IStyledComponentBase<
|
|
|
291
285
|
}
|
|
292
286
|
}
|
|
293
287
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
.step-actions {
|
|
297
|
-
margin-top: 16px;
|
|
288
|
+
.step-actions {
|
|
289
|
+
margin-top: 8px;
|
|
298
290
|
display: flex;
|
|
299
291
|
gap: 6px;
|
|
300
292
|
|
|
@@ -304,6 +296,7 @@ export const ChatList: IStyledComponentBase<
|
|
|
304
296
|
align-items: center;
|
|
305
297
|
}
|
|
306
298
|
}
|
|
299
|
+
}
|
|
307
300
|
|
|
308
301
|
.markdown img {
|
|
309
302
|
max-width: 70%;
|
|
@@ -56,15 +56,20 @@ export const AgentSelector = ({ inputRef, isTrial }: {
|
|
|
56
56
|
|
|
57
57
|
const getAgents = () => {
|
|
58
58
|
if (spotId) {
|
|
59
|
-
return workspaceAiClient.getAgentFromWorkspaceAi.useQuery({ workspaceId: spotId }
|
|
59
|
+
return workspaceAiClient.getAgentFromWorkspaceAi.useQuery({ workspaceId: spotId }, {
|
|
60
|
+
enabled: isAgentEnabled }) as AgentResponseWithBuiltIn[]
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
if (isTrial) {
|
|
63
|
-
return agentToolsClient.allAgents.useQuery({ visibilities: ['personal', 'built_in', 'recently_used'] }
|
|
64
|
+
return agentToolsClient.allAgents.useQuery({ visibilities: ['personal', 'built_in', 'recently_used'] }, {
|
|
65
|
+
enabled: isAgentEnabled,
|
|
66
|
+
})
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
return agentToolsClient.allAgents.useQuery({
|
|
67
70
|
visibilities: ['account', 'shared', 'personal', 'built_in', 'recently_used', 'workspace'],
|
|
71
|
+
}, {
|
|
72
|
+
enabled: isAgentEnabled,
|
|
68
73
|
})
|
|
69
74
|
}
|
|
70
75
|
|
|
@@ -8,11 +8,11 @@ import { useMessageInputDictionary } from './dictionary'
|
|
|
8
8
|
|
|
9
9
|
export const ButtonAgent = () => {
|
|
10
10
|
const t = useMessageInputDictionary()
|
|
11
|
-
const agentDefault = agentToolsClient.agentDefault.useQuery()
|
|
12
11
|
const widget = useWidget()
|
|
13
12
|
const chat = useCurrentChat()
|
|
14
13
|
const agent = useCurrentChatState('agent')
|
|
15
14
|
const features = useCurrentChatState('features')
|
|
15
|
+
const [agentDefault] = agentToolsClient.agentDefault.useStatefulQuery({ enabled: features.agent })
|
|
16
16
|
|
|
17
17
|
const setAgentDefault = () => {
|
|
18
18
|
agentDefault && chat.set(
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { IconButton, Row } from '@stack-spot/citric-react'
|
|
2
2
|
import { useCurrentChat, useCurrentChatState, useWidget } from '../../context/hooks'
|
|
3
3
|
import { useMessageInputDictionary } from './dictionary'
|
|
4
|
-
import { ModelSwitcher } from './ModelSwitcher'
|
|
5
4
|
import { SelectContent } from './SelectContent'
|
|
6
5
|
import { SelectionBarWrapper } from './styled'
|
|
7
6
|
|
|
@@ -14,9 +13,10 @@ interface SelectionBarProps {
|
|
|
14
13
|
* Whether or not the message is currently being sent. This is used to decide which button to show: send or cancel.
|
|
15
14
|
*/
|
|
16
15
|
isLoading?: boolean,
|
|
16
|
+
customButtonBarItems?: React.ReactNode,
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export const ButtonBar = ({ onSend, isLoading }: SelectionBarProps) => {
|
|
19
|
+
export const ButtonBar = ({ onSend, isLoading, customButtonBarItems }: SelectionBarProps) => {
|
|
20
20
|
const t = useMessageInputDictionary()
|
|
21
21
|
const chat = useCurrentChat()
|
|
22
22
|
const widget = useWidget()
|
|
@@ -29,8 +29,8 @@ export const ButtonBar = ({ onSend, isLoading }: SelectionBarProps) => {
|
|
|
29
29
|
{features.editor && (
|
|
30
30
|
<IconButton icon="Code" appearance="square" aria-label={t.code} title={t.code} onClick={() => widget.set('panel', 'editor')} />
|
|
31
31
|
)}
|
|
32
|
+
{customButtonBarItems}
|
|
32
33
|
</Row>
|
|
33
|
-
<ModelSwitcher />
|
|
34
34
|
{isLoading ? (
|
|
35
35
|
<IconButton
|
|
36
36
|
icon="Stop"
|
|
@@ -14,7 +14,7 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
|
|
|
14
14
|
const isQuickCommandEnabled = useCurrentChatState('features').quickCommands
|
|
15
15
|
const spotId = useWidgetState('features')?.workspaceId
|
|
16
16
|
|
|
17
|
-
const useFavorites = () => aiClient.allQuickCommands.useQuery({ visibility: 'favorite' })
|
|
17
|
+
const useFavorites = () => aiClient.allQuickCommands.useQuery({ visibility: 'favorite' }, { enabled: isQuickCommandEnabled })
|
|
18
18
|
const [addFavorite, pendingAddFav] = aiClient.addFavoriteQuickCommand.useMutation()
|
|
19
19
|
const [removeFavorite, pendingRemoveFav] = aiClient.removeFavoriteQuickCommand.useMutation()
|
|
20
20
|
|
|
@@ -24,8 +24,8 @@ import { UploadDragNDrop, useUploadDragDrop } from './UploadDragNDrop'
|
|
|
24
24
|
* going to be used for the question and the buttons to send, cancel, set the workspace, among others. This also includes the Quick
|
|
25
25
|
* Commands panel for auto completing.
|
|
26
26
|
*/
|
|
27
|
-
export const MessageInput = ({ chatWindowRef, customInputMessage }:
|
|
28
|
-
{ chatWindowRef?: React.RefObject<HTMLElement>, customInputMessage?: string }) => {
|
|
27
|
+
export const MessageInput = ({ chatWindowRef, customInputMessage, customButtonBarItems }:
|
|
28
|
+
{ chatWindowRef?: React.RefObject<HTMLElement>, customInputMessage?: string, customButtonBarItems?: React.ReactNode}) => {
|
|
29
29
|
const t = useMessageInputDictionary()
|
|
30
30
|
const [focused, setFocused] = useState(false)
|
|
31
31
|
const [, setExpanded] = useState(true)
|
|
@@ -152,7 +152,7 @@ export const MessageInput = ({ chatWindowRef, customInputMessage }:
|
|
|
152
152
|
placeholder={
|
|
153
153
|
agentLabel
|
|
154
154
|
? customInputMessage ?? interpolate(t.placeholder, agentLabel)
|
|
155
|
-
: t.typing
|
|
155
|
+
: customInputMessage ?? t.typing
|
|
156
156
|
}
|
|
157
157
|
onChange={v => chat.set('nextMessage', v)}
|
|
158
158
|
value={value}
|
|
@@ -168,7 +168,7 @@ export const MessageInput = ({ chatWindowRef, customInputMessage }:
|
|
|
168
168
|
<ProgressBar className="progress-bar" progress={isLoading ? undefined : (focused ? 100 : 0)} speed="fast" />
|
|
169
169
|
<ContextBar />
|
|
170
170
|
{chat.get('features').upload && <UploadBar />}
|
|
171
|
-
<ButtonBar onSend={onSend} isLoading={isLoading} />
|
|
171
|
+
<ButtonBar onSend={onSend} isLoading={isLoading} customButtonBarItems={customButtonBarItems} />
|
|
172
172
|
</MessageInputBox>
|
|
173
173
|
<UploadDragNDrop isDragging={isDragging} onDrop={handleDrop} onDragLeave={handleDragLeave} />
|
|
174
174
|
</UploadProvider>
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Flex } from '@citric/core'
|
|
2
1
|
import { theme } from '@stack-spot/portal-theme'
|
|
3
2
|
import { styled } from 'styled-components'
|
|
4
3
|
|
|
@@ -303,14 +302,3 @@ export const MessageInputBox = styled.div`
|
|
|
303
302
|
}
|
|
304
303
|
}
|
|
305
304
|
`
|
|
306
|
-
export const RowWrapperStyled = styled(Flex)`
|
|
307
|
-
width: 100%;
|
|
308
|
-
justify-content: end;
|
|
309
|
-
margin-right: 4px;
|
|
310
|
-
ul {
|
|
311
|
-
margin: 0;
|
|
312
|
-
}
|
|
313
|
-
.button-select-model {
|
|
314
|
-
border-radius: 15px !important;
|
|
315
|
-
}
|
|
316
|
-
`
|
|
@@ -37,7 +37,7 @@ export const NodeStep = ({ data: { step, index, nextStatus, onClick } }: Props)
|
|
|
37
37
|
{!!step.attempts[0].tools?.length && <StackedBadge
|
|
38
38
|
label={t.tools}
|
|
39
39
|
images={step.attempts[0].tools?.slice(0, 3).map(
|
|
40
|
-
tool => ({ key: tool.id, name: tool.name
|
|
40
|
+
tool => ({ key: tool.id, name: tool.name, url: tool.image, icon: <Icon icon="Cog" /> }),
|
|
41
41
|
)}
|
|
42
42
|
/>}
|
|
43
43
|
</div>}
|
|
@@ -127,7 +127,7 @@ export const StepModal = ({ message, stepId, onClose }: Props) => {
|
|
|
127
127
|
|
|
128
128
|
const tools = step?.type === 'step' ? step.attempts[attempt]?.tools?.map(tool => (
|
|
129
129
|
<div className="tool" key={tool.id}>
|
|
130
|
-
<ToolBadge name={tool.name
|
|
130
|
+
<ToolBadge name={tool.name} duration={tool.duration} image={tool.image} description={tool.description} />
|
|
131
131
|
{tool.input && <>
|
|
132
132
|
<Text appearance="microtext1" color="light.700">{t.input}:</Text>
|
|
133
133
|
<Code language="json" className="tool-input" showLineNumbers={false} showActionBar>{tool.input}</Code>
|
|
@@ -191,7 +191,7 @@ export const StepModal = ({ message, stepId, onClose }: Props) => {
|
|
|
191
191
|
{!!s.attempts[0].tools?.length && <ul className="side-by-side-tools">
|
|
192
192
|
{s.attempts[0].tools.map((tool) => (
|
|
193
193
|
<li key={tool.id}>
|
|
194
|
-
<ToolBadge name={tool.name
|
|
194
|
+
<ToolBadge name={tool.name} image={tool.image} />
|
|
195
195
|
</li>
|
|
196
196
|
))}
|
|
197
197
|
</ul>}
|