@gram-ai/elements 1.34.0 → 1.35.0
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/dist/compat-shims-CO9JXXV4.cjs.map +1 -1
- package/dist/compat-shims-DxtUrORi.js.map +1 -1
- package/dist/compat-shims.d.ts +9 -8
- package/dist/components/Chat/index.d.ts +2 -1
- package/dist/components/ChatHistory.d.ts +1 -1
- package/dist/components/FrontendTools/index.d.ts +1 -1
- package/dist/components/Replay.d.ts +1 -1
- package/dist/components/Replay.stories.d.ts +2 -2
- package/dist/components/ShadowRoot.d.ts +1 -1
- package/dist/components/ShareButton/index.d.ts +1 -1
- package/dist/components/ui/avatar.d.ts +3 -3
- package/dist/components/ui/button.d.ts +2 -2
- package/dist/components/ui/buttonVariants.d.ts +2 -2
- package/dist/components/ui/calendar.d.ts +2 -1
- package/dist/components/ui/collapsible.d.ts +3 -3
- package/dist/components/ui/dialog.d.ts +10 -10
- package/dist/components/ui/popover.d.ts +4 -4
- package/dist/components/ui/skeleton.d.ts +1 -1
- package/dist/components/ui/time-range-picker.d.ts +2 -1
- package/dist/components/ui/tool-ui.d.ts +7 -7
- package/dist/components/ui/tooltip.d.ts +4 -4
- package/dist/contexts/ConnectionStatusContext.d.ts +1 -1
- package/dist/contexts/ElementsProvider.d.ts +1 -1
- package/dist/contexts/ToolApprovalContext.d.ts +2 -2
- package/dist/contexts/ToolExecutionContext.d.ts +1 -1
- package/dist/contexts/portal-container.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 +1 -1
- package/dist/hooks/useElements.d.ts +2 -1
- package/dist/hooks/useGramThreadListAdapter.d.ts +13 -0
- package/dist/hooks/useRadius.d.ts +1 -1
- package/dist/hooks/useThemeProps.d.ts +1 -1
- package/dist/hooks/useToolApproval.d.ts +2 -1
- package/dist/{index-BFU6NvbL.js → index-BhIowiZF.js} +9408 -9204
- package/dist/index-BhIowiZF.js.map +1 -0
- package/dist/{index-C08dvTEo.cjs → index-D0jIGQr7.cjs} +3 -3
- package/dist/index-D0jIGQr7.cjs.map +1 -0
- package/dist/{index-B5lZrrO2.js → index-Dz13dSDa.js} +57 -15
- package/dist/index-Dz13dSDa.js.map +1 -0
- package/dist/index-PXd3rs95.cjs +194 -0
- package/dist/index-PXd3rs95.cjs.map +1 -0
- package/dist/lib/errorTracking.d.ts +1 -1
- package/dist/lib/tools.d.ts +11 -10
- package/dist/plugins/generative-ui/catalog.d.ts +3 -3
- package/dist/plugins/generative-ui/ui/accordion-wrapper.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/accordion.d.ts +4 -4
- package/dist/plugins/generative-ui/ui/action-button.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/alert-wrapper.d.ts +2 -1
- package/dist/plugins/generative-ui/ui/alert.d.ts +3 -3
- package/dist/plugins/generative-ui/ui/avatar-wrapper.d.ts +2 -1
- package/dist/plugins/generative-ui/ui/avatar.d.ts +6 -6
- package/dist/plugins/generative-ui/ui/badge.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/button-wrapper.d.ts +2 -1
- package/dist/plugins/generative-ui/ui/button.d.ts +3 -3
- package/dist/plugins/generative-ui/ui/card-wrapper.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/card.d.ts +7 -7
- package/dist/plugins/generative-ui/ui/checkbox-wrapper.d.ts +2 -1
- package/dist/plugins/generative-ui/ui/checkbox.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/data-table.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/dialog.d.ts +10 -10
- package/dist/plugins/generative-ui/ui/dropdown-menu.d.ts +15 -15
- package/dist/plugins/generative-ui/ui/grid.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/index.d.ts +57 -40
- package/dist/plugins/generative-ui/ui/input-wrapper.d.ts +2 -1
- package/dist/plugins/generative-ui/ui/input.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/label.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/list.d.ts +2 -1
- package/dist/plugins/generative-ui/ui/metric.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/pagination.d.ts +7 -7
- package/dist/plugins/generative-ui/ui/popover.d.ts +7 -7
- package/dist/plugins/generative-ui/ui/progress.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/radio-group.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/select-wrapper.d.ts +2 -1
- package/dist/plugins/generative-ui/ui/select.d.ts +10 -10
- package/dist/plugins/generative-ui/ui/separator.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/skeleton-wrapper.d.ts +2 -1
- package/dist/plugins/generative-ui/ui/skeleton.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/stack.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/switch.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/table.d.ts +8 -8
- package/dist/plugins/generative-ui/ui/tabs-wrapper.d.ts +2 -2
- package/dist/plugins/generative-ui/ui/tabs.d.ts +4 -4
- package/dist/plugins/generative-ui/ui/text.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/textarea.d.ts +1 -1
- package/dist/plugins/generative-ui/ui/tooltip.d.ts +4 -4
- package/dist/plugins.cjs +1 -1
- package/dist/plugins.js +1 -1
- package/dist/{profiler-KLSTpp6I.js → profiler-CtGKTWWP.js} +2 -2
- package/dist/{profiler-KLSTpp6I.js.map → profiler-CtGKTWWP.js.map} +1 -1
- package/dist/{profiler-BRnyr1GA.cjs → profiler-l7_HjTyw.cjs} +2 -2
- package/dist/{profiler-BRnyr1GA.cjs.map → profiler-l7_HjTyw.cjs.map} +1 -1
- package/dist/react-shim.cjs.map +1 -1
- package/dist/react-shim.d.ts +1 -1
- package/dist/react-shim.js +1 -4
- package/dist/react-shim.js.map +1 -1
- package/dist/server/bun.cjs.map +1 -1
- package/dist/server/bun.js.map +1 -1
- package/dist/server/express.cjs.map +1 -1
- package/dist/server/express.js.map +1 -1
- package/dist/server/fastify.cjs.map +1 -1
- package/dist/server/fastify.js.map +1 -1
- package/dist/server/hono.cjs.map +1 -1
- package/dist/server/hono.js.map +1 -1
- package/dist/server/nextjs.cjs.map +1 -1
- package/dist/server/nextjs.js.map +1 -1
- package/dist/server/tanstack-start.cjs.map +1 -1
- package/dist/server/tanstack-start.js.map +1 -1
- package/dist/{startRecording-CKx-YWbq.cjs → startRecording-DEw2Aeq4.cjs} +2 -2
- package/dist/{startRecording-CKx-YWbq.cjs.map → startRecording-DEw2Aeq4.cjs.map} +1 -1
- package/dist/{startRecording-BfxB1xxR.js → startRecording-iYEL0-vr.js} +2 -2
- package/dist/{startRecording-BfxB1xxR.js.map → startRecording-iYEL0-vr.js.map} +1 -1
- package/dist/types/index.d.ts +29 -3
- package/package.json +7 -10
- package/src/compat-shims.ts +16 -2
- package/src/components/Chat/index.tsx +4 -1
- package/src/components/Chat/stories/FrontendTools.stories.tsx +1 -1
- package/src/components/Chat/stories/ToolApproval.stories.tsx +2 -2
- package/src/components/Chat/stories/Tools.stories.tsx +13 -5
- package/src/components/ChatHistory.tsx +3 -1
- package/src/components/FrontendTools/index.tsx +1 -1
- package/src/components/MessageContent.tsx +1 -0
- package/src/components/Replay.stories.tsx +2 -3
- package/src/components/Replay.tsx +17 -10
- package/src/components/ShadowRoot.tsx +2 -2
- package/src/components/ShareButton/index.tsx +4 -2
- package/src/components/assistant-ui/assistant-modal.tsx +5 -3
- package/src/components/assistant-ui/attachment.tsx +1 -1
- package/src/components/assistant-ui/error-boundary.tsx +1 -1
- package/src/components/assistant-ui/markdown-text.tsx +1 -1
- package/src/components/assistant-ui/thread.tsx +249 -11
- package/src/components/assistant-ui/tool-mention-autocomplete.tsx +1 -1
- package/src/components/ui/avatar.tsx +3 -3
- package/src/components/ui/calendar.tsx +1 -1
- package/src/components/ui/collapsible.tsx +7 -3
- package/src/components/ui/dialog.tsx +18 -10
- package/src/components/ui/generative-ui.tsx +9 -4
- package/src/components/ui/popover.tsx +4 -4
- package/src/components/ui/skeleton.tsx +4 -1
- package/src/components/ui/time-range-picker.stories.tsx +164 -154
- package/src/components/ui/time-range-picker.tsx +11 -5
- package/src/components/ui/tool-ui.tsx +18 -9
- package/src/components/ui/tooltip.tsx +4 -4
- package/src/contexts/ChatIdContext.tsx +1 -1
- package/src/contexts/ConnectionStatusContext.tsx +6 -5
- package/src/contexts/ElementsProvider.tsx +64 -41
- package/src/contexts/ReplayContext.ts +1 -1
- package/src/contexts/ToolApprovalContext.tsx +5 -1
- package/src/contexts/ToolExecutionContext.tsx +1 -1
- package/src/contexts/portal-container.tsx +1 -1
- package/src/hooks/useAuth.ts +2 -1
- package/src/hooks/useDensity.ts +1 -1
- package/src/hooks/useElements.ts +2 -1
- package/src/hooks/useFollowOnSuggestions.ts +3 -6
- package/src/hooks/useGramThreadListAdapter.tsx +50 -3
- package/src/hooks/useMCPTools.ts +2 -2
- package/src/hooks/useModel.ts +1 -3
- package/src/hooks/usePluginComponents.ts +3 -1
- package/src/hooks/useRadius.ts +1 -1
- package/src/hooks/useSession.ts +3 -1
- package/src/hooks/useThemeProps.ts +5 -5
- package/src/hooks/useToolApproval.ts +2 -1
- package/src/lib/cassette.ts +20 -8
- package/src/lib/errorTracking.ts +1 -4
- package/src/lib/messageConverter.test.ts +11 -13
- package/src/lib/messageConverter.ts +13 -4
- package/src/lib/token.ts +2 -5
- package/src/lib/tool-mentions.ts +5 -2
- package/src/lib/tools.byte-cap.test.ts +1 -1
- package/src/lib/tools.test.ts +1 -1
- package/src/lib/tools.ts +15 -5
- package/src/lib/utils.ts +2 -2
- package/src/lib.d.ts +8 -1
- package/src/plugins/chart/chart.test.ts +3 -4
- package/src/plugins/chart/component.tsx +7 -6
- package/src/plugins/chart/ui/area-chart.tsx +1 -1
- package/src/plugins/chart/ui/line-chart.tsx +1 -1
- package/src/plugins/generative-ui/ui/accordion-wrapper.tsx +2 -2
- package/src/plugins/generative-ui/ui/accordion.tsx +4 -4
- package/src/plugins/generative-ui/ui/action-button.tsx +4 -2
- package/src/plugins/generative-ui/ui/alert-wrapper.tsx +1 -1
- package/src/plugins/generative-ui/ui/alert.tsx +7 -3
- package/src/plugins/generative-ui/ui/avatar-wrapper.tsx +5 -1
- package/src/plugins/generative-ui/ui/avatar.tsx +12 -6
- package/src/plugins/generative-ui/ui/badge.tsx +1 -1
- package/src/plugins/generative-ui/ui/button-wrapper.tsx +1 -1
- package/src/plugins/generative-ui/ui/button.tsx +1 -1
- package/src/plugins/generative-ui/ui/card-wrapper.tsx +1 -1
- package/src/plugins/generative-ui/ui/card.tsx +28 -7
- package/src/plugins/generative-ui/ui/checkbox-wrapper.tsx +1 -1
- package/src/plugins/generative-ui/ui/checkbox.tsx +1 -1
- package/src/plugins/generative-ui/ui/data-table.tsx +1 -1
- package/src/plugins/generative-ui/ui/dialog.tsx +15 -10
- package/src/plugins/generative-ui/ui/dropdown-menu.tsx +33 -15
- package/src/plugins/generative-ui/ui/grid.tsx +1 -1
- package/src/plugins/generative-ui/ui/index.ts +154 -40
- package/src/plugins/generative-ui/ui/input-wrapper.tsx +1 -1
- package/src/plugins/generative-ui/ui/input.tsx +5 -1
- package/src/plugins/generative-ui/ui/label.tsx +1 -1
- package/src/plugins/generative-ui/ui/list.tsx +5 -1
- package/src/plugins/generative-ui/ui/metric.tsx +2 -1
- package/src/plugins/generative-ui/ui/pagination.tsx +12 -7
- package/src/plugins/generative-ui/ui/popover.tsx +13 -7
- package/src/plugins/generative-ui/ui/progress.tsx +1 -1
- package/src/plugins/generative-ui/ui/radio-group.tsx +2 -2
- package/src/plugins/generative-ui/ui/select-wrapper.tsx +1 -1
- package/src/plugins/generative-ui/ui/select.tsx +14 -10
- package/src/plugins/generative-ui/ui/separator.tsx +1 -1
- package/src/plugins/generative-ui/ui/skeleton-wrapper.tsx +1 -1
- package/src/plugins/generative-ui/ui/skeleton.tsx +4 -1
- package/src/plugins/generative-ui/ui/stack.tsx +1 -1
- package/src/plugins/generative-ui/ui/switch.tsx +1 -1
- package/src/plugins/generative-ui/ui/table.tsx +29 -8
- package/src/plugins/generative-ui/ui/tabs-wrapper.tsx +5 -2
- package/src/plugins/generative-ui/ui/tabs.tsx +4 -4
- package/src/plugins/generative-ui/ui/text.tsx +1 -1
- package/src/plugins/generative-ui/ui/textarea.tsx +4 -1
- package/src/plugins/generative-ui/ui/tooltip.tsx +4 -4
- package/src/react-shim.ts +9 -4
- package/src/server/bun.ts +1 -1
- package/src/server/express.ts +1 -1
- package/src/server/fastify.ts +1 -1
- package/src/server/hono.ts +1 -1
- package/src/server/nextjs.ts +1 -1
- package/src/server/tanstack-start.ts +1 -1
- package/src/storybook.d.ts +5 -0
- package/src/types/index.ts +39 -3
- package/dist/index-B5lZrrO2.js.map +0 -1
- package/dist/index-BFU6NvbL.js.map +0 -1
- package/dist/index-C08dvTEo.cjs.map +0 -1
- package/dist/index-DzZ1-jQY.cjs +0 -194
- package/dist/index-DzZ1-jQY.cjs.map +0 -1
package/src/compat-shims.ts
CHANGED
|
@@ -39,6 +39,7 @@ function createUseSyncExternalStoreShim(R: ReactLike) {
|
|
|
39
39
|
inst.value = value;
|
|
40
40
|
inst.getSnapshot = getSnapshot;
|
|
41
41
|
if (snapshotChanged(inst)) forceUpdate({ inst });
|
|
42
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
42
43
|
}, [subscribe, value, getSnapshot]);
|
|
43
44
|
|
|
44
45
|
R.useEffect(() => {
|
|
@@ -46,6 +47,7 @@ function createUseSyncExternalStoreShim(R: ReactLike) {
|
|
|
46
47
|
return subscribe(() => {
|
|
47
48
|
if (snapshotChanged(inst)) forceUpdate({ inst });
|
|
48
49
|
});
|
|
50
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
49
51
|
}, [subscribe]);
|
|
50
52
|
|
|
51
53
|
return value;
|
|
@@ -61,14 +63,26 @@ function createUseIdShim(R: ReactLike) {
|
|
|
61
63
|
};
|
|
62
64
|
}
|
|
63
65
|
|
|
66
|
+
export interface ReactShims {
|
|
67
|
+
useSyncExternalStore: <T>(
|
|
68
|
+
subscribe: (cb: () => void) => () => void,
|
|
69
|
+
getSnapshot: () => T,
|
|
70
|
+
) => T;
|
|
71
|
+
useId: () => string;
|
|
72
|
+
useInsertionEffect: typeof import("react").useLayoutEffect;
|
|
73
|
+
startTransition: (cb: () => void) => void;
|
|
74
|
+
useTransition: () => [boolean, (cb: () => void) => void];
|
|
75
|
+
useDeferredValue: <T>(value: T) => T;
|
|
76
|
+
}
|
|
77
|
+
|
|
64
78
|
/** Build polyfills for a React instance. Native APIs take precedence via ??. */
|
|
65
|
-
export function createShims(R: ReactLike) {
|
|
79
|
+
export function createShims(R: ReactLike): ReactShims {
|
|
66
80
|
return {
|
|
67
81
|
useSyncExternalStore:
|
|
68
82
|
R.useSyncExternalStore ?? createUseSyncExternalStoreShim(R),
|
|
69
83
|
useId: R.useId ?? createUseIdShim(R),
|
|
70
84
|
useInsertionEffect: R.useInsertionEffect ?? R.useLayoutEffect,
|
|
71
|
-
startTransition: R.startTransition ?? ((cb: () => void) => cb()),
|
|
85
|
+
startTransition: R.startTransition ?? ((cb: () => void): void => cb()),
|
|
72
86
|
useTransition:
|
|
73
87
|
R.useTransition ??
|
|
74
88
|
((): [boolean, (cb: () => void) => void] => [false, (cb) => cb()]),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import * as React from "react";
|
|
3
4
|
import { useElements } from "@/hooks/useElements";
|
|
4
5
|
import { AssistantModal } from "../assistant-ui/assistant-modal";
|
|
5
6
|
import { AssistantSidecar } from "../assistant-ui/assistant-sidecar";
|
|
@@ -11,7 +12,7 @@ interface ChatProps {
|
|
|
11
12
|
className?: string;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
export const Chat = ({ className }: ChatProps) => {
|
|
15
|
+
export const Chat = ({ className }: ChatProps): React.JSX.Element => {
|
|
15
16
|
const { config } = useElements();
|
|
16
17
|
|
|
17
18
|
switch (config.variant) {
|
|
@@ -34,6 +35,8 @@ export const Chat = ({ className }: ChatProps) => {
|
|
|
34
35
|
|
|
35
36
|
// If no variant is provided then fallback to the modal
|
|
36
37
|
// Modal has its own internal ErrorBoundary around Thread
|
|
38
|
+
case "widget":
|
|
39
|
+
case undefined:
|
|
37
40
|
default:
|
|
38
41
|
return (
|
|
39
42
|
<ShadowRoot>
|
|
@@ -29,7 +29,7 @@ const FetchTool = defineFrontendTool<{ url: string }, string>(
|
|
|
29
29
|
const text = await response.text();
|
|
30
30
|
return text;
|
|
31
31
|
} catch (error) {
|
|
32
|
-
return `Error fetching ${url}: ${error instanceof Error ? error.message : "Unknown error"}. Note: URL must support CORS for browser requests.`;
|
|
32
|
+
return `Error fetching ${String(url)}: ${error instanceof Error ? error.message : "Unknown error"}. Note: URL must support CORS for browser requests.`;
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
},
|
|
@@ -93,8 +93,8 @@ const deleteFile = defineFrontendTool<{ fileId: string }, string>(
|
|
|
93
93
|
fileId: z.string().describe("The ID of the file to delete"),
|
|
94
94
|
}),
|
|
95
95
|
execute: async ({ fileId }) => {
|
|
96
|
-
alert(`File ${fileId} deleted`);
|
|
97
|
-
return `File ${fileId} deleted`;
|
|
96
|
+
alert(`File ${String(fileId)} deleted`);
|
|
97
|
+
return `File ${String(fileId)} deleted`;
|
|
98
98
|
},
|
|
99
99
|
},
|
|
100
100
|
"deleteFile",
|
|
@@ -139,7 +139,9 @@ const ProductCardComponent = ({ result }: ToolCallMessagePartProps) => {
|
|
|
139
139
|
${product.price?.toFixed(2)}
|
|
140
140
|
</span>
|
|
141
141
|
<button
|
|
142
|
-
onClick={
|
|
142
|
+
onClick={() => {
|
|
143
|
+
void handleAddToCart();
|
|
144
|
+
}}
|
|
143
145
|
disabled={
|
|
144
146
|
isLoading || addedToCart || !canAddToCart || !product.inStock
|
|
145
147
|
}
|
|
@@ -242,8 +244,10 @@ const ApproveRequestTool = defineFrontendTool<{ id: number }, string>(
|
|
|
242
244
|
}),
|
|
243
245
|
execute: async ({ id }) => {
|
|
244
246
|
// Simulate API call
|
|
245
|
-
await new Promise((resolve) =>
|
|
246
|
-
|
|
247
|
+
await new Promise((resolve) => {
|
|
248
|
+
setTimeout(resolve, 500);
|
|
249
|
+
});
|
|
250
|
+
return `Request #${String(id)} has been approved successfully.`;
|
|
247
251
|
},
|
|
248
252
|
},
|
|
249
253
|
"approve_request",
|
|
@@ -260,8 +264,12 @@ const RejectRequestTool = defineFrontendTool<
|
|
|
260
264
|
reason: z.string().optional().describe("Reason for rejection"),
|
|
261
265
|
}),
|
|
262
266
|
execute: async ({ id, reason }) => {
|
|
263
|
-
await new Promise((resolve) =>
|
|
264
|
-
|
|
267
|
+
await new Promise((resolve) => {
|
|
268
|
+
setTimeout(resolve, 500);
|
|
269
|
+
});
|
|
270
|
+
return `Request #${String(id)} has been rejected.${
|
|
271
|
+
reason ? ` Reason: ${JSON.stringify(reason)}` : ""
|
|
272
|
+
}`;
|
|
265
273
|
},
|
|
266
274
|
},
|
|
267
275
|
"reject_request",
|
|
@@ -7,7 +7,9 @@ interface ChatHistoryProps {
|
|
|
7
7
|
className?: string;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export const ChatHistory = ({
|
|
10
|
+
export const ChatHistory = ({
|
|
11
|
+
className,
|
|
12
|
+
}: ChatHistoryProps): React.JSX.Element => {
|
|
11
13
|
return (
|
|
12
14
|
<ShadowRoot hostStyle={{ height: "inherit", width: "inherit" }}>
|
|
13
15
|
<ThreadList className={className} />
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import type { StoryFn } from "@storybook/react-vite";
|
|
1
|
+
import type { Meta, StoryFn } from "@storybook/react-vite";
|
|
2
2
|
import { Chat } from "@/components/Chat";
|
|
3
3
|
import { Replay } from "@/components/Replay";
|
|
4
4
|
import type { Cassette } from "@/lib/cassette";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
const meta: any = {
|
|
6
|
+
const meta: Meta<typeof Replay> = {
|
|
8
7
|
title: "Misc/Replay",
|
|
9
8
|
component: Replay,
|
|
10
9
|
parameters: {
|
|
@@ -63,17 +63,20 @@ export const Replay = ({
|
|
|
63
63
|
userMessageDelay,
|
|
64
64
|
assistantStartDelay,
|
|
65
65
|
onComplete,
|
|
66
|
-
}: ReplayProps) => {
|
|
67
|
-
const replayOptions
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
}: ReplayProps): React.JSX.Element => {
|
|
67
|
+
const replayOptions = useMemo<ReplayOptions>(
|
|
68
|
+
() => ({
|
|
69
|
+
typingSpeed,
|
|
70
|
+
userMessageDelay,
|
|
71
|
+
assistantStartDelay,
|
|
72
|
+
onComplete,
|
|
73
|
+
}),
|
|
74
|
+
[typingSpeed, userMessageDelay, assistantStartDelay, onComplete],
|
|
75
|
+
);
|
|
73
76
|
|
|
74
77
|
const transport = useMemo(
|
|
75
78
|
() => createReplayTransport(cassette, replayOptions),
|
|
76
|
-
[cassette,
|
|
79
|
+
[cassette, replayOptions],
|
|
77
80
|
);
|
|
78
81
|
|
|
79
82
|
const runtime = useChatRuntime({ transport });
|
|
@@ -108,6 +111,7 @@ export const Replay = ({
|
|
|
108
111
|
setIsOpen: () => {},
|
|
109
112
|
plugins,
|
|
110
113
|
mcpTools: undefined,
|
|
114
|
+
mcpToolsLoading: false,
|
|
111
115
|
}),
|
|
112
116
|
[config, plugins],
|
|
113
117
|
);
|
|
@@ -148,7 +152,9 @@ export const Replay = ({
|
|
|
148
152
|
// ---------------------------------------------------------------------------
|
|
149
153
|
|
|
150
154
|
function sleep(ms: number): Promise<void> {
|
|
151
|
-
return new Promise((resolve) =>
|
|
155
|
+
return new Promise((resolve) => {
|
|
156
|
+
setTimeout(resolve, ms);
|
|
157
|
+
});
|
|
152
158
|
}
|
|
153
159
|
|
|
154
160
|
/**
|
|
@@ -238,11 +244,12 @@ const ReplayController = ({ cassette, options }: ReplayControllerProps) => {
|
|
|
238
244
|
options.onComplete?.();
|
|
239
245
|
};
|
|
240
246
|
|
|
241
|
-
runReplay();
|
|
247
|
+
void runReplay();
|
|
242
248
|
|
|
243
249
|
return () => {
|
|
244
250
|
cancelled = true;
|
|
245
251
|
};
|
|
252
|
+
// oxlint-disable-next-line react-hooks/exhaustive-deps -- run-once driver, see hasStarted ref
|
|
246
253
|
}, []);
|
|
247
254
|
|
|
248
255
|
return null;
|
|
@@ -26,7 +26,7 @@ export const ShadowRoot = ({
|
|
|
26
26
|
children,
|
|
27
27
|
hostClassName,
|
|
28
28
|
hostStyle,
|
|
29
|
-
}: ShadowRootProps) => {
|
|
29
|
+
}: ShadowRootProps): React.JSX.Element => {
|
|
30
30
|
const hostRef = useRef<HTMLDivElement>(null);
|
|
31
31
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
32
32
|
const [shadowRoot, setShadowRoot] = useState<ShadowRoot | null>(null);
|
|
@@ -66,7 +66,7 @@ export const ShadowRoot = ({
|
|
|
66
66
|
styleElement.setAttribute("data-gram-elements", "true");
|
|
67
67
|
styleElement.textContent = elementsStyles;
|
|
68
68
|
shadowRoot.prepend(styleElement);
|
|
69
|
-
}, [shadowRoot
|
|
69
|
+
}, [shadowRoot]);
|
|
70
70
|
|
|
71
71
|
return (
|
|
72
72
|
<div
|
|
@@ -80,7 +80,7 @@ export function ShareButton({
|
|
|
80
80
|
size = "sm",
|
|
81
81
|
className,
|
|
82
82
|
children,
|
|
83
|
-
}: ShareButtonProps) {
|
|
83
|
+
}: ShareButtonProps): React.JSX.Element {
|
|
84
84
|
const { threadId } = useThreadId();
|
|
85
85
|
|
|
86
86
|
const handleShare = useCallback(async () => {
|
|
@@ -118,7 +118,9 @@ export function ShareButton({
|
|
|
118
118
|
<Button
|
|
119
119
|
variant={variant}
|
|
120
120
|
size={size}
|
|
121
|
-
onClick={
|
|
121
|
+
onClick={() => {
|
|
122
|
+
void handleShare();
|
|
123
|
+
}}
|
|
122
124
|
disabled={!threadId}
|
|
123
125
|
className={cn("aui-share-button", className)}
|
|
124
126
|
aria-label="Share chat"
|
|
@@ -36,9 +36,9 @@ const LAYOUT_TRANSITION = {
|
|
|
36
36
|
} as const;
|
|
37
37
|
|
|
38
38
|
type Dimensions = {
|
|
39
|
-
width?: string | number
|
|
40
|
-
height?: string | number
|
|
41
|
-
maxHeight?: string | number
|
|
39
|
+
width?: string | number;
|
|
40
|
+
height?: string | number;
|
|
41
|
+
maxHeight?: string | number;
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
interface AssistantModalProps {
|
|
@@ -277,6 +277,8 @@ function positionClassname(
|
|
|
277
277
|
return "left-4 top-4";
|
|
278
278
|
case "bottom-right":
|
|
279
279
|
return "right-4 bottom-4";
|
|
280
|
+
case undefined:
|
|
281
|
+
return "right-4 bottom-4";
|
|
280
282
|
default:
|
|
281
283
|
assertNever(position);
|
|
282
284
|
}
|
|
@@ -140,7 +140,7 @@ const AttachmentUI: FC = () => {
|
|
|
140
140
|
return "File";
|
|
141
141
|
default: {
|
|
142
142
|
const _exhaustiveCheck: never = type;
|
|
143
|
-
throw new Error(`Unknown attachment type: ${_exhaustiveCheck}`);
|
|
143
|
+
throw new Error(`Unknown attachment type: ${String(_exhaustiveCheck)}`);
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
});
|
|
@@ -90,7 +90,7 @@ export class ErrorBoundary extends Component<
|
|
|
90
90
|
this.props.onError?.(error, errorInfo);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
handleRetry = () => {
|
|
93
|
+
handleRetry = (): void => {
|
|
94
94
|
// Increment resetKey to force remount of children, reinitializing the chat
|
|
95
95
|
this.setState((state) => ({
|
|
96
96
|
hasError: false,
|
|
@@ -66,7 +66,7 @@ const useCopyToClipboard = ({
|
|
|
66
66
|
const copyToClipboard = (value: string) => {
|
|
67
67
|
if (!value) return;
|
|
68
68
|
|
|
69
|
-
navigator.clipboard.writeText(value).then(() => {
|
|
69
|
+
void navigator.clipboard.writeText(value).then(() => {
|
|
70
70
|
setIsCopied(true);
|
|
71
71
|
setTimeout(() => setIsCopied(false), copiedDuration);
|
|
72
72
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ArrowDownIcon,
|
|
3
3
|
ArrowUpIcon,
|
|
4
|
+
AtSign,
|
|
4
5
|
CheckIcon,
|
|
5
6
|
ChevronLeftIcon,
|
|
6
7
|
ChevronRightIcon,
|
|
@@ -8,8 +9,10 @@ import {
|
|
|
8
9
|
CopyIcon,
|
|
9
10
|
DownloadIcon,
|
|
10
11
|
PencilIcon,
|
|
12
|
+
Search,
|
|
11
13
|
Settings2,
|
|
12
14
|
Square,
|
|
15
|
+
Wrench,
|
|
13
16
|
} from "lucide-react";
|
|
14
17
|
|
|
15
18
|
import {
|
|
@@ -20,6 +23,7 @@ import {
|
|
|
20
23
|
ImageMessagePartProps,
|
|
21
24
|
MessagePrimitive,
|
|
22
25
|
ThreadPrimitive,
|
|
26
|
+
useAssistantApi,
|
|
23
27
|
useAssistantState,
|
|
24
28
|
} from "@assistant-ui/react";
|
|
25
29
|
|
|
@@ -68,6 +72,10 @@ import { useToolMentions } from "@/hooks/useToolMentions";
|
|
|
68
72
|
import { getApiUrl } from "@/lib/api";
|
|
69
73
|
import { EASE_OUT_QUINT } from "@/lib/easing";
|
|
70
74
|
import { MODELS } from "@/lib/models";
|
|
75
|
+
import {
|
|
76
|
+
type MentionableTool,
|
|
77
|
+
toolSetToMentionableTools,
|
|
78
|
+
} from "@/lib/tool-mentions";
|
|
71
79
|
import { cn } from "@/lib/utils";
|
|
72
80
|
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
|
73
81
|
import {
|
|
@@ -262,7 +270,7 @@ const ThreadScrollToBottom: FC = () => {
|
|
|
262
270
|
const ThreadWelcome: FC = () => {
|
|
263
271
|
const { config } = useElements();
|
|
264
272
|
const d = useDensity();
|
|
265
|
-
const { title, subtitle } = config.welcome ?? {};
|
|
273
|
+
const { logo, title, subtitle } = config.welcome ?? {};
|
|
266
274
|
const isStandalone = config.variant === "standalone";
|
|
267
275
|
|
|
268
276
|
return (
|
|
@@ -288,6 +296,19 @@ const ThreadWelcome: FC = () => {
|
|
|
288
296
|
!isStandalone && d("py-md"),
|
|
289
297
|
)}
|
|
290
298
|
>
|
|
299
|
+
{logo && (
|
|
300
|
+
<m.img
|
|
301
|
+
src={logo}
|
|
302
|
+
alt=""
|
|
303
|
+
initial={{ opacity: 0, y: 10 }}
|
|
304
|
+
animate={{ opacity: 1, y: 0 }}
|
|
305
|
+
exit={{ opacity: 0, y: 10 }}
|
|
306
|
+
transition={{ duration: 0.25, ease: EASE_OUT_QUINT }}
|
|
307
|
+
className={cn(
|
|
308
|
+
"aui-thread-welcome-logo mb-2 size-12 object-contain",
|
|
309
|
+
)}
|
|
310
|
+
/>
|
|
311
|
+
)}
|
|
291
312
|
<m.div
|
|
292
313
|
initial={{ opacity: 0, y: 10 }}
|
|
293
314
|
animate={{ opacity: 1, y: 0 }}
|
|
@@ -524,7 +545,9 @@ const ComposerFeedback: FC = () => {
|
|
|
524
545
|
<MessageFeedback
|
|
525
546
|
className="mx-auto"
|
|
526
547
|
onResolved={setResolved}
|
|
527
|
-
onFeedback={
|
|
548
|
+
onFeedback={(type) => {
|
|
549
|
+
void handleFeedback(type);
|
|
550
|
+
}}
|
|
528
551
|
/>
|
|
529
552
|
</m.div>
|
|
530
553
|
)}
|
|
@@ -794,6 +817,218 @@ const ComposerCassetteRecorder: FC = () => {
|
|
|
794
817
|
);
|
|
795
818
|
};
|
|
796
819
|
|
|
820
|
+
// Sentinel for the "All" pseudo-category in the tool-mention picker.
|
|
821
|
+
const TOOL_MENTION_ALL_CATEGORY = "__all__";
|
|
822
|
+
|
|
823
|
+
function humanizeToolCategory(raw: string): string {
|
|
824
|
+
const cleaned = raw.replace(/[-_]+/g, " ").trim();
|
|
825
|
+
if (!cleaned) return "Tools";
|
|
826
|
+
return cleaned.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// Derive a grouping label for a tool. Tools from multiple MCP servers are
|
|
830
|
+
// namespaced as `<server>__<tool>`; otherwise group by the first
|
|
831
|
+
// underscore-delimited segment (e.g. `platform_search_logs` -> "Platform"),
|
|
832
|
+
// falling back to a single "Tools" bucket.
|
|
833
|
+
function deriveToolCategory(name: string): string {
|
|
834
|
+
const namespaceIdx = name.indexOf("__");
|
|
835
|
+
if (namespaceIdx > 0)
|
|
836
|
+
return humanizeToolCategory(name.slice(0, namespaceIdx));
|
|
837
|
+
const underscoreIdx = name.indexOf("_");
|
|
838
|
+
if (underscoreIdx > 0)
|
|
839
|
+
return humanizeToolCategory(name.slice(0, underscoreIdx));
|
|
840
|
+
return "Tools";
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
interface ToolCategory {
|
|
844
|
+
name: string;
|
|
845
|
+
tools: MentionableTool[];
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// A discoverable counterpart to the type-`@` autocomplete: a composer button
|
|
849
|
+
// that opens a searchable, category-grouped picker of the available tools and
|
|
850
|
+
// inserts an @mention for the chosen one. Inserts through the composer runtime
|
|
851
|
+
// so it stays in sync with the autocomplete's own textarea handling. Hidden when
|
|
852
|
+
// tool mentions are disabled or there are no tools.
|
|
853
|
+
const ComposerToolMentionPicker: FC = () => {
|
|
854
|
+
const { config, mcpTools, mcpToolsLoading } = useElements();
|
|
855
|
+
const api = useAssistantApi();
|
|
856
|
+
// Read the composer text from the same reactive source the tool-mention
|
|
857
|
+
// badges parse, so an inserted mention renders a pill just like the type-`@`
|
|
858
|
+
// autocomplete does.
|
|
859
|
+
const composerText = useAssistantState(({ composer }) => composer.text);
|
|
860
|
+
const [open, setOpen] = useState(false);
|
|
861
|
+
const [query, setQuery] = useState("");
|
|
862
|
+
const [activeCategory, setActiveCategory] = useState(
|
|
863
|
+
TOOL_MENTION_ALL_CATEGORY,
|
|
864
|
+
);
|
|
865
|
+
|
|
866
|
+
const composerConfig = config.composer;
|
|
867
|
+
const toolMentionsEnabled =
|
|
868
|
+
composerConfig?.toolMentions === undefined ||
|
|
869
|
+
composerConfig.toolMentions === true ||
|
|
870
|
+
(typeof composerConfig.toolMentions === "object" &&
|
|
871
|
+
composerConfig.toolMentions.enabled !== false);
|
|
872
|
+
|
|
873
|
+
const tools = useMemo(() => toolSetToMentionableTools(mcpTools), [mcpTools]);
|
|
874
|
+
|
|
875
|
+
const categories = useMemo<ToolCategory[]>(() => {
|
|
876
|
+
const grouped = new Map<string, MentionableTool[]>();
|
|
877
|
+
for (const tool of tools) {
|
|
878
|
+
const category = deriveToolCategory(tool.name);
|
|
879
|
+
const existing = grouped.get(category);
|
|
880
|
+
if (existing) {
|
|
881
|
+
existing.push(tool);
|
|
882
|
+
} else {
|
|
883
|
+
grouped.set(category, [tool]);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
return [...grouped.entries()]
|
|
887
|
+
.map(([name, categoryTools]) => ({ name, tools: categoryTools }))
|
|
888
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
889
|
+
}, [tools]);
|
|
890
|
+
|
|
891
|
+
// Show the button while tools are still loading (so it appears immediately
|
|
892
|
+
// rather than popping in once the async MCP list resolves) or once there are
|
|
893
|
+
// tools — but hide it when the list has loaded and is empty, so we don't
|
|
894
|
+
// expose a dead-end control.
|
|
895
|
+
if (!toolMentionsEnabled || (!mcpToolsLoading && tools.length === 0)) {
|
|
896
|
+
return null;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
900
|
+
const inActiveCategory =
|
|
901
|
+
activeCategory === TOOL_MENTION_ALL_CATEGORY
|
|
902
|
+
? tools
|
|
903
|
+
: (categories.find((c) => c.name === activeCategory)?.tools ?? []);
|
|
904
|
+
const visibleTools = normalizedQuery
|
|
905
|
+
? inActiveCategory.filter(
|
|
906
|
+
(tool) =>
|
|
907
|
+
tool.name.toLowerCase().includes(normalizedQuery) ||
|
|
908
|
+
(tool.description?.toLowerCase().includes(normalizedQuery) ?? false),
|
|
909
|
+
)
|
|
910
|
+
: inActiveCategory;
|
|
911
|
+
|
|
912
|
+
const insertMention = (toolName: string) => {
|
|
913
|
+
const base =
|
|
914
|
+
composerText && !/\s$/.test(composerText)
|
|
915
|
+
? `${composerText} `
|
|
916
|
+
: composerText;
|
|
917
|
+
api.composer().setText(`${base}@${toolName} `);
|
|
918
|
+
setOpen(false);
|
|
919
|
+
setQuery("");
|
|
920
|
+
};
|
|
921
|
+
|
|
922
|
+
const handleOpenChange = (next: boolean) => {
|
|
923
|
+
setOpen(next);
|
|
924
|
+
if (!next) {
|
|
925
|
+
setQuery("");
|
|
926
|
+
setActiveCategory(TOOL_MENTION_ALL_CATEGORY);
|
|
927
|
+
}
|
|
928
|
+
};
|
|
929
|
+
|
|
930
|
+
return (
|
|
931
|
+
<Popover open={open} onOpenChange={handleOpenChange}>
|
|
932
|
+
<PopoverTrigger asChild>
|
|
933
|
+
<Button
|
|
934
|
+
variant="ghost"
|
|
935
|
+
size="icon"
|
|
936
|
+
data-state={open ? "open" : "closed"}
|
|
937
|
+
className="aui-composer-tool-mention-picker flex w-fit items-center gap-2 rounded-full px-2.5 py-1 text-xs font-semibold data-[state=open]:bg-muted-foreground/15 dark:border-muted-foreground/15 dark:hover:bg-muted-foreground/30"
|
|
938
|
+
aria-label="Mention a tool"
|
|
939
|
+
>
|
|
940
|
+
<AtSign className="size-5 stroke-[1.5px]" />
|
|
941
|
+
</Button>
|
|
942
|
+
</PopoverTrigger>
|
|
943
|
+
<PopoverContent
|
|
944
|
+
side="top"
|
|
945
|
+
align="start"
|
|
946
|
+
className="aui-composer-tool-mention-popover w-[420px] overflow-hidden p-0"
|
|
947
|
+
>
|
|
948
|
+
<div className="flex items-center gap-2 border-b border-input px-3 py-2">
|
|
949
|
+
<Search className="size-4 shrink-0 text-muted-foreground" />
|
|
950
|
+
<input
|
|
951
|
+
autoFocus
|
|
952
|
+
value={query}
|
|
953
|
+
onChange={(e) => setQuery(e.target.value)}
|
|
954
|
+
placeholder="Search tools…"
|
|
955
|
+
className="w-full bg-transparent text-sm text-foreground outline-none placeholder:text-muted-foreground"
|
|
956
|
+
aria-label="Search tools"
|
|
957
|
+
/>
|
|
958
|
+
</div>
|
|
959
|
+
<div className="flex h-72">
|
|
960
|
+
<div className="w-36 shrink-0 overflow-y-auto border-r border-input p-2">
|
|
961
|
+
<div className="px-2 pb-1 text-[10px] font-semibold tracking-wide text-muted-foreground uppercase">
|
|
962
|
+
Categories
|
|
963
|
+
</div>
|
|
964
|
+
<button
|
|
965
|
+
type="button"
|
|
966
|
+
onClick={() => setActiveCategory(TOOL_MENTION_ALL_CATEGORY)}
|
|
967
|
+
className={cn(
|
|
968
|
+
"flex w-full items-center justify-between rounded px-2 py-1 text-left text-xs transition-colors",
|
|
969
|
+
activeCategory === TOOL_MENTION_ALL_CATEGORY
|
|
970
|
+
? "bg-muted font-medium text-foreground"
|
|
971
|
+
: "text-muted-foreground hover:bg-muted/60",
|
|
972
|
+
)}
|
|
973
|
+
>
|
|
974
|
+
<span className="truncate">All</span>
|
|
975
|
+
<span className="ml-2 shrink-0 tabular-nums opacity-60">
|
|
976
|
+
{tools.length}
|
|
977
|
+
</span>
|
|
978
|
+
</button>
|
|
979
|
+
{categories.map((category) => (
|
|
980
|
+
<button
|
|
981
|
+
key={category.name}
|
|
982
|
+
type="button"
|
|
983
|
+
onClick={() => setActiveCategory(category.name)}
|
|
984
|
+
className={cn(
|
|
985
|
+
"flex w-full items-center justify-between rounded px-2 py-1 text-left text-xs transition-colors",
|
|
986
|
+
activeCategory === category.name
|
|
987
|
+
? "bg-muted font-medium text-foreground"
|
|
988
|
+
: "text-muted-foreground hover:bg-muted/60",
|
|
989
|
+
)}
|
|
990
|
+
>
|
|
991
|
+
<span className="truncate">{category.name}</span>
|
|
992
|
+
<span className="ml-2 shrink-0 tabular-nums opacity-60">
|
|
993
|
+
{category.tools.length}
|
|
994
|
+
</span>
|
|
995
|
+
</button>
|
|
996
|
+
))}
|
|
997
|
+
</div>
|
|
998
|
+
<div className="min-w-0 flex-1 overflow-y-auto p-2">
|
|
999
|
+
{visibleTools.length === 0 ? (
|
|
1000
|
+
<div className="px-2 py-6 text-center text-xs text-muted-foreground">
|
|
1001
|
+
{mcpToolsLoading ? "Loading tools…" : "No tools found"}
|
|
1002
|
+
</div>
|
|
1003
|
+
) : (
|
|
1004
|
+
visibleTools.map((tool) => (
|
|
1005
|
+
<button
|
|
1006
|
+
key={tool.id}
|
|
1007
|
+
type="button"
|
|
1008
|
+
onClick={() => insertMention(tool.name)}
|
|
1009
|
+
className="flex w-full items-start gap-2 rounded px-2 py-1.5 text-left transition-colors hover:bg-muted"
|
|
1010
|
+
>
|
|
1011
|
+
<Wrench className="mt-0.5 size-4 shrink-0 text-muted-foreground" />
|
|
1012
|
+
<span className="min-w-0 flex-1">
|
|
1013
|
+
<span className="block truncate text-sm font-medium text-foreground">
|
|
1014
|
+
{tool.name}
|
|
1015
|
+
</span>
|
|
1016
|
+
{tool.description && (
|
|
1017
|
+
<span className="line-clamp-2 text-xs text-muted-foreground">
|
|
1018
|
+
{tool.description}
|
|
1019
|
+
</span>
|
|
1020
|
+
)}
|
|
1021
|
+
</span>
|
|
1022
|
+
</button>
|
|
1023
|
+
))
|
|
1024
|
+
)}
|
|
1025
|
+
</div>
|
|
1026
|
+
</div>
|
|
1027
|
+
</PopoverContent>
|
|
1028
|
+
</Popover>
|
|
1029
|
+
);
|
|
1030
|
+
};
|
|
1031
|
+
|
|
797
1032
|
const ComposerAction: FC = () => {
|
|
798
1033
|
const { config } = useElements();
|
|
799
1034
|
const r = useRadius();
|
|
@@ -807,6 +1042,8 @@ const ComposerAction: FC = () => {
|
|
|
807
1042
|
<div className="aui-composer-add-attachment-placeholder" />
|
|
808
1043
|
)}
|
|
809
1044
|
|
|
1045
|
+
<ComposerToolMentionPicker />
|
|
1046
|
+
|
|
810
1047
|
{config.model?.showModelPicker && !config.languageModel && (
|
|
811
1048
|
<ComposerModelPicker />
|
|
812
1049
|
)}
|
|
@@ -879,21 +1116,22 @@ const ToolCallStreamingIndicator: FC = () => {
|
|
|
879
1116
|
const AssistantMessage: FC = () => {
|
|
880
1117
|
const { config } = useElements();
|
|
881
1118
|
const toolsConfig = config.tools ?? {};
|
|
882
|
-
const components = config.components
|
|
1119
|
+
const components = config.components;
|
|
1120
|
+
const toolsComponents = toolsConfig.components;
|
|
883
1121
|
|
|
884
1122
|
const partsComponents = useMemo(
|
|
885
1123
|
() => ({
|
|
886
|
-
Text: components
|
|
887
|
-
Image: components
|
|
1124
|
+
Text: components?.Text ?? MarkdownText,
|
|
1125
|
+
Image: components?.Image ?? Image,
|
|
888
1126
|
tools: {
|
|
889
|
-
by_name:
|
|
890
|
-
Fallback: components
|
|
1127
|
+
by_name: toolsComponents,
|
|
1128
|
+
Fallback: components?.ToolFallback ?? ToolFallback,
|
|
891
1129
|
},
|
|
892
|
-
Reasoning: components
|
|
893
|
-
ReasoningGroup: components
|
|
894
|
-
ToolGroup: components
|
|
1130
|
+
Reasoning: components?.Reasoning ?? Reasoning,
|
|
1131
|
+
ReasoningGroup: components?.ReasoningGroup ?? ReasoningGroup,
|
|
1132
|
+
ToolGroup: components?.ToolGroup ?? ToolGroup,
|
|
895
1133
|
}),
|
|
896
|
-
[components,
|
|
1134
|
+
[components, toolsComponents],
|
|
897
1135
|
);
|
|
898
1136
|
|
|
899
1137
|
return (
|
|
@@ -74,7 +74,7 @@ export const ToolMentionAutocomplete: FC<ToolMentionAutocompleteProps> = ({
|
|
|
74
74
|
onValueChange(result.text, result.cursorPosition);
|
|
75
75
|
setIsVisible(false);
|
|
76
76
|
},
|
|
77
|
-
[mentionContext, value, cursorPosition, onValueChange
|
|
77
|
+
[mentionContext, value, cursorPosition, onValueChange],
|
|
78
78
|
);
|
|
79
79
|
|
|
80
80
|
useEffect(() => {
|