@gram-ai/elements 1.27.4 → 1.27.6

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 +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.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-KSX4Qjip.cjs → index-A17b62wR.cjs} +10 -10
  28. package/dist/index-A17b62wR.cjs.map +1 -0
  29. package/dist/{index-BpJstUh1.cjs → index-C4bFBGfl.cjs} +4 -4
  30. package/dist/{index-BpJstUh1.cjs.map → index-C4bFBGfl.cjs.map} +1 -1
  31. package/dist/{index-CUitXazZ.js → index-D93pV0_o.js} +55 -55
  32. package/dist/{index-CUitXazZ.js.map → index-D93pV0_o.js.map} +1 -1
  33. package/dist/{index-D0bAYNQy.js → index-Dm2wLFTN.js} +304 -282
  34. package/dist/index-Dm2wLFTN.js.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-CyzxBxVz.cjs → profiler-Cbbf4eEX.cjs} +2 -2
  78. package/dist/{profiler-CyzxBxVz.cjs.map → profiler-Cbbf4eEX.cjs.map} +1 -1
  79. package/dist/{profiler-BFkhZRxj.js → profiler-mca4IXaY.js} +2 -2
  80. package/dist/{profiler-BFkhZRxj.js.map → profiler-mca4IXaY.js.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-C-PPAs_Z.js → startRecording-BCafdS7B.js} +2 -2
  85. package/dist/{startRecording-C-PPAs_Z.js.map → startRecording-BCafdS7B.js.map} +1 -1
  86. package/dist/{startRecording-Dq92sEHf.cjs → startRecording-Eb5f7wqP.cjs} +2 -2
  87. package/dist/{startRecording-Dq92sEHf.cjs.map → startRecording-Eb5f7wqP.cjs.map} +1 -1
  88. package/dist/types/index.d.ts +4 -4
  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 +57 -50
  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 +248 -246
  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 +214 -213
  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 +83 -83
  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 +28 -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 +124 -124
  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-D0bAYNQy.js.map +0 -1
  278. package/dist/index-KSX4Qjip.cjs.map +0 -1
@@ -5,14 +5,14 @@ import {
5
5
  ThreadHistoryAdapter,
6
6
  useAssistantApi,
7
7
  type AssistantApi,
8
- } from '@assistant-ui/react'
9
- import { createAssistantStream, type AssistantStream } from 'assistant-stream'
8
+ } from "@assistant-ui/react";
9
+ import { createAssistantStream, type AssistantStream } from "assistant-stream";
10
10
  import {
11
11
  GramChatOverview,
12
12
  GramChat,
13
13
  convertGramMessagesToExported,
14
14
  convertGramMessagesToUIMessages,
15
- } from '@/lib/messageConverter'
15
+ } from "@/lib/messageConverter";
16
16
  import {
17
17
  useCallback,
18
18
  useEffect,
@@ -20,32 +20,32 @@ import {
20
20
  useRef,
21
21
  useState,
22
22
  type PropsWithChildren,
23
- } from 'react'
23
+ } from "react";
24
24
 
25
25
  /**
26
26
  * Prefix used by assistant-ui for local thread IDs that haven't been persisted yet.
27
27
  * This is an internal implementation detail of assistant-ui's RemoteThreadListThreadListRuntimeCore.
28
28
  * If the library changes this prefix, we only need to update it here.
29
29
  */
30
- const LOCAL_THREAD_ID_PREFIX = '__LOCALID_'
30
+ const LOCAL_THREAD_ID_PREFIX = "__LOCALID_";
31
31
 
32
32
  /**
33
33
  * Checks if a thread ID is a local (unpersisted) thread ID.
34
34
  * Local IDs are generated by assistant-ui before the thread is initialized with a remote ID.
35
35
  */
36
36
  export function isLocalThreadId(threadId: string | null | undefined): boolean {
37
- return !!threadId?.startsWith(LOCAL_THREAD_ID_PREFIX)
37
+ return !!threadId?.startsWith(LOCAL_THREAD_ID_PREFIX);
38
38
  }
39
39
 
40
40
  export interface ThreadListAdapterOptions {
41
- apiUrl: string
42
- headers: Record<string, string>
41
+ apiUrl: string;
42
+ headers: Record<string, string>;
43
43
  /** Map to translate local thread IDs to UUIDs (shared with transport) */
44
- localIdToUuidMap?: Map<string, string>
44
+ localIdToUuidMap?: Map<string, string>;
45
45
  }
46
46
 
47
47
  interface ListChatsResponse {
48
- chats: GramChatOverview[]
48
+ chats: GramChatOverview[];
49
49
  }
50
50
 
51
51
  /**
@@ -54,42 +54,42 @@ interface ListChatsResponse {
54
54
  * signature doesn't match our concrete implementation, but it works at runtime.
55
55
  */
56
56
  class GramThreadHistoryAdapter {
57
- private apiUrl: string
58
- private headers: Record<string, string>
59
- private store: AssistantApi
57
+ private apiUrl: string;
58
+ private headers: Record<string, string>;
59
+ private store: AssistantApi;
60
60
 
61
61
  constructor(
62
62
  apiUrl: string,
63
63
  headers: Record<string, string>,
64
- store: AssistantApi
64
+ store: AssistantApi,
65
65
  ) {
66
- this.apiUrl = apiUrl
67
- this.headers = headers
68
- this.store = store
66
+ this.apiUrl = apiUrl;
67
+ this.headers = headers;
68
+ this.store = store;
69
69
  }
70
70
 
71
71
  async load() {
72
- const remoteId = this.store.threadListItem().getState().remoteId
72
+ const remoteId = this.store.threadListItem().getState().remoteId;
73
73
  if (!remoteId) {
74
- return { messages: [], headId: null }
74
+ return { messages: [], headId: null };
75
75
  }
76
76
 
77
77
  try {
78
78
  const response = await fetch(
79
79
  `${this.apiUrl}/rpc/chat.load?id=${encodeURIComponent(remoteId)}`,
80
- { headers: this.headers }
81
- )
80
+ { headers: this.headers },
81
+ );
82
82
 
83
83
  if (!response.ok) {
84
- console.error('Failed to load chat:', response.status)
85
- return { messages: [], headId: null }
84
+ console.error("Failed to load chat:", response.status);
85
+ return { messages: [], headId: null };
86
86
  }
87
87
 
88
- const chat = (await response.json()) as GramChat
89
- return convertGramMessagesToExported(chat.messages)
88
+ const chat = (await response.json()) as GramChat;
89
+ return convertGramMessagesToExported(chat.messages);
90
90
  } catch (error) {
91
- console.error('Error loading chat:', error)
92
- return { messages: [], headId: null }
91
+ console.error("Error loading chat:", error);
92
+ return { messages: [], headId: null };
93
93
  }
94
94
  }
95
95
 
@@ -104,23 +104,23 @@ class GramThreadHistoryAdapter {
104
104
  withFormat(_formatAdapter: unknown) {
105
105
  return {
106
106
  load: async () => {
107
- const remoteId = this.store.threadListItem().getState().remoteId
107
+ const remoteId = this.store.threadListItem().getState().remoteId;
108
108
  if (!remoteId) {
109
- return { messages: [], headId: null }
109
+ return { messages: [], headId: null };
110
110
  }
111
111
 
112
112
  const response = await fetch(
113
113
  `${this.apiUrl}/rpc/chat.load?id=${encodeURIComponent(remoteId)}`,
114
- { headers: this.headers }
115
- )
114
+ { headers: this.headers },
115
+ );
116
116
 
117
117
  if (!response.ok) {
118
- console.error('Failed to load chat (withFormat):', response.status)
119
- return { messages: [], headId: null }
118
+ console.error("Failed to load chat (withFormat):", response.status);
119
+ return { messages: [], headId: null };
120
120
  }
121
121
 
122
- const chat = (await response.json()) as GramChat
123
- return convertGramMessagesToUIMessages(chat.messages)
122
+ const chat = (await response.json()) as GramChat;
123
+ return convertGramMessagesToUIMessages(chat.messages);
124
124
 
125
125
  // // Filter out system messages (assistant-ui doesn't support them in the import path)
126
126
  // const filteredMessages = chat.messages.filter(
@@ -158,7 +158,7 @@ class GramThreadHistoryAdapter {
158
158
  append: async () => {
159
159
  // No-op
160
160
  },
161
- }
161
+ };
162
162
  }
163
163
  }
164
164
 
@@ -166,19 +166,19 @@ class GramThreadHistoryAdapter {
166
166
  * Hook to create a Gram thread history adapter.
167
167
  */
168
168
  function useGramThreadHistoryAdapter(
169
- optionsRef: React.RefObject<ThreadListAdapterOptions>
169
+ optionsRef: React.RefObject<ThreadListAdapterOptions>,
170
170
  ): ThreadHistoryAdapter {
171
- const store = useAssistantApi()
171
+ const store = useAssistantApi();
172
172
  const [adapter] = useState(
173
173
  () =>
174
174
  new GramThreadHistoryAdapter(
175
175
  optionsRef.current.apiUrl,
176
176
  optionsRef.current.headers,
177
- store
178
- )
179
- )
177
+ store,
178
+ ),
179
+ );
180
180
  // Cast to ThreadHistoryAdapter - the withFormat generic doesn't match but works at runtime
181
- return adapter as unknown as ThreadHistoryAdapter
181
+ return adapter as unknown as ThreadHistoryAdapter;
182
182
  }
183
183
 
184
184
  /**
@@ -186,25 +186,25 @@ function useGramThreadHistoryAdapter(
186
186
  * This properly handles React component identity for the Provider.
187
187
  */
188
188
  export function useGramThreadListAdapter(
189
- options: ThreadListAdapterOptions
189
+ options: ThreadListAdapterOptions,
190
190
  ): RemoteThreadListAdapter {
191
- const optionsRef = useRef(options)
191
+ const optionsRef = useRef(options);
192
192
  useEffect(() => {
193
- optionsRef.current = options
194
- }, [options])
193
+ optionsRef.current = options;
194
+ }, [options]);
195
195
 
196
196
  // Create stable Provider component using useCallback
197
197
  const unstable_Provider = useCallback(function GramHistoryProvider({
198
198
  children,
199
199
  }: PropsWithChildren) {
200
- const history = useGramThreadHistoryAdapter(optionsRef)
201
- const adapters = useMemo(() => ({ history }), [history])
200
+ const history = useGramThreadHistoryAdapter(optionsRef);
201
+ const adapters = useMemo(() => ({ history }), [history]);
202
202
  return (
203
203
  <RuntimeAdapterProvider adapters={adapters}>
204
204
  {children}
205
205
  </RuntimeAdapterProvider>
206
- )
207
- }, [])
206
+ );
207
+ }, []);
208
208
 
209
209
  // Return adapter with stable methods
210
210
  return useMemo(
@@ -217,26 +217,26 @@ export function useGramThreadListAdapter(
217
217
  `${optionsRef.current.apiUrl}/rpc/chat.list`,
218
218
  {
219
219
  headers: optionsRef.current.headers,
220
- }
221
- )
220
+ },
221
+ );
222
222
 
223
223
  if (!response.ok) {
224
- console.error('Failed to list chats:', response.status)
225
- return { threads: [] }
224
+ console.error("Failed to list chats:", response.status);
225
+ return { threads: [] };
226
226
  }
227
227
 
228
- const data = (await response.json()) as ListChatsResponse
228
+ const data = (await response.json()) as ListChatsResponse;
229
229
  return {
230
230
  threads: data.chats.map((chat) => ({
231
231
  remoteId: chat.id,
232
232
  externalId: chat.id,
233
- status: 'regular' as const,
234
- title: chat.title || 'New Chat',
233
+ status: "regular" as const,
234
+ title: chat.title || "New Chat",
235
235
  })),
236
- }
236
+ };
237
237
  } catch (error) {
238
- console.error('Error listing chats:', error)
239
- return { threads: [] }
238
+ console.error("Error listing chats:", error);
239
+ return { threads: [] };
240
240
  }
241
241
  },
242
242
 
@@ -245,26 +245,26 @@ export function useGramThreadListAdapter(
245
245
  if (isLocalThreadId(threadId)) {
246
246
  // Check if transport already generated a UUID for this local ID
247
247
  const existingUuid =
248
- optionsRef.current.localIdToUuidMap?.get(threadId)
248
+ optionsRef.current.localIdToUuidMap?.get(threadId);
249
249
  if (existingUuid) {
250
250
  return {
251
251
  remoteId: existingUuid,
252
252
  externalId: existingUuid,
253
- }
253
+ };
254
254
  }
255
255
  // Otherwise generate a new one and store it
256
- const uuid = crypto.randomUUID()
257
- optionsRef.current.localIdToUuidMap?.set(threadId, uuid)
256
+ const uuid = crypto.randomUUID();
257
+ optionsRef.current.localIdToUuidMap?.set(threadId, uuid);
258
258
  return {
259
259
  remoteId: uuid,
260
260
  externalId: uuid,
261
- }
261
+ };
262
262
  }
263
263
  // For existing threads, use the ID as-is
264
264
  return {
265
265
  remoteId: threadId,
266
266
  externalId: threadId,
267
- }
267
+ };
268
268
  },
269
269
 
270
270
  async rename() {
@@ -286,53 +286,53 @@ export function useGramThreadListAdapter(
286
286
  async generateTitle(
287
287
  remoteId: string,
288
288
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
289
- _messages: readonly ThreadMessage[]
289
+ _messages: readonly ThreadMessage[],
290
290
  ): Promise<AssistantStream> {
291
291
  // Skip if this is a local ID that hasn't been persisted yet
292
292
  if (!remoteId || isLocalThreadId(remoteId)) {
293
293
  return createAssistantStream((controller) => {
294
- controller.close()
295
- })
294
+ controller.close();
295
+ });
296
296
  }
297
297
 
298
298
  // Title generation happens async server-side via Temporal after first completion.
299
299
  // This delay allows the OpenRouter LLM call to complete before we fetch the title.
300
- const TITLE_GENERATION_DELAY_MS = 2000
301
- await new Promise((r) => setTimeout(r, TITLE_GENERATION_DELAY_MS))
300
+ const TITLE_GENERATION_DELAY_MS = 2000;
301
+ await new Promise((r) => setTimeout(r, TITLE_GENERATION_DELAY_MS));
302
302
 
303
303
  try {
304
304
  // TODO: rename generateTitle endpoint to getTitle
305
305
  const response = await fetch(
306
306
  `${optionsRef.current.apiUrl}/rpc/chat.generateTitle`,
307
307
  {
308
- method: 'POST',
308
+ method: "POST",
309
309
  headers: {
310
310
  ...optionsRef.current.headers,
311
- 'Content-Type': 'application/json',
311
+ "Content-Type": "application/json",
312
312
  },
313
313
  body: JSON.stringify({ id: remoteId }),
314
- }
315
- )
314
+ },
315
+ );
316
316
 
317
317
  if (response.ok) {
318
- const result = (await response.json()) as { title: string }
319
- const title = result.title
318
+ const result = (await response.json()) as { title: string };
319
+ const title = result.title;
320
320
 
321
321
  if (title) {
322
322
  return createAssistantStream((controller) => {
323
- controller.appendText(title)
324
- controller.close()
325
- })
323
+ controller.appendText(title);
324
+ controller.close();
325
+ });
326
326
  }
327
327
  }
328
328
  } catch (error) {
329
- console.error('Error fetching title:', error)
329
+ console.error("Error fetching title:", error);
330
330
  }
331
331
 
332
332
  // If title fetch failed or got placeholder, return empty stream (keeps existing title)
333
333
  return createAssistantStream((controller) => {
334
- controller.close()
335
- })
334
+ controller.close();
335
+ });
336
336
  },
337
337
 
338
338
  async fetch(threadId: string) {
@@ -340,8 +340,8 @@ export function useGramThreadListAdapter(
340
340
  if (!threadId || isLocalThreadId(threadId)) {
341
341
  return {
342
342
  remoteId: threadId,
343
- status: 'regular' as const,
344
- }
343
+ status: "regular" as const,
344
+ };
345
345
  }
346
346
 
347
347
  try {
@@ -349,33 +349,33 @@ export function useGramThreadListAdapter(
349
349
  `${optionsRef.current.apiUrl}/rpc/chat.load?id=${encodeURIComponent(threadId)}`,
350
350
  {
351
351
  headers: optionsRef.current.headers,
352
- }
353
- )
352
+ },
353
+ );
354
354
 
355
355
  if (!response.ok) {
356
- console.error('Failed to fetch thread:', response.status)
356
+ console.error("Failed to fetch thread:", response.status);
357
357
  return {
358
358
  remoteId: threadId,
359
- status: 'regular' as const,
360
- }
359
+ status: "regular" as const,
360
+ };
361
361
  }
362
362
 
363
- const chat = await response.json()
363
+ const chat = await response.json();
364
364
  return {
365
365
  remoteId: chat.id,
366
366
  externalId: chat.id,
367
- status: 'regular' as const,
368
- title: chat.title || 'New Chat',
369
- }
367
+ status: "regular" as const,
368
+ title: chat.title || "New Chat",
369
+ };
370
370
  } catch (error) {
371
- console.error('Error fetching thread:', error)
371
+ console.error("Error fetching thread:", error);
372
372
  return {
373
373
  remoteId: threadId,
374
- status: 'regular' as const,
375
- }
374
+ status: "regular" as const,
375
+ };
376
376
  }
377
377
  },
378
378
  }),
379
- [unstable_Provider]
380
- )
379
+ [unstable_Provider],
380
+ );
381
381
  }
@@ -1,13 +1,13 @@
1
- import { assert } from '@/lib/utils'
2
- import { ToolsFilter } from '@/types'
3
- import { experimental_createMCPClient as createMCPClient } from '@ai-sdk/mcp'
4
- import { useQuery, type UseQueryResult } from '@tanstack/react-query'
5
- import { useMemo, useRef } from 'react'
6
- import { Auth } from './useAuth'
1
+ import { assert } from "@/lib/utils";
2
+ import { ToolsFilter } from "@/types";
3
+ import { experimental_createMCPClient as createMCPClient } from "@ai-sdk/mcp";
4
+ import { useQuery, type UseQueryResult } from "@tanstack/react-query";
5
+ import { useMemo, useRef } from "react";
6
+ import { Auth } from "./useAuth";
7
7
 
8
8
  type MCPToolsResult = Awaited<
9
- ReturnType<Awaited<ReturnType<typeof createMCPClient>>['tools']>
10
- >
9
+ ReturnType<Awaited<ReturnType<typeof createMCPClient>>["tools"]>
10
+ >;
11
11
 
12
12
  export function useMCPTools({
13
13
  auth,
@@ -16,108 +16,108 @@ export function useMCPTools({
16
16
  toolsToInclude,
17
17
  gramEnvironment,
18
18
  }: {
19
- auth: Auth
20
- mcp: string | undefined
21
- environment: Record<string, unknown>
22
- toolsToInclude?: ToolsFilter
23
- gramEnvironment?: string
19
+ auth: Auth;
20
+ mcp: string | undefined;
21
+ environment: Record<string, unknown>;
22
+ toolsToInclude?: ToolsFilter;
23
+ gramEnvironment?: string;
24
24
  }): UseQueryResult<MCPToolsResult, Error> & {
25
- mcpHeaders: Record<string, string>
25
+ mcpHeaders: Record<string, string>;
26
26
  } {
27
27
  const envQueryKey = Object.entries(environment ?? {}).map(
28
- ([k, v]) => `${k}:${v}`
29
- )
28
+ ([k, v]) => `${k}:${v}`,
29
+ );
30
30
  const authQueryKey = Object.entries(auth.headers ?? {}).map(
31
- ([k, v]) => `${k}:${v}`
32
- )
31
+ ([k, v]) => `${k}:${v}`,
32
+ );
33
33
 
34
34
  // Mutable headers object shared with the MCP transport. The transport stores
35
35
  // a direct reference (`this.headers = headers`) and spreads it on every
36
36
  // send() call, so mutating properties on this object (e.g. setting
37
37
  // Gram-Chat-ID later) will be picked up by subsequent tool call requests.
38
- const mcpHeaders = useRef<Record<string, string>>({}).current
38
+ const mcpHeaders = useRef<Record<string, string>>({}).current;
39
39
 
40
40
  const queryResult = useQuery({
41
41
  queryKey: [
42
- 'mcpTools',
42
+ "mcpTools",
43
43
  mcp,
44
44
  gramEnvironment,
45
45
  ...envQueryKey,
46
46
  ...authQueryKey,
47
47
  ],
48
48
  queryFn: async () => {
49
- assert(!auth.isLoading, 'No auth found')
50
- assert(mcp, 'No MCP URL found')
49
+ assert(!auth.isLoading, "No auth found");
50
+ assert(mcp, "No MCP URL found");
51
51
 
52
52
  // Populate the shared headers object (mutate in place so the same
53
53
  // reference is used by the transport).
54
- Object.keys(mcpHeaders).forEach((k) => delete mcpHeaders[k])
54
+ Object.keys(mcpHeaders).forEach((k) => delete mcpHeaders[k]);
55
55
  Object.assign(mcpHeaders, {
56
56
  ...transformEnvironmentToHeaders(environment ?? {}),
57
57
  ...auth.headers,
58
- ...(gramEnvironment && { 'Gram-Environment': gramEnvironment }),
59
- })
58
+ ...(gramEnvironment && { "Gram-Environment": gramEnvironment }),
59
+ });
60
60
 
61
61
  const mcpClient = await createMCPClient({
62
- name: 'gram-elements-mcp-client',
62
+ name: "gram-elements-mcp-client",
63
63
  transport: {
64
- type: 'http',
64
+ type: "http",
65
65
  url: mcp,
66
66
  headers: mcpHeaders,
67
67
  },
68
- })
68
+ });
69
69
 
70
- return mcpClient.tools()
70
+ return mcpClient.tools();
71
71
  },
72
72
  enabled: !auth.isLoading && !!mcp,
73
73
  staleTime: Infinity,
74
74
  gcTime: Infinity,
75
- })
75
+ });
76
76
 
77
77
  // Filter tools outside of the query to ensure filtering is applied whenever
78
78
  // toolsToInclude changes, even when the cached query result is reused.
79
79
  const tools = useMemo(() => {
80
80
  if (!queryResult.data || !toolsToInclude) {
81
- return queryResult.data
81
+ return queryResult.data;
82
82
  }
83
83
 
84
84
  return Object.fromEntries(
85
85
  Object.entries(queryResult.data).filter(([name]) =>
86
- typeof toolsToInclude === 'function'
86
+ typeof toolsToInclude === "function"
87
87
  ? toolsToInclude({ toolName: name })
88
- : toolsToInclude.includes(name)
89
- )
90
- )
91
- }, [queryResult.data, toolsToInclude])
88
+ : toolsToInclude.includes(name),
89
+ ),
90
+ );
91
+ }, [queryResult.data, toolsToInclude]);
92
92
 
93
93
  return {
94
94
  ...queryResult,
95
95
  data: tools,
96
96
  mcpHeaders,
97
97
  } as UseQueryResult<MCPToolsResult, Error> & {
98
- mcpHeaders: Record<string, string>
99
- }
98
+ mcpHeaders: Record<string, string>;
99
+ };
100
100
  }
101
101
 
102
- const HEADER_PREFIX = 'MCP-'
102
+ const HEADER_PREFIX = "MCP-";
103
103
 
104
104
  function transformEnvironmentToHeaders(environment: Record<string, unknown>) {
105
- if (typeof environment !== 'object' || environment === null) {
106
- return {}
105
+ if (typeof environment !== "object" || environment === null) {
106
+ return {};
107
107
  }
108
108
  return Object.entries(environment).reduce(
109
109
  (acc, [key, value]) => {
110
110
  // Normalize key: replace underscores with dashes
111
- const normalizedKey = key.replace(/_/g, '-')
111
+ const normalizedKey = key.replace(/_/g, "-");
112
112
 
113
113
  // Add MCP- prefix if it doesn't already have it
114
114
  const headerKey = normalizedKey.startsWith(HEADER_PREFIX)
115
115
  ? normalizedKey
116
- : `${HEADER_PREFIX}${normalizedKey}`
116
+ : `${HEADER_PREFIX}${normalizedKey}`;
117
117
 
118
- acc[headerKey] = value as string
119
- return acc
118
+ acc[headerKey] = value as string;
119
+ return acc;
120
120
  },
121
- {} as Record<string, string>
122
- )
121
+ {} as Record<string, string>,
122
+ );
123
123
  }
@@ -1,30 +1,30 @@
1
- import { getApiUrl } from '@/lib/api'
2
- import { createOpenRouter } from '@openrouter/ai-sdk-provider'
3
- import { LanguageModel } from 'ai'
4
- import { useAuth } from './useAuth'
5
- import { useElements } from './useElements'
1
+ import { getApiUrl } from "@/lib/api";
2
+ import { createOpenRouter } from "@openrouter/ai-sdk-provider";
3
+ import { LanguageModel } from "ai";
4
+ import { useAuth } from "./useAuth";
5
+ import { useElements } from "./useElements";
6
6
 
7
7
  // Creates an OpenRouter client to be used for "internal Gram" usage, such as follow-on suggestions
8
8
  export const useModel = (
9
- model: string = 'openai/gpt-4o-mini'
9
+ model: string = "openai/gpt-5.4-mini",
10
10
  ): LanguageModel => {
11
- const { config } = useElements()
11
+ const { config } = useElements();
12
12
 
13
13
  const auth = useAuth({
14
14
  auth: config.api,
15
15
  projectSlug: config.projectSlug,
16
- })
16
+ });
17
17
 
18
- const apiUrl = getApiUrl(config)
18
+ const apiUrl = getApiUrl(config);
19
19
 
20
20
  const openRouter = createOpenRouter({
21
21
  baseURL: apiUrl,
22
- apiKey: 'unused, but must be set',
22
+ apiKey: "unused, but must be set",
23
23
  headers: {
24
24
  ...auth.headers,
25
- 'X-Gram-Source': 'gram',
25
+ "X-Gram-Source": "gram",
26
26
  },
27
- })
27
+ });
28
28
 
29
- return openRouter.chat(model)
30
- }
29
+ return openRouter.chat(model) as LanguageModel;
30
+ };
@@ -1,25 +1,25 @@
1
1
  import {
2
2
  CodeHeaderProps,
3
3
  SyntaxHighlighterProps,
4
- } from '@assistant-ui/react-markdown'
5
- import { ComponentType, useMemo } from 'react'
6
- import { Plugin } from '@/types/plugins'
4
+ } from "@assistant-ui/react-markdown";
5
+ import { ComponentType, useMemo } from "react";
6
+ import { Plugin } from "@/types/plugins";
7
7
 
8
8
  type ComponentsByLanguage =
9
9
  | Record<
10
10
  string,
11
11
  {
12
- CodeHeader?: ComponentType<CodeHeaderProps> | undefined
13
- SyntaxHighlighter?: ComponentType<SyntaxHighlighterProps> | undefined
12
+ CodeHeader?: ComponentType<CodeHeaderProps> | undefined;
13
+ SyntaxHighlighter?: ComponentType<SyntaxHighlighterProps> | undefined;
14
14
  }
15
15
  >
16
- | undefined
16
+ | undefined;
17
17
 
18
18
  export function useComponentsByLanguage(plugins: Plugin[]) {
19
19
  return useMemo(() => {
20
20
  return plugins.reduce((acc, plugin) => {
21
21
  if (acc?.[plugin.language] && !plugin.overrideExisting) {
22
- return acc
22
+ return acc;
23
23
  }
24
24
  acc = {
25
25
  ...acc,
@@ -27,8 +27,8 @@ export function useComponentsByLanguage(plugins: Plugin[]) {
27
27
  CodeHeader: plugin.Header ?? (() => null),
28
28
  SyntaxHighlighter: plugin.Component ?? undefined,
29
29
  },
30
- }
31
- return acc
32
- }, {} as ComponentsByLanguage)
33
- }, [plugins])
30
+ };
31
+ return acc;
32
+ }, {} as ComponentsByLanguage);
33
+ }, [plugins]);
34
34
  }