@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.
- package/README.md +72 -60
- package/README.typedoc.md +6 -6
- package/bin/cli.js +74 -74
- package/dist/compat-shims-CO9JXXV4.cjs.map +1 -1
- package/dist/{compat-shims-BPJ7Q68c.js → compat-shims-DxtUrORi.js} +4 -2
- package/dist/compat-shims-DxtUrORi.js.map +1 -0
- package/dist/components/ShareButton/index.d.ts +2 -2
- package/dist/components/assistant-ui/message-feedback.d.ts +1 -1
- package/dist/components/assistant-ui/tooltip-icon-button.d.ts +2 -2
- package/dist/components/ui/avatar.d.ts +2 -2
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/components/ui/calendar.d.ts +1 -1
- package/dist/components/ui/collapsible.d.ts +1 -1
- package/dist/components/ui/dialog.d.ts +4 -4
- package/dist/components/ui/popover.d.ts +2 -2
- package/dist/components/ui/skeleton.d.ts +1 -1
- package/dist/components/ui/time-range-picker.d.ts +1 -1
- package/dist/components/ui/tool-ui.d.ts +7 -7
- package/dist/components/ui/tooltip.d.ts +2 -2
- package/dist/contexts/ConnectionStatusContext.d.ts +1 -1
- package/dist/elements.cjs +1 -1
- package/dist/elements.js +2 -2
- package/dist/hooks/useDensity.d.ts +73 -73
- package/dist/hooks/useMCPTools.d.ts +1 -1
- package/dist/hooks/useRadius.d.ts +1 -1
- package/dist/{index-BpJstUh1.cjs → index-C4bFBGfl.cjs} +4 -4
- package/dist/{index-BpJstUh1.cjs.map → index-C4bFBGfl.cjs.map} +1 -1
- package/dist/{index-CUitXazZ.js → index-D93pV0_o.js} +55 -55
- package/dist/{index-CUitXazZ.js.map → index-D93pV0_o.js.map} +1 -1
- package/dist/{index-D0bAYNQy.js → index-DuCQRbcQ.js} +279 -265
- package/dist/index-DuCQRbcQ.js.map +1 -0
- package/dist/{index-KSX4Qjip.cjs → index-y_PNN5vK.cjs} +10 -10
- package/dist/index-y_PNN5vK.cjs.map +1 -0
- package/dist/lib/cassette.d.ts +4 -4
- package/dist/lib/errorTracking.d.ts +1 -1
- package/dist/lib/messageConverter.d.ts +1 -1
- package/dist/lib/models.d.ts +1 -1
- package/dist/plugins/chart/ui/bar-chart.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/accordion-wrapper.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/accordion.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/action-button.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/alert-wrapper.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/alert.d.ts +4 -4
- package/dist/plugins/generative-ui/ui/avatar.d.ts +5 -5
- package/dist/plugins/generative-ui/ui/badge.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/button-wrapper.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/button.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/card-wrapper.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/card.d.ts +8 -8
- package/dist/plugins/generative-ui/ui/checkbox.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/data-table.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/dialog.d.ts +3 -3
- package/dist/plugins/generative-ui/ui/dropdown-menu.d.ts +3 -3
- package/dist/plugins/generative-ui/ui/grid.d.ts +3 -3
- package/dist/plugins/generative-ui/ui/input-wrapper.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/input.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/label.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/metric.d.ts +3 -3
- package/dist/plugins/generative-ui/ui/pagination.d.ts +6 -6
- package/dist/plugins/generative-ui/ui/popover.d.ts +4 -4
- package/dist/plugins/generative-ui/ui/progress.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/radio-group.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/select.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/separator.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/skeleton.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/stack.d.ts +6 -6
- package/dist/plugins/generative-ui/ui/switch.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/table.d.ts +9 -9
- package/dist/plugins/generative-ui/ui/tabs-wrapper.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/tabs.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/text.d.ts +3 -3
- package/dist/plugins/generative-ui/ui/textarea.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/tooltip.d.ts +1 -1
- package/dist/plugins.cjs +1 -1
- package/dist/plugins.js +1 -1
- package/dist/{profiler-BFkhZRxj.js → profiler-FpBY9eRv.js} +2 -2
- package/dist/{profiler-BFkhZRxj.js.map → profiler-FpBY9eRv.js.map} +1 -1
- package/dist/{profiler-CyzxBxVz.cjs → profiler-_mthyjvo.cjs} +2 -2
- package/dist/{profiler-CyzxBxVz.cjs.map → profiler-_mthyjvo.cjs.map} +1 -1
- package/dist/react-shim.js +1 -1
- package/dist/server/express.cjs.map +1 -1
- package/dist/server/express.js.map +1 -1
- package/dist/{startRecording-Dq92sEHf.cjs → startRecording-NJcpiHw-.cjs} +2 -2
- package/dist/{startRecording-Dq92sEHf.cjs.map → startRecording-NJcpiHw-.cjs.map} +1 -1
- package/dist/{startRecording-C-PPAs_Z.js → startRecording-r5MXQ2Dm.js} +2 -2
- package/dist/{startRecording-C-PPAs_Z.js.map → startRecording-r5MXQ2Dm.js.map} +1 -1
- package/dist/types/index.d.ts +2 -2
- package/package.json +1 -5
- package/src/compat-plugin.ts +14 -14
- package/src/compat-shims.ts +33 -31
- package/src/compat.test.ts +48 -48
- package/src/compat.ts +6 -6
- package/src/components/Chat/index.tsx +17 -17
- package/src/components/Chat/stories/Charts.stories.tsx +98 -98
- package/src/components/Chat/stories/Composer.stories.tsx +15 -15
- package/src/components/Chat/stories/ConnectionConfiguration.stories.tsx +44 -44
- package/src/components/Chat/stories/CustomComponents.stories.tsx +17 -17
- package/src/components/Chat/stories/Density.stories.tsx +20 -20
- package/src/components/Chat/stories/ErrorBoundary.stories.tsx +47 -47
- package/src/components/Chat/stories/FrontendTools.stories.tsx +39 -39
- package/src/components/Chat/stories/GenerativeUI.stories.tsx +48 -48
- package/src/components/Chat/stories/MessageFeedback.stories.tsx +52 -52
- package/src/components/Chat/stories/Modal.stories.tsx +28 -28
- package/src/components/Chat/stories/Model.stories.tsx +11 -11
- package/src/components/Chat/stories/Radius.stories.tsx +20 -20
- package/src/components/Chat/stories/Sidecar.stories.tsx +13 -13
- package/src/components/Chat/stories/StyleIsolation.stories.tsx +11 -11
- package/src/components/Chat/stories/Theme.stories.tsx +25 -25
- package/src/components/Chat/stories/Thread.stories.tsx +25 -25
- package/src/components/Chat/stories/ToolApproval.stories.tsx +55 -55
- package/src/components/Chat/stories/ToolMentions.stories.tsx +17 -17
- package/src/components/Chat/stories/Tools.stories.tsx +88 -88
- package/src/components/Chat/stories/Variants.stories.tsx +32 -32
- package/src/components/Chat/stories/Welcome.stories.tsx +14 -14
- package/src/components/ChatHistory.tsx +7 -7
- package/src/components/FrontendTools/index.tsx +5 -5
- package/src/components/Replay.stories.tsx +157 -157
- package/src/components/Replay.tsx +76 -73
- package/src/components/ShadowRoot.tsx +40 -40
- package/src/components/ShareButton/index.tsx +32 -32
- package/src/components/assistant-ui/assistant-modal.tsx +92 -87
- package/src/components/assistant-ui/assistant-sidecar.tsx +35 -35
- package/src/components/assistant-ui/attachment.tsx +80 -80
- package/src/components/assistant-ui/connection-status-indicator.tsx +33 -33
- package/src/components/assistant-ui/error-boundary.tsx +34 -34
- package/src/components/assistant-ui/follow-on-suggestions.tsx +26 -26
- package/src/components/assistant-ui/markdown-text.tsx +69 -69
- package/src/components/assistant-ui/mentioned-tools-badges.tsx +38 -38
- package/src/components/assistant-ui/message-feedback.tsx +57 -50
- package/src/components/assistant-ui/reasoning.tsx +83 -83
- package/src/components/assistant-ui/thread-list.tsx +45 -45
- package/src/components/assistant-ui/thread.tsx +278 -278
- package/src/components/assistant-ui/tool-fallback.tsx +37 -37
- package/src/components/assistant-ui/tool-group.tsx +26 -26
- package/src/components/assistant-ui/tool-mention-autocomplete.tsx +122 -122
- package/src/components/assistant-ui/tooltip-icon-button.tsx +18 -18
- package/src/components/ui/avatar.tsx +12 -12
- package/src/components/ui/button.tsx +12 -12
- package/src/components/ui/buttonVariants.ts +17 -17
- package/src/components/ui/calendar.tsx +106 -106
- package/src/components/ui/charts.stories.tsx +56 -56
- package/src/components/ui/collapsible.tsx +5 -5
- package/src/components/ui/dialog.tsx +30 -30
- package/src/components/ui/generative-ui.stories.tsx +200 -200
- package/src/components/ui/generative-ui.tsx +26 -26
- package/src/components/ui/popover.tsx +14 -14
- package/src/components/ui/skeleton.tsx +5 -5
- package/src/components/ui/time-range-picker.stories.tsx +80 -80
- package/src/components/ui/time-range-picker.tsx +245 -244
- package/src/components/ui/tool-ui.stories.tsx +37 -37
- package/src/components/ui/tool-ui.tsx +221 -215
- package/src/components/ui/tooltip.tsx +15 -15
- package/src/constants/tailwind.ts +1 -1
- package/src/contexts/ChatIdContext.tsx +7 -7
- package/src/contexts/ConnectionStatusContext.tsx +64 -64
- package/src/contexts/ElementsProvider.tsx +214 -213
- package/src/contexts/ReplayContext.ts +3 -3
- package/src/contexts/ToolApprovalContext.tsx +54 -54
- package/src/contexts/ToolExecutionContext.tsx +34 -34
- package/src/contexts/contexts.ts +7 -7
- package/src/contexts/portal-container-context.ts +2 -2
- package/src/contexts/portal-container.tsx +7 -7
- package/src/embedded.ts +1 -1
- package/src/global.css +25 -25
- package/src/hooks/useAuth.ts +72 -72
- package/src/hooks/useDensity.ts +79 -79
- package/src/hooks/useElements.ts +6 -6
- package/src/hooks/useExpanded.ts +12 -12
- package/src/hooks/useFollowOnSuggestions.ts +83 -83
- package/src/hooks/useGramThreadListAdapter.tsx +99 -99
- package/src/hooks/useMCPTools.ts +47 -47
- package/src/hooks/useModel.ts +14 -14
- package/src/hooks/usePluginComponents.ts +11 -11
- package/src/hooks/usePortalContainer.ts +5 -5
- package/src/hooks/useRadius.ts +23 -23
- package/src/hooks/useRecordCassette.ts +34 -34
- package/src/hooks/useSession.ts +11 -11
- package/src/hooks/useThemeProps.ts +13 -13
- package/src/hooks/useThreadId.ts +4 -4
- package/src/hooks/useToolApproval.ts +7 -7
- package/src/hooks/useToolMentions.ts +40 -40
- package/src/index.ts +26 -26
- package/src/lib/api.test.ts +61 -61
- package/src/lib/api.ts +4 -3
- package/src/lib/auth.ts +13 -13
- package/src/lib/cassette.ts +84 -84
- package/src/lib/easing.ts +1 -1
- package/src/lib/errorTracking.config.ts +5 -5
- package/src/lib/errorTracking.ts +29 -29
- package/src/lib/generative-ui.ts +7 -7
- package/src/lib/humanize.ts +3 -3
- package/src/lib/messageConverter.test.ts +130 -127
- package/src/lib/messageConverter.ts +196 -196
- package/src/lib/models.ts +21 -20
- package/src/lib/token.test.ts +56 -56
- package/src/lib/token.ts +14 -14
- package/src/lib/tool-mentions.ts +45 -45
- package/src/lib/tools.ts +66 -62
- package/src/lib/utils.ts +5 -5
- package/src/lib.d.ts +1 -1
- package/src/plugins/README.md +5 -5
- package/src/plugins/chart/catalog.ts +18 -18
- package/src/plugins/chart/chart.test.ts +31 -31
- package/src/plugins/chart/component.tsx +34 -34
- package/src/plugins/chart/index.ts +4 -4
- package/src/plugins/chart/ui/area-chart.tsx +42 -42
- package/src/plugins/chart/ui/bar-chart.tsx +46 -46
- package/src/plugins/chart/ui/donut-chart.tsx +48 -48
- package/src/plugins/chart/ui/index.ts +7 -7
- package/src/plugins/chart/ui/line-chart.tsx +43 -43
- package/src/plugins/chart/ui/pie-chart.tsx +44 -44
- package/src/plugins/chart/ui/radar-chart.tsx +33 -33
- package/src/plugins/chart/ui/scatter-chart.tsx +43 -43
- package/src/plugins/components/MacOSWindowFrame.tsx +15 -15
- package/src/plugins/components/PluginLoadingState.tsx +10 -10
- package/src/plugins/components/index.ts +1 -1
- package/src/plugins/generative-ui/catalog.ts +54 -54
- package/src/plugins/generative-ui/component.tsx +85 -85
- package/src/plugins/generative-ui/index.ts +4 -4
- package/src/plugins/generative-ui/ui/accordion-wrapper.tsx +16 -16
- package/src/plugins/generative-ui/ui/accordion.tsx +16 -16
- package/src/plugins/generative-ui/ui/action-button.tsx +28 -28
- package/src/plugins/generative-ui/ui/alert-wrapper.tsx +8 -8
- package/src/plugins/generative-ui/ui/alert.tsx +20 -20
- package/src/plugins/generative-ui/ui/avatar-wrapper.tsx +7 -7
- package/src/plugins/generative-ui/ui/avatar.tsx +30 -30
- package/src/plugins/generative-ui/ui/badge.tsx +22 -22
- package/src/plugins/generative-ui/ui/button-wrapper.tsx +12 -12
- package/src/plugins/generative-ui/ui/button.tsx +28 -28
- package/src/plugins/generative-ui/ui/card-wrapper.tsx +8 -8
- package/src/plugins/generative-ui/ui/card.tsx +27 -27
- package/src/plugins/generative-ui/ui/checkbox-wrapper.tsx +9 -9
- package/src/plugins/generative-ui/ui/checkbox.tsx +9 -9
- package/src/plugins/generative-ui/ui/data-table.tsx +8 -8
- package/src/plugins/generative-ui/ui/dialog.tsx +31 -31
- package/src/plugins/generative-ui/ui/dropdown-menu.tsx +44 -44
- package/src/plugins/generative-ui/ui/grid.tsx +12 -12
- package/src/plugins/generative-ui/ui/index.ts +40 -40
- package/src/plugins/generative-ui/ui/input-wrapper.tsx +11 -11
- package/src/plugins/generative-ui/ui/input.tsx +9 -9
- package/src/plugins/generative-ui/ui/label.tsx +8 -8
- package/src/plugins/generative-ui/ui/list.tsx +11 -11
- package/src/plugins/generative-ui/ui/metric.tsx +23 -23
- package/src/plugins/generative-ui/ui/pagination.tsx +28 -28
- package/src/plugins/generative-ui/ui/popover.tsx +21 -21
- package/src/plugins/generative-ui/ui/progress.tsx +13 -13
- package/src/plugins/generative-ui/ui/radio-group.tsx +12 -12
- package/src/plugins/generative-ui/ui/select-wrapper.tsx +7 -7
- package/src/plugins/generative-ui/ui/select.tsx +37 -37
- package/src/plugins/generative-ui/ui/separator.tsx +9 -9
- package/src/plugins/generative-ui/ui/skeleton-wrapper.tsx +10 -10
- package/src/plugins/generative-ui/ui/skeleton.tsx +5 -5
- package/src/plugins/generative-ui/ui/stack.tsx +28 -28
- package/src/plugins/generative-ui/ui/switch.tsx +11 -11
- package/src/plugins/generative-ui/ui/table.tsx +32 -32
- package/src/plugins/generative-ui/ui/tabs-wrapper.tsx +11 -11
- package/src/plugins/generative-ui/ui/tabs.tsx +26 -26
- package/src/plugins/generative-ui/ui/text.tsx +12 -12
- package/src/plugins/generative-ui/ui/textarea.tsx +7 -7
- package/src/plugins/generative-ui/ui/tooltip.tsx +12 -12
- package/src/plugins/index.ts +7 -7
- package/src/react-shim.ts +6 -6
- package/src/server/bun.ts +12 -12
- package/src/server/core.ts +25 -25
- package/src/server/express.ts +17 -15
- package/src/server/fastify.ts +14 -14
- package/src/server/hono.ts +9 -9
- package/src/server/nextjs.ts +12 -12
- package/src/server/tanstack-start.ts +12 -12
- package/src/server.ts +27 -27
- package/src/storybook.d.ts +4 -4
- package/src/types/index.ts +122 -122
- package/src/types/plugins.ts +7 -7
- package/src/vite-env.d.ts +12 -12
- package/dist/compat-shims-BPJ7Q68c.js.map +0 -1
- package/dist/index-D0bAYNQy.js.map +0 -1
- package/dist/index-KSX4Qjip.cjs.map +0 -1
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import { useReplayContext } from
|
|
2
|
-
import { getApiUrl } from
|
|
3
|
-
import { useAssistantState } from
|
|
4
|
-
import { generateObject } from
|
|
5
|
-
import { useCallback, useEffect, useRef, useState } from
|
|
6
|
-
import { z } from
|
|
7
|
-
import { useAuth } from
|
|
8
|
-
import { useElements } from
|
|
9
|
-
import { useModel } from
|
|
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(
|
|
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
|
-
|
|
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 =
|
|
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 ===
|
|
77
|
-
.map((part) => (
|
|
78
|
-
.join(
|
|
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 ===
|
|
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(
|
|
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(
|
|
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 ===
|
|
179
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
180
180
|
// Request was aborted, ignore
|
|
181
|
-
return
|
|
181
|
+
return;
|
|
182
182
|
}
|
|
183
|
-
console.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 !==
|
|
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
|
}
|