@gram-ai/elements 1.27.3 → 1.27.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.
Files changed (278) hide show
  1. package/README.md +72 -60
  2. package/README.typedoc.md +6 -6
  3. package/bin/cli.js +74 -74
  4. package/dist/compat-shims-CO9JXXV4.cjs.map +1 -1
  5. package/dist/{compat-shims-BPJ7Q68c.js → compat-shims-DxtUrORi.js} +4 -2
  6. package/dist/compat-shims-DxtUrORi.js.map +1 -0
  7. package/dist/components/ShareButton/index.d.ts +2 -2
  8. package/dist/components/assistant-ui/message-feedback.d.ts +1 -1
  9. package/dist/components/assistant-ui/tooltip-icon-button.d.ts +2 -2
  10. package/dist/components/ui/avatar.d.ts +2 -2
  11. package/dist/components/ui/button.d.ts +1 -1
  12. package/dist/components/ui/calendar.d.ts +1 -1
  13. package/dist/components/ui/collapsible.d.ts +1 -1
  14. package/dist/components/ui/dialog.d.ts +4 -4
  15. package/dist/components/ui/popover.d.ts +2 -2
  16. package/dist/components/ui/skeleton.d.ts +1 -1
  17. package/dist/components/ui/time-range-picker.d.ts +4 -2
  18. package/dist/components/ui/tool-ui.d.ts +7 -7
  19. package/dist/components/ui/tooltip.d.ts +2 -2
  20. package/dist/contexts/ConnectionStatusContext.d.ts +1 -1
  21. package/dist/elements.cjs +1 -1
  22. package/dist/elements.css +1 -1
  23. package/dist/elements.js +2 -2
  24. package/dist/hooks/useDensity.d.ts +73 -73
  25. package/dist/hooks/useMCPTools.d.ts +1 -1
  26. package/dist/hooks/useRadius.d.ts +1 -1
  27. package/dist/{index-BpJstUh1.cjs → index-C4bFBGfl.cjs} +4 -4
  28. package/dist/{index-BpJstUh1.cjs.map → index-C4bFBGfl.cjs.map} +1 -1
  29. package/dist/{index-CUitXazZ.js → index-D93pV0_o.js} +55 -55
  30. package/dist/{index-CUitXazZ.js.map → index-D93pV0_o.js.map} +1 -1
  31. package/dist/{index-DBrhzauj.js → index-DuCQRbcQ.js} +6386 -6337
  32. package/dist/index-DuCQRbcQ.js.map +1 -0
  33. package/dist/{index-DxfW52oA.cjs → index-y_PNN5vK.cjs} +64 -46
  34. package/dist/index-y_PNN5vK.cjs.map +1 -0
  35. package/dist/lib/cassette.d.ts +4 -4
  36. package/dist/lib/errorTracking.d.ts +1 -1
  37. package/dist/lib/messageConverter.d.ts +1 -1
  38. package/dist/lib/models.d.ts +1 -1
  39. package/dist/plugins/chart/ui/bar-chart.d.ts +1 -1
  40. package/dist/plugins/generative-ui/ui/accordion-wrapper.d.ts +2 -2
  41. package/dist/plugins/generative-ui/ui/accordion.d.ts +1 -1
  42. package/dist/plugins/generative-ui/ui/action-button.d.ts +2 -2
  43. package/dist/plugins/generative-ui/ui/alert-wrapper.d.ts +1 -1
  44. package/dist/plugins/generative-ui/ui/alert.d.ts +4 -4
  45. package/dist/plugins/generative-ui/ui/avatar.d.ts +5 -5
  46. package/dist/plugins/generative-ui/ui/badge.d.ts +2 -2
  47. package/dist/plugins/generative-ui/ui/button-wrapper.d.ts +2 -2
  48. package/dist/plugins/generative-ui/ui/button.d.ts +2 -2
  49. package/dist/plugins/generative-ui/ui/card-wrapper.d.ts +2 -2
  50. package/dist/plugins/generative-ui/ui/card.d.ts +8 -8
  51. package/dist/plugins/generative-ui/ui/checkbox.d.ts +1 -1
  52. package/dist/plugins/generative-ui/ui/data-table.d.ts +2 -2
  53. package/dist/plugins/generative-ui/ui/dialog.d.ts +3 -3
  54. package/dist/plugins/generative-ui/ui/dropdown-menu.d.ts +3 -3
  55. package/dist/plugins/generative-ui/ui/grid.d.ts +3 -3
  56. package/dist/plugins/generative-ui/ui/input-wrapper.d.ts +1 -1
  57. package/dist/plugins/generative-ui/ui/input.d.ts +2 -2
  58. package/dist/plugins/generative-ui/ui/label.d.ts +1 -1
  59. package/dist/plugins/generative-ui/ui/metric.d.ts +3 -3
  60. package/dist/plugins/generative-ui/ui/pagination.d.ts +6 -6
  61. package/dist/plugins/generative-ui/ui/popover.d.ts +4 -4
  62. package/dist/plugins/generative-ui/ui/progress.d.ts +2 -2
  63. package/dist/plugins/generative-ui/ui/radio-group.d.ts +1 -1
  64. package/dist/plugins/generative-ui/ui/select.d.ts +2 -2
  65. package/dist/plugins/generative-ui/ui/separator.d.ts +1 -1
  66. package/dist/plugins/generative-ui/ui/skeleton.d.ts +1 -1
  67. package/dist/plugins/generative-ui/ui/stack.d.ts +6 -6
  68. package/dist/plugins/generative-ui/ui/switch.d.ts +2 -2
  69. package/dist/plugins/generative-ui/ui/table.d.ts +9 -9
  70. package/dist/plugins/generative-ui/ui/tabs-wrapper.d.ts +1 -1
  71. package/dist/plugins/generative-ui/ui/tabs.d.ts +1 -1
  72. package/dist/plugins/generative-ui/ui/text.d.ts +3 -3
  73. package/dist/plugins/generative-ui/ui/textarea.d.ts +2 -2
  74. package/dist/plugins/generative-ui/ui/tooltip.d.ts +1 -1
  75. package/dist/plugins.cjs +1 -1
  76. package/dist/plugins.js +1 -1
  77. package/dist/{profiler-D6ndqfsd.js → profiler-FpBY9eRv.js} +2 -2
  78. package/dist/{profiler-D6ndqfsd.js.map → profiler-FpBY9eRv.js.map} +1 -1
  79. package/dist/{profiler-DhnzZ34c.cjs → profiler-_mthyjvo.cjs} +2 -2
  80. package/dist/{profiler-DhnzZ34c.cjs.map → profiler-_mthyjvo.cjs.map} +1 -1
  81. package/dist/react-shim.js +1 -1
  82. package/dist/server/express.cjs.map +1 -1
  83. package/dist/server/express.js.map +1 -1
  84. package/dist/{startRecording-BwXmdmy1.cjs → startRecording-NJcpiHw-.cjs} +2 -2
  85. package/dist/{startRecording-BwXmdmy1.cjs.map → startRecording-NJcpiHw-.cjs.map} +1 -1
  86. package/dist/{startRecording-B_9CRZ_P.js → startRecording-r5MXQ2Dm.js} +2 -2
  87. package/dist/{startRecording-B_9CRZ_P.js.map → startRecording-r5MXQ2Dm.js.map} +1 -1
  88. package/dist/types/index.d.ts +2 -2
  89. package/package.json +1 -5
  90. package/src/compat-plugin.ts +14 -14
  91. package/src/compat-shims.ts +33 -31
  92. package/src/compat.test.ts +48 -48
  93. package/src/compat.ts +6 -6
  94. package/src/components/Chat/index.tsx +17 -17
  95. package/src/components/Chat/stories/Charts.stories.tsx +98 -98
  96. package/src/components/Chat/stories/Composer.stories.tsx +15 -15
  97. package/src/components/Chat/stories/ConnectionConfiguration.stories.tsx +44 -44
  98. package/src/components/Chat/stories/CustomComponents.stories.tsx +17 -17
  99. package/src/components/Chat/stories/Density.stories.tsx +20 -20
  100. package/src/components/Chat/stories/ErrorBoundary.stories.tsx +47 -47
  101. package/src/components/Chat/stories/FrontendTools.stories.tsx +39 -39
  102. package/src/components/Chat/stories/GenerativeUI.stories.tsx +48 -48
  103. package/src/components/Chat/stories/MessageFeedback.stories.tsx +52 -52
  104. package/src/components/Chat/stories/Modal.stories.tsx +28 -28
  105. package/src/components/Chat/stories/Model.stories.tsx +11 -11
  106. package/src/components/Chat/stories/Radius.stories.tsx +20 -20
  107. package/src/components/Chat/stories/Sidecar.stories.tsx +13 -13
  108. package/src/components/Chat/stories/StyleIsolation.stories.tsx +11 -11
  109. package/src/components/Chat/stories/Theme.stories.tsx +25 -25
  110. package/src/components/Chat/stories/Thread.stories.tsx +25 -25
  111. package/src/components/Chat/stories/ToolApproval.stories.tsx +55 -55
  112. package/src/components/Chat/stories/ToolMentions.stories.tsx +17 -17
  113. package/src/components/Chat/stories/Tools.stories.tsx +88 -88
  114. package/src/components/Chat/stories/Variants.stories.tsx +32 -32
  115. package/src/components/Chat/stories/Welcome.stories.tsx +14 -14
  116. package/src/components/ChatHistory.tsx +7 -7
  117. package/src/components/FrontendTools/index.tsx +5 -5
  118. package/src/components/Replay.stories.tsx +157 -157
  119. package/src/components/Replay.tsx +76 -73
  120. package/src/components/ShadowRoot.tsx +40 -40
  121. package/src/components/ShareButton/index.tsx +32 -32
  122. package/src/components/assistant-ui/assistant-modal.tsx +92 -87
  123. package/src/components/assistant-ui/assistant-sidecar.tsx +35 -35
  124. package/src/components/assistant-ui/attachment.tsx +80 -80
  125. package/src/components/assistant-ui/connection-status-indicator.tsx +33 -33
  126. package/src/components/assistant-ui/error-boundary.tsx +34 -34
  127. package/src/components/assistant-ui/follow-on-suggestions.tsx +26 -26
  128. package/src/components/assistant-ui/markdown-text.tsx +69 -69
  129. package/src/components/assistant-ui/mentioned-tools-badges.tsx +38 -38
  130. package/src/components/assistant-ui/message-feedback.tsx +74 -61
  131. package/src/components/assistant-ui/reasoning.tsx +83 -83
  132. package/src/components/assistant-ui/thread-list.tsx +45 -45
  133. package/src/components/assistant-ui/thread.tsx +278 -278
  134. package/src/components/assistant-ui/tool-fallback.tsx +37 -37
  135. package/src/components/assistant-ui/tool-group.tsx +26 -26
  136. package/src/components/assistant-ui/tool-mention-autocomplete.tsx +122 -122
  137. package/src/components/assistant-ui/tooltip-icon-button.tsx +18 -18
  138. package/src/components/ui/avatar.tsx +12 -12
  139. package/src/components/ui/button.tsx +12 -12
  140. package/src/components/ui/buttonVariants.ts +17 -17
  141. package/src/components/ui/calendar.tsx +106 -106
  142. package/src/components/ui/charts.stories.tsx +56 -56
  143. package/src/components/ui/collapsible.tsx +5 -5
  144. package/src/components/ui/dialog.tsx +30 -30
  145. package/src/components/ui/generative-ui.stories.tsx +200 -200
  146. package/src/components/ui/generative-ui.tsx +26 -26
  147. package/src/components/ui/popover.tsx +14 -14
  148. package/src/components/ui/skeleton.tsx +5 -5
  149. package/src/components/ui/time-range-picker.stories.tsx +80 -80
  150. package/src/components/ui/time-range-picker.tsx +272 -235
  151. package/src/components/ui/tool-ui.stories.tsx +37 -37
  152. package/src/components/ui/tool-ui.tsx +221 -215
  153. package/src/components/ui/tooltip.tsx +15 -15
  154. package/src/constants/tailwind.ts +1 -1
  155. package/src/contexts/ChatIdContext.tsx +7 -7
  156. package/src/contexts/ConnectionStatusContext.tsx +64 -64
  157. package/src/contexts/ElementsProvider.tsx +222 -211
  158. package/src/contexts/ReplayContext.ts +3 -3
  159. package/src/contexts/ToolApprovalContext.tsx +54 -54
  160. package/src/contexts/ToolExecutionContext.tsx +34 -34
  161. package/src/contexts/contexts.ts +7 -7
  162. package/src/contexts/portal-container-context.ts +2 -2
  163. package/src/contexts/portal-container.tsx +7 -7
  164. package/src/embedded.ts +1 -1
  165. package/src/global.css +25 -25
  166. package/src/hooks/useAuth.ts +72 -72
  167. package/src/hooks/useDensity.ts +79 -79
  168. package/src/hooks/useElements.ts +6 -6
  169. package/src/hooks/useExpanded.ts +12 -12
  170. package/src/hooks/useFollowOnSuggestions.ts +87 -82
  171. package/src/hooks/useGramThreadListAdapter.tsx +99 -99
  172. package/src/hooks/useMCPTools.ts +47 -47
  173. package/src/hooks/useModel.ts +14 -14
  174. package/src/hooks/usePluginComponents.ts +11 -11
  175. package/src/hooks/usePortalContainer.ts +5 -5
  176. package/src/hooks/useRadius.ts +23 -23
  177. package/src/hooks/useRecordCassette.ts +34 -34
  178. package/src/hooks/useSession.ts +11 -11
  179. package/src/hooks/useThemeProps.ts +13 -13
  180. package/src/hooks/useThreadId.ts +4 -4
  181. package/src/hooks/useToolApproval.ts +7 -7
  182. package/src/hooks/useToolMentions.ts +40 -40
  183. package/src/index.ts +26 -26
  184. package/src/lib/api.test.ts +61 -61
  185. package/src/lib/api.ts +4 -3
  186. package/src/lib/auth.ts +13 -13
  187. package/src/lib/cassette.ts +84 -84
  188. package/src/lib/easing.ts +1 -1
  189. package/src/lib/errorTracking.config.ts +5 -5
  190. package/src/lib/errorTracking.ts +29 -29
  191. package/src/lib/generative-ui.ts +7 -7
  192. package/src/lib/humanize.ts +3 -3
  193. package/src/lib/messageConverter.test.ts +130 -127
  194. package/src/lib/messageConverter.ts +196 -196
  195. package/src/lib/models.ts +21 -20
  196. package/src/lib/token.test.ts +56 -56
  197. package/src/lib/token.ts +14 -14
  198. package/src/lib/tool-mentions.ts +45 -45
  199. package/src/lib/tools.ts +66 -62
  200. package/src/lib/utils.ts +5 -5
  201. package/src/lib.d.ts +1 -1
  202. package/src/plugins/README.md +5 -5
  203. package/src/plugins/chart/catalog.ts +18 -18
  204. package/src/plugins/chart/chart.test.ts +31 -31
  205. package/src/plugins/chart/component.tsx +34 -34
  206. package/src/plugins/chart/index.ts +4 -4
  207. package/src/plugins/chart/ui/area-chart.tsx +42 -42
  208. package/src/plugins/chart/ui/bar-chart.tsx +46 -46
  209. package/src/plugins/chart/ui/donut-chart.tsx +48 -48
  210. package/src/plugins/chart/ui/index.ts +7 -7
  211. package/src/plugins/chart/ui/line-chart.tsx +43 -43
  212. package/src/plugins/chart/ui/pie-chart.tsx +44 -44
  213. package/src/plugins/chart/ui/radar-chart.tsx +33 -33
  214. package/src/plugins/chart/ui/scatter-chart.tsx +43 -43
  215. package/src/plugins/components/MacOSWindowFrame.tsx +15 -15
  216. package/src/plugins/components/PluginLoadingState.tsx +10 -10
  217. package/src/plugins/components/index.ts +1 -1
  218. package/src/plugins/generative-ui/catalog.ts +54 -54
  219. package/src/plugins/generative-ui/component.tsx +85 -85
  220. package/src/plugins/generative-ui/index.ts +4 -4
  221. package/src/plugins/generative-ui/ui/accordion-wrapper.tsx +16 -16
  222. package/src/plugins/generative-ui/ui/accordion.tsx +16 -16
  223. package/src/plugins/generative-ui/ui/action-button.tsx +28 -28
  224. package/src/plugins/generative-ui/ui/alert-wrapper.tsx +8 -8
  225. package/src/plugins/generative-ui/ui/alert.tsx +20 -20
  226. package/src/plugins/generative-ui/ui/avatar-wrapper.tsx +7 -7
  227. package/src/plugins/generative-ui/ui/avatar.tsx +30 -30
  228. package/src/plugins/generative-ui/ui/badge.tsx +22 -22
  229. package/src/plugins/generative-ui/ui/button-wrapper.tsx +12 -12
  230. package/src/plugins/generative-ui/ui/button.tsx +28 -28
  231. package/src/plugins/generative-ui/ui/card-wrapper.tsx +8 -8
  232. package/src/plugins/generative-ui/ui/card.tsx +27 -27
  233. package/src/plugins/generative-ui/ui/checkbox-wrapper.tsx +9 -9
  234. package/src/plugins/generative-ui/ui/checkbox.tsx +9 -9
  235. package/src/plugins/generative-ui/ui/data-table.tsx +8 -8
  236. package/src/plugins/generative-ui/ui/dialog.tsx +31 -31
  237. package/src/plugins/generative-ui/ui/dropdown-menu.tsx +44 -44
  238. package/src/plugins/generative-ui/ui/grid.tsx +12 -12
  239. package/src/plugins/generative-ui/ui/index.ts +40 -40
  240. package/src/plugins/generative-ui/ui/input-wrapper.tsx +11 -11
  241. package/src/plugins/generative-ui/ui/input.tsx +9 -9
  242. package/src/plugins/generative-ui/ui/label.tsx +8 -8
  243. package/src/plugins/generative-ui/ui/list.tsx +11 -11
  244. package/src/plugins/generative-ui/ui/metric.tsx +23 -23
  245. package/src/plugins/generative-ui/ui/pagination.tsx +28 -28
  246. package/src/plugins/generative-ui/ui/popover.tsx +21 -21
  247. package/src/plugins/generative-ui/ui/progress.tsx +13 -13
  248. package/src/plugins/generative-ui/ui/radio-group.tsx +12 -12
  249. package/src/plugins/generative-ui/ui/select-wrapper.tsx +7 -7
  250. package/src/plugins/generative-ui/ui/select.tsx +37 -37
  251. package/src/plugins/generative-ui/ui/separator.tsx +9 -9
  252. package/src/plugins/generative-ui/ui/skeleton-wrapper.tsx +10 -10
  253. package/src/plugins/generative-ui/ui/skeleton.tsx +5 -5
  254. package/src/plugins/generative-ui/ui/stack.tsx +28 -28
  255. package/src/plugins/generative-ui/ui/switch.tsx +11 -11
  256. package/src/plugins/generative-ui/ui/table.tsx +32 -32
  257. package/src/plugins/generative-ui/ui/tabs-wrapper.tsx +11 -11
  258. package/src/plugins/generative-ui/ui/tabs.tsx +26 -26
  259. package/src/plugins/generative-ui/ui/text.tsx +12 -12
  260. package/src/plugins/generative-ui/ui/textarea.tsx +7 -7
  261. package/src/plugins/generative-ui/ui/tooltip.tsx +12 -12
  262. package/src/plugins/index.ts +7 -7
  263. package/src/react-shim.ts +6 -6
  264. package/src/server/bun.ts +12 -12
  265. package/src/server/core.ts +25 -25
  266. package/src/server/express.ts +17 -15
  267. package/src/server/fastify.ts +14 -14
  268. package/src/server/hono.ts +9 -9
  269. package/src/server/nextjs.ts +12 -12
  270. package/src/server/tanstack-start.ts +12 -12
  271. package/src/server.ts +27 -27
  272. package/src/storybook.d.ts +4 -4
  273. package/src/types/index.ts +122 -122
  274. package/src/types/plugins.ts +7 -7
  275. package/src/vite-env.d.ts +12 -12
  276. package/dist/compat-shims-BPJ7Q68c.js.map +0 -1
  277. package/dist/index-DBrhzauj.js.map +0 -1
  278. package/dist/index-DxfW52oA.cjs.map +0 -1
@@ -1,14 +1,14 @@
1
- import { FrontendTools } from '@/components/FrontendTools'
2
- import { ROOT_SELECTOR } from '@/constants/tailwind'
1
+ import { FrontendTools } from "@/components/FrontendTools";
2
+ import { ROOT_SELECTOR } from "@/constants/tailwind";
3
3
  import {
4
4
  isLocalThreadId,
5
5
  useGramThreadListAdapter,
6
- } from '@/hooks/useGramThreadListAdapter'
7
- import { useMCPTools } from '@/hooks/useMCPTools'
8
- import { useToolApproval } from '@/hooks/useToolApproval'
9
- import { getApiUrl } from '@/lib/api'
10
- import { initErrorTracking, trackError } from '@/lib/errorTracking'
11
- import { MODELS } from '@/lib/models'
6
+ } from "@/hooks/useGramThreadListAdapter";
7
+ import { useMCPTools } from "@/hooks/useMCPTools";
8
+ import { useToolApproval } from "@/hooks/useToolApproval";
9
+ import { getApiUrl } from "@/lib/api";
10
+ import { initErrorTracking, trackError } from "@/lib/errorTracking";
11
+ import { MODELS } from "@/lib/models";
12
12
  import {
13
13
  clearFrontendToolApprovalConfig,
14
14
  getEnabledTools,
@@ -17,33 +17,34 @@ import {
17
17
  wrapToolsWithApproval,
18
18
  type ApprovalHelpers,
19
19
  type FrontendTool,
20
- } from '@/lib/tools'
21
- import { cn } from '@/lib/utils'
22
- import { recommended } from '@/plugins'
23
- import { ElementsConfig, Model } from '@/types'
24
- import { Plugin } from '@/types/plugins'
20
+ } from "@/lib/tools";
21
+ import { cn } from "@/lib/utils";
22
+ import { recommended } from "@/plugins";
23
+ import { ElementsConfig, Model } from "@/types";
24
+ import { Plugin } from "@/types/plugins";
25
25
  import {
26
26
  AssistantRuntimeProvider,
27
27
  AssistantTool,
28
28
  useAssistantState,
29
29
  unstable_useRemoteThreadListRuntime as useRemoteThreadListRuntime,
30
- } from '@assistant-ui/react'
30
+ } from "@assistant-ui/react";
31
31
  import {
32
32
  frontendTools as convertFrontendToolsToAISDKTools,
33
33
  useChatRuntime,
34
- } from '@assistant-ui/react-ai-sdk'
35
- import { createOpenRouter } from '@openrouter/ai-sdk-provider'
36
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
34
+ } from "@assistant-ui/react-ai-sdk";
35
+ import { createOpenRouter } from "@openrouter/ai-sdk-provider";
36
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
37
37
  import {
38
38
  convertToModelMessages,
39
39
  createUIMessageStream,
40
+ LanguageModel,
40
41
  smoothStream,
41
42
  stepCountIs,
42
43
  streamText,
43
44
  ToolSet,
44
45
  type ChatTransport,
45
46
  type UIMessage,
46
- } from 'ai'
47
+ } from "ai";
47
48
  import {
48
49
  ReactNode,
49
50
  useCallback,
@@ -51,16 +52,16 @@ import {
51
52
  useMemo,
52
53
  useRef,
53
54
  useState,
54
- } from 'react'
55
- import { useAuth } from '../hooks/useAuth'
56
- import { ChatIdContext } from './ChatIdContext'
55
+ } from "react";
56
+ import { useAuth } from "../hooks/useAuth";
57
+ import { ChatIdContext } from "./ChatIdContext";
57
58
  import {
58
59
  ConnectionStatusProvider,
59
60
  useConnectionStatusOptional,
60
- } from './ConnectionStatusContext'
61
- import { ElementsContext } from './contexts'
62
- import { ToolApprovalProvider } from './ToolApprovalContext'
63
- import { ToolExecutionProvider } from './ToolExecutionContext'
61
+ } from "./ConnectionStatusContext";
62
+ import { ElementsContext } from "./contexts";
63
+ import { ToolApprovalProvider } from "./ToolApprovalContext";
64
+ import { ToolExecutionProvider } from "./ToolExecutionContext";
64
65
 
65
66
  /**
66
67
  * Extracts executable tools from frontend tool definitions.
@@ -69,30 +70,30 @@ import { ToolExecutionProvider } from './ToolExecutionContext'
69
70
  */
70
71
  function extractExecutableTools(
71
72
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
72
- frontendTools: Record<string, FrontendTool<any, any>> | undefined
73
+ frontendTools: Record<string, FrontendTool<any, any>> | undefined,
73
74
  ): Record<
74
75
  string,
75
76
  { execute?: (args: unknown, options?: unknown) => Promise<unknown> }
76
77
  > {
77
- if (!frontendTools) return {}
78
+ if (!frontendTools) return {};
78
79
 
79
80
  return Object.fromEntries(
80
81
  Object.entries(frontendTools).map(([name, tool]) => {
81
82
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
82
- const toolDef = (tool as any).unstable_tool
83
+ const toolDef = (tool as any).unstable_tool;
83
84
  return [
84
85
  name,
85
86
  {
86
87
  execute: toolDef?.execute,
87
88
  },
88
- ]
89
- })
90
- )
89
+ ];
90
+ }),
91
+ );
91
92
  }
92
93
 
93
94
  export interface ElementsProviderProps {
94
- children: ReactNode
95
- config: ElementsConfig
95
+ children: ReactNode;
96
+ config: ElementsConfig;
96
97
  }
97
98
 
98
99
  const BASE_SYSTEM_PROMPT = `You are a helpful assistant that can answer questions and help with tasks.
@@ -100,26 +101,29 @@ const BASE_SYSTEM_PROMPT = `You are a helpful assistant that can answer question
100
101
  Tool Result Display:
101
102
  Some tools have custom visual components that automatically render their results (you'll see a rich card/widget appear). For these, do not repeat the data - just add brief context or a follow-up question if needed.
102
103
 
103
- For tools WITHOUT custom components, you should present the data clearly - either as plain text for simple results, or using the UI code block format for structured data like lists of items, categories, or dashboards.`
104
+ For tools WITHOUT custom components, you should present the data clearly - either as plain text for simple results, or using the UI code block format for structured data like lists of items, categories, or dashboards.
105
+
106
+ UI Widget Guidelines:
107
+ IMPORTANT: Only render ONE generative UI widget (chart, dashboard, visualization) per response. Never render multiple widgets in a single message - this causes layout shifts during streaming and overwhelms the user. If you have multiple visualizations to show, render the most important one and explicitly offer to show others as follow-ups (e.g., "Would you like to see a breakdown by status as well?").`;
104
108
 
105
109
  function mergeInternalSystemPromptWith(
106
110
  userSystemPrompt: string | undefined,
107
111
  plugins: Plugin[],
108
- toolsWithCustomComponents: string[]
112
+ toolsWithCustomComponents: string[],
109
113
  ) {
110
114
  const customToolsSection =
111
115
  toolsWithCustomComponents.length > 0
112
- ? `\n\nTools with custom visual components (DO NOT render UI widgets for these - they already display rich visuals):\n${toolsWithCustomComponents.map((t) => `- ${t}`).join('\n')}`
113
- : ''
116
+ ? `\n\nTools with custom visual components (DO NOT render UI widgets for these - they already display rich visuals):\n${toolsWithCustomComponents.map((t) => `- ${t}`).join("\n")}`
117
+ : "";
114
118
 
115
119
  return `
116
120
  ${BASE_SYSTEM_PROMPT}${customToolsSection}
117
121
 
118
122
  User-provided System Prompt:
119
- ${userSystemPrompt ?? 'None provided'}
123
+ ${userSystemPrompt ?? "None provided"}
120
124
 
121
125
  Utilities:
122
- ${plugins.map((plugin) => `- ${plugin.language}: ${plugin.prompt}`).join('\n')}`
126
+ ${plugins.map((plugin) => `- ${plugin.language}: ${plugin.prompt}`).join("\n")}`;
123
127
  }
124
128
 
125
129
  /**
@@ -128,9 +132,9 @@ function mergeInternalSystemPromptWith(
128
132
  */
129
133
  function cleanMessagesForModel(messages: UIMessage[]): UIMessage[] {
130
134
  return messages.map((message) => {
131
- const partsArray = message.parts
135
+ const partsArray = message.parts;
132
136
  if (!Array.isArray(partsArray)) {
133
- return message
137
+ return message;
134
138
  }
135
139
 
136
140
  // Process each part: strip providerOptions/providerMetadata and filter reasoning
@@ -138,15 +142,15 @@ function cleanMessagesForModel(messages: UIMessage[]): UIMessage[] {
138
142
  const cleanedParts = partsArray.map((part: any) => {
139
143
  // Strip providerOptions and providerMetadata from all remaining parts
140
144
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
141
- const { callProviderMetadata: _, ...cleanPart } = part
142
- return cleanPart
143
- })
145
+ const { callProviderMetadata: _, ...cleanPart } = part;
146
+ return cleanPart;
147
+ });
144
148
 
145
149
  return {
146
150
  ...message,
147
151
  parts: cleanedParts,
148
- }
149
- })
152
+ };
153
+ });
150
154
  }
151
155
 
152
156
  /**
@@ -154,35 +158,35 @@ function cleanMessagesForModel(messages: UIMessage[]): UIMessage[] {
154
158
  * Delegates to either WithHistory or WithoutHistory based on config.
155
159
  */
156
160
  const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
157
- const apiUrl = getApiUrl(config)
161
+ const apiUrl = getApiUrl(config);
158
162
  const auth = useAuth({
159
163
  auth: config.api,
160
164
  projectSlug: config.projectSlug,
161
- })
165
+ });
162
166
 
163
167
  // Ref to access ensureValidHeaders in async transport without stale closures
164
- const ensureValidHeadersRef = useRef(auth.ensureValidHeaders)
165
- ensureValidHeadersRef.current = auth.ensureValidHeaders
166
- const toolApproval = useToolApproval()
168
+ const ensureValidHeadersRef = useRef(auth.ensureValidHeaders);
169
+ ensureValidHeadersRef.current = auth.ensureValidHeaders;
170
+ const toolApproval = useToolApproval();
167
171
 
168
172
  const [model, setModel] = useState<Model>(
169
- config.model?.defaultModel ?? MODELS[0]
170
- )
173
+ config.model?.defaultModel ?? MODELS[0],
174
+ );
171
175
  const [isExpanded, setIsExpanded] = useState(
172
- config.modal?.defaultExpanded ?? false
173
- )
174
- const [isOpen, setIsOpen] = useState(config.modal?.defaultOpen)
176
+ config.modal?.defaultExpanded ?? false,
177
+ );
178
+ const [isOpen, setIsOpen] = useState(config.modal?.defaultOpen);
175
179
 
176
- const plugins = config.plugins ?? recommended
180
+ const plugins = config.plugins ?? recommended;
177
181
 
178
182
  // Get list of tools that have custom components registered
179
- const toolsWithCustomComponents = Object.keys(config.tools?.components ?? {})
183
+ const toolsWithCustomComponents = Object.keys(config.tools?.components ?? {});
180
184
 
181
185
  const systemPrompt = mergeInternalSystemPromptWith(
182
186
  config.systemPrompt,
183
187
  plugins,
184
- toolsWithCustomComponents
185
- )
188
+ toolsWithCustomComponents,
189
+ );
186
190
 
187
191
  // Initialize error tracking on mount
188
192
  useEffect(() => {
@@ -190,15 +194,15 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
190
194
  enabled: config.errorTracking?.enabled,
191
195
  projectSlug: config.projectSlug,
192
196
  variant: config.variant,
193
- })
194
- }, [])
197
+ });
198
+ }, []);
195
199
 
196
200
  // Generate a stable chat ID for server-side persistence (when history is disabled)
197
201
  // When history is enabled, the thread adapter manages chat IDs instead
198
- const chatIdRef = useRef<string | null>(null)
202
+ const chatIdRef = useRef<string | null>(null);
199
203
 
200
204
  // State to expose the current chat ID via context
201
- const [currentChatId, setCurrentChatId] = useState<string | null>(null)
205
+ const [currentChatId, setCurrentChatId] = useState<string | null>(null);
202
206
 
203
207
  const { data: mcpTools, mcpHeaders } = useMCPTools({
204
208
  auth,
@@ -206,23 +210,23 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
206
210
  environment: config.environment ?? {},
207
211
  toolsToInclude: config.tools?.toolsToInclude,
208
212
  gramEnvironment: config.gramEnvironment,
209
- })
213
+ });
210
214
 
211
215
  // Store approval helpers in ref so they can be used in async contexts
212
216
  const approvalHelpersRef = useRef<ApprovalHelpers>({
213
217
  requestApproval: toolApproval.requestApproval,
214
218
  isToolApproved: toolApproval.isToolApproved,
215
219
  whitelistTool: toolApproval.whitelistTool,
216
- })
220
+ });
217
221
 
218
222
  // Connection status for tracking network failures
219
- const connectionStatus = useConnectionStatusOptional()
223
+ const connectionStatus = useConnectionStatusOptional();
220
224
 
221
225
  approvalHelpersRef.current = {
222
226
  requestApproval: toolApproval.requestApproval,
223
227
  isToolApproved: toolApproval.isToolApproved,
224
228
  whitelistTool: toolApproval.whitelistTool,
225
- }
229
+ };
226
230
 
227
231
  const getApprovalHelpers = useCallback((): ApprovalHelpers => {
228
232
  return {
@@ -232,51 +236,51 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
232
236
  approvalHelpersRef.current.isToolApproved(...args),
233
237
  whitelistTool: (...args) =>
234
238
  approvalHelpersRef.current.whitelistTool(...args),
235
- }
236
- }, [])
239
+ };
240
+ }, []);
237
241
 
238
242
  // Set up frontend tool approval config for runtime checking
239
243
  useEffect(() => {
240
244
  if (config.tools?.toolsRequiringApproval) {
241
245
  setFrontendToolApprovalConfig(
242
246
  getApprovalHelpers(),
243
- config.tools.toolsRequiringApproval
244
- )
247
+ config.tools.toolsRequiringApproval,
248
+ );
245
249
  }
246
250
  return () => {
247
- clearFrontendToolApprovalConfig()
248
- }
249
- }, [config.tools?.toolsRequiringApproval, getApprovalHelpers])
251
+ clearFrontendToolApprovalConfig();
252
+ };
253
+ }, [config.tools?.toolsRequiringApproval, getApprovalHelpers]);
250
254
 
251
255
  // Ref to access runtime from within transport's sendMessages.
252
256
  // This solves a circular dependency: transport needs runtime.thread.getModelContext(),
253
257
  // but runtime is created using transport. The ref gets populated after runtime creation.
254
- const runtimeRef = useRef<ReturnType<typeof useChatRuntime> | null>(null)
258
+ const runtimeRef = useRef<ReturnType<typeof useChatRuntime> | null>(null);
255
259
 
256
260
  // Map to share local thread IDs to UUIDs between adapter and transport (for history mode)
257
- const localIdToUuidMapRef = useRef(new Map<string, string>())
261
+ const localIdToUuidMapRef = useRef(new Map<string, string>());
258
262
 
259
263
  // Ref to store the current thread's remoteId, synced from assistant-ui state.
260
264
  // This is needed because the runtime object doesn't expose threadListItem.remoteId
261
265
  // in a way that's accessible from the transport's sendMessages function.
262
- const currentRemoteIdRef = useRef<string | null>(null)
266
+ const currentRemoteIdRef = useRef<string | null>(null);
263
267
 
264
268
  // Create chat transport configuration
265
269
  const transport = useMemo<ChatTransport<UIMessage>>(
266
270
  () => ({
267
271
  sendMessages: async ({ messages, abortSignal }) => {
268
- const usingCustomModel = !!config.languageModel
272
+ const usingCustomModel = !!config.languageModel;
269
273
 
270
274
  if (auth.isLoading) {
271
- throw new Error('Session is loading')
275
+ throw new Error("Session is loading");
272
276
  }
273
277
 
274
278
  // Ensure the session token is still valid; refresh if expired
275
- const validHeaders = await ensureValidHeadersRef.current()
279
+ const validHeaders = await ensureValidHeadersRef.current();
276
280
 
277
281
  // Get chat ID - use the synced remoteId ref first (history mode),
278
282
  // fall back to generated ID (non-history mode)
279
- let chatId = currentRemoteIdRef.current
283
+ let chatId = currentRemoteIdRef.current;
280
284
 
281
285
  // If we have a valid remoteId (not a local ID), use it directly
282
286
  if (chatId && !isLocalThreadId(chatId)) {
@@ -284,21 +288,21 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
284
288
  } else if (isLocalThreadId(chatId) || !chatId) {
285
289
  // For local thread IDs or no ID, check/generate UUID mapping
286
290
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
287
- const runtimeAny = runtimeRef.current as any
288
- const threadsState = runtimeAny?.threads?.getState?.()
291
+ const runtimeAny = runtimeRef.current as any;
292
+ const threadsState = runtimeAny?.threads?.getState?.();
289
293
  const localThreadId = (threadsState?.mainThreadId ??
290
- threadsState?.threadIds?.[0]) as string | undefined
294
+ threadsState?.threadIds?.[0]) as string | undefined;
291
295
 
292
- const lookupKey = chatId ?? localThreadId
296
+ const lookupKey = chatId ?? localThreadId;
293
297
  if (lookupKey) {
294
- const existingUuid = localIdToUuidMapRef.current.get(lookupKey)
298
+ const existingUuid = localIdToUuidMapRef.current.get(lookupKey);
295
299
  if (existingUuid) {
296
- chatId = existingUuid
300
+ chatId = existingUuid;
297
301
  } else {
298
302
  // Generate a new UUID and store the mapping
299
- const newUuid = crypto.randomUUID()
300
- localIdToUuidMapRef.current.set(lookupKey, newUuid)
301
- chatId = newUuid
303
+ const newUuid = crypto.randomUUID();
304
+ localIdToUuidMapRef.current.set(lookupKey, newUuid);
305
+ chatId = newUuid;
302
306
  }
303
307
  }
304
308
  }
@@ -306,40 +310,40 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
306
310
  if (!chatId) {
307
311
  // Non-history mode fallback - use stable chatIdRef
308
312
  if (!chatIdRef.current) {
309
- chatIdRef.current = crypto.randomUUID()
313
+ chatIdRef.current = crypto.randomUUID();
310
314
  }
311
- chatId = chatIdRef.current
315
+ chatId = chatIdRef.current;
312
316
  }
313
317
 
314
318
  // Mutate the shared headers object so the MCP transport picks up the
315
319
  // chat ID on subsequent tool call requests.
316
320
  if (chatId) {
317
- mcpHeaders['Gram-Chat-ID'] = chatId
321
+ mcpHeaders["Gram-Chat-ID"] = chatId;
318
322
  // Update the context state so consumers can access the current chat ID
319
- setCurrentChatId(chatId)
323
+ setCurrentChatId(chatId);
320
324
  }
321
325
 
322
- const context = runtimeRef.current?.thread.getModelContext()
326
+ const context = runtimeRef.current?.thread.getModelContext();
323
327
  const frontendTools = toAISDKTools(
324
- getEnabledTools(context?.tools ?? {})
325
- )
328
+ getEnabledTools(context?.tools ?? {}),
329
+ );
326
330
 
327
331
  // Include Gram-Chat-ID header for chat persistence and Gram-Environment for environment selection
328
332
  const headersWithChatId = {
329
333
  ...validHeaders,
330
- 'Gram-Chat-ID': chatId,
331
- 'X-Gram-Source': 'elements',
334
+ "Gram-Chat-ID": chatId,
335
+ "X-Gram-Source": "elements",
332
336
  ...config.api?.headers, // We do this after X-Gram-Source so the playground can override it
333
337
  ...(config.gramEnvironment && {
334
- 'Gram-Environment': config.gramEnvironment,
338
+ "Gram-Environment": config.gramEnvironment,
335
339
  }),
336
- }
340
+ };
337
341
 
338
342
  // Update MCP headers with the (possibly refreshed) session token
339
343
  // so mid-stream MCP tool calls use the fresh token
340
- const freshSession = validHeaders['Gram-Chat-Session']
344
+ const freshSession = validHeaders["Gram-Chat-Session"];
341
345
  if (freshSession) {
342
- mcpHeaders['Gram-Chat-Session'] = freshSession
346
+ mcpHeaders["Gram-Chat-Session"] = freshSession;
343
347
  }
344
348
 
345
349
  // Create OpenRouter model (only needed when not using custom model)
@@ -347,36 +351,43 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
347
351
  ? null
348
352
  : createOpenRouter({
349
353
  baseURL: apiUrl,
350
- apiKey: 'unused, but must be set',
354
+ apiKey: "unused, but must be set",
351
355
  headers: headersWithChatId,
352
- })
356
+ });
353
357
 
354
358
  if (config.languageModel) {
355
- console.log('Using custom language model', config.languageModel)
359
+ console.log("Using custom language model", config.languageModel);
356
360
  }
357
361
 
358
362
  // Combine tools - MCP tools only available when not using custom model
359
363
  const combinedTools: ToolSet = {
360
364
  ...mcpTools,
361
365
  ...convertFrontendToolsToAISDKTools(frontendTools),
362
- } as ToolSet
366
+ } as ToolSet;
363
367
 
364
368
  // Wrap tools that require approval
365
369
  const tools = wrapToolsWithApproval(
366
370
  combinedTools,
367
371
  config.tools?.toolsRequiringApproval,
368
- getApprovalHelpers()
369
- )
372
+ getApprovalHelpers(),
373
+ );
370
374
 
371
375
  // Stream the response
372
376
  const modelToUse = config.languageModel
373
377
  ? config.languageModel
374
- : openRouterModel!.chat(model)
378
+ : (openRouterModel!.chat(model) as LanguageModel);
375
379
 
376
380
  try {
377
381
  // This works around AI SDK bug where these fields cause validation failures
378
- const cleanedMessages = cleanMessagesForModel(messages)
379
- const modelMessages = convertToModelMessages(cleanedMessages)
382
+ const cleanedMessages = cleanMessagesForModel(messages);
383
+ // Filter out system messages from the UI state — the system prompt
384
+ // is already provided via the `system:` parameter to streamText().
385
+ // Without this, loaded chat history includes the system message which
386
+ // gets sent alongside the `system:` param, causing duplication.
387
+ const nonSystemMessages = cleanedMessages.filter(
388
+ (m) => m.role !== "system",
389
+ );
390
+ const modelMessages = convertToModelMessages(nonSystemMessages);
380
391
 
381
392
  const result = streamText({
382
393
  system: systemPrompt,
@@ -387,59 +398,59 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
387
398
  experimental_transform: smoothStream({ delayInMs: 15 }),
388
399
  abortSignal,
389
400
  onError: ({ error }) => {
390
- console.error('Stream error in onError callback:', error)
391
- trackError(error, { source: 'streaming' })
401
+ console.error("Stream error in onError callback:", error);
402
+ trackError(error, { source: "streaming" });
392
403
 
393
404
  // Check if this is a network/connection error
394
405
  const isNetworkError =
395
406
  error instanceof TypeError ||
396
407
  (error instanceof Error &&
397
- (error.message.includes('fetch') ||
398
- error.message.includes('network') ||
399
- error.message.includes('Failed to fetch') ||
400
- error.message.includes('NetworkError') ||
401
- error.message.includes('ECONNREFUSED') ||
402
- error.message.includes('ETIMEDOUT')))
408
+ (error.message.includes("fetch") ||
409
+ error.message.includes("network") ||
410
+ error.message.includes("Failed to fetch") ||
411
+ error.message.includes("NetworkError") ||
412
+ error.message.includes("ECONNREFUSED") ||
413
+ error.message.includes("ETIMEDOUT")));
403
414
 
404
415
  if (isNetworkError) {
405
- connectionStatus?.markDisconnected()
416
+ connectionStatus?.markDisconnected();
406
417
  }
407
418
  },
408
- })
419
+ });
409
420
 
410
421
  // Mark as connected when stream starts successfully
411
- connectionStatus?.markConnected()
422
+ connectionStatus?.markConnected();
412
423
 
413
424
  // This weird construction is necessary to get errors to propagate properly to assistant-ui
414
425
  return createUIMessageStream({
415
426
  execute: ({ writer }) => {
416
- writer.merge(result.toUIMessageStream())
427
+ writer.merge(result.toUIMessageStream());
417
428
  },
418
- })
429
+ });
419
430
  } catch (error) {
420
- console.error('Error creating stream:', error)
421
- trackError(error, { source: 'stream-creation' })
431
+ console.error("Error creating stream:", error);
432
+ trackError(error, { source: "stream-creation" });
422
433
 
423
434
  // Check if this is a network/connection error
424
435
  const isNetworkError =
425
436
  error instanceof TypeError ||
426
437
  (error instanceof Error &&
427
- (error.message.includes('fetch') ||
428
- error.message.includes('network') ||
429
- error.message.includes('Failed to fetch') ||
430
- error.message.includes('NetworkError') ||
431
- error.message.includes('ECONNREFUSED') ||
432
- error.message.includes('ETIMEDOUT')))
438
+ (error.message.includes("fetch") ||
439
+ error.message.includes("network") ||
440
+ error.message.includes("Failed to fetch") ||
441
+ error.message.includes("NetworkError") ||
442
+ error.message.includes("ECONNREFUSED") ||
443
+ error.message.includes("ETIMEDOUT")));
433
444
 
434
445
  if (isNetworkError) {
435
- connectionStatus?.markDisconnected()
446
+ connectionStatus?.markDisconnected();
436
447
  }
437
448
 
438
- throw error
449
+ throw error;
439
450
  }
440
451
  },
441
452
  reconnectToStream: async () => {
442
- throw new Error('Stream reconnection not supported')
453
+ throw new Error("Stream reconnection not supported");
443
454
  },
444
455
  }),
445
456
  [
@@ -452,10 +463,10 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
452
463
  apiUrl,
453
464
  auth.isLoading,
454
465
  connectionStatus,
455
- ]
456
- )
466
+ ],
467
+ );
457
468
 
458
- const historyEnabled = config.history?.enabled ?? false
469
+ const historyEnabled = config.history?.enabled ?? false;
459
470
 
460
471
  // Shared context value for ElementsContext
461
472
  const contextValue = useMemo(
@@ -470,10 +481,10 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
470
481
  plugins,
471
482
  mcpTools,
472
483
  }),
473
- [config, model, isExpanded, isOpen, plugins, mcpTools]
474
- )
484
+ [config, model, isExpanded, isOpen, plugins, mcpTools],
485
+ );
475
486
 
476
- const frontendTools = config.tools?.frontendTools ?? {}
487
+ const frontendTools = config.tools?.frontendTools ?? {};
477
488
 
478
489
  // Create combined executable tools for direct tool execution (ActionButton)
479
490
  // Uses a simplified type that focuses on the execute function
@@ -481,17 +492,17 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
481
492
  string,
482
493
  | { execute?: (args: unknown, options?: unknown) => Promise<unknown> }
483
494
  | undefined
484
- >
495
+ >;
485
496
  const executableTools = useMemo<ExecutableToolSet>(() => {
486
497
  const extractedFrontendTools = extractExecutableTools(
487
- config.tools?.frontendTools
488
- )
498
+ config.tools?.frontendTools,
499
+ );
489
500
  // MCP tools and extracted frontend tools both have execute functions
490
501
  return {
491
502
  ...mcpTools,
492
503
  ...extractedFrontendTools,
493
- } as ExecutableToolSet
494
- }, [mcpTools, config.tools?.frontendTools])
504
+ } as ExecutableToolSet;
505
+ }, [mcpTools, config.tools?.frontendTools]);
495
506
 
496
507
  // Render the appropriate runtime provider based on history config.
497
508
  // We use separate components to avoid conditional hook calls.
@@ -512,7 +523,7 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
512
523
  >
513
524
  {children}
514
525
  </ElementsProviderWithHistory>
515
- )
526
+ );
516
527
  }
517
528
 
518
529
  return (
@@ -526,31 +537,31 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
526
537
  >
527
538
  {children}
528
539
  </ElementsProviderWithoutHistory>
529
- )
530
- }
540
+ );
541
+ };
531
542
 
532
543
  // Shared type for executable tools
533
544
  type ExecutableToolSet = Record<
534
545
  string,
535
546
  | { execute?: (args: unknown, options?: unknown) => Promise<unknown> }
536
547
  | undefined
537
- >
548
+ >;
538
549
 
539
550
  // Separate component for history-enabled mode to avoid conditional hook calls
540
551
  interface ElementsProviderWithHistoryProps {
541
- children: ReactNode
542
- transport: ChatTransport<UIMessage>
543
- apiUrl: string
544
- headers: Record<string, string>
545
- contextValue: React.ContextType<typeof ElementsContext>
546
- runtimeRef: React.RefObject<ReturnType<typeof useChatRuntime> | null>
552
+ children: ReactNode;
553
+ transport: ChatTransport<UIMessage>;
554
+ apiUrl: string;
555
+ headers: Record<string, string>;
556
+ contextValue: React.ContextType<typeof ElementsContext>;
557
+ runtimeRef: React.RefObject<ReturnType<typeof useChatRuntime> | null>;
547
558
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
548
- frontendTools: Record<string, AssistantTool | FrontendTool<any, any>>
549
- localIdToUuidMap: Map<string, string>
550
- currentRemoteIdRef: React.RefObject<string | null>
551
- executableTools: ExecutableToolSet
552
- currentChatId: string | null
553
- setCurrentChatId: (chatId: string | null) => void
559
+ frontendTools: Record<string, AssistantTool | FrontendTool<any, any>>;
560
+ localIdToUuidMap: Map<string, string>;
561
+ currentRemoteIdRef: React.RefObject<string | null>;
562
+ executableTools: ExecutableToolSet;
563
+ currentChatId: string | null;
564
+ setCurrentChatId: (chatId: string | null) => void;
554
565
  }
555
566
 
556
567
  /**
@@ -561,18 +572,18 @@ const ThreadIdSync = ({
561
572
  remoteIdRef,
562
573
  onChatIdChange,
563
574
  }: {
564
- remoteIdRef: React.RefObject<string | null>
565
- onChatIdChange: (chatId: string | null) => void
575
+ remoteIdRef: React.RefObject<string | null>;
576
+ onChatIdChange: (chatId: string | null) => void;
566
577
  }) => {
567
578
  const remoteId = useAssistantState(
568
- ({ threadListItem }) => threadListItem.remoteId ?? null
569
- )
579
+ ({ threadListItem }) => threadListItem.remoteId ?? null,
580
+ );
570
581
  useEffect(() => {
571
- remoteIdRef.current = remoteId
572
- onChatIdChange(remoteId)
573
- }, [remoteId, remoteIdRef, onChatIdChange])
574
- return null
575
- }
582
+ remoteIdRef.current = remoteId;
583
+ onChatIdChange(remoteId);
584
+ }, [remoteId, remoteIdRef, onChatIdChange]);
585
+ return null;
586
+ };
576
587
 
577
588
  const ElementsProviderWithHistory = ({
578
589
  children,
@@ -592,43 +603,43 @@ const ElementsProviderWithHistory = ({
592
603
  apiUrl,
593
604
  headers,
594
605
  localIdToUuidMap,
595
- })
596
- const initialThreadId = contextValue?.config.history?.initialThreadId
606
+ });
607
+ const initialThreadId = contextValue?.config.history?.initialThreadId;
597
608
 
598
609
  // Hook factory for creating the base chat runtime
599
610
  const useChatRuntimeHook = useCallback(() => {
600
- return useChatRuntime({ transport })
601
- }, [transport])
611
+ return useChatRuntime({ transport });
612
+ }, [transport]);
602
613
 
603
614
  const runtime = useRemoteThreadListRuntime({
604
615
  adapter: threadListAdapter,
605
616
  runtimeHook: useChatRuntimeHook,
606
- })
617
+ });
607
618
 
608
619
  // Populate runtimeRef so transport can access thread context
609
620
  useEffect(() => {
610
- runtimeRef.current = runtime as ReturnType<typeof useChatRuntime>
611
- }, [runtime, runtimeRef])
621
+ runtimeRef.current = runtime as ReturnType<typeof useChatRuntime>;
622
+ }, [runtime, runtimeRef]);
612
623
 
613
624
  // Switch to initial thread if provided (for shared chat URLs)
614
- const initialThreadSwitched = useRef(false)
625
+ const initialThreadSwitched = useRef(false);
615
626
  useEffect(() => {
616
627
  if (initialThreadId && !initialThreadSwitched.current) {
617
- initialThreadSwitched.current = true
628
+ initialThreadSwitched.current = true;
618
629
  // Use setTimeout to ensure runtime is fully initialized
619
630
  const timeoutId = setTimeout(() => {
620
631
  runtime.threads.switchToThread(initialThreadId).catch((error) => {
621
- console.error('Failed to switch to initial thread:', error)
622
- })
623
- }, 100)
624
- return () => clearTimeout(timeoutId)
632
+ console.error("Failed to switch to initial thread:", error);
633
+ });
634
+ }, 100);
635
+ return () => clearTimeout(timeoutId);
625
636
  }
626
- }, [initialThreadId, runtime])
637
+ }, [initialThreadId, runtime]);
627
638
 
628
639
  // Get the Provider from our adapter to wrap the content
629
640
  const HistoryProvider =
630
641
  threadListAdapter.unstable_Provider ??
631
- (({ children }: { children: React.ReactNode }) => <>{children}</>)
642
+ (({ children }: { children: React.ReactNode }) => <>{children}</>);
632
643
 
633
644
  return (
634
645
  <AssistantRuntimeProvider runtime={runtime}>
@@ -643,9 +654,9 @@ const ElementsProviderWithHistory = ({
643
654
  <div
644
655
  className={cn(
645
656
  ROOT_SELECTOR,
646
- (contextValue?.config.variant === 'standalone' ||
647
- contextValue?.config.variant === 'sidecar') &&
648
- 'h-full'
657
+ (contextValue?.config.variant === "standalone" ||
658
+ contextValue?.config.variant === "sidecar") &&
659
+ "h-full",
649
660
  )}
650
661
  >
651
662
  {children}
@@ -656,19 +667,19 @@ const ElementsProviderWithHistory = ({
656
667
  </ChatIdContext.Provider>
657
668
  </HistoryProvider>
658
669
  </AssistantRuntimeProvider>
659
- )
660
- }
670
+ );
671
+ };
661
672
 
662
673
  // Separate component for non-history mode to avoid conditional hook calls
663
674
  interface ElementsProviderWithoutHistoryProps {
664
- children: ReactNode
665
- transport: ChatTransport<UIMessage>
666
- contextValue: React.ContextType<typeof ElementsContext>
667
- runtimeRef: React.RefObject<ReturnType<typeof useChatRuntime> | null>
675
+ children: ReactNode;
676
+ transport: ChatTransport<UIMessage>;
677
+ contextValue: React.ContextType<typeof ElementsContext>;
678
+ runtimeRef: React.RefObject<ReturnType<typeof useChatRuntime> | null>;
668
679
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
669
- frontendTools: Record<string, AssistantTool | FrontendTool<any, any>>
670
- executableTools: ExecutableToolSet
671
- currentChatId: string | null
680
+ frontendTools: Record<string, AssistantTool | FrontendTool<any, any>>;
681
+ executableTools: ExecutableToolSet;
682
+ currentChatId: string | null;
672
683
  }
673
684
 
674
685
  const ElementsProviderWithoutHistory = ({
@@ -680,12 +691,12 @@ const ElementsProviderWithoutHistory = ({
680
691
  executableTools,
681
692
  currentChatId,
682
693
  }: ElementsProviderWithoutHistoryProps) => {
683
- const runtime = useChatRuntime({ transport })
694
+ const runtime = useChatRuntime({ transport });
684
695
 
685
696
  // Populate runtimeRef so transport can access thread context
686
697
  useEffect(() => {
687
- runtimeRef.current = runtime
688
- }, [runtime, runtimeRef])
698
+ runtimeRef.current = runtime;
699
+ }, [runtime, runtimeRef]);
689
700
 
690
701
  return (
691
702
  <AssistantRuntimeProvider runtime={runtime}>
@@ -695,9 +706,9 @@ const ElementsProviderWithoutHistory = ({
695
706
  <div
696
707
  className={cn(
697
708
  ROOT_SELECTOR,
698
- (contextValue?.config.variant === 'standalone' ||
699
- contextValue?.config.variant === 'sidecar') &&
700
- 'h-full'
709
+ (contextValue?.config.variant === "standalone" ||
710
+ contextValue?.config.variant === "sidecar") &&
711
+ "h-full",
701
712
  )}
702
713
  >
703
714
  {children}
@@ -707,10 +718,10 @@ const ElementsProviderWithoutHistory = ({
707
718
  </ElementsContext.Provider>
708
719
  </ChatIdContext.Provider>
709
720
  </AssistantRuntimeProvider>
710
- )
711
- }
721
+ );
722
+ };
712
723
 
713
- const queryClient = new QueryClient()
724
+ const queryClient = new QueryClient();
714
725
 
715
726
  export const ElementsProvider = (props: ElementsProviderProps) => {
716
727
  return (
@@ -721,5 +732,5 @@ export const ElementsProvider = (props: ElementsProviderProps) => {
721
732
  </ToolApprovalProvider>
722
733
  </ConnectionStatusProvider>
723
734
  </QueryClientProvider>
724
- )
725
- }
735
+ );
736
+ };