@gram-ai/elements 1.34.0 → 1.36.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/assistant-ui/thinking-indicator.d.ts +8 -0
- 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 +9 -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-7fTI_vaV.cjs +194 -0
- package/dist/index-7fTI_vaV.cjs.map +1 -0
- package/dist/{index-B5lZrrO2.js → index-Bv-yE4G1.js} +2919 -2806
- package/dist/index-Bv-yE4G1.js.map +1 -0
- package/dist/{index-BFU6NvbL.js → index-BziIHO9O.js} +9621 -9308
- package/dist/index-BziIHO9O.js.map +1 -0
- package/dist/{index-C08dvTEo.cjs → index-CGBkMd0d.cjs} +48 -48
- package/dist/index-CGBkMd0d.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-BRnyr1GA.cjs → profiler-DuJEf_S6.cjs} +2 -2
- package/dist/{profiler-BRnyr1GA.cjs.map → profiler-DuJEf_S6.cjs.map} +1 -1
- package/dist/{profiler-KLSTpp6I.js → profiler-xLXOPfmj.js} +2 -2
- package/dist/{profiler-KLSTpp6I.js.map → profiler-xLXOPfmj.js.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-C2XF9-Ol.cjs} +2 -2
- package/dist/{startRecording-CKx-YWbq.cjs.map → startRecording-C2XF9-Ol.cjs.map} +1 -1
- package/dist/{startRecording-BfxB1xxR.js → startRecording-qKnXr4lw.js} +2 -2
- package/dist/{startRecording-BfxB1xxR.js.map → startRecording-qKnXr4lw.js.map} +1 -1
- package/dist/types/index.d.ts +29 -3
- package/package.json +8 -11
- 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/thinking-indicator.tsx +175 -0
- package/src/components/assistant-ui/thread.tsx +251 -27
- package/src/components/assistant-ui/tool-fallback.tsx +8 -8
- package/src/components/assistant-ui/tool-group.tsx +4 -13
- 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 +68 -40
- 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/global.css +55 -16
- 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
|
});
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useAssistantState } from "@assistant-ui/react";
|
|
4
|
+
import { type FC, useEffect, useMemo, useState } from "react";
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Whimsical verbs cycled while the assistant is "thinking" — i.e. the message
|
|
10
|
+
* is running but no answer text has streamed in yet (or it is waiting on a tool
|
|
11
|
+
* call / reasoning). The word shown is cosmetic and NOT tied to the actual work
|
|
12
|
+
* being done, mirroring the playful verbs Claude shows while it works. To make
|
|
13
|
+
* them reflect the real action instead, map from the streamed tool name in
|
|
14
|
+
* `ThinkingIndicator` below.
|
|
15
|
+
*/
|
|
16
|
+
const THINKING_VERBS = [
|
|
17
|
+
"Thinking",
|
|
18
|
+
"Reasoning",
|
|
19
|
+
"Pondering",
|
|
20
|
+
"Synthesizing",
|
|
21
|
+
"Connecting",
|
|
22
|
+
"Analyzing",
|
|
23
|
+
"Inspecting",
|
|
24
|
+
"Correlating",
|
|
25
|
+
"Digging",
|
|
26
|
+
"Untangling",
|
|
27
|
+
"Assembling",
|
|
28
|
+
"Sketching",
|
|
29
|
+
"Reticulating",
|
|
30
|
+
"Wrangling",
|
|
31
|
+
"Distilling",
|
|
32
|
+
"Surveying",
|
|
33
|
+
"Mapping",
|
|
34
|
+
"Cross-referencing",
|
|
35
|
+
"Investigating",
|
|
36
|
+
"Considering",
|
|
37
|
+
"Formulating",
|
|
38
|
+
"Piecing",
|
|
39
|
+
"Tracing",
|
|
40
|
+
"Computing",
|
|
41
|
+
"Noodling",
|
|
42
|
+
"Percolating",
|
|
43
|
+
"Marshalling",
|
|
44
|
+
"Crunching",
|
|
45
|
+
"Orchestrating",
|
|
46
|
+
"Composing",
|
|
47
|
+
] as const;
|
|
48
|
+
|
|
49
|
+
// Cadence: hold each verb, then crossfade to the next.
|
|
50
|
+
const HOLD_MS = 2000;
|
|
51
|
+
const FADE_MS = 350;
|
|
52
|
+
|
|
53
|
+
function shuffled<T>(items: readonly T[]): T[] {
|
|
54
|
+
const copy = [...items];
|
|
55
|
+
for (let i = copy.length - 1; i > 0; i--) {
|
|
56
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
57
|
+
[copy[i], copy[j]] = [copy[j]!, copy[i]!];
|
|
58
|
+
}
|
|
59
|
+
return copy;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Tracks the user's `prefers-reduced-motion` setting, updating if it changes. */
|
|
63
|
+
function usePrefersReducedMotion(): boolean {
|
|
64
|
+
const query = "(prefers-reduced-motion: reduce)";
|
|
65
|
+
const [reduced, setReduced] = useState(
|
|
66
|
+
() =>
|
|
67
|
+
typeof window !== "undefined" &&
|
|
68
|
+
typeof window.matchMedia === "function" &&
|
|
69
|
+
window.matchMedia(query).matches,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (
|
|
74
|
+
typeof window === "undefined" ||
|
|
75
|
+
typeof window.matchMedia !== "function"
|
|
76
|
+
)
|
|
77
|
+
return;
|
|
78
|
+
const mql = window.matchMedia(query);
|
|
79
|
+
const onChange = () => setReduced(mql.matches);
|
|
80
|
+
mql.addEventListener("change", onChange);
|
|
81
|
+
return () => mql.removeEventListener("change", onChange);
|
|
82
|
+
}, []);
|
|
83
|
+
|
|
84
|
+
return reduced;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Cycles through a shuffled copy of {@link THINKING_VERBS} while `active`, with
|
|
89
|
+
* a brief opacity dip between words so they crossfade rather than snap. When the
|
|
90
|
+
* user prefers reduced motion, a single verb is shown statically — no timer, no
|
|
91
|
+
* fade — so motion-sensitive users don't get text changing under them.
|
|
92
|
+
*/
|
|
93
|
+
function useThinkingVerb(
|
|
94
|
+
active: boolean,
|
|
95
|
+
reduced: boolean,
|
|
96
|
+
): { verb: string; visible: boolean } {
|
|
97
|
+
const order = useMemo(() => shuffled(THINKING_VERBS), []);
|
|
98
|
+
const [index, setIndex] = useState(0);
|
|
99
|
+
const [visible, setVisible] = useState(true);
|
|
100
|
+
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
// Restore visibility on every (de)activation and motion-preference change —
|
|
103
|
+
// only the cycling path below dims it. This runs before the early return so
|
|
104
|
+
// that flipping reduced-motion on (or deactivating) during a fade-out can't
|
|
105
|
+
// latch the verb at opacity-0 forever.
|
|
106
|
+
setVisible(true);
|
|
107
|
+
|
|
108
|
+
if (!active || reduced) return;
|
|
109
|
+
|
|
110
|
+
let outTimer: ReturnType<typeof setTimeout>;
|
|
111
|
+
let inTimer: ReturnType<typeof setTimeout>;
|
|
112
|
+
|
|
113
|
+
const tick = () => {
|
|
114
|
+
setVisible(false);
|
|
115
|
+
outTimer = setTimeout(() => {
|
|
116
|
+
setIndex((i) => (i + 1) % order.length);
|
|
117
|
+
setVisible(true);
|
|
118
|
+
inTimer = setTimeout(tick, HOLD_MS);
|
|
119
|
+
}, FADE_MS);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
inTimer = setTimeout(tick, HOLD_MS);
|
|
123
|
+
return () => {
|
|
124
|
+
clearTimeout(outTimer);
|
|
125
|
+
clearTimeout(inTimer);
|
|
126
|
+
};
|
|
127
|
+
}, [active, reduced, order.length]);
|
|
128
|
+
|
|
129
|
+
return { verb: order[index]!, visible };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Shows a rainbow spinner alongside a cycling "thinking" verb whenever the
|
|
134
|
+
* assistant is running but has not yet produced visible answer text. Once text
|
|
135
|
+
* starts streaming, this hides and the inline trailing dot (see the
|
|
136
|
+
* `aui-md[data-status="running"]` rules in global.css) takes over.
|
|
137
|
+
*/
|
|
138
|
+
export const ThinkingIndicator: FC = () => {
|
|
139
|
+
const active = useAssistantState(({ message }) => {
|
|
140
|
+
if (message.status?.type !== "running") return false;
|
|
141
|
+
const parts = message.parts;
|
|
142
|
+
if (parts.length === 0) return true;
|
|
143
|
+
const last = parts[parts.length - 1];
|
|
144
|
+
if (!last) return true;
|
|
145
|
+
if (last.type === "tool-call" || last.type === "reasoning") return true;
|
|
146
|
+
if (last.type === "text") return last.text.trim().length === 0;
|
|
147
|
+
return false;
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const reducedMotion = usePrefersReducedMotion();
|
|
151
|
+
const { verb, visible } = useThinkingVerb(active, reducedMotion);
|
|
152
|
+
|
|
153
|
+
if (!active) return null;
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<div
|
|
157
|
+
className="aui-thinking mt-2 flex items-center gap-2 text-sm text-muted-foreground"
|
|
158
|
+
role="status"
|
|
159
|
+
>
|
|
160
|
+
{/* Stable label for assistive tech — the rotating verb below is purely
|
|
161
|
+
decorative, so announcing each word would just be noise. */}
|
|
162
|
+
<span className="sr-only">Assistant is working…</span>
|
|
163
|
+
<span className="aui-thinking-dot" aria-hidden="true" />
|
|
164
|
+
<span
|
|
165
|
+
aria-hidden="true"
|
|
166
|
+
className={cn(
|
|
167
|
+
"aui-thinking-label transition-opacity duration-300 ease-out motion-reduce:transition-none",
|
|
168
|
+
visible ? "opacity-100" : "opacity-0",
|
|
169
|
+
)}
|
|
170
|
+
>
|
|
171
|
+
{verb}…
|
|
172
|
+
</span>
|
|
173
|
+
</div>
|
|
174
|
+
);
|
|
175
|
+
};
|