@gram-ai/elements 1.27.3 → 1.27.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +4 -2
- 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.css +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-DBrhzauj.js → index-DuCQRbcQ.js} +6386 -6337
- package/dist/index-DuCQRbcQ.js.map +1 -0
- package/dist/{index-DxfW52oA.cjs → index-y_PNN5vK.cjs} +64 -46
- 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-D6ndqfsd.js → profiler-FpBY9eRv.js} +2 -2
- package/dist/{profiler-D6ndqfsd.js.map → profiler-FpBY9eRv.js.map} +1 -1
- package/dist/{profiler-DhnzZ34c.cjs → profiler-_mthyjvo.cjs} +2 -2
- package/dist/{profiler-DhnzZ34c.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-BwXmdmy1.cjs → startRecording-NJcpiHw-.cjs} +2 -2
- package/dist/{startRecording-BwXmdmy1.cjs.map → startRecording-NJcpiHw-.cjs.map} +1 -1
- package/dist/{startRecording-B_9CRZ_P.js → startRecording-r5MXQ2Dm.js} +2 -2
- package/dist/{startRecording-B_9CRZ_P.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 +74 -61
- 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 +272 -235
- 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 +222 -211
- 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 +87 -82
- 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-DBrhzauj.js.map +0 -1
- package/dist/index-DxfW52oA.cjs.map +0 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { FrontendTools } from
|
|
2
|
-
import { ROOT_SELECTOR } from
|
|
1
|
+
import { FrontendTools } from "@/components/FrontendTools";
|
|
2
|
+
import { ROOT_SELECTOR } from "@/constants/tailwind";
|
|
3
3
|
import {
|
|
4
4
|
isLocalThreadId,
|
|
5
5
|
useGramThreadListAdapter,
|
|
6
|
-
} from
|
|
7
|
-
import { useMCPTools } from
|
|
8
|
-
import { useToolApproval } from
|
|
9
|
-
import { getApiUrl } from
|
|
10
|
-
import { initErrorTracking, trackError } from
|
|
11
|
-
import { MODELS } from
|
|
6
|
+
} from "@/hooks/useGramThreadListAdapter";
|
|
7
|
+
import { useMCPTools } from "@/hooks/useMCPTools";
|
|
8
|
+
import { useToolApproval } from "@/hooks/useToolApproval";
|
|
9
|
+
import { getApiUrl } from "@/lib/api";
|
|
10
|
+
import { initErrorTracking, trackError } from "@/lib/errorTracking";
|
|
11
|
+
import { MODELS } from "@/lib/models";
|
|
12
12
|
import {
|
|
13
13
|
clearFrontendToolApprovalConfig,
|
|
14
14
|
getEnabledTools,
|
|
@@ -17,33 +17,34 @@ import {
|
|
|
17
17
|
wrapToolsWithApproval,
|
|
18
18
|
type ApprovalHelpers,
|
|
19
19
|
type FrontendTool,
|
|
20
|
-
} from
|
|
21
|
-
import { cn } from
|
|
22
|
-
import { recommended } from
|
|
23
|
-
import { ElementsConfig, Model } from
|
|
24
|
-
import { Plugin } from
|
|
20
|
+
} from "@/lib/tools";
|
|
21
|
+
import { cn } from "@/lib/utils";
|
|
22
|
+
import { recommended } from "@/plugins";
|
|
23
|
+
import { ElementsConfig, Model } from "@/types";
|
|
24
|
+
import { Plugin } from "@/types/plugins";
|
|
25
25
|
import {
|
|
26
26
|
AssistantRuntimeProvider,
|
|
27
27
|
AssistantTool,
|
|
28
28
|
useAssistantState,
|
|
29
29
|
unstable_useRemoteThreadListRuntime as useRemoteThreadListRuntime,
|
|
30
|
-
} from
|
|
30
|
+
} from "@assistant-ui/react";
|
|
31
31
|
import {
|
|
32
32
|
frontendTools as convertFrontendToolsToAISDKTools,
|
|
33
33
|
useChatRuntime,
|
|
34
|
-
} from
|
|
35
|
-
import { createOpenRouter } from
|
|
36
|
-
import { QueryClient, QueryClientProvider } from
|
|
34
|
+
} from "@assistant-ui/react-ai-sdk";
|
|
35
|
+
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
|
|
36
|
+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
37
37
|
import {
|
|
38
38
|
convertToModelMessages,
|
|
39
39
|
createUIMessageStream,
|
|
40
|
+
LanguageModel,
|
|
40
41
|
smoothStream,
|
|
41
42
|
stepCountIs,
|
|
42
43
|
streamText,
|
|
43
44
|
ToolSet,
|
|
44
45
|
type ChatTransport,
|
|
45
46
|
type UIMessage,
|
|
46
|
-
} from
|
|
47
|
+
} from "ai";
|
|
47
48
|
import {
|
|
48
49
|
ReactNode,
|
|
49
50
|
useCallback,
|
|
@@ -51,16 +52,16 @@ import {
|
|
|
51
52
|
useMemo,
|
|
52
53
|
useRef,
|
|
53
54
|
useState,
|
|
54
|
-
} from
|
|
55
|
-
import { useAuth } from
|
|
56
|
-
import { ChatIdContext } from
|
|
55
|
+
} from "react";
|
|
56
|
+
import { useAuth } from "../hooks/useAuth";
|
|
57
|
+
import { ChatIdContext } from "./ChatIdContext";
|
|
57
58
|
import {
|
|
58
59
|
ConnectionStatusProvider,
|
|
59
60
|
useConnectionStatusOptional,
|
|
60
|
-
} from
|
|
61
|
-
import { ElementsContext } from
|
|
62
|
-
import { ToolApprovalProvider } from
|
|
63
|
-
import { ToolExecutionProvider } from
|
|
61
|
+
} from "./ConnectionStatusContext";
|
|
62
|
+
import { ElementsContext } from "./contexts";
|
|
63
|
+
import { ToolApprovalProvider } from "./ToolApprovalContext";
|
|
64
|
+
import { ToolExecutionProvider } from "./ToolExecutionContext";
|
|
64
65
|
|
|
65
66
|
/**
|
|
66
67
|
* Extracts executable tools from frontend tool definitions.
|
|
@@ -69,30 +70,30 @@ import { ToolExecutionProvider } from './ToolExecutionContext'
|
|
|
69
70
|
*/
|
|
70
71
|
function extractExecutableTools(
|
|
71
72
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
72
|
-
frontendTools: Record<string, FrontendTool<any, any>> | undefined
|
|
73
|
+
frontendTools: Record<string, FrontendTool<any, any>> | undefined,
|
|
73
74
|
): Record<
|
|
74
75
|
string,
|
|
75
76
|
{ execute?: (args: unknown, options?: unknown) => Promise<unknown> }
|
|
76
77
|
> {
|
|
77
|
-
if (!frontendTools) return {}
|
|
78
|
+
if (!frontendTools) return {};
|
|
78
79
|
|
|
79
80
|
return Object.fromEntries(
|
|
80
81
|
Object.entries(frontendTools).map(([name, tool]) => {
|
|
81
82
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
82
|
-
const toolDef = (tool as any).unstable_tool
|
|
83
|
+
const toolDef = (tool as any).unstable_tool;
|
|
83
84
|
return [
|
|
84
85
|
name,
|
|
85
86
|
{
|
|
86
87
|
execute: toolDef?.execute,
|
|
87
88
|
},
|
|
88
|
-
]
|
|
89
|
-
})
|
|
90
|
-
)
|
|
89
|
+
];
|
|
90
|
+
}),
|
|
91
|
+
);
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
export interface ElementsProviderProps {
|
|
94
|
-
children: ReactNode
|
|
95
|
-
config: ElementsConfig
|
|
95
|
+
children: ReactNode;
|
|
96
|
+
config: ElementsConfig;
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
const BASE_SYSTEM_PROMPT = `You are a helpful assistant that can answer questions and help with tasks.
|
|
@@ -100,26 +101,29 @@ const BASE_SYSTEM_PROMPT = `You are a helpful assistant that can answer question
|
|
|
100
101
|
Tool Result Display:
|
|
101
102
|
Some tools have custom visual components that automatically render their results (you'll see a rich card/widget appear). For these, do not repeat the data - just add brief context or a follow-up question if needed.
|
|
102
103
|
|
|
103
|
-
For tools WITHOUT custom components, you should present the data clearly - either as plain text for simple results, or using the UI code block format for structured data like lists of items, categories, or dashboards
|
|
104
|
+
For tools WITHOUT custom components, you should present the data clearly - either as plain text for simple results, or using the UI code block format for structured data like lists of items, categories, or dashboards.
|
|
105
|
+
|
|
106
|
+
UI Widget Guidelines:
|
|
107
|
+
IMPORTANT: Only render ONE generative UI widget (chart, dashboard, visualization) per response. Never render multiple widgets in a single message - this causes layout shifts during streaming and overwhelms the user. If you have multiple visualizations to show, render the most important one and explicitly offer to show others as follow-ups (e.g., "Would you like to see a breakdown by status as well?").`;
|
|
104
108
|
|
|
105
109
|
function mergeInternalSystemPromptWith(
|
|
106
110
|
userSystemPrompt: string | undefined,
|
|
107
111
|
plugins: Plugin[],
|
|
108
|
-
toolsWithCustomComponents: string[]
|
|
112
|
+
toolsWithCustomComponents: string[],
|
|
109
113
|
) {
|
|
110
114
|
const customToolsSection =
|
|
111
115
|
toolsWithCustomComponents.length > 0
|
|
112
|
-
? `\n\nTools with custom visual components (DO NOT render UI widgets for these - they already display rich visuals):\n${toolsWithCustomComponents.map((t) => `- ${t}`).join(
|
|
113
|
-
:
|
|
116
|
+
? `\n\nTools with custom visual components (DO NOT render UI widgets for these - they already display rich visuals):\n${toolsWithCustomComponents.map((t) => `- ${t}`).join("\n")}`
|
|
117
|
+
: "";
|
|
114
118
|
|
|
115
119
|
return `
|
|
116
120
|
${BASE_SYSTEM_PROMPT}${customToolsSection}
|
|
117
121
|
|
|
118
122
|
User-provided System Prompt:
|
|
119
|
-
${userSystemPrompt ??
|
|
123
|
+
${userSystemPrompt ?? "None provided"}
|
|
120
124
|
|
|
121
125
|
Utilities:
|
|
122
|
-
${plugins.map((plugin) => `- ${plugin.language}: ${plugin.prompt}`).join(
|
|
126
|
+
${plugins.map((plugin) => `- ${plugin.language}: ${plugin.prompt}`).join("\n")}`;
|
|
123
127
|
}
|
|
124
128
|
|
|
125
129
|
/**
|
|
@@ -128,9 +132,9 @@ function mergeInternalSystemPromptWith(
|
|
|
128
132
|
*/
|
|
129
133
|
function cleanMessagesForModel(messages: UIMessage[]): UIMessage[] {
|
|
130
134
|
return messages.map((message) => {
|
|
131
|
-
const partsArray = message.parts
|
|
135
|
+
const partsArray = message.parts;
|
|
132
136
|
if (!Array.isArray(partsArray)) {
|
|
133
|
-
return message
|
|
137
|
+
return message;
|
|
134
138
|
}
|
|
135
139
|
|
|
136
140
|
// Process each part: strip providerOptions/providerMetadata and filter reasoning
|
|
@@ -138,15 +142,15 @@ function cleanMessagesForModel(messages: UIMessage[]): UIMessage[] {
|
|
|
138
142
|
const cleanedParts = partsArray.map((part: any) => {
|
|
139
143
|
// Strip providerOptions and providerMetadata from all remaining parts
|
|
140
144
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
141
|
-
const { callProviderMetadata: _, ...cleanPart } = part
|
|
142
|
-
return cleanPart
|
|
143
|
-
})
|
|
145
|
+
const { callProviderMetadata: _, ...cleanPart } = part;
|
|
146
|
+
return cleanPart;
|
|
147
|
+
});
|
|
144
148
|
|
|
145
149
|
return {
|
|
146
150
|
...message,
|
|
147
151
|
parts: cleanedParts,
|
|
148
|
-
}
|
|
149
|
-
})
|
|
152
|
+
};
|
|
153
|
+
});
|
|
150
154
|
}
|
|
151
155
|
|
|
152
156
|
/**
|
|
@@ -154,35 +158,35 @@ function cleanMessagesForModel(messages: UIMessage[]): UIMessage[] {
|
|
|
154
158
|
* Delegates to either WithHistory or WithoutHistory based on config.
|
|
155
159
|
*/
|
|
156
160
|
const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
|
|
157
|
-
const apiUrl = getApiUrl(config)
|
|
161
|
+
const apiUrl = getApiUrl(config);
|
|
158
162
|
const auth = useAuth({
|
|
159
163
|
auth: config.api,
|
|
160
164
|
projectSlug: config.projectSlug,
|
|
161
|
-
})
|
|
165
|
+
});
|
|
162
166
|
|
|
163
167
|
// Ref to access ensureValidHeaders in async transport without stale closures
|
|
164
|
-
const ensureValidHeadersRef = useRef(auth.ensureValidHeaders)
|
|
165
|
-
ensureValidHeadersRef.current = auth.ensureValidHeaders
|
|
166
|
-
const toolApproval = useToolApproval()
|
|
168
|
+
const ensureValidHeadersRef = useRef(auth.ensureValidHeaders);
|
|
169
|
+
ensureValidHeadersRef.current = auth.ensureValidHeaders;
|
|
170
|
+
const toolApproval = useToolApproval();
|
|
167
171
|
|
|
168
172
|
const [model, setModel] = useState<Model>(
|
|
169
|
-
config.model?.defaultModel ?? MODELS[0]
|
|
170
|
-
)
|
|
173
|
+
config.model?.defaultModel ?? MODELS[0],
|
|
174
|
+
);
|
|
171
175
|
const [isExpanded, setIsExpanded] = useState(
|
|
172
|
-
config.modal?.defaultExpanded ?? false
|
|
173
|
-
)
|
|
174
|
-
const [isOpen, setIsOpen] = useState(config.modal?.defaultOpen)
|
|
176
|
+
config.modal?.defaultExpanded ?? false,
|
|
177
|
+
);
|
|
178
|
+
const [isOpen, setIsOpen] = useState(config.modal?.defaultOpen);
|
|
175
179
|
|
|
176
|
-
const plugins = config.plugins ?? recommended
|
|
180
|
+
const plugins = config.plugins ?? recommended;
|
|
177
181
|
|
|
178
182
|
// Get list of tools that have custom components registered
|
|
179
|
-
const toolsWithCustomComponents = Object.keys(config.tools?.components ?? {})
|
|
183
|
+
const toolsWithCustomComponents = Object.keys(config.tools?.components ?? {});
|
|
180
184
|
|
|
181
185
|
const systemPrompt = mergeInternalSystemPromptWith(
|
|
182
186
|
config.systemPrompt,
|
|
183
187
|
plugins,
|
|
184
|
-
toolsWithCustomComponents
|
|
185
|
-
)
|
|
188
|
+
toolsWithCustomComponents,
|
|
189
|
+
);
|
|
186
190
|
|
|
187
191
|
// Initialize error tracking on mount
|
|
188
192
|
useEffect(() => {
|
|
@@ -190,15 +194,15 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
|
|
|
190
194
|
enabled: config.errorTracking?.enabled,
|
|
191
195
|
projectSlug: config.projectSlug,
|
|
192
196
|
variant: config.variant,
|
|
193
|
-
})
|
|
194
|
-
}, [])
|
|
197
|
+
});
|
|
198
|
+
}, []);
|
|
195
199
|
|
|
196
200
|
// Generate a stable chat ID for server-side persistence (when history is disabled)
|
|
197
201
|
// When history is enabled, the thread adapter manages chat IDs instead
|
|
198
|
-
const chatIdRef = useRef<string | null>(null)
|
|
202
|
+
const chatIdRef = useRef<string | null>(null);
|
|
199
203
|
|
|
200
204
|
// State to expose the current chat ID via context
|
|
201
|
-
const [currentChatId, setCurrentChatId] = useState<string | null>(null)
|
|
205
|
+
const [currentChatId, setCurrentChatId] = useState<string | null>(null);
|
|
202
206
|
|
|
203
207
|
const { data: mcpTools, mcpHeaders } = useMCPTools({
|
|
204
208
|
auth,
|
|
@@ -206,23 +210,23 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
|
|
|
206
210
|
environment: config.environment ?? {},
|
|
207
211
|
toolsToInclude: config.tools?.toolsToInclude,
|
|
208
212
|
gramEnvironment: config.gramEnvironment,
|
|
209
|
-
})
|
|
213
|
+
});
|
|
210
214
|
|
|
211
215
|
// Store approval helpers in ref so they can be used in async contexts
|
|
212
216
|
const approvalHelpersRef = useRef<ApprovalHelpers>({
|
|
213
217
|
requestApproval: toolApproval.requestApproval,
|
|
214
218
|
isToolApproved: toolApproval.isToolApproved,
|
|
215
219
|
whitelistTool: toolApproval.whitelistTool,
|
|
216
|
-
})
|
|
220
|
+
});
|
|
217
221
|
|
|
218
222
|
// Connection status for tracking network failures
|
|
219
|
-
const connectionStatus = useConnectionStatusOptional()
|
|
223
|
+
const connectionStatus = useConnectionStatusOptional();
|
|
220
224
|
|
|
221
225
|
approvalHelpersRef.current = {
|
|
222
226
|
requestApproval: toolApproval.requestApproval,
|
|
223
227
|
isToolApproved: toolApproval.isToolApproved,
|
|
224
228
|
whitelistTool: toolApproval.whitelistTool,
|
|
225
|
-
}
|
|
229
|
+
};
|
|
226
230
|
|
|
227
231
|
const getApprovalHelpers = useCallback((): ApprovalHelpers => {
|
|
228
232
|
return {
|
|
@@ -232,51 +236,51 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
|
|
|
232
236
|
approvalHelpersRef.current.isToolApproved(...args),
|
|
233
237
|
whitelistTool: (...args) =>
|
|
234
238
|
approvalHelpersRef.current.whitelistTool(...args),
|
|
235
|
-
}
|
|
236
|
-
}, [])
|
|
239
|
+
};
|
|
240
|
+
}, []);
|
|
237
241
|
|
|
238
242
|
// Set up frontend tool approval config for runtime checking
|
|
239
243
|
useEffect(() => {
|
|
240
244
|
if (config.tools?.toolsRequiringApproval) {
|
|
241
245
|
setFrontendToolApprovalConfig(
|
|
242
246
|
getApprovalHelpers(),
|
|
243
|
-
config.tools.toolsRequiringApproval
|
|
244
|
-
)
|
|
247
|
+
config.tools.toolsRequiringApproval,
|
|
248
|
+
);
|
|
245
249
|
}
|
|
246
250
|
return () => {
|
|
247
|
-
clearFrontendToolApprovalConfig()
|
|
248
|
-
}
|
|
249
|
-
}, [config.tools?.toolsRequiringApproval, getApprovalHelpers])
|
|
251
|
+
clearFrontendToolApprovalConfig();
|
|
252
|
+
};
|
|
253
|
+
}, [config.tools?.toolsRequiringApproval, getApprovalHelpers]);
|
|
250
254
|
|
|
251
255
|
// Ref to access runtime from within transport's sendMessages.
|
|
252
256
|
// This solves a circular dependency: transport needs runtime.thread.getModelContext(),
|
|
253
257
|
// but runtime is created using transport. The ref gets populated after runtime creation.
|
|
254
|
-
const runtimeRef = useRef<ReturnType<typeof useChatRuntime> | null>(null)
|
|
258
|
+
const runtimeRef = useRef<ReturnType<typeof useChatRuntime> | null>(null);
|
|
255
259
|
|
|
256
260
|
// Map to share local thread IDs to UUIDs between adapter and transport (for history mode)
|
|
257
|
-
const localIdToUuidMapRef = useRef(new Map<string, string>())
|
|
261
|
+
const localIdToUuidMapRef = useRef(new Map<string, string>());
|
|
258
262
|
|
|
259
263
|
// Ref to store the current thread's remoteId, synced from assistant-ui state.
|
|
260
264
|
// This is needed because the runtime object doesn't expose threadListItem.remoteId
|
|
261
265
|
// in a way that's accessible from the transport's sendMessages function.
|
|
262
|
-
const currentRemoteIdRef = useRef<string | null>(null)
|
|
266
|
+
const currentRemoteIdRef = useRef<string | null>(null);
|
|
263
267
|
|
|
264
268
|
// Create chat transport configuration
|
|
265
269
|
const transport = useMemo<ChatTransport<UIMessage>>(
|
|
266
270
|
() => ({
|
|
267
271
|
sendMessages: async ({ messages, abortSignal }) => {
|
|
268
|
-
const usingCustomModel = !!config.languageModel
|
|
272
|
+
const usingCustomModel = !!config.languageModel;
|
|
269
273
|
|
|
270
274
|
if (auth.isLoading) {
|
|
271
|
-
throw new Error(
|
|
275
|
+
throw new Error("Session is loading");
|
|
272
276
|
}
|
|
273
277
|
|
|
274
278
|
// Ensure the session token is still valid; refresh if expired
|
|
275
|
-
const validHeaders = await ensureValidHeadersRef.current()
|
|
279
|
+
const validHeaders = await ensureValidHeadersRef.current();
|
|
276
280
|
|
|
277
281
|
// Get chat ID - use the synced remoteId ref first (history mode),
|
|
278
282
|
// fall back to generated ID (non-history mode)
|
|
279
|
-
let chatId = currentRemoteIdRef.current
|
|
283
|
+
let chatId = currentRemoteIdRef.current;
|
|
280
284
|
|
|
281
285
|
// If we have a valid remoteId (not a local ID), use it directly
|
|
282
286
|
if (chatId && !isLocalThreadId(chatId)) {
|
|
@@ -284,21 +288,21 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
|
|
|
284
288
|
} else if (isLocalThreadId(chatId) || !chatId) {
|
|
285
289
|
// For local thread IDs or no ID, check/generate UUID mapping
|
|
286
290
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
287
|
-
const runtimeAny = runtimeRef.current as any
|
|
288
|
-
const threadsState = runtimeAny?.threads?.getState?.()
|
|
291
|
+
const runtimeAny = runtimeRef.current as any;
|
|
292
|
+
const threadsState = runtimeAny?.threads?.getState?.();
|
|
289
293
|
const localThreadId = (threadsState?.mainThreadId ??
|
|
290
|
-
threadsState?.threadIds?.[0]) as string | undefined
|
|
294
|
+
threadsState?.threadIds?.[0]) as string | undefined;
|
|
291
295
|
|
|
292
|
-
const lookupKey = chatId ?? localThreadId
|
|
296
|
+
const lookupKey = chatId ?? localThreadId;
|
|
293
297
|
if (lookupKey) {
|
|
294
|
-
const existingUuid = localIdToUuidMapRef.current.get(lookupKey)
|
|
298
|
+
const existingUuid = localIdToUuidMapRef.current.get(lookupKey);
|
|
295
299
|
if (existingUuid) {
|
|
296
|
-
chatId = existingUuid
|
|
300
|
+
chatId = existingUuid;
|
|
297
301
|
} else {
|
|
298
302
|
// Generate a new UUID and store the mapping
|
|
299
|
-
const newUuid = crypto.randomUUID()
|
|
300
|
-
localIdToUuidMapRef.current.set(lookupKey, newUuid)
|
|
301
|
-
chatId = newUuid
|
|
303
|
+
const newUuid = crypto.randomUUID();
|
|
304
|
+
localIdToUuidMapRef.current.set(lookupKey, newUuid);
|
|
305
|
+
chatId = newUuid;
|
|
302
306
|
}
|
|
303
307
|
}
|
|
304
308
|
}
|
|
@@ -306,40 +310,40 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
|
|
|
306
310
|
if (!chatId) {
|
|
307
311
|
// Non-history mode fallback - use stable chatIdRef
|
|
308
312
|
if (!chatIdRef.current) {
|
|
309
|
-
chatIdRef.current = crypto.randomUUID()
|
|
313
|
+
chatIdRef.current = crypto.randomUUID();
|
|
310
314
|
}
|
|
311
|
-
chatId = chatIdRef.current
|
|
315
|
+
chatId = chatIdRef.current;
|
|
312
316
|
}
|
|
313
317
|
|
|
314
318
|
// Mutate the shared headers object so the MCP transport picks up the
|
|
315
319
|
// chat ID on subsequent tool call requests.
|
|
316
320
|
if (chatId) {
|
|
317
|
-
mcpHeaders[
|
|
321
|
+
mcpHeaders["Gram-Chat-ID"] = chatId;
|
|
318
322
|
// Update the context state so consumers can access the current chat ID
|
|
319
|
-
setCurrentChatId(chatId)
|
|
323
|
+
setCurrentChatId(chatId);
|
|
320
324
|
}
|
|
321
325
|
|
|
322
|
-
const context = runtimeRef.current?.thread.getModelContext()
|
|
326
|
+
const context = runtimeRef.current?.thread.getModelContext();
|
|
323
327
|
const frontendTools = toAISDKTools(
|
|
324
|
-
getEnabledTools(context?.tools ?? {})
|
|
325
|
-
)
|
|
328
|
+
getEnabledTools(context?.tools ?? {}),
|
|
329
|
+
);
|
|
326
330
|
|
|
327
331
|
// Include Gram-Chat-ID header for chat persistence and Gram-Environment for environment selection
|
|
328
332
|
const headersWithChatId = {
|
|
329
333
|
...validHeaders,
|
|
330
|
-
|
|
331
|
-
|
|
334
|
+
"Gram-Chat-ID": chatId,
|
|
335
|
+
"X-Gram-Source": "elements",
|
|
332
336
|
...config.api?.headers, // We do this after X-Gram-Source so the playground can override it
|
|
333
337
|
...(config.gramEnvironment && {
|
|
334
|
-
|
|
338
|
+
"Gram-Environment": config.gramEnvironment,
|
|
335
339
|
}),
|
|
336
|
-
}
|
|
340
|
+
};
|
|
337
341
|
|
|
338
342
|
// Update MCP headers with the (possibly refreshed) session token
|
|
339
343
|
// so mid-stream MCP tool calls use the fresh token
|
|
340
|
-
const freshSession = validHeaders[
|
|
344
|
+
const freshSession = validHeaders["Gram-Chat-Session"];
|
|
341
345
|
if (freshSession) {
|
|
342
|
-
mcpHeaders[
|
|
346
|
+
mcpHeaders["Gram-Chat-Session"] = freshSession;
|
|
343
347
|
}
|
|
344
348
|
|
|
345
349
|
// Create OpenRouter model (only needed when not using custom model)
|
|
@@ -347,36 +351,43 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
|
|
|
347
351
|
? null
|
|
348
352
|
: createOpenRouter({
|
|
349
353
|
baseURL: apiUrl,
|
|
350
|
-
apiKey:
|
|
354
|
+
apiKey: "unused, but must be set",
|
|
351
355
|
headers: headersWithChatId,
|
|
352
|
-
})
|
|
356
|
+
});
|
|
353
357
|
|
|
354
358
|
if (config.languageModel) {
|
|
355
|
-
console.log(
|
|
359
|
+
console.log("Using custom language model", config.languageModel);
|
|
356
360
|
}
|
|
357
361
|
|
|
358
362
|
// Combine tools - MCP tools only available when not using custom model
|
|
359
363
|
const combinedTools: ToolSet = {
|
|
360
364
|
...mcpTools,
|
|
361
365
|
...convertFrontendToolsToAISDKTools(frontendTools),
|
|
362
|
-
} as ToolSet
|
|
366
|
+
} as ToolSet;
|
|
363
367
|
|
|
364
368
|
// Wrap tools that require approval
|
|
365
369
|
const tools = wrapToolsWithApproval(
|
|
366
370
|
combinedTools,
|
|
367
371
|
config.tools?.toolsRequiringApproval,
|
|
368
|
-
getApprovalHelpers()
|
|
369
|
-
)
|
|
372
|
+
getApprovalHelpers(),
|
|
373
|
+
);
|
|
370
374
|
|
|
371
375
|
// Stream the response
|
|
372
376
|
const modelToUse = config.languageModel
|
|
373
377
|
? config.languageModel
|
|
374
|
-
: openRouterModel!.chat(model)
|
|
378
|
+
: (openRouterModel!.chat(model) as LanguageModel);
|
|
375
379
|
|
|
376
380
|
try {
|
|
377
381
|
// This works around AI SDK bug where these fields cause validation failures
|
|
378
|
-
const cleanedMessages = cleanMessagesForModel(messages)
|
|
379
|
-
|
|
382
|
+
const cleanedMessages = cleanMessagesForModel(messages);
|
|
383
|
+
// Filter out system messages from the UI state — the system prompt
|
|
384
|
+
// is already provided via the `system:` parameter to streamText().
|
|
385
|
+
// Without this, loaded chat history includes the system message which
|
|
386
|
+
// gets sent alongside the `system:` param, causing duplication.
|
|
387
|
+
const nonSystemMessages = cleanedMessages.filter(
|
|
388
|
+
(m) => m.role !== "system",
|
|
389
|
+
);
|
|
390
|
+
const modelMessages = convertToModelMessages(nonSystemMessages);
|
|
380
391
|
|
|
381
392
|
const result = streamText({
|
|
382
393
|
system: systemPrompt,
|
|
@@ -387,59 +398,59 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
|
|
|
387
398
|
experimental_transform: smoothStream({ delayInMs: 15 }),
|
|
388
399
|
abortSignal,
|
|
389
400
|
onError: ({ error }) => {
|
|
390
|
-
console.error(
|
|
391
|
-
trackError(error, { source:
|
|
401
|
+
console.error("Stream error in onError callback:", error);
|
|
402
|
+
trackError(error, { source: "streaming" });
|
|
392
403
|
|
|
393
404
|
// Check if this is a network/connection error
|
|
394
405
|
const isNetworkError =
|
|
395
406
|
error instanceof TypeError ||
|
|
396
407
|
(error instanceof Error &&
|
|
397
|
-
(error.message.includes(
|
|
398
|
-
error.message.includes(
|
|
399
|
-
error.message.includes(
|
|
400
|
-
error.message.includes(
|
|
401
|
-
error.message.includes(
|
|
402
|
-
error.message.includes(
|
|
408
|
+
(error.message.includes("fetch") ||
|
|
409
|
+
error.message.includes("network") ||
|
|
410
|
+
error.message.includes("Failed to fetch") ||
|
|
411
|
+
error.message.includes("NetworkError") ||
|
|
412
|
+
error.message.includes("ECONNREFUSED") ||
|
|
413
|
+
error.message.includes("ETIMEDOUT")));
|
|
403
414
|
|
|
404
415
|
if (isNetworkError) {
|
|
405
|
-
connectionStatus?.markDisconnected()
|
|
416
|
+
connectionStatus?.markDisconnected();
|
|
406
417
|
}
|
|
407
418
|
},
|
|
408
|
-
})
|
|
419
|
+
});
|
|
409
420
|
|
|
410
421
|
// Mark as connected when stream starts successfully
|
|
411
|
-
connectionStatus?.markConnected()
|
|
422
|
+
connectionStatus?.markConnected();
|
|
412
423
|
|
|
413
424
|
// This weird construction is necessary to get errors to propagate properly to assistant-ui
|
|
414
425
|
return createUIMessageStream({
|
|
415
426
|
execute: ({ writer }) => {
|
|
416
|
-
writer.merge(result.toUIMessageStream())
|
|
427
|
+
writer.merge(result.toUIMessageStream());
|
|
417
428
|
},
|
|
418
|
-
})
|
|
429
|
+
});
|
|
419
430
|
} catch (error) {
|
|
420
|
-
console.error(
|
|
421
|
-
trackError(error, { source:
|
|
431
|
+
console.error("Error creating stream:", error);
|
|
432
|
+
trackError(error, { source: "stream-creation" });
|
|
422
433
|
|
|
423
434
|
// Check if this is a network/connection error
|
|
424
435
|
const isNetworkError =
|
|
425
436
|
error instanceof TypeError ||
|
|
426
437
|
(error instanceof Error &&
|
|
427
|
-
(error.message.includes(
|
|
428
|
-
error.message.includes(
|
|
429
|
-
error.message.includes(
|
|
430
|
-
error.message.includes(
|
|
431
|
-
error.message.includes(
|
|
432
|
-
error.message.includes(
|
|
438
|
+
(error.message.includes("fetch") ||
|
|
439
|
+
error.message.includes("network") ||
|
|
440
|
+
error.message.includes("Failed to fetch") ||
|
|
441
|
+
error.message.includes("NetworkError") ||
|
|
442
|
+
error.message.includes("ECONNREFUSED") ||
|
|
443
|
+
error.message.includes("ETIMEDOUT")));
|
|
433
444
|
|
|
434
445
|
if (isNetworkError) {
|
|
435
|
-
connectionStatus?.markDisconnected()
|
|
446
|
+
connectionStatus?.markDisconnected();
|
|
436
447
|
}
|
|
437
448
|
|
|
438
|
-
throw error
|
|
449
|
+
throw error;
|
|
439
450
|
}
|
|
440
451
|
},
|
|
441
452
|
reconnectToStream: async () => {
|
|
442
|
-
throw new Error(
|
|
453
|
+
throw new Error("Stream reconnection not supported");
|
|
443
454
|
},
|
|
444
455
|
}),
|
|
445
456
|
[
|
|
@@ -452,10 +463,10 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
|
|
|
452
463
|
apiUrl,
|
|
453
464
|
auth.isLoading,
|
|
454
465
|
connectionStatus,
|
|
455
|
-
]
|
|
456
|
-
)
|
|
466
|
+
],
|
|
467
|
+
);
|
|
457
468
|
|
|
458
|
-
const historyEnabled = config.history?.enabled ?? false
|
|
469
|
+
const historyEnabled = config.history?.enabled ?? false;
|
|
459
470
|
|
|
460
471
|
// Shared context value for ElementsContext
|
|
461
472
|
const contextValue = useMemo(
|
|
@@ -470,10 +481,10 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
|
|
|
470
481
|
plugins,
|
|
471
482
|
mcpTools,
|
|
472
483
|
}),
|
|
473
|
-
[config, model, isExpanded, isOpen, plugins, mcpTools]
|
|
474
|
-
)
|
|
484
|
+
[config, model, isExpanded, isOpen, plugins, mcpTools],
|
|
485
|
+
);
|
|
475
486
|
|
|
476
|
-
const frontendTools = config.tools?.frontendTools ?? {}
|
|
487
|
+
const frontendTools = config.tools?.frontendTools ?? {};
|
|
477
488
|
|
|
478
489
|
// Create combined executable tools for direct tool execution (ActionButton)
|
|
479
490
|
// Uses a simplified type that focuses on the execute function
|
|
@@ -481,17 +492,17 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
|
|
|
481
492
|
string,
|
|
482
493
|
| { execute?: (args: unknown, options?: unknown) => Promise<unknown> }
|
|
483
494
|
| undefined
|
|
484
|
-
|
|
495
|
+
>;
|
|
485
496
|
const executableTools = useMemo<ExecutableToolSet>(() => {
|
|
486
497
|
const extractedFrontendTools = extractExecutableTools(
|
|
487
|
-
config.tools?.frontendTools
|
|
488
|
-
)
|
|
498
|
+
config.tools?.frontendTools,
|
|
499
|
+
);
|
|
489
500
|
// MCP tools and extracted frontend tools both have execute functions
|
|
490
501
|
return {
|
|
491
502
|
...mcpTools,
|
|
492
503
|
...extractedFrontendTools,
|
|
493
|
-
} as ExecutableToolSet
|
|
494
|
-
}, [mcpTools, config.tools?.frontendTools])
|
|
504
|
+
} as ExecutableToolSet;
|
|
505
|
+
}, [mcpTools, config.tools?.frontendTools]);
|
|
495
506
|
|
|
496
507
|
// Render the appropriate runtime provider based on history config.
|
|
497
508
|
// We use separate components to avoid conditional hook calls.
|
|
@@ -512,7 +523,7 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
|
|
|
512
523
|
>
|
|
513
524
|
{children}
|
|
514
525
|
</ElementsProviderWithHistory>
|
|
515
|
-
)
|
|
526
|
+
);
|
|
516
527
|
}
|
|
517
528
|
|
|
518
529
|
return (
|
|
@@ -526,31 +537,31 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
|
|
|
526
537
|
>
|
|
527
538
|
{children}
|
|
528
539
|
</ElementsProviderWithoutHistory>
|
|
529
|
-
)
|
|
530
|
-
}
|
|
540
|
+
);
|
|
541
|
+
};
|
|
531
542
|
|
|
532
543
|
// Shared type for executable tools
|
|
533
544
|
type ExecutableToolSet = Record<
|
|
534
545
|
string,
|
|
535
546
|
| { execute?: (args: unknown, options?: unknown) => Promise<unknown> }
|
|
536
547
|
| undefined
|
|
537
|
-
|
|
548
|
+
>;
|
|
538
549
|
|
|
539
550
|
// Separate component for history-enabled mode to avoid conditional hook calls
|
|
540
551
|
interface ElementsProviderWithHistoryProps {
|
|
541
|
-
children: ReactNode
|
|
542
|
-
transport: ChatTransport<UIMessage
|
|
543
|
-
apiUrl: string
|
|
544
|
-
headers: Record<string, string
|
|
545
|
-
contextValue: React.ContextType<typeof ElementsContext
|
|
546
|
-
runtimeRef: React.RefObject<ReturnType<typeof useChatRuntime> | null
|
|
552
|
+
children: ReactNode;
|
|
553
|
+
transport: ChatTransport<UIMessage>;
|
|
554
|
+
apiUrl: string;
|
|
555
|
+
headers: Record<string, string>;
|
|
556
|
+
contextValue: React.ContextType<typeof ElementsContext>;
|
|
557
|
+
runtimeRef: React.RefObject<ReturnType<typeof useChatRuntime> | null>;
|
|
547
558
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
548
|
-
frontendTools: Record<string, AssistantTool | FrontendTool<any, any
|
|
549
|
-
localIdToUuidMap: Map<string, string
|
|
550
|
-
currentRemoteIdRef: React.RefObject<string | null
|
|
551
|
-
executableTools: ExecutableToolSet
|
|
552
|
-
currentChatId: string | null
|
|
553
|
-
setCurrentChatId: (chatId: string | null) => void
|
|
559
|
+
frontendTools: Record<string, AssistantTool | FrontendTool<any, any>>;
|
|
560
|
+
localIdToUuidMap: Map<string, string>;
|
|
561
|
+
currentRemoteIdRef: React.RefObject<string | null>;
|
|
562
|
+
executableTools: ExecutableToolSet;
|
|
563
|
+
currentChatId: string | null;
|
|
564
|
+
setCurrentChatId: (chatId: string | null) => void;
|
|
554
565
|
}
|
|
555
566
|
|
|
556
567
|
/**
|
|
@@ -561,18 +572,18 @@ const ThreadIdSync = ({
|
|
|
561
572
|
remoteIdRef,
|
|
562
573
|
onChatIdChange,
|
|
563
574
|
}: {
|
|
564
|
-
remoteIdRef: React.RefObject<string | null
|
|
565
|
-
onChatIdChange: (chatId: string | null) => void
|
|
575
|
+
remoteIdRef: React.RefObject<string | null>;
|
|
576
|
+
onChatIdChange: (chatId: string | null) => void;
|
|
566
577
|
}) => {
|
|
567
578
|
const remoteId = useAssistantState(
|
|
568
|
-
({ threadListItem }) => threadListItem.remoteId ?? null
|
|
569
|
-
)
|
|
579
|
+
({ threadListItem }) => threadListItem.remoteId ?? null,
|
|
580
|
+
);
|
|
570
581
|
useEffect(() => {
|
|
571
|
-
remoteIdRef.current = remoteId
|
|
572
|
-
onChatIdChange(remoteId)
|
|
573
|
-
}, [remoteId, remoteIdRef, onChatIdChange])
|
|
574
|
-
return null
|
|
575
|
-
}
|
|
582
|
+
remoteIdRef.current = remoteId;
|
|
583
|
+
onChatIdChange(remoteId);
|
|
584
|
+
}, [remoteId, remoteIdRef, onChatIdChange]);
|
|
585
|
+
return null;
|
|
586
|
+
};
|
|
576
587
|
|
|
577
588
|
const ElementsProviderWithHistory = ({
|
|
578
589
|
children,
|
|
@@ -592,43 +603,43 @@ const ElementsProviderWithHistory = ({
|
|
|
592
603
|
apiUrl,
|
|
593
604
|
headers,
|
|
594
605
|
localIdToUuidMap,
|
|
595
|
-
})
|
|
596
|
-
const initialThreadId = contextValue?.config.history?.initialThreadId
|
|
606
|
+
});
|
|
607
|
+
const initialThreadId = contextValue?.config.history?.initialThreadId;
|
|
597
608
|
|
|
598
609
|
// Hook factory for creating the base chat runtime
|
|
599
610
|
const useChatRuntimeHook = useCallback(() => {
|
|
600
|
-
return useChatRuntime({ transport })
|
|
601
|
-
}, [transport])
|
|
611
|
+
return useChatRuntime({ transport });
|
|
612
|
+
}, [transport]);
|
|
602
613
|
|
|
603
614
|
const runtime = useRemoteThreadListRuntime({
|
|
604
615
|
adapter: threadListAdapter,
|
|
605
616
|
runtimeHook: useChatRuntimeHook,
|
|
606
|
-
})
|
|
617
|
+
});
|
|
607
618
|
|
|
608
619
|
// Populate runtimeRef so transport can access thread context
|
|
609
620
|
useEffect(() => {
|
|
610
|
-
runtimeRef.current = runtime as ReturnType<typeof useChatRuntime
|
|
611
|
-
}, [runtime, runtimeRef])
|
|
621
|
+
runtimeRef.current = runtime as ReturnType<typeof useChatRuntime>;
|
|
622
|
+
}, [runtime, runtimeRef]);
|
|
612
623
|
|
|
613
624
|
// Switch to initial thread if provided (for shared chat URLs)
|
|
614
|
-
const initialThreadSwitched = useRef(false)
|
|
625
|
+
const initialThreadSwitched = useRef(false);
|
|
615
626
|
useEffect(() => {
|
|
616
627
|
if (initialThreadId && !initialThreadSwitched.current) {
|
|
617
|
-
initialThreadSwitched.current = true
|
|
628
|
+
initialThreadSwitched.current = true;
|
|
618
629
|
// Use setTimeout to ensure runtime is fully initialized
|
|
619
630
|
const timeoutId = setTimeout(() => {
|
|
620
631
|
runtime.threads.switchToThread(initialThreadId).catch((error) => {
|
|
621
|
-
console.error(
|
|
622
|
-
})
|
|
623
|
-
}, 100)
|
|
624
|
-
return () => clearTimeout(timeoutId)
|
|
632
|
+
console.error("Failed to switch to initial thread:", error);
|
|
633
|
+
});
|
|
634
|
+
}, 100);
|
|
635
|
+
return () => clearTimeout(timeoutId);
|
|
625
636
|
}
|
|
626
|
-
}, [initialThreadId, runtime])
|
|
637
|
+
}, [initialThreadId, runtime]);
|
|
627
638
|
|
|
628
639
|
// Get the Provider from our adapter to wrap the content
|
|
629
640
|
const HistoryProvider =
|
|
630
641
|
threadListAdapter.unstable_Provider ??
|
|
631
|
-
(({ children }: { children: React.ReactNode }) => <>{children}</>)
|
|
642
|
+
(({ children }: { children: React.ReactNode }) => <>{children}</>);
|
|
632
643
|
|
|
633
644
|
return (
|
|
634
645
|
<AssistantRuntimeProvider runtime={runtime}>
|
|
@@ -643,9 +654,9 @@ const ElementsProviderWithHistory = ({
|
|
|
643
654
|
<div
|
|
644
655
|
className={cn(
|
|
645
656
|
ROOT_SELECTOR,
|
|
646
|
-
(contextValue?.config.variant ===
|
|
647
|
-
contextValue?.config.variant ===
|
|
648
|
-
|
|
657
|
+
(contextValue?.config.variant === "standalone" ||
|
|
658
|
+
contextValue?.config.variant === "sidecar") &&
|
|
659
|
+
"h-full",
|
|
649
660
|
)}
|
|
650
661
|
>
|
|
651
662
|
{children}
|
|
@@ -656,19 +667,19 @@ const ElementsProviderWithHistory = ({
|
|
|
656
667
|
</ChatIdContext.Provider>
|
|
657
668
|
</HistoryProvider>
|
|
658
669
|
</AssistantRuntimeProvider>
|
|
659
|
-
)
|
|
660
|
-
}
|
|
670
|
+
);
|
|
671
|
+
};
|
|
661
672
|
|
|
662
673
|
// Separate component for non-history mode to avoid conditional hook calls
|
|
663
674
|
interface ElementsProviderWithoutHistoryProps {
|
|
664
|
-
children: ReactNode
|
|
665
|
-
transport: ChatTransport<UIMessage
|
|
666
|
-
contextValue: React.ContextType<typeof ElementsContext
|
|
667
|
-
runtimeRef: React.RefObject<ReturnType<typeof useChatRuntime> | null
|
|
675
|
+
children: ReactNode;
|
|
676
|
+
transport: ChatTransport<UIMessage>;
|
|
677
|
+
contextValue: React.ContextType<typeof ElementsContext>;
|
|
678
|
+
runtimeRef: React.RefObject<ReturnType<typeof useChatRuntime> | null>;
|
|
668
679
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
669
|
-
frontendTools: Record<string, AssistantTool | FrontendTool<any, any
|
|
670
|
-
executableTools: ExecutableToolSet
|
|
671
|
-
currentChatId: string | null
|
|
680
|
+
frontendTools: Record<string, AssistantTool | FrontendTool<any, any>>;
|
|
681
|
+
executableTools: ExecutableToolSet;
|
|
682
|
+
currentChatId: string | null;
|
|
672
683
|
}
|
|
673
684
|
|
|
674
685
|
const ElementsProviderWithoutHistory = ({
|
|
@@ -680,12 +691,12 @@ const ElementsProviderWithoutHistory = ({
|
|
|
680
691
|
executableTools,
|
|
681
692
|
currentChatId,
|
|
682
693
|
}: ElementsProviderWithoutHistoryProps) => {
|
|
683
|
-
const runtime = useChatRuntime({ transport })
|
|
694
|
+
const runtime = useChatRuntime({ transport });
|
|
684
695
|
|
|
685
696
|
// Populate runtimeRef so transport can access thread context
|
|
686
697
|
useEffect(() => {
|
|
687
|
-
runtimeRef.current = runtime
|
|
688
|
-
}, [runtime, runtimeRef])
|
|
698
|
+
runtimeRef.current = runtime;
|
|
699
|
+
}, [runtime, runtimeRef]);
|
|
689
700
|
|
|
690
701
|
return (
|
|
691
702
|
<AssistantRuntimeProvider runtime={runtime}>
|
|
@@ -695,9 +706,9 @@ const ElementsProviderWithoutHistory = ({
|
|
|
695
706
|
<div
|
|
696
707
|
className={cn(
|
|
697
708
|
ROOT_SELECTOR,
|
|
698
|
-
(contextValue?.config.variant ===
|
|
699
|
-
contextValue?.config.variant ===
|
|
700
|
-
|
|
709
|
+
(contextValue?.config.variant === "standalone" ||
|
|
710
|
+
contextValue?.config.variant === "sidecar") &&
|
|
711
|
+
"h-full",
|
|
701
712
|
)}
|
|
702
713
|
>
|
|
703
714
|
{children}
|
|
@@ -707,10 +718,10 @@ const ElementsProviderWithoutHistory = ({
|
|
|
707
718
|
</ElementsContext.Provider>
|
|
708
719
|
</ChatIdContext.Provider>
|
|
709
720
|
</AssistantRuntimeProvider>
|
|
710
|
-
)
|
|
711
|
-
}
|
|
721
|
+
);
|
|
722
|
+
};
|
|
712
723
|
|
|
713
|
-
const queryClient = new QueryClient()
|
|
724
|
+
const queryClient = new QueryClient();
|
|
714
725
|
|
|
715
726
|
export const ElementsProvider = (props: ElementsProviderProps) => {
|
|
716
727
|
return (
|
|
@@ -721,5 +732,5 @@ export const ElementsProvider = (props: ElementsProviderProps) => {
|
|
|
721
732
|
</ToolApprovalProvider>
|
|
722
733
|
</ConnectionStatusProvider>
|
|
723
734
|
</QueryClientProvider>
|
|
724
|
-
)
|
|
725
|
-
}
|
|
735
|
+
);
|
|
736
|
+
};
|