@budibase/frontend-core 3.34.2 → 3.34.3
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.34.
|
|
3
|
+
"version": "3.34.3",
|
|
4
4
|
"description": "Budibase frontend core libraries used in builder and client",
|
|
5
5
|
"author": "Budibase",
|
|
6
6
|
"license": "MPL-2.0",
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
"test:watch": "vitest"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@ai-sdk/svelte": "^4.0.
|
|
14
|
+
"@ai-sdk/svelte": "^4.0.116",
|
|
15
15
|
"@budibase/bbui": "*",
|
|
16
16
|
"@budibase/shared-core": "*",
|
|
17
17
|
"@budibase/types": "*",
|
|
18
|
-
"ai": "^6.0.
|
|
18
|
+
"ai": "^6.0.116",
|
|
19
19
|
"dayjs": "^1.10.8",
|
|
20
20
|
"lodash": "4.17.23",
|
|
21
21
|
"shortid": "2.2.15",
|
|
@@ -24,5 +24,5 @@
|
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"vitest": "^3.2.4"
|
|
26
26
|
},
|
|
27
|
-
"gitHead": "
|
|
27
|
+
"gitHead": "9c56751662ed542fe5398a29d207dd55198c9f83"
|
|
28
28
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Icon } from "@budibase/bbui"
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
thinking?: boolean
|
|
6
|
+
label?: string
|
|
7
|
+
interactive?: boolean
|
|
8
|
+
expanded?: boolean
|
|
9
|
+
content?: string
|
|
10
|
+
ontoggle?: () => void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let {
|
|
14
|
+
thinking = false,
|
|
15
|
+
label = "Thought",
|
|
16
|
+
interactive = false,
|
|
17
|
+
expanded = false,
|
|
18
|
+
content = "",
|
|
19
|
+
ontoggle,
|
|
20
|
+
}: Props = $props()
|
|
21
|
+
|
|
22
|
+
const handleToggle = () => {
|
|
23
|
+
if (!interactive) {
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
ontoggle?.()
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<div class="reasoning-part">
|
|
32
|
+
<button
|
|
33
|
+
class="reasoning-toggle"
|
|
34
|
+
class:reasoning-toggle-static={!interactive}
|
|
35
|
+
type="button"
|
|
36
|
+
onclick={handleToggle}
|
|
37
|
+
aria-disabled={!interactive}
|
|
38
|
+
tabindex={interactive ? undefined : -1}
|
|
39
|
+
>
|
|
40
|
+
<span class="reasoning-icon" class:shimmer={thinking}>
|
|
41
|
+
<Icon
|
|
42
|
+
name="brain"
|
|
43
|
+
size="M"
|
|
44
|
+
color="var(--spectrum-global-color-gray-600)"
|
|
45
|
+
/>
|
|
46
|
+
</span>
|
|
47
|
+
<span class="reasoning-label" class:shimmer={thinking}>{label}</span>
|
|
48
|
+
</button>
|
|
49
|
+
{#if expanded && content}
|
|
50
|
+
<div class="reasoning-content">{content}</div>
|
|
51
|
+
{/if}
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<style>
|
|
55
|
+
.reasoning-part {
|
|
56
|
+
display: flex;
|
|
57
|
+
flex-direction: column;
|
|
58
|
+
gap: 8px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.reasoning-toggle {
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
gap: 6px;
|
|
65
|
+
padding: 0;
|
|
66
|
+
margin: 0;
|
|
67
|
+
background: none;
|
|
68
|
+
border: none;
|
|
69
|
+
cursor: pointer;
|
|
70
|
+
border-radius: 4px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.reasoning-toggle-static {
|
|
74
|
+
cursor: default;
|
|
75
|
+
pointer-events: none;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.reasoning-icon {
|
|
79
|
+
display: flex;
|
|
80
|
+
align-items: center;
|
|
81
|
+
justify-content: center;
|
|
82
|
+
flex-shrink: 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.reasoning-label {
|
|
86
|
+
font-size: 13px;
|
|
87
|
+
color: var(--spectrum-global-color-gray-600);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.reasoning-label.shimmer,
|
|
91
|
+
.reasoning-icon.shimmer {
|
|
92
|
+
animation: shimmer 2s ease-in-out infinite;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.reasoning-content {
|
|
96
|
+
font-size: 13px;
|
|
97
|
+
color: var(--spectrum-global-color-gray-600);
|
|
98
|
+
font-style: italic;
|
|
99
|
+
line-height: 1.4;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@keyframes shimmer {
|
|
103
|
+
0%,
|
|
104
|
+
100% {
|
|
105
|
+
opacity: 0.6;
|
|
106
|
+
}
|
|
107
|
+
50% {
|
|
108
|
+
opacity: 1;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
</style>
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
import { createAPIClient } from "@budibase/frontend-core"
|
|
18
18
|
import { Chat } from "@ai-sdk/svelte"
|
|
19
19
|
import { formatToolName } from "../../utils/aiTools"
|
|
20
|
+
import ReasoningStatus from "./ReasoningStatus.svelte"
|
|
20
21
|
import {
|
|
21
22
|
DefaultChatTransport,
|
|
22
23
|
isTextUIPart,
|
|
@@ -72,35 +73,12 @@
|
|
|
72
73
|
let expandedTools = $state<Record<string, boolean>>({})
|
|
73
74
|
let inputValue = $state("")
|
|
74
75
|
let lastInitialPrompt = $state("")
|
|
75
|
-
let reasoningTimers = $state<Record<string, number>>({})
|
|
76
76
|
let isPreparingResponse = $state(false)
|
|
77
|
-
let isHoldingFirstResponse = $state(false)
|
|
78
|
-
let firstResponseHoldTimer: ReturnType<typeof setTimeout> | undefined
|
|
79
|
-
|
|
80
|
-
const MIN_FIRST_RESPONSE_LOADING_MS = 1000
|
|
81
|
-
|
|
82
|
-
const clearFirstResponseHold = () => {
|
|
83
|
-
if (firstResponseHoldTimer) {
|
|
84
|
-
clearTimeout(firstResponseHoldTimer)
|
|
85
|
-
firstResponseHoldTimer = undefined
|
|
86
|
-
}
|
|
87
|
-
isHoldingFirstResponse = false
|
|
88
|
-
}
|
|
89
77
|
|
|
90
78
|
const resetPendingResponse = () => {
|
|
91
|
-
clearFirstResponseHold()
|
|
92
79
|
isPreparingResponse = false
|
|
93
80
|
}
|
|
94
81
|
|
|
95
|
-
const holdFirstResponse = () => {
|
|
96
|
-
clearFirstResponseHold()
|
|
97
|
-
isHoldingFirstResponse = true
|
|
98
|
-
firstResponseHoldTimer = setTimeout(() => {
|
|
99
|
-
isHoldingFirstResponse = false
|
|
100
|
-
firstResponseHoldTimer = undefined
|
|
101
|
-
}, MIN_FIRST_RESPONSE_LOADING_MS)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
82
|
const getReasoningText = (message: UIMessage<AgentMessageMetadata>) =>
|
|
105
83
|
(message.parts ?? [])
|
|
106
84
|
.filter(isReasoningUIPart)
|
|
@@ -112,6 +90,26 @@
|
|
|
112
90
|
part => isReasoningUIPart(part) && part.state === "streaming"
|
|
113
91
|
)
|
|
114
92
|
|
|
93
|
+
const hasVisibleAssistantContent = (
|
|
94
|
+
message: UIMessage<AgentMessageMetadata>
|
|
95
|
+
) => {
|
|
96
|
+
if (getReasoningText(message).trim()) {
|
|
97
|
+
return true
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (
|
|
101
|
+
(message.parts ?? []).some(
|
|
102
|
+
part =>
|
|
103
|
+
(isTextUIPart(part) && part.text.trim().length > 0) ||
|
|
104
|
+
isToolUIPart(part)
|
|
105
|
+
)
|
|
106
|
+
) {
|
|
107
|
+
return true
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return Boolean(message.metadata?.ragSources?.length)
|
|
111
|
+
}
|
|
112
|
+
|
|
115
113
|
const hasToolError = (message: UIMessage<AgentMessageMetadata>) =>
|
|
116
114
|
(message.parts ?? []).some(
|
|
117
115
|
part => isToolUIPart(part) && part.state === "output-error"
|
|
@@ -138,54 +136,6 @@
|
|
|
138
136
|
return displayName
|
|
139
137
|
}
|
|
140
138
|
|
|
141
|
-
$effect(() => {
|
|
142
|
-
const interval = setInterval(() => {
|
|
143
|
-
let updated = false
|
|
144
|
-
const newTimers = { ...reasoningTimers }
|
|
145
|
-
|
|
146
|
-
for (const message of messages) {
|
|
147
|
-
if (message.role !== "assistant") continue
|
|
148
|
-
const createdAt = message.metadata?.createdAt
|
|
149
|
-
const completedAt = message.metadata?.completedAt
|
|
150
|
-
const id = `${message.id}-reasoning`
|
|
151
|
-
|
|
152
|
-
if (!createdAt) continue
|
|
153
|
-
|
|
154
|
-
if (completedAt) {
|
|
155
|
-
const finalElapsed = (completedAt - createdAt) / 1000
|
|
156
|
-
if (newTimers[id] !== finalElapsed) {
|
|
157
|
-
newTimers[id] = finalElapsed
|
|
158
|
-
updated = true
|
|
159
|
-
}
|
|
160
|
-
continue
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const toolError = hasToolError(message)
|
|
164
|
-
if (toolError) {
|
|
165
|
-
if (newTimers[id] == null) {
|
|
166
|
-
newTimers[id] = (Date.now() - createdAt) / 1000
|
|
167
|
-
updated = true
|
|
168
|
-
}
|
|
169
|
-
continue
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (isReasoningStreaming(message)) {
|
|
173
|
-
const newElapsed = (Date.now() - createdAt) / 1000
|
|
174
|
-
if (newTimers[id] !== newElapsed) {
|
|
175
|
-
newTimers[id] = newElapsed
|
|
176
|
-
updated = true
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (updated) {
|
|
182
|
-
reasoningTimers = newTimers
|
|
183
|
-
}
|
|
184
|
-
}, 100)
|
|
185
|
-
|
|
186
|
-
return () => clearInterval(interval)
|
|
187
|
-
})
|
|
188
|
-
|
|
189
139
|
const PREVIEW_CHAT_APP_ID = "agent-preview"
|
|
190
140
|
|
|
191
141
|
let resolvedChatAppId = $state<string | undefined>()
|
|
@@ -281,28 +231,19 @@
|
|
|
281
231
|
})
|
|
282
232
|
|
|
283
233
|
let messages = $derived(chatInstance.messages)
|
|
284
|
-
let
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
: messages[messages.length - 1]
|
|
234
|
+
let lastMessage = $derived(messages[messages.length - 1])
|
|
235
|
+
let lastAssistantMessage = $derived(
|
|
236
|
+
messages.findLast(message => message.role === "assistant")
|
|
288
237
|
)
|
|
289
238
|
let isBusy = $derived(
|
|
290
239
|
chatInstance.status === "streaming" || chatInstance.status === "submitted"
|
|
291
240
|
)
|
|
292
|
-
let isRequestPending = $derived(
|
|
293
|
-
isPreparingResponse || isHoldingFirstResponse || isBusy
|
|
294
|
-
)
|
|
241
|
+
let isRequestPending = $derived(isPreparingResponse || isBusy)
|
|
295
242
|
let showPendingAssistantState = $derived(
|
|
296
|
-
isPreparingResponse ||
|
|
297
|
-
((isBusy || isHoldingFirstResponse) &&
|
|
298
|
-
lastVisibleMessage?.role === "user")
|
|
243
|
+
isPreparingResponse || (isBusy && lastMessage?.role === "user")
|
|
299
244
|
)
|
|
300
245
|
let canStart = $derived(inputValue.trim().length > 0)
|
|
301
|
-
let hasMessages = $derived(
|
|
302
|
-
messages.some(
|
|
303
|
-
message => !isHoldingFirstResponse || message.role !== "assistant"
|
|
304
|
-
)
|
|
305
|
-
)
|
|
246
|
+
let hasMessages = $derived(messages.length > 0)
|
|
306
247
|
let showConversationStarters = $derived(
|
|
307
248
|
!isRequestPending &&
|
|
308
249
|
!hasMessages &&
|
|
@@ -415,11 +356,7 @@
|
|
|
415
356
|
notifications.error(message)
|
|
416
357
|
}
|
|
417
358
|
|
|
418
|
-
const isFirstMessage = !messages.length
|
|
419
359
|
isPreparingResponse = true
|
|
420
|
-
if (isFirstMessage) {
|
|
421
|
-
holdFirstResponse()
|
|
422
|
-
}
|
|
423
360
|
|
|
424
361
|
const chatAppIdFromEnsure = await ensureChatApp()
|
|
425
362
|
|
|
@@ -575,186 +512,165 @@
|
|
|
575
512
|
<div class="message user">
|
|
576
513
|
<MarkdownViewer value={getUserMessageText(message)} />
|
|
577
514
|
</div>
|
|
578
|
-
{:else if message.role === "assistant"
|
|
515
|
+
{:else if message.role === "assistant"}
|
|
579
516
|
{@const reasoningText = getReasoningText(message)}
|
|
580
517
|
{@const reasoningId = `${message.id}-reasoning`}
|
|
518
|
+
{@const pendingAssistant =
|
|
519
|
+
isBusy &&
|
|
520
|
+
lastAssistantMessage?.id === message.id &&
|
|
521
|
+
!hasVisibleAssistantContent(message)}
|
|
581
522
|
{@const toolError = hasToolError(message)}
|
|
582
523
|
{@const messageError = getMessageError(message)}
|
|
583
524
|
{@const reasoningStreaming = isReasoningStreaming(message)}
|
|
584
525
|
{@const isThinking =
|
|
585
|
-
reasoningStreaming &&
|
|
526
|
+
(reasoningStreaming || pendingAssistant) &&
|
|
586
527
|
!toolError &&
|
|
587
528
|
!messageError &&
|
|
588
529
|
!message.metadata?.completedAt}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
<
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
530
|
+
{#if hasVisibleAssistantContent(message) || pendingAssistant}
|
|
531
|
+
<div class="message assistant">
|
|
532
|
+
{#if reasoningText || pendingAssistant}
|
|
533
|
+
<ReasoningStatus
|
|
534
|
+
thinking={isThinking}
|
|
535
|
+
label={isThinking ? "Thinking" : "Thought"}
|
|
536
|
+
interactive={!!reasoningText}
|
|
537
|
+
expanded={Boolean(expandedTools[reasoningId])}
|
|
538
|
+
content={reasoningText}
|
|
539
|
+
ontoggle={() =>
|
|
596
540
|
(expandedTools = {
|
|
597
541
|
...expandedTools,
|
|
598
542
|
[reasoningId]: !expandedTools[reasoningId],
|
|
599
543
|
})}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
{#if isTextUIPart(part)}
|
|
624
|
-
<MarkdownViewer value={part.text} />
|
|
625
|
-
{:else if isToolUIPart(part)}
|
|
626
|
-
{@const rawToolName = getToolName(part)}
|
|
627
|
-
{@const displayToolName = formatToolName(
|
|
628
|
-
rawToolName,
|
|
629
|
-
getToolDisplayName(message, rawToolName)
|
|
630
|
-
)}
|
|
631
|
-
{@const toolId = `${message.id}-${rawToolName}-${partIndex}`}
|
|
632
|
-
{@const isRunning =
|
|
633
|
-
part.state === "input-streaming" ||
|
|
634
|
-
part.state === "input-available"}
|
|
635
|
-
{@const isSuccess = part.state === "output-available"}
|
|
636
|
-
{@const isError = part.state === "output-error"}
|
|
637
|
-
<div class="tool-part" class:tool-running={isRunning}>
|
|
638
|
-
<button
|
|
639
|
-
class="tool-header"
|
|
640
|
-
class:tool-header-expanded={expandedTools[toolId]}
|
|
641
|
-
type="button"
|
|
642
|
-
onclick={() => toggleTool(toolId)}
|
|
643
|
-
>
|
|
644
|
-
<span
|
|
645
|
-
class="tool-chevron"
|
|
646
|
-
class:expanded={expandedTools[toolId]}
|
|
544
|
+
/>
|
|
545
|
+
{/if}
|
|
546
|
+
{#each message.parts ?? [] as part, partIndex}
|
|
547
|
+
{#if isTextUIPart(part)}
|
|
548
|
+
<MarkdownViewer value={part.text} />
|
|
549
|
+
{:else if isToolUIPart(part)}
|
|
550
|
+
{@const rawToolName = getToolName(part)}
|
|
551
|
+
{@const displayToolName = formatToolName(
|
|
552
|
+
rawToolName,
|
|
553
|
+
getToolDisplayName(message, rawToolName)
|
|
554
|
+
)}
|
|
555
|
+
{@const toolId = `${message.id}-${rawToolName}-${partIndex}`}
|
|
556
|
+
{@const isRunning =
|
|
557
|
+
part.state === "input-streaming" ||
|
|
558
|
+
part.state === "input-available"}
|
|
559
|
+
{@const isSuccess = part.state === "output-available"}
|
|
560
|
+
{@const isError = part.state === "output-error"}
|
|
561
|
+
<div class="tool-part" class:tool-running={isRunning}>
|
|
562
|
+
<button
|
|
563
|
+
class="tool-header"
|
|
564
|
+
class:tool-header-expanded={expandedTools[toolId]}
|
|
565
|
+
type="button"
|
|
566
|
+
onclick={() => toggleTool(toolId)}
|
|
647
567
|
>
|
|
648
|
-
<span
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
size="M"
|
|
652
|
-
weight="regular"
|
|
653
|
-
color="var(--spectrum-global-color-gray-600)"
|
|
654
|
-
/>
|
|
655
|
-
</span>
|
|
656
|
-
<span class="tool-chevron-icon tool-chevron-icon-expanded">
|
|
657
|
-
<Icon
|
|
658
|
-
name="minus"
|
|
659
|
-
size="M"
|
|
660
|
-
weight="regular"
|
|
661
|
-
color="var(--spectrum-global-color-gray-600)"
|
|
662
|
-
/>
|
|
663
|
-
</span>
|
|
664
|
-
</span>
|
|
665
|
-
<span class="tool-call-label">Tool call</span>
|
|
666
|
-
<div class="tool-name-wrapper">
|
|
667
|
-
<span class="tool-name-primary"
|
|
668
|
-
>{displayToolName.primary}</span
|
|
568
|
+
<span
|
|
569
|
+
class="tool-chevron"
|
|
570
|
+
class:expanded={expandedTools[toolId]}
|
|
669
571
|
>
|
|
670
|
-
|
|
671
|
-
{#if isRunning || isError || isSuccess}
|
|
672
|
-
<span class="tool-status">
|
|
673
|
-
{#if isRunning}
|
|
674
|
-
<ProgressCircle size="S" />
|
|
675
|
-
{:else if isError}
|
|
572
|
+
<span class="tool-chevron-icon tool-chevron-icon-default">
|
|
676
573
|
<Icon
|
|
677
|
-
name="
|
|
678
|
-
size="
|
|
679
|
-
|
|
574
|
+
name="wrench"
|
|
575
|
+
size="M"
|
|
576
|
+
weight="regular"
|
|
577
|
+
color="var(--spectrum-global-color-gray-600)"
|
|
680
578
|
/>
|
|
681
|
-
|
|
579
|
+
</span>
|
|
580
|
+
<span
|
|
581
|
+
class="tool-chevron-icon tool-chevron-icon-expanded"
|
|
582
|
+
>
|
|
682
583
|
<Icon
|
|
683
|
-
name="
|
|
684
|
-
size="
|
|
685
|
-
|
|
584
|
+
name="minus"
|
|
585
|
+
size="M"
|
|
586
|
+
weight="regular"
|
|
587
|
+
color="var(--spectrum-global-color-gray-600)"
|
|
686
588
|
/>
|
|
687
|
-
|
|
589
|
+
</span>
|
|
688
590
|
</span>
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
</div>
|
|
591
|
+
<span class="tool-call-label">Tool call</span>
|
|
592
|
+
<div class="tool-name-wrapper">
|
|
593
|
+
<span class="tool-name-primary"
|
|
594
|
+
>{displayToolName.primary}</span
|
|
595
|
+
>
|
|
596
|
+
</div>
|
|
597
|
+
{#if isRunning || isError || isSuccess}
|
|
598
|
+
<span class="tool-status">
|
|
599
|
+
{#if isRunning}
|
|
600
|
+
<ProgressCircle size="S" />
|
|
601
|
+
{:else if isError}
|
|
602
|
+
<Icon
|
|
603
|
+
name="x"
|
|
604
|
+
size="S"
|
|
605
|
+
color="var(--spectrum-global-color-red-600)"
|
|
606
|
+
/>
|
|
607
|
+
{:else if isSuccess}
|
|
608
|
+
<Icon
|
|
609
|
+
name="check"
|
|
610
|
+
size="S"
|
|
611
|
+
color="var(--spectrum-global-color-green-600)"
|
|
612
|
+
/>
|
|
613
|
+
{/if}
|
|
614
|
+
</span>
|
|
714
615
|
{/if}
|
|
715
|
-
</
|
|
716
|
-
|
|
616
|
+
</button>
|
|
617
|
+
{#if expandedTools[toolId]}
|
|
618
|
+
<div class="tool-details">
|
|
619
|
+
{#if part.input}
|
|
620
|
+
<div class="tool-section">
|
|
621
|
+
<div class="tool-section-label">Input</div>
|
|
622
|
+
<pre class="tool-section-content">{formatToolOutput(
|
|
623
|
+
part.input
|
|
624
|
+
)}</pre>
|
|
625
|
+
</div>
|
|
626
|
+
{/if}
|
|
627
|
+
{#if isSuccess && part.output}
|
|
628
|
+
<div class="tool-section">
|
|
629
|
+
<div class="tool-section-label">Output</div>
|
|
630
|
+
<pre class="tool-section-content">{formatToolOutput(
|
|
631
|
+
part.output
|
|
632
|
+
)}</pre>
|
|
633
|
+
</div>
|
|
634
|
+
{:else if isError && part.errorText}
|
|
635
|
+
<div class="tool-section tool-error">
|
|
636
|
+
<div class="tool-section-label">Error</div>
|
|
637
|
+
<pre
|
|
638
|
+
class="tool-section-content error-content">{part.errorText}</pre>
|
|
639
|
+
</div>
|
|
640
|
+
{/if}
|
|
641
|
+
</div>
|
|
642
|
+
{/if}
|
|
643
|
+
</div>
|
|
644
|
+
{/if}
|
|
645
|
+
{/each}
|
|
646
|
+
{#if message.metadata?.ragSources?.length}
|
|
647
|
+
<div class="sources">
|
|
648
|
+
<div class="sources-title">Sources</div>
|
|
649
|
+
<ul>
|
|
650
|
+
{#each message.metadata.ragSources as source (source.sourceId)}
|
|
651
|
+
<li class="source-item">
|
|
652
|
+
<span class="source-name"
|
|
653
|
+
>{source.filename || source.sourceId}</span
|
|
654
|
+
>
|
|
655
|
+
{#if source.chunkCount > 0}
|
|
656
|
+
<span class="source-count"
|
|
657
|
+
>({source.chunkCount} chunk{source.chunkCount === 1
|
|
658
|
+
? ""
|
|
659
|
+
: "s"})</span
|
|
660
|
+
>
|
|
661
|
+
{/if}
|
|
662
|
+
</li>
|
|
663
|
+
{/each}
|
|
664
|
+
</ul>
|
|
717
665
|
</div>
|
|
718
666
|
{/if}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
<div class="sources">
|
|
722
|
-
<div class="sources-title">Sources</div>
|
|
723
|
-
<ul>
|
|
724
|
-
{#each message.metadata.ragSources as source (source.sourceId)}
|
|
725
|
-
<li class="source-item">
|
|
726
|
-
<span class="source-name"
|
|
727
|
-
>{source.filename || source.sourceId}</span
|
|
728
|
-
>
|
|
729
|
-
{#if source.chunkCount > 0}
|
|
730
|
-
<span class="source-count"
|
|
731
|
-
>({source.chunkCount} chunk{source.chunkCount === 1
|
|
732
|
-
? ""
|
|
733
|
-
: "s"})</span
|
|
734
|
-
>
|
|
735
|
-
{/if}
|
|
736
|
-
</li>
|
|
737
|
-
{/each}
|
|
738
|
-
</ul>
|
|
739
|
-
</div>
|
|
740
|
-
{/if}
|
|
741
|
-
</div>
|
|
667
|
+
</div>
|
|
668
|
+
{/if}
|
|
742
669
|
{/if}
|
|
743
670
|
{/each}
|
|
744
671
|
{#if showPendingAssistantState}
|
|
745
672
|
<div class="message assistant assistant-loading" aria-live="polite">
|
|
746
|
-
<
|
|
747
|
-
<button class="reasoning-toggle" type="button" disabled>
|
|
748
|
-
<span class="reasoning-icon shimmer">
|
|
749
|
-
<Icon
|
|
750
|
-
name="brain"
|
|
751
|
-
size="M"
|
|
752
|
-
color="var(--spectrum-global-color-gray-600)"
|
|
753
|
-
/>
|
|
754
|
-
</span>
|
|
755
|
-
<span class="reasoning-label shimmer">Thinking</span>
|
|
756
|
-
</button>
|
|
757
|
-
</div>
|
|
673
|
+
<ReasoningStatus thinking={true} label="Thinking" />
|
|
758
674
|
</div>
|
|
759
675
|
{/if}
|
|
760
676
|
</div>
|
|
@@ -912,14 +828,6 @@
|
|
|
912
828
|
max-width: 100%;
|
|
913
829
|
}
|
|
914
830
|
|
|
915
|
-
.assistant-loading {
|
|
916
|
-
min-height: 24px;
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
.assistant-loading .reasoning-toggle {
|
|
920
|
-
cursor: default;
|
|
921
|
-
}
|
|
922
|
-
|
|
923
831
|
.input-wrapper {
|
|
924
832
|
position: sticky;
|
|
925
833
|
bottom: 0;
|
|
@@ -1190,65 +1098,6 @@
|
|
|
1190
1098
|
color: var(--spectrum-global-color-red-700);
|
|
1191
1099
|
}
|
|
1192
1100
|
|
|
1193
|
-
/* Reasoning parts styling */
|
|
1194
|
-
.reasoning-part {
|
|
1195
|
-
display: flex;
|
|
1196
|
-
flex-direction: column;
|
|
1197
|
-
gap: 8px;
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
.reasoning-toggle {
|
|
1201
|
-
display: flex;
|
|
1202
|
-
align-items: center;
|
|
1203
|
-
gap: 6px;
|
|
1204
|
-
padding: 0;
|
|
1205
|
-
margin: 0;
|
|
1206
|
-
background: none;
|
|
1207
|
-
border: none;
|
|
1208
|
-
cursor: pointer;
|
|
1209
|
-
border-radius: 4px;
|
|
1210
|
-
}
|
|
1211
|
-
|
|
1212
|
-
.reasoning-icon {
|
|
1213
|
-
display: flex;
|
|
1214
|
-
align-items: center;
|
|
1215
|
-
justify-content: center;
|
|
1216
|
-
flex-shrink: 0;
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
.reasoning-label {
|
|
1220
|
-
font-size: 13px;
|
|
1221
|
-
color: var(--spectrum-global-color-gray-600);
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
.reasoning-timer {
|
|
1225
|
-
font-size: 12px;
|
|
1226
|
-
color: var(--spectrum-global-color-gray-600);
|
|
1227
|
-
font-weight: 400;
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
.reasoning-label.shimmer,
|
|
1231
|
-
.reasoning-icon.shimmer {
|
|
1232
|
-
animation: shimmer 2s ease-in-out infinite;
|
|
1233
|
-
}
|
|
1234
|
-
|
|
1235
|
-
.reasoning-content {
|
|
1236
|
-
font-size: 13px;
|
|
1237
|
-
color: var(--spectrum-global-color-gray-600);
|
|
1238
|
-
font-style: italic;
|
|
1239
|
-
line-height: 1.4;
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
@keyframes shimmer {
|
|
1243
|
-
0%,
|
|
1244
|
-
100% {
|
|
1245
|
-
opacity: 0.6;
|
|
1246
|
-
}
|
|
1247
|
-
50% {
|
|
1248
|
-
opacity: 1;
|
|
1249
|
-
}
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
1101
|
.sources {
|
|
1253
1102
|
margin-top: var(--spacing-m);
|
|
1254
1103
|
padding-top: var(--spacing-s);
|