@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
|
@@ -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
|
|
|
@@ -51,6 +55,7 @@ import { MarkdownText } from "@/components/assistant-ui/markdown-text";
|
|
|
51
55
|
import { MentionedToolsBadges } from "@/components/assistant-ui/mentioned-tools-badges";
|
|
52
56
|
import { MessageFeedback } from "@/components/assistant-ui/message-feedback";
|
|
53
57
|
import { Reasoning, ReasoningGroup } from "@/components/assistant-ui/reasoning";
|
|
58
|
+
import { ThinkingIndicator } from "@/components/assistant-ui/thinking-indicator";
|
|
54
59
|
import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
|
|
55
60
|
import { ToolMentionAutocomplete } from "@/components/assistant-ui/tool-mention-autocomplete";
|
|
56
61
|
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
@@ -68,6 +73,10 @@ import { useToolMentions } from "@/hooks/useToolMentions";
|
|
|
68
73
|
import { getApiUrl } from "@/lib/api";
|
|
69
74
|
import { EASE_OUT_QUINT } from "@/lib/easing";
|
|
70
75
|
import { MODELS } from "@/lib/models";
|
|
76
|
+
import {
|
|
77
|
+
type MentionableTool,
|
|
78
|
+
toolSetToMentionableTools,
|
|
79
|
+
} from "@/lib/tool-mentions";
|
|
71
80
|
import { cn } from "@/lib/utils";
|
|
72
81
|
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
|
73
82
|
import {
|
|
@@ -262,7 +271,7 @@ const ThreadScrollToBottom: FC = () => {
|
|
|
262
271
|
const ThreadWelcome: FC = () => {
|
|
263
272
|
const { config } = useElements();
|
|
264
273
|
const d = useDensity();
|
|
265
|
-
const { title, subtitle } = config.welcome ?? {};
|
|
274
|
+
const { logo, title, subtitle } = config.welcome ?? {};
|
|
266
275
|
const isStandalone = config.variant === "standalone";
|
|
267
276
|
|
|
268
277
|
return (
|
|
@@ -288,6 +297,19 @@ const ThreadWelcome: FC = () => {
|
|
|
288
297
|
!isStandalone && d("py-md"),
|
|
289
298
|
)}
|
|
290
299
|
>
|
|
300
|
+
{logo && (
|
|
301
|
+
<m.img
|
|
302
|
+
src={logo}
|
|
303
|
+
alt=""
|
|
304
|
+
initial={{ opacity: 0, y: 10 }}
|
|
305
|
+
animate={{ opacity: 1, y: 0 }}
|
|
306
|
+
exit={{ opacity: 0, y: 10 }}
|
|
307
|
+
transition={{ duration: 0.25, ease: EASE_OUT_QUINT }}
|
|
308
|
+
className={cn(
|
|
309
|
+
"aui-thread-welcome-logo mb-2 size-12 object-contain",
|
|
310
|
+
)}
|
|
311
|
+
/>
|
|
312
|
+
)}
|
|
291
313
|
<m.div
|
|
292
314
|
initial={{ opacity: 0, y: 10 }}
|
|
293
315
|
animate={{ opacity: 1, y: 0 }}
|
|
@@ -524,7 +546,9 @@ const ComposerFeedback: FC = () => {
|
|
|
524
546
|
<MessageFeedback
|
|
525
547
|
className="mx-auto"
|
|
526
548
|
onResolved={setResolved}
|
|
527
|
-
onFeedback={
|
|
549
|
+
onFeedback={(type) => {
|
|
550
|
+
void handleFeedback(type);
|
|
551
|
+
}}
|
|
528
552
|
/>
|
|
529
553
|
</m.div>
|
|
530
554
|
)}
|
|
@@ -794,6 +818,218 @@ const ComposerCassetteRecorder: FC = () => {
|
|
|
794
818
|
);
|
|
795
819
|
};
|
|
796
820
|
|
|
821
|
+
// Sentinel for the "All" pseudo-category in the tool-mention picker.
|
|
822
|
+
const TOOL_MENTION_ALL_CATEGORY = "__all__";
|
|
823
|
+
|
|
824
|
+
function humanizeToolCategory(raw: string): string {
|
|
825
|
+
const cleaned = raw.replace(/[-_]+/g, " ").trim();
|
|
826
|
+
if (!cleaned) return "Tools";
|
|
827
|
+
return cleaned.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// Derive a grouping label for a tool. Tools from multiple MCP servers are
|
|
831
|
+
// namespaced as `<server>__<tool>`; otherwise group by the first
|
|
832
|
+
// underscore-delimited segment (e.g. `platform_search_logs` -> "Platform"),
|
|
833
|
+
// falling back to a single "Tools" bucket.
|
|
834
|
+
function deriveToolCategory(name: string): string {
|
|
835
|
+
const namespaceIdx = name.indexOf("__");
|
|
836
|
+
if (namespaceIdx > 0)
|
|
837
|
+
return humanizeToolCategory(name.slice(0, namespaceIdx));
|
|
838
|
+
const underscoreIdx = name.indexOf("_");
|
|
839
|
+
if (underscoreIdx > 0)
|
|
840
|
+
return humanizeToolCategory(name.slice(0, underscoreIdx));
|
|
841
|
+
return "Tools";
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
interface ToolCategory {
|
|
845
|
+
name: string;
|
|
846
|
+
tools: MentionableTool[];
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// A discoverable counterpart to the type-`@` autocomplete: a composer button
|
|
850
|
+
// that opens a searchable, category-grouped picker of the available tools and
|
|
851
|
+
// inserts an @mention for the chosen one. Inserts through the composer runtime
|
|
852
|
+
// so it stays in sync with the autocomplete's own textarea handling. Hidden when
|
|
853
|
+
// tool mentions are disabled or there are no tools.
|
|
854
|
+
const ComposerToolMentionPicker: FC = () => {
|
|
855
|
+
const { config, mcpTools, mcpToolsLoading } = useElements();
|
|
856
|
+
const api = useAssistantApi();
|
|
857
|
+
// Read the composer text from the same reactive source the tool-mention
|
|
858
|
+
// badges parse, so an inserted mention renders a pill just like the type-`@`
|
|
859
|
+
// autocomplete does.
|
|
860
|
+
const composerText = useAssistantState(({ composer }) => composer.text);
|
|
861
|
+
const [open, setOpen] = useState(false);
|
|
862
|
+
const [query, setQuery] = useState("");
|
|
863
|
+
const [activeCategory, setActiveCategory] = useState(
|
|
864
|
+
TOOL_MENTION_ALL_CATEGORY,
|
|
865
|
+
);
|
|
866
|
+
|
|
867
|
+
const composerConfig = config.composer;
|
|
868
|
+
const toolMentionsEnabled =
|
|
869
|
+
composerConfig?.toolMentions === undefined ||
|
|
870
|
+
composerConfig.toolMentions === true ||
|
|
871
|
+
(typeof composerConfig.toolMentions === "object" &&
|
|
872
|
+
composerConfig.toolMentions.enabled !== false);
|
|
873
|
+
|
|
874
|
+
const tools = useMemo(() => toolSetToMentionableTools(mcpTools), [mcpTools]);
|
|
875
|
+
|
|
876
|
+
const categories = useMemo<ToolCategory[]>(() => {
|
|
877
|
+
const grouped = new Map<string, MentionableTool[]>();
|
|
878
|
+
for (const tool of tools) {
|
|
879
|
+
const category = deriveToolCategory(tool.name);
|
|
880
|
+
const existing = grouped.get(category);
|
|
881
|
+
if (existing) {
|
|
882
|
+
existing.push(tool);
|
|
883
|
+
} else {
|
|
884
|
+
grouped.set(category, [tool]);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
return [...grouped.entries()]
|
|
888
|
+
.map(([name, categoryTools]) => ({ name, tools: categoryTools }))
|
|
889
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
890
|
+
}, [tools]);
|
|
891
|
+
|
|
892
|
+
// Show the button while tools are still loading (so it appears immediately
|
|
893
|
+
// rather than popping in once the async MCP list resolves) or once there are
|
|
894
|
+
// tools — but hide it when the list has loaded and is empty, so we don't
|
|
895
|
+
// expose a dead-end control.
|
|
896
|
+
if (!toolMentionsEnabled || (!mcpToolsLoading && tools.length === 0)) {
|
|
897
|
+
return null;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
901
|
+
const inActiveCategory =
|
|
902
|
+
activeCategory === TOOL_MENTION_ALL_CATEGORY
|
|
903
|
+
? tools
|
|
904
|
+
: (categories.find((c) => c.name === activeCategory)?.tools ?? []);
|
|
905
|
+
const visibleTools = normalizedQuery
|
|
906
|
+
? inActiveCategory.filter(
|
|
907
|
+
(tool) =>
|
|
908
|
+
tool.name.toLowerCase().includes(normalizedQuery) ||
|
|
909
|
+
(tool.description?.toLowerCase().includes(normalizedQuery) ?? false),
|
|
910
|
+
)
|
|
911
|
+
: inActiveCategory;
|
|
912
|
+
|
|
913
|
+
const insertMention = (toolName: string) => {
|
|
914
|
+
const base =
|
|
915
|
+
composerText && !/\s$/.test(composerText)
|
|
916
|
+
? `${composerText} `
|
|
917
|
+
: composerText;
|
|
918
|
+
api.composer().setText(`${base}@${toolName} `);
|
|
919
|
+
setOpen(false);
|
|
920
|
+
setQuery("");
|
|
921
|
+
};
|
|
922
|
+
|
|
923
|
+
const handleOpenChange = (next: boolean) => {
|
|
924
|
+
setOpen(next);
|
|
925
|
+
if (!next) {
|
|
926
|
+
setQuery("");
|
|
927
|
+
setActiveCategory(TOOL_MENTION_ALL_CATEGORY);
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
|
|
931
|
+
return (
|
|
932
|
+
<Popover open={open} onOpenChange={handleOpenChange}>
|
|
933
|
+
<PopoverTrigger asChild>
|
|
934
|
+
<Button
|
|
935
|
+
variant="ghost"
|
|
936
|
+
size="icon"
|
|
937
|
+
data-state={open ? "open" : "closed"}
|
|
938
|
+
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"
|
|
939
|
+
aria-label="Mention a tool"
|
|
940
|
+
>
|
|
941
|
+
<AtSign className="size-5 stroke-[1.5px]" />
|
|
942
|
+
</Button>
|
|
943
|
+
</PopoverTrigger>
|
|
944
|
+
<PopoverContent
|
|
945
|
+
side="top"
|
|
946
|
+
align="start"
|
|
947
|
+
className="aui-composer-tool-mention-popover w-[420px] overflow-hidden p-0"
|
|
948
|
+
>
|
|
949
|
+
<div className="flex items-center gap-2 border-b border-input px-3 py-2">
|
|
950
|
+
<Search className="size-4 shrink-0 text-muted-foreground" />
|
|
951
|
+
<input
|
|
952
|
+
autoFocus
|
|
953
|
+
value={query}
|
|
954
|
+
onChange={(e) => setQuery(e.target.value)}
|
|
955
|
+
placeholder="Search tools…"
|
|
956
|
+
className="w-full bg-transparent text-sm text-foreground outline-none placeholder:text-muted-foreground"
|
|
957
|
+
aria-label="Search tools"
|
|
958
|
+
/>
|
|
959
|
+
</div>
|
|
960
|
+
<div className="flex h-72">
|
|
961
|
+
<div className="w-36 shrink-0 overflow-y-auto border-r border-input p-2">
|
|
962
|
+
<div className="px-2 pb-1 text-[10px] font-semibold tracking-wide text-muted-foreground uppercase">
|
|
963
|
+
Categories
|
|
964
|
+
</div>
|
|
965
|
+
<button
|
|
966
|
+
type="button"
|
|
967
|
+
onClick={() => setActiveCategory(TOOL_MENTION_ALL_CATEGORY)}
|
|
968
|
+
className={cn(
|
|
969
|
+
"flex w-full items-center justify-between rounded px-2 py-1 text-left text-xs transition-colors",
|
|
970
|
+
activeCategory === TOOL_MENTION_ALL_CATEGORY
|
|
971
|
+
? "bg-muted font-medium text-foreground"
|
|
972
|
+
: "text-muted-foreground hover:bg-muted/60",
|
|
973
|
+
)}
|
|
974
|
+
>
|
|
975
|
+
<span className="truncate">All</span>
|
|
976
|
+
<span className="ml-2 shrink-0 tabular-nums opacity-60">
|
|
977
|
+
{tools.length}
|
|
978
|
+
</span>
|
|
979
|
+
</button>
|
|
980
|
+
{categories.map((category) => (
|
|
981
|
+
<button
|
|
982
|
+
key={category.name}
|
|
983
|
+
type="button"
|
|
984
|
+
onClick={() => setActiveCategory(category.name)}
|
|
985
|
+
className={cn(
|
|
986
|
+
"flex w-full items-center justify-between rounded px-2 py-1 text-left text-xs transition-colors",
|
|
987
|
+
activeCategory === category.name
|
|
988
|
+
? "bg-muted font-medium text-foreground"
|
|
989
|
+
: "text-muted-foreground hover:bg-muted/60",
|
|
990
|
+
)}
|
|
991
|
+
>
|
|
992
|
+
<span className="truncate">{category.name}</span>
|
|
993
|
+
<span className="ml-2 shrink-0 tabular-nums opacity-60">
|
|
994
|
+
{category.tools.length}
|
|
995
|
+
</span>
|
|
996
|
+
</button>
|
|
997
|
+
))}
|
|
998
|
+
</div>
|
|
999
|
+
<div className="min-w-0 flex-1 overflow-y-auto p-2">
|
|
1000
|
+
{visibleTools.length === 0 ? (
|
|
1001
|
+
<div className="px-2 py-6 text-center text-xs text-muted-foreground">
|
|
1002
|
+
{mcpToolsLoading ? "Loading tools…" : "No tools found"}
|
|
1003
|
+
</div>
|
|
1004
|
+
) : (
|
|
1005
|
+
visibleTools.map((tool) => (
|
|
1006
|
+
<button
|
|
1007
|
+
key={tool.id}
|
|
1008
|
+
type="button"
|
|
1009
|
+
onClick={() => insertMention(tool.name)}
|
|
1010
|
+
className="flex w-full items-start gap-2 rounded px-2 py-1.5 text-left transition-colors hover:bg-muted"
|
|
1011
|
+
>
|
|
1012
|
+
<Wrench className="mt-0.5 size-4 shrink-0 text-muted-foreground" />
|
|
1013
|
+
<span className="min-w-0 flex-1">
|
|
1014
|
+
<span className="block truncate text-sm font-medium text-foreground">
|
|
1015
|
+
{tool.name}
|
|
1016
|
+
</span>
|
|
1017
|
+
{tool.description && (
|
|
1018
|
+
<span className="line-clamp-2 text-xs text-muted-foreground">
|
|
1019
|
+
{tool.description}
|
|
1020
|
+
</span>
|
|
1021
|
+
)}
|
|
1022
|
+
</span>
|
|
1023
|
+
</button>
|
|
1024
|
+
))
|
|
1025
|
+
)}
|
|
1026
|
+
</div>
|
|
1027
|
+
</div>
|
|
1028
|
+
</PopoverContent>
|
|
1029
|
+
</Popover>
|
|
1030
|
+
);
|
|
1031
|
+
};
|
|
1032
|
+
|
|
797
1033
|
const ComposerAction: FC = () => {
|
|
798
1034
|
const { config } = useElements();
|
|
799
1035
|
const r = useRadius();
|
|
@@ -807,6 +1043,8 @@ const ComposerAction: FC = () => {
|
|
|
807
1043
|
<div className="aui-composer-add-attachment-placeholder" />
|
|
808
1044
|
)}
|
|
809
1045
|
|
|
1046
|
+
<ComposerToolMentionPicker />
|
|
1047
|
+
|
|
810
1048
|
{config.model?.showModelPicker && !config.languageModel && (
|
|
811
1049
|
<ComposerModelPicker />
|
|
812
1050
|
)}
|
|
@@ -861,39 +1099,25 @@ const MessageError: FC = () => {
|
|
|
861
1099
|
);
|
|
862
1100
|
};
|
|
863
1101
|
|
|
864
|
-
/**
|
|
865
|
-
* Shows the pulsing dot indicator when the message is still running but the
|
|
866
|
-
* last rendered part is a tool call (not text). Without this, there's no
|
|
867
|
-
* visual feedback that the model is still working after a tool call.
|
|
868
|
-
*/
|
|
869
|
-
const ToolCallStreamingIndicator: FC = () => {
|
|
870
|
-
const show = useAssistantState(({ message }) => {
|
|
871
|
-
if (message.status?.type !== "running") return false;
|
|
872
|
-
const lastPart = message.parts[message.parts.length - 1];
|
|
873
|
-
return lastPart?.type === "tool-call";
|
|
874
|
-
});
|
|
875
|
-
if (!show) return null;
|
|
876
|
-
return <div className="aui-md mt-2" data-status="running" />;
|
|
877
|
-
};
|
|
878
|
-
|
|
879
1102
|
const AssistantMessage: FC = () => {
|
|
880
1103
|
const { config } = useElements();
|
|
881
1104
|
const toolsConfig = config.tools ?? {};
|
|
882
|
-
const components = config.components
|
|
1105
|
+
const components = config.components;
|
|
1106
|
+
const toolsComponents = toolsConfig.components;
|
|
883
1107
|
|
|
884
1108
|
const partsComponents = useMemo(
|
|
885
1109
|
() => ({
|
|
886
|
-
Text: components
|
|
887
|
-
Image: components
|
|
1110
|
+
Text: components?.Text ?? MarkdownText,
|
|
1111
|
+
Image: components?.Image ?? Image,
|
|
888
1112
|
tools: {
|
|
889
|
-
by_name:
|
|
890
|
-
Fallback: components
|
|
1113
|
+
by_name: toolsComponents,
|
|
1114
|
+
Fallback: components?.ToolFallback ?? ToolFallback,
|
|
891
1115
|
},
|
|
892
|
-
Reasoning: components
|
|
893
|
-
ReasoningGroup: components
|
|
894
|
-
ToolGroup: components
|
|
1116
|
+
Reasoning: components?.Reasoning ?? Reasoning,
|
|
1117
|
+
ReasoningGroup: components?.ReasoningGroup ?? ReasoningGroup,
|
|
1118
|
+
ToolGroup: components?.ToolGroup ?? ToolGroup,
|
|
895
1119
|
}),
|
|
896
|
-
[components,
|
|
1120
|
+
[components, toolsComponents],
|
|
897
1121
|
);
|
|
898
1122
|
|
|
899
1123
|
return (
|
|
@@ -904,7 +1128,7 @@ const AssistantMessage: FC = () => {
|
|
|
904
1128
|
>
|
|
905
1129
|
<div className="aui-assistant-message-content mx-2 leading-7 wrap-break-word text-foreground">
|
|
906
1130
|
<MessagePrimitive.Parts components={partsComponents} />
|
|
907
|
-
<
|
|
1131
|
+
<ThinkingIndicator />
|
|
908
1132
|
<MessageError />
|
|
909
1133
|
</div>
|
|
910
1134
|
|
|
@@ -26,11 +26,13 @@ export const ToolFallback: ToolCallMessagePartComponent = ({
|
|
|
26
26
|
|
|
27
27
|
// Check if this specific tool call has a pending approval
|
|
28
28
|
const pendingApproval = pendingApprovals.get(toolCallId);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
(part) => part.
|
|
33
|
-
|
|
29
|
+
// Selecting the whole message would re-render this card on every streamed
|
|
30
|
+
// chunk; select only the derived value.
|
|
31
|
+
const needsTrailingBorder = useAssistantState(({ message }) => {
|
|
32
|
+
const toolParts = message.parts.filter((part) => part.type === "tool-call");
|
|
33
|
+
const index = toolParts.findIndex((part) => part.toolCallId === toolCallId);
|
|
34
|
+
return index !== -1 && index !== toolParts.length - 1;
|
|
35
|
+
});
|
|
34
36
|
|
|
35
37
|
const handleApproveOnce = () => {
|
|
36
38
|
confirmPendingApproval(toolCallId);
|
|
@@ -89,9 +91,7 @@ export const ToolFallback: ToolCallMessagePartComponent = ({
|
|
|
89
91
|
<div
|
|
90
92
|
className={cn(
|
|
91
93
|
"aui-tool-fallback-root flex w-full flex-col",
|
|
92
|
-
|
|
93
|
-
matchingMessagePartIndex !== toolParts.length - 1 &&
|
|
94
|
-
"border-b",
|
|
94
|
+
needsTrailingBorder && "border-b",
|
|
95
95
|
)}
|
|
96
96
|
>
|
|
97
97
|
<ToolUI
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { cn } from "@/lib/utils";
|
|
2
1
|
import { useAssistantState } from "@assistant-ui/react";
|
|
3
2
|
import { useMemo, type FC, type PropsWithChildren } from "react";
|
|
4
3
|
import { useElements } from "@/hooks/useElements";
|
|
@@ -44,21 +43,13 @@ export const ToolGroup: FC<
|
|
|
44
43
|
return children;
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
<div className={cn("my-4 w-full max-w-xl")}>
|
|
51
|
-
<div className="overflow-hidden rounded-lg border border-border bg-card">
|
|
52
|
-
{children}
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// For multiple tool calls, use the group component
|
|
46
|
+
// Single and multiple tool calls must share one wrapper element type —
|
|
47
|
+
// diverging branches would remount every card when a streaming turn grows
|
|
48
|
+
// the group.
|
|
59
49
|
return (
|
|
60
50
|
<div className="my-4 w-full max-w-xl">
|
|
61
51
|
<ToolUIGroup
|
|
52
|
+
headerless={toolCount === 1}
|
|
62
53
|
title={groupTitle}
|
|
63
54
|
status={anyMessagePartsAreRunning ? "running" : "complete"}
|
|
64
55
|
defaultExpanded={defaultExpanded}
|
|
@@ -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(() => {
|
|
@@ -6,7 +6,7 @@ import { cn } from "@/lib/utils";
|
|
|
6
6
|
function Avatar({
|
|
7
7
|
className,
|
|
8
8
|
...props
|
|
9
|
-
}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
|
|
9
|
+
}: React.ComponentProps<typeof AvatarPrimitive.Root>): React.JSX.Element {
|
|
10
10
|
return (
|
|
11
11
|
<AvatarPrimitive.Root
|
|
12
12
|
data-slot="avatar"
|
|
@@ -22,7 +22,7 @@ function Avatar({
|
|
|
22
22
|
function AvatarImage({
|
|
23
23
|
className,
|
|
24
24
|
...props
|
|
25
|
-
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
|
25
|
+
}: React.ComponentProps<typeof AvatarPrimitive.Image>): React.JSX.Element {
|
|
26
26
|
return (
|
|
27
27
|
<AvatarPrimitive.Image
|
|
28
28
|
data-slot="avatar-image"
|
|
@@ -35,7 +35,7 @@ function AvatarImage({
|
|
|
35
35
|
function AvatarFallback({
|
|
36
36
|
className,
|
|
37
37
|
...props
|
|
38
|
-
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
|
|
38
|
+
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>): React.JSX.Element {
|
|
39
39
|
return (
|
|
40
40
|
<AvatarPrimitive.Fallback
|
|
41
41
|
data-slot="avatar-fallback"
|
|
@@ -130,7 +130,7 @@ function Calendar({
|
|
|
130
130
|
minDate,
|
|
131
131
|
maxDate,
|
|
132
132
|
className,
|
|
133
|
-
}: CalendarProps) {
|
|
133
|
+
}: CalendarProps): React.JSX.Element {
|
|
134
134
|
const [viewDate, setViewDate] = React.useState(() => {
|
|
135
135
|
if (selected.start) return new Date(selected.start);
|
|
136
136
|
return new Date();
|
|
@@ -2,13 +2,15 @@ import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
|
|
|
2
2
|
|
|
3
3
|
function Collapsible({
|
|
4
4
|
...props
|
|
5
|
-
}: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {
|
|
5
|
+
}: React.ComponentProps<typeof CollapsiblePrimitive.Root>): React.JSX.Element {
|
|
6
6
|
return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
function CollapsibleTrigger({
|
|
10
10
|
...props
|
|
11
|
-
}: React.ComponentProps<
|
|
11
|
+
}: React.ComponentProps<
|
|
12
|
+
typeof CollapsiblePrimitive.CollapsibleTrigger
|
|
13
|
+
>): React.JSX.Element {
|
|
12
14
|
return (
|
|
13
15
|
<CollapsiblePrimitive.CollapsibleTrigger
|
|
14
16
|
data-slot="collapsible-trigger"
|
|
@@ -19,7 +21,9 @@ function CollapsibleTrigger({
|
|
|
19
21
|
|
|
20
22
|
function CollapsibleContent({
|
|
21
23
|
...props
|
|
22
|
-
}: React.ComponentProps<
|
|
24
|
+
}: React.ComponentProps<
|
|
25
|
+
typeof CollapsiblePrimitive.CollapsibleContent
|
|
26
|
+
>): React.JSX.Element {
|
|
23
27
|
return (
|
|
24
28
|
<CollapsiblePrimitive.CollapsibleContent
|
|
25
29
|
data-slot="collapsible-content"
|
|
@@ -7,20 +7,20 @@ import { usePortalContainer } from "@/hooks/usePortalContainer";
|
|
|
7
7
|
|
|
8
8
|
function Dialog({
|
|
9
9
|
...props
|
|
10
|
-
}: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
|
10
|
+
}: React.ComponentProps<typeof DialogPrimitive.Root>): React.JSX.Element {
|
|
11
11
|
return <DialogPrimitive.Root data-slot="dialog" {...props} />;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function DialogTrigger({
|
|
15
15
|
...props
|
|
16
|
-
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
16
|
+
}: React.ComponentProps<typeof DialogPrimitive.Trigger>): React.JSX.Element {
|
|
17
17
|
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
function DialogPortal({
|
|
21
21
|
container,
|
|
22
22
|
...props
|
|
23
|
-
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
23
|
+
}: React.ComponentProps<typeof DialogPrimitive.Portal>): React.JSX.Element {
|
|
24
24
|
const portalContainer = usePortalContainer();
|
|
25
25
|
return (
|
|
26
26
|
<DialogPrimitive.Portal
|
|
@@ -33,14 +33,14 @@ function DialogPortal({
|
|
|
33
33
|
|
|
34
34
|
function DialogClose({
|
|
35
35
|
...props
|
|
36
|
-
}: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
|
36
|
+
}: React.ComponentProps<typeof DialogPrimitive.Close>): React.JSX.Element {
|
|
37
37
|
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
function DialogOverlay({
|
|
41
41
|
className,
|
|
42
42
|
...props
|
|
43
|
-
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
43
|
+
}: React.ComponentProps<typeof DialogPrimitive.Overlay>): React.JSX.Element {
|
|
44
44
|
return (
|
|
45
45
|
<DialogPrimitive.Overlay
|
|
46
46
|
data-slot="dialog-overlay"
|
|
@@ -60,7 +60,7 @@ function DialogContent({
|
|
|
60
60
|
...props
|
|
61
61
|
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
|
|
62
62
|
showCloseButton?: boolean;
|
|
63
|
-
}) {
|
|
63
|
+
}): React.JSX.Element {
|
|
64
64
|
return (
|
|
65
65
|
<DialogPortal data-slot="dialog-portal">
|
|
66
66
|
<DialogOverlay />
|
|
@@ -87,7 +87,10 @@ function DialogContent({
|
|
|
87
87
|
);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
function DialogHeader({
|
|
90
|
+
function DialogHeader({
|
|
91
|
+
className,
|
|
92
|
+
...props
|
|
93
|
+
}: React.ComponentProps<"div">): React.JSX.Element {
|
|
91
94
|
return (
|
|
92
95
|
<div
|
|
93
96
|
data-slot="dialog-header"
|
|
@@ -97,7 +100,10 @@ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
97
100
|
);
|
|
98
101
|
}
|
|
99
102
|
|
|
100
|
-
function DialogFooter({
|
|
103
|
+
function DialogFooter({
|
|
104
|
+
className,
|
|
105
|
+
...props
|
|
106
|
+
}: React.ComponentProps<"div">): React.JSX.Element {
|
|
101
107
|
return (
|
|
102
108
|
<div
|
|
103
109
|
data-slot="dialog-footer"
|
|
@@ -113,7 +119,7 @@ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
113
119
|
function DialogTitle({
|
|
114
120
|
className,
|
|
115
121
|
...props
|
|
116
|
-
}: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
122
|
+
}: React.ComponentProps<typeof DialogPrimitive.Title>): React.JSX.Element {
|
|
117
123
|
return (
|
|
118
124
|
<DialogPrimitive.Title
|
|
119
125
|
data-slot="dialog-title"
|
|
@@ -126,7 +132,9 @@ function DialogTitle({
|
|
|
126
132
|
function DialogDescription({
|
|
127
133
|
className,
|
|
128
134
|
...props
|
|
129
|
-
}: React.ComponentProps<
|
|
135
|
+
}: React.ComponentProps<
|
|
136
|
+
typeof DialogPrimitive.Description
|
|
137
|
+
>): React.JSX.Element {
|
|
130
138
|
return (
|
|
131
139
|
<DialogPrimitive.Description
|
|
132
140
|
data-slot="dialog-description"
|
|
@@ -4,7 +4,7 @@ import { useDensity } from "@/hooks/useDensity";
|
|
|
4
4
|
import { cn } from "@/lib/utils";
|
|
5
5
|
import { isJsonRenderTree, type JsonRenderNode } from "@/lib/generative-ui";
|
|
6
6
|
import { AlertCircleIcon } from "lucide-react";
|
|
7
|
-
import { FC, useMemo } from "react";
|
|
7
|
+
import { ElementType, FC, useMemo } from "react";
|
|
8
8
|
|
|
9
9
|
// Import all components from the generative-ui plugin ui directory
|
|
10
10
|
import {
|
|
@@ -42,9 +42,10 @@ interface GenerativeUIProps {
|
|
|
42
42
|
/**
|
|
43
43
|
* Built-in components for rendering json-render trees.
|
|
44
44
|
* These provide a default set of UI primitives for tool results.
|
|
45
|
+
* Each entry has its own prop shape; the registry erases those generics via
|
|
46
|
+
* `ElementType` so heterogeneous components can coexist under one map.
|
|
45
47
|
*/
|
|
46
|
-
|
|
47
|
-
const components: Record<string, FC<any>> = {
|
|
48
|
+
const components: Record<string, ElementType> = {
|
|
48
49
|
// Layout
|
|
49
50
|
Card: CardWrapper,
|
|
50
51
|
Grid,
|
|
@@ -98,7 +99,11 @@ function renderNode(node: JsonRenderNode, key?: number): React.ReactNode {
|
|
|
98
99
|
? node.children.map((child, i) => renderNode(child, i))
|
|
99
100
|
: undefined;
|
|
100
101
|
|
|
101
|
-
return
|
|
102
|
+
return (
|
|
103
|
+
<Component key={key} {...(node.props ?? {})}>
|
|
104
|
+
{children}
|
|
105
|
+
</Component>
|
|
106
|
+
);
|
|
102
107
|
}
|
|
103
108
|
|
|
104
109
|
/**
|
|
@@ -6,13 +6,13 @@ import { usePortalContainer } from "@/hooks/usePortalContainer";
|
|
|
6
6
|
|
|
7
7
|
function Popover({
|
|
8
8
|
...props
|
|
9
|
-
}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
|
9
|
+
}: React.ComponentProps<typeof PopoverPrimitive.Root>): React.JSX.Element {
|
|
10
10
|
return <PopoverPrimitive.Root data-slot="popover" {...props} />;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
function PopoverTrigger({
|
|
14
14
|
...props
|
|
15
|
-
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
|
|
15
|
+
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>): React.JSX.Element {
|
|
16
16
|
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -24,7 +24,7 @@ function PopoverContent({
|
|
|
24
24
|
...props
|
|
25
25
|
}: React.ComponentProps<typeof PopoverPrimitive.Content> & {
|
|
26
26
|
container?: HTMLElement | null;
|
|
27
|
-
}) {
|
|
27
|
+
}): React.JSX.Element {
|
|
28
28
|
const portalContainer = usePortalContainer();
|
|
29
29
|
return (
|
|
30
30
|
<PopoverPrimitive.Portal container={container ?? portalContainer}>
|
|
@@ -44,7 +44,7 @@ function PopoverContent({
|
|
|
44
44
|
|
|
45
45
|
function PopoverAnchor({
|
|
46
46
|
...props
|
|
47
|
-
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
|
|
47
|
+
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>): React.JSX.Element {
|
|
48
48
|
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />;
|
|
49
49
|
}
|
|
50
50
|
|