@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
@@ -10,7 +10,7 @@ import {
10
10
  PencilIcon,
11
11
  Settings2,
12
12
  Square,
13
- } from 'lucide-react'
13
+ } from "lucide-react";
14
14
 
15
15
  import {
16
16
  ActionBarPrimitive,
@@ -21,15 +21,15 @@ import {
21
21
  MessagePrimitive,
22
22
  ThreadPrimitive,
23
23
  useAssistantState,
24
- } from '@assistant-ui/react'
24
+ } from "@assistant-ui/react";
25
25
 
26
26
  import {
27
27
  AnimatePresence,
28
28
  LazyMotion,
29
29
  MotionConfig,
30
30
  domAnimation,
31
- } from 'motion/react'
32
- import * as m from 'motion/react-m'
31
+ } from "motion/react";
32
+ import * as m from "motion/react-m";
33
33
  import {
34
34
  createContext,
35
35
  useCallback,
@@ -39,56 +39,56 @@ import {
39
39
  useRef,
40
40
  useState,
41
41
  type FC,
42
- } from 'react'
42
+ } from "react";
43
43
 
44
44
  import {
45
45
  ComposerAddAttachment,
46
46
  ComposerAttachments,
47
47
  UserMessageAttachments,
48
- } from '@/components/assistant-ui/attachment'
49
- import { FollowOnSuggestions } from '@/components/assistant-ui/follow-on-suggestions'
50
- import { MarkdownText } from '@/components/assistant-ui/markdown-text'
51
- import { MentionedToolsBadges } from '@/components/assistant-ui/mentioned-tools-badges'
52
- import { MessageFeedback } from '@/components/assistant-ui/message-feedback'
53
- import { Reasoning, ReasoningGroup } from '@/components/assistant-ui/reasoning'
54
- import { ToolFallback } from '@/components/assistant-ui/tool-fallback'
55
- import { ToolMentionAutocomplete } from '@/components/assistant-ui/tool-mention-autocomplete'
56
- import { TooltipIconButton } from '@/components/assistant-ui/tooltip-icon-button'
57
- import { Button } from '@/components/ui/button'
58
- import { useChatId } from '@/contexts/ChatIdContext'
59
- import { useReplayContext } from '@/contexts/ReplayContext'
60
- import { useAuth } from '@/hooks/useAuth'
61
- import { useDensity } from '@/hooks/useDensity'
62
- import { useElements } from '@/hooks/useElements'
63
- import { isLocalThreadId } from '@/hooks/useGramThreadListAdapter'
64
- import { useRadius } from '@/hooks/useRadius'
65
- import { useRecordCassette } from '@/hooks/useRecordCassette'
66
- import { useThemeProps } from '@/hooks/useThemeProps'
67
- import { useToolMentions } from '@/hooks/useToolMentions'
68
- import { getApiUrl } from '@/lib/api'
69
- import { EASE_OUT_QUINT } from '@/lib/easing'
70
- import { MODELS } from '@/lib/models'
71
- import { cn } from '@/lib/utils'
72
- import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'
48
+ } from "@/components/assistant-ui/attachment";
49
+ import { FollowOnSuggestions } from "@/components/assistant-ui/follow-on-suggestions";
50
+ import { MarkdownText } from "@/components/assistant-ui/markdown-text";
51
+ import { MentionedToolsBadges } from "@/components/assistant-ui/mentioned-tools-badges";
52
+ import { MessageFeedback } from "@/components/assistant-ui/message-feedback";
53
+ import { Reasoning, ReasoningGroup } from "@/components/assistant-ui/reasoning";
54
+ import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
55
+ import { ToolMentionAutocomplete } from "@/components/assistant-ui/tool-mention-autocomplete";
56
+ import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
57
+ import { Button } from "@/components/ui/button";
58
+ import { useChatId } from "@/contexts/ChatIdContext";
59
+ import { useReplayContext } from "@/contexts/ReplayContext";
60
+ import { useAuth } from "@/hooks/useAuth";
61
+ import { useDensity } from "@/hooks/useDensity";
62
+ import { useElements } from "@/hooks/useElements";
63
+ import { isLocalThreadId } from "@/hooks/useGramThreadListAdapter";
64
+ import { useRadius } from "@/hooks/useRadius";
65
+ import { useRecordCassette } from "@/hooks/useRecordCassette";
66
+ import { useThemeProps } from "@/hooks/useThemeProps";
67
+ import { useToolMentions } from "@/hooks/useToolMentions";
68
+ import { getApiUrl } from "@/lib/api";
69
+ import { EASE_OUT_QUINT } from "@/lib/easing";
70
+ import { MODELS } from "@/lib/models";
71
+ import { cn } from "@/lib/utils";
72
+ import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
73
73
  import {
74
74
  Tooltip,
75
75
  TooltipContent,
76
76
  TooltipProvider,
77
77
  TooltipTrigger,
78
- } from '../ui/tooltip'
79
- import { ConnectionStatusIndicatorSafe } from './connection-status-indicator'
80
- import { ToolGroup } from './tool-group'
78
+ } from "../ui/tooltip";
79
+ import { ConnectionStatusIndicatorSafe } from "./connection-status-indicator";
80
+ import { ToolGroup } from "./tool-group";
81
81
 
82
- type Feedback = 'success' | 'failure'
82
+ type Feedback = "success" | "failure";
83
83
 
84
84
  // Context for chat resolution state
85
85
  const ChatResolutionContext = createContext<{
86
- isResolved: boolean
87
- feedbackHidden: boolean
88
- setResolved: () => void
89
- setUnresolved: () => void
90
- resetFeedbackHidden: () => void
91
- submitFeedback: (feedback: Feedback) => Promise<void>
86
+ isResolved: boolean;
87
+ feedbackHidden: boolean;
88
+ setResolved: () => void;
89
+ setUnresolved: () => void;
90
+ resetFeedbackHidden: () => void;
91
+ submitFeedback: (feedback: Feedback) => Promise<void>;
92
92
  }>({
93
93
  isResolved: false,
94
94
  feedbackHidden: false,
@@ -96,9 +96,9 @@ const ChatResolutionContext = createContext<{
96
96
  setUnresolved: () => {},
97
97
  resetFeedbackHidden: () => {},
98
98
  submitFeedback: async () => {},
99
- })
99
+ });
100
100
 
101
- const useChatResolution = () => useContext(ChatResolutionContext)
101
+ const useChatResolution = () => useContext(ChatResolutionContext);
102
102
 
103
103
  const DangerousApiKeyWarning = () => (
104
104
  <div className="m-2 rounded-md border border-red-500 bg-red-100 px-4 py-3 text-sm text-red-800 dark:border-red-600 dark:bg-red-900/30 dark:text-red-200">
@@ -106,68 +106,68 @@ const DangerousApiKeyWarning = () => (
106
106
  browser. This exposes your key to anyone who inspects this page. Do NOT use
107
107
  this in production.
108
108
  </div>
109
- )
109
+ );
110
110
 
111
111
  interface ThreadProps {
112
- className?: string
112
+ className?: string;
113
113
  }
114
114
 
115
115
  export const Thread: FC<ThreadProps> = ({ className }) => {
116
- const themeProps = useThemeProps()
117
- const d = useDensity()
118
- const { config } = useElements()
119
- const components = config.components ?? {}
116
+ const themeProps = useThemeProps();
117
+ const d = useDensity();
118
+ const { config } = useElements();
119
+ const components = config.components ?? {};
120
120
  const showDangerousApiKeyWarning =
121
- config.api && 'dangerousApiKey' in config.api
122
- const showFeedback = config.thread?.showFeedback ?? false
123
- const [isResolved, setIsResolved] = useState(false)
124
- const [feedbackHidden, setFeedbackHidden] = useState(false)
125
- const chatId = useChatId()
121
+ config.api && "dangerousApiKey" in config.api;
122
+ const showFeedback = config.thread?.showFeedback ?? true;
123
+ const [isResolved, setIsResolved] = useState(false);
124
+ const [feedbackHidden, setFeedbackHidden] = useState(false);
125
+ const chatId = useChatId();
126
126
 
127
- const apiUrl = getApiUrl(config)
127
+ const apiUrl = getApiUrl(config);
128
128
  const auth = useAuth({
129
129
  auth: config.api,
130
130
  projectSlug: config.projectSlug,
131
- })
131
+ });
132
132
 
133
- const setResolved = () => setIsResolved(true)
133
+ const setResolved = () => setIsResolved(true);
134
134
  const setUnresolved = () => {
135
- setIsResolved(false)
136
- setFeedbackHidden(true)
137
- }
138
- const resetFeedbackHidden = () => setFeedbackHidden(false)
135
+ setIsResolved(false);
136
+ setFeedbackHidden(true);
137
+ };
138
+ const resetFeedbackHidden = () => setFeedbackHidden(false);
139
139
 
140
140
  // Submit feedback to the API
141
141
  const submitFeedback = useCallback(
142
142
  async (feedback: Feedback) => {
143
- if (!chatId) return
143
+ if (!chatId) return;
144
144
  if (isLocalThreadId(chatId)) {
145
- console.error("Local thread ID, can't submit feedback")
146
- return
145
+ console.error("Local thread ID, can't submit feedback");
146
+ return;
147
147
  }
148
148
 
149
149
  try {
150
150
  const response = await fetch(`${apiUrl}/rpc/chat.submitFeedback`, {
151
- method: 'POST',
151
+ method: "POST",
152
152
  headers: {
153
- 'Content-Type': 'application/json',
153
+ "Content-Type": "application/json",
154
154
  ...auth.headers,
155
155
  },
156
156
  body: JSON.stringify({
157
157
  id: chatId,
158
158
  feedback,
159
159
  }),
160
- })
160
+ });
161
161
 
162
162
  if (!response.ok) {
163
- console.error('Failed to submit feedback:', response.statusText)
163
+ console.error("Failed to submit feedback:", response.statusText);
164
164
  }
165
165
  } catch (error) {
166
- console.error('Failed to submit feedback:', error)
166
+ console.error("Failed to submit feedback:", error);
167
167
  }
168
168
  },
169
- [chatId, apiUrl, auth.headers]
170
- )
169
+ [chatId, apiUrl, auth.headers],
170
+ );
171
171
 
172
172
  return (
173
173
  <ChatResolutionContext.Provider
@@ -184,16 +184,16 @@ export const Thread: FC<ThreadProps> = ({ className }) => {
184
184
  <MotionConfig reducedMotion="user">
185
185
  <ThreadPrimitive.Root
186
186
  className={cn(
187
- 'aui-root aui-thread-root bg-background @container relative flex h-full flex-col',
187
+ "aui-root aui-thread-root @container relative flex h-full flex-col bg-background",
188
188
  themeProps.className,
189
- className
189
+ className,
190
190
  )}
191
191
  >
192
192
  <ConnectionStatusIndicatorSafe />
193
193
  <ThreadPrimitive.Viewport
194
194
  className={cn(
195
- 'aui-thread-viewport relative mx-auto flex w-full flex-1 flex-col overflow-x-auto overflow-y-scroll pb-0!',
196
- d('p-lg')
195
+ "aui-thread-viewport relative mx-auto flex w-full flex-1 flex-col overflow-x-auto overflow-y-scroll pb-0!",
196
+ d("p-lg"),
197
197
  )}
198
198
  >
199
199
  <ThreadPrimitive.If empty>
@@ -230,7 +230,7 @@ export const Thread: FC<ThreadProps> = ({ className }) => {
230
230
  <AnimatePresence>
231
231
  {showFeedback && isResolved && (
232
232
  <m.div
233
- className="bg-background/40 pointer-events-none absolute inset-0 z-50"
233
+ className="pointer-events-none absolute inset-0 z-50 bg-background/40"
234
234
  initial={{ opacity: 0 }}
235
235
  animate={{ opacity: 1 }}
236
236
  exit={{ opacity: 0 }}
@@ -242,8 +242,8 @@ export const Thread: FC<ThreadProps> = ({ className }) => {
242
242
  </MotionConfig>
243
243
  </LazyMotion>
244
244
  </ChatResolutionContext.Provider>
245
- )
246
- }
245
+ );
246
+ };
247
247
 
248
248
  const ThreadScrollToBottom: FC = () => {
249
249
  return (
@@ -251,41 +251,41 @@ const ThreadScrollToBottom: FC = () => {
251
251
  <TooltipIconButton
252
252
  tooltip="Scroll to bottom"
253
253
  variant="outline"
254
- className="aui-thread-scroll-to-bottom dark:bg-background dark:text-foreground dark:hover:bg-accent absolute -top-12 z-10 self-center rounded-full p-4 disabled:invisible"
254
+ className="aui-thread-scroll-to-bottom absolute -top-12 z-10 self-center rounded-full p-4 disabled:invisible dark:bg-background dark:text-foreground dark:hover:bg-accent"
255
255
  >
256
256
  <ArrowDownIcon />
257
257
  </TooltipIconButton>
258
258
  </ThreadPrimitive.ScrollToBottom>
259
- )
260
- }
259
+ );
260
+ };
261
261
 
262
262
  const ThreadWelcome: FC = () => {
263
- const { config } = useElements()
264
- const d = useDensity()
265
- const { title, subtitle } = config.welcome ?? {}
266
- const isStandalone = config.variant === 'standalone'
263
+ const { config } = useElements();
264
+ const d = useDensity();
265
+ const { title, subtitle } = config.welcome ?? {};
266
+ const isStandalone = config.variant === "standalone";
267
267
 
268
268
  return (
269
269
  <div
270
270
  className={cn(
271
- 'aui-thread-welcome-root my-auto flex w-full grow flex-col',
272
- isStandalone ? 'items-center justify-center' : '',
273
- d('gap-lg')
271
+ "aui-thread-welcome-root my-auto flex w-full grow flex-col",
272
+ isStandalone ? "items-center justify-center" : "",
273
+ d("gap-lg"),
274
274
  )}
275
275
  >
276
276
  <div
277
277
  className={cn(
278
- 'aui-thread-welcome-center flex w-full grow flex-col items-center justify-start'
278
+ "aui-thread-welcome-center flex w-full grow flex-col items-center justify-start",
279
279
  )}
280
280
  >
281
281
  <div
282
282
  className={cn(
283
- 'aui-thread-welcome-message flex flex-col',
283
+ "aui-thread-welcome-message flex flex-col",
284
284
  isStandalone
285
- ? 'items-center text-center'
286
- : 'size-full justify-start',
287
- d('gap-sm'),
288
- !isStandalone && d('py-md')
285
+ ? "items-center text-center"
286
+ : "size-full justify-start",
287
+ d("gap-sm"),
288
+ !isStandalone && d("py-md"),
289
289
  )}
290
290
  >
291
291
  <m.div
@@ -294,8 +294,8 @@ const ThreadWelcome: FC = () => {
294
294
  exit={{ opacity: 0, y: 10 }}
295
295
  transition={{ duration: 0.25, ease: EASE_OUT_QUINT }}
296
296
  className={cn(
297
- 'aui-thread-welcome-message-motion-1 text-foreground font-semibold',
298
- d('text-title')
297
+ "aui-thread-welcome-message-motion-1 font-semibold text-foreground",
298
+ d("text-title"),
299
299
  )}
300
300
  >
301
301
  {title}
@@ -306,8 +306,8 @@ const ThreadWelcome: FC = () => {
306
306
  exit={{ opacity: 0, y: 10 }}
307
307
  transition={{ duration: 0.25, delay: 0.05, ease: EASE_OUT_QUINT }}
308
308
  className={cn(
309
- 'aui-thread-welcome-message-motion-2 text-muted-foreground/65',
310
- d('text-subtitle')
309
+ "aui-thread-welcome-message-motion-2 text-muted-foreground/65",
310
+ d("text-subtitle"),
311
311
  )}
312
312
  >
313
313
  {subtitle}
@@ -316,29 +316,29 @@ const ThreadWelcome: FC = () => {
316
316
  </div>
317
317
  <ThreadSuggestions />
318
318
  </div>
319
- )
320
- }
319
+ );
320
+ };
321
321
 
322
322
  const ThreadSuggestions: FC = () => {
323
- const { config } = useElements()
324
- const r = useRadius()
325
- const d = useDensity()
326
- const suggestions = config.welcome?.suggestions ?? []
327
- const isStandalone = config.variant === 'standalone'
323
+ const { config } = useElements();
324
+ const r = useRadius();
325
+ const d = useDensity();
326
+ const suggestions = config.welcome?.suggestions ?? [];
327
+ const isStandalone = config.variant === "standalone";
328
328
 
329
- if (suggestions.length === 0) return null
329
+ if (suggestions.length === 0) return null;
330
330
 
331
331
  return (
332
332
  <div
333
333
  className={cn(
334
- 'aui-thread-welcome-suggestions w-full',
335
- d('gap-md'),
336
- d('py-lg'),
334
+ "aui-thread-welcome-suggestions w-full",
335
+ d("gap-md"),
336
+ d("py-lg"),
337
337
  isStandalone
338
- ? 'flex flex-col @sm:flex-row @sm:flex-wrap @sm:items-center @sm:justify-center'
338
+ ? "flex flex-col @sm:flex-row @sm:flex-wrap @sm:items-center @sm:justify-center"
339
339
  : suggestions.length === 1
340
- ? 'flex'
341
- : 'grid max-w-fit @md:grid-cols-2'
340
+ ? "flex"
341
+ : "grid max-w-fit @md:grid-cols-2",
342
342
  )}
343
343
  >
344
344
  {suggestions.map((suggestion, index) => (
@@ -353,26 +353,26 @@ const ThreadSuggestions: FC = () => {
353
353
  }}
354
354
  key={`suggested-action-${suggestion.title}-${index}`}
355
355
  className={cn(
356
- 'aui-thread-welcome-suggestion-display',
357
- !isStandalone && 'nth-[n+3]:hidden @md:nth-[n+3]:block'
356
+ "aui-thread-welcome-suggestion-display",
357
+ !isStandalone && "nth-[n+3]:hidden @md:nth-[n+3]:block",
358
358
  )}
359
359
  >
360
360
  <ThreadPrimitive.Suggestion prompt={suggestion.prompt} send asChild>
361
361
  <Button
362
362
  variant="ghost"
363
363
  className={cn(
364
- 'aui-thread-welcome-suggestion dark:hover:bg-accent/60 h-auto w-full border text-left whitespace-break-spaces',
365
- d('text-base'),
364
+ "aui-thread-welcome-suggestion h-auto w-full border text-left whitespace-break-spaces dark:hover:bg-accent/60",
365
+ d("text-base"),
366
366
  isStandalone
367
- ? `flex-col items-start @sm:flex-row @sm:items-center ${d('gap-sm')} ${d('px-lg')} ${d('py-sm')} ${r('full')}`
368
- : `w-full flex-1 flex-col flex-wrap items-start justify-start ${d('gap-sm')} ${d('px-lg')} ${d('py-md')} ${r('xl')}`
367
+ ? `flex-col items-start @sm:flex-row @sm:items-center ${d("gap-sm")} ${d("px-lg")} ${d("py-sm")} ${r("full")}`
368
+ : `w-full flex-1 flex-col flex-wrap items-start justify-start ${d("gap-sm")} ${d("px-lg")} ${d("py-md")} ${r("xl")}`,
369
369
  )}
370
370
  aria-label={suggestion.prompt}
371
371
  >
372
- <span className="aui-thread-welcome-suggestion-text-1 text-foreground text-sm font-medium">
372
+ <span className="aui-thread-welcome-suggestion-text-1 text-sm font-medium text-foreground">
373
373
  {suggestion.title}
374
374
  </span>
375
- <span className="aui-thread-welcome-suggestion-text-2 text-muted-foreground text-sm">
375
+ <span className="aui-thread-welcome-suggestion-text-2 text-sm text-muted-foreground">
376
376
  {suggestion.label}
377
377
  </span>
378
378
  </Button>
@@ -380,17 +380,17 @@ const ThreadSuggestions: FC = () => {
380
380
  </m.div>
381
381
  ))}
382
382
  </div>
383
- )
384
- }
383
+ );
384
+ };
385
385
 
386
386
  /**
387
387
  * Component that handles tool mentions (@tool) in the composer.
388
388
  * Shows autocomplete dropdown and badges for mentioned tools.
389
389
  */
390
390
  const ComposerToolMentions: FC<{
391
- tools: Record<string, unknown> | undefined
391
+ tools: Record<string, unknown> | undefined;
392
392
  }> = ({ tools }) => {
393
- const containerRef = useRef<HTMLDivElement>(null)
393
+ const containerRef = useRef<HTMLDivElement>(null);
394
394
 
395
395
  const {
396
396
  mentionableTools,
@@ -402,61 +402,61 @@ const ComposerToolMentions: FC<{
402
402
  handleAutocompleteChange,
403
403
  removeMention,
404
404
  isActive,
405
- } = useToolMentions({ tools })
405
+ } = useToolMentions({ tools });
406
406
 
407
407
  // Find and attach to the textarea within the composer.
408
408
  // Uses getRootNode() so it works inside Shadow DOM (where document.querySelector can't reach).
409
409
  useEffect(() => {
410
- if (!isActive) return
410
+ if (!isActive) return;
411
411
 
412
412
  const rootNode = containerRef.current?.getRootNode() as
413
413
  | Document
414
414
  | ShadowRoot
415
- | undefined
416
- if (!rootNode) return
415
+ | undefined;
416
+ if (!rootNode) return;
417
417
 
418
418
  const observeTarget =
419
- rootNode instanceof ShadowRoot ? rootNode : document.body
419
+ rootNode instanceof ShadowRoot ? rootNode : document.body;
420
420
 
421
421
  const findTextarea = () => {
422
422
  const textarea = rootNode.querySelector(
423
- '.aui-composer-input'
424
- ) as HTMLTextAreaElement | null
423
+ ".aui-composer-input",
424
+ ) as HTMLTextAreaElement | null;
425
425
  if (textarea && textareaRef.current !== textarea) {
426
- textareaRef.current = textarea
426
+ textareaRef.current = textarea;
427
427
 
428
- const handleSelectionChange = () => updateCursorPosition()
429
- textarea.addEventListener('click', handleSelectionChange)
430
- textarea.addEventListener('keyup', handleSelectionChange)
431
- textarea.addEventListener('input', handleSelectionChange)
428
+ const handleSelectionChange = () => updateCursorPosition();
429
+ textarea.addEventListener("click", handleSelectionChange);
430
+ textarea.addEventListener("keyup", handleSelectionChange);
431
+ textarea.addEventListener("input", handleSelectionChange);
432
432
 
433
433
  return () => {
434
- textarea.removeEventListener('click', handleSelectionChange)
435
- textarea.removeEventListener('keyup', handleSelectionChange)
436
- textarea.removeEventListener('input', handleSelectionChange)
437
- }
434
+ textarea.removeEventListener("click", handleSelectionChange);
435
+ textarea.removeEventListener("keyup", handleSelectionChange);
436
+ textarea.removeEventListener("input", handleSelectionChange);
437
+ };
438
438
  }
439
- }
439
+ };
440
440
 
441
- const cleanup = findTextarea()
441
+ const cleanup = findTextarea();
442
442
 
443
443
  const observer = new MutationObserver(() => {
444
- findTextarea()
445
- })
444
+ findTextarea();
445
+ });
446
446
 
447
447
  observer.observe(observeTarget, {
448
448
  childList: true,
449
449
  subtree: true,
450
- })
450
+ });
451
451
 
452
452
  return () => {
453
- cleanup?.()
454
- observer.disconnect()
455
- }
456
- }, [isActive, textareaRef, updateCursorPosition])
453
+ cleanup?.();
454
+ observer.disconnect();
455
+ };
456
+ }, [isActive, textareaRef, updateCursorPosition]);
457
457
 
458
458
  if (!isActive) {
459
- return null
459
+ return null;
460
460
  }
461
461
 
462
462
  return (
@@ -479,31 +479,31 @@ const ComposerToolMentions: FC<{
479
479
  />
480
480
  </AnimatePresence>
481
481
  </div>
482
- )
483
- }
482
+ );
483
+ };
484
484
 
485
485
  // Resets feedbackHidden when a new message starts generating
486
486
  const FeedbackHiddenResetter: FC = () => {
487
- const { resetFeedbackHidden } = useChatResolution()
487
+ const { resetFeedbackHidden } = useChatResolution();
488
488
 
489
489
  useEffect(() => {
490
- resetFeedbackHidden()
491
- }, [resetFeedbackHidden])
490
+ resetFeedbackHidden();
491
+ }, [resetFeedbackHidden]);
492
492
 
493
- return null
494
- }
493
+ return null;
494
+ };
495
495
 
496
496
  const ComposerFeedback: FC = () => {
497
497
  const { isResolved, feedbackHidden, setResolved, submitFeedback } =
498
- useChatResolution()
498
+ useChatResolution();
499
499
 
500
500
  const handleFeedback = useCallback(
501
- async (type: 'like' | 'dislike') => {
502
- const feedback = type === 'like' ? 'success' : 'failure'
503
- await submitFeedback(feedback)
501
+ async (type: "like" | "dislike") => {
502
+ const feedback = type === "like" ? "success" : "failure";
503
+ await submitFeedback(feedback);
504
504
  },
505
- [submitFeedback]
506
- )
505
+ [submitFeedback],
506
+ );
507
507
 
508
508
  return (
509
509
  <ThreadPrimitive.If empty={false}>
@@ -531,59 +531,59 @@ const ComposerFeedback: FC = () => {
531
531
  </AnimatePresence>
532
532
  </ThreadPrimitive.If>
533
533
  </ThreadPrimitive.If>
534
- )
535
- }
534
+ );
535
+ };
536
536
 
537
537
  interface ComposerProps {
538
- showFeedback?: boolean
538
+ showFeedback?: boolean;
539
539
  }
540
540
 
541
541
  const Composer: FC<ComposerProps> = ({ showFeedback = false }) => {
542
- const { config, mcpTools } = useElements()
543
- const { isResolved, setUnresolved } = useChatResolution()
544
- const r = useRadius()
545
- const d = useDensity()
546
- const replayCtx = useReplayContext()
542
+ const { config, mcpTools } = useElements();
543
+ const { isResolved, setUnresolved } = useChatResolution();
544
+ const r = useRadius();
545
+ const d = useDensity();
546
+ const replayCtx = useReplayContext();
547
547
 
548
- const isReplay = replayCtx?.isReplay ?? false
548
+ const isReplay = replayCtx?.isReplay ?? false;
549
549
  const composerConfig = config.composer ?? {
550
- placeholder: 'Send a message...',
550
+ placeholder: "Send a message...",
551
551
  attachments: true,
552
- }
553
- const components = config.components ?? {}
552
+ };
553
+ const components = config.components ?? {};
554
554
 
555
555
  // Determine if tool mentions are enabled (default: true)
556
556
  const toolMentionsEnabled =
557
557
  composerConfig.toolMentions === undefined ||
558
558
  composerConfig.toolMentions === true ||
559
- (typeof composerConfig.toolMentions === 'object' &&
560
- composerConfig.toolMentions.enabled !== false)
559
+ (typeof composerConfig.toolMentions === "object" &&
560
+ composerConfig.toolMentions.enabled !== false);
561
561
 
562
- const composerRootRef = useRef<HTMLFormElement>(null)
562
+ const composerRootRef = useRef<HTMLFormElement>(null);
563
563
 
564
564
  if (components.Composer) {
565
- return <components.Composer />
565
+ return <components.Composer />;
566
566
  }
567
567
 
568
568
  return (
569
569
  <div
570
570
  className={cn(
571
- 'aui-composer-wrapper bg-background sticky bottom-0 z-[60] flex w-full flex-col overflow-visible',
572
- d('gap-md'),
573
- d('py-md'),
574
- r('xl')
571
+ "aui-composer-wrapper sticky bottom-0 z-[60] flex w-full flex-col overflow-visible bg-background",
572
+ d("gap-md"),
573
+ d("py-md"),
574
+ r("xl"),
575
575
  )}
576
576
  >
577
577
  {showFeedback && <ComposerFeedback />}
578
578
  <ThreadScrollToBottom />
579
579
  {showFeedback && isResolved ? (
580
580
  <m.div
581
- className="aui-composer-resolved border-input flex min-h-[118px] flex-col items-center justify-center gap-2 border-t px-1"
581
+ className="aui-composer-resolved flex min-h-[118px] flex-col items-center justify-center gap-2 border-t border-input px-1"
582
582
  initial={{ opacity: 0 }}
583
583
  animate={{ opacity: 1 }}
584
584
  transition={{ duration: 0.2, ease: EASE_OUT_QUINT }}
585
585
  >
586
- <span className="text-muted-foreground text-sm">
586
+ <span className="text-sm text-muted-foreground">
587
587
  This conversation has been resolved
588
588
  </span>
589
589
  <Button
@@ -599,9 +599,9 @@ const Composer: FC<ComposerProps> = ({ showFeedback = false }) => {
599
599
  <ComposerPrimitive.Root
600
600
  ref={composerRootRef}
601
601
  className={cn(
602
- 'aui-composer-root group/input-group border-input bg-background has-[textarea:focus-visible]:border-ring has-[textarea:focus-visible]:ring-ring/5 dark:bg-background relative flex min-h-[118px] w-full flex-col border px-1 pt-2 shadow-xs transition-[color,box-shadow] outline-none has-[textarea:focus-visible]:ring-1',
603
- r('xl'),
604
- isReplay && 'pointer-events-none opacity-50'
602
+ "aui-composer-root group/input-group relative flex min-h-[118px] w-full flex-col border border-input bg-background px-1 pt-2 shadow-xs transition-[color,box-shadow] outline-none has-[textarea:focus-visible]:border-ring has-[textarea:focus-visible]:ring-1 has-[textarea:focus-visible]:ring-ring/5 dark:bg-background",
603
+ r("xl"),
604
+ isReplay && "pointer-events-none opacity-50",
605
605
  )}
606
606
  >
607
607
  {composerConfig.attachments && <ComposerAttachments />}
@@ -611,9 +611,9 @@ const Composer: FC<ComposerProps> = ({ showFeedback = false }) => {
611
611
  <ComposerPrimitive.Input
612
612
  placeholder={composerConfig.placeholder}
613
613
  className={cn(
614
- 'aui-composer-input text-foreground placeholder:text-muted-foreground mb-1 max-h-32 w-full resize-none bg-transparent px-3.5 pt-1.5 pb-3 outline-none focus-visible:ring-0',
615
- d('h-input'),
616
- d('text-base')
614
+ "aui-composer-input mb-1 max-h-32 w-full resize-none bg-transparent px-3.5 pt-1.5 pb-3 text-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-0",
615
+ d("h-input"),
616
+ d("text-base"),
617
617
  )}
618
618
  rows={1}
619
619
  autoFocus={!isReplay}
@@ -624,41 +624,41 @@ const Composer: FC<ComposerProps> = ({ showFeedback = false }) => {
624
624
  </ComposerPrimitive.Root>
625
625
  )}
626
626
  </div>
627
- )
628
- }
627
+ );
628
+ };
629
629
 
630
630
  const ComposerModelPicker: FC = () => {
631
- const { model, setModel } = useElements()
632
- const [popoverOpen, setPopoverOpen] = useState(false)
633
- const [tooltipOpen, setTooltipOpen] = useState(false)
634
- const scrollContainerRef = useRef<HTMLDivElement>(null)
635
- const savedScrollPosition = useRef(0)
636
- const previousOpenRef = useRef(false)
631
+ const { model, setModel } = useElements();
632
+ const [popoverOpen, setPopoverOpen] = useState(false);
633
+ const [tooltipOpen, setTooltipOpen] = useState(false);
634
+ const scrollContainerRef = useRef<HTMLDivElement>(null);
635
+ const savedScrollPosition = useRef(0);
636
+ const previousOpenRef = useRef(false);
637
637
 
638
638
  useEffect(() => {
639
639
  // Restore scroll position when opening
640
640
  if (popoverOpen && !previousOpenRef.current) {
641
641
  requestAnimationFrame(() => {
642
- const container = scrollContainerRef.current
642
+ const container = scrollContainerRef.current;
643
643
  if (container && container.scrollHeight > 0) {
644
- container.scrollTop = savedScrollPosition.current
644
+ container.scrollTop = savedScrollPosition.current;
645
645
  }
646
- })
646
+ });
647
647
  }
648
648
 
649
- previousOpenRef.current = popoverOpen
650
- }, [popoverOpen])
649
+ previousOpenRef.current = popoverOpen;
650
+ }, [popoverOpen]);
651
651
 
652
652
  // Close tooltip when popover opens
653
653
  useEffect(() => {
654
654
  if (popoverOpen) {
655
- setTooltipOpen(false)
655
+ setTooltipOpen(false);
656
656
  }
657
- }, [popoverOpen])
657
+ }, [popoverOpen]);
658
658
 
659
659
  const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
660
- savedScrollPosition.current = e.currentTarget.scrollTop
661
- }
660
+ savedScrollPosition.current = e.currentTarget.scrollTop;
661
+ };
662
662
 
663
663
  return (
664
664
  <TooltipProvider>
@@ -669,8 +669,8 @@ const ComposerModelPicker: FC = () => {
669
669
  <Button
670
670
  variant="ghost"
671
671
  size="icon"
672
- data-state={popoverOpen ? 'open' : 'closed'}
673
- className="aui-composer-model-picker data-[state=open]:bg-muted-foreground/15 dark:border-muted-foreground/15 dark:hover:bg-muted-foreground/30 flex w-fit items-center gap-2 rounded-full px-2.5 py-1 text-xs font-semibold"
672
+ data-state={popoverOpen ? "open" : "closed"}
673
+ className="aui-composer-model-picker flex w-fit items-center gap-2 rounded-full px-2.5 py-1 text-xs font-semibold data-[state=open]:bg-muted-foreground/15 dark:border-muted-foreground/15 dark:hover:bg-muted-foreground/30"
674
674
  aria-label="Model Settings"
675
675
  >
676
676
  <Settings2 className="aui-attachment-add-icon size-5 stroke-[1.5px]" />
@@ -691,7 +691,7 @@ const ComposerModelPicker: FC = () => {
691
691
  <Button
692
692
  key={m}
693
693
  onClick={() => {
694
- setModel(m)
694
+ setModel(m);
695
695
  }}
696
696
  variant="ghost"
697
697
  className="w-full justify-start gap-2 rounded-none px-2"
@@ -714,21 +714,21 @@ const ComposerModelPicker: FC = () => {
714
714
  </TooltipContent>
715
715
  </Tooltip>
716
716
  </TooltipProvider>
717
- )
718
- }
717
+ );
718
+ };
719
719
 
720
720
  const CASSETTE_RECORDING_ENABLED =
721
- import.meta.env.VITE_ELEMENTS_ENABLE_CASSETTE_RECORDING === 'true'
721
+ import.meta.env.VITE_ELEMENTS_ENABLE_CASSETTE_RECORDING === "true";
722
722
 
723
723
  const ComposerCassetteRecorder: FC = () => {
724
- const [popoverOpen, setPopoverOpen] = useState(false)
725
- const [tooltipOpen, setTooltipOpen] = useState(false)
724
+ const [popoverOpen, setPopoverOpen] = useState(false);
725
+ const [tooltipOpen, setTooltipOpen] = useState(false);
726
726
  const { isRecording, startRecording, stopRecording, download } =
727
- useRecordCassette()
727
+ useRecordCassette();
728
728
 
729
729
  useEffect(() => {
730
- if (popoverOpen) setTooltipOpen(false)
731
- }, [popoverOpen])
730
+ if (popoverOpen) setTooltipOpen(false);
731
+ }, [popoverOpen]);
732
732
 
733
733
  return (
734
734
  <TooltipProvider>
@@ -739,17 +739,17 @@ const ComposerCassetteRecorder: FC = () => {
739
739
  <Button
740
740
  variant="ghost"
741
741
  size="icon"
742
- data-state={popoverOpen ? 'open' : 'closed'}
742
+ data-state={popoverOpen ? "open" : "closed"}
743
743
  className={cn(
744
- 'aui-composer-cassette-recorder data-[state=open]:bg-muted-foreground/15 dark:border-muted-foreground/15 dark:hover:bg-muted-foreground/30 flex w-fit items-center gap-2 rounded-full px-2.5 py-1 text-xs font-semibold',
745
- isRecording && 'text-red-500'
744
+ "aui-composer-cassette-recorder flex w-fit items-center gap-2 rounded-full px-2.5 py-1 text-xs font-semibold data-[state=open]:bg-muted-foreground/15 dark:border-muted-foreground/15 dark:hover:bg-muted-foreground/30",
745
+ isRecording && "text-red-500",
746
746
  )}
747
747
  aria-label="Cassette Recorder"
748
748
  >
749
749
  <CircleIcon
750
750
  className={cn(
751
- 'size-5 stroke-[1.5px]',
752
- isRecording && 'animate-pulse fill-red-500 text-red-500'
751
+ "size-5 stroke-[1.5px]",
752
+ isRecording && "animate-pulse fill-red-500 text-red-500",
753
753
  )}
754
754
  />
755
755
  </Button>
@@ -774,9 +774,9 @@ const ComposerCassetteRecorder: FC = () => {
774
774
  variant="outline"
775
775
  className="w-full justify-start gap-2"
776
776
  onClick={() => {
777
- stopRecording()
778
- download()
779
- setPopoverOpen(false)
777
+ stopRecording();
778
+ download();
779
+ setPopoverOpen(false);
780
780
  }}
781
781
  >
782
782
  <DownloadIcon className="size-3" />
@@ -787,20 +787,20 @@ const ComposerCassetteRecorder: FC = () => {
787
787
  </PopoverContent>
788
788
  </Popover>
789
789
  <TooltipContent side="bottom" align="start">
790
- {isRecording ? 'Recording…' : 'Cassette Recorder'}
790
+ {isRecording ? "Recording…" : "Cassette Recorder"}
791
791
  </TooltipContent>
792
792
  </Tooltip>
793
793
  </TooltipProvider>
794
- )
795
- }
794
+ );
795
+ };
796
796
 
797
797
  const ComposerAction: FC = () => {
798
- const { config } = useElements()
799
- const r = useRadius()
800
- const composerConfig = config.composer ?? { attachments: true }
798
+ const { config } = useElements();
799
+ const r = useRadius();
800
+ const composerConfig = config.composer ?? { attachments: true };
801
801
  return (
802
802
  <div className="aui-composer-action-wrapper relative mx-1 mt-2 mb-2 flex items-center justify-between">
803
- <div className="aui-composer-action-wrapper-inner text-muted-foreground flex items-center">
803
+ <div className="aui-composer-action-wrapper-inner flex items-center text-muted-foreground">
804
804
  {composerConfig.attachments ? (
805
805
  <ComposerAddAttachment />
806
806
  ) : (
@@ -822,7 +822,7 @@ const ComposerAction: FC = () => {
822
822
  type="submit"
823
823
  variant="default"
824
824
  size="icon"
825
- className={cn('aui-composer-send size-[34px] p-1', r('full'))}
825
+ className={cn("aui-composer-send size-[34px] p-1", r("full"))}
826
826
  aria-label="Send message"
827
827
  >
828
828
  <ArrowUpIcon className="aui-composer-send-icon size-5" />
@@ -837,8 +837,8 @@ const ComposerAction: FC = () => {
837
837
  variant="default"
838
838
  size="icon"
839
839
  className={cn(
840
- 'aui-composer-cancel border-muted-foreground/60 hover:bg-primary/75 dark:border-muted-foreground/90 size-[34px] border',
841
- r('full')
840
+ "aui-composer-cancel size-[34px] border border-muted-foreground/60 hover:bg-primary/75 dark:border-muted-foreground/90",
841
+ r("full"),
842
842
  )}
843
843
  aria-label="Stop generating"
844
844
  >
@@ -847,18 +847,18 @@ const ComposerAction: FC = () => {
847
847
  </ComposerPrimitive.Cancel>
848
848
  </ThreadPrimitive.If>
849
849
  </div>
850
- )
851
- }
850
+ );
851
+ };
852
852
 
853
853
  const MessageError: FC = () => {
854
854
  return (
855
855
  <MessagePrimitive.Error>
856
- <ErrorPrimitive.Root className="aui-message-error-root border-destructive bg-destructive/10 text-destructive dark:bg-destructive/5 mt-2 rounded-md border p-3 text-sm dark:text-red-200">
856
+ <ErrorPrimitive.Root className="aui-message-error-root mt-2 rounded-md border border-destructive bg-destructive/10 p-3 text-sm text-destructive dark:bg-destructive/5 dark:text-red-200">
857
857
  <ErrorPrimitive.Message className="aui-message-error-message line-clamp-2" />
858
858
  </ErrorPrimitive.Root>
859
859
  </MessagePrimitive.Error>
860
- )
861
- }
860
+ );
861
+ };
862
862
 
863
863
  /**
864
864
  * Shows the pulsing dot indicator when the message is still running but the
@@ -867,18 +867,18 @@ const MessageError: FC = () => {
867
867
  */
868
868
  const ToolCallStreamingIndicator: FC = () => {
869
869
  const show = useAssistantState(({ message }) => {
870
- if (message.status?.type !== 'running') return false
871
- const lastPart = message.parts[message.parts.length - 1]
872
- return lastPart?.type === 'tool-call'
873
- })
874
- if (!show) return null
875
- return <div className="aui-md mt-2" data-status="running" />
876
- }
870
+ if (message.status?.type !== "running") return false;
871
+ const lastPart = message.parts[message.parts.length - 1];
872
+ return lastPart?.type === "tool-call";
873
+ });
874
+ if (!show) return null;
875
+ return <div className="aui-md mt-2" data-status="running" />;
876
+ };
877
877
 
878
878
  const AssistantMessage: FC = () => {
879
- const { config } = useElements()
880
- const toolsConfig = config.tools ?? {}
881
- const components = config.components ?? {}
879
+ const { config } = useElements();
880
+ const toolsConfig = config.tools ?? {};
881
+ const components = config.components ?? {};
882
882
 
883
883
  const partsComponents = useMemo(
884
884
  () => ({
@@ -892,16 +892,16 @@ const AssistantMessage: FC = () => {
892
892
  ReasoningGroup: components.ReasoningGroup ?? ReasoningGroup,
893
893
  ToolGroup: components.ToolGroup ?? ToolGroup,
894
894
  }),
895
- [components, toolsConfig.components]
896
- )
895
+ [components, toolsConfig.components],
896
+ );
897
897
 
898
898
  return (
899
899
  <MessagePrimitive.Root asChild>
900
900
  <div
901
- className="aui-assistant-message-root animate-in fade-in slide-in-from-bottom-1 relative mx-auto w-full py-4 duration-150 ease-out last:mb-24"
901
+ className="aui-assistant-message-root relative mx-auto w-full animate-in py-4 duration-150 ease-out fade-in slide-in-from-bottom-1 last:mb-24"
902
902
  data-role="assistant"
903
903
  >
904
- <div className="aui-assistant-message-content text-foreground mx-2 leading-7 wrap-break-word">
904
+ <div className="aui-assistant-message-content mx-2 leading-7 wrap-break-word text-foreground">
905
905
  <MessagePrimitive.Parts components={partsComponents} />
906
906
  <ToolCallStreamingIndicator />
907
907
  <MessageError />
@@ -913,12 +913,12 @@ const AssistantMessage: FC = () => {
913
913
  </div>
914
914
  </div>
915
915
  </MessagePrimitive.Root>
916
- )
917
- }
916
+ );
917
+ };
918
918
 
919
919
  const Image: FC<ImageMessagePartProps> = (props) => {
920
- return <img src={props.image} />
921
- }
920
+ return <img src={props.image} />;
921
+ };
922
922
 
923
923
  const AssistantActionBar: FC = () => {
924
924
  return (
@@ -926,7 +926,7 @@ const AssistantActionBar: FC = () => {
926
926
  hideWhenRunning
927
927
  autohide="not-last"
928
928
  autohideFloat="single-branch"
929
- className="aui-assistant-action-bar-root text-muted-foreground data-floating:bg-background col-start-3 row-start-2 -ml-1 flex gap-1 data-floating:absolute data-floating:rounded-md data-floating:border data-floating:p-1 data-floating:shadow-sm"
929
+ className="aui-assistant-action-bar-root col-start-3 row-start-2 -ml-1 flex gap-1 text-muted-foreground data-floating:absolute data-floating:rounded-md data-floating:border data-floating:bg-background data-floating:p-1 data-floating:shadow-sm"
930
930
  >
931
931
  <ActionBarPrimitive.Copy asChild>
932
932
  <TooltipIconButton tooltip="Copy">
@@ -944,15 +944,15 @@ const AssistantActionBar: FC = () => {
944
944
  </TooltipIconButton>
945
945
  </ActionBarPrimitive.Reload> */}
946
946
  </ActionBarPrimitive.Root>
947
- )
948
- }
947
+ );
948
+ };
949
949
 
950
950
  const UserMessage: FC = () => {
951
- const r = useRadius()
951
+ const r = useRadius();
952
952
  return (
953
953
  <MessagePrimitive.Root asChild>
954
954
  <div
955
- className="aui-user-message-root animate-in fade-in slide-in-from-bottom-1 mx-auto grid w-full auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] gap-y-2 px-2 py-4 duration-150 ease-out first:mt-3 last:mb-5 [&:where(>*)]:col-start-2"
955
+ className="aui-user-message-root mx-auto grid w-full animate-in auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] gap-y-2 px-2 py-4 duration-150 ease-out fade-in slide-in-from-bottom-1 first:mt-3 last:mb-5 [&:where(>*)]:col-start-2"
956
956
  data-role="user"
957
957
  >
958
958
  <UserMessageAttachments />
@@ -960,8 +960,8 @@ const UserMessage: FC = () => {
960
960
  <div className="aui-user-message-content-wrapper relative col-start-2 min-w-0">
961
961
  <div
962
962
  className={cn(
963
- 'aui-user-message-content bg-muted text-foreground px-5 py-2.5 wrap-break-word',
964
- r('xl')
963
+ "aui-user-message-content bg-muted px-5 py-2.5 wrap-break-word text-foreground",
964
+ r("xl"),
965
965
  )}
966
966
  >
967
967
  <MessagePrimitive.Parts />
@@ -974,8 +974,8 @@ const UserMessage: FC = () => {
974
974
  <BranchPicker className="aui-user-branch-picker col-span-full col-start-1 row-start-3 -mr-1 justify-end" />
975
975
  </div>
976
976
  </MessagePrimitive.Root>
977
- )
978
- }
977
+ );
978
+ };
979
979
 
980
980
  const UserActionBar: FC = () => {
981
981
  return (
@@ -990,15 +990,15 @@ const UserActionBar: FC = () => {
990
990
  </TooltipIconButton>
991
991
  </ActionBarPrimitive.Edit>
992
992
  </ActionBarPrimitive.Root>
993
- )
994
- }
993
+ );
994
+ };
995
995
 
996
996
  const EditComposer: FC = () => {
997
997
  return (
998
998
  <div className="aui-edit-composer-wrapper mx-auto flex w-full flex-col gap-4 px-2 first:mt-4">
999
- <ComposerPrimitive.Root className="aui-edit-composer-root bg-muted ml-auto flex w-full max-w-7/8 flex-col rounded-xl">
999
+ <ComposerPrimitive.Root className="aui-edit-composer-root ml-auto flex w-full max-w-7/8 flex-col rounded-xl bg-muted">
1000
1000
  <ComposerPrimitive.Input
1001
- className="aui-edit-composer-input text-foreground flex min-h-[60px] w-full resize-none bg-transparent p-4 outline-none"
1001
+ className="aui-edit-composer-input flex min-h-[60px] w-full resize-none bg-transparent p-4 text-foreground outline-none"
1002
1002
  autoFocus
1003
1003
  />
1004
1004
 
@@ -1016,8 +1016,8 @@ const EditComposer: FC = () => {
1016
1016
  </div>
1017
1017
  </ComposerPrimitive.Root>
1018
1018
  </div>
1019
- )
1020
- }
1019
+ );
1020
+ };
1021
1021
 
1022
1022
  const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
1023
1023
  className,
@@ -1027,8 +1027,8 @@ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
1027
1027
  <BranchPickerPrimitive.Root
1028
1028
  hideWhenSingleBranch
1029
1029
  className={cn(
1030
- 'aui-branch-picker-root text-muted-foreground mr-2 -ml-2 inline-flex items-center text-xs',
1031
- className
1030
+ "aui-branch-picker-root mr-2 -ml-2 inline-flex items-center text-xs text-muted-foreground",
1031
+ className,
1032
1032
  )}
1033
1033
  {...rest}
1034
1034
  >
@@ -1046,5 +1046,5 @@ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
1046
1046
  </TooltipIconButton>
1047
1047
  </BranchPickerPrimitive.Next>
1048
1048
  </BranchPickerPrimitive.Root>
1049
- )
1050
- }
1049
+ );
1050
+ };