@budibase/frontend-core 3.38.1 → 3.38.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.38.
|
|
3
|
+
"version": "3.38.3",
|
|
4
4
|
"description": "Budibase frontend core libraries used in builder and client",
|
|
5
5
|
"author": "Budibase",
|
|
6
6
|
"license": "MPL-2.0",
|
|
@@ -23,5 +23,5 @@
|
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"vitest": "^3.2.4"
|
|
25
25
|
},
|
|
26
|
-
"gitHead": "
|
|
26
|
+
"gitHead": "6d025a1d0b3c1b0dc4e1de0c88ce7f3ec6a97c0b"
|
|
27
27
|
}
|
package/src/api/agents.ts
CHANGED
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
FetchAgentsResponse,
|
|
13
13
|
ProvisionAgentSlackChannelRequest,
|
|
14
14
|
ProvisionAgentSlackChannelResponse,
|
|
15
|
+
ProvisionAgentTelegramChannelRequest,
|
|
16
|
+
ProvisionAgentTelegramChannelResponse,
|
|
15
17
|
ProvisionAgentMSTeamsChannelRequest,
|
|
16
18
|
ProvisionAgentMSTeamsChannelResponse,
|
|
17
19
|
SyncAgentDiscordCommandsRequest,
|
|
@@ -48,6 +50,10 @@ export interface AgentEndpoints {
|
|
|
48
50
|
agentId: string,
|
|
49
51
|
body?: ProvisionAgentSlackChannelRequest
|
|
50
52
|
) => Promise<ProvisionAgentSlackChannelResponse>
|
|
53
|
+
provisionAgentTelegramChannel: (
|
|
54
|
+
agentId: string,
|
|
55
|
+
body?: ProvisionAgentTelegramChannelRequest
|
|
56
|
+
) => Promise<ProvisionAgentTelegramChannelResponse>
|
|
51
57
|
toggleAgentDiscordDeployment: (
|
|
52
58
|
agentId: string,
|
|
53
59
|
enabled: boolean
|
|
@@ -60,6 +66,10 @@ export interface AgentEndpoints {
|
|
|
60
66
|
agentId: string,
|
|
61
67
|
enabled: boolean
|
|
62
68
|
) => Promise<ToggleAgentDeploymentResponse>
|
|
69
|
+
toggleAgentTelegramDeployment: (
|
|
70
|
+
agentId: string,
|
|
71
|
+
enabled: boolean
|
|
72
|
+
) => Promise<ToggleAgentDeploymentResponse>
|
|
63
73
|
fetchAgentKnowledge: (agentId: string) => Promise<FetchAgentKnowledgeResponse>
|
|
64
74
|
uploadAgentFile: (
|
|
65
75
|
agentId: string,
|
|
@@ -167,6 +177,16 @@ export const buildAgentEndpoints = (API: BaseAPIClient): AgentEndpoints => ({
|
|
|
167
177
|
})
|
|
168
178
|
},
|
|
169
179
|
|
|
180
|
+
provisionAgentTelegramChannel: async (agentId: string, body) => {
|
|
181
|
+
return await API.post<
|
|
182
|
+
ProvisionAgentTelegramChannelRequest | undefined,
|
|
183
|
+
ProvisionAgentTelegramChannelResponse
|
|
184
|
+
>({
|
|
185
|
+
url: `/api/agent/${agentId}/telegram/provision`,
|
|
186
|
+
body,
|
|
187
|
+
})
|
|
188
|
+
},
|
|
189
|
+
|
|
170
190
|
toggleAgentDiscordDeployment: async (agentId: string, enabled: boolean) => {
|
|
171
191
|
return await API.post<
|
|
172
192
|
ToggleAgentDeploymentRequest,
|
|
@@ -197,6 +217,16 @@ export const buildAgentEndpoints = (API: BaseAPIClient): AgentEndpoints => ({
|
|
|
197
217
|
})
|
|
198
218
|
},
|
|
199
219
|
|
|
220
|
+
toggleAgentTelegramDeployment: async (agentId: string, enabled: boolean) => {
|
|
221
|
+
return await API.post<
|
|
222
|
+
ToggleAgentDeploymentRequest,
|
|
223
|
+
ToggleAgentDeploymentResponse
|
|
224
|
+
>({
|
|
225
|
+
url: `/api/agent/${agentId}/telegram/toggle`,
|
|
226
|
+
body: { enabled },
|
|
227
|
+
})
|
|
228
|
+
},
|
|
229
|
+
|
|
200
230
|
fetchAgentKnowledge: async (agentId: string) => {
|
|
201
231
|
return await API.get<FetchAgentKnowledgeResponse>({
|
|
202
232
|
url: `/api/agent/${agentId}/knowledge`,
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
Icon,
|
|
4
|
+
Popover,
|
|
5
|
+
PopoverAlignment,
|
|
6
|
+
type PopoverAPI,
|
|
7
|
+
} from "@budibase/bbui"
|
|
8
|
+
import type {
|
|
9
|
+
AgentMessageUsage,
|
|
10
|
+
AgentMessageUsageSegment,
|
|
11
|
+
} from "@budibase/types"
|
|
12
|
+
|
|
13
|
+
type SegmentDetails = {
|
|
14
|
+
name: string
|
|
15
|
+
color: string
|
|
16
|
+
}
|
|
17
|
+
type VisibleSegment = AgentMessageUsageSegment & SegmentDetails
|
|
18
|
+
|
|
19
|
+
interface Props {
|
|
20
|
+
usage?: AgentMessageUsage
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let { usage }: Props = $props()
|
|
24
|
+
|
|
25
|
+
let open = $state(false)
|
|
26
|
+
let triggerEl = $state<HTMLButtonElement>()
|
|
27
|
+
let popover = $state<PopoverAPI>()
|
|
28
|
+
|
|
29
|
+
const DEFAULT_MAX_TOKENS = 200000
|
|
30
|
+
const SEGMENT_DETAILS: Record<
|
|
31
|
+
AgentMessageUsageSegment["type"],
|
|
32
|
+
SegmentDetails
|
|
33
|
+
> = {
|
|
34
|
+
system: {
|
|
35
|
+
name: "System prompt",
|
|
36
|
+
color: "var(--grey-7)",
|
|
37
|
+
},
|
|
38
|
+
input: {
|
|
39
|
+
name: "Input",
|
|
40
|
+
color: "var(--color-purple-500)",
|
|
41
|
+
},
|
|
42
|
+
cachedInput: {
|
|
43
|
+
name: "Cached input",
|
|
44
|
+
color: "var(--color-blue-400)",
|
|
45
|
+
},
|
|
46
|
+
output: {
|
|
47
|
+
name: "Output",
|
|
48
|
+
color: "var(--color-red-500)",
|
|
49
|
+
},
|
|
50
|
+
reasoning: {
|
|
51
|
+
name: "Reasoning",
|
|
52
|
+
color: "var(--color-orange-500)",
|
|
53
|
+
},
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const maxTokens = $derived(usage?.maxTokens ?? DEFAULT_MAX_TOKENS)
|
|
57
|
+
const visibleSegments = $derived.by((): VisibleSegment[] =>
|
|
58
|
+
(usage?.segments || [])
|
|
59
|
+
.filter(segment => segment.tokens > 0)
|
|
60
|
+
.map(segment => ({
|
|
61
|
+
...segment,
|
|
62
|
+
...SEGMENT_DETAILS[segment.type],
|
|
63
|
+
}))
|
|
64
|
+
)
|
|
65
|
+
const totalTokens = $derived(
|
|
66
|
+
visibleSegments.reduce((sum, s) => sum + s.tokens, 0)
|
|
67
|
+
)
|
|
68
|
+
const percentage = $derived(
|
|
69
|
+
maxTokens > 0
|
|
70
|
+
? Math.min(100, Math.round((totalTokens / maxTokens) * 100))
|
|
71
|
+
: 0
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
const RING_RADIUS = 7
|
|
75
|
+
const RING_CIRC = 2 * Math.PI * RING_RADIUS
|
|
76
|
+
const dashOffset = $derived(RING_CIRC - (percentage / 100) * RING_CIRC)
|
|
77
|
+
|
|
78
|
+
const compact = new Intl.NumberFormat("en", {
|
|
79
|
+
notation: "compact",
|
|
80
|
+
maximumFractionDigits: 1,
|
|
81
|
+
})
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<button
|
|
85
|
+
bind:this={triggerEl}
|
|
86
|
+
type="button"
|
|
87
|
+
class="trigger"
|
|
88
|
+
class:active={open}
|
|
89
|
+
onclick={() => popover?.show()}
|
|
90
|
+
aria-label="Context usage"
|
|
91
|
+
aria-expanded={open}
|
|
92
|
+
>
|
|
93
|
+
<span class="ring" aria-hidden="true">
|
|
94
|
+
<svg viewBox="0 0 18 18">
|
|
95
|
+
<circle cx="9" cy="9" r={RING_RADIUS} class="ring-track" />
|
|
96
|
+
<circle
|
|
97
|
+
cx="9"
|
|
98
|
+
cy="9"
|
|
99
|
+
r={RING_RADIUS}
|
|
100
|
+
class="ring-progress"
|
|
101
|
+
style="stroke-dasharray: {RING_CIRC}; stroke-dashoffset: {dashOffset};"
|
|
102
|
+
/>
|
|
103
|
+
</svg>
|
|
104
|
+
</span>
|
|
105
|
+
<span class="trigger-label">
|
|
106
|
+
<span class="trigger-percent">{percentage}%</span>
|
|
107
|
+
<span class="trigger-suffix">context</span>
|
|
108
|
+
</span>
|
|
109
|
+
</button>
|
|
110
|
+
|
|
111
|
+
<Popover
|
|
112
|
+
bind:this={popover}
|
|
113
|
+
bind:open
|
|
114
|
+
anchor={triggerEl}
|
|
115
|
+
align={PopoverAlignment.Right}
|
|
116
|
+
offset={8}
|
|
117
|
+
minWidth={420}
|
|
118
|
+
maxWidth={420}
|
|
119
|
+
resizable={false}
|
|
120
|
+
>
|
|
121
|
+
<div class="popover">
|
|
122
|
+
<header class="popover-header">
|
|
123
|
+
<span class="popover-title">Context</span>
|
|
124
|
+
<span class="popover-fill">{percentage}% Full</span>
|
|
125
|
+
<div class="popover-right">
|
|
126
|
+
{#if usage}
|
|
127
|
+
<span class="popover-total">
|
|
128
|
+
~{compact.format(totalTokens)} / {compact.format(maxTokens)} Tokens
|
|
129
|
+
</span>
|
|
130
|
+
{/if}
|
|
131
|
+
<button
|
|
132
|
+
class="popover-close"
|
|
133
|
+
type="button"
|
|
134
|
+
onclick={() => popover?.hide()}
|
|
135
|
+
aria-label="Close context details"
|
|
136
|
+
>
|
|
137
|
+
<Icon
|
|
138
|
+
name="x"
|
|
139
|
+
size="S"
|
|
140
|
+
color="var(--spectrum-global-color-gray-700)"
|
|
141
|
+
/>
|
|
142
|
+
</button>
|
|
143
|
+
</div>
|
|
144
|
+
</header>
|
|
145
|
+
|
|
146
|
+
<div class="bar" role="img" aria-label="Context breakdown">
|
|
147
|
+
{#each visibleSegments as segment (segment.name)}
|
|
148
|
+
{@const segPct = (segment.tokens / maxTokens) * 100}
|
|
149
|
+
<span
|
|
150
|
+
class="bar-segment"
|
|
151
|
+
style="width: {segPct}%; background: {segment.color};"
|
|
152
|
+
></span>
|
|
153
|
+
{/each}
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
<ul class="legend">
|
|
157
|
+
{#each visibleSegments as segment (segment.name)}
|
|
158
|
+
<li class="legend-row">
|
|
159
|
+
<span class="legend-swatch" style="background: {segment.color};"
|
|
160
|
+
></span>
|
|
161
|
+
<span class="legend-name">{segment.name}</span>
|
|
162
|
+
<span class="legend-tokens">{compact.format(segment.tokens)}</span>
|
|
163
|
+
</li>
|
|
164
|
+
{/each}
|
|
165
|
+
</ul>
|
|
166
|
+
</div>
|
|
167
|
+
</Popover>
|
|
168
|
+
|
|
169
|
+
<style>
|
|
170
|
+
.trigger {
|
|
171
|
+
display: inline-flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
gap: 6px;
|
|
174
|
+
padding: 4px 10px 4px 6px;
|
|
175
|
+
border: 1px solid transparent;
|
|
176
|
+
border-radius: 999px;
|
|
177
|
+
background: transparent;
|
|
178
|
+
color: var(--spectrum-global-color-gray-700);
|
|
179
|
+
font-size: 12px;
|
|
180
|
+
line-height: 1;
|
|
181
|
+
cursor: pointer;
|
|
182
|
+
transition:
|
|
183
|
+
background-color 0.15s ease,
|
|
184
|
+
border-color 0.15s ease,
|
|
185
|
+
color 0.15s ease;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.trigger:hover,
|
|
189
|
+
.trigger.active {
|
|
190
|
+
background: var(--spectrum-global-color-gray-100);
|
|
191
|
+
border-color: var(--spectrum-global-color-gray-200);
|
|
192
|
+
color: var(--spectrum-global-color-gray-900);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.ring {
|
|
196
|
+
display: inline-flex;
|
|
197
|
+
width: 16px;
|
|
198
|
+
height: 16px;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.ring svg {
|
|
202
|
+
width: 100%;
|
|
203
|
+
height: 100%;
|
|
204
|
+
transform: rotate(-90deg);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.ring-track {
|
|
208
|
+
fill: none;
|
|
209
|
+
stroke: var(--spectrum-global-color-gray-300);
|
|
210
|
+
stroke-width: 2;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.ring-progress {
|
|
214
|
+
fill: none;
|
|
215
|
+
stroke: var(--spectrum-global-color-gray-800);
|
|
216
|
+
stroke-width: 2;
|
|
217
|
+
stroke-linecap: round;
|
|
218
|
+
transition:
|
|
219
|
+
stroke-dashoffset 0.4s cubic-bezier(0.22, 1, 0.36, 1),
|
|
220
|
+
stroke 0.2s ease;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.trigger-label {
|
|
224
|
+
display: inline-flex;
|
|
225
|
+
gap: 4px;
|
|
226
|
+
align-items: baseline;
|
|
227
|
+
font-variant-numeric: tabular-nums;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.trigger-percent {
|
|
231
|
+
font-weight: 600;
|
|
232
|
+
color: var(--spectrum-global-color-gray-900);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.trigger-suffix {
|
|
236
|
+
color: var(--spectrum-global-color-gray-700);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.popover {
|
|
240
|
+
padding: 16px 16px 14px;
|
|
241
|
+
display: flex;
|
|
242
|
+
flex-direction: column;
|
|
243
|
+
gap: 12px;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.popover-header {
|
|
247
|
+
display: flex;
|
|
248
|
+
align-items: center;
|
|
249
|
+
gap: 10px;
|
|
250
|
+
font-variant-numeric: tabular-nums;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.popover-title {
|
|
254
|
+
font-size: 14px;
|
|
255
|
+
font-weight: 600;
|
|
256
|
+
color: var(--spectrum-global-color-gray-900);
|
|
257
|
+
letter-spacing: -0.01em;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.popover-fill {
|
|
261
|
+
font-size: 12px;
|
|
262
|
+
color: var(--spectrum-global-color-gray-700);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.popover-right {
|
|
266
|
+
margin-left: auto;
|
|
267
|
+
display: inline-flex;
|
|
268
|
+
align-items: center;
|
|
269
|
+
gap: 10px;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.popover-total {
|
|
273
|
+
font-size: 12px;
|
|
274
|
+
color: var(--spectrum-global-color-gray-700);
|
|
275
|
+
white-space: nowrap;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.popover-close {
|
|
279
|
+
width: 22px;
|
|
280
|
+
height: 22px;
|
|
281
|
+
display: inline-flex;
|
|
282
|
+
align-items: center;
|
|
283
|
+
justify-content: center;
|
|
284
|
+
border-radius: 6px;
|
|
285
|
+
border: none;
|
|
286
|
+
background: transparent;
|
|
287
|
+
cursor: pointer;
|
|
288
|
+
color: var(--spectrum-global-color-gray-700);
|
|
289
|
+
transition: background-color 0.15s ease;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.popover-close:hover {
|
|
293
|
+
background: var(--spectrum-global-color-gray-200);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.bar {
|
|
297
|
+
display: flex;
|
|
298
|
+
width: 100%;
|
|
299
|
+
height: 8px;
|
|
300
|
+
border-radius: 999px;
|
|
301
|
+
background: var(--spectrum-global-color-gray-200);
|
|
302
|
+
overflow: hidden;
|
|
303
|
+
gap: 2px;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.bar-segment {
|
|
307
|
+
height: 100%;
|
|
308
|
+
transition: width 0.4s cubic-bezier(0.22, 1, 0.36, 1);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.bar-segment:first-child {
|
|
312
|
+
border-top-left-radius: 999px;
|
|
313
|
+
border-bottom-left-radius: 999px;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.legend {
|
|
317
|
+
list-style: none;
|
|
318
|
+
margin: 0;
|
|
319
|
+
padding: 0;
|
|
320
|
+
display: flex;
|
|
321
|
+
flex-direction: column;
|
|
322
|
+
gap: 2px;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.legend-row {
|
|
326
|
+
display: grid;
|
|
327
|
+
grid-template-columns: 14px 1fr auto;
|
|
328
|
+
align-items: center;
|
|
329
|
+
gap: 10px;
|
|
330
|
+
padding: 6px 2px;
|
|
331
|
+
font-size: 13px;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.legend-row + .legend-row {
|
|
335
|
+
border-top: 1px solid var(--spectrum-global-color-gray-100);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.legend-swatch {
|
|
339
|
+
width: 10px;
|
|
340
|
+
height: 10px;
|
|
341
|
+
border-radius: 2px;
|
|
342
|
+
display: inline-block;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.legend-name {
|
|
346
|
+
color: var(--spectrum-global-color-gray-800);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.legend-tokens {
|
|
350
|
+
color: var(--spectrum-global-color-gray-700);
|
|
351
|
+
font-variant-numeric: tabular-nums;
|
|
352
|
+
font-size: 12px;
|
|
353
|
+
}
|
|
354
|
+
</style>
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import { Chat } from "@ai-sdk/svelte"
|
|
19
19
|
import { formatToolName } from "../../utils/aiTools"
|
|
20
20
|
import ReasoningStatus from "./ReasoningStatus.svelte"
|
|
21
|
+
import ContextUsage from "./ContextUsage.svelte"
|
|
21
22
|
import {
|
|
22
23
|
DefaultChatTransport,
|
|
23
24
|
isTextUIPart,
|
|
@@ -232,6 +233,11 @@
|
|
|
232
233
|
|
|
233
234
|
let messages = $derived(chatInstance.messages)
|
|
234
235
|
let lastMessage = $derived(messages[messages.length - 1])
|
|
236
|
+
|
|
237
|
+
let lastAssistantUsage = $derived(
|
|
238
|
+
messages.findLast(m => m.role === "assistant" && m.metadata?.usage)
|
|
239
|
+
?.metadata?.usage
|
|
240
|
+
)
|
|
235
241
|
let lastAssistantMessage = $derived(
|
|
236
242
|
messages.findLast(message => message.role === "assistant")
|
|
237
243
|
)
|
|
@@ -713,6 +719,9 @@
|
|
|
713
719
|
{/if}
|
|
714
720
|
</button>
|
|
715
721
|
</div>
|
|
722
|
+
<div class="input-footer">
|
|
723
|
+
<ContextUsage usage={lastAssistantUsage} />
|
|
724
|
+
</div>
|
|
716
725
|
</div>
|
|
717
726
|
{/if}
|
|
718
727
|
</div>
|
|
@@ -838,6 +847,13 @@
|
|
|
838
847
|
flex-direction: column;
|
|
839
848
|
flex-shrink: 0;
|
|
840
849
|
line-height: 1.4;
|
|
850
|
+
gap: 6px;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
.input-footer {
|
|
854
|
+
display: flex;
|
|
855
|
+
justify-content: flex-end;
|
|
856
|
+
padding: 0 4px;
|
|
841
857
|
}
|
|
842
858
|
|
|
843
859
|
.read-only-notice {
|