@gram-ai/elements 1.27.4 → 1.27.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. package/README.md +72 -60
  2. package/README.typedoc.md +6 -6
  3. package/bin/cli.js +74 -74
  4. package/dist/compat-shims-CO9JXXV4.cjs.map +1 -1
  5. package/dist/{compat-shims-BPJ7Q68c.js → compat-shims-DxtUrORi.js} +4 -2
  6. package/dist/compat-shims-DxtUrORi.js.map +1 -0
  7. package/dist/components/ShareButton/index.d.ts +2 -2
  8. package/dist/components/assistant-ui/message-feedback.d.ts +1 -1
  9. package/dist/components/assistant-ui/tooltip-icon-button.d.ts +2 -2
  10. package/dist/components/ui/avatar.d.ts +2 -2
  11. package/dist/components/ui/button.d.ts +1 -1
  12. package/dist/components/ui/calendar.d.ts +1 -1
  13. package/dist/components/ui/collapsible.d.ts +1 -1
  14. package/dist/components/ui/dialog.d.ts +4 -4
  15. package/dist/components/ui/popover.d.ts +2 -2
  16. package/dist/components/ui/skeleton.d.ts +1 -1
  17. package/dist/components/ui/time-range-picker.d.ts +1 -1
  18. package/dist/components/ui/tool-ui.d.ts +7 -7
  19. package/dist/components/ui/tooltip.d.ts +2 -2
  20. package/dist/contexts/ConnectionStatusContext.d.ts +1 -1
  21. package/dist/elements.cjs +1 -1
  22. package/dist/elements.js +2 -2
  23. package/dist/hooks/useDensity.d.ts +73 -73
  24. package/dist/hooks/useMCPTools.d.ts +1 -1
  25. package/dist/hooks/useRadius.d.ts +1 -1
  26. package/dist/{index-BpJstUh1.cjs → index-C4bFBGfl.cjs} +4 -4
  27. package/dist/{index-BpJstUh1.cjs.map → index-C4bFBGfl.cjs.map} +1 -1
  28. package/dist/{index-CUitXazZ.js → index-D93pV0_o.js} +55 -55
  29. package/dist/{index-CUitXazZ.js.map → index-D93pV0_o.js.map} +1 -1
  30. package/dist/{index-D0bAYNQy.js → index-DuCQRbcQ.js} +279 -265
  31. package/dist/index-DuCQRbcQ.js.map +1 -0
  32. package/dist/{index-KSX4Qjip.cjs → index-y_PNN5vK.cjs} +10 -10
  33. package/dist/index-y_PNN5vK.cjs.map +1 -0
  34. package/dist/lib/cassette.d.ts +4 -4
  35. package/dist/lib/errorTracking.d.ts +1 -1
  36. package/dist/lib/messageConverter.d.ts +1 -1
  37. package/dist/lib/models.d.ts +1 -1
  38. package/dist/plugins/chart/ui/bar-chart.d.ts +1 -1
  39. package/dist/plugins/generative-ui/ui/accordion-wrapper.d.ts +2 -2
  40. package/dist/plugins/generative-ui/ui/accordion.d.ts +1 -1
  41. package/dist/plugins/generative-ui/ui/action-button.d.ts +2 -2
  42. package/dist/plugins/generative-ui/ui/alert-wrapper.d.ts +1 -1
  43. package/dist/plugins/generative-ui/ui/alert.d.ts +4 -4
  44. package/dist/plugins/generative-ui/ui/avatar.d.ts +5 -5
  45. package/dist/plugins/generative-ui/ui/badge.d.ts +2 -2
  46. package/dist/plugins/generative-ui/ui/button-wrapper.d.ts +2 -2
  47. package/dist/plugins/generative-ui/ui/button.d.ts +2 -2
  48. package/dist/plugins/generative-ui/ui/card-wrapper.d.ts +2 -2
  49. package/dist/plugins/generative-ui/ui/card.d.ts +8 -8
  50. package/dist/plugins/generative-ui/ui/checkbox.d.ts +1 -1
  51. package/dist/plugins/generative-ui/ui/data-table.d.ts +2 -2
  52. package/dist/plugins/generative-ui/ui/dialog.d.ts +3 -3
  53. package/dist/plugins/generative-ui/ui/dropdown-menu.d.ts +3 -3
  54. package/dist/plugins/generative-ui/ui/grid.d.ts +3 -3
  55. package/dist/plugins/generative-ui/ui/input-wrapper.d.ts +1 -1
  56. package/dist/plugins/generative-ui/ui/input.d.ts +2 -2
  57. package/dist/plugins/generative-ui/ui/label.d.ts +1 -1
  58. package/dist/plugins/generative-ui/ui/metric.d.ts +3 -3
  59. package/dist/plugins/generative-ui/ui/pagination.d.ts +6 -6
  60. package/dist/plugins/generative-ui/ui/popover.d.ts +4 -4
  61. package/dist/plugins/generative-ui/ui/progress.d.ts +2 -2
  62. package/dist/plugins/generative-ui/ui/radio-group.d.ts +1 -1
  63. package/dist/plugins/generative-ui/ui/select.d.ts +2 -2
  64. package/dist/plugins/generative-ui/ui/separator.d.ts +1 -1
  65. package/dist/plugins/generative-ui/ui/skeleton.d.ts +1 -1
  66. package/dist/plugins/generative-ui/ui/stack.d.ts +6 -6
  67. package/dist/plugins/generative-ui/ui/switch.d.ts +2 -2
  68. package/dist/plugins/generative-ui/ui/table.d.ts +9 -9
  69. package/dist/plugins/generative-ui/ui/tabs-wrapper.d.ts +1 -1
  70. package/dist/plugins/generative-ui/ui/tabs.d.ts +1 -1
  71. package/dist/plugins/generative-ui/ui/text.d.ts +3 -3
  72. package/dist/plugins/generative-ui/ui/textarea.d.ts +2 -2
  73. package/dist/plugins/generative-ui/ui/tooltip.d.ts +1 -1
  74. package/dist/plugins.cjs +1 -1
  75. package/dist/plugins.js +1 -1
  76. package/dist/{profiler-BFkhZRxj.js → profiler-FpBY9eRv.js} +2 -2
  77. package/dist/{profiler-BFkhZRxj.js.map → profiler-FpBY9eRv.js.map} +1 -1
  78. package/dist/{profiler-CyzxBxVz.cjs → profiler-_mthyjvo.cjs} +2 -2
  79. package/dist/{profiler-CyzxBxVz.cjs.map → profiler-_mthyjvo.cjs.map} +1 -1
  80. package/dist/react-shim.js +1 -1
  81. package/dist/server/express.cjs.map +1 -1
  82. package/dist/server/express.js.map +1 -1
  83. package/dist/{startRecording-Dq92sEHf.cjs → startRecording-NJcpiHw-.cjs} +2 -2
  84. package/dist/{startRecording-Dq92sEHf.cjs.map → startRecording-NJcpiHw-.cjs.map} +1 -1
  85. package/dist/{startRecording-C-PPAs_Z.js → startRecording-r5MXQ2Dm.js} +2 -2
  86. package/dist/{startRecording-C-PPAs_Z.js.map → startRecording-r5MXQ2Dm.js.map} +1 -1
  87. package/dist/types/index.d.ts +2 -2
  88. package/package.json +1 -5
  89. package/src/compat-plugin.ts +14 -14
  90. package/src/compat-shims.ts +33 -31
  91. package/src/compat.test.ts +48 -48
  92. package/src/compat.ts +6 -6
  93. package/src/components/Chat/index.tsx +17 -17
  94. package/src/components/Chat/stories/Charts.stories.tsx +98 -98
  95. package/src/components/Chat/stories/Composer.stories.tsx +15 -15
  96. package/src/components/Chat/stories/ConnectionConfiguration.stories.tsx +44 -44
  97. package/src/components/Chat/stories/CustomComponents.stories.tsx +17 -17
  98. package/src/components/Chat/stories/Density.stories.tsx +20 -20
  99. package/src/components/Chat/stories/ErrorBoundary.stories.tsx +47 -47
  100. package/src/components/Chat/stories/FrontendTools.stories.tsx +39 -39
  101. package/src/components/Chat/stories/GenerativeUI.stories.tsx +48 -48
  102. package/src/components/Chat/stories/MessageFeedback.stories.tsx +52 -52
  103. package/src/components/Chat/stories/Modal.stories.tsx +28 -28
  104. package/src/components/Chat/stories/Model.stories.tsx +11 -11
  105. package/src/components/Chat/stories/Radius.stories.tsx +20 -20
  106. package/src/components/Chat/stories/Sidecar.stories.tsx +13 -13
  107. package/src/components/Chat/stories/StyleIsolation.stories.tsx +11 -11
  108. package/src/components/Chat/stories/Theme.stories.tsx +25 -25
  109. package/src/components/Chat/stories/Thread.stories.tsx +25 -25
  110. package/src/components/Chat/stories/ToolApproval.stories.tsx +55 -55
  111. package/src/components/Chat/stories/ToolMentions.stories.tsx +17 -17
  112. package/src/components/Chat/stories/Tools.stories.tsx +88 -88
  113. package/src/components/Chat/stories/Variants.stories.tsx +32 -32
  114. package/src/components/Chat/stories/Welcome.stories.tsx +14 -14
  115. package/src/components/ChatHistory.tsx +7 -7
  116. package/src/components/FrontendTools/index.tsx +5 -5
  117. package/src/components/Replay.stories.tsx +157 -157
  118. package/src/components/Replay.tsx +76 -73
  119. package/src/components/ShadowRoot.tsx +40 -40
  120. package/src/components/ShareButton/index.tsx +32 -32
  121. package/src/components/assistant-ui/assistant-modal.tsx +92 -87
  122. package/src/components/assistant-ui/assistant-sidecar.tsx +35 -35
  123. package/src/components/assistant-ui/attachment.tsx +80 -80
  124. package/src/components/assistant-ui/connection-status-indicator.tsx +33 -33
  125. package/src/components/assistant-ui/error-boundary.tsx +34 -34
  126. package/src/components/assistant-ui/follow-on-suggestions.tsx +26 -26
  127. package/src/components/assistant-ui/markdown-text.tsx +69 -69
  128. package/src/components/assistant-ui/mentioned-tools-badges.tsx +38 -38
  129. package/src/components/assistant-ui/message-feedback.tsx +57 -50
  130. package/src/components/assistant-ui/reasoning.tsx +83 -83
  131. package/src/components/assistant-ui/thread-list.tsx +45 -45
  132. package/src/components/assistant-ui/thread.tsx +278 -278
  133. package/src/components/assistant-ui/tool-fallback.tsx +37 -37
  134. package/src/components/assistant-ui/tool-group.tsx +26 -26
  135. package/src/components/assistant-ui/tool-mention-autocomplete.tsx +122 -122
  136. package/src/components/assistant-ui/tooltip-icon-button.tsx +18 -18
  137. package/src/components/ui/avatar.tsx +12 -12
  138. package/src/components/ui/button.tsx +12 -12
  139. package/src/components/ui/buttonVariants.ts +17 -17
  140. package/src/components/ui/calendar.tsx +106 -106
  141. package/src/components/ui/charts.stories.tsx +56 -56
  142. package/src/components/ui/collapsible.tsx +5 -5
  143. package/src/components/ui/dialog.tsx +30 -30
  144. package/src/components/ui/generative-ui.stories.tsx +200 -200
  145. package/src/components/ui/generative-ui.tsx +26 -26
  146. package/src/components/ui/popover.tsx +14 -14
  147. package/src/components/ui/skeleton.tsx +5 -5
  148. package/src/components/ui/time-range-picker.stories.tsx +80 -80
  149. package/src/components/ui/time-range-picker.tsx +245 -244
  150. package/src/components/ui/tool-ui.stories.tsx +37 -37
  151. package/src/components/ui/tool-ui.tsx +221 -215
  152. package/src/components/ui/tooltip.tsx +15 -15
  153. package/src/constants/tailwind.ts +1 -1
  154. package/src/contexts/ChatIdContext.tsx +7 -7
  155. package/src/contexts/ConnectionStatusContext.tsx +64 -64
  156. package/src/contexts/ElementsProvider.tsx +214 -213
  157. package/src/contexts/ReplayContext.ts +3 -3
  158. package/src/contexts/ToolApprovalContext.tsx +54 -54
  159. package/src/contexts/ToolExecutionContext.tsx +34 -34
  160. package/src/contexts/contexts.ts +7 -7
  161. package/src/contexts/portal-container-context.ts +2 -2
  162. package/src/contexts/portal-container.tsx +7 -7
  163. package/src/embedded.ts +1 -1
  164. package/src/global.css +25 -25
  165. package/src/hooks/useAuth.ts +72 -72
  166. package/src/hooks/useDensity.ts +79 -79
  167. package/src/hooks/useElements.ts +6 -6
  168. package/src/hooks/useExpanded.ts +12 -12
  169. package/src/hooks/useFollowOnSuggestions.ts +83 -83
  170. package/src/hooks/useGramThreadListAdapter.tsx +99 -99
  171. package/src/hooks/useMCPTools.ts +47 -47
  172. package/src/hooks/useModel.ts +14 -14
  173. package/src/hooks/usePluginComponents.ts +11 -11
  174. package/src/hooks/usePortalContainer.ts +5 -5
  175. package/src/hooks/useRadius.ts +23 -23
  176. package/src/hooks/useRecordCassette.ts +34 -34
  177. package/src/hooks/useSession.ts +11 -11
  178. package/src/hooks/useThemeProps.ts +13 -13
  179. package/src/hooks/useThreadId.ts +4 -4
  180. package/src/hooks/useToolApproval.ts +7 -7
  181. package/src/hooks/useToolMentions.ts +40 -40
  182. package/src/index.ts +26 -26
  183. package/src/lib/api.test.ts +61 -61
  184. package/src/lib/api.ts +4 -3
  185. package/src/lib/auth.ts +13 -13
  186. package/src/lib/cassette.ts +84 -84
  187. package/src/lib/easing.ts +1 -1
  188. package/src/lib/errorTracking.config.ts +5 -5
  189. package/src/lib/errorTracking.ts +29 -29
  190. package/src/lib/generative-ui.ts +7 -7
  191. package/src/lib/humanize.ts +3 -3
  192. package/src/lib/messageConverter.test.ts +130 -127
  193. package/src/lib/messageConverter.ts +196 -196
  194. package/src/lib/models.ts +21 -20
  195. package/src/lib/token.test.ts +56 -56
  196. package/src/lib/token.ts +14 -14
  197. package/src/lib/tool-mentions.ts +45 -45
  198. package/src/lib/tools.ts +66 -62
  199. package/src/lib/utils.ts +5 -5
  200. package/src/lib.d.ts +1 -1
  201. package/src/plugins/README.md +5 -5
  202. package/src/plugins/chart/catalog.ts +18 -18
  203. package/src/plugins/chart/chart.test.ts +31 -31
  204. package/src/plugins/chart/component.tsx +34 -34
  205. package/src/plugins/chart/index.ts +4 -4
  206. package/src/plugins/chart/ui/area-chart.tsx +42 -42
  207. package/src/plugins/chart/ui/bar-chart.tsx +46 -46
  208. package/src/plugins/chart/ui/donut-chart.tsx +48 -48
  209. package/src/plugins/chart/ui/index.ts +7 -7
  210. package/src/plugins/chart/ui/line-chart.tsx +43 -43
  211. package/src/plugins/chart/ui/pie-chart.tsx +44 -44
  212. package/src/plugins/chart/ui/radar-chart.tsx +33 -33
  213. package/src/plugins/chart/ui/scatter-chart.tsx +43 -43
  214. package/src/plugins/components/MacOSWindowFrame.tsx +15 -15
  215. package/src/plugins/components/PluginLoadingState.tsx +10 -10
  216. package/src/plugins/components/index.ts +1 -1
  217. package/src/plugins/generative-ui/catalog.ts +54 -54
  218. package/src/plugins/generative-ui/component.tsx +85 -85
  219. package/src/plugins/generative-ui/index.ts +4 -4
  220. package/src/plugins/generative-ui/ui/accordion-wrapper.tsx +16 -16
  221. package/src/plugins/generative-ui/ui/accordion.tsx +16 -16
  222. package/src/plugins/generative-ui/ui/action-button.tsx +28 -28
  223. package/src/plugins/generative-ui/ui/alert-wrapper.tsx +8 -8
  224. package/src/plugins/generative-ui/ui/alert.tsx +20 -20
  225. package/src/plugins/generative-ui/ui/avatar-wrapper.tsx +7 -7
  226. package/src/plugins/generative-ui/ui/avatar.tsx +30 -30
  227. package/src/plugins/generative-ui/ui/badge.tsx +22 -22
  228. package/src/plugins/generative-ui/ui/button-wrapper.tsx +12 -12
  229. package/src/plugins/generative-ui/ui/button.tsx +28 -28
  230. package/src/plugins/generative-ui/ui/card-wrapper.tsx +8 -8
  231. package/src/plugins/generative-ui/ui/card.tsx +27 -27
  232. package/src/plugins/generative-ui/ui/checkbox-wrapper.tsx +9 -9
  233. package/src/plugins/generative-ui/ui/checkbox.tsx +9 -9
  234. package/src/plugins/generative-ui/ui/data-table.tsx +8 -8
  235. package/src/plugins/generative-ui/ui/dialog.tsx +31 -31
  236. package/src/plugins/generative-ui/ui/dropdown-menu.tsx +44 -44
  237. package/src/plugins/generative-ui/ui/grid.tsx +12 -12
  238. package/src/plugins/generative-ui/ui/index.ts +40 -40
  239. package/src/plugins/generative-ui/ui/input-wrapper.tsx +11 -11
  240. package/src/plugins/generative-ui/ui/input.tsx +9 -9
  241. package/src/plugins/generative-ui/ui/label.tsx +8 -8
  242. package/src/plugins/generative-ui/ui/list.tsx +11 -11
  243. package/src/plugins/generative-ui/ui/metric.tsx +23 -23
  244. package/src/plugins/generative-ui/ui/pagination.tsx +28 -28
  245. package/src/plugins/generative-ui/ui/popover.tsx +21 -21
  246. package/src/plugins/generative-ui/ui/progress.tsx +13 -13
  247. package/src/plugins/generative-ui/ui/radio-group.tsx +12 -12
  248. package/src/plugins/generative-ui/ui/select-wrapper.tsx +7 -7
  249. package/src/plugins/generative-ui/ui/select.tsx +37 -37
  250. package/src/plugins/generative-ui/ui/separator.tsx +9 -9
  251. package/src/plugins/generative-ui/ui/skeleton-wrapper.tsx +10 -10
  252. package/src/plugins/generative-ui/ui/skeleton.tsx +5 -5
  253. package/src/plugins/generative-ui/ui/stack.tsx +28 -28
  254. package/src/plugins/generative-ui/ui/switch.tsx +11 -11
  255. package/src/plugins/generative-ui/ui/table.tsx +32 -32
  256. package/src/plugins/generative-ui/ui/tabs-wrapper.tsx +11 -11
  257. package/src/plugins/generative-ui/ui/tabs.tsx +26 -26
  258. package/src/plugins/generative-ui/ui/text.tsx +12 -12
  259. package/src/plugins/generative-ui/ui/textarea.tsx +7 -7
  260. package/src/plugins/generative-ui/ui/tooltip.tsx +12 -12
  261. package/src/plugins/index.ts +7 -7
  262. package/src/react-shim.ts +6 -6
  263. package/src/server/bun.ts +12 -12
  264. package/src/server/core.ts +25 -25
  265. package/src/server/express.ts +17 -15
  266. package/src/server/fastify.ts +14 -14
  267. package/src/server/hono.ts +9 -9
  268. package/src/server/nextjs.ts +12 -12
  269. package/src/server/tanstack-start.ts +12 -12
  270. package/src/server.ts +27 -27
  271. package/src/storybook.d.ts +4 -4
  272. package/src/types/index.ts +122 -122
  273. package/src/types/plugins.ts +7 -7
  274. package/src/vite-env.d.ts +12 -12
  275. package/dist/compat-shims-BPJ7Q68c.js.map +0 -1
  276. package/dist/index-D0bAYNQy.js.map +0 -1
  277. package/dist/index-KSX4Qjip.cjs.map +0 -1
@@ -1,31 +1,31 @@
1
- import { useReplayContext } from '@/contexts/ReplayContext'
2
- import { getApiUrl } from '@/lib/api'
3
- import { useAssistantState } from '@assistant-ui/react'
4
- import { generateObject } from 'ai'
5
- import { useCallback, useEffect, useRef, useState } from 'react'
6
- import { z } from 'zod'
7
- import { useAuth } from './useAuth'
8
- import { useElements } from './useElements'
9
- import { useModel } from './useModel'
1
+ import { useReplayContext } from "@/contexts/ReplayContext";
2
+ import { getApiUrl } from "@/lib/api";
3
+ import { useAssistantState } from "@assistant-ui/react";
4
+ import { generateObject } from "ai";
5
+ import { useCallback, useEffect, useRef, useState } from "react";
6
+ import { z } from "zod";
7
+ import { useAuth } from "./useAuth";
8
+ import { useElements } from "./useElements";
9
+ import { useModel } from "./useModel";
10
10
 
11
11
  export interface FollowOnSuggestion {
12
- id: string
13
- prompt: string
12
+ id: string;
13
+ prompt: string;
14
14
  }
15
15
 
16
16
  const suggestionsSchema = z.object({
17
- suggestions: z.array(z.string()).describe('Array of follow-up questions'),
18
- })
17
+ suggestions: z.array(z.string()).describe("Array of follow-up questions"),
18
+ });
19
19
 
20
20
  const questionCheckSchema = z.object({
21
21
  isQuestion: z
22
22
  .boolean()
23
23
  .describe(
24
- 'Whether the message ends by asking the user a question that requires their input or response'
24
+ "Whether the message ends by asking the user a question that requires their input or response",
25
25
  ),
26
- })
26
+ });
27
27
 
28
- const SUGGESTIONS_MODEL = 'openai/gpt-4o-mini'
28
+ const SUGGESTIONS_MODEL = "openai/gpt-4o-mini";
29
29
 
30
30
  /**
31
31
  * Hook to fetch follow-on suggestions after the assistant finishes responding.
@@ -34,76 +34,76 @@ const SUGGESTIONS_MODEL = 'openai/gpt-4o-mini'
34
34
  * Can be disabled via `config.thread.followUpSuggestions: false`
35
35
  */
36
36
  export function useFollowOnSuggestions(): {
37
- suggestions: FollowOnSuggestion[]
38
- isLoading: boolean
37
+ suggestions: FollowOnSuggestion[];
38
+ isLoading: boolean;
39
39
  } {
40
- const { config } = useElements()
41
- const replayCtx = useReplayContext()
42
- const isReplay = replayCtx?.isReplay ?? false
40
+ const { config } = useElements();
41
+ const replayCtx = useReplayContext();
42
+ const isReplay = replayCtx?.isReplay ?? false;
43
43
 
44
44
  const auth = useAuth({
45
45
  auth: config.api,
46
46
  projectSlug: config.projectSlug,
47
- })
47
+ });
48
48
 
49
- const model = useModel(SUGGESTIONS_MODEL)
49
+ const model = useModel(SUGGESTIONS_MODEL);
50
50
 
51
51
  // Check if follow-up suggestions are enabled (default: true)
52
52
  // Disable in replay mode since we don't need AI-generated suggestions
53
- const isEnabled = !isReplay && config.thread?.followUpSuggestions !== false
53
+ const isEnabled = !isReplay && config.thread?.followUpSuggestions !== false;
54
54
 
55
- const [suggestions, setSuggestions] = useState<FollowOnSuggestion[]>([])
56
- const [isLoading, setIsLoading] = useState(false)
55
+ const [suggestions, setSuggestions] = useState<FollowOnSuggestion[]>([]);
56
+ const [isLoading, setIsLoading] = useState(false);
57
57
 
58
58
  // Track the last message ID we generated suggestions for to avoid duplicates
59
- const lastProcessedMessageIdRef = useRef<string | null>(null)
59
+ const lastProcessedMessageIdRef = useRef<string | null>(null);
60
60
  // Track abort controller for in-flight requests
61
- const abortControllerRef = useRef<AbortController | null>(null)
61
+ const abortControllerRef = useRef<AbortController | null>(null);
62
62
 
63
63
  // Get thread state from assistant-ui
64
- const isRunning = useAssistantState(({ thread }) => thread.isRunning)
65
- const messages = useAssistantState(({ thread }) => thread.messages)
64
+ const isRunning = useAssistantState(({ thread }) => thread.isRunning);
65
+ const messages = useAssistantState(({ thread }) => thread.messages);
66
66
 
67
- const apiUrl = getApiUrl(config)
67
+ const apiUrl = getApiUrl(config);
68
68
 
69
69
  const fetchSuggestions = useCallback(async () => {
70
- if (!isEnabled || auth.isLoading || !auth.headers) return
70
+ if (!isEnabled || auth.isLoading || !auth.headers) return;
71
71
 
72
72
  // Get the last few messages for context
73
73
  const recentMessages = messages.slice(-10).map((msg) => {
74
74
  // Extract text content from message parts
75
75
  const textContent = msg.parts
76
- .filter((part) => part.type === 'text')
77
- .map((part) => ('text' in part ? part.text : ''))
78
- .join('\n')
76
+ .filter((part) => part.type === "text")
77
+ .map((part) => ("text" in part ? part.text : ""))
78
+ .join("\n");
79
79
 
80
80
  return {
81
81
  role: msg.role,
82
82
  content: textContent,
83
- }
84
- })
83
+ };
84
+ });
85
85
 
86
- if (recentMessages.length === 0) return
86
+ if (recentMessages.length === 0) return;
87
87
 
88
88
  // Find the last assistant message
89
- let lastAssistantMessage = ''
89
+ let lastAssistantMessage = "";
90
90
  for (let i = recentMessages.length - 1; i >= 0; i--) {
91
- const msg = recentMessages[i]
92
- if (msg.role === 'assistant') {
93
- lastAssistantMessage = msg.content
94
- break
91
+ const msg = recentMessages[i];
92
+ if (msg.role === "assistant") {
93
+ lastAssistantMessage = msg.content;
94
+ break;
95
95
  }
96
96
  }
97
97
 
98
98
  // Cancel any in-flight request
99
99
  if (abortControllerRef.current) {
100
- abortControllerRef.current.abort()
100
+ abortControllerRef.current.abort();
101
101
  }
102
102
 
103
- const controller = new AbortController()
104
- abortControllerRef.current = controller
103
+ const controller = new AbortController();
104
+ abortControllerRef.current = controller;
105
105
 
106
- setIsLoading(true)
106
+ setIsLoading(true);
107
107
 
108
108
  try {
109
109
  // Check if the assistant is asking a question
@@ -117,29 +117,29 @@ export function useFollowOnSuggestions(): {
117
117
  Message:
118
118
  ${lastAssistantMessage}`,
119
119
  abortSignal: controller.signal,
120
- })
120
+ });
121
121
 
122
122
  if (checkResult.object.isQuestion) {
123
123
  // Don't generate suggestions if assistant is asking a question
124
124
  if (abortControllerRef.current === controller) {
125
- setSuggestions([])
126
- setIsLoading(false)
127
- abortControllerRef.current = null
125
+ setSuggestions([]);
126
+ setIsLoading(false);
127
+ abortControllerRef.current = null;
128
128
  }
129
- return
129
+ return;
130
130
  }
131
131
  } catch (error) {
132
132
  // If check fails, continue with generating suggestions
133
- console.warn('Failed to check if message is a question:', error)
133
+ console.warn("Failed to check if message is a question:", error);
134
134
  }
135
135
  }
136
136
 
137
137
  // Build conversation context
138
138
  const conversation = recentMessages
139
139
  .map((msg) => `${msg.role}: ${msg.content}`)
140
- .join('\n')
140
+ .join("\n");
141
141
 
142
- const count = 3
142
+ const count = 3;
143
143
  const systemPrompt = `Generate exactly ${count} follow-up questions the user could ask to learn MORE from the assistant.
144
144
 
145
145
  The user wants to dig deeper into what the assistant just explained. Generate questions that ask the assistant to elaborate, compare, or provide more details.
@@ -154,7 +154,7 @@ Rules:
154
154
  - Ask for elaboration, comparisons, or deeper explanations
155
155
  - Keep each question concise (under 12 words)
156
156
  - No numbering or bullet points
157
- - One question per line, nothing else`
157
+ - One question per line, nothing else`;
158
158
 
159
159
  const result = await generateObject({
160
160
  model,
@@ -164,7 +164,7 @@ Rules:
164
164
  Conversation:
165
165
  ${conversation}`,
166
166
  abortSignal: controller.signal,
167
- })
167
+ });
168
168
 
169
169
  // Only update state if this request is still the current one
170
170
  if (abortControllerRef.current === controller) {
@@ -172,26 +172,26 @@ ${conversation}`,
172
172
  result.object.suggestions.slice(0, count).map((prompt) => ({
173
173
  id: crypto.randomUUID(),
174
174
  prompt,
175
- }))
176
- )
175
+ })),
176
+ );
177
177
  }
178
178
  } catch (error) {
179
- if (error instanceof Error && error.name === 'AbortError') {
179
+ if (error instanceof Error && error.name === "AbortError") {
180
180
  // Request was aborted, ignore
181
- return
181
+ return;
182
182
  }
183
- console.error('Error generating follow-on suggestions:', error)
183
+ console.error("Error generating follow-on suggestions:", error);
184
184
  if (abortControllerRef.current === controller) {
185
- setSuggestions([])
185
+ setSuggestions([]);
186
186
  }
187
187
  } finally {
188
188
  // Only clear state if this request is still the current one
189
189
  if (abortControllerRef.current === controller) {
190
- setIsLoading(false)
191
- abortControllerRef.current = null
190
+ setIsLoading(false);
191
+ abortControllerRef.current = null;
192
192
  }
193
193
  }
194
- }, [isEnabled, apiUrl, auth.headers, auth.isLoading, messages])
194
+ }, [isEnabled, apiUrl, auth.headers, auth.isLoading, messages]);
195
195
 
196
196
  // Fetch suggestions when:
197
197
  // 1. The thread stops running (assistant finished responding)
@@ -203,38 +203,38 @@ ${conversation}`,
203
203
  if (isRunning) {
204
204
  // Abort any in-flight request and clear suggestions when a new run starts
205
205
  if (abortControllerRef.current) {
206
- abortControllerRef.current.abort()
207
- abortControllerRef.current = null
206
+ abortControllerRef.current.abort();
207
+ abortControllerRef.current = null;
208
208
  }
209
- setSuggestions([])
210
- setIsLoading(false)
211
- return
209
+ setSuggestions([]);
210
+ setIsLoading(false);
211
+ return;
212
212
  }
213
213
 
214
214
  // Wait for auth to be ready before attempting to fetch
215
215
  // This prevents marking a message as processed before we can actually make the request
216
- if (auth.isLoading || !auth.headers) return
216
+ if (auth.isLoading || !auth.headers) return;
217
217
 
218
- if (messages.length === 0) return
218
+ if (messages.length === 0) return;
219
219
 
220
- const lastMessage = messages[messages.length - 1]
221
- if (!lastMessage || lastMessage.role !== 'assistant') return
220
+ const lastMessage = messages[messages.length - 1];
221
+ if (!lastMessage || lastMessage.role !== "assistant") return;
222
222
 
223
223
  // Check if we've already processed this message
224
- if (lastProcessedMessageIdRef.current === lastMessage.id) return
224
+ if (lastProcessedMessageIdRef.current === lastMessage.id) return;
225
225
 
226
- lastProcessedMessageIdRef.current = lastMessage.id
227
- fetchSuggestions()
228
- }, [isRunning, messages, fetchSuggestions, auth.isLoading, auth.headers])
226
+ lastProcessedMessageIdRef.current = lastMessage.id;
227
+ fetchSuggestions();
228
+ }, [isRunning, messages, fetchSuggestions, auth.isLoading, auth.headers]);
229
229
 
230
230
  // Cleanup on unmount
231
231
  useEffect(() => {
232
232
  return () => {
233
233
  if (abortControllerRef.current) {
234
- abortControllerRef.current.abort()
234
+ abortControllerRef.current.abort();
235
235
  }
236
- }
237
- }, [])
236
+ };
237
+ }, []);
238
238
 
239
- return { suggestions, isLoading }
239
+ return { suggestions, isLoading };
240
240
  }