@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
@@ -18,206 +18,206 @@ import type {
18
18
  ThreadUserMessagePart,
19
19
  ThreadAssistantMessagePart,
20
20
  TextMessagePart,
21
- } from '@assistant-ui/react'
21
+ } from "@assistant-ui/react";
22
22
  import type {
23
23
  Message,
24
24
  UserMessage,
25
25
  AssistantMessage,
26
26
  ToolResponseMessage,
27
- } from '@openrouter/sdk/models'
28
- import { UIMessage } from 'ai'
27
+ } from "@openrouter/sdk/models";
28
+ import { UIMessage } from "ai";
29
29
 
30
30
  /**
31
31
  * Represents a chat message from the Gram API.
32
32
  * This mirrors the ChatMessage type from @gram/sdk without requiring the SDK dependency.
33
33
  */
34
34
  export type GramChatMessage = Message & {
35
- id: string
36
- model: string
37
- created_at: Date | string
38
- }
35
+ id: string;
36
+ model: string;
37
+ created_at: Date | string;
38
+ };
39
39
 
40
40
  /**
41
41
  * Represents a chat from the Gram API.
42
42
  */
43
43
  export interface GramChat {
44
- id: string
45
- title: string
46
- userId: string
47
- numMessages: number
48
- messages: GramChatMessage[]
49
- createdAt: Date | string
50
- updatedAt: Date | string
44
+ id: string;
45
+ title: string;
46
+ userId: string;
47
+ numMessages: number;
48
+ messages: GramChatMessage[];
49
+ createdAt: Date | string;
50
+ updatedAt: Date | string;
51
51
  }
52
52
 
53
53
  /**
54
54
  * Represents a chat overview from the Gram API (without full messages).
55
55
  */
56
56
  export interface GramChatOverview {
57
- id: string
58
- title: string
59
- userId: string
60
- numMessages: number
61
- createdAt: Date | string
62
- updatedAt: Date | string
57
+ id: string;
58
+ title: string;
59
+ userId: string;
60
+ numMessages: number;
61
+ createdAt: Date | string;
62
+ updatedAt: Date | string;
63
63
  }
64
64
 
65
65
  /**
66
66
  * Parses a date that might be a string or Date object.
67
67
  */
68
68
  function parseDate(date: Date | string): Date {
69
- return typeof date === 'string' ? new Date(date) : date
69
+ return typeof date === "string" ? new Date(date) : date;
70
70
  }
71
71
 
72
72
  /**
73
73
  * Builds content parts for a user message.
74
74
  */
75
75
  function buildUserContentParts(msg: GramChatMessage): ThreadUserMessagePart[] {
76
- if (msg.role !== 'user') {
77
- return []
76
+ if (msg.role !== "user") {
77
+ return [];
78
78
  }
79
79
 
80
- if (typeof msg.content === 'string' || !msg.content) {
80
+ if (typeof msg.content === "string" || !msg.content) {
81
81
  return [
82
82
  {
83
- type: 'text',
84
- text: msg.content ?? '',
83
+ type: "text",
84
+ text: msg.content ?? "",
85
85
  },
86
- ]
86
+ ];
87
87
  }
88
88
 
89
- const parts: ThreadUserMessagePart[] = []
89
+ const parts: ThreadUserMessagePart[] = [];
90
90
 
91
91
  for (const item of msg.content) {
92
92
  switch (item.type) {
93
- case 'text':
93
+ case "text":
94
94
  parts.push({
95
- type: 'text',
95
+ type: "text",
96
96
  text: item.text,
97
- })
98
- break
99
- case 'image_url':
97
+ });
98
+ break;
99
+ case "image_url":
100
100
  parts.push({
101
- type: 'image',
101
+ type: "image",
102
102
  image: (item as any).image_url?.url as FIXME<
103
103
  string,
104
- 'Fixed by switching to Gram TS SDK.'
104
+ "Fixed by switching to Gram TS SDK."
105
105
  >,
106
- })
107
- break
108
- case 'input_audio': {
106
+ });
107
+ break;
108
+ case "input_audio": {
109
109
  const format = (item as any).input_audio?.format as FIXME<
110
110
  string,
111
- 'Fixed by switching to Gram TS SDK.'
112
- >
113
- if (format === 'mp3' || format === 'wav') {
111
+ "Fixed by switching to Gram TS SDK."
112
+ >;
113
+ if (format === "mp3" || format === "wav") {
114
114
  parts.push({
115
- type: 'audio',
115
+ type: "audio",
116
116
  audio: {
117
117
  data: (item as any).input_audio.data as FIXME<
118
118
  string,
119
- 'Fixed by switching to Gram TS SDK.'
119
+ "Fixed by switching to Gram TS SDK."
120
120
  >,
121
121
  format: format,
122
122
  },
123
- })
123
+ });
124
124
  }
125
- break
125
+ break;
126
126
  }
127
127
  default:
128
128
  parts.push({
129
- type: 'text',
130
- text: '',
131
- })
132
- break
129
+ type: "text",
130
+ text: "",
131
+ });
132
+ break;
133
133
  }
134
134
  }
135
135
 
136
- return parts
136
+ return parts;
137
137
  }
138
138
 
139
139
  /**
140
140
  * Builds content parts for an assistant message, including tool calls.
141
141
  */
142
142
  function buildAssistantContentParts(
143
- msg: GramChatMessage
143
+ msg: GramChatMessage,
144
144
  ): ThreadAssistantMessagePart[] {
145
- if (msg.role !== 'assistant') {
146
- return []
145
+ if (msg.role !== "assistant") {
146
+ return [];
147
147
  }
148
148
 
149
- const parts: ThreadAssistantMessagePart[] = []
149
+ const parts: ThreadAssistantMessagePart[] = [];
150
150
 
151
- if (typeof msg.content === 'string' || !msg.content) {
151
+ if (typeof msg.content === "string" || !msg.content) {
152
152
  parts.push({
153
- type: 'text',
154
- text: msg.content ?? '',
155
- })
153
+ type: "text",
154
+ text: msg.content ?? "",
155
+ });
156
156
  }
157
157
 
158
158
  const toolCallsJSON = (msg as any).tool_calls as FIXME<
159
159
  string | undefined,
160
- 'Fixed by switching to Gram TS SDK.'
161
- >
160
+ "Fixed by switching to Gram TS SDK."
161
+ >;
162
162
 
163
- let toolCalls = tryParseJSON(toolCallsJSON || '[]')
163
+ let toolCalls = tryParseJSON(toolCallsJSON || "[]");
164
164
  if (!Array.isArray(toolCalls)) {
165
- console.warn('Invalid tool_calls format, expected an array.')
166
- toolCalls = []
165
+ console.warn("Invalid tool_calls format, expected an array.");
166
+ toolCalls = [];
167
167
  }
168
168
 
169
169
  for (const tc of toolCalls) {
170
- const args = tc.function?.arguments ?? tc.args ?? {}
171
- const argsText = typeof args === 'string' ? args : JSON.stringify(args)
170
+ const args = tc.function?.arguments ?? tc.args ?? {};
171
+ const argsText = typeof args === "string" ? args : JSON.stringify(args);
172
172
  parts.push({
173
- type: 'tool-call',
174
- toolCallId: tc.id ?? tc.toolCallId ?? '',
175
- toolName: tc.function?.name ?? tc.toolName ?? '',
176
- args: typeof args === 'string' ? JSON.parse(args) : args,
173
+ type: "tool-call",
174
+ toolCallId: tc.id ?? tc.toolCallId ?? "",
175
+ toolName: tc.function?.name ?? tc.toolName ?? "",
176
+ args: typeof args === "string" ? JSON.parse(args) : args,
177
177
  argsText,
178
178
  result: undefined,
179
- } as ThreadAssistantMessagePart)
179
+ } as ThreadAssistantMessagePart);
180
180
  }
181
181
 
182
182
  // Return at least an empty text part if no content
183
183
  if (parts.length === 0) {
184
184
  parts.push({
185
- type: 'text',
186
- text: '',
187
- } as TextMessagePart)
185
+ type: "text",
186
+ text: "",
187
+ } as TextMessagePart);
188
188
  }
189
189
 
190
- return parts
190
+ return parts;
191
191
  }
192
192
 
193
193
  function buildSystemContentParts(msg: GramChatMessage): [TextMessagePart] {
194
- if (msg.role !== 'system') {
195
- return [{ type: 'text', text: '' }]
194
+ if (msg.role !== "system") {
195
+ return [{ type: "text", text: "" }];
196
196
  }
197
197
 
198
- if (typeof msg.content === 'string' || !msg.content) {
199
- return [{ type: 'text', text: msg.content ?? '' }]
198
+ if (typeof msg.content === "string" || !msg.content) {
199
+ return [{ type: "text", text: msg.content ?? "" }];
200
200
  }
201
201
 
202
- const text: string[] = []
202
+ const text: string[] = [];
203
203
 
204
204
  for (const item of msg.content) {
205
- if (item.type !== 'text') {
206
- continue
205
+ if (item.type !== "text") {
206
+ continue;
207
207
  }
208
- text.push(item.text)
208
+ text.push(item.text);
209
209
  }
210
210
 
211
- return [{ type: 'text', text: text.join('\n') }]
211
+ return [{ type: "text", text: text.join("\n") }];
212
212
  }
213
213
 
214
214
  /**
215
215
  * Converts a single Gram ChatMessage to a ThreadMessage.
216
216
  */
217
217
  function convertGramMessageToThreadMessage(
218
- msg: GramChatMessage
218
+ msg: GramChatMessage,
219
219
  ): ThreadMessage {
220
- const createdAt = parseDate(msg.created_at)
220
+ const createdAt = parseDate(msg.created_at);
221
221
 
222
222
  const baseMetadata = {
223
223
  unstable_state: undefined,
@@ -226,36 +226,36 @@ function convertGramMessageToThreadMessage(
226
226
  steps: undefined,
227
227
  submittedFeedback: undefined,
228
228
  custom: {},
229
- }
229
+ };
230
230
 
231
- if (msg.role === 'user') {
231
+ if (msg.role === "user") {
232
232
  return {
233
233
  id: msg.id,
234
- role: 'user',
234
+ role: "user",
235
235
  createdAt,
236
236
  content: buildUserContentParts(msg),
237
237
  attachments: [],
238
238
  metadata: baseMetadata,
239
- }
239
+ };
240
240
  }
241
241
 
242
- if (msg.role === 'system') {
242
+ if (msg.role === "system") {
243
243
  return {
244
244
  id: msg.id,
245
- role: 'system',
245
+ role: "system",
246
246
  createdAt,
247
247
  content: buildSystemContentParts(msg),
248
248
  metadata: baseMetadata,
249
- }
249
+ };
250
250
  }
251
251
 
252
252
  // Assistant message
253
253
  return {
254
254
  id: msg.id,
255
- role: 'assistant',
255
+ role: "assistant",
256
256
  createdAt,
257
257
  content: buildAssistantContentParts(msg),
258
- status: { type: 'complete', reason: 'stop' },
258
+ status: { type: "complete", reason: "stop" },
259
259
  metadata: {
260
260
  unstable_state: null,
261
261
  unstable_annotations: [],
@@ -264,7 +264,7 @@ function convertGramMessageToThreadMessage(
264
264
  submittedFeedback: undefined,
265
265
  custom: {},
266
266
  },
267
- }
267
+ };
268
268
  }
269
269
 
270
270
  /**
@@ -275,252 +275,252 @@ function convertGramMessageToThreadMessage(
275
275
  * `fromThreadMessageLike` doesn't support them in the exported format.
276
276
  */
277
277
  export function convertGramMessagesToExported(
278
- messages: GramChatMessage[]
278
+ messages: GramChatMessage[],
279
279
  ): ExportedMessageRepository {
280
280
  if (messages.length === 0) {
281
- return { messages: [], headId: null }
281
+ return { messages: [], headId: null };
282
282
  }
283
283
 
284
- const exportedMessages: ExportedMessageRepository['messages'] = []
285
- let prevId: string | null = null
284
+ const exportedMessages: ExportedMessageRepository["messages"] = [];
285
+ let prevId: string | null = null;
286
286
 
287
287
  for (const msg of messages) {
288
288
  // Skip system messages - they're not supported in the exported message format
289
- if (msg.role === 'system') {
290
- continue
289
+ if (msg.role === "system") {
290
+ continue;
291
291
  }
292
292
 
293
- const threadMessage = convertGramMessageToThreadMessage(msg)
293
+ const threadMessage = convertGramMessageToThreadMessage(msg);
294
294
  exportedMessages.push({
295
295
  message: threadMessage,
296
296
  parentId: prevId,
297
297
  runConfig: undefined,
298
- })
299
- prevId = msg.id
298
+ });
299
+ prevId = msg.id;
300
300
  }
301
301
 
302
302
  return {
303
303
  messages: exportedMessages,
304
304
  headId: prevId,
305
- }
305
+ };
306
306
  }
307
307
 
308
308
  export function convertGramMessagesToUIMessages(messages: GramChatMessage[]): {
309
- headId: string | null
310
- messages: { parentId: string | null; message: UIMessage }[]
309
+ headId: string | null;
310
+ messages: { parentId: string | null; message: UIMessage }[];
311
311
  } {
312
312
  if (messages.length === 0) {
313
- return { messages: [], headId: null }
313
+ return { messages: [], headId: null };
314
314
  }
315
315
 
316
- const toolCallResults = new Map<string, ToolResponseMessage>()
316
+ const toolCallResults = new Map<string, ToolResponseMessage>();
317
317
  for (const msg of messages) {
318
- if (msg.role !== 'tool') {
319
- continue
318
+ if (msg.role !== "tool") {
319
+ continue;
320
320
  }
321
- const id = (msg as any).tool_call_id
322
- if (typeof id !== 'string') {
323
- continue
321
+ const id = (msg as any).tool_call_id;
322
+ if (typeof id !== "string") {
323
+ continue;
324
324
  }
325
325
 
326
- toolCallResults.set(id, msg as ToolResponseMessage)
326
+ toolCallResults.set(id, msg as ToolResponseMessage);
327
327
  }
328
328
 
329
- const uiMessages: { parentId: string | null; message: UIMessage }[] = []
330
- let prevId: string | null = null
329
+ const uiMessages: { parentId: string | null; message: UIMessage }[] = [];
330
+ let prevId: string | null = null;
331
331
 
332
332
  // Track tool call IDs across messages to deduplicate. The server accumulates
333
333
  // all tool calls from a turn into each message, so without this, every
334
334
  // assistant message in a multi-step tool use flow would show the full count.
335
- const seenToolCallIds = new Set<string>()
335
+ const seenToolCallIds = new Set<string>();
336
336
 
337
337
  for (const msg of messages) {
338
338
  switch (msg.role) {
339
- case 'developer':
340
- case 'tool':
341
- continue
342
- case 'system': {
339
+ case "developer":
340
+ case "tool":
341
+ continue;
342
+ case "system": {
343
343
  uiMessages.push({
344
344
  parentId: prevId,
345
345
  message: {
346
346
  id: msg.id,
347
- role: 'system',
347
+ role: "system",
348
348
  parts: [
349
349
  {
350
- type: 'text',
350
+ type: "text",
351
351
  text:
352
- typeof msg.content === 'string'
352
+ typeof msg.content === "string"
353
353
  ? msg.content
354
354
  : Array.isArray(msg.content)
355
355
  ? msg.content
356
- .filter((item) => item.type === 'text')
356
+ .filter((item) => item.type === "text")
357
357
  .map((item) => item.text)
358
- .join('\n')
359
- : '',
358
+ .join("\n")
359
+ : "",
360
360
  },
361
361
  ],
362
362
  },
363
- })
364
- break
363
+ });
364
+ break;
365
365
  }
366
- case 'user': {
367
- seenToolCallIds.clear()
366
+ case "user": {
367
+ seenToolCallIds.clear();
368
368
  uiMessages.push({
369
369
  parentId: prevId,
370
370
  message: {
371
371
  id: msg.id,
372
- role: 'user',
372
+ role: "user",
373
373
  parts: convertGramMessagePartsToUIMessageParts(
374
374
  msg,
375
- toolCallResults
375
+ toolCallResults,
376
376
  ),
377
377
  },
378
- })
379
- break
378
+ });
379
+ break;
380
380
  }
381
- case 'assistant': {
381
+ case "assistant": {
382
382
  const uiMessage = {
383
383
  parentId: prevId,
384
384
  message: {
385
385
  id: msg.id,
386
- role: 'assistant',
386
+ role: "assistant",
387
387
  parts: convertGramMessagePartsToUIMessageParts(
388
388
  msg,
389
389
  toolCallResults,
390
- seenToolCallIds
390
+ seenToolCallIds,
391
391
  ),
392
392
  } satisfies UIMessage,
393
- }
394
- uiMessages.push(uiMessage)
393
+ };
394
+ uiMessages.push(uiMessage);
395
395
 
396
- break
396
+ break;
397
397
  }
398
398
  }
399
399
 
400
- prevId = msg.id
400
+ prevId = msg.id;
401
401
  }
402
402
 
403
403
  return {
404
404
  messages: uiMessages,
405
405
  headId: prevId,
406
- }
406
+ };
407
407
  }
408
408
 
409
409
  export function convertGramMessagePartsToUIMessageParts(
410
410
  msg: UserMessage | AssistantMessage,
411
411
  toolResults: Map<string, ToolResponseMessage>,
412
- seenToolCallIds?: Set<string>
413
- ): UIMessage['parts'] {
414
- const uiparts: UIMessage['parts'] = []
412
+ seenToolCallIds?: Set<string>,
413
+ ): UIMessage["parts"] {
414
+ const uiparts: UIMessage["parts"] = [];
415
415
 
416
- if (typeof msg.content === 'string' && msg.content) {
416
+ if (typeof msg.content === "string" && msg.content) {
417
417
  uiparts.push({
418
- type: 'text',
418
+ type: "text",
419
419
  text: msg.content,
420
- })
420
+ });
421
421
  }
422
422
 
423
- const content = Array.isArray(msg.content) ? msg.content : []
423
+ const content = Array.isArray(msg.content) ? msg.content : [];
424
424
  for (const p of content) {
425
425
  switch (p.type) {
426
- case 'text': {
426
+ case "text": {
427
427
  uiparts.push({
428
- type: 'text',
428
+ type: "text",
429
429
  text: p.text,
430
- })
431
- break
430
+ });
431
+ break;
432
432
  }
433
- case 'image_url': {
433
+ case "image_url": {
434
434
  const url = (p as any).image_url?.url as FIXME<
435
435
  string | undefined,
436
- 'Fixed by switching to Gram TS SDK.'
437
- >
436
+ "Fixed by switching to Gram TS SDK."
437
+ >;
438
438
  if (!url) {
439
- break
439
+ break;
440
440
  }
441
441
 
442
442
  uiparts.push({
443
- type: 'file',
443
+ type: "file",
444
444
  url,
445
445
  mediaType: mediaTypeFromURL(url),
446
- })
447
- break
446
+ });
447
+ break;
448
448
  }
449
- case 'input_audio': {
449
+ case "input_audio": {
450
450
  const url = (p as any).input_audio?.data as FIXME<
451
451
  string | undefined,
452
- 'Fixed by switching to Gram TS SDK.'
453
- >
452
+ "Fixed by switching to Gram TS SDK."
453
+ >;
454
454
  if (!url) {
455
- break
455
+ break;
456
456
  }
457
457
 
458
458
  uiparts.push({
459
- type: 'file',
459
+ type: "file",
460
460
  url,
461
461
  mediaType: mediaTypeFromURL(url),
462
- })
463
- break
462
+ });
463
+ break;
464
464
  }
465
465
  }
466
466
  }
467
467
 
468
- if (msg.role === 'assistant' && msg.reasoning) {
468
+ if (msg.role === "assistant" && msg.reasoning) {
469
469
  uiparts.push({
470
- type: 'reasoning',
470
+ type: "reasoning",
471
471
  text: msg.reasoning,
472
- })
472
+ });
473
473
  }
474
474
 
475
- if (msg.role === 'assistant' && (msg as any).tool_calls) {
475
+ if (msg.role === "assistant" && (msg as any).tool_calls) {
476
476
  const toolCallsJSON = (msg as any).tool_calls as FIXME<
477
477
  string,
478
- 'Fixed by switching to Gram TS SDK.'
479
- >
480
- let toolCalls = tryParseJSON<AssistantMessage['toolCalls']>(
481
- toolCallsJSON || '[]'
482
- )
478
+ "Fixed by switching to Gram TS SDK."
479
+ >;
480
+ let toolCalls = tryParseJSON<AssistantMessage["toolCalls"]>(
481
+ toolCallsJSON || "[]",
482
+ );
483
483
  if (!Array.isArray(toolCalls)) {
484
- console.warn('Invalid tool_calls format, expected an array.')
485
- toolCalls = []
484
+ console.warn("Invalid tool_calls format, expected an array.");
485
+ toolCalls = [];
486
486
  }
487
487
 
488
488
  for (const tc of toolCalls) {
489
489
  // The server accumulates all tool calls from a turn into each message's
490
490
  // tool_calls field. Deduplicate across messages so each tool call only
491
491
  // appears in the first message that references it.
492
- if (seenToolCallIds?.has(tc.id)) continue
493
- seenToolCallIds?.add(tc.id)
492
+ if (seenToolCallIds?.has(tc.id)) continue;
493
+ seenToolCallIds?.add(tc.id);
494
494
 
495
- const content = toolResults.get(tc.id)?.content
495
+ const content = toolResults.get(tc.id)?.content;
496
496
  uiparts.push({
497
- type: 'dynamic-tool',
497
+ type: "dynamic-tool",
498
498
  toolCallId: tc.id,
499
- toolName: tc.function?.name ?? '',
500
- state: 'output-available',
499
+ toolName: tc.function?.name ?? "",
500
+ state: "output-available",
501
501
  input: tc.function?.arguments ?? {},
502
- output: typeof content === 'string' ? tryParseJSON(content) : '',
503
- })
502
+ output: typeof content === "string" ? tryParseJSON(content) : "",
503
+ });
504
504
  }
505
505
  }
506
506
 
507
- return uiparts
507
+ return uiparts;
508
508
  }
509
509
 
510
510
  function mediaTypeFromURL(url: string): string {
511
- const unspecified = 'unknown/unknown'
512
- if (!url.startsWith('data:')) {
513
- return unspecified
511
+ const unspecified = "unknown/unknown";
512
+ if (!url.startsWith("data:")) {
513
+ return unspecified;
514
514
  }
515
515
 
516
- const match = url.match(/^data:([^;]+);/)
517
- return match?.[1] || unspecified
516
+ const match = url.match(/^data:([^;]+);/);
517
+ return match?.[1] || unspecified;
518
518
  }
519
519
 
520
520
  function tryParseJSON<T = any>(str: string): T | null {
521
521
  try {
522
- return JSON.parse(str) as T
522
+ return JSON.parse(str) as T;
523
523
  } catch {
524
- return null
524
+ return null;
525
525
  }
526
526
  }