@gugacoder/agentic-chat 0.2.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.
Files changed (187) hide show
  1. package/dist/components/Chat.d.ts +21 -0
  2. package/dist/components/Chat.js +13 -0
  3. package/dist/components/ErrorNote.d.ts +5 -0
  4. package/dist/components/ErrorNote.js +6 -0
  5. package/dist/components/LazyRender.d.ts +8 -0
  6. package/dist/components/LazyRender.js +22 -0
  7. package/dist/components/Markdown.d.ts +5 -0
  8. package/dist/components/Markdown.js +65 -0
  9. package/dist/components/MessageBubble.d.ts +10 -0
  10. package/dist/components/MessageBubble.js +39 -0
  11. package/dist/components/MessageInput.d.ts +19 -0
  12. package/dist/components/MessageInput.js +214 -0
  13. package/dist/components/MessageList.d.ts +12 -0
  14. package/dist/components/MessageList.js +68 -0
  15. package/dist/components/StreamingIndicator.d.ts +1 -0
  16. package/dist/components/StreamingIndicator.js +9 -0
  17. package/dist/conversations/CollapsibleGroup.d.ts +11 -0
  18. package/dist/conversations/CollapsibleGroup.js +9 -0
  19. package/dist/conversations/ConversationBar.d.ts +27 -0
  20. package/dist/conversations/ConversationBar.js +53 -0
  21. package/dist/conversations/ConversationList.d.ts +33 -0
  22. package/dist/conversations/ConversationList.js +48 -0
  23. package/dist/conversations/ConversationListItem.d.ts +20 -0
  24. package/dist/conversations/ConversationListItem.js +22 -0
  25. package/dist/conversations/DeleteDialog.d.ts +13 -0
  26. package/dist/conversations/DeleteDialog.js +8 -0
  27. package/dist/conversations/RenameDialog.d.ts +15 -0
  28. package/dist/conversations/RenameDialog.js +15 -0
  29. package/dist/conversations/index.d.ts +9 -0
  30. package/dist/conversations/index.js +5 -0
  31. package/dist/conversations/types.d.ts +21 -0
  32. package/dist/conversations/types.js +1 -0
  33. package/dist/conversations/useConversations.d.ts +19 -0
  34. package/dist/conversations/useConversations.js +102 -0
  35. package/dist/conversations/utils.d.ts +8 -0
  36. package/dist/conversations/utils.js +134 -0
  37. package/dist/display/AlertRenderer.d.ts +2 -0
  38. package/dist/display/AlertRenderer.js +13 -0
  39. package/dist/display/CarouselRenderer.d.ts +2 -0
  40. package/dist/display/CarouselRenderer.js +41 -0
  41. package/dist/display/ChartRenderer.d.ts +2 -0
  42. package/dist/display/ChartRenderer.js +76 -0
  43. package/dist/display/ChoiceButtonsRenderer.d.ts +6 -0
  44. package/dist/display/ChoiceButtonsRenderer.js +23 -0
  45. package/dist/display/CodeBlockRenderer.d.ts +2 -0
  46. package/dist/display/CodeBlockRenderer.js +17 -0
  47. package/dist/display/ComparisonTableRenderer.d.ts +2 -0
  48. package/dist/display/ComparisonTableRenderer.js +26 -0
  49. package/dist/display/DataTableRenderer.d.ts +2 -0
  50. package/dist/display/DataTableRenderer.js +74 -0
  51. package/dist/display/FileCardRenderer.d.ts +2 -0
  52. package/dist/display/FileCardRenderer.js +31 -0
  53. package/dist/display/GalleryRenderer.d.ts +2 -0
  54. package/dist/display/GalleryRenderer.js +11 -0
  55. package/dist/display/ImageViewerRenderer.d.ts +2 -0
  56. package/dist/display/ImageViewerRenderer.js +15 -0
  57. package/dist/display/LinkPreviewRenderer.d.ts +2 -0
  58. package/dist/display/LinkPreviewRenderer.js +20 -0
  59. package/dist/display/MapViewRenderer.d.ts +2 -0
  60. package/dist/display/MapViewRenderer.js +20 -0
  61. package/dist/display/MetricCardRenderer.d.ts +2 -0
  62. package/dist/display/MetricCardRenderer.js +12 -0
  63. package/dist/display/PriceHighlightRenderer.d.ts +2 -0
  64. package/dist/display/PriceHighlightRenderer.js +13 -0
  65. package/dist/display/ProductCardRenderer.d.ts +2 -0
  66. package/dist/display/ProductCardRenderer.js +23 -0
  67. package/dist/display/ProgressStepsRenderer.d.ts +2 -0
  68. package/dist/display/ProgressStepsRenderer.js +14 -0
  69. package/dist/display/SourcesListRenderer.d.ts +2 -0
  70. package/dist/display/SourcesListRenderer.js +5 -0
  71. package/dist/display/SpreadsheetRenderer.d.ts +2 -0
  72. package/dist/display/SpreadsheetRenderer.js +32 -0
  73. package/dist/display/StepTimelineRenderer.d.ts +2 -0
  74. package/dist/display/StepTimelineRenderer.js +21 -0
  75. package/dist/display/index.d.ts +21 -0
  76. package/dist/display/index.js +20 -0
  77. package/dist/display/registry.d.ts +5 -0
  78. package/dist/display/registry.js +50 -0
  79. package/dist/hooks/ChatProvider.d.ts +10 -0
  80. package/dist/hooks/ChatProvider.js +14 -0
  81. package/dist/hooks/useBackboneChat.d.ts +37 -0
  82. package/dist/hooks/useBackboneChat.js +121 -0
  83. package/dist/hooks/useIsMobile.d.ts +1 -0
  84. package/dist/hooks/useIsMobile.js +12 -0
  85. package/dist/index.d.ts +47 -0
  86. package/dist/index.js +40 -0
  87. package/dist/lib/utils.d.ts +2 -0
  88. package/dist/lib/utils.js +5 -0
  89. package/dist/parts/PartRenderer.d.ts +40 -0
  90. package/dist/parts/PartRenderer.js +97 -0
  91. package/dist/parts/ReasoningBlock.d.ts +6 -0
  92. package/dist/parts/ReasoningBlock.js +18 -0
  93. package/dist/parts/ToolActivity.d.ts +11 -0
  94. package/dist/parts/ToolActivity.js +52 -0
  95. package/dist/parts/ToolResult.d.ts +7 -0
  96. package/dist/parts/ToolResult.js +38 -0
  97. package/dist/styles.css +2 -0
  98. package/dist/ui/alert.d.ts +12 -0
  99. package/dist/ui/alert.js +28 -0
  100. package/dist/ui/badge.d.ts +9 -0
  101. package/dist/ui/badge.js +20 -0
  102. package/dist/ui/button.d.ts +11 -0
  103. package/dist/ui/button.js +31 -0
  104. package/dist/ui/card.d.ts +8 -0
  105. package/dist/ui/card.js +21 -0
  106. package/dist/ui/collapsible.d.ts +1 -0
  107. package/dist/ui/collapsible.js +2 -0
  108. package/dist/ui/dialog.d.ts +19 -0
  109. package/dist/ui/dialog.js +23 -0
  110. package/dist/ui/dropdown-menu.d.ts +11 -0
  111. package/dist/ui/dropdown-menu.js +15 -0
  112. package/dist/ui/input.d.ts +3 -0
  113. package/dist/ui/input.js +6 -0
  114. package/dist/ui/progress.d.ts +7 -0
  115. package/dist/ui/progress.js +9 -0
  116. package/dist/ui/scroll-area.d.ts +5 -0
  117. package/dist/ui/scroll-area.js +12 -0
  118. package/dist/ui/separator.d.ts +4 -0
  119. package/dist/ui/separator.js +8 -0
  120. package/dist/ui/skeleton.d.ts +3 -0
  121. package/dist/ui/skeleton.js +6 -0
  122. package/dist/ui/table.d.ts +10 -0
  123. package/dist/ui/table.js +27 -0
  124. package/package.json +53 -0
  125. package/src/components/Chat.tsx +80 -0
  126. package/src/components/ErrorNote.tsx +32 -0
  127. package/src/components/LazyRender.tsx +42 -0
  128. package/src/components/Markdown.tsx +114 -0
  129. package/src/components/MessageBubble.tsx +102 -0
  130. package/src/components/MessageInput.tsx +421 -0
  131. package/src/components/MessageList.tsx +139 -0
  132. package/src/components/StreamingIndicator.tsx +19 -0
  133. package/src/conversations/CollapsibleGroup.tsx +41 -0
  134. package/src/conversations/ConversationBar.tsx +200 -0
  135. package/src/conversations/ConversationList.tsx +234 -0
  136. package/src/conversations/ConversationListItem.tsx +123 -0
  137. package/src/conversations/DeleteDialog.tsx +55 -0
  138. package/src/conversations/RenameDialog.tsx +74 -0
  139. package/src/conversations/index.ts +14 -0
  140. package/src/conversations/types.ts +17 -0
  141. package/src/conversations/useConversations.ts +148 -0
  142. package/src/conversations/utils.ts +159 -0
  143. package/src/display/AlertRenderer.tsx +27 -0
  144. package/src/display/CarouselRenderer.tsx +141 -0
  145. package/src/display/ChartRenderer.tsx +195 -0
  146. package/src/display/ChoiceButtonsRenderer.tsx +114 -0
  147. package/src/display/CodeBlockRenderer.tsx +49 -0
  148. package/src/display/ComparisonTableRenderer.tsx +132 -0
  149. package/src/display/DataTableRenderer.tsx +144 -0
  150. package/src/display/FileCardRenderer.tsx +55 -0
  151. package/src/display/GalleryRenderer.tsx +65 -0
  152. package/src/display/ImageViewerRenderer.tsx +114 -0
  153. package/src/display/LinkPreviewRenderer.tsx +74 -0
  154. package/src/display/MapViewRenderer.tsx +75 -0
  155. package/src/display/MetricCardRenderer.tsx +29 -0
  156. package/src/display/PriceHighlightRenderer.tsx +44 -0
  157. package/src/display/ProductCardRenderer.tsx +112 -0
  158. package/src/display/ProgressStepsRenderer.tsx +59 -0
  159. package/src/display/SourcesListRenderer.tsx +47 -0
  160. package/src/display/SpreadsheetRenderer.tsx +86 -0
  161. package/src/display/StepTimelineRenderer.tsx +75 -0
  162. package/src/display/index.ts +21 -0
  163. package/src/display/registry.ts +81 -0
  164. package/src/hooks/ChatProvider.tsx +22 -0
  165. package/src/hooks/useBackboneChat.ts +148 -0
  166. package/src/hooks/useIsMobile.ts +15 -0
  167. package/src/index.ts +80 -0
  168. package/src/lib/utils.ts +6 -0
  169. package/src/parts/PartRenderer.tsx +198 -0
  170. package/src/parts/ReasoningBlock.tsx +41 -0
  171. package/src/parts/ToolActivity.tsx +79 -0
  172. package/src/parts/ToolResult.tsx +79 -0
  173. package/src/styles.css +2 -0
  174. package/src/ui/alert.tsx +77 -0
  175. package/src/ui/badge.tsx +36 -0
  176. package/src/ui/button.tsx +54 -0
  177. package/src/ui/card.tsx +68 -0
  178. package/src/ui/collapsible.tsx +7 -0
  179. package/src/ui/dialog.tsx +122 -0
  180. package/src/ui/dropdown-menu.tsx +76 -0
  181. package/src/ui/input.tsx +24 -0
  182. package/src/ui/progress.tsx +36 -0
  183. package/src/ui/scroll-area.tsx +48 -0
  184. package/src/ui/separator.tsx +31 -0
  185. package/src/ui/skeleton.tsx +9 -0
  186. package/src/ui/table.tsx +114 -0
  187. package/tsconfig.json +17 -0
@@ -0,0 +1,53 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { ArrowLeft, Download, MoreHorizontal, Pencil, Trash2 } from "lucide-react";
5
+ import { Badge } from "../ui/badge.js";
6
+ import { Button } from "../ui/button.js";
7
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "../ui/dropdown-menu.js";
8
+ import { Skeleton } from "../ui/skeleton.js";
9
+ import { cn } from "../lib/utils.js";
10
+ import { DeleteDialog } from "./DeleteDialog.js";
11
+ import { RenameDialog } from "./RenameDialog.js";
12
+ function ConversationBar({ title, agentLabel, isLoading, onRename, onExport, onDelete, onBack, renameOpen: renameOpenProp, onRenameOpenChange, deleteOpen: deleteOpenProp, onDeleteOpenChange, isPendingRename, isPendingDelete, renameLabel = "Rename", exportLabel = "Export", deleteLabel = "Delete", untitledLabel = "Untitled", actionsExtra, menuItemsExtra, afterBar, className, }) {
13
+ // Internal dialog state for uncontrolled mode
14
+ const [internalRenameOpen, setInternalRenameOpen] = React.useState(false);
15
+ const [internalDeleteOpen, setInternalDeleteOpen] = React.useState(false);
16
+ const [renameValue, setRenameValue] = React.useState("");
17
+ const isControlledRename = renameOpenProp !== undefined && onRenameOpenChange !== undefined;
18
+ const isControlledDelete = deleteOpenProp !== undefined && onDeleteOpenChange !== undefined;
19
+ const renameOpen = isControlledRename ? renameOpenProp : internalRenameOpen;
20
+ const deleteOpen = isControlledDelete ? deleteOpenProp : internalDeleteOpen;
21
+ const setRenameOpen = (open) => {
22
+ if (isControlledRename) {
23
+ onRenameOpenChange(open);
24
+ }
25
+ else {
26
+ setInternalRenameOpen(open);
27
+ }
28
+ };
29
+ const setDeleteOpen = (open) => {
30
+ if (isControlledDelete) {
31
+ onDeleteOpenChange(open);
32
+ }
33
+ else {
34
+ setInternalDeleteOpen(open);
35
+ }
36
+ };
37
+ const handleRenameClick = () => {
38
+ setRenameValue(title ?? "");
39
+ setRenameOpen(true);
40
+ };
41
+ const handleRenameConfirm = () => {
42
+ if (renameValue.trim()) {
43
+ onRename?.(renameValue.trim());
44
+ }
45
+ setRenameOpen(false);
46
+ };
47
+ const handleDeleteConfirm = () => {
48
+ onDelete?.();
49
+ setDeleteOpen(false);
50
+ };
51
+ return (_jsxs("div", { className: cn("flex flex-col", className), children: [_jsxs("div", { className: "flex items-center gap-2 border-b bg-background px-3 py-2", children: [onBack && (_jsx(Button, { variant: "ghost", size: "icon", className: "size-8 shrink-0", onClick: onBack, children: _jsx(ArrowLeft, { className: "size-4" }) })), _jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [isLoading ? (_jsx(Skeleton, { className: "h-5 w-40" })) : (_jsx("span", { className: "truncate text-sm font-medium", children: title ?? untitledLabel })), agentLabel && (_jsx(Badge, { variant: "secondary", className: "shrink-0 text-xs", children: agentLabel }))] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [actionsExtra, _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", className: "size-8", children: _jsx(MoreHorizontal, { className: "size-4" }) }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsxs(DropdownMenuItem, { onClick: handleRenameClick, children: [_jsx(Pencil, { className: "mr-2 size-4" }), renameLabel] }), _jsxs(DropdownMenuItem, { onClick: onExport, children: [_jsx(Download, { className: "mr-2 size-4" }), exportLabel] }), menuItemsExtra, _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { className: "text-destructive focus:text-destructive", onClick: () => setDeleteOpen(true), children: [_jsx(Trash2, { className: "mr-2 size-4" }), deleteLabel] })] })] })] })] }), afterBar, _jsx(RenameDialog, { open: renameOpen, onOpenChange: setRenameOpen, value: renameValue, onValueChange: setRenameValue, onConfirm: handleRenameConfirm, isPending: isPendingRename }), _jsx(DeleteDialog, { open: deleteOpen, onOpenChange: setDeleteOpen, onConfirm: handleDeleteConfirm, isPending: isPendingDelete })] }));
52
+ }
53
+ export { ConversationBar };
@@ -0,0 +1,33 @@
1
+ import * as React from "react";
2
+ import type { Conversation } from "./types.js";
3
+ interface ConversationListProps {
4
+ conversations: Conversation[];
5
+ activeId?: string;
6
+ isLoading?: boolean;
7
+ search?: string;
8
+ onSearchChange?: (value: string) => void;
9
+ searchPlaceholder?: string;
10
+ favorites?: Conversation[];
11
+ history?: Conversation[];
12
+ favoritesLabel?: string;
13
+ historyLabel?: string;
14
+ hasMore?: boolean;
15
+ onLoadMore?: () => void;
16
+ loadMoreLabel?: string;
17
+ remainingCount?: number;
18
+ onSelect?: (id: string) => void;
19
+ onRename?: (id: string, title: string) => void;
20
+ onStar?: (id: string, starred: boolean) => void;
21
+ onCreateRequest?: () => void;
22
+ getAgentLabel?: (agentId: string) => string;
23
+ headerExtra?: React.ReactNode;
24
+ filterExtra?: React.ReactNode;
25
+ itemBadgesExtra?: (conv: Conversation) => React.ReactNode;
26
+ emptyIcon?: React.ReactNode;
27
+ emptyTitle?: string;
28
+ emptyDescription?: string;
29
+ className?: string;
30
+ }
31
+ declare function ConversationList({ conversations, activeId, isLoading, search, onSearchChange, searchPlaceholder, favorites: favoritesProp, history: historyProp, favoritesLabel, historyLabel, hasMore, onLoadMore, loadMoreLabel, remainingCount, onSelect, onRename, onStar, onCreateRequest, getAgentLabel, headerExtra, filterExtra, itemBadgesExtra, emptyIcon, emptyTitle, emptyDescription, className, }: ConversationListProps): import("react/jsx-runtime").JSX.Element;
32
+ export { ConversationList };
33
+ export type { ConversationListProps };
@@ -0,0 +1,48 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { MessageSquare, Plus, Search } from "lucide-react";
4
+ import * as React from "react";
5
+ import { cn } from "../lib/utils.js";
6
+ import { Button } from "../ui/button.js";
7
+ import { Input } from "../ui/input.js";
8
+ import { ScrollArea } from "../ui/scroll-area.js";
9
+ import { Skeleton } from "../ui/skeleton.js";
10
+ import { CollapsibleGroup } from "./CollapsibleGroup.js";
11
+ import { ConversationListItem } from "./ConversationListItem.js";
12
+ import { groupConversations } from "./utils.js";
13
+ function ConversationList({ conversations, activeId, isLoading = false, search = "", onSearchChange, searchPlaceholder = "Search...", favorites: favoritesProp, history: historyProp, favoritesLabel = "Favorites", historyLabel = "History", hasMore = false, onLoadMore, loadMoreLabel = "Load more", remainingCount, onSelect, onRename, onStar, onCreateRequest, getAgentLabel, headerExtra, filterExtra, itemBadgesExtra, emptyIcon, emptyTitle = "No conversations", emptyDescription = "Start a conversation to begin.", className, }) {
14
+ const [renamingId, setRenamingId] = React.useState(null);
15
+ const [renameValue, setRenameValue] = React.useState("");
16
+ const [favoritesOpen, setFavoritesOpen] = React.useState(true);
17
+ const [historyOpen, setHistoryOpen] = React.useState(true);
18
+ const derived = React.useMemo(() => groupConversations(conversations), [conversations]);
19
+ const favorites = favoritesProp ?? derived.favorites;
20
+ const history = historyProp ?? derived.history;
21
+ function handleStartRename(conv) {
22
+ return (e) => {
23
+ e.stopPropagation();
24
+ setRenamingId(conv.id);
25
+ setRenameValue(conv.title ?? "");
26
+ };
27
+ }
28
+ function handleRenameCommit(id) {
29
+ if (renameValue.trim()) {
30
+ onRename?.(id, renameValue.trim());
31
+ }
32
+ setRenamingId(null);
33
+ setRenameValue("");
34
+ }
35
+ function handleRenameCancel() {
36
+ setRenamingId(null);
37
+ setRenameValue("");
38
+ }
39
+ function renderItem(conv) {
40
+ return (_jsx(ConversationListItem, { conversation: conv, agentLabel: getAgentLabel?.(conv.agentId), isActive: conv.id === activeId, isRenaming: renamingId === conv.id, renameValue: renameValue, onRenameChange: setRenameValue, onRenameCommit: () => handleRenameCommit(conv.id), onRenameCancel: handleRenameCancel, onStartRename: handleStartRename(conv), onToggleStar: (e) => {
41
+ e.stopPropagation();
42
+ onStar?.(conv.id, !conv.starred);
43
+ }, onClick: () => onSelect?.(conv.id), badgesExtra: itemBadgesExtra?.(conv) }, conv.id));
44
+ }
45
+ const isEmpty = !isLoading && conversations.length === 0;
46
+ return (_jsxs("div", { className: cn("flex h-full flex-col", className), children: [_jsxs("div", { className: "flex items-center gap-1 px-2 py-2", children: [_jsxs("div", { className: "relative flex-1", children: [_jsx(Search, { className: "absolute left-2 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { className: "h-8 pl-7 text-sm", placeholder: searchPlaceholder, value: search, onChange: (e) => onSearchChange?.(e.target.value) })] }), headerExtra, _jsx(Button, { variant: "ghost", size: "icon", className: "size-8 shrink-0", onClick: onCreateRequest, "aria-label": "New conversation", children: _jsx(Plus, { className: "size-4" }) })] }), filterExtra && _jsx("div", { className: "px-2 pb-2", children: filterExtra }), _jsx(ScrollArea, { className: "flex-1", children: _jsxs("div", { className: "px-2 pb-2", children: [isLoading && (_jsx("div", { className: "flex flex-col gap-2 pt-1", children: Array.from({ length: 8 }).map((_, i) => (_jsx(Skeleton, { className: "h-16 w-full rounded-lg" }, i))) })), isEmpty && (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 py-12 text-center", children: [emptyIcon ?? _jsx(MessageSquare, { className: "size-10 text-muted-foreground/50" }), _jsx("p", { className: "text-sm font-medium text-foreground", children: emptyTitle }), _jsx("p", { className: "text-xs text-muted-foreground", children: emptyDescription })] })), !isLoading && !isEmpty && (_jsxs(_Fragment, { children: [favorites.length > 0 && (_jsx(CollapsibleGroup, { label: favoritesLabel, open: favoritesOpen, onToggle: () => setFavoritesOpen((v) => !v), children: _jsx("div", { className: "mt-0.5 flex flex-col gap-0.5", children: favorites.map(renderItem) }) })), history.length > 0 && (_jsxs(CollapsibleGroup, { label: historyLabel, open: historyOpen, onToggle: () => setHistoryOpen((v) => !v), children: [_jsx("div", { className: "mt-0.5 flex flex-col gap-0.5", children: history.map(renderItem) }), hasMore && (_jsxs("button", { className: "mt-1 w-full rounded-md py-1.5 text-xs text-muted-foreground hover:bg-accent hover:text-foreground", onClick: onLoadMore, children: [loadMoreLabel, remainingCount != null && remainingCount > 0 && (_jsxs("span", { className: "ml-1 text-muted-foreground", children: ["(", remainingCount, " remaining)"] }))] }))] }))] }))] }) })] }));
47
+ }
48
+ export { ConversationList };
@@ -0,0 +1,20 @@
1
+ import * as React from "react";
2
+ import type { Conversation } from "./types.js";
3
+ interface ConversationListItemProps {
4
+ conversation: Conversation;
5
+ agentLabel?: string;
6
+ isActive?: boolean;
7
+ isRenaming?: boolean;
8
+ renameValue?: string;
9
+ onRenameChange?: (value: string) => void;
10
+ onRenameCommit?: () => void;
11
+ onRenameCancel?: () => void;
12
+ onStartRename?: (e: React.MouseEvent) => void;
13
+ onToggleStar?: (e: React.MouseEvent) => void;
14
+ onClick?: () => void;
15
+ badgesExtra?: React.ReactNode;
16
+ className?: string;
17
+ }
18
+ declare function ConversationListItem({ conversation, agentLabel, isActive, isRenaming, renameValue, onRenameChange, onRenameCommit, onRenameCancel, onStartRename, onToggleStar, onClick, badgesExtra, className, }: ConversationListItemProps): import("react/jsx-runtime").JSX.Element;
19
+ export { ConversationListItem };
20
+ export type { ConversationListItemProps };
@@ -0,0 +1,22 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Pencil, Star } from "lucide-react";
4
+ import { cn } from "../lib/utils.js";
5
+ import { Input } from "../ui/input.js";
6
+ import { formatRelativeTime } from "./utils.js";
7
+ function ConversationListItem({ conversation, agentLabel, isActive, isRenaming, renameValue = "", onRenameChange, onRenameCommit, onRenameCancel, onStartRename, onToggleStar, onClick, badgesExtra, className, }) {
8
+ const handleRenameKeyDown = (e) => {
9
+ if (e.key === "Enter") {
10
+ e.preventDefault();
11
+ onRenameCommit?.();
12
+ }
13
+ else if (e.key === "Escape") {
14
+ e.preventDefault();
15
+ onRenameCancel?.();
16
+ }
17
+ };
18
+ return (_jsxs("div", { className: cn("group relative flex items-center gap-1 rounded-md px-1 py-1 hover:bg-accent", isActive && "bg-accent", className), children: [_jsx("button", { className: cn("shrink-0 rounded p-0.5 transition-colors", conversation.starred
19
+ ? "text-yellow-500 hover:text-yellow-400"
20
+ : "text-muted-foreground opacity-0 group-hover:opacity-100 hover:text-yellow-500"), onClick: onToggleStar, "aria-label": conversation.starred ? "Unstar conversation" : "Star conversation", tabIndex: -1, children: _jsx(Star, { className: cn("size-3.5", conversation.starred && "fill-yellow-500") }) }), isRenaming ? (_jsx(Input, { className: "h-6 flex-1 px-1 py-0 text-sm", value: renameValue, onChange: (e) => onRenameChange?.(e.target.value), onKeyDown: handleRenameKeyDown, onBlur: onRenameCancel, autoFocus: true })) : (_jsxs("button", { className: "flex min-w-0 flex-1 flex-col items-start text-left", onClick: onClick, children: [_jsxs("div", { className: "flex w-full items-center gap-1", children: [agentLabel && (_jsx("span", { className: "shrink-0 rounded bg-secondary px-1 py-0 text-[10px] text-secondary-foreground", children: agentLabel })), badgesExtra, _jsx("span", { className: "ml-auto shrink-0 text-[10px] text-muted-foreground", children: formatRelativeTime(conversation.updatedAt) })] }), _jsx("span", { className: "w-full truncate text-sm text-foreground", children: conversation.title ?? "Untitled" })] })), !isRenaming && (_jsx("button", { className: "shrink-0 rounded p-0.5 text-muted-foreground opacity-0 transition-colors group-hover:opacity-100 hover:text-foreground", onClick: onStartRename, "aria-label": "Rename conversation", tabIndex: -1, children: _jsx(Pencil, { className: "size-3.5" }) }))] }));
21
+ }
22
+ export { ConversationListItem };
@@ -0,0 +1,13 @@
1
+ interface DeleteDialogProps {
2
+ open: boolean;
3
+ onOpenChange: (open: boolean) => void;
4
+ onConfirm: () => void;
5
+ isPending?: boolean;
6
+ title?: string;
7
+ description?: string;
8
+ cancelLabel?: string;
9
+ confirmLabel?: string;
10
+ }
11
+ declare function DeleteDialog({ open, onOpenChange, onConfirm, isPending, title, description, cancelLabel, confirmLabel, }: DeleteDialogProps): import("react/jsx-runtime").JSX.Element;
12
+ export { DeleteDialog };
13
+ export type { DeleteDialogProps };
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Button } from "../ui/button.js";
4
+ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "../ui/dialog.js";
5
+ function DeleteDialog({ open, onOpenChange, onConfirm, isPending, title = "Delete conversation", description = "This conversation will be permanently removed.", cancelLabel = "Cancel", confirmLabel = "Delete", }) {
6
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "sm:max-w-sm", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: title }), _jsx(DialogDescription, { children: description })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: isPending, children: cancelLabel }), _jsx(Button, { variant: "destructive", onClick: onConfirm, disabled: isPending, children: confirmLabel })] })] }) }));
7
+ }
8
+ export { DeleteDialog };
@@ -0,0 +1,15 @@
1
+ interface RenameDialogProps {
2
+ open: boolean;
3
+ onOpenChange: (open: boolean) => void;
4
+ value: string;
5
+ onValueChange: (value: string) => void;
6
+ onConfirm: () => void;
7
+ isPending?: boolean;
8
+ title?: string;
9
+ placeholder?: string;
10
+ cancelLabel?: string;
11
+ confirmLabel?: string;
12
+ }
13
+ declare function RenameDialog({ open, onOpenChange, value, onValueChange, onConfirm, isPending, title, placeholder, cancelLabel, confirmLabel, }: RenameDialogProps): import("react/jsx-runtime").JSX.Element;
14
+ export { RenameDialog };
15
+ export type { RenameDialogProps };
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Button } from "../ui/button.js";
4
+ import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from "../ui/dialog.js";
5
+ import { Input } from "../ui/input.js";
6
+ function RenameDialog({ open, onOpenChange, value, onValueChange, onConfirm, isPending, title = "Rename conversation", placeholder = "Conversation title", cancelLabel = "Cancel", confirmLabel = "Save", }) {
7
+ const handleKeyDown = (e) => {
8
+ if (e.key === "Enter" && value.trim() && !isPending) {
9
+ e.preventDefault();
10
+ onConfirm();
11
+ }
12
+ };
13
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "sm:max-w-sm", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: title }) }), _jsx(Input, { value: value, onChange: (e) => onValueChange(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, autoFocus: true }), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: isPending, children: cancelLabel }), _jsx(Button, { onClick: onConfirm, disabled: !value.trim() || isPending, children: confirmLabel })] })] }) }));
14
+ }
15
+ export { RenameDialog };
@@ -0,0 +1,9 @@
1
+ export { ConversationList } from "./ConversationList.js";
2
+ export type { ConversationListProps } from "./ConversationList.js";
3
+ export { ConversationBar } from "./ConversationBar.js";
4
+ export type { ConversationBarProps } from "./ConversationBar.js";
5
+ export { useConversations } from "./useConversations.js";
6
+ export type { UseConversationsOptions, UseConversationsReturn } from "./useConversations.js";
7
+ export { useIsMobile } from "../hooks/useIsMobile.js";
8
+ export { formatRelativeTime, buildInitialMessages, groupConversations } from "./utils.js";
9
+ export type { Conversation, BackendMessage } from "./types.js";
@@ -0,0 +1,5 @@
1
+ export { ConversationList } from "./ConversationList.js";
2
+ export { ConversationBar } from "./ConversationBar.js";
3
+ export { useConversations } from "./useConversations.js";
4
+ export { useIsMobile } from "../hooks/useIsMobile.js";
5
+ export { formatRelativeTime, buildInitialMessages, groupConversations } from "./utils.js";
@@ -0,0 +1,21 @@
1
+ export interface Conversation {
2
+ id: string;
3
+ title?: string;
4
+ agentId: string;
5
+ updatedAt: string;
6
+ starred: boolean;
7
+ metadata?: Record<string, unknown>;
8
+ }
9
+ export interface BackendMessage {
10
+ id?: string;
11
+ role: string;
12
+ content: string | unknown[];
13
+ _meta?: {
14
+ id?: string;
15
+ ts?: string;
16
+ userId?: string;
17
+ metadata?: Record<string, unknown>;
18
+ };
19
+ timestamp?: string;
20
+ metadata?: Record<string, unknown>;
21
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ import type { Conversation } from "./types.js";
2
+ export interface UseConversationsOptions {
3
+ endpoint?: string;
4
+ token?: string;
5
+ fetcher?: (url: string, init?: RequestInit) => Promise<Response>;
6
+ autoFetch?: boolean;
7
+ }
8
+ export interface UseConversationsReturn {
9
+ conversations: Conversation[];
10
+ isLoading: boolean;
11
+ error: Error | null;
12
+ refresh: () => Promise<void>;
13
+ create: (agentId: string) => Promise<Conversation>;
14
+ rename: (id: string, title: string) => Promise<void>;
15
+ star: (id: string, starred: boolean) => Promise<void>;
16
+ remove: (id: string) => Promise<void>;
17
+ exportUrl: (id: string, format?: "json" | "markdown") => string;
18
+ }
19
+ export declare function useConversations(options?: UseConversationsOptions): UseConversationsReturn;
@@ -0,0 +1,102 @@
1
+ import { useState, useCallback, useEffect } from "react";
2
+ export function useConversations(options = {}) {
3
+ const { endpoint = "", token, fetcher, autoFetch = true } = options;
4
+ const [conversations, setConversations] = useState([]);
5
+ const [isLoading, setIsLoading] = useState(false);
6
+ const [error, setError] = useState(null);
7
+ const doFetch = useCallback((url, init) => {
8
+ const fn = fetcher ?? fetch;
9
+ const headers = {
10
+ "Content-Type": "application/json",
11
+ ...init?.headers,
12
+ };
13
+ if (token) {
14
+ headers["Authorization"] = `Bearer ${token}`;
15
+ }
16
+ return fn(url, { ...init, headers });
17
+ }, [fetcher, token]);
18
+ const refresh = useCallback(async () => {
19
+ setIsLoading(true);
20
+ setError(null);
21
+ try {
22
+ const res = await doFetch(`${endpoint}/api/v1/ai/conversations`);
23
+ if (!res.ok)
24
+ throw new Error(`Failed to fetch conversations: ${res.status}`);
25
+ const data = (await res.json());
26
+ setConversations(data);
27
+ }
28
+ catch (err) {
29
+ setError(err instanceof Error ? err : new Error(String(err)));
30
+ }
31
+ finally {
32
+ setIsLoading(false);
33
+ }
34
+ }, [doFetch, endpoint]);
35
+ useEffect(() => {
36
+ if (autoFetch) {
37
+ void refresh();
38
+ }
39
+ }, [autoFetch, refresh]);
40
+ const create = useCallback(async (agentId) => {
41
+ const res = await doFetch(`${endpoint}/api/v1/ai/conversations`, {
42
+ method: "POST",
43
+ body: JSON.stringify({ agentId }),
44
+ });
45
+ if (!res.ok)
46
+ throw new Error(`Failed to create conversation: ${res.status}`);
47
+ const created = (await res.json());
48
+ setConversations((prev) => [created, ...prev]);
49
+ return created;
50
+ }, [doFetch, endpoint]);
51
+ const rename = useCallback(async (id, title) => {
52
+ const res = await doFetch(`${endpoint}/api/v1/ai/conversations/${id}`, {
53
+ method: "PATCH",
54
+ body: JSON.stringify({ title }),
55
+ });
56
+ if (!res.ok)
57
+ throw new Error(`Failed to rename conversation: ${res.status}`);
58
+ setConversations((prev) => prev.map((c) => (c.id === id ? { ...c, title } : c)));
59
+ }, [doFetch, endpoint]);
60
+ const star = useCallback(async (id, starred) => {
61
+ // Optimistic update
62
+ setConversations((prev) => prev.map((c) => (c.id === id ? { ...c, starred } : c)));
63
+ try {
64
+ const res = await doFetch(`${endpoint}/api/v1/ai/conversations/${id}`, {
65
+ method: "PATCH",
66
+ body: JSON.stringify({ starred }),
67
+ });
68
+ if (!res.ok)
69
+ throw new Error(`Failed to star conversation: ${res.status}`);
70
+ }
71
+ catch (err) {
72
+ // Rollback on error
73
+ setConversations((prev) => prev.map((c) => (c.id === id ? { ...c, starred: !starred } : c)));
74
+ throw err;
75
+ }
76
+ }, [doFetch, endpoint]);
77
+ const remove = useCallback(async (id) => {
78
+ const res = await doFetch(`${endpoint}/api/v1/ai/conversations/${id}`, {
79
+ method: "DELETE",
80
+ });
81
+ if (!res.ok)
82
+ throw new Error(`Failed to delete conversation: ${res.status}`);
83
+ setConversations((prev) => prev.filter((c) => c.id !== id));
84
+ }, [doFetch, endpoint]);
85
+ const exportUrl = useCallback((id, format = "json") => {
86
+ const params = new URLSearchParams({ format });
87
+ if (token)
88
+ params.set("token", token);
89
+ return `${endpoint}/api/v1/ai/conversations/${id}/export?${params.toString()}`;
90
+ }, [endpoint, token]);
91
+ return {
92
+ conversations,
93
+ isLoading,
94
+ error,
95
+ refresh,
96
+ create,
97
+ rename,
98
+ star,
99
+ remove,
100
+ exportUrl,
101
+ };
102
+ }
@@ -0,0 +1,8 @@
1
+ import type { Message } from "@ai-sdk/react";
2
+ import type { BackendMessage, Conversation } from "./types.js";
3
+ export declare function formatRelativeTime(dateStr: string): string;
4
+ export declare function buildInitialMessages(messages?: BackendMessage[]): Message[] | undefined;
5
+ export declare function groupConversations(conversations: Conversation[]): {
6
+ favorites: Conversation[];
7
+ history: Conversation[];
8
+ };
@@ -0,0 +1,134 @@
1
+ export function formatRelativeTime(dateStr) {
2
+ const diff = Date.now() - new Date(dateStr).getTime();
3
+ const seconds = Math.floor(diff / 1000);
4
+ if (seconds < 60)
5
+ return "now";
6
+ const minutes = Math.floor(seconds / 60);
7
+ if (minutes < 60)
8
+ return `${minutes}m ago`;
9
+ const hours = Math.floor(minutes / 60);
10
+ if (hours < 24)
11
+ return `${hours}h ago`;
12
+ const days = Math.floor(hours / 24);
13
+ return `${days}d ago`;
14
+ }
15
+ export function buildInitialMessages(messages) {
16
+ if (!messages)
17
+ return undefined;
18
+ // Index tool results by toolCallId
19
+ const toolResults = new Map();
20
+ for (const m of messages) {
21
+ if (m.role === "tool" && Array.isArray(m.content)) {
22
+ for (const part of m.content) {
23
+ if (part.type === "tool-result" && part.toolCallId) {
24
+ const raw = part.output;
25
+ const value = typeof raw === "object" &&
26
+ raw !== null &&
27
+ "type" in raw &&
28
+ raw.type === "json"
29
+ ? raw.value
30
+ : raw;
31
+ toolResults.set(part.toolCallId, { toolName: part.toolName ?? "", result: value });
32
+ }
33
+ }
34
+ }
35
+ }
36
+ const result = [];
37
+ let i = 0;
38
+ while (i < messages.length) {
39
+ const m = messages[i];
40
+ if (m.role === "user") {
41
+ let content = "";
42
+ const parts = [];
43
+ if (typeof m.content === "string") {
44
+ content = m.content;
45
+ }
46
+ else if (Array.isArray(m.content)) {
47
+ for (const p of m.content) {
48
+ if (p["type"] === "text") {
49
+ const text = String(p["text"] ?? "");
50
+ if (!text.startsWith("[📎") && !content)
51
+ content = text;
52
+ parts.push(p);
53
+ }
54
+ else if (p["type"] === "image" || p["type"] === "file") {
55
+ parts.push({ type: p["type"], _ref: p["_ref"], mimeType: p["mimeType"] });
56
+ }
57
+ else {
58
+ parts.push(p);
59
+ }
60
+ }
61
+ }
62
+ result.push({
63
+ id: m._meta?.id ?? m.id ?? `msg-${i}`,
64
+ role: "user",
65
+ content,
66
+ ...(parts.length > 0 ? { parts } : {}),
67
+ });
68
+ i++;
69
+ continue;
70
+ }
71
+ if (m.role === "tool") {
72
+ i++;
73
+ continue;
74
+ }
75
+ if (m.role === "assistant") {
76
+ const parts = [];
77
+ let textContent = "";
78
+ const id = m._meta?.id ?? m.id ?? `msg-${i}`;
79
+ while (i < messages.length &&
80
+ (messages[i].role === "assistant" || messages[i].role === "tool")) {
81
+ const cur = messages[i];
82
+ if (cur.role === "tool") {
83
+ i++;
84
+ continue;
85
+ }
86
+ if (typeof cur.content === "string") {
87
+ if (cur.content) {
88
+ parts.push({ type: "text", text: cur.content });
89
+ textContent += cur.content;
90
+ }
91
+ }
92
+ else if (Array.isArray(cur.content)) {
93
+ for (const p of cur.content) {
94
+ if (p.type === "text" && p.text) {
95
+ parts.push({ type: "text", text: p.text });
96
+ textContent += p.text;
97
+ }
98
+ else if (p.type === "tool-call" && p.toolCallId) {
99
+ const tr = toolResults.get(p.toolCallId);
100
+ parts.push({
101
+ type: "tool-invocation",
102
+ toolInvocation: {
103
+ toolName: p.toolName ?? "",
104
+ toolCallId: p.toolCallId,
105
+ state: tr ? "result" : "call",
106
+ args: p.input,
107
+ result: tr?.result,
108
+ },
109
+ });
110
+ }
111
+ }
112
+ }
113
+ i++;
114
+ }
115
+ result.push({ id, role: "assistant", content: textContent, parts });
116
+ continue;
117
+ }
118
+ i++;
119
+ }
120
+ return result;
121
+ }
122
+ export function groupConversations(conversations) {
123
+ const favorites = [];
124
+ const history = [];
125
+ for (const conv of conversations) {
126
+ if (conv.starred) {
127
+ favorites.push(conv);
128
+ }
129
+ else {
130
+ history.push(conv);
131
+ }
132
+ }
133
+ return { favorites, history };
134
+ }
@@ -0,0 +1,2 @@
1
+ import type { DisplayAlert } from "@gugacoder/agentic-sdk";
2
+ export declare function AlertRenderer({ variant, title, message }: DisplayAlert): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { AlertCircle, AlertTriangle, CheckCircle, Info } from "lucide-react";
3
+ import { Alert, AlertDescription, AlertTitle } from "../ui/alert.js";
4
+ const VARIANT_CONFIG = {
5
+ info: { Icon: Info, className: "text-blue-600 dark:text-blue-400 *:[svg]:text-blue-600 dark:*:[svg]:text-blue-400 border-blue-500/50" },
6
+ warning: { Icon: AlertTriangle, className: "text-yellow-600 dark:text-yellow-400 *:[svg]:text-yellow-600 dark:*:[svg]:text-yellow-400 border-yellow-500/50" },
7
+ error: { Icon: AlertCircle },
8
+ success: { Icon: CheckCircle, className: "text-green-600 dark:text-green-400 *:[svg]:text-green-600 dark:*:[svg]:text-green-400 border-green-500/50" },
9
+ };
10
+ export function AlertRenderer({ variant = "info", title, message }) {
11
+ const { Icon, className } = VARIANT_CONFIG[variant];
12
+ return (_jsxs(Alert, { variant: variant === "error" ? "destructive" : "default", className: className, children: [_jsx(Icon, {}), title && _jsx(AlertTitle, { children: title }), _jsx(AlertDescription, { children: message })] }));
13
+ }
@@ -0,0 +1,2 @@
1
+ import type { DisplayCarousel } from "@gugacoder/agentic-sdk";
2
+ export declare function CarouselRenderer({ title, items }: DisplayCarousel): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,41 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import useEmblaCarousel from "embla-carousel-react";
3
+ import { ChevronLeft, ChevronRight } from "lucide-react";
4
+ import { useCallback, useEffect, useState } from "react";
5
+ import { Badge } from "../ui/badge";
6
+ import { Button } from "../ui/button";
7
+ import { Card, CardContent } from "../ui/card";
8
+ import { cn } from "../lib/utils";
9
+ function formatPrice(value, currency) {
10
+ return new Intl.NumberFormat("pt-BR", { style: "currency", currency }).format(value);
11
+ }
12
+ export function CarouselRenderer({ title, items }) {
13
+ const [emblaRef, emblaApi] = useEmblaCarousel({ loop: false, dragFree: false });
14
+ const [selectedIndex, setSelectedIndex] = useState(0);
15
+ const [canScrollPrev, setCanScrollPrev] = useState(false);
16
+ const [canScrollNext, setCanScrollNext] = useState(false);
17
+ const onSelect = useCallback(() => {
18
+ if (!emblaApi)
19
+ return;
20
+ setSelectedIndex(emblaApi.selectedScrollSnap());
21
+ setCanScrollPrev(emblaApi.canScrollPrev());
22
+ setCanScrollNext(emblaApi.canScrollNext());
23
+ }, [emblaApi]);
24
+ useEffect(() => {
25
+ if (!emblaApi)
26
+ return;
27
+ onSelect();
28
+ emblaApi.on("select", onSelect);
29
+ emblaApi.on("reInit", onSelect);
30
+ return () => {
31
+ emblaApi.off("select", onSelect);
32
+ emblaApi.off("reInit", onSelect);
33
+ };
34
+ }, [emblaApi, onSelect]);
35
+ const scrollPrev = useCallback(() => emblaApi?.scrollPrev(), [emblaApi]);
36
+ const scrollNext = useCallback(() => emblaApi?.scrollNext(), [emblaApi]);
37
+ return (_jsxs("div", { className: "flex flex-col gap-3", children: [title && _jsx("p", { className: "text-sm font-medium text-foreground", children: title }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "outline", size: "icon", className: "rounded-full shrink-0", onClick: scrollPrev, disabled: !canScrollPrev, "aria-label": "Anterior", type: "button", children: _jsx(ChevronLeft, { className: "h-4 w-4" }) }), _jsx("div", { className: "overflow-hidden flex-1", ref: emblaRef, children: _jsx("div", { className: "flex", children: items.map((item, index) => (_jsx("div", { className: "flex-[0_0_80%] min-w-0 pl-3 first:pl-0", children: item.url ? (_jsx("a", { href: item.url, target: "_blank", rel: "noopener noreferrer", className: "block", children: _jsx(CarouselCard, { item: item }) })) : (_jsx(CarouselCard, { item: item })) }, index))) }) }), _jsx(Button, { variant: "outline", size: "icon", className: "rounded-full shrink-0", onClick: scrollNext, disabled: !canScrollNext, "aria-label": "Pr\u00F3ximo", type: "button", children: _jsx(ChevronRight, { className: "h-4 w-4" }) })] }), items.length > 1 && (_jsx("div", { className: "flex items-center justify-center gap-1.5", role: "tablist", "aria-label": "Slides", children: items.map((_, index) => (_jsx("button", { className: cn("w-2 h-2 rounded-full transition-colors", index === selectedIndex ? "bg-primary" : "bg-muted"), onClick: () => emblaApi?.scrollTo(index), role: "tab", "aria-selected": index === selectedIndex, "aria-label": `Slide ${index + 1}`, type: "button" }, index))) }))] }));
38
+ }
39
+ function CarouselCard({ item }) {
40
+ return (_jsxs(Card, { className: "overflow-hidden", children: [item.image && (_jsx("div", { className: "aspect-video overflow-hidden", children: _jsx("img", { src: item.image, alt: item.title, loading: "lazy", className: "w-full h-full object-cover" }) })), _jsxs(CardContent, { className: "p-3 space-y-1", children: [_jsx("p", { className: "font-medium text-sm text-foreground", children: item.title }), item.subtitle && (_jsx("p", { className: "text-xs text-muted-foreground", children: item.subtitle })), item.price && (_jsx("p", { className: "text-sm font-bold text-foreground", children: formatPrice(item.price.value, item.price.currency) })), item.badges && item.badges.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-1 pt-1", children: item.badges.map((badge, i) => (_jsx(Badge, { variant: badge.variant === "destructive" ? "destructive" : badge.variant === "secondary" ? "secondary" : "default", children: badge.label }, i))) }))] })] }));
41
+ }
@@ -0,0 +1,2 @@
1
+ import type { DisplayChart } from "@gugacoder/agentic-sdk";
2
+ export declare function ChartRenderer({ type, title, data, format }: DisplayChart): import("react/jsx-runtime").JSX.Element;