@stack-spot/ai-chat-widget 2.0.0 → 3.0.0-beta.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 +83 -0
- package/dist/app-metadata.json +7 -7
- package/dist/chat-interceptors/send-message.d.ts.map +1 -1
- package/dist/chat-interceptors/send-message.js +78 -0
- package/dist/chat-interceptors/send-message.js.map +1 -1
- package/dist/state/ChatState.d.ts +4 -0
- package/dist/state/ChatState.d.ts.map +1 -1
- package/dist/state/ChatState.js.map +1 -1
- package/dist/utils/date.d.ts +1 -2
- package/dist/utils/date.d.ts.map +1 -1
- package/dist/utils/date.js +3 -3
- package/dist/utils/date.js.map +1 -1
- package/dist/utils/error.js +2 -2
- package/dist/utils/error.js.map +1 -1
- package/dist/utils/planning-tool.d.ts +14 -0
- package/dist/utils/planning-tool.d.ts.map +1 -0
- package/dist/utils/planning-tool.js +25 -0
- package/dist/utils/planning-tool.js.map +1 -0
- package/dist/utils/update-tool-step.d.ts +3 -0
- package/dist/utils/update-tool-step.d.ts.map +1 -0
- package/dist/utils/update-tool-step.js +23 -0
- package/dist/utils/update-tool-step.js.map +1 -0
- 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 +4 -3
- package/dist/views/Chat/ChatMessage.js.map +1 -1
- package/dist/views/Chat/StepsList.d.ts +6 -1
- package/dist/views/Chat/StepsList.d.ts.map +1 -1
- package/dist/views/Chat/StepsList.js +118 -13
- 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 +13 -6
- package/dist/views/Chat/styled.js.map +1 -1
- package/dist/views/MessageInput/dictionary.d.ts +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 +1 -0
- 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 +6 -6
- package/src/app-metadata.json +7 -7
- package/src/chat-interceptors/send-message.ts +91 -1
- package/src/state/ChatState.ts +4 -0
- package/src/utils/date.ts +3 -3
- package/src/utils/error.ts +2 -2
- package/src/utils/planning-tool.ts +32 -0
- package/src/utils/update-tool-step.tsx +27 -0
- package/src/views/Chat/ChatMessage.tsx +8 -4
- package/src/views/Chat/StepsList.tsx +284 -31
- package/src/views/Chat/styled.ts +13 -6
- package/src/views/Steps/FlowChart/NodeStep.tsx +1 -1
- package/src/views/Steps/FlowChart/layout.ts +1 -0
- package/src/views/Steps/FlowChart/types.ts +1 -1
- package/src/views/Steps/StepModal.tsx +2 -2
package/src/app-metadata.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stack-spot/ai-chat-widget",
|
|
3
|
-
"version": "
|
|
4
|
-
"date": "
|
|
3
|
+
"version": "3.0.0-beta.1",
|
|
4
|
+
"date": "Wed Oct 01 2025 15:13:49 GMT+0000 (Coordinated Universal Time)",
|
|
5
5
|
"dependencies": [
|
|
6
6
|
{
|
|
7
7
|
"name": "@stack-spot/app-metadata",
|
|
@@ -109,19 +109,19 @@
|
|
|
109
109
|
},
|
|
110
110
|
{
|
|
111
111
|
"name": "@stack-spot/citric-icons",
|
|
112
|
-
"version": "0.2.
|
|
112
|
+
"version": "0.2.3"
|
|
113
113
|
},
|
|
114
114
|
{
|
|
115
115
|
"name": "@stack-spot/citric-react",
|
|
116
|
-
"version": "0.
|
|
116
|
+
"version": "0.36.0(@stack-spot/citric-icons@0.2.3)(@stack-spot/portal-theme@1.2.1(@citric/core@6.4.0(lodash@4.17.21)(react@18.2.0)(styled-components@6.1.10(react-dom@18.2.0(react@18.2.0))(react@18.2.0)))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(styled-components@6.1.10(react-dom@18.2.0(react@18.2.0))(react@18.2.0)))(@stack-spot/portal-translate@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(lodash@4.17.21)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)"
|
|
117
117
|
},
|
|
118
118
|
{
|
|
119
119
|
"name": "@stack-spot/portal-components",
|
|
120
|
-
"version": "2.
|
|
120
|
+
"version": "2.26.0(@citric/core@6.4.0(lodash@4.17.21)(react@18.2.0)(styled-components@6.1.10(react-dom@18.2.0(react@18.2.0))(react@18.2.0)))(@citric/icons@5.13.0(react@18.2.0))(@citric/ui@6.10.2(@citric/core@6.4.0(lodash@4.17.21)(react@18.2.0)(styled-components@6.1.10(react-dom@18.2.0(react@18.2.0))(react@18.2.0)))(@citric/icons@5.13.0(react@18.2.0))(lodash@4.17.21)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(styled-components@6.1.10(react-dom@18.2.0(react@18.2.0))(react@18.2.0)))(@stack-spot/portal-theme@1.2.1(@citric/core@6.4.0(lodash@4.17.21)(react@18.2.0)(styled-components@6.1.10(react-dom@18.2.0(react@18.2.0))(react@18.2.0)))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(styled-components@6.1.10(react-dom@18.2.0(react@18.2.0))(react@18.2.0)))(@stack-spot/portal-translate@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@types/react@18.3.11)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)"
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
"name": "@stack-spot/portal-network",
|
|
124
|
-
"version": "0.
|
|
124
|
+
"version": "0.179.1-beta.1(@stack-spot/auth@6.1.0)(@stack-spot/opa@2.5.0(@stack-spot/auth@6.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@stack-spot/portal-translate@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@tanstack/react-query@5.59.16(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)"
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
"name": "@stack-spot/portal-theme",
|
|
@@ -129,7 +129,7 @@
|
|
|
129
129
|
},
|
|
130
130
|
{
|
|
131
131
|
"name": "@stack-spot/portal-translate",
|
|
132
|
-
"version": "
|
|
132
|
+
"version": "2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)"
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
"name": "@xyflow/react",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { aiClient, ChatResponseWithSteps, StackspotAPIError, StreamCanceledError } from '@stack-spot/portal-network'
|
|
1
|
+
import { AgentInfo, aiClient, ChatResponseWithSteps, StackspotAPIError, StreamCanceledError } from '@stack-spot/portal-network'
|
|
2
2
|
import { ChatResponse3 } from '@stack-spot/portal-network/api/ai'
|
|
3
3
|
import { ChatEntry, KnowledgeSource, TextChatEntry } from '../state/ChatEntry'
|
|
4
4
|
import { ChatState } from '../state/ChatState'
|
|
@@ -6,6 +6,7 @@ import { LabeledWithImage } from '../state/types'
|
|
|
6
6
|
import { buildConversationContext } from '../utils/chat'
|
|
7
7
|
import { treatHTMLInErrorMessage } from '../utils/error'
|
|
8
8
|
import { genericSourcesToKnowledgeSources } from '../utils/knowledge-source'
|
|
9
|
+
import { planningToolDictionaryHelper } from '../utils/planning-tool'
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Transforms a chat response from the backend into a chat entry that can be added to the chat.
|
|
@@ -61,6 +62,18 @@ export async function sendMessageInterceptor(entry: ChatEntry, chat: ChatState,
|
|
|
61
62
|
chat.set('label', content || entry.getValue().upload?.[0]?.name || 'Chat')
|
|
62
63
|
chat.untitled = false
|
|
63
64
|
}
|
|
65
|
+
|
|
66
|
+
//Verify if the last planning in the messages has status awaiting_approval
|
|
67
|
+
const messages = chat.getMessages()
|
|
68
|
+
const lastPlanningAwaiting = messages.slice().reverse().find(item => {
|
|
69
|
+
const steps = item.getValue().steps
|
|
70
|
+
if (steps) {
|
|
71
|
+
const hasPlanning = steps.find((step) => step.type === 'planning')
|
|
72
|
+
return hasPlanning ? hasPlanning.status === 'awaiting_approval' : false
|
|
73
|
+
}
|
|
74
|
+
return false
|
|
75
|
+
})
|
|
76
|
+
|
|
64
77
|
const stream = aiClient.sendChatMessage({ context, user_prompt: buildPrompt(content, data) })
|
|
65
78
|
signal.addEventListener('abort', () => stream.cancel())
|
|
66
79
|
const botEntry = ChatEntry.createStreamedBotEntry()
|
|
@@ -69,12 +82,89 @@ export async function sendMessageInterceptor(entry: ChatEntry, chat: ChatState,
|
|
|
69
82
|
chat.pushMessage(botEntry)
|
|
70
83
|
}
|
|
71
84
|
let knowledgeSources: KnowledgeSource[] | undefined
|
|
85
|
+
|
|
86
|
+
const updatePlanningMessage = () => {
|
|
87
|
+
if (lastPlanningAwaiting) {
|
|
88
|
+
const originalItem = messages.find((message) => message.id === lastPlanningAwaiting.id)
|
|
89
|
+
const originalItemValue = originalItem?.getValue()
|
|
90
|
+
originalItemValue?.steps?.map((step) => {
|
|
91
|
+
if (step.type === 'planning' && step.status === 'awaiting_approval') {
|
|
92
|
+
step.status = 'success'
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
originalItem?.setValue({ ...originalItemValue as TextChatEntry })
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const updateToolStatus = (agentInfo: AgentInfo) => {
|
|
100
|
+
const executionId = agentInfo.id
|
|
101
|
+
if (executionId) {
|
|
102
|
+
//Update message with type step which contains the planning steps
|
|
103
|
+
const messageId = planningToolDictionaryHelper.getMessageIdPlanningStepFromToolExecutionId(executionId)
|
|
104
|
+
const originalItem = messages.find((message) => `${message.id}` === messageId)
|
|
105
|
+
const originalItemValue = originalItem?.getValue()
|
|
106
|
+
let update = false
|
|
107
|
+
const status = agentInfo.action === 'start' ? 'pending' : 'success'
|
|
108
|
+
const step = originalItemValue?.steps?.find(step => step.type === 'step' && step.attempts?.[0].tools?.[0].executionId === executionId)
|
|
109
|
+
if (step && step.status !== status) {
|
|
110
|
+
step.status = status
|
|
111
|
+
update = true
|
|
112
|
+
}
|
|
113
|
+
if (update) {
|
|
114
|
+
originalItem?.setValue({ ...originalItemValue as TextChatEntry })
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
//Updates message with type tool which contains the actually tool steps
|
|
118
|
+
const toolMessageId = planningToolDictionaryHelper.getMessageIdToolStepFromToolExecutionId(executionId)
|
|
119
|
+
const toolOriginalItem = messages.find((message) => `${message.id}` === toolMessageId)
|
|
120
|
+
const toolOriginalItemValue = toolOriginalItem?.getValue()
|
|
121
|
+
const toolStep = toolOriginalItemValue?.steps?.find(step =>
|
|
122
|
+
step.type === 'tool' && step.attempts?.[0].tools?.[0].executionId === executionId)
|
|
123
|
+
update = false
|
|
124
|
+
if (toolStep && toolStep.status !== status) {
|
|
125
|
+
toolStep.status = status
|
|
126
|
+
update = true
|
|
127
|
+
}
|
|
128
|
+
if (update) {
|
|
129
|
+
toolOriginalItem?.setValue({ ...toolOriginalItemValue as TextChatEntry })
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
72
134
|
stream.onChange(value => {
|
|
135
|
+
if (value.agent_info?.type === 'planning') {
|
|
136
|
+
if (value.agent_info.action === 'start') {
|
|
137
|
+
chat.set('isPlaning', true)
|
|
138
|
+
} else {
|
|
139
|
+
chat.set('isPlaning', false)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
73
143
|
if (value.sources?.length !== knowledgeSources?.length && chat.get('features').showSourcesInResponse) {
|
|
74
144
|
knowledgeSources = genericSourcesToKnowledgeSources(value.sources)
|
|
75
145
|
}
|
|
146
|
+
|
|
147
|
+
// When there is a planning with status awaiting_approval and we receive a new one
|
|
148
|
+
// we do not not want to add it again.
|
|
149
|
+
if (lastPlanningAwaiting && value.steps) {
|
|
150
|
+
const hasPlanningAwaiting = value.steps.find((item) => item.type === 'planning' && item.status === 'awaiting_approval')
|
|
151
|
+
value.steps = value.steps?.filter(step => {
|
|
152
|
+
if (step.type === 'planning') {
|
|
153
|
+
updatePlanningMessage()
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return hasPlanningAwaiting ? true : (step.type !== 'planning' && step.type !== 'step' &&
|
|
157
|
+
(step.type !== 'answer' || (step.type === 'answer' && step.status === 'pending')))
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (value.agent_info?.type === 'tool') {
|
|
162
|
+
updateToolStatus(value.agent_info)
|
|
163
|
+
}
|
|
164
|
+
|
|
76
165
|
botEntry.setValue(createEntryValueFromChatResponse(value, knowledgeSources, chat.get('agent')))
|
|
77
166
|
})
|
|
167
|
+
|
|
78
168
|
let finalValue: Partial<ChatResponse3> | undefined
|
|
79
169
|
try {
|
|
80
170
|
finalValue = await stream.getValue()
|
package/src/state/ChatState.ts
CHANGED
|
@@ -33,6 +33,10 @@ export interface ChatPropertiesWithOptionalFeatures {
|
|
|
33
33
|
* Whether or not the chat is in a loading state.
|
|
34
34
|
*/
|
|
35
35
|
isLoading?: boolean,
|
|
36
|
+
/**
|
|
37
|
+
* Whether or not the chat is planning.
|
|
38
|
+
*/
|
|
39
|
+
isPlaning?: boolean,
|
|
36
40
|
/**
|
|
37
41
|
* The value of the next message. This is the value of the text typed in the textarea below the chat.
|
|
38
42
|
*/
|
package/src/utils/date.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Dictionary,
|
|
1
|
+
import { Dictionary, getLanguage, ptEn, useLanguage } from '@stack-spot/portal-translate'
|
|
2
2
|
|
|
3
3
|
const OneDay = 24 * 60 * 60 * 1000
|
|
4
4
|
const timeFormatOptions: Intl.DateTimeFormatOptions = { hour: '2-digit', minute:'2-digit' }
|
|
@@ -19,7 +19,7 @@ const fullFormatOptions: Intl.DateTimeFormatOptions = {
|
|
|
19
19
|
* @param language the language to use.
|
|
20
20
|
* @returns the formatted date.
|
|
21
21
|
*/
|
|
22
|
-
export function formatDateForChatMessage(date: Date, language
|
|
22
|
+
export function formatDateForChatMessage(date: Date, language = getLanguage(ptEn)) {
|
|
23
23
|
const formatted: string[] = []
|
|
24
24
|
const now = new Date()
|
|
25
25
|
const isToday = date.toDateString() === now.toDateString()
|
|
@@ -36,7 +36,7 @@ export function formatDateForChatMessage(date: Date, language: Language = getLan
|
|
|
36
36
|
* @returns an object containing functions for formatting dates.
|
|
37
37
|
*/
|
|
38
38
|
export function useDateFormatter() {
|
|
39
|
-
const language = useLanguage()
|
|
39
|
+
const language = useLanguage(ptEn)
|
|
40
40
|
return {
|
|
41
41
|
/**
|
|
42
42
|
* @param date the date to format using {@link formatDateForChatMessage}.
|
package/src/utils/error.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getLanguage } from '@stack-spot/portal-translate'
|
|
1
|
+
import { getLanguage, ptEn } from '@stack-spot/portal-translate'
|
|
2
2
|
|
|
3
3
|
const httpErrors: Record<'en' | 'pt', Record<number, string>> = {
|
|
4
4
|
en: {
|
|
@@ -48,7 +48,7 @@ const httpErrors: Record<'en' | 'pt', Record<number, string>> = {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
function getGenericErrorBasedOnStatus(status: number) {
|
|
51
|
-
return httpErrors[getLanguage()][status] ?? `Unknown error. Status code: ${status}.`
|
|
51
|
+
return httpErrors[getLanguage(ptEn)][status] ?? `Unknown error. Status code: ${status}.`
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
export function treatHTMLInErrorMessage(text: string, status: number) {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
class PlanningToolDictionaryHelper {
|
|
2
|
+
static instance: PlanningToolDictionaryHelper | undefined
|
|
3
|
+
private toolExecutionIdPlanningStep: Record<string, string> = {}
|
|
4
|
+
private toolExecutionIdToolStep: Record<string, string> = {}
|
|
5
|
+
|
|
6
|
+
private constructor() {
|
|
7
|
+
PlanningToolDictionaryHelper.instance = this
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
static create() {
|
|
11
|
+
return PlanningToolDictionaryHelper.instance ?? new PlanningToolDictionaryHelper()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
setMessageIdPlanningStepToolExecutionId(messageId: string, toolExecutionId: string){
|
|
15
|
+
this.toolExecutionIdPlanningStep[toolExecutionId] = messageId
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
setMessageIdToolStepToolExecutionId(messageId: string, toolExecutionId: string){
|
|
19
|
+
this.toolExecutionIdToolStep[toolExecutionId] = messageId
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getMessageIdPlanningStepFromToolExecutionId(toolExecutionId: string){
|
|
23
|
+
return this.toolExecutionIdPlanningStep[toolExecutionId]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getMessageIdToolStepFromToolExecutionId(toolExecutionId: string){
|
|
27
|
+
return this.toolExecutionIdToolStep[toolExecutionId]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const planningToolDictionaryHelper = PlanningToolDictionaryHelper.create()
|
|
32
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ChatEntry, TextChatEntry } from '../state/ChatEntry'
|
|
2
|
+
import { planningToolDictionaryHelper } from './planning-tool'
|
|
3
|
+
|
|
4
|
+
export const updateToolStep = (messages: ChatEntry[], executionId: string,
|
|
5
|
+
newStatus: 'pending' | 'running' | 'success' | 'error' | 'awaiting_approval') => {
|
|
6
|
+
|
|
7
|
+
// if last message is a user message, no update in tool status is needed
|
|
8
|
+
if (messages[messages.length-1].getValue().agentType === 'user') return
|
|
9
|
+
|
|
10
|
+
const messageId = planningToolDictionaryHelper.getMessageIdPlanningStepFromToolExecutionId(executionId)
|
|
11
|
+
const message = messages.find((message) => `${message.id}` === messageId)
|
|
12
|
+
let update = false
|
|
13
|
+
const messageValue = message?.getValue()
|
|
14
|
+
messageValue?.steps?.map((step) => {
|
|
15
|
+
if (step.type === 'step') {
|
|
16
|
+
const tool = step.attempts?.[0].tools?.[0]
|
|
17
|
+
if (tool?.executionId === executionId && step.status !== newStatus) {
|
|
18
|
+
step.status = newStatus
|
|
19
|
+
update = true
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
if (update) {
|
|
25
|
+
message?.setValue({ ...messageValue as TextChatEntry })
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -9,7 +9,7 @@ import { PhoneInput } from 'react-international-phone'
|
|
|
9
9
|
import 'react-international-phone/style.css'
|
|
10
10
|
import { FileDescription } from '../../components/FileDescription'
|
|
11
11
|
import { Markdown } from '../../components/Markdown'
|
|
12
|
-
import { useChatEntry, useCurrentChat, useWidget } from '../../context/hooks'
|
|
12
|
+
import { useChatEntry, useCurrentChat, useCurrentChatState, useWidget } from '../../context/hooks'
|
|
13
13
|
import { useMidnightUpdateView } from '../../hooks/midnight-update-view'
|
|
14
14
|
import { ChatEntry, SerializableAction, TextChatEntry } from '../../state/ChatEntry'
|
|
15
15
|
import { useDateFormatter } from '../../utils/date'
|
|
@@ -17,7 +17,7 @@ import { toolById } from '../../utils/tools'
|
|
|
17
17
|
import { AgentInfo } from './AgentInfo'
|
|
18
18
|
import { useChatScrollToBottomEffect } from './chat-scroll'
|
|
19
19
|
import { onCopyAll, onCopyCode, onLikeOrDislike } from './events'
|
|
20
|
-
import { StepsList } from './StepsList'
|
|
20
|
+
import { StepsList, StepsPlaceholder } from './StepsList'
|
|
21
21
|
|
|
22
22
|
export interface CustomRenderResult {
|
|
23
23
|
/**
|
|
@@ -218,6 +218,7 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage, cust
|
|
|
218
218
|
{ searchAgentsRequest: { ids: entry.tools || [''] } }, { enabled: !!entry.tools })
|
|
219
219
|
const [copied, setCopied] = useState(false)
|
|
220
220
|
const [showUserButtonCopy, setShowUserButtonCopy] = useState(false)
|
|
221
|
+
const isPlanning = useCurrentChatState('isPlaning') ?? false
|
|
221
222
|
|
|
222
223
|
useChatScrollToBottomEffect(ref, [entry])
|
|
223
224
|
useMidnightUpdateView()
|
|
@@ -343,7 +344,7 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage, cust
|
|
|
343
344
|
widget.set('panel', 'resources')
|
|
344
345
|
}
|
|
345
346
|
|
|
346
|
-
return (entry.content || entry.error || !!entry.steps?.length || entry.upload?.length) && (
|
|
347
|
+
return (entry.content || entry.error || !!entry.steps?.length || entry.upload?.length || isPlanning) && (
|
|
347
348
|
<li key={entry.messageId} className={entry.agentType} ref={ref}>
|
|
348
349
|
<div className="chat-message-container"
|
|
349
350
|
onMouseEnter={entry.agentType === 'user' ? () => setShowUserButtonCopy(true) : undefined}
|
|
@@ -356,11 +357,14 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage, cust
|
|
|
356
357
|
{!!entry.badges?.length && <div className="badges">
|
|
357
358
|
{entry.badges.map((b, index) => <Badge key={index} colorPalette={b.color ?? 'cyan'} appearance="square">{b.label}</Badge>)}
|
|
358
359
|
</div>}
|
|
360
|
+
|
|
361
|
+
{!!entry.steps?.length && <StepsList steps={entry.steps} chatId={chat.id} messageId={message.id} />}
|
|
362
|
+
|
|
359
363
|
{renderContent()}
|
|
360
364
|
|
|
361
|
-
{!!entry.steps?.length && <StepsList steps={entry.steps} chatId={chat.id} messageId={message.id} />}
|
|
362
365
|
</div>
|
|
363
366
|
)}
|
|
367
|
+
{isPlanning && entry.agentType === 'bot' && isLast && <StepsPlaceholder /> }
|
|
364
368
|
|
|
365
369
|
{entry.error && <Alert type="error">{entry.error}</Alert>}
|
|
366
370
|
</div>
|