@budibase/frontend-core 3.38.4 → 3.38.5

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.4",
3
+ "version": "3.38.5",
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": "3c6f6c46783826f174b3ae006064332b8377193a"
26
+ "gitHead": "5795ec6c95812463cba1d8cede8295f6c2b915cb"
27
27
  }
@@ -0,0 +1,55 @@
1
+ import type {
2
+ FetchAgentTestSuiteResponse,
3
+ FetchAgentTestRunResponse,
4
+ RunAgentTestSuiteRequest,
5
+ RunAgentTestSuiteResponse,
6
+ UpdateAgentTestSuiteRequest,
7
+ UpdateAgentTestSuiteResponse,
8
+ } from "@budibase/types"
9
+ import type { BaseAPIClient } from "./types"
10
+
11
+ export interface AgentTestEndpoints {
12
+ fetchAgentTestSuite: (agentId: string) => Promise<FetchAgentTestSuiteResponse>
13
+ updateAgentTestSuite: (
14
+ agentId: string,
15
+ body: UpdateAgentTestSuiteRequest
16
+ ) => Promise<UpdateAgentTestSuiteResponse>
17
+ runAgentTestSuite: (
18
+ agentId: string,
19
+ body?: RunAgentTestSuiteRequest
20
+ ) => Promise<RunAgentTestSuiteResponse>
21
+ fetchAgentTestRun: (
22
+ agentId: string,
23
+ runId: string
24
+ ) => Promise<FetchAgentTestRunResponse>
25
+ }
26
+
27
+ export const buildAgentTestEndpoints = (
28
+ API: BaseAPIClient
29
+ ): AgentTestEndpoints => ({
30
+ fetchAgentTestSuite: async agentId => {
31
+ return await API.get({
32
+ url: `/api/agent/${agentId}/tests`,
33
+ })
34
+ },
35
+
36
+ updateAgentTestSuite: async (agentId, body) => {
37
+ return await API.put({
38
+ url: `/api/agent/${agentId}/tests`,
39
+ body,
40
+ })
41
+ },
42
+
43
+ runAgentTestSuite: async (agentId, body) => {
44
+ return await API.post({
45
+ url: `/api/agent/${agentId}/tests/run`,
46
+ body: body ?? {},
47
+ })
48
+ },
49
+
50
+ fetchAgentTestRun: async (agentId, runId) => {
51
+ return await API.get({
52
+ url: `/api/agent/${agentId}/tests/run/${runId}`,
53
+ })
54
+ },
55
+ })
package/src/api/index.ts CHANGED
@@ -47,6 +47,7 @@ import { buildMigrationEndpoints } from "./migrations"
47
47
  import { buildRowActionEndpoints } from "./rowActions"
48
48
  import { buildOAuth2Endpoints } from "./oauth2"
49
49
  import { buildAgentEndpoints } from "./agents"
50
+ import { buildAgentTestEndpoints } from "./agentTests"
50
51
  import { buildAgentLogEndpoints } from "./agentLogs"
51
52
  import { buildChatAppEndpoints } from "./chatApps"
52
53
  import { buildFeatureFlagEndpoints } from "./features"
@@ -317,6 +318,7 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => {
317
318
  ...buildLogsEndpoints(API),
318
319
  ...buildMigrationEndpoints(API),
319
320
  ...buildAgentEndpoints(API),
321
+ ...buildAgentTestEndpoints(API),
320
322
  ...buildAgentLogEndpoints(API),
321
323
  ...buildChatAppEndpoints(API),
322
324
  ...buildFeatureFlagEndpoints(API),
package/src/api/types.ts CHANGED
@@ -35,6 +35,7 @@ import { UserEndpoints } from "./user"
35
35
  import { ViewEndpoints } from "./views"
36
36
  import { ViewV2Endpoints } from "./viewsV2"
37
37
  import { AgentEndpoints } from "./agents"
38
+ import { AgentTestEndpoints } from "./agentTests"
38
39
  import { AgentLogEndpoints } from "./agentLogs"
39
40
  import { ChatAppEndpoints } from "./chatApps"
40
41
  import { NavigationEndpoints } from "./navigation"
@@ -119,6 +120,7 @@ export type APIError = {
119
120
  export type APIClient = BaseAPIClient &
120
121
  AIEndpoints &
121
122
  AgentEndpoints &
123
+ AgentTestEndpoints &
122
124
  AgentLogEndpoints &
123
125
  ChatAppEndpoints &
124
126
  AnalyticsEndpoints &
@@ -13,7 +13,7 @@
13
13
  AgentMessageMetadata,
14
14
  } from "@budibase/types"
15
15
  import { Header } from "@budibase/shared-core"
16
- import { tick } from "svelte"
16
+ import { tick, untrack } from "svelte"
17
17
  import { createAPIClient } from "@budibase/frontend-core"
18
18
  import { Chat } from "@ai-sdk/svelte"
19
19
  import { formatToolName } from "../../utils/aiTools"
@@ -72,6 +72,7 @@
72
72
  let chatAreaElement = $state<HTMLDivElement>()
73
73
  let textareaElement = $state<HTMLTextAreaElement>()
74
74
  let expandedTools = $state<Record<string, boolean>>({})
75
+ let reasoningTextByMessageId = $state<Record<string, string>>({})
75
76
  let inputValue = $state("")
76
77
  let lastInitialPrompt = $state("")
77
78
  let isPreparingResponse = $state(false)
@@ -86,6 +87,9 @@
86
87
  .map(p => p.text)
87
88
  .join("")
88
89
 
90
+ const getCachedReasoningText = (message: UIMessage<AgentMessageMetadata>) =>
91
+ reasoningTextByMessageId[message.id] || getReasoningText(message)
92
+
89
93
  const isReasoningStreaming = (message: UIMessage<AgentMessageMetadata>) =>
90
94
  (message.parts ?? []).some(
91
95
  part => isReasoningUIPart(part) && part.state === "streaming"
@@ -275,6 +279,36 @@
275
279
  }
276
280
  chatInstance.messages = chat?.messages || []
277
281
  expandedTools = {}
282
+ reasoningTextByMessageId = {}
283
+ }
284
+ })
285
+
286
+ $effect(() => {
287
+ const nextReasoningTextByMessageId = untrack(() => ({
288
+ ...reasoningTextByMessageId,
289
+ }))
290
+ let hasChanged = false
291
+
292
+ for (const message of messages) {
293
+ if (message.role !== "assistant") {
294
+ continue
295
+ }
296
+
297
+ const reasoningText = getReasoningText(message)
298
+ if (!reasoningText) {
299
+ continue
300
+ }
301
+
302
+ if (nextReasoningTextByMessageId[message.id] === reasoningText) {
303
+ continue
304
+ }
305
+
306
+ nextReasoningTextByMessageId[message.id] = reasoningText
307
+ hasChanged = true
308
+ }
309
+
310
+ if (hasChanged) {
311
+ reasoningTextByMessageId = nextReasoningTextByMessageId
278
312
  }
279
313
  })
280
314
 
@@ -519,7 +553,7 @@
519
553
  <MarkdownViewer value={getUserMessageText(message)} />
520
554
  </div>
521
555
  {:else if message.role === "assistant"}
522
- {@const reasoningText = getReasoningText(message)}
556
+ {@const reasoningText = getCachedReasoningText(message)}
523
557
  {@const reasoningId = `${message.id}-reasoning`}
524
558
  {@const pendingAssistant =
525
559
  isBusy &&
@@ -528,14 +562,22 @@
528
562
  {@const toolError = hasToolError(message)}
529
563
  {@const messageError = getMessageError(message)}
530
564
  {@const reasoningStreaming = isReasoningStreaming(message)}
565
+ {@const activeAssistant =
566
+ isBusy && lastAssistantMessage?.id === message.id}
531
567
  {@const isThinking =
532
- (reasoningStreaming || pendingAssistant) &&
568
+ (reasoningStreaming || pendingAssistant || activeAssistant) &&
533
569
  !toolError &&
534
570
  !messageError &&
535
571
  !message.metadata?.completedAt}
572
+ {@const showReasoningStatus =
573
+ reasoningText ||
574
+ pendingAssistant ||
575
+ activeAssistant ||
576
+ message.metadata?.createdAt ||
577
+ message.metadata?.completedAt}
536
578
  {#if hasVisibleAssistantContent(message) || pendingAssistant}
537
579
  <div class="message assistant">
538
- {#if reasoningText || pendingAssistant}
580
+ {#if showReasoningStatus}
539
581
  <ReasoningStatus
540
582
  thinking={isThinking}
541
583
  label={isThinking ? "Thinking" : "Thought"}
@@ -42,6 +42,7 @@
42
42
  export let canExpandRows = true
43
43
  export let canEditRows = true
44
44
  export let canDeleteRows = true
45
+ export let canSelectRows = true
45
46
  export let canEditColumns = true
46
47
  export let canSaveSchema = true
47
48
  export let stripeRows = false
@@ -102,6 +103,7 @@
102
103
  canExpandRows,
103
104
  canEditRows,
104
105
  canDeleteRows,
106
+ canSelectRows,
105
107
  canEditColumns,
106
108
  canSaveSchema,
107
109
  stripeRows,
@@ -82,9 +82,8 @@ export const deriveStores = (context: StoreContext): ConfigDerivedStore => {
82
82
  config.canEditColumns = false
83
83
  }
84
84
 
85
- // Determine if we can select rows. Always true in the meantime as you can
86
- // use the selected rows binding regardless of readonly state.
87
- config.canSelectRows = true
85
+ // Determine if we can select rows.
86
+ config.canSelectRows = $props.canSelectRows !== false
88
87
 
89
88
  return config
90
89
  }
@@ -78,6 +78,7 @@ export interface BaseStoreProps {
78
78
  canAddRows?: boolean
79
79
  canEditRows?: boolean
80
80
  canDeleteRows?: boolean
81
+ canSelectRows?: boolean
81
82
  canEditColumns?: boolean
82
83
  canExpandRows?: boolean
83
84
  canSaveSchema?: boolean