@gram-ai/elements 1.27.4 → 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 (277) 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 +1 -1
  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.js +2 -2
  23. package/dist/hooks/useDensity.d.ts +73 -73
  24. package/dist/hooks/useMCPTools.d.ts +1 -1
  25. package/dist/hooks/useRadius.d.ts +1 -1
  26. package/dist/{index-BpJstUh1.cjs → index-C4bFBGfl.cjs} +4 -4
  27. package/dist/{index-BpJstUh1.cjs.map → index-C4bFBGfl.cjs.map} +1 -1
  28. package/dist/{index-CUitXazZ.js → index-D93pV0_o.js} +55 -55
  29. package/dist/{index-CUitXazZ.js.map → index-D93pV0_o.js.map} +1 -1
  30. package/dist/{index-D0bAYNQy.js → index-DuCQRbcQ.js} +279 -265
  31. package/dist/index-DuCQRbcQ.js.map +1 -0
  32. package/dist/{index-KSX4Qjip.cjs → index-y_PNN5vK.cjs} +10 -10
  33. package/dist/index-y_PNN5vK.cjs.map +1 -0
  34. package/dist/lib/cassette.d.ts +4 -4
  35. package/dist/lib/errorTracking.d.ts +1 -1
  36. package/dist/lib/messageConverter.d.ts +1 -1
  37. package/dist/lib/models.d.ts +1 -1
  38. package/dist/plugins/chart/ui/bar-chart.d.ts +1 -1
  39. package/dist/plugins/generative-ui/ui/accordion-wrapper.d.ts +2 -2
  40. package/dist/plugins/generative-ui/ui/accordion.d.ts +1 -1
  41. package/dist/plugins/generative-ui/ui/action-button.d.ts +2 -2
  42. package/dist/plugins/generative-ui/ui/alert-wrapper.d.ts +1 -1
  43. package/dist/plugins/generative-ui/ui/alert.d.ts +4 -4
  44. package/dist/plugins/generative-ui/ui/avatar.d.ts +5 -5
  45. package/dist/plugins/generative-ui/ui/badge.d.ts +2 -2
  46. package/dist/plugins/generative-ui/ui/button-wrapper.d.ts +2 -2
  47. package/dist/plugins/generative-ui/ui/button.d.ts +2 -2
  48. package/dist/plugins/generative-ui/ui/card-wrapper.d.ts +2 -2
  49. package/dist/plugins/generative-ui/ui/card.d.ts +8 -8
  50. package/dist/plugins/generative-ui/ui/checkbox.d.ts +1 -1
  51. package/dist/plugins/generative-ui/ui/data-table.d.ts +2 -2
  52. package/dist/plugins/generative-ui/ui/dialog.d.ts +3 -3
  53. package/dist/plugins/generative-ui/ui/dropdown-menu.d.ts +3 -3
  54. package/dist/plugins/generative-ui/ui/grid.d.ts +3 -3
  55. package/dist/plugins/generative-ui/ui/input-wrapper.d.ts +1 -1
  56. package/dist/plugins/generative-ui/ui/input.d.ts +2 -2
  57. package/dist/plugins/generative-ui/ui/label.d.ts +1 -1
  58. package/dist/plugins/generative-ui/ui/metric.d.ts +3 -3
  59. package/dist/plugins/generative-ui/ui/pagination.d.ts +6 -6
  60. package/dist/plugins/generative-ui/ui/popover.d.ts +4 -4
  61. package/dist/plugins/generative-ui/ui/progress.d.ts +2 -2
  62. package/dist/plugins/generative-ui/ui/radio-group.d.ts +1 -1
  63. package/dist/plugins/generative-ui/ui/select.d.ts +2 -2
  64. package/dist/plugins/generative-ui/ui/separator.d.ts +1 -1
  65. package/dist/plugins/generative-ui/ui/skeleton.d.ts +1 -1
  66. package/dist/plugins/generative-ui/ui/stack.d.ts +6 -6
  67. package/dist/plugins/generative-ui/ui/switch.d.ts +2 -2
  68. package/dist/plugins/generative-ui/ui/table.d.ts +9 -9
  69. package/dist/plugins/generative-ui/ui/tabs-wrapper.d.ts +1 -1
  70. package/dist/plugins/generative-ui/ui/tabs.d.ts +1 -1
  71. package/dist/plugins/generative-ui/ui/text.d.ts +3 -3
  72. package/dist/plugins/generative-ui/ui/textarea.d.ts +2 -2
  73. package/dist/plugins/generative-ui/ui/tooltip.d.ts +1 -1
  74. package/dist/plugins.cjs +1 -1
  75. package/dist/plugins.js +1 -1
  76. package/dist/{profiler-BFkhZRxj.js → profiler-FpBY9eRv.js} +2 -2
  77. package/dist/{profiler-BFkhZRxj.js.map → profiler-FpBY9eRv.js.map} +1 -1
  78. package/dist/{profiler-CyzxBxVz.cjs → profiler-_mthyjvo.cjs} +2 -2
  79. package/dist/{profiler-CyzxBxVz.cjs.map → profiler-_mthyjvo.cjs.map} +1 -1
  80. package/dist/react-shim.js +1 -1
  81. package/dist/server/express.cjs.map +1 -1
  82. package/dist/server/express.js.map +1 -1
  83. package/dist/{startRecording-Dq92sEHf.cjs → startRecording-NJcpiHw-.cjs} +2 -2
  84. package/dist/{startRecording-Dq92sEHf.cjs.map → startRecording-NJcpiHw-.cjs.map} +1 -1
  85. package/dist/{startRecording-C-PPAs_Z.js → startRecording-r5MXQ2Dm.js} +2 -2
  86. package/dist/{startRecording-C-PPAs_Z.js.map → startRecording-r5MXQ2Dm.js.map} +1 -1
  87. package/dist/types/index.d.ts +2 -2
  88. package/package.json +1 -5
  89. package/src/compat-plugin.ts +14 -14
  90. package/src/compat-shims.ts +33 -31
  91. package/src/compat.test.ts +48 -48
  92. package/src/compat.ts +6 -6
  93. package/src/components/Chat/index.tsx +17 -17
  94. package/src/components/Chat/stories/Charts.stories.tsx +98 -98
  95. package/src/components/Chat/stories/Composer.stories.tsx +15 -15
  96. package/src/components/Chat/stories/ConnectionConfiguration.stories.tsx +44 -44
  97. package/src/components/Chat/stories/CustomComponents.stories.tsx +17 -17
  98. package/src/components/Chat/stories/Density.stories.tsx +20 -20
  99. package/src/components/Chat/stories/ErrorBoundary.stories.tsx +47 -47
  100. package/src/components/Chat/stories/FrontendTools.stories.tsx +39 -39
  101. package/src/components/Chat/stories/GenerativeUI.stories.tsx +48 -48
  102. package/src/components/Chat/stories/MessageFeedback.stories.tsx +52 -52
  103. package/src/components/Chat/stories/Modal.stories.tsx +28 -28
  104. package/src/components/Chat/stories/Model.stories.tsx +11 -11
  105. package/src/components/Chat/stories/Radius.stories.tsx +20 -20
  106. package/src/components/Chat/stories/Sidecar.stories.tsx +13 -13
  107. package/src/components/Chat/stories/StyleIsolation.stories.tsx +11 -11
  108. package/src/components/Chat/stories/Theme.stories.tsx +25 -25
  109. package/src/components/Chat/stories/Thread.stories.tsx +25 -25
  110. package/src/components/Chat/stories/ToolApproval.stories.tsx +55 -55
  111. package/src/components/Chat/stories/ToolMentions.stories.tsx +17 -17
  112. package/src/components/Chat/stories/Tools.stories.tsx +88 -88
  113. package/src/components/Chat/stories/Variants.stories.tsx +32 -32
  114. package/src/components/Chat/stories/Welcome.stories.tsx +14 -14
  115. package/src/components/ChatHistory.tsx +7 -7
  116. package/src/components/FrontendTools/index.tsx +5 -5
  117. package/src/components/Replay.stories.tsx +157 -157
  118. package/src/components/Replay.tsx +76 -73
  119. package/src/components/ShadowRoot.tsx +40 -40
  120. package/src/components/ShareButton/index.tsx +32 -32
  121. package/src/components/assistant-ui/assistant-modal.tsx +92 -87
  122. package/src/components/assistant-ui/assistant-sidecar.tsx +35 -35
  123. package/src/components/assistant-ui/attachment.tsx +80 -80
  124. package/src/components/assistant-ui/connection-status-indicator.tsx +33 -33
  125. package/src/components/assistant-ui/error-boundary.tsx +34 -34
  126. package/src/components/assistant-ui/follow-on-suggestions.tsx +26 -26
  127. package/src/components/assistant-ui/markdown-text.tsx +69 -69
  128. package/src/components/assistant-ui/mentioned-tools-badges.tsx +38 -38
  129. package/src/components/assistant-ui/message-feedback.tsx +57 -50
  130. package/src/components/assistant-ui/reasoning.tsx +83 -83
  131. package/src/components/assistant-ui/thread-list.tsx +45 -45
  132. package/src/components/assistant-ui/thread.tsx +278 -278
  133. package/src/components/assistant-ui/tool-fallback.tsx +37 -37
  134. package/src/components/assistant-ui/tool-group.tsx +26 -26
  135. package/src/components/assistant-ui/tool-mention-autocomplete.tsx +122 -122
  136. package/src/components/assistant-ui/tooltip-icon-button.tsx +18 -18
  137. package/src/components/ui/avatar.tsx +12 -12
  138. package/src/components/ui/button.tsx +12 -12
  139. package/src/components/ui/buttonVariants.ts +17 -17
  140. package/src/components/ui/calendar.tsx +106 -106
  141. package/src/components/ui/charts.stories.tsx +56 -56
  142. package/src/components/ui/collapsible.tsx +5 -5
  143. package/src/components/ui/dialog.tsx +30 -30
  144. package/src/components/ui/generative-ui.stories.tsx +200 -200
  145. package/src/components/ui/generative-ui.tsx +26 -26
  146. package/src/components/ui/popover.tsx +14 -14
  147. package/src/components/ui/skeleton.tsx +5 -5
  148. package/src/components/ui/time-range-picker.stories.tsx +80 -80
  149. package/src/components/ui/time-range-picker.tsx +245 -244
  150. package/src/components/ui/tool-ui.stories.tsx +37 -37
  151. package/src/components/ui/tool-ui.tsx +221 -215
  152. package/src/components/ui/tooltip.tsx +15 -15
  153. package/src/constants/tailwind.ts +1 -1
  154. package/src/contexts/ChatIdContext.tsx +7 -7
  155. package/src/contexts/ConnectionStatusContext.tsx +64 -64
  156. package/src/contexts/ElementsProvider.tsx +214 -213
  157. package/src/contexts/ReplayContext.ts +3 -3
  158. package/src/contexts/ToolApprovalContext.tsx +54 -54
  159. package/src/contexts/ToolExecutionContext.tsx +34 -34
  160. package/src/contexts/contexts.ts +7 -7
  161. package/src/contexts/portal-container-context.ts +2 -2
  162. package/src/contexts/portal-container.tsx +7 -7
  163. package/src/embedded.ts +1 -1
  164. package/src/global.css +25 -25
  165. package/src/hooks/useAuth.ts +72 -72
  166. package/src/hooks/useDensity.ts +79 -79
  167. package/src/hooks/useElements.ts +6 -6
  168. package/src/hooks/useExpanded.ts +12 -12
  169. package/src/hooks/useFollowOnSuggestions.ts +83 -83
  170. package/src/hooks/useGramThreadListAdapter.tsx +99 -99
  171. package/src/hooks/useMCPTools.ts +47 -47
  172. package/src/hooks/useModel.ts +14 -14
  173. package/src/hooks/usePluginComponents.ts +11 -11
  174. package/src/hooks/usePortalContainer.ts +5 -5
  175. package/src/hooks/useRadius.ts +23 -23
  176. package/src/hooks/useRecordCassette.ts +34 -34
  177. package/src/hooks/useSession.ts +11 -11
  178. package/src/hooks/useThemeProps.ts +13 -13
  179. package/src/hooks/useThreadId.ts +4 -4
  180. package/src/hooks/useToolApproval.ts +7 -7
  181. package/src/hooks/useToolMentions.ts +40 -40
  182. package/src/index.ts +26 -26
  183. package/src/lib/api.test.ts +61 -61
  184. package/src/lib/api.ts +4 -3
  185. package/src/lib/auth.ts +13 -13
  186. package/src/lib/cassette.ts +84 -84
  187. package/src/lib/easing.ts +1 -1
  188. package/src/lib/errorTracking.config.ts +5 -5
  189. package/src/lib/errorTracking.ts +29 -29
  190. package/src/lib/generative-ui.ts +7 -7
  191. package/src/lib/humanize.ts +3 -3
  192. package/src/lib/messageConverter.test.ts +130 -127
  193. package/src/lib/messageConverter.ts +196 -196
  194. package/src/lib/models.ts +21 -20
  195. package/src/lib/token.test.ts +56 -56
  196. package/src/lib/token.ts +14 -14
  197. package/src/lib/tool-mentions.ts +45 -45
  198. package/src/lib/tools.ts +66 -62
  199. package/src/lib/utils.ts +5 -5
  200. package/src/lib.d.ts +1 -1
  201. package/src/plugins/README.md +5 -5
  202. package/src/plugins/chart/catalog.ts +18 -18
  203. package/src/plugins/chart/chart.test.ts +31 -31
  204. package/src/plugins/chart/component.tsx +34 -34
  205. package/src/plugins/chart/index.ts +4 -4
  206. package/src/plugins/chart/ui/area-chart.tsx +42 -42
  207. package/src/plugins/chart/ui/bar-chart.tsx +46 -46
  208. package/src/plugins/chart/ui/donut-chart.tsx +48 -48
  209. package/src/plugins/chart/ui/index.ts +7 -7
  210. package/src/plugins/chart/ui/line-chart.tsx +43 -43
  211. package/src/plugins/chart/ui/pie-chart.tsx +44 -44
  212. package/src/plugins/chart/ui/radar-chart.tsx +33 -33
  213. package/src/plugins/chart/ui/scatter-chart.tsx +43 -43
  214. package/src/plugins/components/MacOSWindowFrame.tsx +15 -15
  215. package/src/plugins/components/PluginLoadingState.tsx +10 -10
  216. package/src/plugins/components/index.ts +1 -1
  217. package/src/plugins/generative-ui/catalog.ts +54 -54
  218. package/src/plugins/generative-ui/component.tsx +85 -85
  219. package/src/plugins/generative-ui/index.ts +4 -4
  220. package/src/plugins/generative-ui/ui/accordion-wrapper.tsx +16 -16
  221. package/src/plugins/generative-ui/ui/accordion.tsx +16 -16
  222. package/src/plugins/generative-ui/ui/action-button.tsx +28 -28
  223. package/src/plugins/generative-ui/ui/alert-wrapper.tsx +8 -8
  224. package/src/plugins/generative-ui/ui/alert.tsx +20 -20
  225. package/src/plugins/generative-ui/ui/avatar-wrapper.tsx +7 -7
  226. package/src/plugins/generative-ui/ui/avatar.tsx +30 -30
  227. package/src/plugins/generative-ui/ui/badge.tsx +22 -22
  228. package/src/plugins/generative-ui/ui/button-wrapper.tsx +12 -12
  229. package/src/plugins/generative-ui/ui/button.tsx +28 -28
  230. package/src/plugins/generative-ui/ui/card-wrapper.tsx +8 -8
  231. package/src/plugins/generative-ui/ui/card.tsx +27 -27
  232. package/src/plugins/generative-ui/ui/checkbox-wrapper.tsx +9 -9
  233. package/src/plugins/generative-ui/ui/checkbox.tsx +9 -9
  234. package/src/plugins/generative-ui/ui/data-table.tsx +8 -8
  235. package/src/plugins/generative-ui/ui/dialog.tsx +31 -31
  236. package/src/plugins/generative-ui/ui/dropdown-menu.tsx +44 -44
  237. package/src/plugins/generative-ui/ui/grid.tsx +12 -12
  238. package/src/plugins/generative-ui/ui/index.ts +40 -40
  239. package/src/plugins/generative-ui/ui/input-wrapper.tsx +11 -11
  240. package/src/plugins/generative-ui/ui/input.tsx +9 -9
  241. package/src/plugins/generative-ui/ui/label.tsx +8 -8
  242. package/src/plugins/generative-ui/ui/list.tsx +11 -11
  243. package/src/plugins/generative-ui/ui/metric.tsx +23 -23
  244. package/src/plugins/generative-ui/ui/pagination.tsx +28 -28
  245. package/src/plugins/generative-ui/ui/popover.tsx +21 -21
  246. package/src/plugins/generative-ui/ui/progress.tsx +13 -13
  247. package/src/plugins/generative-ui/ui/radio-group.tsx +12 -12
  248. package/src/plugins/generative-ui/ui/select-wrapper.tsx +7 -7
  249. package/src/plugins/generative-ui/ui/select.tsx +37 -37
  250. package/src/plugins/generative-ui/ui/separator.tsx +9 -9
  251. package/src/plugins/generative-ui/ui/skeleton-wrapper.tsx +10 -10
  252. package/src/plugins/generative-ui/ui/skeleton.tsx +5 -5
  253. package/src/plugins/generative-ui/ui/stack.tsx +28 -28
  254. package/src/plugins/generative-ui/ui/switch.tsx +11 -11
  255. package/src/plugins/generative-ui/ui/table.tsx +32 -32
  256. package/src/plugins/generative-ui/ui/tabs-wrapper.tsx +11 -11
  257. package/src/plugins/generative-ui/ui/tabs.tsx +26 -26
  258. package/src/plugins/generative-ui/ui/text.tsx +12 -12
  259. package/src/plugins/generative-ui/ui/textarea.tsx +7 -7
  260. package/src/plugins/generative-ui/ui/tooltip.tsx +12 -12
  261. package/src/plugins/index.ts +7 -7
  262. package/src/react-shim.ts +6 -6
  263. package/src/server/bun.ts +12 -12
  264. package/src/server/core.ts +25 -25
  265. package/src/server/express.ts +17 -15
  266. package/src/server/fastify.ts +14 -14
  267. package/src/server/hono.ts +9 -9
  268. package/src/server/nextjs.ts +12 -12
  269. package/src/server/tanstack-start.ts +12 -12
  270. package/src/server.ts +27 -27
  271. package/src/storybook.d.ts +4 -4
  272. package/src/types/index.ts +122 -122
  273. package/src/types/plugins.ts +7 -7
  274. package/src/vite-env.d.ts +12 -12
  275. package/dist/compat-shims-BPJ7Q68c.js.map +0 -1
  276. package/dist/index-D0bAYNQy.js.map +0 -1
  277. package/dist/index-KSX4Qjip.cjs.map +0 -1
@@ -1,19 +1,19 @@
1
- import { datadogRum } from '@datadog/browser-rum'
2
- import { DATADOG_CONFIG } from './errorTracking.config'
1
+ import { datadogRum } from "@datadog/browser-rum";
2
+ import { DATADOG_CONFIG } from "./errorTracking.config";
3
3
 
4
- let initialized = false
5
- let enabled = true
4
+ let initialized = false;
5
+ let enabled = true;
6
6
 
7
7
  export interface ErrorTrackingConfig {
8
- enabled?: boolean
9
- projectSlug?: string
10
- variant?: string
8
+ enabled?: boolean;
9
+ projectSlug?: string;
10
+ variant?: string;
11
11
  }
12
12
 
13
13
  export interface ErrorContext {
14
- source: 'error-boundary' | 'streaming' | 'stream-creation' | 'custom'
15
- componentStack?: string
16
- [key: string]: unknown
14
+ source: "error-boundary" | "streaming" | "stream-creation" | "custom";
15
+ componentStack?: string;
16
+ [key: string]: unknown;
17
17
  }
18
18
 
19
19
  /**
@@ -23,19 +23,19 @@ export interface ErrorContext {
23
23
  export function initErrorTracking(config: ErrorTrackingConfig = {}): void {
24
24
  // Check if explicitly disabled
25
25
  if (config.enabled === false) {
26
- enabled = false
27
- return
26
+ enabled = false;
27
+ return;
28
28
  }
29
29
 
30
30
  // Prevent double initialization
31
31
  if (initialized) {
32
- return
32
+ return;
33
33
  }
34
34
 
35
35
  // Skip if credentials not configured (e.g., local dev without env vars)
36
36
  if (!DATADOG_CONFIG.applicationId || !DATADOG_CONFIG.clientToken) {
37
- enabled = false
38
- return
37
+ enabled = false;
38
+ return;
39
39
  }
40
40
 
41
41
  try {
@@ -44,7 +44,7 @@ export function initErrorTracking(config: ErrorTrackingConfig = {}): void {
44
44
  clientToken: DATADOG_CONFIG.clientToken,
45
45
  site: DATADOG_CONFIG.site,
46
46
  service: DATADOG_CONFIG.service,
47
- env: process.env.NODE_ENV || 'production',
47
+ env: process.env.NODE_ENV || "production",
48
48
  sessionSampleRate: 100,
49
49
  sessionReplaySampleRate: 100,
50
50
  trackUserInteractions: true,
@@ -53,21 +53,21 @@ export function initErrorTracking(config: ErrorTrackingConfig = {}): void {
53
53
 
54
54
  // Note: we need to mask everything, not just user input, as sensitive data may be echo-ed
55
55
  // back in the LLM messages or the user messages in the chat window
56
- defaultPrivacyLevel: 'mask',
57
- })
56
+ defaultPrivacyLevel: "mask",
57
+ });
58
58
 
59
59
  // Set global context
60
60
  if (config.projectSlug) {
61
- datadogRum.setGlobalContextProperty('projectSlug', config.projectSlug)
61
+ datadogRum.setGlobalContextProperty("projectSlug", config.projectSlug);
62
62
  }
63
63
  if (config.variant) {
64
- datadogRum.setGlobalContextProperty('variant', config.variant)
64
+ datadogRum.setGlobalContextProperty("variant", config.variant);
65
65
  }
66
66
 
67
- initialized = true
67
+ initialized = true;
68
68
  } catch (error) {
69
- console.warn('[Elements] Failed to initialize Datadog RUM:', error)
70
- enabled = false
69
+ console.warn("[Elements] Failed to initialize Datadog RUM:", error);
70
+ enabled = false;
71
71
  }
72
72
  }
73
73
 
@@ -77,22 +77,22 @@ export function initErrorTracking(config: ErrorTrackingConfig = {}): void {
77
77
  */
78
78
  export function trackError(
79
79
  error: Error | unknown,
80
- context: ErrorContext
80
+ context: ErrorContext,
81
81
  ): void {
82
82
  if (!enabled || !initialized) {
83
- return
83
+ return;
84
84
  }
85
85
 
86
- const errorObj = error instanceof Error ? error : new Error(String(error))
86
+ const errorObj = error instanceof Error ? error : new Error(String(error));
87
87
 
88
88
  try {
89
89
  datadogRum.addError(errorObj, {
90
90
  ...context,
91
91
  timestamp: new Date().toISOString(),
92
- })
92
+ });
93
93
  } catch (e) {
94
94
  // Silently fail - we don't want error tracking to cause more errors
95
- console.warn('[Elements] Failed to track error:', e)
95
+ console.warn("[Elements] Failed to track error:", e);
96
96
  }
97
97
  }
98
98
 
@@ -100,5 +100,5 @@ export function trackError(
100
100
  * Check if error tracking is currently enabled.
101
101
  */
102
102
  export function isErrorTrackingEnabled(): boolean {
103
- return enabled && initialized
103
+ return enabled && initialized;
104
104
  }
@@ -1,8 +1,8 @@
1
1
  // Type for json-render tree structure
2
2
  export interface JsonRenderNode {
3
- type: string
4
- props?: Record<string, unknown>
5
- children?: JsonRenderNode[]
3
+ type: string;
4
+ props?: Record<string, unknown>;
5
+ children?: JsonRenderNode[];
6
6
  }
7
7
 
8
8
  /**
@@ -10,9 +10,9 @@ export interface JsonRenderNode {
10
10
  */
11
11
  export function isJsonRenderTree(content: unknown): content is JsonRenderNode {
12
12
  return (
13
- typeof content === 'object' &&
13
+ typeof content === "object" &&
14
14
  content !== null &&
15
- 'type' in content &&
16
- typeof (content as JsonRenderNode).type === 'string'
17
- )
15
+ "type" in content &&
16
+ typeof (content as JsonRenderNode).type === "string"
17
+ );
18
18
  }
@@ -5,10 +5,10 @@
5
5
  // - title case the string
6
6
  export function humanizeToolName(toolName: string): string {
7
7
  return toolName
8
- .replace(/[-_]/g, ' ') // Replace hyphens and underscores with spaces
8
+ .replace(/[-_]/g, " ") // Replace hyphens and underscores with spaces
9
9
  .split(/(?=[A-Z])/) // Split on camelCase boundaries
10
- .join(' ') // Join with spaces
10
+ .join(" ") // Join with spaces
11
11
  .split(/\s+/) // Split on any whitespace to normalize
12
12
  .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // Title case each word
13
- .join(' ')
13
+ .join(" ");
14
14
  }
@@ -1,82 +1,85 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { describe, expect, it } from 'vitest'
2
+ import { describe, expect, it } from "vitest";
3
3
  import {
4
4
  convertGramMessagesToExported,
5
5
  convertGramMessagesToUIMessages,
6
6
  convertGramMessagePartsToUIMessageParts,
7
7
  type GramChatMessage,
8
- } from './messageConverter'
8
+ } from "./messageConverter";
9
9
 
10
10
  /**
11
11
  * Helper to create a minimal GramChatMessage for testing.
12
12
  */
13
13
  function makeMsg(
14
- overrides: Partial<GramChatMessage> & { role: string }
14
+ overrides: Partial<GramChatMessage> & { role: string },
15
15
  ): GramChatMessage {
16
16
  return {
17
17
  id: crypto.randomUUID(),
18
- model: 'test-model',
18
+ model: "test-model",
19
19
  created_at: new Date().toISOString(),
20
20
  ...overrides,
21
- } as GramChatMessage
21
+ } as GramChatMessage;
22
22
  }
23
23
 
24
24
  function makeToolCallsJSON(
25
- calls: { id: string; name: string; args?: string }[]
25
+ calls: { id: string; name: string; args?: string }[],
26
26
  ): string {
27
27
  return JSON.stringify(
28
28
  calls.map((c) => ({
29
29
  id: c.id,
30
- type: 'function',
31
- function: { name: c.name, arguments: c.args ?? '{}' },
32
- }))
33
- )
30
+ type: "function",
31
+ function: { name: c.name, arguments: c.args ?? "{}" },
32
+ })),
33
+ );
34
34
  }
35
35
 
36
- describe('convertGramMessagePartsToUIMessageParts', () => {
37
- it('includes tool calls for a single assistant message', () => {
36
+ describe("convertGramMessagePartsToUIMessageParts", () => {
37
+ it("includes tool calls for a single assistant message", () => {
38
38
  const msg = makeMsg({
39
- role: 'assistant',
40
- content: 'Let me search.',
41
- tool_calls: makeToolCallsJSON([{ id: 'tc_1', name: 'search_deals' }]),
42
- } as Partial<GramChatMessage> & { role: string })
39
+ role: "assistant",
40
+ content: "Let me search.",
41
+ tool_calls: makeToolCallsJSON([{ id: "tc_1", name: "search_deals" }]),
42
+ } as Partial<GramChatMessage> & { role: string });
43
43
 
44
- const parts = convertGramMessagePartsToUIMessageParts(msg as any, new Map())
44
+ const parts = convertGramMessagePartsToUIMessageParts(
45
+ msg as any,
46
+ new Map(),
47
+ );
45
48
 
46
- const toolParts = parts.filter((p) => p.type === 'dynamic-tool')
47
- expect(toolParts).toHaveLength(1)
49
+ const toolParts = parts.filter((p) => p.type === "dynamic-tool");
50
+ expect(toolParts).toHaveLength(1);
48
51
  expect(toolParts[0]).toMatchObject({
49
- type: 'dynamic-tool',
50
- toolCallId: 'tc_1',
51
- toolName: 'search_deals',
52
- })
53
- })
54
-
55
- it('deduplicates tool calls when seenToolCallIds is provided', () => {
56
- const seen = new Set(['tc_1'])
52
+ type: "dynamic-tool",
53
+ toolCallId: "tc_1",
54
+ toolName: "search_deals",
55
+ });
56
+ });
57
+
58
+ it("deduplicates tool calls when seenToolCallIds is provided", () => {
59
+ const seen = new Set(["tc_1"]);
57
60
  const msg = makeMsg({
58
- role: 'assistant',
59
- content: 'Trying again.',
61
+ role: "assistant",
62
+ content: "Trying again.",
60
63
  tool_calls: makeToolCallsJSON([
61
- { id: 'tc_1', name: 'search_deals' },
62
- { id: 'tc_2', name: 'search_deals' },
64
+ { id: "tc_1", name: "search_deals" },
65
+ { id: "tc_2", name: "search_deals" },
63
66
  ]),
64
- } as Partial<GramChatMessage> & { role: string })
67
+ } as Partial<GramChatMessage> & { role: string });
65
68
 
66
69
  const parts = convertGramMessagePartsToUIMessageParts(
67
70
  msg as any,
68
71
  new Map(),
69
- seen
70
- )
72
+ seen,
73
+ );
71
74
 
72
- const toolParts = parts.filter((p) => p.type === 'dynamic-tool')
73
- expect(toolParts).toHaveLength(1)
74
- expect(toolParts[0]).toMatchObject({ toolCallId: 'tc_2' })
75
- expect(seen.has('tc_2')).toBe(true)
76
- })
77
- })
75
+ const toolParts = parts.filter((p) => p.type === "dynamic-tool");
76
+ expect(toolParts).toHaveLength(1);
77
+ expect(toolParts[0]).toMatchObject({ toolCallId: "tc_2" });
78
+ expect(seen.has("tc_2")).toBe(true);
79
+ });
80
+ });
78
81
 
79
- describe('convertGramMessagesToUIMessages - tool call deduplication', () => {
82
+ describe("convertGramMessagesToUIMessages - tool call deduplication", () => {
80
83
  /**
81
84
  * Simulates the server behavior where each assistant message in a multi-step
82
85
  * tool use flow accumulates ALL tool calls from the turn, not just its own.
@@ -90,153 +93,153 @@ describe('convertGramMessagesToUIMessages - tool call deduplication', () => {
90
93
  * Without dedup, each message renders all its tool calls → every group shows
91
94
  * the accumulated count. With dedup, each message only renders the new ones.
92
95
  */
93
- it('deduplicates accumulated tool calls across assistant messages', () => {
96
+ it("deduplicates accumulated tool calls across assistant messages", () => {
94
97
  const messages: GramChatMessage[] = [
95
98
  makeMsg({
96
- role: 'user',
97
- content: 'Search for deals',
99
+ role: "user",
100
+ content: "Search for deals",
98
101
  }),
99
102
  makeMsg({
100
- role: 'assistant',
103
+ role: "assistant",
101
104
  content: "I'll search for deals.",
102
105
  tool_calls: makeToolCallsJSON([
103
- { id: 'tc_1', name: 'hubspot_search_deals' },
106
+ { id: "tc_1", name: "hubspot_search_deals" },
104
107
  ]),
105
108
  } as Partial<GramChatMessage> & { role: string }),
106
109
  makeMsg({
107
- role: 'tool',
110
+ role: "tool",
108
111
  content: '{"error": "invalid filter"}',
109
- tool_call_id: 'tc_1',
112
+ tool_call_id: "tc_1",
110
113
  } as Partial<GramChatMessage> & { role: string }),
111
114
  makeMsg({
112
- role: 'assistant',
113
- content: 'Let me try differently.',
115
+ role: "assistant",
116
+ content: "Let me try differently.",
114
117
  tool_calls: makeToolCallsJSON([
115
- { id: 'tc_1', name: 'hubspot_search_deals' },
116
- { id: 'tc_2', name: 'hubspot_search_deals' },
118
+ { id: "tc_1", name: "hubspot_search_deals" },
119
+ { id: "tc_2", name: "hubspot_search_deals" },
117
120
  ]),
118
121
  } as Partial<GramChatMessage> & { role: string }),
119
122
  makeMsg({
120
- role: 'tool',
123
+ role: "tool",
121
124
  content: '{"error": "empty filters"}',
122
- tool_call_id: 'tc_2',
125
+ tool_call_id: "tc_2",
123
126
  } as Partial<GramChatMessage> & { role: string }),
124
127
  makeMsg({
125
- role: 'assistant',
126
- content: 'Let me try with proper filters.',
128
+ role: "assistant",
129
+ content: "Let me try with proper filters.",
127
130
  tool_calls: makeToolCallsJSON([
128
- { id: 'tc_1', name: 'hubspot_search_deals' },
129
- { id: 'tc_2', name: 'hubspot_search_deals' },
130
- { id: 'tc_3', name: 'hubspot_search_deals' },
131
+ { id: "tc_1", name: "hubspot_search_deals" },
132
+ { id: "tc_2", name: "hubspot_search_deals" },
133
+ { id: "tc_3", name: "hubspot_search_deals" },
131
134
  ]),
132
135
  } as Partial<GramChatMessage> & { role: string }),
133
136
  makeMsg({
134
- role: 'tool',
137
+ role: "tool",
135
138
  content: '{"deals": []}',
136
- tool_call_id: 'tc_3',
139
+ tool_call_id: "tc_3",
137
140
  } as Partial<GramChatMessage> & { role: string }),
138
141
  makeMsg({
139
- role: 'assistant',
140
- content: 'Here are the results.',
142
+ role: "assistant",
143
+ content: "Here are the results.",
141
144
  }),
142
- ]
145
+ ];
143
146
 
144
- const result = convertGramMessagesToUIMessages(messages)
147
+ const result = convertGramMessagesToUIMessages(messages);
145
148
  const assistantMessages = result.messages.filter(
146
- (m) => m.message.role === 'assistant'
147
- )
149
+ (m) => m.message.role === "assistant",
150
+ );
148
151
 
149
152
  // Each assistant message should only have its OWN tool call, not all accumulated ones
150
153
  const firstAssistant = assistantMessages[0]!.message.parts.filter(
151
- (p) => p.type === 'dynamic-tool'
152
- )
153
- expect(firstAssistant).toHaveLength(1)
154
- expect(firstAssistant[0]).toMatchObject({ toolCallId: 'tc_1' })
154
+ (p) => p.type === "dynamic-tool",
155
+ );
156
+ expect(firstAssistant).toHaveLength(1);
157
+ expect(firstAssistant[0]).toMatchObject({ toolCallId: "tc_1" });
155
158
 
156
159
  const secondAssistant = assistantMessages[1]!.message.parts.filter(
157
- (p) => p.type === 'dynamic-tool'
158
- )
159
- expect(secondAssistant).toHaveLength(1)
160
- expect(secondAssistant[0]).toMatchObject({ toolCallId: 'tc_2' })
160
+ (p) => p.type === "dynamic-tool",
161
+ );
162
+ expect(secondAssistant).toHaveLength(1);
163
+ expect(secondAssistant[0]).toMatchObject({ toolCallId: "tc_2" });
161
164
 
162
165
  const thirdAssistant = assistantMessages[2]!.message.parts.filter(
163
- (p) => p.type === 'dynamic-tool'
164
- )
165
- expect(thirdAssistant).toHaveLength(1)
166
- expect(thirdAssistant[0]).toMatchObject({ toolCallId: 'tc_3' })
166
+ (p) => p.type === "dynamic-tool",
167
+ );
168
+ expect(thirdAssistant).toHaveLength(1);
169
+ expect(thirdAssistant[0]).toMatchObject({ toolCallId: "tc_3" });
167
170
 
168
171
  // Final assistant message has no tool calls
169
172
  const fourthAssistant = assistantMessages[3]!.message.parts.filter(
170
- (p) => p.type === 'dynamic-tool'
171
- )
172
- expect(fourthAssistant).toHaveLength(0)
173
- })
173
+ (p) => p.type === "dynamic-tool",
174
+ );
175
+ expect(fourthAssistant).toHaveLength(0);
176
+ });
174
177
 
175
- it('resets dedup tracking after a user message', () => {
178
+ it("resets dedup tracking after a user message", () => {
176
179
  const messages: GramChatMessage[] = [
177
- makeMsg({ role: 'user', content: 'First question' }),
180
+ makeMsg({ role: "user", content: "First question" }),
178
181
  makeMsg({
179
- role: 'assistant',
180
- content: 'Searching.',
181
- tool_calls: makeToolCallsJSON([{ id: 'tc_1', name: 'search' }]),
182
+ role: "assistant",
183
+ content: "Searching.",
184
+ tool_calls: makeToolCallsJSON([{ id: "tc_1", name: "search" }]),
182
185
  } as Partial<GramChatMessage> & { role: string }),
183
186
  makeMsg({
184
- role: 'tool',
185
- content: '{}',
186
- tool_call_id: 'tc_1',
187
+ role: "tool",
188
+ content: "{}",
189
+ tool_call_id: "tc_1",
187
190
  } as Partial<GramChatMessage> & { role: string }),
188
- makeMsg({ role: 'user', content: 'Second question' }),
191
+ makeMsg({ role: "user", content: "Second question" }),
189
192
  // New turn — tc_1 reused as ID (different conversation turn)
190
193
  makeMsg({
191
- role: 'assistant',
192
- content: 'Searching again.',
193
- tool_calls: makeToolCallsJSON([{ id: 'tc_1', name: 'search' }]),
194
+ role: "assistant",
195
+ content: "Searching again.",
196
+ tool_calls: makeToolCallsJSON([{ id: "tc_1", name: "search" }]),
194
197
  } as Partial<GramChatMessage> & { role: string }),
195
- ]
198
+ ];
196
199
 
197
- const result = convertGramMessagesToUIMessages(messages)
200
+ const result = convertGramMessagesToUIMessages(messages);
198
201
  const assistantMessages = result.messages.filter(
199
- (m) => m.message.role === 'assistant'
200
- )
202
+ (m) => m.message.role === "assistant",
203
+ );
201
204
 
202
205
  // Both assistant messages should have tc_1 since the user message resets tracking
203
206
  const first = assistantMessages[0]!.message.parts.filter(
204
- (p) => p.type === 'dynamic-tool'
205
- )
206
- expect(first).toHaveLength(1)
207
+ (p) => p.type === "dynamic-tool",
208
+ );
209
+ expect(first).toHaveLength(1);
207
210
 
208
211
  const second = assistantMessages[1]!.message.parts.filter(
209
- (p) => p.type === 'dynamic-tool'
210
- )
211
- expect(second).toHaveLength(1)
212
- })
213
- })
214
-
215
- describe('convertGramMessagesToExported - string content with tool calls', () => {
216
- it('includes tool calls when assistant message has string content', () => {
212
+ (p) => p.type === "dynamic-tool",
213
+ );
214
+ expect(second).toHaveLength(1);
215
+ });
216
+ });
217
+
218
+ describe("convertGramMessagesToExported - string content with tool calls", () => {
219
+ it("includes tool calls when assistant message has string content", () => {
217
220
  const messages: GramChatMessage[] = [
218
- makeMsg({ role: 'user', content: 'Search for deals' }),
221
+ makeMsg({ role: "user", content: "Search for deals" }),
219
222
  makeMsg({
220
- role: 'assistant',
221
- content: 'Let me search.',
223
+ role: "assistant",
224
+ content: "Let me search.",
222
225
  tool_calls: makeToolCallsJSON([
223
- { id: 'tc_1', name: 'hubspot_search_deals' },
226
+ { id: "tc_1", name: "hubspot_search_deals" },
224
227
  ]),
225
228
  } as Partial<GramChatMessage> & { role: string }),
226
- ]
229
+ ];
227
230
 
228
- const result = convertGramMessagesToExported(messages)
231
+ const result = convertGramMessagesToExported(messages);
229
232
  const assistantEntry = result.messages.find(
230
- (m) => m.message.role === 'assistant'
231
- )!
233
+ (m) => m.message.role === "assistant",
234
+ )!;
232
235
  const toolCallParts = (assistantEntry.message as any).content.filter(
233
- (p: any) => p.type === 'tool-call'
234
- )
235
- expect(toolCallParts).toHaveLength(1)
236
+ (p: any) => p.type === "tool-call",
237
+ );
238
+ expect(toolCallParts).toHaveLength(1);
236
239
  expect(toolCallParts[0]).toMatchObject({
237
- type: 'tool-call',
238
- toolCallId: 'tc_1',
239
- toolName: 'hubspot_search_deals',
240
- })
241
- })
242
- })
240
+ type: "tool-call",
241
+ toolCallId: "tc_1",
242
+ toolName: "hubspot_search_deals",
243
+ });
244
+ });
245
+ });