@budibase/frontend-core 3.23.4 → 3.23.6
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/frontend-core",
|
|
3
|
-
"version": "3.23.
|
|
3
|
+
"version": "3.23.6",
|
|
4
4
|
"description": "Budibase frontend core libraries used in builder and client",
|
|
5
5
|
"author": "Budibase",
|
|
6
6
|
"license": "MPL-2.0",
|
|
@@ -17,5 +17,5 @@
|
|
|
17
17
|
"shortid": "2.2.15",
|
|
18
18
|
"socket.io-client": "^4.7.5"
|
|
19
19
|
},
|
|
20
|
-
"gitHead": "
|
|
20
|
+
"gitHead": "993c44f2265cdca05008c355c1225967e2eb10c2"
|
|
21
21
|
}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { MarkdownViewer, notifications } from "@budibase/bbui"
|
|
3
|
+
import type { UserMessage, AgentChat } from "@budibase/types"
|
|
4
|
+
import BBAI from "../../icons/BBAI.svelte"
|
|
5
|
+
import { tick } from "svelte"
|
|
6
|
+
import { onDestroy } from "svelte"
|
|
7
|
+
import { onMount } from "svelte"
|
|
8
|
+
import { createAPIClient } from "@budibase/frontend-core"
|
|
9
|
+
import { createEventDispatcher } from "svelte"
|
|
10
|
+
|
|
11
|
+
export let API = createAPIClient()
|
|
12
|
+
|
|
13
|
+
export let workspaceId: string
|
|
14
|
+
export let chat: AgentChat
|
|
15
|
+
|
|
16
|
+
const dispatch = createEventDispatcher<{ chatSaved: { chatId: string } }>()
|
|
17
|
+
|
|
18
|
+
let inputValue = ""
|
|
19
|
+
let loading: boolean = false
|
|
20
|
+
let chatAreaElement: HTMLDivElement
|
|
21
|
+
let observer: MutationObserver
|
|
22
|
+
let textareaElement: HTMLTextAreaElement
|
|
23
|
+
|
|
24
|
+
$: if (chat.messages.length) {
|
|
25
|
+
scrollToBottom()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function scrollToBottom() {
|
|
29
|
+
await tick()
|
|
30
|
+
if (chatAreaElement) {
|
|
31
|
+
chatAreaElement.scrollTop = chatAreaElement.scrollHeight
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function handleKeyDown(event: any) {
|
|
36
|
+
if (event.key === "Enter" && !event.shiftKey) {
|
|
37
|
+
event.preventDefault()
|
|
38
|
+
await prompt()
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function prompt() {
|
|
43
|
+
if (!chat) {
|
|
44
|
+
chat = { title: "", messages: [] }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const userMessage: UserMessage = { role: "user", content: inputValue }
|
|
48
|
+
|
|
49
|
+
const updatedChat = {
|
|
50
|
+
...chat,
|
|
51
|
+
messages: [...chat.messages, userMessage],
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Update local display immediately with user message
|
|
55
|
+
chat = updatedChat
|
|
56
|
+
|
|
57
|
+
// Ensure we scroll to the new message
|
|
58
|
+
await scrollToBottom()
|
|
59
|
+
|
|
60
|
+
inputValue = ""
|
|
61
|
+
loading = true
|
|
62
|
+
|
|
63
|
+
let streamingContent = ""
|
|
64
|
+
let isToolCall = false
|
|
65
|
+
let toolCallInfo: string = ""
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
await API.agentChatStream(
|
|
69
|
+
updatedChat,
|
|
70
|
+
workspaceId,
|
|
71
|
+
chunk => {
|
|
72
|
+
if (chunk.type === "content") {
|
|
73
|
+
// Accumulate streaming content
|
|
74
|
+
streamingContent += chunk.content || ""
|
|
75
|
+
|
|
76
|
+
// Update chat with partial content
|
|
77
|
+
const updatedMessages = [...updatedChat.messages]
|
|
78
|
+
|
|
79
|
+
// Find or create assistant message
|
|
80
|
+
const lastMessage = updatedMessages[updatedMessages.length - 1]
|
|
81
|
+
if (lastMessage?.role === "assistant") {
|
|
82
|
+
lastMessage.content =
|
|
83
|
+
streamingContent + (isToolCall ? toolCallInfo : "")
|
|
84
|
+
} else {
|
|
85
|
+
updatedMessages.push({
|
|
86
|
+
role: "assistant",
|
|
87
|
+
content: streamingContent + (isToolCall ? toolCallInfo : ""),
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
chat = {
|
|
92
|
+
...chat,
|
|
93
|
+
messages: updatedMessages,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Auto-scroll as content streams
|
|
97
|
+
scrollToBottom()
|
|
98
|
+
} else if (chunk.type === "tool_call_start") {
|
|
99
|
+
isToolCall = true
|
|
100
|
+
toolCallInfo = `\n\n**🔧 Executing Tool:** ${chunk.toolCall?.name}\n**Parameters:**\n\`\`\`json\n${chunk.toolCall?.arguments}\n\`\`\`\n`
|
|
101
|
+
|
|
102
|
+
const updatedMessages = [...updatedChat.messages]
|
|
103
|
+
const lastMessage = updatedMessages[updatedMessages.length - 1]
|
|
104
|
+
if (lastMessage?.role === "assistant") {
|
|
105
|
+
lastMessage.content = streamingContent + toolCallInfo
|
|
106
|
+
} else {
|
|
107
|
+
updatedMessages.push({
|
|
108
|
+
role: "assistant",
|
|
109
|
+
content: streamingContent + toolCallInfo,
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
chat = {
|
|
114
|
+
...chat,
|
|
115
|
+
messages: updatedMessages,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
scrollToBottom()
|
|
119
|
+
} else if (chunk.type === "tool_call_result") {
|
|
120
|
+
const resultInfo = chunk.toolResult?.error
|
|
121
|
+
? `\n**❌ Tool Error:** ${chunk.toolResult.error}`
|
|
122
|
+
: `\n**✅ Tool Result:** Complete`
|
|
123
|
+
|
|
124
|
+
toolCallInfo += resultInfo
|
|
125
|
+
|
|
126
|
+
const updatedMessages = [...updatedChat.messages]
|
|
127
|
+
const lastMessage = updatedMessages[updatedMessages.length - 1]
|
|
128
|
+
if (lastMessage?.role === "assistant") {
|
|
129
|
+
lastMessage.content = streamingContent + toolCallInfo
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
chat = {
|
|
133
|
+
...chat,
|
|
134
|
+
messages: updatedMessages,
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
scrollToBottom()
|
|
138
|
+
} else if (chunk.type === "chat_saved") {
|
|
139
|
+
if (chunk.chat) {
|
|
140
|
+
chat = chunk.chat
|
|
141
|
+
if (chunk.chat._id) {
|
|
142
|
+
dispatch("chatSaved", { chatId: chunk.chat._id })
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} else if (chunk.type === "done") {
|
|
146
|
+
loading = false
|
|
147
|
+
scrollToBottom()
|
|
148
|
+
} else if (chunk.type === "error") {
|
|
149
|
+
notifications.error(chunk.content || "An error occurred")
|
|
150
|
+
loading = false
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
error => {
|
|
154
|
+
console.error("Streaming error:", error)
|
|
155
|
+
notifications.error(error.message)
|
|
156
|
+
loading = false
|
|
157
|
+
}
|
|
158
|
+
)
|
|
159
|
+
} catch (err: any) {
|
|
160
|
+
console.error(err)
|
|
161
|
+
notifications.error(err.message)
|
|
162
|
+
loading = false
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Return focus to textarea after the response
|
|
166
|
+
await tick()
|
|
167
|
+
if (textareaElement) {
|
|
168
|
+
textareaElement.focus()
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
onMount(async () => {
|
|
173
|
+
chat = { title: "", messages: [] }
|
|
174
|
+
|
|
175
|
+
// Ensure we always autoscroll to reveal new messages
|
|
176
|
+
observer = new MutationObserver(async () => {
|
|
177
|
+
await tick()
|
|
178
|
+
if (chatAreaElement) {
|
|
179
|
+
chatAreaElement.scrollTop = chatAreaElement.scrollHeight
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
if (chatAreaElement) {
|
|
184
|
+
observer.observe(chatAreaElement, {
|
|
185
|
+
childList: true,
|
|
186
|
+
subtree: true,
|
|
187
|
+
attributes: true,
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
await tick()
|
|
192
|
+
if (textareaElement) {
|
|
193
|
+
textareaElement.focus()
|
|
194
|
+
}
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
onDestroy(() => {
|
|
198
|
+
observer.disconnect()
|
|
199
|
+
})
|
|
200
|
+
</script>
|
|
201
|
+
|
|
202
|
+
<div class="chat-area" bind:this={chatAreaElement}>
|
|
203
|
+
<div class="chatbox">
|
|
204
|
+
{#each chat.messages as message}
|
|
205
|
+
{#if message.role === "user"}
|
|
206
|
+
<div class="message user">
|
|
207
|
+
<MarkdownViewer
|
|
208
|
+
value={typeof message.content === "string"
|
|
209
|
+
? message.content
|
|
210
|
+
: message.content.length > 0
|
|
211
|
+
? message.content
|
|
212
|
+
.map(part =>
|
|
213
|
+
part.type === "text"
|
|
214
|
+
? part.text
|
|
215
|
+
: `${part.type} content not supported`
|
|
216
|
+
)
|
|
217
|
+
.join("")
|
|
218
|
+
: "[Empty message]"}
|
|
219
|
+
/>
|
|
220
|
+
</div>
|
|
221
|
+
{:else if message.role === "assistant" && message.content}
|
|
222
|
+
<div class="message assistant">
|
|
223
|
+
<MarkdownViewer value={message.content} />
|
|
224
|
+
</div>
|
|
225
|
+
{/if}
|
|
226
|
+
{/each}
|
|
227
|
+
{#if loading}
|
|
228
|
+
<div class="message system">
|
|
229
|
+
<BBAI size="48px" animate />
|
|
230
|
+
</div>
|
|
231
|
+
{/if}
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
<div class="input-wrapper">
|
|
235
|
+
<textarea
|
|
236
|
+
bind:value={inputValue}
|
|
237
|
+
bind:this={textareaElement}
|
|
238
|
+
class="input spectrum-Textfield-input"
|
|
239
|
+
on:keydown={handleKeyDown}
|
|
240
|
+
placeholder="Ask anything"
|
|
241
|
+
disabled={loading}
|
|
242
|
+
/>
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
|
|
246
|
+
<style>
|
|
247
|
+
.chat-area {
|
|
248
|
+
flex: 1 1 auto;
|
|
249
|
+
display: flex;
|
|
250
|
+
flex-direction: column;
|
|
251
|
+
overflow-y: auto;
|
|
252
|
+
height: 0;
|
|
253
|
+
}
|
|
254
|
+
.chatbox {
|
|
255
|
+
display: flex;
|
|
256
|
+
flex-direction: column;
|
|
257
|
+
gap: 24px;
|
|
258
|
+
width: 600px;
|
|
259
|
+
margin: 0 auto;
|
|
260
|
+
flex: 1 1 auto;
|
|
261
|
+
padding: 48px 0 24px 0;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.message {
|
|
265
|
+
display: flex;
|
|
266
|
+
flex-direction: column;
|
|
267
|
+
max-width: 80%;
|
|
268
|
+
padding: var(--spacing-l);
|
|
269
|
+
border-radius: 20px;
|
|
270
|
+
font-size: 16px;
|
|
271
|
+
color: var(--spectrum-global-color-gray-900);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.message.user {
|
|
275
|
+
align-self: flex-end;
|
|
276
|
+
background-color: var(--grey-3);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.message.assistant {
|
|
280
|
+
align-self: flex-start;
|
|
281
|
+
background-color: var(--grey-1);
|
|
282
|
+
border: 1px solid var(--grey-3);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.message.system {
|
|
286
|
+
align-self: flex-start;
|
|
287
|
+
background: none;
|
|
288
|
+
padding-left: 0;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.input-wrapper {
|
|
292
|
+
position: sticky;
|
|
293
|
+
bottom: 0;
|
|
294
|
+
width: 600px;
|
|
295
|
+
margin: 0 auto;
|
|
296
|
+
background: var(--background-alt);
|
|
297
|
+
padding-bottom: 32px;
|
|
298
|
+
display: flex;
|
|
299
|
+
flex-direction: column;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.input {
|
|
303
|
+
width: 100%;
|
|
304
|
+
height: 100px;
|
|
305
|
+
top: 0;
|
|
306
|
+
resize: none;
|
|
307
|
+
padding: 20px;
|
|
308
|
+
font-size: 16px;
|
|
309
|
+
background-color: var(--grey-3);
|
|
310
|
+
color: var(--grey-9);
|
|
311
|
+
border-radius: 16px;
|
|
312
|
+
border: none;
|
|
313
|
+
outline: none;
|
|
314
|
+
min-height: 100px;
|
|
315
|
+
margin-bottom: 8px;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.input::placeholder {
|
|
319
|
+
color: var(--spectrum-global-color-gray-600);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/* Style the markdown tool sections in assistant messages */
|
|
323
|
+
:global(.assistant strong) {
|
|
324
|
+
color: var(--spectrum-global-color-static-seafoam-700);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
:global(.assistant h3) {
|
|
328
|
+
margin-top: var(--spacing-m);
|
|
329
|
+
color: var(--spectrum-global-color-static-seafoam-700);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
:global(.assistant pre) {
|
|
333
|
+
background-color: var(--grey-2);
|
|
334
|
+
border: 1px solid var(--grey-3);
|
|
335
|
+
border-radius: 4px;
|
|
336
|
+
}
|
|
337
|
+
</style>
|
package/src/components/index.js
CHANGED
|
@@ -10,3 +10,4 @@ export { default as FilterUsers } from "./FilterUsers.svelte"
|
|
|
10
10
|
export { default as ChangePasswordModal } from "./ChangePasswordModal.svelte"
|
|
11
11
|
export { default as ProfileModal } from "./ProfileModal.svelte"
|
|
12
12
|
export { default as PasswordRepeatInput } from "./PasswordRepeatInput.svelte"
|
|
13
|
+
export { default as Chatbox } from "./Chatbox/index.svelte"
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export let size = "64px"
|
|
3
|
+
export let animate: boolean = false
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<svg
|
|
7
|
+
viewBox="0 0 150 150"
|
|
8
|
+
width={size}
|
|
9
|
+
fill="none"
|
|
10
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
11
|
+
>
|
|
12
|
+
<g id="bbai">
|
|
13
|
+
<g id="Group 48096461">
|
|
14
|
+
{#if animate}
|
|
15
|
+
<animateTransform
|
|
16
|
+
attributeName="transform"
|
|
17
|
+
attributeType="XML"
|
|
18
|
+
type="rotate"
|
|
19
|
+
from="0 75 75"
|
|
20
|
+
to="360 75 75"
|
|
21
|
+
dur="2.5s"
|
|
22
|
+
repeatCount="indefinite"
|
|
23
|
+
calcMode="spline"
|
|
24
|
+
keyTimes="0;1"
|
|
25
|
+
keySplines="0.3 0 0.5 1"
|
|
26
|
+
/>
|
|
27
|
+
{/if}
|
|
28
|
+
<path
|
|
29
|
+
id="Vector"
|
|
30
|
+
d="M22.3457 95.0839L51.9032 124.642C53.199 125.937 55.2988 125.937 56.5946 124.642L69.4653 111.771C70.6236 110.612 71.171 108.976 70.9436 107.352L67.4872 82.9246C67.2334 81.1475 65.8371 79.7512 64.0626 79.4999L39.6354 76.0436C38.0143 75.8135 36.3774 76.3609 35.2164 77.5218L22.3457 90.3926C21.0499 91.6884 21.0499 93.7881 22.3457 95.0839Z"
|
|
31
|
+
fill="url(#paint0_linear_605_124)"
|
|
32
|
+
/>
|
|
33
|
+
<path
|
|
34
|
+
id="Vector_2"
|
|
35
|
+
d="M92.0381 124.643L121.596 95.0851C122.891 93.7893 122.891 91.6895 121.596 90.3937L108.725 77.5229C107.567 76.3647 105.93 75.8172 104.306 76.0447L79.8787 79.501C78.1016 79.7549 76.7053 81.1512 76.454 82.9257L72.9977 107.353C72.7676 108.974 73.315 110.611 74.4759 111.772L87.3467 124.643C88.6425 125.938 90.7422 125.938 92.0381 124.643Z"
|
|
36
|
+
fill="url(#paint1_linear_605_124)"
|
|
37
|
+
/>
|
|
38
|
+
<path
|
|
39
|
+
id="Vector_3"
|
|
40
|
+
d="M121.654 54.92L92.0968 25.3624C90.801 24.0666 88.7012 24.0666 87.4054 25.3624L74.5347 38.2332C73.3764 39.3915 72.829 41.0284 73.0564 42.6521L76.5128 67.0793C76.7666 68.8565 78.1629 70.2527 79.9374 70.504L104.365 73.9603C105.986 74.1904 107.623 73.643 108.784 72.4821L121.654 59.6113C122.95 58.3155 122.95 56.2158 121.654 54.92Z"
|
|
41
|
+
fill="url(#paint2_linear_605_124)"
|
|
42
|
+
/>
|
|
43
|
+
<path
|
|
44
|
+
id="Vector_4"
|
|
45
|
+
d="M51.9619 25.3613L22.4044 54.9188C21.1086 56.2146 21.1086 58.3144 22.4044 59.6102L35.2752 72.481C36.4334 73.6393 38.0704 74.1867 39.6941 73.9592L64.1213 70.5029C65.8984 70.249 67.2947 68.8527 67.546 67.0782L71.0023 42.651C71.2324 41.0299 70.685 39.393 69.5241 38.2321L56.6533 25.3613C55.3575 24.0655 53.2578 24.0655 51.9619 25.3613Z"
|
|
46
|
+
fill="url(#paint3_linear_605_124)"
|
|
47
|
+
/>
|
|
48
|
+
</g>
|
|
49
|
+
</g>
|
|
50
|
+
<defs>
|
|
51
|
+
<linearGradient
|
|
52
|
+
id="paint0_linear_605_124"
|
|
53
|
+
x1="52.1505"
|
|
54
|
+
y1="121.517"
|
|
55
|
+
x2="68.292"
|
|
56
|
+
y2="84.222"
|
|
57
|
+
gradientUnits="userSpaceOnUse"
|
|
58
|
+
>
|
|
59
|
+
<stop stop-color="#6E56FF" />
|
|
60
|
+
<stop offset="1" stop-color="#9F8FFF" />
|
|
61
|
+
</linearGradient>
|
|
62
|
+
<linearGradient
|
|
63
|
+
id="paint1_linear_605_124"
|
|
64
|
+
x1="118.471"
|
|
65
|
+
y1="94.8378"
|
|
66
|
+
x2="81.1761"
|
|
67
|
+
y2="78.6963"
|
|
68
|
+
gradientUnits="userSpaceOnUse"
|
|
69
|
+
>
|
|
70
|
+
<stop stop-color="#6E56FF" />
|
|
71
|
+
<stop offset="1" stop-color="#9F8FFF" />
|
|
72
|
+
</linearGradient>
|
|
73
|
+
<linearGradient
|
|
74
|
+
id="paint2_linear_605_124"
|
|
75
|
+
x1="91.8495"
|
|
76
|
+
y1="28.4869"
|
|
77
|
+
x2="75.708"
|
|
78
|
+
y2="65.7819"
|
|
79
|
+
gradientUnits="userSpaceOnUse"
|
|
80
|
+
>
|
|
81
|
+
<stop stop-color="#6E56FF" />
|
|
82
|
+
<stop offset="1" stop-color="#9F8FFF" />
|
|
83
|
+
</linearGradient>
|
|
84
|
+
<linearGradient
|
|
85
|
+
id="paint3_linear_605_124"
|
|
86
|
+
x1="25.5289"
|
|
87
|
+
y1="55.1661"
|
|
88
|
+
x2="62.8239"
|
|
89
|
+
y2="71.3076"
|
|
90
|
+
gradientUnits="userSpaceOnUse"
|
|
91
|
+
>
|
|
92
|
+
<stop stop-color="#6E56FF" />
|
|
93
|
+
<stop offset="1" stop-color="#9F8FFF" />
|
|
94
|
+
</linearGradient>
|
|
95
|
+
</defs>
|
|
96
|
+
</svg>
|