@gram-ai/elements 1.27.3 → 1.27.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/README.md +72 -60
  2. package/README.typedoc.md +6 -6
  3. package/bin/cli.js +74 -74
  4. package/dist/compat-shims-CO9JXXV4.cjs.map +1 -1
  5. package/dist/{compat-shims-BPJ7Q68c.js → compat-shims-DxtUrORi.js} +4 -2
  6. package/dist/compat-shims-DxtUrORi.js.map +1 -0
  7. package/dist/components/ShareButton/index.d.ts +2 -2
  8. package/dist/components/assistant-ui/message-feedback.d.ts +1 -1
  9. package/dist/components/assistant-ui/tooltip-icon-button.d.ts +2 -2
  10. package/dist/components/ui/avatar.d.ts +2 -2
  11. package/dist/components/ui/button.d.ts +1 -1
  12. package/dist/components/ui/calendar.d.ts +1 -1
  13. package/dist/components/ui/collapsible.d.ts +1 -1
  14. package/dist/components/ui/dialog.d.ts +4 -4
  15. package/dist/components/ui/popover.d.ts +2 -2
  16. package/dist/components/ui/skeleton.d.ts +1 -1
  17. package/dist/components/ui/time-range-picker.d.ts +4 -2
  18. package/dist/components/ui/tool-ui.d.ts +7 -7
  19. package/dist/components/ui/tooltip.d.ts +2 -2
  20. package/dist/contexts/ConnectionStatusContext.d.ts +1 -1
  21. package/dist/elements.cjs +1 -1
  22. package/dist/elements.css +1 -1
  23. package/dist/elements.js +2 -2
  24. package/dist/hooks/useDensity.d.ts +73 -73
  25. package/dist/hooks/useMCPTools.d.ts +1 -1
  26. package/dist/hooks/useRadius.d.ts +1 -1
  27. package/dist/{index-BpJstUh1.cjs → index-C4bFBGfl.cjs} +4 -4
  28. package/dist/{index-BpJstUh1.cjs.map → index-C4bFBGfl.cjs.map} +1 -1
  29. package/dist/{index-CUitXazZ.js → index-D93pV0_o.js} +55 -55
  30. package/dist/{index-CUitXazZ.js.map → index-D93pV0_o.js.map} +1 -1
  31. package/dist/{index-DBrhzauj.js → index-DuCQRbcQ.js} +6386 -6337
  32. package/dist/index-DuCQRbcQ.js.map +1 -0
  33. package/dist/{index-DxfW52oA.cjs → index-y_PNN5vK.cjs} +64 -46
  34. package/dist/index-y_PNN5vK.cjs.map +1 -0
  35. package/dist/lib/cassette.d.ts +4 -4
  36. package/dist/lib/errorTracking.d.ts +1 -1
  37. package/dist/lib/messageConverter.d.ts +1 -1
  38. package/dist/lib/models.d.ts +1 -1
  39. package/dist/plugins/chart/ui/bar-chart.d.ts +1 -1
  40. package/dist/plugins/generative-ui/ui/accordion-wrapper.d.ts +2 -2
  41. package/dist/plugins/generative-ui/ui/accordion.d.ts +1 -1
  42. package/dist/plugins/generative-ui/ui/action-button.d.ts +2 -2
  43. package/dist/plugins/generative-ui/ui/alert-wrapper.d.ts +1 -1
  44. package/dist/plugins/generative-ui/ui/alert.d.ts +4 -4
  45. package/dist/plugins/generative-ui/ui/avatar.d.ts +5 -5
  46. package/dist/plugins/generative-ui/ui/badge.d.ts +2 -2
  47. package/dist/plugins/generative-ui/ui/button-wrapper.d.ts +2 -2
  48. package/dist/plugins/generative-ui/ui/button.d.ts +2 -2
  49. package/dist/plugins/generative-ui/ui/card-wrapper.d.ts +2 -2
  50. package/dist/plugins/generative-ui/ui/card.d.ts +8 -8
  51. package/dist/plugins/generative-ui/ui/checkbox.d.ts +1 -1
  52. package/dist/plugins/generative-ui/ui/data-table.d.ts +2 -2
  53. package/dist/plugins/generative-ui/ui/dialog.d.ts +3 -3
  54. package/dist/plugins/generative-ui/ui/dropdown-menu.d.ts +3 -3
  55. package/dist/plugins/generative-ui/ui/grid.d.ts +3 -3
  56. package/dist/plugins/generative-ui/ui/input-wrapper.d.ts +1 -1
  57. package/dist/plugins/generative-ui/ui/input.d.ts +2 -2
  58. package/dist/plugins/generative-ui/ui/label.d.ts +1 -1
  59. package/dist/plugins/generative-ui/ui/metric.d.ts +3 -3
  60. package/dist/plugins/generative-ui/ui/pagination.d.ts +6 -6
  61. package/dist/plugins/generative-ui/ui/popover.d.ts +4 -4
  62. package/dist/plugins/generative-ui/ui/progress.d.ts +2 -2
  63. package/dist/plugins/generative-ui/ui/radio-group.d.ts +1 -1
  64. package/dist/plugins/generative-ui/ui/select.d.ts +2 -2
  65. package/dist/plugins/generative-ui/ui/separator.d.ts +1 -1
  66. package/dist/plugins/generative-ui/ui/skeleton.d.ts +1 -1
  67. package/dist/plugins/generative-ui/ui/stack.d.ts +6 -6
  68. package/dist/plugins/generative-ui/ui/switch.d.ts +2 -2
  69. package/dist/plugins/generative-ui/ui/table.d.ts +9 -9
  70. package/dist/plugins/generative-ui/ui/tabs-wrapper.d.ts +1 -1
  71. package/dist/plugins/generative-ui/ui/tabs.d.ts +1 -1
  72. package/dist/plugins/generative-ui/ui/text.d.ts +3 -3
  73. package/dist/plugins/generative-ui/ui/textarea.d.ts +2 -2
  74. package/dist/plugins/generative-ui/ui/tooltip.d.ts +1 -1
  75. package/dist/plugins.cjs +1 -1
  76. package/dist/plugins.js +1 -1
  77. package/dist/{profiler-D6ndqfsd.js → profiler-FpBY9eRv.js} +2 -2
  78. package/dist/{profiler-D6ndqfsd.js.map → profiler-FpBY9eRv.js.map} +1 -1
  79. package/dist/{profiler-DhnzZ34c.cjs → profiler-_mthyjvo.cjs} +2 -2
  80. package/dist/{profiler-DhnzZ34c.cjs.map → profiler-_mthyjvo.cjs.map} +1 -1
  81. package/dist/react-shim.js +1 -1
  82. package/dist/server/express.cjs.map +1 -1
  83. package/dist/server/express.js.map +1 -1
  84. package/dist/{startRecording-BwXmdmy1.cjs → startRecording-NJcpiHw-.cjs} +2 -2
  85. package/dist/{startRecording-BwXmdmy1.cjs.map → startRecording-NJcpiHw-.cjs.map} +1 -1
  86. package/dist/{startRecording-B_9CRZ_P.js → startRecording-r5MXQ2Dm.js} +2 -2
  87. package/dist/{startRecording-B_9CRZ_P.js.map → startRecording-r5MXQ2Dm.js.map} +1 -1
  88. package/dist/types/index.d.ts +2 -2
  89. package/package.json +1 -5
  90. package/src/compat-plugin.ts +14 -14
  91. package/src/compat-shims.ts +33 -31
  92. package/src/compat.test.ts +48 -48
  93. package/src/compat.ts +6 -6
  94. package/src/components/Chat/index.tsx +17 -17
  95. package/src/components/Chat/stories/Charts.stories.tsx +98 -98
  96. package/src/components/Chat/stories/Composer.stories.tsx +15 -15
  97. package/src/components/Chat/stories/ConnectionConfiguration.stories.tsx +44 -44
  98. package/src/components/Chat/stories/CustomComponents.stories.tsx +17 -17
  99. package/src/components/Chat/stories/Density.stories.tsx +20 -20
  100. package/src/components/Chat/stories/ErrorBoundary.stories.tsx +47 -47
  101. package/src/components/Chat/stories/FrontendTools.stories.tsx +39 -39
  102. package/src/components/Chat/stories/GenerativeUI.stories.tsx +48 -48
  103. package/src/components/Chat/stories/MessageFeedback.stories.tsx +52 -52
  104. package/src/components/Chat/stories/Modal.stories.tsx +28 -28
  105. package/src/components/Chat/stories/Model.stories.tsx +11 -11
  106. package/src/components/Chat/stories/Radius.stories.tsx +20 -20
  107. package/src/components/Chat/stories/Sidecar.stories.tsx +13 -13
  108. package/src/components/Chat/stories/StyleIsolation.stories.tsx +11 -11
  109. package/src/components/Chat/stories/Theme.stories.tsx +25 -25
  110. package/src/components/Chat/stories/Thread.stories.tsx +25 -25
  111. package/src/components/Chat/stories/ToolApproval.stories.tsx +55 -55
  112. package/src/components/Chat/stories/ToolMentions.stories.tsx +17 -17
  113. package/src/components/Chat/stories/Tools.stories.tsx +88 -88
  114. package/src/components/Chat/stories/Variants.stories.tsx +32 -32
  115. package/src/components/Chat/stories/Welcome.stories.tsx +14 -14
  116. package/src/components/ChatHistory.tsx +7 -7
  117. package/src/components/FrontendTools/index.tsx +5 -5
  118. package/src/components/Replay.stories.tsx +157 -157
  119. package/src/components/Replay.tsx +76 -73
  120. package/src/components/ShadowRoot.tsx +40 -40
  121. package/src/components/ShareButton/index.tsx +32 -32
  122. package/src/components/assistant-ui/assistant-modal.tsx +92 -87
  123. package/src/components/assistant-ui/assistant-sidecar.tsx +35 -35
  124. package/src/components/assistant-ui/attachment.tsx +80 -80
  125. package/src/components/assistant-ui/connection-status-indicator.tsx +33 -33
  126. package/src/components/assistant-ui/error-boundary.tsx +34 -34
  127. package/src/components/assistant-ui/follow-on-suggestions.tsx +26 -26
  128. package/src/components/assistant-ui/markdown-text.tsx +69 -69
  129. package/src/components/assistant-ui/mentioned-tools-badges.tsx +38 -38
  130. package/src/components/assistant-ui/message-feedback.tsx +74 -61
  131. package/src/components/assistant-ui/reasoning.tsx +83 -83
  132. package/src/components/assistant-ui/thread-list.tsx +45 -45
  133. package/src/components/assistant-ui/thread.tsx +278 -278
  134. package/src/components/assistant-ui/tool-fallback.tsx +37 -37
  135. package/src/components/assistant-ui/tool-group.tsx +26 -26
  136. package/src/components/assistant-ui/tool-mention-autocomplete.tsx +122 -122
  137. package/src/components/assistant-ui/tooltip-icon-button.tsx +18 -18
  138. package/src/components/ui/avatar.tsx +12 -12
  139. package/src/components/ui/button.tsx +12 -12
  140. package/src/components/ui/buttonVariants.ts +17 -17
  141. package/src/components/ui/calendar.tsx +106 -106
  142. package/src/components/ui/charts.stories.tsx +56 -56
  143. package/src/components/ui/collapsible.tsx +5 -5
  144. package/src/components/ui/dialog.tsx +30 -30
  145. package/src/components/ui/generative-ui.stories.tsx +200 -200
  146. package/src/components/ui/generative-ui.tsx +26 -26
  147. package/src/components/ui/popover.tsx +14 -14
  148. package/src/components/ui/skeleton.tsx +5 -5
  149. package/src/components/ui/time-range-picker.stories.tsx +80 -80
  150. package/src/components/ui/time-range-picker.tsx +272 -235
  151. package/src/components/ui/tool-ui.stories.tsx +37 -37
  152. package/src/components/ui/tool-ui.tsx +221 -215
  153. package/src/components/ui/tooltip.tsx +15 -15
  154. package/src/constants/tailwind.ts +1 -1
  155. package/src/contexts/ChatIdContext.tsx +7 -7
  156. package/src/contexts/ConnectionStatusContext.tsx +64 -64
  157. package/src/contexts/ElementsProvider.tsx +222 -211
  158. package/src/contexts/ReplayContext.ts +3 -3
  159. package/src/contexts/ToolApprovalContext.tsx +54 -54
  160. package/src/contexts/ToolExecutionContext.tsx +34 -34
  161. package/src/contexts/contexts.ts +7 -7
  162. package/src/contexts/portal-container-context.ts +2 -2
  163. package/src/contexts/portal-container.tsx +7 -7
  164. package/src/embedded.ts +1 -1
  165. package/src/global.css +25 -25
  166. package/src/hooks/useAuth.ts +72 -72
  167. package/src/hooks/useDensity.ts +79 -79
  168. package/src/hooks/useElements.ts +6 -6
  169. package/src/hooks/useExpanded.ts +12 -12
  170. package/src/hooks/useFollowOnSuggestions.ts +87 -82
  171. package/src/hooks/useGramThreadListAdapter.tsx +99 -99
  172. package/src/hooks/useMCPTools.ts +47 -47
  173. package/src/hooks/useModel.ts +14 -14
  174. package/src/hooks/usePluginComponents.ts +11 -11
  175. package/src/hooks/usePortalContainer.ts +5 -5
  176. package/src/hooks/useRadius.ts +23 -23
  177. package/src/hooks/useRecordCassette.ts +34 -34
  178. package/src/hooks/useSession.ts +11 -11
  179. package/src/hooks/useThemeProps.ts +13 -13
  180. package/src/hooks/useThreadId.ts +4 -4
  181. package/src/hooks/useToolApproval.ts +7 -7
  182. package/src/hooks/useToolMentions.ts +40 -40
  183. package/src/index.ts +26 -26
  184. package/src/lib/api.test.ts +61 -61
  185. package/src/lib/api.ts +4 -3
  186. package/src/lib/auth.ts +13 -13
  187. package/src/lib/cassette.ts +84 -84
  188. package/src/lib/easing.ts +1 -1
  189. package/src/lib/errorTracking.config.ts +5 -5
  190. package/src/lib/errorTracking.ts +29 -29
  191. package/src/lib/generative-ui.ts +7 -7
  192. package/src/lib/humanize.ts +3 -3
  193. package/src/lib/messageConverter.test.ts +130 -127
  194. package/src/lib/messageConverter.ts +196 -196
  195. package/src/lib/models.ts +21 -20
  196. package/src/lib/token.test.ts +56 -56
  197. package/src/lib/token.ts +14 -14
  198. package/src/lib/tool-mentions.ts +45 -45
  199. package/src/lib/tools.ts +66 -62
  200. package/src/lib/utils.ts +5 -5
  201. package/src/lib.d.ts +1 -1
  202. package/src/plugins/README.md +5 -5
  203. package/src/plugins/chart/catalog.ts +18 -18
  204. package/src/plugins/chart/chart.test.ts +31 -31
  205. package/src/plugins/chart/component.tsx +34 -34
  206. package/src/plugins/chart/index.ts +4 -4
  207. package/src/plugins/chart/ui/area-chart.tsx +42 -42
  208. package/src/plugins/chart/ui/bar-chart.tsx +46 -46
  209. package/src/plugins/chart/ui/donut-chart.tsx +48 -48
  210. package/src/plugins/chart/ui/index.ts +7 -7
  211. package/src/plugins/chart/ui/line-chart.tsx +43 -43
  212. package/src/plugins/chart/ui/pie-chart.tsx +44 -44
  213. package/src/plugins/chart/ui/radar-chart.tsx +33 -33
  214. package/src/plugins/chart/ui/scatter-chart.tsx +43 -43
  215. package/src/plugins/components/MacOSWindowFrame.tsx +15 -15
  216. package/src/plugins/components/PluginLoadingState.tsx +10 -10
  217. package/src/plugins/components/index.ts +1 -1
  218. package/src/plugins/generative-ui/catalog.ts +54 -54
  219. package/src/plugins/generative-ui/component.tsx +85 -85
  220. package/src/plugins/generative-ui/index.ts +4 -4
  221. package/src/plugins/generative-ui/ui/accordion-wrapper.tsx +16 -16
  222. package/src/plugins/generative-ui/ui/accordion.tsx +16 -16
  223. package/src/plugins/generative-ui/ui/action-button.tsx +28 -28
  224. package/src/plugins/generative-ui/ui/alert-wrapper.tsx +8 -8
  225. package/src/plugins/generative-ui/ui/alert.tsx +20 -20
  226. package/src/plugins/generative-ui/ui/avatar-wrapper.tsx +7 -7
  227. package/src/plugins/generative-ui/ui/avatar.tsx +30 -30
  228. package/src/plugins/generative-ui/ui/badge.tsx +22 -22
  229. package/src/plugins/generative-ui/ui/button-wrapper.tsx +12 -12
  230. package/src/plugins/generative-ui/ui/button.tsx +28 -28
  231. package/src/plugins/generative-ui/ui/card-wrapper.tsx +8 -8
  232. package/src/plugins/generative-ui/ui/card.tsx +27 -27
  233. package/src/plugins/generative-ui/ui/checkbox-wrapper.tsx +9 -9
  234. package/src/plugins/generative-ui/ui/checkbox.tsx +9 -9
  235. package/src/plugins/generative-ui/ui/data-table.tsx +8 -8
  236. package/src/plugins/generative-ui/ui/dialog.tsx +31 -31
  237. package/src/plugins/generative-ui/ui/dropdown-menu.tsx +44 -44
  238. package/src/plugins/generative-ui/ui/grid.tsx +12 -12
  239. package/src/plugins/generative-ui/ui/index.ts +40 -40
  240. package/src/plugins/generative-ui/ui/input-wrapper.tsx +11 -11
  241. package/src/plugins/generative-ui/ui/input.tsx +9 -9
  242. package/src/plugins/generative-ui/ui/label.tsx +8 -8
  243. package/src/plugins/generative-ui/ui/list.tsx +11 -11
  244. package/src/plugins/generative-ui/ui/metric.tsx +23 -23
  245. package/src/plugins/generative-ui/ui/pagination.tsx +28 -28
  246. package/src/plugins/generative-ui/ui/popover.tsx +21 -21
  247. package/src/plugins/generative-ui/ui/progress.tsx +13 -13
  248. package/src/plugins/generative-ui/ui/radio-group.tsx +12 -12
  249. package/src/plugins/generative-ui/ui/select-wrapper.tsx +7 -7
  250. package/src/plugins/generative-ui/ui/select.tsx +37 -37
  251. package/src/plugins/generative-ui/ui/separator.tsx +9 -9
  252. package/src/plugins/generative-ui/ui/skeleton-wrapper.tsx +10 -10
  253. package/src/plugins/generative-ui/ui/skeleton.tsx +5 -5
  254. package/src/plugins/generative-ui/ui/stack.tsx +28 -28
  255. package/src/plugins/generative-ui/ui/switch.tsx +11 -11
  256. package/src/plugins/generative-ui/ui/table.tsx +32 -32
  257. package/src/plugins/generative-ui/ui/tabs-wrapper.tsx +11 -11
  258. package/src/plugins/generative-ui/ui/tabs.tsx +26 -26
  259. package/src/plugins/generative-ui/ui/text.tsx +12 -12
  260. package/src/plugins/generative-ui/ui/textarea.tsx +7 -7
  261. package/src/plugins/generative-ui/ui/tooltip.tsx +12 -12
  262. package/src/plugins/index.ts +7 -7
  263. package/src/react-shim.ts +6 -6
  264. package/src/server/bun.ts +12 -12
  265. package/src/server/core.ts +25 -25
  266. package/src/server/express.ts +17 -15
  267. package/src/server/fastify.ts +14 -14
  268. package/src/server/hono.ts +9 -9
  269. package/src/server/nextjs.ts +12 -12
  270. package/src/server/tanstack-start.ts +12 -12
  271. package/src/server.ts +27 -27
  272. package/src/storybook.d.ts +4 -4
  273. package/src/types/index.ts +122 -122
  274. package/src/types/plugins.ts +7 -7
  275. package/src/vite-env.d.ts +12 -12
  276. package/dist/compat-shims-BPJ7Q68c.js.map +0 -1
  277. package/dist/index-DBrhzauj.js.map +0 -1
  278. package/dist/index-DxfW52oA.cjs.map +0 -1
@@ -1,90 +1,90 @@
1
- import type { ElementsConfig } from '@/types'
2
- import { beforeEach, describe, expect, it, vi } from 'vitest'
1
+ import type { ElementsConfig } from "@/types";
2
+ import { beforeEach, describe, expect, it, vi } from "vitest";
3
3
 
4
- describe('getApiUrl', () => {
4
+ describe("getApiUrl", () => {
5
5
  beforeEach(() => {
6
- vi.resetModules()
7
- })
6
+ vi.resetModules();
7
+ });
8
8
 
9
9
  async function loadGetApiUrl(gramApiUrl: string | undefined) {
10
- vi.stubGlobal('__GRAM_API_URL__', gramApiUrl)
11
- const { getApiUrl } = await import('./api')
12
- return getApiUrl
10
+ vi.stubGlobal("__GRAM_API_URL__", gramApiUrl);
11
+ const { getApiUrl } = await import("./api");
12
+ return getApiUrl;
13
13
  }
14
14
 
15
- it('uses config.api.url when set', async () => {
16
- const getApiUrl = await loadGetApiUrl('https://env.example.com')
15
+ it("uses config.api.url when set", async () => {
16
+ const getApiUrl = await loadGetApiUrl("https://env.example.com");
17
17
  const config: ElementsConfig = {
18
- projectSlug: 'test',
19
- api: { url: 'https://config.example.com', session: 'test-key' },
20
- }
18
+ projectSlug: "test",
19
+ api: { url: "https://config.example.com", session: "test-key" },
20
+ };
21
21
 
22
- expect(getApiUrl(config)).toBe('https://config.example.com')
23
- })
22
+ expect(getApiUrl(config)).toBe("https://config.example.com");
23
+ });
24
24
 
25
- it('falls back to __GRAM_API_URL__ when config.api.url is not set', async () => {
26
- const getApiUrl = await loadGetApiUrl('https://env.example.com')
25
+ it("falls back to __GRAM_API_URL__ when config.api.url is not set", async () => {
26
+ const getApiUrl = await loadGetApiUrl("https://env.example.com");
27
27
  const config: ElementsConfig = {
28
- projectSlug: 'test',
29
- api: { session: 'test-key' },
30
- }
28
+ projectSlug: "test",
29
+ api: { session: "test-key" },
30
+ };
31
31
 
32
- expect(getApiUrl(config)).toBe('https://env.example.com')
33
- })
32
+ expect(getApiUrl(config)).toBe("https://env.example.com");
33
+ });
34
34
 
35
- it('falls back to __GRAM_API_URL__ when config.api is undefined', async () => {
36
- const getApiUrl = await loadGetApiUrl('https://env.example.com')
35
+ it("falls back to __GRAM_API_URL__ when config.api is undefined", async () => {
36
+ const getApiUrl = await loadGetApiUrl("https://env.example.com");
37
37
  const config: ElementsConfig = {
38
- projectSlug: 'test',
39
- }
38
+ projectSlug: "test",
39
+ };
40
40
 
41
- expect(getApiUrl(config)).toBe('https://env.example.com')
42
- })
41
+ expect(getApiUrl(config)).toBe("https://env.example.com");
42
+ });
43
43
 
44
- it('falls back to default URL when both config.api.url and __GRAM_API_URL__ are not set', async () => {
45
- const getApiUrl = await loadGetApiUrl('')
44
+ it("falls back to default URL when both config.api.url and __GRAM_API_URL__ are not set", async () => {
45
+ const getApiUrl = await loadGetApiUrl("");
46
46
  const config: ElementsConfig = {
47
- projectSlug: 'test',
48
- }
47
+ projectSlug: "test",
48
+ };
49
49
 
50
- expect(getApiUrl(config)).toBe('https://app.getgram.ai')
51
- })
50
+ expect(getApiUrl(config)).toBe("https://app.getgram.ai");
51
+ });
52
52
 
53
- it('falls back to default URL when __GRAM_API_URL__ is undefined', async () => {
54
- const getApiUrl = await loadGetApiUrl(undefined)
53
+ it("falls back to default URL when __GRAM_API_URL__ is undefined", async () => {
54
+ const getApiUrl = await loadGetApiUrl(undefined);
55
55
  const config: ElementsConfig = {
56
- projectSlug: 'test',
57
- }
56
+ projectSlug: "test",
57
+ };
58
58
 
59
- expect(getApiUrl(config)).toBe('https://app.getgram.ai')
60
- })
59
+ expect(getApiUrl(config)).toBe("https://app.getgram.ai");
60
+ });
61
61
 
62
- it('skips empty string config.api.url and uses __GRAM_API_URL__', async () => {
63
- const getApiUrl = await loadGetApiUrl('https://env.example.com')
62
+ it("skips empty string config.api.url and uses __GRAM_API_URL__", async () => {
63
+ const getApiUrl = await loadGetApiUrl("https://env.example.com");
64
64
  const config: ElementsConfig = {
65
- projectSlug: 'test',
66
- api: { url: '', session: 'test-key' },
67
- }
65
+ projectSlug: "test",
66
+ api: { url: "", session: "test-key" },
67
+ };
68
68
 
69
- expect(getApiUrl(config)).toBe('https://env.example.com')
70
- })
69
+ expect(getApiUrl(config)).toBe("https://env.example.com");
70
+ });
71
71
 
72
- it('removes trailing slashes from the URL', async () => {
73
- const getApiUrl = await loadGetApiUrl('')
72
+ it("removes trailing slashes from the URL", async () => {
73
+ const getApiUrl = await loadGetApiUrl("");
74
74
  const config: ElementsConfig = {
75
- projectSlug: 'test',
76
- api: { url: 'https://config.example.com///', session: 'test-key' },
77
- }
75
+ projectSlug: "test",
76
+ api: { url: "https://config.example.com///", session: "test-key" },
77
+ };
78
78
 
79
- expect(getApiUrl(config)).toBe('https://config.example.com')
80
- })
79
+ expect(getApiUrl(config)).toBe("https://config.example.com");
80
+ });
81
81
 
82
- it('removes trailing slashes from __GRAM_API_URL__', async () => {
83
- const getApiUrl = await loadGetApiUrl('https://env.example.com//')
82
+ it("removes trailing slashes from __GRAM_API_URL__", async () => {
83
+ const getApiUrl = await loadGetApiUrl("https://env.example.com//");
84
84
  const config: ElementsConfig = {
85
- projectSlug: 'test',
86
- }
85
+ projectSlug: "test",
86
+ };
87
87
 
88
- expect(getApiUrl(config)).toBe('https://env.example.com')
89
- })
90
- })
88
+ expect(getApiUrl(config)).toBe("https://env.example.com");
89
+ });
90
+ });
package/src/lib/api.ts CHANGED
@@ -1,8 +1,9 @@
1
- import { ElementsConfig } from '@/types'
1
+ import { ElementsConfig } from "@/types";
2
2
 
3
3
  export function getApiUrl(config: ElementsConfig): string {
4
4
  // The api.url in the config should take precedence over the __GRAM_API_URL__ environment variable
5
5
  // because it is a user-defined override
6
- const apiURL = config.api?.url || __GRAM_API_URL__ || 'https://app.getgram.ai'
7
- return apiURL.replace(/\/+$/, '') // Remove trailing slashes
6
+ const apiURL =
7
+ config.api?.url || __GRAM_API_URL__ || "https://app.getgram.ai";
8
+ return apiURL.replace(/\/+$/, ""); // Remove trailing slashes
8
9
  }
package/src/lib/auth.ts CHANGED
@@ -6,42 +6,42 @@ import {
6
6
  SessionAuthConfig,
7
7
  StaticSessionAuthConfig,
8
8
  UnifiedSessionAuthConfig,
9
- } from '@/types'
9
+ } from "@/types";
10
10
 
11
11
  export function isDangerousApiKeyAuth(
12
- auth: ApiConfig | undefined
12
+ auth: ApiConfig | undefined,
13
13
  ): auth is DangerousApiKeyAuthConfig {
14
- return !!auth && 'dangerousApiKey' in auth
14
+ return !!auth && "dangerousApiKey" in auth;
15
15
  }
16
16
 
17
17
  export function isUnifiedStaticSession(
18
- auth: ApiConfig | undefined
18
+ auth: ApiConfig | undefined,
19
19
  ): auth is UnifiedSessionAuthConfig & { session: string } {
20
- return !!auth && 'session' in auth && typeof auth.session === 'string'
20
+ return !!auth && "session" in auth && typeof auth.session === "string";
21
21
  }
22
22
 
23
23
  export function isUnifiedFunctionSession(
24
- auth: ApiConfig | undefined
24
+ auth: ApiConfig | undefined,
25
25
  ): auth is BaseApiConfig & { session: GetSessionFn } {
26
- return !!auth && 'session' in auth && typeof auth.session === 'function'
26
+ return !!auth && "session" in auth && typeof auth.session === "function";
27
27
  }
28
28
 
29
29
  /** @deprecated Legacy check for `{ sessionToken }` configs. */
30
30
  export function isStaticSessionAuth(
31
- auth: ApiConfig | undefined
31
+ auth: ApiConfig | undefined,
32
32
  ): auth is StaticSessionAuthConfig {
33
- return !!auth && 'sessionToken' in auth
33
+ return !!auth && "sessionToken" in auth;
34
34
  }
35
35
 
36
36
  /** @deprecated Legacy check for `{ sessionFn }` configs. */
37
37
  export function hasExplicitSessionAuth(
38
- auth: ApiConfig | undefined
38
+ auth: ApiConfig | undefined,
39
39
  ): auth is SessionAuthConfig {
40
- if (!auth) return false
41
- return 'sessionFn' in auth
40
+ if (!auth) return false;
41
+ return "sessionFn" in auth;
42
42
  }
43
43
 
44
44
  /** Returns true when either the legacy `sessionToken` or the unified static `session` string is used. */
45
45
  export function isAnyStaticSession(auth: ApiConfig | undefined): boolean {
46
- return isStaticSessionAuth(auth) || isUnifiedStaticSession(auth)
46
+ return isStaticSessionAuth(auth) || isUnifiedStaticSession(auth);
47
47
  }
@@ -10,35 +10,35 @@
10
10
  * 3. Pass it to `<Replay cassette={...}>` to play it back
11
11
  */
12
12
 
13
- import { createUIMessageStream, type ChatTransport, type UIMessage } from 'ai'
14
- import type { ThreadMessage } from '@assistant-ui/react'
13
+ import { createUIMessageStream, type ChatTransport, type UIMessage } from "ai";
14
+ import type { ThreadMessage } from "@assistant-ui/react";
15
15
 
16
16
  // ---------------------------------------------------------------------------
17
17
  // Cassette types
18
18
  // ---------------------------------------------------------------------------
19
19
 
20
- export type CassetteTextPart = { type: 'text'; text: string }
21
- export type CassetteReasoningPart = { type: 'reasoning'; text: string }
20
+ export type CassetteTextPart = { type: "text"; text: string };
21
+ export type CassetteReasoningPart = { type: "reasoning"; text: string };
22
22
  export type CassetteToolCallPart = {
23
- type: 'tool-call'
24
- toolCallId: string
25
- toolName: string
26
- args: unknown
27
- result?: unknown
28
- }
23
+ type: "tool-call";
24
+ toolCallId: string;
25
+ toolName: string;
26
+ args: unknown;
27
+ result?: unknown;
28
+ };
29
29
 
30
30
  export type CassettePart =
31
31
  | CassetteTextPart
32
32
  | CassetteReasoningPart
33
- | CassetteToolCallPart
33
+ | CassetteToolCallPart;
34
34
 
35
35
  export interface CassetteMessage {
36
- role: 'user' | 'assistant'
37
- content: CassettePart[]
36
+ role: "user" | "assistant";
37
+ content: CassettePart[];
38
38
  }
39
39
 
40
40
  export interface Cassette {
41
- messages: CassetteMessage[]
41
+ messages: CassetteMessage[];
42
42
  }
43
43
 
44
44
  // ---------------------------------------------------------------------------
@@ -47,13 +47,13 @@ export interface Cassette {
47
47
 
48
48
  export interface ReplayOptions {
49
49
  /** Milliseconds per character when streaming text. @default 15 */
50
- typingSpeed?: number
50
+ typingSpeed?: number;
51
51
  /** Milliseconds to wait before showing each user message. @default 800 */
52
- userMessageDelay?: number
52
+ userMessageDelay?: number;
53
53
  /** Milliseconds to wait before the assistant starts "typing". @default 400 */
54
- assistantStartDelay?: number
54
+ assistantStartDelay?: number;
55
55
  /** Called when the full replay sequence finishes. */
56
- onComplete?: () => void
56
+ onComplete?: () => void;
57
57
  }
58
58
 
59
59
  // ---------------------------------------------------------------------------
@@ -65,47 +65,47 @@ export interface ReplayOptions {
65
65
  * System messages are filtered out since they aren't displayed.
66
66
  */
67
67
  export function recordCassette(messages: readonly ThreadMessage[]): Cassette {
68
- const cassetteMessages: CassetteMessage[] = []
68
+ const cassetteMessages: CassetteMessage[] = [];
69
69
 
70
70
  for (const msg of messages) {
71
- if (msg.role === 'system') continue
71
+ if (msg.role === "system") continue;
72
72
 
73
- const parts: CassettePart[] = []
73
+ const parts: CassettePart[] = [];
74
74
 
75
75
  for (const part of msg.content) {
76
76
  switch (part.type) {
77
- case 'text':
77
+ case "text":
78
78
  if (part.text) {
79
- parts.push({ type: 'text', text: part.text })
79
+ parts.push({ type: "text", text: part.text });
80
80
  }
81
- break
82
- case 'reasoning':
81
+ break;
82
+ case "reasoning":
83
83
  if (part.text) {
84
- parts.push({ type: 'reasoning', text: part.text })
84
+ parts.push({ type: "reasoning", text: part.text });
85
85
  }
86
- break
87
- case 'tool-call':
86
+ break;
87
+ case "tool-call":
88
88
  parts.push({
89
- type: 'tool-call',
89
+ type: "tool-call",
90
90
  toolCallId: part.toolCallId,
91
91
  toolName: part.toolName,
92
92
  args: part.args,
93
93
  result: part.result,
94
- })
95
- break
94
+ });
95
+ break;
96
96
  // Skip image, file, audio, source, data parts for now
97
97
  }
98
98
  }
99
99
 
100
100
  if (parts.length > 0) {
101
101
  cassetteMessages.push({
102
- role: msg.role as 'user' | 'assistant',
102
+ role: msg.role as "user" | "assistant",
103
103
  content: parts,
104
- })
104
+ });
105
105
  }
106
106
  }
107
107
 
108
- return { messages: cassetteMessages }
108
+ return { messages: cassetteMessages };
109
109
  }
110
110
 
111
111
  // ---------------------------------------------------------------------------
@@ -116,19 +116,19 @@ export function recordCassette(messages: readonly ThreadMessage[]): Cassette {
116
116
  function sleep(ms: number, signal?: AbortSignal): Promise<void> {
117
117
  return new Promise((resolve, reject) => {
118
118
  if (signal?.aborted) {
119
- reject(new DOMException('Aborted', 'AbortError'))
120
- return
119
+ reject(new DOMException("Aborted", "AbortError"));
120
+ return;
121
121
  }
122
- const timeout = setTimeout(resolve, ms)
122
+ const timeout = setTimeout(resolve, ms);
123
123
  signal?.addEventListener(
124
- 'abort',
124
+ "abort",
125
125
  () => {
126
- clearTimeout(timeout)
127
- reject(new DOMException('Aborted', 'AbortError'))
126
+ clearTimeout(timeout);
127
+ reject(new DOMException("Aborted", "AbortError"));
128
128
  },
129
- { once: true }
130
- )
131
- })
129
+ { once: true },
130
+ );
131
+ });
132
132
  }
133
133
 
134
134
  /**
@@ -138,14 +138,14 @@ function sleep(ms: number, signal?: AbortSignal): Promise<void> {
138
138
  */
139
139
  export function createReplayTransport(
140
140
  cassette: Cassette,
141
- options?: ReplayOptions
141
+ options?: ReplayOptions,
142
142
  ): ChatTransport<UIMessage> {
143
- const typingSpeed = options?.typingSpeed ?? 15
144
- const assistantStartDelay = options?.assistantStartDelay ?? 400
143
+ const typingSpeed = options?.typingSpeed ?? 15;
144
+ const assistantStartDelay = options?.assistantStartDelay ?? 400;
145
145
 
146
146
  // Cursor tracking which message index to serve next.
147
147
  // Starts at 0 and advances past user+assistant pairs.
148
- let cursor = 0
148
+ let cursor = 0;
149
149
 
150
150
  return {
151
151
  sendMessages: async ({ abortSignal }) => {
@@ -153,51 +153,51 @@ export function createReplayTransport(
153
153
  // Advance cursor past it (it should be pointing at a user message).
154
154
  if (
155
155
  cursor < cassette.messages.length &&
156
- cassette.messages[cursor].role === 'user'
156
+ cassette.messages[cursor].role === "user"
157
157
  ) {
158
- cursor++
158
+ cursor++;
159
159
  }
160
160
 
161
161
  // Collect the next assistant message(s).
162
162
  // Multiple consecutive assistant messages are possible (e.g. multi-step tool calls).
163
- const assistantMessages: CassetteMessage[] = []
163
+ const assistantMessages: CassetteMessage[] = [];
164
164
  while (
165
165
  cursor < cassette.messages.length &&
166
- cassette.messages[cursor].role === 'assistant'
166
+ cassette.messages[cursor].role === "assistant"
167
167
  ) {
168
- assistantMessages.push(cassette.messages[cursor])
169
- cursor++
168
+ assistantMessages.push(cassette.messages[cursor]);
169
+ cursor++;
170
170
  }
171
171
 
172
172
  // Return a stream that emits the pre-recorded content
173
173
  return createUIMessageStream({
174
174
  execute: async ({ writer }) => {
175
175
  if (assistantMessages.length === 0) {
176
- return
176
+ return;
177
177
  }
178
178
 
179
179
  try {
180
- await sleep(assistantStartDelay, abortSignal)
180
+ await sleep(assistantStartDelay, abortSignal);
181
181
  } catch {
182
- return // aborted
182
+ return; // aborted
183
183
  }
184
184
 
185
185
  for (const message of assistantMessages) {
186
186
  for (const part of message.content) {
187
187
  try {
188
- await writeReplayPart(writer, part, typingSpeed, abortSignal)
188
+ await writeReplayPart(writer, part, typingSpeed, abortSignal);
189
189
  } catch {
190
- return // aborted
190
+ return; // aborted
191
191
  }
192
192
  }
193
193
  }
194
194
  },
195
- })
195
+ });
196
196
  },
197
197
  reconnectToStream: async () => {
198
- return null
198
+ return null;
199
199
  },
200
- }
200
+ };
201
201
  }
202
202
 
203
203
  // ---------------------------------------------------------------------------
@@ -206,55 +206,55 @@ export function createReplayTransport(
206
206
 
207
207
  interface StreamWriter {
208
208
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
209
- write(part: any): void
209
+ write(part: any): void;
210
210
  }
211
211
 
212
212
  async function writeReplayPart(
213
213
  writer: StreamWriter,
214
214
  part: CassettePart,
215
215
  typingSpeed: number,
216
- abortSignal?: AbortSignal
216
+ abortSignal?: AbortSignal,
217
217
  ): Promise<void> {
218
218
  switch (part.type) {
219
- case 'text': {
220
- const partId = crypto.randomUUID()
221
- writer.write({ type: 'text-start', id: partId })
219
+ case "text": {
220
+ const partId = crypto.randomUUID();
221
+ writer.write({ type: "text-start", id: partId });
222
222
  for (const char of part.text) {
223
- writer.write({ type: 'text-delta', id: partId, delta: char })
224
- await sleep(typingSpeed, abortSignal)
223
+ writer.write({ type: "text-delta", id: partId, delta: char });
224
+ await sleep(typingSpeed, abortSignal);
225
225
  }
226
- writer.write({ type: 'text-end', id: partId })
227
- break
226
+ writer.write({ type: "text-end", id: partId });
227
+ break;
228
228
  }
229
229
 
230
- case 'reasoning': {
231
- const partId = crypto.randomUUID()
232
- writer.write({ type: 'reasoning-start', id: partId })
230
+ case "reasoning": {
231
+ const partId = crypto.randomUUID();
232
+ writer.write({ type: "reasoning-start", id: partId });
233
233
  for (const char of part.text) {
234
- writer.write({ type: 'reasoning-delta', id: partId, delta: char })
235
- await sleep(typingSpeed, abortSignal)
234
+ writer.write({ type: "reasoning-delta", id: partId, delta: char });
235
+ await sleep(typingSpeed, abortSignal);
236
236
  }
237
- writer.write({ type: 'reasoning-end', id: partId })
238
- break
237
+ writer.write({ type: "reasoning-end", id: partId });
238
+ break;
239
239
  }
240
240
 
241
- case 'tool-call': {
241
+ case "tool-call": {
242
242
  writer.write({
243
- type: 'tool-input-available',
243
+ type: "tool-input-available",
244
244
  toolCallId: part.toolCallId,
245
245
  toolName: part.toolName,
246
246
  input: part.args,
247
- })
247
+ });
248
248
  if (part.result !== undefined) {
249
249
  // Brief pause to simulate tool execution
250
- await sleep(300, abortSignal)
250
+ await sleep(300, abortSignal);
251
251
  writer.write({
252
- type: 'tool-output-available',
252
+ type: "tool-output-available",
253
253
  toolCallId: part.toolCallId,
254
254
  output: part.result,
255
- })
255
+ });
256
256
  }
257
- break
257
+ break;
258
258
  }
259
259
  }
260
260
  }
package/src/lib/easing.ts CHANGED
@@ -1 +1 @@
1
- export const EASE_OUT_QUINT = [0.23, 1, 0.32, 1] as const
1
+ export const EASE_OUT_QUINT = [0.23, 1, 0.32, 1] as const;
@@ -9,8 +9,8 @@
9
9
  * - VITE_DATADOG_SITE (optional, defaults to datadoghq.com)
10
10
  */
11
11
  export const DATADOG_CONFIG = {
12
- applicationId: import.meta.env.VITE_DATADOG_APPLICATION_ID ?? '',
13
- clientToken: import.meta.env.VITE_DATADOG_CLIENT_TOKEN ?? '',
14
- site: import.meta.env.VITE_DATADOG_SITE ?? 'datadoghq.com',
15
- service: 'gram-elements',
16
- } as const
12
+ applicationId: import.meta.env.VITE_DATADOG_APPLICATION_ID ?? "",
13
+ clientToken: import.meta.env.VITE_DATADOG_CLIENT_TOKEN ?? "",
14
+ site: import.meta.env.VITE_DATADOG_SITE ?? "datadoghq.com",
15
+ service: "gram-elements",
16
+ } as const;