@rodrigocoliveira/agno-react 1.0.1 → 1.0.3

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 (158) hide show
  1. package/README.md +363 -83
  2. package/dist/components/GenerativeUIRenderer.d.ts +21 -0
  3. package/dist/components/GenerativeUIRenderer.d.ts.map +1 -0
  4. package/dist/context/AgnoContext.d.ts +16 -0
  5. package/dist/context/AgnoContext.d.ts.map +1 -0
  6. package/dist/context/ToolHandlerContext.d.ts +44 -0
  7. package/dist/context/ToolHandlerContext.d.ts.map +1 -0
  8. package/dist/hooks/useAgnoActions.d.ts +25 -0
  9. package/dist/hooks/useAgnoActions.d.ts.map +1 -0
  10. package/dist/hooks/useAgnoChat.d.ts +22 -0
  11. package/dist/hooks/useAgnoChat.d.ts.map +1 -0
  12. package/dist/hooks/useAgnoCustomEvents.d.ts +38 -0
  13. package/dist/hooks/useAgnoCustomEvents.d.ts.map +1 -0
  14. package/dist/hooks/useAgnoEvals.d.ts +39 -0
  15. package/dist/hooks/useAgnoEvals.d.ts.map +1 -0
  16. package/dist/hooks/useAgnoKnowledge.d.ts +56 -0
  17. package/dist/hooks/useAgnoKnowledge.d.ts.map +1 -0
  18. package/dist/hooks/useAgnoMemory.d.ts +42 -0
  19. package/dist/hooks/useAgnoMemory.d.ts.map +1 -0
  20. package/dist/hooks/useAgnoMetrics.d.ts +51 -0
  21. package/dist/hooks/useAgnoMetrics.d.ts.map +1 -0
  22. package/dist/hooks/useAgnoSession.d.ts +38 -0
  23. package/dist/hooks/useAgnoSession.d.ts.map +1 -0
  24. package/dist/hooks/useAgnoToolExecution.d.ts +70 -0
  25. package/dist/hooks/useAgnoToolExecution.d.ts.map +1 -0
  26. package/dist/hooks/useAgnoTraces.d.ts +51 -0
  27. package/dist/hooks/useAgnoTraces.d.ts.map +1 -0
  28. package/dist/index.d.ts +27 -723
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +932 -1052
  31. package/dist/index.js.map +24 -0
  32. package/dist/index.mjs +816 -909
  33. package/dist/index.mjs.map +24 -0
  34. package/dist/ui/components/artifact.d.ts +24 -0
  35. package/dist/ui/components/artifact.d.ts.map +1 -0
  36. package/dist/ui/components/audio-recorder.d.ts +32 -0
  37. package/dist/ui/components/audio-recorder.d.ts.map +1 -0
  38. package/dist/ui/components/code-block.d.ts +15 -0
  39. package/dist/ui/components/code-block.d.ts.map +1 -0
  40. package/dist/ui/components/conversation.d.ts +17 -0
  41. package/dist/ui/components/conversation.d.ts.map +1 -0
  42. package/dist/ui/components/file-preview-card.d.ts +13 -0
  43. package/dist/ui/components/file-preview-card.d.ts.map +1 -0
  44. package/dist/ui/components/file-preview-modal.d.ts +8 -0
  45. package/dist/ui/components/file-preview-modal.d.ts.map +1 -0
  46. package/dist/ui/components/image-lightbox.d.ts +12 -0
  47. package/dist/ui/components/image-lightbox.d.ts.map +1 -0
  48. package/dist/ui/components/message.d.ts +19 -0
  49. package/dist/ui/components/message.d.ts.map +1 -0
  50. package/dist/ui/components/prompt-input/attachments.d.ts +21 -0
  51. package/dist/ui/components/prompt-input/attachments.d.ts.map +1 -0
  52. package/dist/ui/components/prompt-input/buttons.d.ts +19 -0
  53. package/dist/ui/components/prompt-input/buttons.d.ts.map +1 -0
  54. package/dist/ui/components/prompt-input/command.d.ts +17 -0
  55. package/dist/ui/components/prompt-input/command.d.ts.map +1 -0
  56. package/dist/ui/components/prompt-input/context.d.ts +36 -0
  57. package/dist/ui/components/prompt-input/context.d.ts.map +1 -0
  58. package/dist/ui/components/prompt-input/drop-zone.d.ts +7 -0
  59. package/dist/ui/components/prompt-input/drop-zone.d.ts.map +1 -0
  60. package/dist/ui/components/prompt-input/footer.d.ts +11 -0
  61. package/dist/ui/components/prompt-input/footer.d.ts.map +1 -0
  62. package/dist/ui/components/prompt-input/index.d.ts +25 -0
  63. package/dist/ui/components/prompt-input/index.d.ts.map +1 -0
  64. package/dist/ui/components/prompt-input/model-select.d.ts +13 -0
  65. package/dist/ui/components/prompt-input/model-select.d.ts.map +1 -0
  66. package/dist/ui/components/prompt-input/prompt-input.d.ts +22 -0
  67. package/dist/ui/components/prompt-input/prompt-input.d.ts.map +1 -0
  68. package/dist/ui/components/prompt-input/provider.d.ts +6 -0
  69. package/dist/ui/components/prompt-input/provider.d.ts.map +1 -0
  70. package/dist/ui/components/prompt-input/speech.d.ts +51 -0
  71. package/dist/ui/components/prompt-input/speech.d.ts.map +1 -0
  72. package/dist/ui/components/prompt-input/tabs.d.ts +12 -0
  73. package/dist/ui/components/prompt-input/tabs.d.ts.map +1 -0
  74. package/dist/ui/components/prompt-input/textarea.d.ts +5 -0
  75. package/dist/ui/components/prompt-input/textarea.d.ts.map +1 -0
  76. package/dist/ui/components/response.d.ts +5 -0
  77. package/dist/ui/components/response.d.ts.map +1 -0
  78. package/dist/ui/components/smart-timestamp.d.ts +8 -0
  79. package/dist/ui/components/smart-timestamp.d.ts.map +1 -0
  80. package/dist/ui/components/streaming-indicator.d.ts +8 -0
  81. package/dist/ui/components/streaming-indicator.d.ts.map +1 -0
  82. package/dist/ui/components/tool.d.ts +24 -0
  83. package/dist/ui/components/tool.d.ts.map +1 -0
  84. package/dist/ui/composed/AgnoChatInput.d.ts +44 -0
  85. package/dist/ui/composed/AgnoChatInput.d.ts.map +1 -0
  86. package/dist/ui/composed/AgnoChatInterface.d.ts +49 -0
  87. package/dist/ui/composed/AgnoChatInterface.d.ts.map +1 -0
  88. package/dist/ui/composed/AgnoMessageItem.d.ts +38 -0
  89. package/dist/ui/composed/AgnoMessageItem.d.ts.map +1 -0
  90. package/dist/ui/composed/agno-chat/agno-chat.d.ts +9 -0
  91. package/dist/ui/composed/agno-chat/agno-chat.d.ts.map +1 -0
  92. package/dist/ui/composed/agno-chat/context.d.ts +33 -0
  93. package/dist/ui/composed/agno-chat/context.d.ts.map +1 -0
  94. package/dist/ui/composed/agno-chat/empty-state.d.ts +6 -0
  95. package/dist/ui/composed/agno-chat/empty-state.d.ts.map +1 -0
  96. package/dist/ui/composed/agno-chat/error-bar.d.ts +5 -0
  97. package/dist/ui/composed/agno-chat/error-bar.d.ts.map +1 -0
  98. package/dist/ui/composed/agno-chat/index.d.ts +33 -0
  99. package/dist/ui/composed/agno-chat/index.d.ts.map +1 -0
  100. package/dist/ui/composed/agno-chat/input.d.ts +39 -0
  101. package/dist/ui/composed/agno-chat/input.d.ts.map +1 -0
  102. package/dist/ui/composed/agno-chat/messages.d.ts +21 -0
  103. package/dist/ui/composed/agno-chat/messages.d.ts.map +1 -0
  104. package/dist/ui/composed/agno-chat/suggested-prompts.d.ts +7 -0
  105. package/dist/ui/composed/agno-chat/suggested-prompts.d.ts.map +1 -0
  106. package/dist/ui/composed/agno-chat/tool-status.d.ts +5 -0
  107. package/dist/ui/composed/agno-chat/tool-status.d.ts.map +1 -0
  108. package/dist/ui/composed/index.d.ts +9 -0
  109. package/dist/ui/composed/index.d.ts.map +1 -0
  110. package/dist/ui/index.d.ts +59 -0
  111. package/dist/ui/index.d.ts.map +1 -0
  112. package/dist/ui/lib/cn.d.ts +3 -0
  113. package/dist/ui/lib/cn.d.ts.map +1 -0
  114. package/dist/ui/lib/file-utils.d.ts +20 -0
  115. package/dist/ui/lib/file-utils.d.ts.map +1 -0
  116. package/dist/ui/lib/format-timestamp.d.ts +16 -0
  117. package/dist/ui/lib/format-timestamp.d.ts.map +1 -0
  118. package/dist/ui/primitives/accordion.d.ts +8 -0
  119. package/dist/ui/primitives/accordion.d.ts.map +1 -0
  120. package/dist/ui/primitives/avatar.d.ts +7 -0
  121. package/dist/ui/primitives/avatar.d.ts.map +1 -0
  122. package/dist/ui/primitives/badge.d.ts +10 -0
  123. package/dist/ui/primitives/badge.d.ts.map +1 -0
  124. package/dist/ui/primitives/button.d.ts +12 -0
  125. package/dist/ui/primitives/button.d.ts.map +1 -0
  126. package/dist/ui/primitives/collapsible.d.ts +6 -0
  127. package/dist/ui/primitives/collapsible.d.ts.map +1 -0
  128. package/dist/ui/primitives/command.d.ts +79 -0
  129. package/dist/ui/primitives/command.d.ts.map +1 -0
  130. package/dist/ui/primitives/dialog.d.ts +26 -0
  131. package/dist/ui/primitives/dialog.d.ts.map +1 -0
  132. package/dist/ui/primitives/dropdown-menu.d.ts +28 -0
  133. package/dist/ui/primitives/dropdown-menu.d.ts.map +1 -0
  134. package/dist/ui/primitives/hover-card.d.ts +7 -0
  135. package/dist/ui/primitives/hover-card.d.ts.map +1 -0
  136. package/dist/ui/primitives/index.d.ts +16 -0
  137. package/dist/ui/primitives/index.d.ts.map +1 -0
  138. package/dist/ui/primitives/input-group.d.ts +17 -0
  139. package/dist/ui/primitives/input-group.d.ts.map +1 -0
  140. package/dist/ui/primitives/select.d.ts +14 -0
  141. package/dist/ui/primitives/select.d.ts.map +1 -0
  142. package/dist/ui/primitives/tooltip.d.ts +8 -0
  143. package/dist/ui/primitives/tooltip.d.ts.map +1 -0
  144. package/dist/ui/types.d.ts +56 -0
  145. package/dist/ui/types.d.ts.map +1 -0
  146. package/dist/ui.d.ts +2 -0
  147. package/dist/ui.d.ts.map +1 -0
  148. package/dist/ui.js +4059 -0
  149. package/dist/ui.js.map +60 -0
  150. package/dist/ui.mjs +4044 -0
  151. package/dist/ui.mjs.map +60 -0
  152. package/dist/utils/component-registry.d.ts +63 -0
  153. package/dist/utils/component-registry.d.ts.map +1 -0
  154. package/dist/utils/ui-helpers.d.ts +165 -0
  155. package/dist/utils/ui-helpers.d.ts.map +1 -0
  156. package/package.json +122 -17
  157. package/LICENSE +0 -21
  158. package/dist/index.d.mts +0 -724
package/dist/ui.mjs ADDED
@@ -0,0 +1,4044 @@
1
+ "use client";
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined")
6
+ return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
9
+
10
+ // src/ui/lib/cn.ts
11
+ import { clsx } from "clsx";
12
+ import { twMerge } from "tailwind-merge";
13
+ function cn(...inputs) {
14
+ return twMerge(clsx(inputs));
15
+ }
16
+ // src/ui/lib/format-timestamp.ts
17
+ function formatSmartTimestamp(date) {
18
+ const now = new Date;
19
+ const isToday = date.getFullYear() === now.getFullYear() && date.getMonth() === now.getMonth() && date.getDate() === now.getDate();
20
+ if (isToday) {
21
+ return new Intl.DateTimeFormat(undefined, {
22
+ hour: "numeric",
23
+ minute: "2-digit",
24
+ hour12: true
25
+ }).format(date);
26
+ }
27
+ const isSameYear = date.getFullYear() === now.getFullYear();
28
+ if (isSameYear) {
29
+ return new Intl.DateTimeFormat(undefined, {
30
+ month: "short",
31
+ day: "numeric"
32
+ }).format(date);
33
+ }
34
+ return new Intl.DateTimeFormat(undefined, {
35
+ month: "short",
36
+ day: "numeric",
37
+ year: "numeric"
38
+ }).format(date);
39
+ }
40
+ function formatFullTimestamp(date) {
41
+ return new Intl.DateTimeFormat(undefined, {
42
+ month: "short",
43
+ day: "numeric",
44
+ year: "numeric",
45
+ hour: "numeric",
46
+ minute: "2-digit",
47
+ hour12: true
48
+ }).format(date);
49
+ }
50
+ // src/ui/lib/file-utils.ts
51
+ function getFilePreviewType(mimeType) {
52
+ if (!mimeType)
53
+ return "none";
54
+ if (mimeType.startsWith("image/"))
55
+ return "image";
56
+ if (mimeType === "application/pdf")
57
+ return "pdf";
58
+ if (mimeType.startsWith("text/"))
59
+ return "text";
60
+ if (mimeType.startsWith("video/"))
61
+ return "video";
62
+ if (mimeType.startsWith("audio/"))
63
+ return "audio";
64
+ return "none";
65
+ }
66
+ function formatFileSize(bytes) {
67
+ if (bytes === 0)
68
+ return "0 B";
69
+ const units = ["B", "KB", "MB", "GB", "TB"];
70
+ const k = 1024;
71
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
72
+ const value = bytes / Math.pow(k, i);
73
+ return `${value % 1 === 0 ? value : value.toFixed(1)} ${units[i]}`;
74
+ }
75
+ function getFileExtension(filename, mimeType) {
76
+ const lastDot = filename.lastIndexOf(".");
77
+ if (lastDot !== -1 && lastDot !== 0) {
78
+ return filename.slice(lastDot + 1).toLowerCase();
79
+ }
80
+ if (mimeType) {
81
+ return extensionFromMime(mimeType);
82
+ }
83
+ return "";
84
+ }
85
+ var mimeToExt = {
86
+ "application/pdf": "pdf",
87
+ "application/zip": "zip",
88
+ "application/x-rar-compressed": "rar",
89
+ "application/json": "json",
90
+ "application/xml": "xml",
91
+ "application/msword": "doc",
92
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
93
+ "application/vnd.ms-excel": "xls",
94
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
95
+ "application/vnd.ms-powerpoint": "ppt",
96
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": "pptx",
97
+ "text/csv": "csv",
98
+ "text/plain": "txt",
99
+ "text/html": "html",
100
+ "text/css": "css",
101
+ "text/javascript": "js"
102
+ };
103
+ function extensionFromMime(mimeType) {
104
+ if (mimeToExt[mimeType])
105
+ return mimeToExt[mimeType];
106
+ const subtype = mimeType.split("/")[1];
107
+ if (subtype && !subtype.includes(".") && !subtype.includes("+")) {
108
+ return subtype.toLowerCase();
109
+ }
110
+ return "";
111
+ }
112
+ function isPreviewable(mimeType) {
113
+ const type = getFilePreviewType(mimeType);
114
+ return type === "image" || type === "pdf";
115
+ }
116
+ // src/ui/primitives/button.tsx
117
+ import * as React from "react";
118
+ import { Slot } from "@radix-ui/react-slot";
119
+ import { cva } from "class-variance-authority";
120
+ import { jsxDEV } from "react/jsx-dev-runtime";
121
+ var buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", {
122
+ variants: {
123
+ variant: {
124
+ default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
125
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
126
+ outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
127
+ secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
128
+ ghost: "hover:bg-accent hover:text-accent-foreground",
129
+ link: "text-primary underline-offset-4 hover:underline"
130
+ },
131
+ size: {
132
+ default: "h-9 px-4 py-2",
133
+ sm: "h-8 rounded-md px-3 text-xs",
134
+ lg: "h-10 rounded-md px-8",
135
+ icon: "h-9 w-9"
136
+ }
137
+ },
138
+ defaultVariants: {
139
+ variant: "default",
140
+ size: "default"
141
+ }
142
+ });
143
+ var Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
144
+ const Comp = asChild ? Slot : "button";
145
+ return /* @__PURE__ */ jsxDEV(Comp, {
146
+ className: cn(buttonVariants({ variant, size, className })),
147
+ ref,
148
+ ...props
149
+ }, undefined, false, undefined, this);
150
+ });
151
+ Button.displayName = "Button";
152
+ // src/ui/primitives/badge.tsx
153
+ import { cva as cva2 } from "class-variance-authority";
154
+ import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
155
+ var badgeVariants = cva2("inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", {
156
+ variants: {
157
+ variant: {
158
+ default: "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
159
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
160
+ destructive: "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
161
+ outline: "text-foreground"
162
+ }
163
+ },
164
+ defaultVariants: {
165
+ variant: "default"
166
+ }
167
+ });
168
+ function Badge({ className, variant, ...props }) {
169
+ return /* @__PURE__ */ jsxDEV2("div", {
170
+ className: cn(badgeVariants({ variant }), className),
171
+ ...props
172
+ }, undefined, false, undefined, this);
173
+ }
174
+ // src/ui/primitives/avatar.tsx
175
+ import * as React2 from "react";
176
+ import * as AvatarPrimitive from "@radix-ui/react-avatar";
177
+ import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
178
+ var Avatar = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV3(AvatarPrimitive.Root, {
179
+ ref,
180
+ className: cn("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", className),
181
+ ...props
182
+ }, undefined, false, undefined, this));
183
+ Avatar.displayName = AvatarPrimitive.Root.displayName;
184
+ var AvatarImage = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV3(AvatarPrimitive.Image, {
185
+ ref,
186
+ className: cn("aspect-square h-full w-full", className),
187
+ ...props
188
+ }, undefined, false, undefined, this));
189
+ AvatarImage.displayName = AvatarPrimitive.Image.displayName;
190
+ var AvatarFallback = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV3(AvatarPrimitive.Fallback, {
191
+ ref,
192
+ className: cn("flex h-full w-full items-center justify-center rounded-full bg-muted", className),
193
+ ...props
194
+ }, undefined, false, undefined, this));
195
+ AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
196
+ // src/ui/primitives/input-group.tsx
197
+ import * as React3 from "react";
198
+ import { cva as cva3 } from "class-variance-authority";
199
+ import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
200
+ var Input = React3.forwardRef(({ className, type, ...props }, ref) => {
201
+ return /* @__PURE__ */ jsxDEV4("input", {
202
+ type,
203
+ className: cn("flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", className),
204
+ ref,
205
+ ...props
206
+ }, undefined, false, undefined, this);
207
+ });
208
+ Input.displayName = "Input";
209
+ var Textarea = React3.forwardRef(({ className, ...props }, ref) => {
210
+ return /* @__PURE__ */ jsxDEV4("textarea", {
211
+ className: cn("flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", className),
212
+ ref,
213
+ ...props
214
+ }, undefined, false, undefined, this);
215
+ });
216
+ Textarea.displayName = "Textarea";
217
+ function InputGroup({ className, ...props }) {
218
+ return /* @__PURE__ */ jsxDEV4("div", {
219
+ "data-slot": "input-group",
220
+ role: "group",
221
+ className: cn("group/input-group border-input dark:bg-input/30 shadow-xs relative flex w-full items-center rounded-md border outline-none transition-[color,box-shadow]", "h-9 has-[>textarea]:h-auto", "has-[>[data-align=inline-start]]:[&>input]:pl-2", "has-[>[data-align=inline-end]]:[&>input]:pr-2", "has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3", "has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-2.5", "has-[[data-slot=input-group-control]:focus-visible]:ring-ring has-[[data-slot=input-group-control]:focus-visible]:ring-1", "has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40", className),
222
+ ...props
223
+ }, undefined, false, undefined, this);
224
+ }
225
+ var inputGroupAddonVariants = cva3("text-muted-foreground flex h-auto cursor-text select-none items-center justify-center gap-2 py-1.5 text-sm font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4", {
226
+ variants: {
227
+ align: {
228
+ "inline-start": "order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]",
229
+ "inline-end": "order-last pr-3 has-[>button]:mr-[-0.4rem] has-[>kbd]:mr-[-0.35rem]",
230
+ "block-start": "[.border-b]:pb-3 order-first w-full justify-start px-3 pt-2 pb-0 group-has-[>input]/input-group:pt-2.5",
231
+ "block-end": "[.border-t]:pt-3 order-last w-full justify-start px-3 pb-1.5 group-has-[>input]/input-group:pb-1.5"
232
+ }
233
+ },
234
+ defaultVariants: {
235
+ align: "inline-start"
236
+ }
237
+ });
238
+ function InputGroupAddon({
239
+ className,
240
+ align = "inline-start",
241
+ ...props
242
+ }) {
243
+ return /* @__PURE__ */ jsxDEV4("div", {
244
+ role: "group",
245
+ "data-slot": "input-group-addon",
246
+ "data-align": align,
247
+ className: cn(inputGroupAddonVariants({ align }), className),
248
+ onClick: (e) => {
249
+ if (e.target.closest("button")) {
250
+ return;
251
+ }
252
+ e.currentTarget.parentElement?.querySelector("input")?.focus();
253
+ },
254
+ ...props
255
+ }, undefined, false, undefined, this);
256
+ }
257
+ var inputGroupButtonVariants = cva3("flex items-center gap-2 text-sm shadow-none", {
258
+ variants: {
259
+ size: {
260
+ xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
261
+ sm: "h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5",
262
+ "icon-xs": "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0",
263
+ "icon-sm": "size-8 p-0 has-[>svg]:p-0"
264
+ }
265
+ },
266
+ defaultVariants: {
267
+ size: "xs"
268
+ }
269
+ });
270
+ function InputGroupButton({
271
+ className,
272
+ type = "button",
273
+ variant = "ghost",
274
+ size = "xs",
275
+ ...props
276
+ }) {
277
+ return /* @__PURE__ */ jsxDEV4(Button, {
278
+ type,
279
+ "data-size": size,
280
+ variant,
281
+ className: cn(inputGroupButtonVariants({ size }), className),
282
+ ...props
283
+ }, undefined, false, undefined, this);
284
+ }
285
+ function InputGroupText({ className, ...props }) {
286
+ return /* @__PURE__ */ jsxDEV4("span", {
287
+ className: cn("text-muted-foreground flex items-center gap-2 text-sm [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none", className),
288
+ ...props
289
+ }, undefined, false, undefined, this);
290
+ }
291
+ function InputGroupInput({ className, ...props }) {
292
+ return /* @__PURE__ */ jsxDEV4(Input, {
293
+ "data-slot": "input-group-control",
294
+ className: cn("flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent", className),
295
+ ...props
296
+ }, undefined, false, undefined, this);
297
+ }
298
+ function InputGroupTextarea({ className, ...props }) {
299
+ return /* @__PURE__ */ jsxDEV4(Textarea, {
300
+ "data-slot": "input-group-control",
301
+ className: cn("flex-1 resize-none rounded-none border-0 bg-transparent min-h-0 pt-3.5 pb-1.5 pl-3.5 shadow-none focus-visible:ring-0 dark:bg-transparent", className),
302
+ ...props
303
+ }, undefined, false, undefined, this);
304
+ }
305
+ // src/ui/primitives/collapsible.tsx
306
+ import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
307
+ var Collapsible = CollapsiblePrimitive.Root;
308
+ var CollapsibleTrigger2 = CollapsiblePrimitive.CollapsibleTrigger;
309
+ var CollapsibleContent2 = CollapsiblePrimitive.CollapsibleContent;
310
+ // src/ui/primitives/tooltip.tsx
311
+ import * as React4 from "react";
312
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
313
+ import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
314
+ var TooltipProvider = TooltipPrimitive.Provider;
315
+ var Tooltip = TooltipPrimitive.Root;
316
+ var TooltipTrigger = TooltipPrimitive.Trigger;
317
+ var TooltipContent = React4.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsxDEV5(TooltipPrimitive.Portal, {
318
+ children: /* @__PURE__ */ jsxDEV5(TooltipPrimitive.Content, {
319
+ ref,
320
+ sideOffset,
321
+ className: cn("z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]", className),
322
+ ...props
323
+ }, undefined, false, undefined, this)
324
+ }, undefined, false, undefined, this));
325
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
326
+ // src/ui/primitives/accordion.tsx
327
+ import * as React5 from "react";
328
+ import * as AccordionPrimitive from "@radix-ui/react-accordion";
329
+ import { ChevronDown } from "lucide-react";
330
+ import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
331
+ var Accordion = AccordionPrimitive.Root;
332
+ var AccordionItem = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV6(AccordionPrimitive.Item, {
333
+ ref,
334
+ className: cn("border-b", className),
335
+ ...props
336
+ }, undefined, false, undefined, this));
337
+ AccordionItem.displayName = "AccordionItem";
338
+ var AccordionTrigger = React5.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxDEV6(AccordionPrimitive.Header, {
339
+ className: "flex",
340
+ children: /* @__PURE__ */ jsxDEV6(AccordionPrimitive.Trigger, {
341
+ ref,
342
+ className: cn("flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline text-left [&[data-state=open]>svg]:rotate-180", className),
343
+ ...props,
344
+ children: [
345
+ children,
346
+ /* @__PURE__ */ jsxDEV6(ChevronDown, {
347
+ className: "h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200"
348
+ }, undefined, false, undefined, this)
349
+ ]
350
+ }, undefined, true, undefined, this)
351
+ }, undefined, false, undefined, this));
352
+ AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
353
+ var AccordionContent = React5.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxDEV6(AccordionPrimitive.Content, {
354
+ ref,
355
+ className: "overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",
356
+ ...props,
357
+ children: /* @__PURE__ */ jsxDEV6("div", {
358
+ className: cn("pb-4 pt-0", className),
359
+ children
360
+ }, undefined, false, undefined, this)
361
+ }, undefined, false, undefined, this));
362
+ AccordionContent.displayName = AccordionPrimitive.Content.displayName;
363
+ // src/ui/primitives/dropdown-menu.tsx
364
+ import * as React6 from "react";
365
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
366
+ import { Check, ChevronRight, Circle } from "lucide-react";
367
+ import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
368
+ var DropdownMenu = DropdownMenuPrimitive.Root;
369
+ var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
370
+ var DropdownMenuGroup = DropdownMenuPrimitive.Group;
371
+ var DropdownMenuPortal = DropdownMenuPrimitive.Portal;
372
+ var DropdownMenuSub = DropdownMenuPrimitive.Sub;
373
+ var DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
374
+ var DropdownMenuSubTrigger = React6.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxDEV7(DropdownMenuPrimitive.SubTrigger, {
375
+ ref,
376
+ className: cn("flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", inset && "pl-8", className),
377
+ ...props,
378
+ children: [
379
+ children,
380
+ /* @__PURE__ */ jsxDEV7(ChevronRight, {
381
+ className: "ml-auto"
382
+ }, undefined, false, undefined, this)
383
+ ]
384
+ }, undefined, true, undefined, this));
385
+ DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
386
+ var DropdownMenuSubContent = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV7(DropdownMenuPrimitive.SubContent, {
387
+ ref,
388
+ className: cn("z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]", className),
389
+ ...props
390
+ }, undefined, false, undefined, this));
391
+ DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
392
+ var DropdownMenuContent = React6.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsxDEV7(DropdownMenuPrimitive.Portal, {
393
+ children: /* @__PURE__ */ jsxDEV7(DropdownMenuPrimitive.Content, {
394
+ ref,
395
+ sideOffset,
396
+ className: cn("z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md", "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]", className),
397
+ ...props
398
+ }, undefined, false, undefined, this)
399
+ }, undefined, false, undefined, this));
400
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
401
+ var DropdownMenuItem = React6.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsxDEV7(DropdownMenuPrimitive.Item, {
402
+ ref,
403
+ className: cn("relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0", inset && "pl-8", className),
404
+ ...props
405
+ }, undefined, false, undefined, this));
406
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
407
+ var DropdownMenuCheckboxItem = React6.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxDEV7(DropdownMenuPrimitive.CheckboxItem, {
408
+ ref,
409
+ className: cn("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className),
410
+ checked,
411
+ ...props,
412
+ children: [
413
+ /* @__PURE__ */ jsxDEV7("span", {
414
+ className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center",
415
+ children: /* @__PURE__ */ jsxDEV7(DropdownMenuPrimitive.ItemIndicator, {
416
+ children: /* @__PURE__ */ jsxDEV7(Check, {
417
+ className: "h-4 w-4"
418
+ }, undefined, false, undefined, this)
419
+ }, undefined, false, undefined, this)
420
+ }, undefined, false, undefined, this),
421
+ children
422
+ ]
423
+ }, undefined, true, undefined, this));
424
+ DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
425
+ var DropdownMenuRadioItem = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxDEV7(DropdownMenuPrimitive.RadioItem, {
426
+ ref,
427
+ className: cn("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className),
428
+ ...props,
429
+ children: [
430
+ /* @__PURE__ */ jsxDEV7("span", {
431
+ className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center",
432
+ children: /* @__PURE__ */ jsxDEV7(DropdownMenuPrimitive.ItemIndicator, {
433
+ children: /* @__PURE__ */ jsxDEV7(Circle, {
434
+ className: "h-2 w-2 fill-current"
435
+ }, undefined, false, undefined, this)
436
+ }, undefined, false, undefined, this)
437
+ }, undefined, false, undefined, this),
438
+ children
439
+ ]
440
+ }, undefined, true, undefined, this));
441
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
442
+ var DropdownMenuLabel = React6.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsxDEV7(DropdownMenuPrimitive.Label, {
443
+ ref,
444
+ className: cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className),
445
+ ...props
446
+ }, undefined, false, undefined, this));
447
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
448
+ var DropdownMenuSeparator = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV7(DropdownMenuPrimitive.Separator, {
449
+ ref,
450
+ className: cn("-mx-1 my-1 h-px bg-muted", className),
451
+ ...props
452
+ }, undefined, false, undefined, this));
453
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
454
+ var DropdownMenuShortcut = ({ className, ...props }) => {
455
+ return /* @__PURE__ */ jsxDEV7("span", {
456
+ className: cn("ml-auto text-xs tracking-widest opacity-60", className),
457
+ ...props
458
+ }, undefined, false, undefined, this);
459
+ };
460
+ DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
461
+ // src/ui/primitives/hover-card.tsx
462
+ import * as React7 from "react";
463
+ import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
464
+ import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
465
+ var HoverCard = HoverCardPrimitive.Root;
466
+ var HoverCardTrigger = HoverCardPrimitive.Trigger;
467
+ var HoverCardContent = React7.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsxDEV8(HoverCardPrimitive.Content, {
468
+ ref,
469
+ align,
470
+ sideOffset,
471
+ className: cn("z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-hover-card-content-transform-origin]", className),
472
+ ...props
473
+ }, undefined, false, undefined, this));
474
+ HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
475
+ // src/ui/primitives/select.tsx
476
+ import * as React8 from "react";
477
+ import * as SelectPrimitive from "@radix-ui/react-select";
478
+ import { Check as Check2, ChevronDown as ChevronDown2, ChevronUp } from "lucide-react";
479
+ import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
480
+ var Select = SelectPrimitive.Root;
481
+ var SelectGroup = SelectPrimitive.Group;
482
+ var SelectValue = SelectPrimitive.Value;
483
+ var SelectTrigger = React8.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxDEV9(SelectPrimitive.Trigger, {
484
+ ref,
485
+ className: cn("flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1", className),
486
+ ...props,
487
+ children: [
488
+ children,
489
+ /* @__PURE__ */ jsxDEV9(SelectPrimitive.Icon, {
490
+ asChild: true,
491
+ children: /* @__PURE__ */ jsxDEV9(ChevronDown2, {
492
+ className: "h-4 w-4 opacity-50"
493
+ }, undefined, false, undefined, this)
494
+ }, undefined, false, undefined, this)
495
+ ]
496
+ }, undefined, true, undefined, this));
497
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
498
+ var SelectScrollUpButton = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV9(SelectPrimitive.ScrollUpButton, {
499
+ ref,
500
+ className: cn("flex cursor-default items-center justify-center py-1", className),
501
+ ...props,
502
+ children: /* @__PURE__ */ jsxDEV9(ChevronUp, {
503
+ className: "h-4 w-4"
504
+ }, undefined, false, undefined, this)
505
+ }, undefined, false, undefined, this));
506
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
507
+ var SelectScrollDownButton = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV9(SelectPrimitive.ScrollDownButton, {
508
+ ref,
509
+ className: cn("flex cursor-default items-center justify-center py-1", className),
510
+ ...props,
511
+ children: /* @__PURE__ */ jsxDEV9(ChevronDown2, {
512
+ className: "h-4 w-4"
513
+ }, undefined, false, undefined, this)
514
+ }, undefined, false, undefined, this));
515
+ SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
516
+ var SelectContent = React8.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsxDEV9(SelectPrimitive.Portal, {
517
+ children: /* @__PURE__ */ jsxDEV9(SelectPrimitive.Content, {
518
+ ref,
519
+ className: cn("relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]", position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", className),
520
+ position,
521
+ ...props,
522
+ children: [
523
+ /* @__PURE__ */ jsxDEV9(SelectScrollUpButton, {}, undefined, false, undefined, this),
524
+ /* @__PURE__ */ jsxDEV9(SelectPrimitive.Viewport, {
525
+ className: cn("p-1", position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"),
526
+ children
527
+ }, undefined, false, undefined, this),
528
+ /* @__PURE__ */ jsxDEV9(SelectScrollDownButton, {}, undefined, false, undefined, this)
529
+ ]
530
+ }, undefined, true, undefined, this)
531
+ }, undefined, false, undefined, this));
532
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
533
+ var SelectLabel = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV9(SelectPrimitive.Label, {
534
+ ref,
535
+ className: cn("px-2 py-1.5 text-sm font-semibold", className),
536
+ ...props
537
+ }, undefined, false, undefined, this));
538
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
539
+ var SelectItem = React8.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxDEV9(SelectPrimitive.Item, {
540
+ ref,
541
+ className: cn("relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className),
542
+ ...props,
543
+ children: [
544
+ /* @__PURE__ */ jsxDEV9("span", {
545
+ className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center",
546
+ children: /* @__PURE__ */ jsxDEV9(SelectPrimitive.ItemIndicator, {
547
+ children: /* @__PURE__ */ jsxDEV9(Check2, {
548
+ className: "h-4 w-4"
549
+ }, undefined, false, undefined, this)
550
+ }, undefined, false, undefined, this)
551
+ }, undefined, false, undefined, this),
552
+ /* @__PURE__ */ jsxDEV9(SelectPrimitive.ItemText, {
553
+ children
554
+ }, undefined, false, undefined, this)
555
+ ]
556
+ }, undefined, true, undefined, this));
557
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
558
+ var SelectSeparator = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV9(SelectPrimitive.Separator, {
559
+ ref,
560
+ className: cn("-mx-1 my-1 h-px bg-muted", className),
561
+ ...props
562
+ }, undefined, false, undefined, this));
563
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
564
+ // src/ui/primitives/command.tsx
565
+ import * as React9 from "react";
566
+ import { Command as CommandPrimitive } from "cmdk";
567
+ import { Search } from "lucide-react";
568
+ import { jsxDEV as jsxDEV10 } from "react/jsx-dev-runtime";
569
+ var Command = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV10(CommandPrimitive, {
570
+ ref,
571
+ className: cn("flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground", className),
572
+ ...props
573
+ }, undefined, false, undefined, this));
574
+ Command.displayName = CommandPrimitive.displayName;
575
+ var CommandInput = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV10("div", {
576
+ className: "flex items-center border-b px-3",
577
+ "cmdk-input-wrapper": "",
578
+ children: [
579
+ /* @__PURE__ */ jsxDEV10(Search, {
580
+ className: "mr-2 h-4 w-4 shrink-0 opacity-50"
581
+ }, undefined, false, undefined, this),
582
+ /* @__PURE__ */ jsxDEV10(CommandPrimitive.Input, {
583
+ ref,
584
+ className: cn("flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50", className),
585
+ ...props
586
+ }, undefined, false, undefined, this)
587
+ ]
588
+ }, undefined, true, undefined, this));
589
+ CommandInput.displayName = CommandPrimitive.Input.displayName;
590
+ var CommandList = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV10(CommandPrimitive.List, {
591
+ ref,
592
+ className: cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className),
593
+ ...props
594
+ }, undefined, false, undefined, this));
595
+ CommandList.displayName = CommandPrimitive.List.displayName;
596
+ var CommandEmpty = React9.forwardRef((props, ref) => /* @__PURE__ */ jsxDEV10(CommandPrimitive.Empty, {
597
+ ref,
598
+ className: "py-6 text-center text-sm",
599
+ ...props
600
+ }, undefined, false, undefined, this));
601
+ CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
602
+ var CommandGroup = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV10(CommandPrimitive.Group, {
603
+ ref,
604
+ className: cn("overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground", className),
605
+ ...props
606
+ }, undefined, false, undefined, this));
607
+ CommandGroup.displayName = CommandPrimitive.Group.displayName;
608
+ var CommandSeparator = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV10(CommandPrimitive.Separator, {
609
+ ref,
610
+ className: cn("-mx-1 h-px bg-border", className),
611
+ ...props
612
+ }, undefined, false, undefined, this));
613
+ CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
614
+ var CommandItem = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV10(CommandPrimitive.Item, {
615
+ ref,
616
+ className: cn("relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", className),
617
+ ...props
618
+ }, undefined, false, undefined, this));
619
+ CommandItem.displayName = CommandPrimitive.Item.displayName;
620
+ var CommandShortcut = ({ className, ...props }) => {
621
+ return /* @__PURE__ */ jsxDEV10("span", {
622
+ className: cn("ml-auto text-xs tracking-widest text-muted-foreground", className),
623
+ ...props
624
+ }, undefined, false, undefined, this);
625
+ };
626
+ CommandShortcut.displayName = "CommandShortcut";
627
+ // src/ui/primitives/dialog.tsx
628
+ import * as React10 from "react";
629
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
630
+ import { cva as cva4 } from "class-variance-authority";
631
+ import { X } from "lucide-react";
632
+ import { jsxDEV as jsxDEV11 } from "react/jsx-dev-runtime";
633
+ var Dialog = DialogPrimitive.Root;
634
+ var DialogTrigger = DialogPrimitive.Trigger;
635
+ var DialogPortal = DialogPrimitive.Portal;
636
+ var DialogClose = DialogPrimitive.Close;
637
+ var DialogOverlay = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV11(DialogPrimitive.Overlay, {
638
+ ref,
639
+ className: cn("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", className),
640
+ ...props
641
+ }, undefined, false, undefined, this));
642
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
643
+ var dialogContentVariants = cva4("fixed left-[50%] top-[50%] z-50 grid translate-x-[-50%] translate-y-[-50%] gap-4 border shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", {
644
+ variants: {
645
+ variant: {
646
+ default: "w-full max-w-lg bg-background p-6",
647
+ lightbox: "max-w-[90vw] max-h-[90vh] bg-background/95 backdrop-blur-sm p-2"
648
+ }
649
+ },
650
+ defaultVariants: {
651
+ variant: "default"
652
+ }
653
+ });
654
+ var DialogContent = React10.forwardRef(({ className, variant, children, ...props }, ref) => /* @__PURE__ */ jsxDEV11(DialogPortal, {
655
+ children: [
656
+ /* @__PURE__ */ jsxDEV11(DialogOverlay, {}, undefined, false, undefined, this),
657
+ /* @__PURE__ */ jsxDEV11(DialogPrimitive.Content, {
658
+ ref,
659
+ className: cn(dialogContentVariants({ variant }), className),
660
+ ...props,
661
+ children: [
662
+ children,
663
+ /* @__PURE__ */ jsxDEV11(DialogPrimitive.Close, {
664
+ className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",
665
+ children: [
666
+ /* @__PURE__ */ jsxDEV11(X, {
667
+ className: "h-4 w-4"
668
+ }, undefined, false, undefined, this),
669
+ /* @__PURE__ */ jsxDEV11("span", {
670
+ className: "sr-only",
671
+ children: "Close"
672
+ }, undefined, false, undefined, this)
673
+ ]
674
+ }, undefined, true, undefined, this)
675
+ ]
676
+ }, undefined, true, undefined, this)
677
+ ]
678
+ }, undefined, true, undefined, this));
679
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
680
+ var DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsxDEV11("div", {
681
+ className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className),
682
+ ...props
683
+ }, undefined, false, undefined, this);
684
+ DialogHeader.displayName = "DialogHeader";
685
+ var DialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsxDEV11("div", {
686
+ className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className),
687
+ ...props
688
+ }, undefined, false, undefined, this);
689
+ DialogFooter.displayName = "DialogFooter";
690
+ var DialogTitle = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV11(DialogPrimitive.Title, {
691
+ ref,
692
+ className: cn("text-lg font-semibold leading-none tracking-tight", className),
693
+ ...props
694
+ }, undefined, false, undefined, this));
695
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
696
+ var DialogDescription = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxDEV11(DialogPrimitive.Description, {
697
+ ref,
698
+ className: cn("text-sm text-muted-foreground", className),
699
+ ...props
700
+ }, undefined, false, undefined, this));
701
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
702
+ // src/ui/components/message.tsx
703
+ import { cva as cva5 } from "class-variance-authority";
704
+ import { jsxDEV as jsxDEV12 } from "react/jsx-dev-runtime";
705
+ var Message = ({ className, from, ...props }) => /* @__PURE__ */ jsxDEV12("div", {
706
+ className: cn("group flex w-full items-end justify-end gap-2 py-4", from === "user" ? "is-user" : "is-assistant flex-row-reverse justify-end", className),
707
+ ...props
708
+ }, undefined, false, undefined, this);
709
+ var messageContentVariants = cva5("flex flex-col gap-2 overflow-hidden rounded-lg text-sm", {
710
+ variants: {
711
+ variant: {
712
+ contained: [
713
+ "max-w-[80%] px-4 py-3",
714
+ "group-[.is-user]:bg-primary group-[.is-user]:text-primary-foreground",
715
+ "group-[.is-assistant]:bg-secondary group-[.is-assistant]:text-foreground"
716
+ ],
717
+ flat: [
718
+ "group-[.is-user]:max-w-[80%] group-[.is-user]:bg-secondary group-[.is-user]:px-4 group-[.is-user]:py-3 group-[.is-user]:text-foreground",
719
+ "group-[.is-assistant]:text-foreground"
720
+ ]
721
+ }
722
+ },
723
+ defaultVariants: {
724
+ variant: "contained"
725
+ }
726
+ });
727
+ var MessageContent = ({ children, className, variant, ...props }) => /* @__PURE__ */ jsxDEV12("div", {
728
+ className: cn(messageContentVariants({ variant, className })),
729
+ ...props,
730
+ children
731
+ }, undefined, false, undefined, this);
732
+ var MessageAvatar = ({ src, name, className, ...props }) => /* @__PURE__ */ jsxDEV12(Avatar, {
733
+ className: cn("size-8 ring-1 ring-border", className),
734
+ ...props,
735
+ children: [
736
+ /* @__PURE__ */ jsxDEV12(AvatarImage, {
737
+ alt: "",
738
+ className: "mt-0 mb-0",
739
+ src
740
+ }, undefined, false, undefined, this),
741
+ /* @__PURE__ */ jsxDEV12(AvatarFallback, {
742
+ children: name?.slice(0, 2) || "ME"
743
+ }, undefined, false, undefined, this)
744
+ ]
745
+ }, undefined, true, undefined, this);
746
+ // src/ui/components/conversation.tsx
747
+ import { ArrowDownIcon } from "lucide-react";
748
+ import { useCallback } from "react";
749
+ import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
750
+ import { useStickToBottomContext as useStickToBottomContext2 } from "use-stick-to-bottom";
751
+ import { jsxDEV as jsxDEV13, Fragment } from "react/jsx-dev-runtime";
752
+ var Conversation = ({ className, ...props }) => /* @__PURE__ */ jsxDEV13(StickToBottom, {
753
+ className: cn("relative flex-1 overflow-y-auto", className),
754
+ initial: "smooth",
755
+ role: "log",
756
+ ...props
757
+ }, undefined, false, undefined, this);
758
+ var ConversationContent = ({ className, ...props }) => /* @__PURE__ */ jsxDEV13(StickToBottom.Content, {
759
+ className: cn("p-4", className),
760
+ ...props
761
+ }, undefined, false, undefined, this);
762
+ var ConversationEmptyState = ({
763
+ className,
764
+ title = "No messages yet",
765
+ description = "Start a conversation to see messages here",
766
+ icon,
767
+ children,
768
+ ...props
769
+ }) => /* @__PURE__ */ jsxDEV13("div", {
770
+ className: cn("flex size-full flex-col items-center justify-center gap-3 p-8 text-center", className),
771
+ ...props,
772
+ children: children ?? /* @__PURE__ */ jsxDEV13(Fragment, {
773
+ children: [
774
+ icon && /* @__PURE__ */ jsxDEV13("div", {
775
+ className: "text-muted-foreground",
776
+ children: icon
777
+ }, undefined, false, undefined, this),
778
+ /* @__PURE__ */ jsxDEV13("div", {
779
+ className: "space-y-1",
780
+ children: [
781
+ /* @__PURE__ */ jsxDEV13("h3", {
782
+ className: "font-medium text-sm",
783
+ children: title
784
+ }, undefined, false, undefined, this),
785
+ description && /* @__PURE__ */ jsxDEV13("p", {
786
+ className: "text-muted-foreground text-sm",
787
+ children: description
788
+ }, undefined, false, undefined, this)
789
+ ]
790
+ }, undefined, true, undefined, this)
791
+ ]
792
+ }, undefined, true, undefined, this)
793
+ }, undefined, false, undefined, this);
794
+ var ConversationScrollButton = ({ className, ...props }) => {
795
+ const { isAtBottom, scrollToBottom } = useStickToBottomContext();
796
+ const handleScrollToBottom = useCallback(() => {
797
+ scrollToBottom();
798
+ }, [scrollToBottom]);
799
+ return !isAtBottom && /* @__PURE__ */ jsxDEV13(Button, {
800
+ className: cn("absolute bottom-4 left-[50%] translate-x-[-50%] rounded-full", className),
801
+ onClick: handleScrollToBottom,
802
+ size: "icon",
803
+ type: "button",
804
+ variant: "outline",
805
+ ...props,
806
+ children: /* @__PURE__ */ jsxDEV13(ArrowDownIcon, {
807
+ className: "size-4"
808
+ }, undefined, false, undefined, this)
809
+ }, undefined, false, undefined, this);
810
+ };
811
+ // src/ui/components/response.tsx
812
+ import { memo } from "react";
813
+ import { Streamdown } from "streamdown";
814
+ import { jsxDEV as jsxDEV14 } from "react/jsx-dev-runtime";
815
+ var Response = memo(({ className, ...props }) => /* @__PURE__ */ jsxDEV14(Streamdown, {
816
+ className: cn("size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", className),
817
+ ...props
818
+ }, undefined, false, undefined, this), (prevProps, nextProps) => prevProps.children === nextProps.children);
819
+ Response.displayName = "Response";
820
+ // src/ui/components/tool.tsx
821
+ import {
822
+ CheckCircleIcon,
823
+ ChevronDownIcon,
824
+ CircleIcon,
825
+ ClockIcon,
826
+ WrenchIcon,
827
+ XCircleIcon
828
+ } from "lucide-react";
829
+ import { isValidElement } from "react";
830
+
831
+ // src/ui/components/code-block.tsx
832
+ import { CheckIcon, CopyIcon } from "lucide-react";
833
+ import {
834
+ createContext,
835
+ useContext,
836
+ useEffect,
837
+ useRef,
838
+ useState
839
+ } from "react";
840
+ import { jsxDEV as jsxDEV15, Fragment as Fragment2 } from "react/jsx-dev-runtime";
841
+ var CodeBlockContext = createContext({
842
+ code: ""
843
+ });
844
+ async function highlightCode(code, language, showLineNumbers = false) {
845
+ try {
846
+ const shiki = await import("shiki");
847
+ const lineNumberTransformer = showLineNumbers ? [
848
+ {
849
+ name: "line-numbers",
850
+ line(node, line) {
851
+ node.children.unshift({
852
+ type: "element",
853
+ tagName: "span",
854
+ properties: {
855
+ className: ["inline-block", "min-w-10", "mr-4", "text-right", "select-none", "text-muted-foreground"]
856
+ },
857
+ children: [{ type: "text", value: String(line) }]
858
+ });
859
+ }
860
+ }
861
+ ] : [];
862
+ const [light, dark] = await Promise.all([
863
+ shiki.codeToHtml(code, { lang: language, theme: "one-light", transformers: lineNumberTransformer }),
864
+ shiki.codeToHtml(code, { lang: language, theme: "one-dark-pro", transformers: lineNumberTransformer })
865
+ ]);
866
+ return [light, dark];
867
+ } catch {
868
+ return ["", ""];
869
+ }
870
+ }
871
+ var CodeBlock = ({
872
+ code,
873
+ language,
874
+ showLineNumbers = false,
875
+ className,
876
+ children,
877
+ ...props
878
+ }) => {
879
+ const [html, setHtml] = useState("");
880
+ const [darkHtml, setDarkHtml] = useState("");
881
+ const effectIdRef = useRef(0);
882
+ useEffect(() => {
883
+ const id = ++effectIdRef.current;
884
+ highlightCode(code, language, showLineNumbers).then(([light, dark]) => {
885
+ if (id === effectIdRef.current) {
886
+ setHtml(light);
887
+ setDarkHtml(dark);
888
+ }
889
+ });
890
+ }, [code, language, showLineNumbers]);
891
+ const useFallback = !html && !darkHtml;
892
+ return /* @__PURE__ */ jsxDEV15(CodeBlockContext.Provider, {
893
+ value: { code },
894
+ children: /* @__PURE__ */ jsxDEV15("div", {
895
+ className: cn("group relative w-full overflow-hidden rounded-md border bg-background text-foreground", className),
896
+ ...props,
897
+ children: /* @__PURE__ */ jsxDEV15("div", {
898
+ className: "relative",
899
+ children: [
900
+ useFallback ? /* @__PURE__ */ jsxDEV15("pre", {
901
+ className: "m-0 overflow-auto bg-background p-4 text-foreground text-sm",
902
+ children: /* @__PURE__ */ jsxDEV15("code", {
903
+ className: "font-mono text-sm",
904
+ children: code
905
+ }, undefined, false, undefined, this)
906
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV15(Fragment2, {
907
+ children: [
908
+ /* @__PURE__ */ jsxDEV15("div", {
909
+ className: "overflow-hidden dark:hidden [&>pre]:m-0 [&>pre]:bg-background! [&>pre]:p-4 [&>pre]:text-foreground! [&>pre]:text-sm [&_code]:font-mono [&_code]:text-sm",
910
+ dangerouslySetInnerHTML: { __html: html }
911
+ }, undefined, false, undefined, this),
912
+ /* @__PURE__ */ jsxDEV15("div", {
913
+ className: "hidden overflow-hidden dark:block [&>pre]:m-0 [&>pre]:bg-background! [&>pre]:p-4 [&>pre]:text-foreground! [&>pre]:text-sm [&_code]:font-mono [&_code]:text-sm",
914
+ dangerouslySetInnerHTML: { __html: darkHtml }
915
+ }, undefined, false, undefined, this)
916
+ ]
917
+ }, undefined, true, undefined, this),
918
+ children && /* @__PURE__ */ jsxDEV15("div", {
919
+ className: "absolute top-2 right-2 flex items-center gap-2",
920
+ children
921
+ }, undefined, false, undefined, this)
922
+ ]
923
+ }, undefined, true, undefined, this)
924
+ }, undefined, false, undefined, this)
925
+ }, undefined, false, undefined, this);
926
+ };
927
+ var CodeBlockCopyButton = ({
928
+ onCopy,
929
+ onError,
930
+ timeout = 2000,
931
+ children,
932
+ className,
933
+ ...props
934
+ }) => {
935
+ const [isCopied, setIsCopied] = useState(false);
936
+ const { code } = useContext(CodeBlockContext);
937
+ const copyToClipboard = async () => {
938
+ if (typeof window === "undefined" || !navigator?.clipboard?.writeText) {
939
+ onError?.(new Error("Clipboard API not available"));
940
+ return;
941
+ }
942
+ try {
943
+ await navigator.clipboard.writeText(code);
944
+ setIsCopied(true);
945
+ onCopy?.();
946
+ setTimeout(() => setIsCopied(false), timeout);
947
+ } catch (error) {
948
+ onError?.(error);
949
+ }
950
+ };
951
+ const Icon2 = isCopied ? CheckIcon : CopyIcon;
952
+ return /* @__PURE__ */ jsxDEV15(Button, {
953
+ className: cn("shrink-0", className),
954
+ onClick: copyToClipboard,
955
+ size: "icon",
956
+ variant: "ghost",
957
+ ...props,
958
+ children: children ?? /* @__PURE__ */ jsxDEV15(Icon2, {
959
+ size: 14
960
+ }, undefined, false, undefined, this)
961
+ }, undefined, false, undefined, this);
962
+ };
963
+
964
+ // src/ui/components/tool.tsx
965
+ import { jsxDEV as jsxDEV16 } from "react/jsx-dev-runtime";
966
+ var Tool = ({ className, ...props }) => /* @__PURE__ */ jsxDEV16(Collapsible, {
967
+ className: cn("not-prose mb-4 w-full rounded-md border", className),
968
+ ...props
969
+ }, undefined, false, undefined, this);
970
+ var getStatusBadge = (status) => {
971
+ const labels = {
972
+ "input-streaming": "Pending",
973
+ "input-available": "Running",
974
+ "approval-requested": "Awaiting Approval",
975
+ "approval-responded": "Responded",
976
+ "output-available": "Completed",
977
+ "output-error": "Error",
978
+ "output-denied": "Denied"
979
+ };
980
+ const icons = {
981
+ "input-streaming": /* @__PURE__ */ jsxDEV16(CircleIcon, {
982
+ className: "size-4"
983
+ }, undefined, false, undefined, this),
984
+ "input-available": /* @__PURE__ */ jsxDEV16(ClockIcon, {
985
+ className: "size-4 animate-pulse"
986
+ }, undefined, false, undefined, this),
987
+ "approval-requested": /* @__PURE__ */ jsxDEV16(ClockIcon, {
988
+ className: "size-4 text-yellow-600"
989
+ }, undefined, false, undefined, this),
990
+ "approval-responded": /* @__PURE__ */ jsxDEV16(CheckCircleIcon, {
991
+ className: "size-4 text-blue-600"
992
+ }, undefined, false, undefined, this),
993
+ "output-available": /* @__PURE__ */ jsxDEV16(CheckCircleIcon, {
994
+ className: "size-4 text-green-600"
995
+ }, undefined, false, undefined, this),
996
+ "output-error": /* @__PURE__ */ jsxDEV16(XCircleIcon, {
997
+ className: "size-4 text-red-600"
998
+ }, undefined, false, undefined, this),
999
+ "output-denied": /* @__PURE__ */ jsxDEV16(XCircleIcon, {
1000
+ className: "size-4 text-orange-600"
1001
+ }, undefined, false, undefined, this)
1002
+ };
1003
+ return /* @__PURE__ */ jsxDEV16(Badge, {
1004
+ className: "gap-1.5 rounded-full text-xs",
1005
+ variant: "secondary",
1006
+ children: [
1007
+ icons[status],
1008
+ labels[status]
1009
+ ]
1010
+ }, undefined, true, undefined, this);
1011
+ };
1012
+ var ToolHeader = ({ className, title, type, state, ...props }) => /* @__PURE__ */ jsxDEV16(CollapsibleTrigger2, {
1013
+ className: cn("group flex w-full items-center justify-between gap-4 p-3", className),
1014
+ ...props,
1015
+ children: [
1016
+ /* @__PURE__ */ jsxDEV16("div", {
1017
+ className: "flex items-center gap-2",
1018
+ children: [
1019
+ /* @__PURE__ */ jsxDEV16(WrenchIcon, {
1020
+ className: "size-4 text-muted-foreground"
1021
+ }, undefined, false, undefined, this),
1022
+ /* @__PURE__ */ jsxDEV16("span", {
1023
+ className: "font-medium text-sm",
1024
+ children: title ?? type?.split("-").slice(1).join("-") ?? "Tool"
1025
+ }, undefined, false, undefined, this),
1026
+ getStatusBadge(state)
1027
+ ]
1028
+ }, undefined, true, undefined, this),
1029
+ /* @__PURE__ */ jsxDEV16(ChevronDownIcon, {
1030
+ className: "size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180"
1031
+ }, undefined, false, undefined, this)
1032
+ ]
1033
+ }, undefined, true, undefined, this);
1034
+ var ToolContent = ({ className, ...props }) => /* @__PURE__ */ jsxDEV16(CollapsibleContent2, {
1035
+ className: cn("data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-popover-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in", className),
1036
+ ...props
1037
+ }, undefined, false, undefined, this);
1038
+ var ToolInput = ({ className, input, ...props }) => /* @__PURE__ */ jsxDEV16("div", {
1039
+ className: cn("space-y-2 overflow-hidden p-4", className),
1040
+ ...props,
1041
+ children: [
1042
+ /* @__PURE__ */ jsxDEV16("h4", {
1043
+ className: "font-medium text-muted-foreground text-xs uppercase tracking-wide",
1044
+ children: "Parameters"
1045
+ }, undefined, false, undefined, this),
1046
+ /* @__PURE__ */ jsxDEV16("div", {
1047
+ className: "rounded-md bg-muted/50",
1048
+ children: /* @__PURE__ */ jsxDEV16(CodeBlock, {
1049
+ code: JSON.stringify(input, null, 2),
1050
+ language: "json"
1051
+ }, undefined, false, undefined, this)
1052
+ }, undefined, false, undefined, this)
1053
+ ]
1054
+ }, undefined, true, undefined, this);
1055
+ var ToolOutput = ({ className, output, errorText, ...props }) => {
1056
+ if (!(output || errorText)) {
1057
+ return null;
1058
+ }
1059
+ let Output = /* @__PURE__ */ jsxDEV16("div", {
1060
+ children: output
1061
+ }, undefined, false, undefined, this);
1062
+ if (typeof output === "object" && !isValidElement(output)) {
1063
+ Output = /* @__PURE__ */ jsxDEV16(CodeBlock, {
1064
+ code: JSON.stringify(output, null, 2),
1065
+ language: "json"
1066
+ }, undefined, false, undefined, this);
1067
+ } else if (typeof output === "string") {
1068
+ Output = /* @__PURE__ */ jsxDEV16(CodeBlock, {
1069
+ code: output,
1070
+ language: "json"
1071
+ }, undefined, false, undefined, this);
1072
+ }
1073
+ return /* @__PURE__ */ jsxDEV16("div", {
1074
+ className: cn("space-y-2 p-4", className),
1075
+ ...props,
1076
+ children: [
1077
+ /* @__PURE__ */ jsxDEV16("h4", {
1078
+ className: "font-medium text-muted-foreground text-xs uppercase tracking-wide",
1079
+ children: errorText ? "Error" : "Result"
1080
+ }, undefined, false, undefined, this),
1081
+ /* @__PURE__ */ jsxDEV16("div", {
1082
+ className: cn("overflow-x-auto rounded-md text-xs [&_table]:w-full", errorText ? "bg-destructive/10 text-destructive" : "bg-muted/50 text-foreground"),
1083
+ children: [
1084
+ errorText && /* @__PURE__ */ jsxDEV16("div", {
1085
+ children: errorText
1086
+ }, undefined, false, undefined, this),
1087
+ Output
1088
+ ]
1089
+ }, undefined, true, undefined, this)
1090
+ ]
1091
+ }, undefined, true, undefined, this);
1092
+ };
1093
+ // src/ui/components/artifact.tsx
1094
+ import { XIcon } from "lucide-react";
1095
+ import { jsxDEV as jsxDEV17 } from "react/jsx-dev-runtime";
1096
+ var Artifact = ({ className, ...props }) => /* @__PURE__ */ jsxDEV17("div", {
1097
+ className: cn("flex flex-col overflow-hidden rounded-lg border bg-background shadow-sm", className),
1098
+ ...props
1099
+ }, undefined, false, undefined, this);
1100
+ var ArtifactHeader = ({ className, ...props }) => /* @__PURE__ */ jsxDEV17("div", {
1101
+ className: cn("flex items-center justify-between border-b bg-muted/50 px-4 py-3", className),
1102
+ ...props
1103
+ }, undefined, false, undefined, this);
1104
+ var ArtifactClose = ({
1105
+ className,
1106
+ children,
1107
+ size = "sm",
1108
+ variant = "ghost",
1109
+ ...props
1110
+ }) => /* @__PURE__ */ jsxDEV17(Button, {
1111
+ className: cn("size-8 p-0 text-muted-foreground hover:text-foreground", className),
1112
+ size,
1113
+ type: "button",
1114
+ variant,
1115
+ ...props,
1116
+ children: [
1117
+ children ?? /* @__PURE__ */ jsxDEV17(XIcon, {
1118
+ className: "size-4"
1119
+ }, undefined, false, undefined, this),
1120
+ /* @__PURE__ */ jsxDEV17("span", {
1121
+ className: "sr-only",
1122
+ children: "Close"
1123
+ }, undefined, false, undefined, this)
1124
+ ]
1125
+ }, undefined, true, undefined, this);
1126
+ var ArtifactTitle = ({ className, ...props }) => /* @__PURE__ */ jsxDEV17("p", {
1127
+ className: cn("font-medium text-foreground text-sm", className),
1128
+ ...props
1129
+ }, undefined, false, undefined, this);
1130
+ var ArtifactDescription = ({ className, ...props }) => /* @__PURE__ */ jsxDEV17("p", {
1131
+ className: cn("text-muted-foreground text-sm", className),
1132
+ ...props
1133
+ }, undefined, false, undefined, this);
1134
+ var ArtifactActions = ({ className, ...props }) => /* @__PURE__ */ jsxDEV17("div", {
1135
+ className: cn("flex items-center gap-1", className),
1136
+ ...props
1137
+ }, undefined, false, undefined, this);
1138
+ var ArtifactAction = ({
1139
+ tooltip,
1140
+ label,
1141
+ icon: Icon2,
1142
+ children,
1143
+ className,
1144
+ size = "sm",
1145
+ variant = "ghost",
1146
+ ...props
1147
+ }) => {
1148
+ const button = /* @__PURE__ */ jsxDEV17(Button, {
1149
+ className: cn("size-8 p-0 text-muted-foreground hover:text-foreground", className),
1150
+ size,
1151
+ type: "button",
1152
+ variant,
1153
+ ...props,
1154
+ children: [
1155
+ Icon2 ? /* @__PURE__ */ jsxDEV17(Icon2, {
1156
+ className: "size-4"
1157
+ }, undefined, false, undefined, this) : children,
1158
+ /* @__PURE__ */ jsxDEV17("span", {
1159
+ className: "sr-only",
1160
+ children: label || tooltip
1161
+ }, undefined, false, undefined, this)
1162
+ ]
1163
+ }, undefined, true, undefined, this);
1164
+ if (tooltip) {
1165
+ return /* @__PURE__ */ jsxDEV17(TooltipProvider, {
1166
+ children: /* @__PURE__ */ jsxDEV17(Tooltip, {
1167
+ children: [
1168
+ /* @__PURE__ */ jsxDEV17(TooltipTrigger, {
1169
+ asChild: true,
1170
+ children: button
1171
+ }, undefined, false, undefined, this),
1172
+ /* @__PURE__ */ jsxDEV17(TooltipContent, {
1173
+ children: /* @__PURE__ */ jsxDEV17("p", {
1174
+ children: tooltip
1175
+ }, undefined, false, undefined, this)
1176
+ }, undefined, false, undefined, this)
1177
+ ]
1178
+ }, undefined, true, undefined, this)
1179
+ }, undefined, false, undefined, this);
1180
+ }
1181
+ return button;
1182
+ };
1183
+ var ArtifactContent = ({ className, ...props }) => /* @__PURE__ */ jsxDEV17("div", {
1184
+ className: cn("flex-1 overflow-auto p-4", className),
1185
+ ...props
1186
+ }, undefined, false, undefined, this);
1187
+ // src/ui/components/streaming-indicator.tsx
1188
+ import { Bot } from "lucide-react";
1189
+ import { jsxDEV as jsxDEV18 } from "react/jsx-dev-runtime";
1190
+ function StreamingIndicator({ className, icon, avatar, ...props }) {
1191
+ return /* @__PURE__ */ jsxDEV18("div", {
1192
+ className: cn("flex items-start gap-3 px-1", className),
1193
+ ...props,
1194
+ children: [
1195
+ avatar ?? /* @__PURE__ */ jsxDEV18("div", {
1196
+ className: "h-8 w-8 rounded-full bg-primary/10 flex items-center justify-center flex-shrink-0 mt-0.5",
1197
+ children: icon ?? /* @__PURE__ */ jsxDEV18(Bot, {
1198
+ className: "h-4 w-4 text-primary"
1199
+ }, undefined, false, undefined, this)
1200
+ }, undefined, false, undefined, this),
1201
+ /* @__PURE__ */ jsxDEV18("div", {
1202
+ className: "flex items-center gap-1.5 pt-2.5",
1203
+ children: [
1204
+ /* @__PURE__ */ jsxDEV18("span", {
1205
+ className: "h-2 w-2 rounded-full bg-primary/60 animate-pulse"
1206
+ }, undefined, false, undefined, this),
1207
+ /* @__PURE__ */ jsxDEV18("span", {
1208
+ className: "h-2 w-2 rounded-full bg-primary/60 animate-pulse [animation-delay:150ms]"
1209
+ }, undefined, false, undefined, this),
1210
+ /* @__PURE__ */ jsxDEV18("span", {
1211
+ className: "h-2 w-2 rounded-full bg-primary/60 animate-pulse [animation-delay:300ms]"
1212
+ }, undefined, false, undefined, this)
1213
+ ]
1214
+ }, undefined, true, undefined, this)
1215
+ ]
1216
+ }, undefined, true, undefined, this);
1217
+ }
1218
+ // src/ui/components/audio-recorder.tsx
1219
+ import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
1220
+ import { Loader2, Mic, Square } from "lucide-react";
1221
+ import { jsxDEV as jsxDEV19 } from "react/jsx-dev-runtime";
1222
+ function encodeWav(samples, sampleRate) {
1223
+ const numChannels = 1;
1224
+ const bitsPerSample = 16;
1225
+ const byteRate = sampleRate * numChannels * (bitsPerSample / 8);
1226
+ const blockAlign = numChannels * (bitsPerSample / 8);
1227
+ const dataLength = samples.length * (bitsPerSample / 8);
1228
+ const buffer = new ArrayBuffer(44 + dataLength);
1229
+ const view = new DataView(buffer);
1230
+ writeString(view, 0, "RIFF");
1231
+ view.setUint32(4, 36 + dataLength, true);
1232
+ writeString(view, 8, "WAVE");
1233
+ writeString(view, 12, "fmt ");
1234
+ view.setUint32(16, 16, true);
1235
+ view.setUint16(20, 1, true);
1236
+ view.setUint16(22, numChannels, true);
1237
+ view.setUint32(24, sampleRate, true);
1238
+ view.setUint32(28, byteRate, true);
1239
+ view.setUint16(32, blockAlign, true);
1240
+ view.setUint16(34, bitsPerSample, true);
1241
+ writeString(view, 36, "data");
1242
+ view.setUint32(40, dataLength, true);
1243
+ let offset = 44;
1244
+ for (let i = 0;i < samples.length; i++) {
1245
+ const s = Math.max(-1, Math.min(1, samples[i]));
1246
+ view.setInt16(offset, s < 0 ? s * 32768 : s * 32767, true);
1247
+ offset += 2;
1248
+ }
1249
+ return new Blob([buffer], { type: "audio/wav" });
1250
+ }
1251
+ function writeString(view, offset, str) {
1252
+ for (let i = 0;i < str.length; i++) {
1253
+ view.setUint8(offset + i, str.charCodeAt(i));
1254
+ }
1255
+ }
1256
+ function createWorkletUrl() {
1257
+ const code = `
1258
+ class RecorderProcessor extends AudioWorkletProcessor {
1259
+ constructor() {
1260
+ super();
1261
+ this._stopped = false;
1262
+ this.port.onmessage = (e) => {
1263
+ if (e.data === 'stop') this._stopped = true;
1264
+ };
1265
+ }
1266
+ process(inputs) {
1267
+ if (this._stopped) return false;
1268
+ const input = inputs[0];
1269
+ if (input && input[0]) {
1270
+ this.port.postMessage(new Float32Array(input[0]));
1271
+ }
1272
+ return true;
1273
+ }
1274
+ }
1275
+ registerProcessor('recorder-processor', RecorderProcessor);
1276
+ `;
1277
+ const blob = new Blob([code], { type: "application/javascript" });
1278
+ return URL.createObjectURL(blob);
1279
+ }
1280
+ function AudioRecorder({
1281
+ onRecordingComplete,
1282
+ disabled,
1283
+ className,
1284
+ mode = "send",
1285
+ transcriptionEndpoint,
1286
+ transcriptionHeaders,
1287
+ onTranscriptionComplete,
1288
+ transcriptionFieldName = "file",
1289
+ parseTranscriptionResponse,
1290
+ onRequestPermission,
1291
+ labels
1292
+ }) {
1293
+ const [isRecording, setIsRecording] = useState2(false);
1294
+ const [isTranscribing, setIsTranscribing] = useState2(false);
1295
+ const [duration, setDuration] = useState2(0);
1296
+ const [isSupported, setIsSupported] = useState2(true);
1297
+ const streamRef = useRef2(null);
1298
+ const audioContextRef = useRef2(null);
1299
+ const workletNodeRef = useRef2(null);
1300
+ const chunksRef = useRef2([]);
1301
+ const timerRef = useRef2(null);
1302
+ const workletUrlRef = useRef2(null);
1303
+ const onTranscriptionCompleteRef = useRef2(onTranscriptionComplete);
1304
+ onTranscriptionCompleteRef.current = onTranscriptionComplete;
1305
+ useEffect2(() => {
1306
+ if (typeof window === "undefined" || !navigator.mediaDevices?.getUserMedia) {
1307
+ setIsSupported(false);
1308
+ }
1309
+ return () => {
1310
+ if (timerRef.current)
1311
+ clearInterval(timerRef.current);
1312
+ if (workletNodeRef.current) {
1313
+ workletNodeRef.current.port.postMessage("stop");
1314
+ workletNodeRef.current.disconnect();
1315
+ workletNodeRef.current = null;
1316
+ }
1317
+ if (audioContextRef.current) {
1318
+ audioContextRef.current.close();
1319
+ audioContextRef.current = null;
1320
+ }
1321
+ if (streamRef.current) {
1322
+ streamRef.current.getTracks().forEach((track) => track.stop());
1323
+ streamRef.current = null;
1324
+ }
1325
+ if (workletUrlRef.current)
1326
+ URL.revokeObjectURL(workletUrlRef.current);
1327
+ };
1328
+ }, []);
1329
+ const startRecording = useCallback2(async () => {
1330
+ try {
1331
+ if (onRequestPermission) {
1332
+ const granted = await onRequestPermission();
1333
+ if (!granted)
1334
+ return;
1335
+ }
1336
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
1337
+ streamRef.current = stream;
1338
+ const audioContext = new AudioContext;
1339
+ audioContextRef.current = audioContext;
1340
+ const workletUrl = createWorkletUrl();
1341
+ workletUrlRef.current = workletUrl;
1342
+ await audioContext.audioWorklet.addModule(workletUrl);
1343
+ const source = audioContext.createMediaStreamSource(stream);
1344
+ const workletNode = new AudioWorkletNode(audioContext, "recorder-processor");
1345
+ workletNodeRef.current = workletNode;
1346
+ chunksRef.current = [];
1347
+ workletNode.port.onmessage = (e) => {
1348
+ if (e.data instanceof Float32Array) {
1349
+ chunksRef.current.push(e.data);
1350
+ }
1351
+ };
1352
+ source.connect(workletNode);
1353
+ workletNode.connect(audioContext.destination);
1354
+ setIsRecording(true);
1355
+ setDuration(0);
1356
+ timerRef.current = setInterval(() => {
1357
+ setDuration((prev) => prev + 1);
1358
+ }, 1000);
1359
+ } catch {
1360
+ console.error("Failed to start recording");
1361
+ }
1362
+ }, [onRequestPermission]);
1363
+ const stopRecording = useCallback2(async () => {
1364
+ if (workletNodeRef.current) {
1365
+ workletNodeRef.current.port.postMessage("stop");
1366
+ workletNodeRef.current.disconnect();
1367
+ workletNodeRef.current = null;
1368
+ }
1369
+ const audioContext = audioContextRef.current;
1370
+ let wavBlob = null;
1371
+ if (audioContext) {
1372
+ const sampleRate = audioContext.sampleRate;
1373
+ const totalLength = chunksRef.current.reduce((sum, chunk) => sum + chunk.length, 0);
1374
+ const merged = new Float32Array(totalLength);
1375
+ let offset = 0;
1376
+ for (const chunk of chunksRef.current) {
1377
+ merged.set(chunk, offset);
1378
+ offset += chunk.length;
1379
+ }
1380
+ chunksRef.current = [];
1381
+ wavBlob = encodeWav(merged, sampleRate);
1382
+ audioContext.close();
1383
+ audioContextRef.current = null;
1384
+ }
1385
+ if (streamRef.current) {
1386
+ streamRef.current.getTracks().forEach((track) => track.stop());
1387
+ streamRef.current = null;
1388
+ }
1389
+ if (workletUrlRef.current) {
1390
+ URL.revokeObjectURL(workletUrlRef.current);
1391
+ workletUrlRef.current = null;
1392
+ }
1393
+ setIsRecording(false);
1394
+ if (timerRef.current) {
1395
+ clearInterval(timerRef.current);
1396
+ timerRef.current = null;
1397
+ }
1398
+ if (!wavBlob)
1399
+ return;
1400
+ if (mode === "transcribe" && transcriptionEndpoint) {
1401
+ setIsTranscribing(true);
1402
+ const formData = new FormData;
1403
+ formData.append(transcriptionFieldName, wavBlob, "recording.wav");
1404
+ try {
1405
+ const res = await fetch(transcriptionEndpoint, {
1406
+ method: "POST",
1407
+ headers: transcriptionHeaders,
1408
+ credentials: "include",
1409
+ body: formData
1410
+ });
1411
+ const data = await res.json();
1412
+ const text = parseTranscriptionResponse ? parseTranscriptionResponse(data) : data.text || data.transcript || data.transcription || (typeof data === "string" ? data : "");
1413
+ if (text)
1414
+ onTranscriptionCompleteRef.current?.(text);
1415
+ } catch (err) {
1416
+ console.error("Transcription failed:", err);
1417
+ } finally {
1418
+ setIsTranscribing(false);
1419
+ }
1420
+ } else {
1421
+ onRecordingComplete(wavBlob);
1422
+ }
1423
+ }, [onRecordingComplete, mode, transcriptionEndpoint, transcriptionHeaders, transcriptionFieldName, parseTranscriptionResponse]);
1424
+ const resolvedLabels = {
1425
+ recordAudio: labels?.recordAudio ?? "Record audio",
1426
+ stopRecording: labels?.stopRecording ?? "Stop recording",
1427
+ transcribing: labels?.transcribing ?? "Transcribing..."
1428
+ };
1429
+ const formatDuration = (seconds) => {
1430
+ const m = Math.floor(seconds / 60);
1431
+ const s = seconds % 60;
1432
+ return `${m}:${s.toString().padStart(2, "0")}`;
1433
+ };
1434
+ if (!isSupported)
1435
+ return null;
1436
+ return /* @__PURE__ */ jsxDEV19("div", {
1437
+ className: cn("flex items-center gap-1", className),
1438
+ children: [
1439
+ isRecording && /* @__PURE__ */ jsxDEV19("span", {
1440
+ className: "text-xs text-destructive font-mono animate-pulse",
1441
+ children: formatDuration(duration)
1442
+ }, undefined, false, undefined, this),
1443
+ isTranscribing ? /* @__PURE__ */ jsxDEV19("span", {
1444
+ className: "flex items-center gap-1.5 text-xs text-muted-foreground",
1445
+ children: [
1446
+ /* @__PURE__ */ jsxDEV19(Loader2, {
1447
+ className: "size-3.5 animate-spin"
1448
+ }, undefined, false, undefined, this),
1449
+ resolvedLabels.transcribing
1450
+ ]
1451
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV19(Button, {
1452
+ type: "button",
1453
+ variant: "ghost",
1454
+ size: "icon",
1455
+ className: cn("h-8 w-8", isRecording && "text-destructive hover:text-destructive"),
1456
+ disabled,
1457
+ onClick: isRecording ? stopRecording : startRecording,
1458
+ title: isRecording ? resolvedLabels.stopRecording : resolvedLabels.recordAudio,
1459
+ children: isRecording ? /* @__PURE__ */ jsxDEV19(Square, {
1460
+ className: "size-4 fill-current"
1461
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV19(Mic, {
1462
+ className: "size-4"
1463
+ }, undefined, false, undefined, this)
1464
+ }, undefined, false, undefined, this)
1465
+ ]
1466
+ }, undefined, true, undefined, this);
1467
+ }
1468
+ // src/ui/components/smart-timestamp.tsx
1469
+ import { jsxDEV as jsxDEV20 } from "react/jsx-dev-runtime";
1470
+ function SmartTimestamp({ date, formatShort, className }) {
1471
+ const shortText = formatShort ? formatShort(date) : formatSmartTimestamp(date);
1472
+ const fullText = formatFullTimestamp(date);
1473
+ return /* @__PURE__ */ jsxDEV20(TooltipProvider, {
1474
+ children: /* @__PURE__ */ jsxDEV20(Tooltip, {
1475
+ children: [
1476
+ /* @__PURE__ */ jsxDEV20(TooltipTrigger, {
1477
+ asChild: true,
1478
+ children: /* @__PURE__ */ jsxDEV20("span", {
1479
+ className,
1480
+ children: shortText
1481
+ }, undefined, false, undefined, this)
1482
+ }, undefined, false, undefined, this),
1483
+ /* @__PURE__ */ jsxDEV20(TooltipContent, {
1484
+ children: /* @__PURE__ */ jsxDEV20("p", {
1485
+ children: fullText
1486
+ }, undefined, false, undefined, this)
1487
+ }, undefined, false, undefined, this)
1488
+ ]
1489
+ }, undefined, true, undefined, this)
1490
+ }, undefined, false, undefined, this);
1491
+ }
1492
+ // src/ui/components/file-preview-card.tsx
1493
+ import { FileIcon, Search as Search2 } from "lucide-react";
1494
+ import { jsxDEV as jsxDEV21 } from "react/jsx-dev-runtime";
1495
+ function ExtBadge({ ext }) {
1496
+ if (!ext)
1497
+ return null;
1498
+ return /* @__PURE__ */ jsxDEV21("span", {
1499
+ className: "absolute bottom-1.5 left-1.5 rounded px-1 py-0.5 text-[9px] font-semibold uppercase leading-none bg-background/80 text-muted-foreground border border-border/50 backdrop-blur-sm",
1500
+ children: ext
1501
+ }, undefined, false, undefined, this);
1502
+ }
1503
+ function FilePreviewCard({ file, onClick, className }) {
1504
+ const previewType = getFilePreviewType(file.type);
1505
+ const isClickable = !!onClick;
1506
+ const ext = getFileExtension(file.name, file.type);
1507
+ const cardBase = cn("group relative flex flex-col overflow-hidden rounded-xl border border-border bg-muted/20 w-28 h-28", isClickable && "cursor-pointer hover:border-foreground/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 transition-colors", className);
1508
+ if (previewType === "image" && file.url) {
1509
+ return /* @__PURE__ */ jsxDEV21("button", {
1510
+ type: "button",
1511
+ onClick,
1512
+ disabled: !isClickable,
1513
+ className: cardBase,
1514
+ children: [
1515
+ /* @__PURE__ */ jsxDEV21("img", {
1516
+ src: file.url,
1517
+ alt: file.name,
1518
+ className: "w-full h-full object-cover"
1519
+ }, undefined, false, undefined, this),
1520
+ /* @__PURE__ */ jsxDEV21(ExtBadge, {
1521
+ ext
1522
+ }, undefined, false, undefined, this),
1523
+ isClickable && /* @__PURE__ */ jsxDEV21("div", {
1524
+ className: "absolute inset-0 flex items-center justify-center bg-black/0 group-hover:bg-black/30 transition-colors",
1525
+ children: /* @__PURE__ */ jsxDEV21(Search2, {
1526
+ className: "h-5 w-5 text-white opacity-0 group-hover:opacity-100 transition-opacity"
1527
+ }, undefined, false, undefined, this)
1528
+ }, undefined, false, undefined, this)
1529
+ ]
1530
+ }, undefined, true, undefined, this);
1531
+ }
1532
+ if (previewType === "pdf" && file.url) {
1533
+ return /* @__PURE__ */ jsxDEV21("button", {
1534
+ type: "button",
1535
+ onClick,
1536
+ disabled: !isClickable,
1537
+ className: cardBase,
1538
+ children: [
1539
+ /* @__PURE__ */ jsxDEV21("div", {
1540
+ className: "w-full h-full overflow-hidden pointer-events-none",
1541
+ children: /* @__PURE__ */ jsxDEV21("object", {
1542
+ data: `${file.url}#page=1&view=FitH`,
1543
+ type: "application/pdf",
1544
+ className: "w-[200%] h-[200%] origin-top-left scale-50",
1545
+ "aria-label": file.name,
1546
+ children: /* @__PURE__ */ jsxDEV21("div", {
1547
+ className: "flex items-center justify-center w-full h-full",
1548
+ children: /* @__PURE__ */ jsxDEV21(FileIcon, {
1549
+ className: "h-8 w-8 text-muted-foreground/40"
1550
+ }, undefined, false, undefined, this)
1551
+ }, undefined, false, undefined, this)
1552
+ }, undefined, false, undefined, this)
1553
+ }, undefined, false, undefined, this),
1554
+ /* @__PURE__ */ jsxDEV21(ExtBadge, {
1555
+ ext
1556
+ }, undefined, false, undefined, this),
1557
+ isClickable && /* @__PURE__ */ jsxDEV21("div", {
1558
+ className: "absolute inset-0 flex items-center justify-center bg-black/0 group-hover:bg-black/10 transition-colors",
1559
+ children: /* @__PURE__ */ jsxDEV21(Search2, {
1560
+ className: "h-5 w-5 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity"
1561
+ }, undefined, false, undefined, this)
1562
+ }, undefined, false, undefined, this)
1563
+ ]
1564
+ }, undefined, true, undefined, this);
1565
+ }
1566
+ return /* @__PURE__ */ jsxDEV21("button", {
1567
+ type: "button",
1568
+ onClick,
1569
+ disabled: !isClickable,
1570
+ className: cardBase,
1571
+ children: [
1572
+ /* @__PURE__ */ jsxDEV21("div", {
1573
+ className: "flex-1 flex items-center justify-center",
1574
+ children: /* @__PURE__ */ jsxDEV21(FileIcon, {
1575
+ className: "h-8 w-8 text-muted-foreground/40"
1576
+ }, undefined, false, undefined, this)
1577
+ }, undefined, false, undefined, this),
1578
+ /* @__PURE__ */ jsxDEV21("div", {
1579
+ className: "w-full text-center min-w-0 px-2 pb-2 space-y-0.5",
1580
+ children: [
1581
+ /* @__PURE__ */ jsxDEV21("p", {
1582
+ className: "text-[10px] text-foreground truncate leading-tight",
1583
+ title: file.name,
1584
+ children: file.name
1585
+ }, undefined, false, undefined, this),
1586
+ file.size != null && file.size > 0 && /* @__PURE__ */ jsxDEV21("p", {
1587
+ className: "text-[9px] text-muted-foreground leading-tight",
1588
+ children: formatFileSize(file.size)
1589
+ }, undefined, false, undefined, this)
1590
+ ]
1591
+ }, undefined, true, undefined, this),
1592
+ /* @__PURE__ */ jsxDEV21(ExtBadge, {
1593
+ ext
1594
+ }, undefined, false, undefined, this)
1595
+ ]
1596
+ }, undefined, true, undefined, this);
1597
+ }
1598
+ // src/ui/components/file-preview-modal.tsx
1599
+ import { Download, FileIcon as FileIcon2 } from "lucide-react";
1600
+ import { jsxDEV as jsxDEV22 } from "react/jsx-dev-runtime";
1601
+ function FilePreviewModal({ open, onOpenChange, file }) {
1602
+ if (!file)
1603
+ return null;
1604
+ const previewType = getFilePreviewType(file.type);
1605
+ const canPreview = isPreviewable(file.type) && !!file.url;
1606
+ return /* @__PURE__ */ jsxDEV22(Dialog, {
1607
+ open,
1608
+ onOpenChange,
1609
+ children: previewType === "image" && file.url ? /* @__PURE__ */ jsxDEV22(DialogContent, {
1610
+ variant: "lightbox",
1611
+ "aria-describedby": undefined,
1612
+ children: [
1613
+ /* @__PURE__ */ jsxDEV22(DialogTitle, {
1614
+ className: "sr-only",
1615
+ children: file.name
1616
+ }, undefined, false, undefined, this),
1617
+ /* @__PURE__ */ jsxDEV22("img", {
1618
+ src: file.url,
1619
+ alt: file.name,
1620
+ className: "max-h-[85vh] max-w-full object-contain rounded-md"
1621
+ }, undefined, false, undefined, this)
1622
+ ]
1623
+ }, undefined, true, undefined, this) : previewType === "pdf" && file.url ? /* @__PURE__ */ jsxDEV22(DialogContent, {
1624
+ variant: "lightbox",
1625
+ className: "w-[80vw] h-[85vh]",
1626
+ "aria-describedby": undefined,
1627
+ children: [
1628
+ /* @__PURE__ */ jsxDEV22(DialogTitle, {
1629
+ className: "sr-only",
1630
+ children: file.name
1631
+ }, undefined, false, undefined, this),
1632
+ /* @__PURE__ */ jsxDEV22("object", {
1633
+ data: file.url,
1634
+ type: "application/pdf",
1635
+ className: "w-full h-full rounded-md",
1636
+ children: /* @__PURE__ */ jsxDEV22("div", {
1637
+ className: "flex flex-col items-center justify-center h-full gap-3 text-muted-foreground",
1638
+ children: [
1639
+ /* @__PURE__ */ jsxDEV22("p", {
1640
+ className: "text-sm",
1641
+ children: "Unable to display PDF"
1642
+ }, undefined, false, undefined, this),
1643
+ /* @__PURE__ */ jsxDEV22("a", {
1644
+ href: file.url,
1645
+ target: "_blank",
1646
+ rel: "noopener noreferrer",
1647
+ className: "inline-flex items-center gap-1.5 text-sm text-primary hover:underline",
1648
+ children: [
1649
+ /* @__PURE__ */ jsxDEV22(Download, {
1650
+ className: "h-4 w-4"
1651
+ }, undefined, false, undefined, this),
1652
+ "Download ",
1653
+ file.name
1654
+ ]
1655
+ }, undefined, true, undefined, this)
1656
+ ]
1657
+ }, undefined, true, undefined, this)
1658
+ }, undefined, false, undefined, this)
1659
+ ]
1660
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV22(DialogContent, {
1661
+ children: [
1662
+ /* @__PURE__ */ jsxDEV22(DialogHeader, {
1663
+ children: [
1664
+ /* @__PURE__ */ jsxDEV22(DialogTitle, {
1665
+ className: "flex items-center gap-2",
1666
+ children: [
1667
+ /* @__PURE__ */ jsxDEV22(FileIcon2, {
1668
+ className: "h-5 w-5 text-muted-foreground"
1669
+ }, undefined, false, undefined, this),
1670
+ file.name
1671
+ ]
1672
+ }, undefined, true, undefined, this),
1673
+ /* @__PURE__ */ jsxDEV22(DialogDescription, {
1674
+ children: [
1675
+ file.size != null && file.size > 0 && /* @__PURE__ */ jsxDEV22("span", {
1676
+ children: formatFileSize(file.size)
1677
+ }, undefined, false, undefined, this),
1678
+ !canPreview && /* @__PURE__ */ jsxDEV22("span", {
1679
+ children: " · Preview not available for this file type"
1680
+ }, undefined, false, undefined, this)
1681
+ ]
1682
+ }, undefined, true, undefined, this)
1683
+ ]
1684
+ }, undefined, true, undefined, this),
1685
+ /* @__PURE__ */ jsxDEV22("div", {
1686
+ className: "flex flex-col items-center justify-center py-8 text-muted-foreground gap-3",
1687
+ children: [
1688
+ /* @__PURE__ */ jsxDEV22(FileIcon2, {
1689
+ className: "h-12 w-12"
1690
+ }, undefined, false, undefined, this),
1691
+ /* @__PURE__ */ jsxDEV22("p", {
1692
+ className: "text-sm",
1693
+ children: "Preview not available"
1694
+ }, undefined, false, undefined, this),
1695
+ file.url && /^https?:\/\//i.test(file.url) && /* @__PURE__ */ jsxDEV22("a", {
1696
+ href: file.url,
1697
+ target: "_blank",
1698
+ rel: "noopener noreferrer",
1699
+ className: "inline-flex items-center gap-1.5 text-sm text-primary hover:underline",
1700
+ children: [
1701
+ /* @__PURE__ */ jsxDEV22(Download, {
1702
+ className: "h-4 w-4"
1703
+ }, undefined, false, undefined, this),
1704
+ "Download file"
1705
+ ]
1706
+ }, undefined, true, undefined, this)
1707
+ ]
1708
+ }, undefined, true, undefined, this)
1709
+ ]
1710
+ }, undefined, true, undefined, this)
1711
+ }, undefined, false, undefined, this);
1712
+ }
1713
+ // src/ui/components/image-lightbox.tsx
1714
+ import { useState as useState3, useEffect as useEffect3, useCallback as useCallback3 } from "react";
1715
+ import { ChevronLeft, ChevronRight as ChevronRight2 } from "lucide-react";
1716
+ import { jsxDEV as jsxDEV23, Fragment as Fragment3 } from "react/jsx-dev-runtime";
1717
+ function ImageLightbox({ open, onOpenChange, images, initialIndex = 0 }) {
1718
+ const [currentIndex, setCurrentIndex] = useState3(initialIndex);
1719
+ const hasMultiple = images.length > 1;
1720
+ useEffect3(() => {
1721
+ if (open)
1722
+ setCurrentIndex(initialIndex);
1723
+ }, [open, initialIndex]);
1724
+ const goNext = useCallback3(() => {
1725
+ setCurrentIndex((i) => (i + 1) % images.length);
1726
+ }, [images.length]);
1727
+ const goPrev = useCallback3(() => {
1728
+ setCurrentIndex((i) => (i - 1 + images.length) % images.length);
1729
+ }, [images.length]);
1730
+ useEffect3(() => {
1731
+ if (!open || !hasMultiple)
1732
+ return;
1733
+ const handler = (e) => {
1734
+ if (e.key === "ArrowRight")
1735
+ goNext();
1736
+ if (e.key === "ArrowLeft")
1737
+ goPrev();
1738
+ };
1739
+ window.addEventListener("keydown", handler);
1740
+ return () => window.removeEventListener("keydown", handler);
1741
+ }, [open, hasMultiple, goNext, goPrev]);
1742
+ if (images.length === 0)
1743
+ return null;
1744
+ const current = images[currentIndex];
1745
+ if (!current)
1746
+ return null;
1747
+ return /* @__PURE__ */ jsxDEV23(Dialog, {
1748
+ open,
1749
+ onOpenChange,
1750
+ children: /* @__PURE__ */ jsxDEV23(DialogContent, {
1751
+ variant: "lightbox",
1752
+ "aria-describedby": undefined,
1753
+ children: [
1754
+ /* @__PURE__ */ jsxDEV23(DialogTitle, {
1755
+ className: "sr-only",
1756
+ children: current.alt || `Image ${currentIndex + 1} of ${images.length}`
1757
+ }, undefined, false, undefined, this),
1758
+ /* @__PURE__ */ jsxDEV23("div", {
1759
+ className: "relative flex items-center justify-center",
1760
+ children: [
1761
+ /* @__PURE__ */ jsxDEV23("img", {
1762
+ src: current.url,
1763
+ alt: current.alt || "Image preview",
1764
+ className: "max-h-[85vh] max-w-full object-contain rounded-md"
1765
+ }, undefined, false, undefined, this),
1766
+ hasMultiple && /* @__PURE__ */ jsxDEV23(Fragment3, {
1767
+ children: [
1768
+ /* @__PURE__ */ jsxDEV23("button", {
1769
+ type: "button",
1770
+ onClick: goPrev,
1771
+ className: cn("absolute left-2 top-1/2 -translate-y-1/2 rounded-full bg-black/50 p-2 text-white", "hover:bg-black/70 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring transition-colors"),
1772
+ children: [
1773
+ /* @__PURE__ */ jsxDEV23(ChevronLeft, {
1774
+ className: "h-5 w-5"
1775
+ }, undefined, false, undefined, this),
1776
+ /* @__PURE__ */ jsxDEV23("span", {
1777
+ className: "sr-only",
1778
+ children: "Previous image"
1779
+ }, undefined, false, undefined, this)
1780
+ ]
1781
+ }, undefined, true, undefined, this),
1782
+ /* @__PURE__ */ jsxDEV23("button", {
1783
+ type: "button",
1784
+ onClick: goNext,
1785
+ className: cn("absolute right-2 top-1/2 -translate-y-1/2 rounded-full bg-black/50 p-2 text-white", "hover:bg-black/70 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring transition-colors"),
1786
+ children: [
1787
+ /* @__PURE__ */ jsxDEV23(ChevronRight2, {
1788
+ className: "h-5 w-5"
1789
+ }, undefined, false, undefined, this),
1790
+ /* @__PURE__ */ jsxDEV23("span", {
1791
+ className: "sr-only",
1792
+ children: "Next image"
1793
+ }, undefined, false, undefined, this)
1794
+ ]
1795
+ }, undefined, true, undefined, this),
1796
+ /* @__PURE__ */ jsxDEV23("div", {
1797
+ className: "absolute bottom-2 left-1/2 -translate-x-1/2 rounded-full bg-black/50 px-3 py-1 text-xs text-white",
1798
+ children: [
1799
+ currentIndex + 1,
1800
+ " / ",
1801
+ images.length
1802
+ ]
1803
+ }, undefined, true, undefined, this)
1804
+ ]
1805
+ }, undefined, true, undefined, this)
1806
+ ]
1807
+ }, undefined, true, undefined, this)
1808
+ ]
1809
+ }, undefined, true, undefined, this)
1810
+ }, undefined, false, undefined, this);
1811
+ }
1812
+ // src/ui/components/prompt-input/context.ts
1813
+ import { createContext as createContext2, useContext as useContext2 } from "react";
1814
+ var PromptInputController = createContext2(null);
1815
+ var ProviderAttachmentsContext = createContext2(null);
1816
+ var LocalAttachmentsContext = createContext2(null);
1817
+ var usePromptInputController = () => {
1818
+ const ctx = useContext2(PromptInputController);
1819
+ if (!ctx) {
1820
+ throw new Error("Wrap your component inside <PromptInputProvider> to use usePromptInputController().");
1821
+ }
1822
+ return ctx;
1823
+ };
1824
+ var useOptionalPromptInputController = () => useContext2(PromptInputController);
1825
+ var useProviderAttachments = () => {
1826
+ const ctx = useContext2(ProviderAttachmentsContext);
1827
+ if (!ctx) {
1828
+ throw new Error("Wrap your component inside <PromptInputProvider> to use useProviderAttachments().");
1829
+ }
1830
+ return ctx;
1831
+ };
1832
+ var useOptionalProviderAttachments = () => useContext2(ProviderAttachmentsContext);
1833
+ var usePromptInputAttachments = () => {
1834
+ const provider = useOptionalProviderAttachments();
1835
+ const local = useContext2(LocalAttachmentsContext);
1836
+ const context = provider ?? local;
1837
+ if (!context) {
1838
+ throw new Error("usePromptInputAttachments must be used within a PromptInput or PromptInputProvider");
1839
+ }
1840
+ return context;
1841
+ };
1842
+ var DropZoneContext = createContext2({ isDraggingOver: false });
1843
+ var usePromptInputDropZone = () => useContext2(DropZoneContext);
1844
+ // src/ui/components/prompt-input/provider.tsx
1845
+ import { useCallback as useCallback4, useMemo, useRef as useRef3, useState as useState4 } from "react";
1846
+ import { jsxDEV as jsxDEV24 } from "react/jsx-dev-runtime";
1847
+ function generateId() {
1848
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
1849
+ return crypto.randomUUID();
1850
+ }
1851
+ return Math.random().toString(36).slice(2) + Date.now().toString(36);
1852
+ }
1853
+ function PromptInputProvider({ initialInput: initialTextInput = "", children }) {
1854
+ const [textInput, setTextInput] = useState4(initialTextInput);
1855
+ const clearInput = useCallback4(() => setTextInput(""), []);
1856
+ const [fileItems, setFileItems] = useState4([]);
1857
+ const fileInputRef = useRef3(null);
1858
+ const openRef = useRef3(() => {});
1859
+ const add = useCallback4((files) => {
1860
+ const incoming = Array.from(files);
1861
+ if (incoming.length === 0)
1862
+ return;
1863
+ setFileItems((prev) => prev.concat(incoming.map((file) => ({
1864
+ id: generateId(),
1865
+ type: "file",
1866
+ url: URL.createObjectURL(file),
1867
+ mediaType: file.type,
1868
+ filename: file.name
1869
+ }))));
1870
+ }, []);
1871
+ const remove = useCallback4((id) => {
1872
+ setFileItems((prev) => {
1873
+ const found = prev.find((f) => f.id === id);
1874
+ if (found?.url)
1875
+ URL.revokeObjectURL(found.url);
1876
+ return prev.filter((f) => f.id !== id);
1877
+ });
1878
+ }, []);
1879
+ const clear = useCallback4(() => {
1880
+ setFileItems((prev) => {
1881
+ for (const f of prev)
1882
+ if (f.url)
1883
+ URL.revokeObjectURL(f.url);
1884
+ return [];
1885
+ });
1886
+ }, []);
1887
+ const openFileDialog = useCallback4(() => {
1888
+ openRef.current?.();
1889
+ }, []);
1890
+ const attachments = useMemo(() => ({
1891
+ files: fileItems,
1892
+ add,
1893
+ remove,
1894
+ clear,
1895
+ openFileDialog,
1896
+ fileInputRef
1897
+ }), [fileItems, add, remove, clear, openFileDialog]);
1898
+ const __registerFileInput = useCallback4((ref, open) => {
1899
+ fileInputRef.current = ref.current;
1900
+ openRef.current = open;
1901
+ }, []);
1902
+ const controller = useMemo(() => ({
1903
+ textInput: { value: textInput, setInput: setTextInput, clear: clearInput },
1904
+ attachments,
1905
+ __registerFileInput
1906
+ }), [textInput, clearInput, attachments, __registerFileInput]);
1907
+ return /* @__PURE__ */ jsxDEV24(PromptInputController.Provider, {
1908
+ value: controller,
1909
+ children: /* @__PURE__ */ jsxDEV24(ProviderAttachmentsContext.Provider, {
1910
+ value: attachments,
1911
+ children
1912
+ }, undefined, false, undefined, this)
1913
+ }, undefined, false, undefined, this);
1914
+ }
1915
+ // src/ui/components/prompt-input/prompt-input.tsx
1916
+ import { useCallback as useCallback5, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4, useState as useState5 } from "react";
1917
+ import { jsxDEV as jsxDEV25 } from "react/jsx-dev-runtime";
1918
+ function generateId2() {
1919
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
1920
+ return crypto.randomUUID();
1921
+ }
1922
+ return Math.random().toString(36).slice(2) + Date.now().toString(36);
1923
+ }
1924
+ var PromptInput = ({
1925
+ className,
1926
+ accept,
1927
+ multiple,
1928
+ globalDrop,
1929
+ syncHiddenInput,
1930
+ maxFiles,
1931
+ maxFileSize,
1932
+ dragListenerTarget,
1933
+ onError,
1934
+ onSubmit,
1935
+ children,
1936
+ ...props
1937
+ }) => {
1938
+ const controller = useOptionalPromptInputController();
1939
+ const usingProvider = !!controller;
1940
+ const inputRef = useRef4(null);
1941
+ const formRef = useRef4(null);
1942
+ const [items, setItems] = useState5([]);
1943
+ const files = usingProvider ? controller.attachments.files : items;
1944
+ const [isDraggingOver, setIsDraggingOver] = useState5(false);
1945
+ const dragCounter = useRef4(0);
1946
+ const openFileDialogLocal = useCallback5(() => {
1947
+ inputRef.current?.click();
1948
+ }, []);
1949
+ const matchesAccept = useCallback5((f) => {
1950
+ if (!accept || accept.trim() === "")
1951
+ return true;
1952
+ const patterns = accept.split(",").map((p) => p.trim()).filter(Boolean);
1953
+ for (const pattern of patterns) {
1954
+ if (pattern.endsWith("/*")) {
1955
+ const prefix = pattern.slice(0, -1);
1956
+ if (f.type.startsWith(prefix))
1957
+ return true;
1958
+ } else if (pattern.startsWith(".")) {
1959
+ const ext = f.name.toLowerCase().split(".").pop();
1960
+ if (ext && `.${ext}` === pattern.toLowerCase())
1961
+ return true;
1962
+ } else if (f.type === pattern) {
1963
+ return true;
1964
+ }
1965
+ }
1966
+ return false;
1967
+ }, [accept]);
1968
+ const addLocal = useCallback5((fileList) => {
1969
+ const incoming = Array.from(fileList);
1970
+ const accepted = incoming.filter((f) => matchesAccept(f));
1971
+ if (incoming.length && accepted.length === 0) {
1972
+ onError?.({ code: "accept", message: "No files match the accepted types." });
1973
+ return;
1974
+ }
1975
+ const withinSize = (f) => maxFileSize ? f.size <= maxFileSize : true;
1976
+ const sized = accepted.filter(withinSize);
1977
+ if (accepted.length > 0 && sized.length === 0) {
1978
+ onError?.({ code: "max_file_size", message: "All files exceed the maximum size." });
1979
+ return;
1980
+ }
1981
+ setItems((prev) => {
1982
+ const capacity = typeof maxFiles === "number" ? Math.max(0, maxFiles - prev.length) : undefined;
1983
+ const capped = typeof capacity === "number" ? sized.slice(0, capacity) : sized;
1984
+ if (typeof capacity === "number" && sized.length > capacity) {
1985
+ onError?.({ code: "max_files", message: "Too many files. Some were not added." });
1986
+ }
1987
+ const next = [];
1988
+ for (const file of capped) {
1989
+ next.push({
1990
+ id: generateId2(),
1991
+ type: "file",
1992
+ url: URL.createObjectURL(file),
1993
+ mediaType: file.type,
1994
+ filename: file.name
1995
+ });
1996
+ }
1997
+ return prev.concat(next);
1998
+ });
1999
+ }, [matchesAccept, maxFiles, maxFileSize, onError]);
2000
+ const add = usingProvider ? (fileList) => controller.attachments.add(fileList) : addLocal;
2001
+ const remove = usingProvider ? (id) => controller.attachments.remove(id) : (id) => setItems((prev) => {
2002
+ const found = prev.find((file) => file.id === id);
2003
+ if (found?.url)
2004
+ URL.revokeObjectURL(found.url);
2005
+ return prev.filter((file) => file.id !== id);
2006
+ });
2007
+ const clear = usingProvider ? () => controller.attachments.clear() : () => setItems((prev) => {
2008
+ for (const file of prev)
2009
+ if (file.url)
2010
+ URL.revokeObjectURL(file.url);
2011
+ return [];
2012
+ });
2013
+ const openFileDialog = usingProvider ? () => controller.attachments.openFileDialog() : openFileDialogLocal;
2014
+ useEffect4(() => {
2015
+ if (!usingProvider)
2016
+ return;
2017
+ controller.__registerFileInput(inputRef, () => inputRef.current?.click());
2018
+ }, [usingProvider, controller]);
2019
+ useEffect4(() => {
2020
+ if (syncHiddenInput && inputRef.current && files.length === 0) {
2021
+ inputRef.current.value = "";
2022
+ }
2023
+ }, [files, syncHiddenInput]);
2024
+ useEffect4(() => {
2025
+ if (globalDrop)
2026
+ return;
2027
+ const form = formRef.current;
2028
+ if (!form)
2029
+ return;
2030
+ const onDragOver = (e) => {
2031
+ if (e.dataTransfer?.types?.includes("Files"))
2032
+ e.preventDefault();
2033
+ };
2034
+ const onDragEnter = (e) => {
2035
+ if (e.dataTransfer?.types?.includes("Files")) {
2036
+ e.preventDefault();
2037
+ dragCounter.current++;
2038
+ if (dragCounter.current === 1)
2039
+ setIsDraggingOver(true);
2040
+ }
2041
+ };
2042
+ const onDragLeave = (_e) => {
2043
+ dragCounter.current--;
2044
+ if (dragCounter.current === 0)
2045
+ setIsDraggingOver(false);
2046
+ };
2047
+ const onDrop = (e) => {
2048
+ if (e.dataTransfer?.types?.includes("Files"))
2049
+ e.preventDefault();
2050
+ dragCounter.current = 0;
2051
+ setIsDraggingOver(false);
2052
+ if (e.dataTransfer?.files && e.dataTransfer.files.length > 0)
2053
+ add(e.dataTransfer.files);
2054
+ };
2055
+ form.addEventListener("dragover", onDragOver);
2056
+ form.addEventListener("dragenter", onDragEnter);
2057
+ form.addEventListener("dragleave", onDragLeave);
2058
+ form.addEventListener("drop", onDrop);
2059
+ return () => {
2060
+ form.removeEventListener("dragover", onDragOver);
2061
+ form.removeEventListener("dragenter", onDragEnter);
2062
+ form.removeEventListener("dragleave", onDragLeave);
2063
+ form.removeEventListener("drop", onDrop);
2064
+ };
2065
+ }, [add, globalDrop]);
2066
+ useEffect4(() => {
2067
+ if (!globalDrop)
2068
+ return;
2069
+ const target = dragListenerTarget?.current ?? document;
2070
+ const onDragOver = (e) => {
2071
+ if (e.dataTransfer?.types?.includes("Files"))
2072
+ e.preventDefault();
2073
+ };
2074
+ const onDragEnter = (e) => {
2075
+ if (e.dataTransfer?.types?.includes("Files")) {
2076
+ e.preventDefault();
2077
+ dragCounter.current++;
2078
+ if (dragCounter.current === 1)
2079
+ setIsDraggingOver(true);
2080
+ }
2081
+ };
2082
+ const onDragLeave = (_e) => {
2083
+ dragCounter.current--;
2084
+ if (dragCounter.current === 0)
2085
+ setIsDraggingOver(false);
2086
+ };
2087
+ const onDrop = (e) => {
2088
+ if (e.dataTransfer?.types?.includes("Files"))
2089
+ e.preventDefault();
2090
+ dragCounter.current = 0;
2091
+ setIsDraggingOver(false);
2092
+ if (e.dataTransfer?.files && e.dataTransfer.files.length > 0)
2093
+ add(e.dataTransfer.files);
2094
+ };
2095
+ target.addEventListener("dragover", onDragOver);
2096
+ target.addEventListener("dragenter", onDragEnter);
2097
+ target.addEventListener("dragleave", onDragLeave);
2098
+ target.addEventListener("drop", onDrop);
2099
+ return () => {
2100
+ target.removeEventListener("dragover", onDragOver);
2101
+ target.removeEventListener("dragenter", onDragEnter);
2102
+ target.removeEventListener("dragleave", onDragLeave);
2103
+ target.removeEventListener("drop", onDrop);
2104
+ };
2105
+ }, [add, globalDrop, dragListenerTarget]);
2106
+ const filesRef = useRef4(files);
2107
+ filesRef.current = files;
2108
+ useEffect4(() => () => {
2109
+ if (!usingProvider) {
2110
+ for (const f of filesRef.current)
2111
+ if (f.url)
2112
+ URL.revokeObjectURL(f.url);
2113
+ }
2114
+ }, [usingProvider]);
2115
+ const handleChange = (event) => {
2116
+ if (event.currentTarget.files)
2117
+ add(event.currentTarget.files);
2118
+ };
2119
+ const convertBlobUrlToDataUrl = async (url) => {
2120
+ const response = await fetch(url);
2121
+ const blob = await response.blob();
2122
+ return new Promise((resolve, reject) => {
2123
+ const reader = new FileReader;
2124
+ reader.onloadend = () => resolve(reader.result);
2125
+ reader.onerror = reject;
2126
+ reader.readAsDataURL(blob);
2127
+ });
2128
+ };
2129
+ const ctx = useMemo2(() => ({
2130
+ files: files.map((item) => ({ ...item, id: item.id })),
2131
+ add,
2132
+ remove,
2133
+ clear,
2134
+ openFileDialog,
2135
+ fileInputRef: inputRef
2136
+ }), [files, add, remove, clear, openFileDialog]);
2137
+ const handleSubmit = (event) => {
2138
+ event.preventDefault();
2139
+ const form = event.currentTarget;
2140
+ const text = usingProvider ? controller.textInput.value : (() => {
2141
+ const formData = new FormData(form);
2142
+ return formData.get("message") || "";
2143
+ })();
2144
+ if (!usingProvider)
2145
+ form.reset();
2146
+ Promise.all(files.map(async ({ id, ...item }) => {
2147
+ if (item.url && item.url.startsWith("blob:")) {
2148
+ return { ...item, url: await convertBlobUrlToDataUrl(item.url) };
2149
+ }
2150
+ return item;
2151
+ })).then((convertedFiles) => {
2152
+ try {
2153
+ const result = onSubmit({ text, files: convertedFiles }, event);
2154
+ if (result instanceof Promise) {
2155
+ result.then(() => {
2156
+ clear();
2157
+ if (usingProvider)
2158
+ controller.textInput.clear();
2159
+ }).catch(() => {});
2160
+ } else {
2161
+ clear();
2162
+ if (usingProvider)
2163
+ controller.textInput.clear();
2164
+ }
2165
+ } catch {}
2166
+ });
2167
+ };
2168
+ const dropZoneValue = useMemo2(() => ({ isDraggingOver }), [isDraggingOver]);
2169
+ const inner = /* @__PURE__ */ jsxDEV25(DropZoneContext.Provider, {
2170
+ value: dropZoneValue,
2171
+ children: /* @__PURE__ */ jsxDEV25("form", {
2172
+ className: cn("relative w-full", className),
2173
+ onSubmit: handleSubmit,
2174
+ ref: formRef,
2175
+ ...props,
2176
+ children: [
2177
+ /* @__PURE__ */ jsxDEV25("input", {
2178
+ accept,
2179
+ "aria-label": "Upload files",
2180
+ className: "hidden",
2181
+ multiple,
2182
+ onChange: handleChange,
2183
+ ref: inputRef,
2184
+ title: "Upload files",
2185
+ type: "file"
2186
+ }, undefined, false, undefined, this),
2187
+ /* @__PURE__ */ jsxDEV25(InputGroup, {
2188
+ children
2189
+ }, undefined, false, undefined, this)
2190
+ ]
2191
+ }, undefined, true, undefined, this)
2192
+ }, undefined, false, undefined, this);
2193
+ return usingProvider ? inner : /* @__PURE__ */ jsxDEV25(LocalAttachmentsContext.Provider, {
2194
+ value: ctx,
2195
+ children: inner
2196
+ }, undefined, false, undefined, this);
2197
+ };
2198
+ // src/ui/components/prompt-input/textarea.tsx
2199
+ import { useState as useState6 } from "react";
2200
+ import { jsxDEV as jsxDEV26 } from "react/jsx-dev-runtime";
2201
+ var PromptInputTextarea = ({
2202
+ onChange,
2203
+ className,
2204
+ placeholder = "What would you like to know?",
2205
+ ...props
2206
+ }) => {
2207
+ const controller = useOptionalPromptInputController();
2208
+ const attachments = usePromptInputAttachments();
2209
+ const [isComposing, setIsComposing] = useState6(false);
2210
+ const handleKeyDown = (e) => {
2211
+ if (e.key === "Enter") {
2212
+ if (isComposing || e.nativeEvent.isComposing)
2213
+ return;
2214
+ if (e.shiftKey)
2215
+ return;
2216
+ e.preventDefault();
2217
+ e.currentTarget.form?.requestSubmit();
2218
+ }
2219
+ if (e.key === "Backspace" && e.currentTarget.value === "" && attachments.files.length > 0) {
2220
+ e.preventDefault();
2221
+ const lastAttachment = attachments.files.at(-1);
2222
+ if (lastAttachment)
2223
+ attachments.remove(lastAttachment.id);
2224
+ }
2225
+ };
2226
+ const handlePaste = (event) => {
2227
+ const items = event.clipboardData?.items;
2228
+ if (!items)
2229
+ return;
2230
+ const files = [];
2231
+ for (const item of items) {
2232
+ if (item.kind === "file") {
2233
+ const file = item.getAsFile();
2234
+ if (file)
2235
+ files.push(file);
2236
+ }
2237
+ }
2238
+ if (files.length > 0) {
2239
+ event.preventDefault();
2240
+ attachments.add(files);
2241
+ }
2242
+ };
2243
+ const controlledProps = controller ? {
2244
+ value: controller.textInput.value,
2245
+ onChange: (e) => {
2246
+ controller.textInput.setInput(e.currentTarget.value);
2247
+ onChange?.(e);
2248
+ }
2249
+ } : { onChange };
2250
+ return /* @__PURE__ */ jsxDEV26(InputGroupTextarea, {
2251
+ className: cn("[field-sizing:content] max-h-48 text-base", className),
2252
+ rows: 1,
2253
+ name: "message",
2254
+ onCompositionEnd: () => setIsComposing(false),
2255
+ onCompositionStart: () => setIsComposing(true),
2256
+ onKeyDown: handleKeyDown,
2257
+ onPaste: handlePaste,
2258
+ placeholder,
2259
+ ...props,
2260
+ ...controlledProps
2261
+ }, undefined, false, undefined, this);
2262
+ };
2263
+ // src/ui/components/prompt-input/attachments.tsx
2264
+ import { ImageIcon, MicIcon, PaperclipIcon, XIcon as XIcon2 } from "lucide-react";
2265
+ import { Fragment as Fragment4 } from "react";
2266
+ import { jsxDEV as jsxDEV27 } from "react/jsx-dev-runtime";
2267
+ function PromptInputAttachment({ data, className, ...props }) {
2268
+ const attachments = usePromptInputAttachments();
2269
+ const filename = data.filename || "";
2270
+ const isImage = data.mediaType?.startsWith("image/") && data.url;
2271
+ const isAudio = data.mediaType?.startsWith("audio/");
2272
+ const attachmentLabel = filename || (isImage ? "Image" : isAudio ? "Audio" : "Attachment");
2273
+ return /* @__PURE__ */ jsxDEV27(HoverCard, {
2274
+ openDelay: 0,
2275
+ closeDelay: 0,
2276
+ children: [
2277
+ /* @__PURE__ */ jsxDEV27(HoverCardTrigger, {
2278
+ asChild: true,
2279
+ children: /* @__PURE__ */ jsxDEV27("div", {
2280
+ className: cn("group relative flex h-8 cursor-default select-none items-center gap-1.5 rounded-md border border-border px-1.5 font-medium text-sm transition-all hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", className),
2281
+ ...props,
2282
+ children: [
2283
+ /* @__PURE__ */ jsxDEV27("div", {
2284
+ className: "relative size-5 shrink-0",
2285
+ children: [
2286
+ /* @__PURE__ */ jsxDEV27("div", {
2287
+ className: "absolute inset-0 flex size-5 items-center justify-center overflow-hidden rounded bg-background transition-opacity group-hover:opacity-0",
2288
+ children: isImage ? /* @__PURE__ */ jsxDEV27("img", {
2289
+ alt: filename || "attachment",
2290
+ className: "size-5 object-cover",
2291
+ height: 20,
2292
+ src: data.url,
2293
+ width: 20
2294
+ }, undefined, false, undefined, this) : isAudio ? /* @__PURE__ */ jsxDEV27("div", {
2295
+ className: "flex size-5 items-center justify-center text-muted-foreground",
2296
+ children: /* @__PURE__ */ jsxDEV27(MicIcon, {
2297
+ className: "size-3"
2298
+ }, undefined, false, undefined, this)
2299
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV27("div", {
2300
+ className: "flex size-5 items-center justify-center text-muted-foreground",
2301
+ children: /* @__PURE__ */ jsxDEV27(PaperclipIcon, {
2302
+ className: "size-3"
2303
+ }, undefined, false, undefined, this)
2304
+ }, undefined, false, undefined, this)
2305
+ }, undefined, false, undefined, this),
2306
+ /* @__PURE__ */ jsxDEV27(Button, {
2307
+ "aria-label": "Remove attachment",
2308
+ className: "absolute inset-0 size-5 cursor-pointer rounded p-0 opacity-0 transition-opacity group-hover:pointer-events-auto group-hover:opacity-100 [&>svg]:size-2.5",
2309
+ onClick: (e) => {
2310
+ e.stopPropagation();
2311
+ attachments.remove(data.id);
2312
+ },
2313
+ type: "button",
2314
+ variant: "ghost",
2315
+ children: [
2316
+ /* @__PURE__ */ jsxDEV27(XIcon2, {}, undefined, false, undefined, this),
2317
+ /* @__PURE__ */ jsxDEV27("span", {
2318
+ className: "sr-only",
2319
+ children: "Remove"
2320
+ }, undefined, false, undefined, this)
2321
+ ]
2322
+ }, undefined, true, undefined, this)
2323
+ ]
2324
+ }, undefined, true, undefined, this),
2325
+ /* @__PURE__ */ jsxDEV27("span", {
2326
+ className: "flex-1 truncate",
2327
+ children: attachmentLabel
2328
+ }, undefined, false, undefined, this)
2329
+ ]
2330
+ }, data.id, true, undefined, this)
2331
+ }, undefined, false, undefined, this),
2332
+ /* @__PURE__ */ jsxDEV27(HoverCardContent, {
2333
+ align: "start",
2334
+ className: "w-auto p-2",
2335
+ children: /* @__PURE__ */ jsxDEV27("div", {
2336
+ className: "w-auto space-y-3",
2337
+ children: [
2338
+ isImage && /* @__PURE__ */ jsxDEV27("div", {
2339
+ className: "flex max-h-96 w-96 items-center justify-center overflow-hidden rounded-md border",
2340
+ children: /* @__PURE__ */ jsxDEV27("img", {
2341
+ alt: filename || "attachment preview",
2342
+ className: "max-h-full max-w-full object-contain",
2343
+ height: 384,
2344
+ src: data.url,
2345
+ width: 448
2346
+ }, undefined, false, undefined, this)
2347
+ }, undefined, false, undefined, this),
2348
+ isAudio && data.url && /* @__PURE__ */ jsxDEV27("div", {
2349
+ className: "w-64",
2350
+ children: /* @__PURE__ */ jsxDEV27("audio", {
2351
+ src: data.url,
2352
+ controls: true,
2353
+ className: "w-full"
2354
+ }, undefined, false, undefined, this)
2355
+ }, undefined, false, undefined, this),
2356
+ /* @__PURE__ */ jsxDEV27("div", {
2357
+ className: "flex items-center gap-2.5",
2358
+ children: /* @__PURE__ */ jsxDEV27("div", {
2359
+ className: "min-w-0 flex-1 space-y-1 px-0.5",
2360
+ children: [
2361
+ /* @__PURE__ */ jsxDEV27("h4", {
2362
+ className: "truncate font-semibold text-sm leading-none",
2363
+ children: filename || (isImage ? "Image" : "Attachment")
2364
+ }, undefined, false, undefined, this),
2365
+ data.mediaType && /* @__PURE__ */ jsxDEV27("p", {
2366
+ className: "truncate font-mono text-muted-foreground text-xs",
2367
+ children: data.mediaType
2368
+ }, undefined, false, undefined, this)
2369
+ ]
2370
+ }, undefined, true, undefined, this)
2371
+ }, undefined, false, undefined, this)
2372
+ ]
2373
+ }, undefined, true, undefined, this)
2374
+ }, undefined, false, undefined, this)
2375
+ ]
2376
+ }, undefined, true, undefined, this);
2377
+ }
2378
+ function PromptInputAttachments({ children }) {
2379
+ const attachments = usePromptInputAttachments();
2380
+ if (!attachments.files.length)
2381
+ return null;
2382
+ return attachments.files.map((file) => /* @__PURE__ */ jsxDEV27(Fragment4, {
2383
+ children: children(file)
2384
+ }, file.id, false, undefined, this));
2385
+ }
2386
+ var PromptInputActionAddAttachments = ({
2387
+ label = "Add photos or files",
2388
+ ...props
2389
+ }) => {
2390
+ const attachments = usePromptInputAttachments();
2391
+ return /* @__PURE__ */ jsxDEV27(DropdownMenuItem, {
2392
+ ...props,
2393
+ onSelect: () => {
2394
+ attachments.openFileDialog();
2395
+ },
2396
+ children: [
2397
+ /* @__PURE__ */ jsxDEV27(ImageIcon, {
2398
+ className: "mr-2 size-4"
2399
+ }, undefined, false, undefined, this),
2400
+ " ",
2401
+ label
2402
+ ]
2403
+ }, undefined, true, undefined, this);
2404
+ };
2405
+ // src/ui/components/prompt-input/footer.tsx
2406
+ import { jsxDEV as jsxDEV28 } from "react/jsx-dev-runtime";
2407
+ var PromptInputBody = ({ className, ...props }) => /* @__PURE__ */ jsxDEV28("div", {
2408
+ className: cn("contents", className),
2409
+ ...props
2410
+ }, undefined, false, undefined, this);
2411
+ var PromptInputHeader = ({ className, ...props }) => /* @__PURE__ */ jsxDEV28(InputGroupAddon, {
2412
+ align: "block-start",
2413
+ className: cn("flex-wrap gap-1 empty:hidden empty:p-0", className),
2414
+ ...props
2415
+ }, undefined, false, undefined, this);
2416
+ var PromptInputFooter = ({ className, ...props }) => /* @__PURE__ */ jsxDEV28(InputGroupAddon, {
2417
+ align: "block-end",
2418
+ className: cn("justify-between gap-1", className),
2419
+ ...props
2420
+ }, undefined, false, undefined, this);
2421
+ var PromptInputTools = ({ className, ...props }) => /* @__PURE__ */ jsxDEV28("div", {
2422
+ className: cn("flex items-center gap-1", className),
2423
+ ...props
2424
+ }, undefined, false, undefined, this);
2425
+ // src/ui/components/prompt-input/buttons.tsx
2426
+ import { Loader2Icon, PlusIcon, SendIcon, SquareIcon, XIcon as XIcon3 } from "lucide-react";
2427
+ import { Children } from "react";
2428
+ import { jsxDEV as jsxDEV29 } from "react/jsx-dev-runtime";
2429
+ var PromptInputButton = ({
2430
+ variant = "ghost",
2431
+ className,
2432
+ size,
2433
+ ...props
2434
+ }) => {
2435
+ const newSize = size ?? (Children.count(props.children) > 1 ? "sm" : "icon-sm");
2436
+ return /* @__PURE__ */ jsxDEV29(InputGroupButton, {
2437
+ className: cn(className),
2438
+ size: newSize,
2439
+ type: "button",
2440
+ variant,
2441
+ ...props
2442
+ }, undefined, false, undefined, this);
2443
+ };
2444
+ var PromptInputSubmit = ({
2445
+ className,
2446
+ variant = "default",
2447
+ size = "icon-sm",
2448
+ status,
2449
+ children,
2450
+ ...props
2451
+ }) => {
2452
+ let Icon2 = /* @__PURE__ */ jsxDEV29(SendIcon, {
2453
+ className: "size-4"
2454
+ }, undefined, false, undefined, this);
2455
+ if (status === "submitted") {
2456
+ Icon2 = /* @__PURE__ */ jsxDEV29(Loader2Icon, {
2457
+ className: "size-4 animate-spin"
2458
+ }, undefined, false, undefined, this);
2459
+ } else if (status === "streaming") {
2460
+ Icon2 = /* @__PURE__ */ jsxDEV29(SquareIcon, {
2461
+ className: "size-4"
2462
+ }, undefined, false, undefined, this);
2463
+ } else if (status === "error") {
2464
+ Icon2 = /* @__PURE__ */ jsxDEV29(XIcon3, {
2465
+ className: "size-4"
2466
+ }, undefined, false, undefined, this);
2467
+ }
2468
+ return /* @__PURE__ */ jsxDEV29(InputGroupButton, {
2469
+ "aria-label": "Submit",
2470
+ className: cn(className),
2471
+ size,
2472
+ type: "submit",
2473
+ variant,
2474
+ ...props,
2475
+ children: children ?? Icon2
2476
+ }, undefined, false, undefined, this);
2477
+ };
2478
+ var PromptInputActionMenu = (props) => /* @__PURE__ */ jsxDEV29(DropdownMenu, {
2479
+ ...props
2480
+ }, undefined, false, undefined, this);
2481
+ var PromptInputActionMenuTrigger = ({
2482
+ className,
2483
+ children,
2484
+ ...props
2485
+ }) => /* @__PURE__ */ jsxDEV29(DropdownMenuTrigger, {
2486
+ asChild: true,
2487
+ children: /* @__PURE__ */ jsxDEV29(PromptInputButton, {
2488
+ className,
2489
+ ...props,
2490
+ children: children ?? /* @__PURE__ */ jsxDEV29(PlusIcon, {
2491
+ className: "size-4"
2492
+ }, undefined, false, undefined, this)
2493
+ }, undefined, false, undefined, this)
2494
+ }, undefined, false, undefined, this);
2495
+ var PromptInputActionMenuContent = ({
2496
+ className,
2497
+ ...props
2498
+ }) => /* @__PURE__ */ jsxDEV29(DropdownMenuContent, {
2499
+ align: "start",
2500
+ className: cn(className),
2501
+ ...props
2502
+ }, undefined, false, undefined, this);
2503
+ var PromptInputActionMenuItem = ({
2504
+ className,
2505
+ ...props
2506
+ }) => /* @__PURE__ */ jsxDEV29(DropdownMenuItem, {
2507
+ className: cn(className),
2508
+ ...props
2509
+ }, undefined, false, undefined, this);
2510
+ // src/ui/components/prompt-input/drop-zone.tsx
2511
+ import { Upload } from "lucide-react";
2512
+ import { createPortal } from "react-dom";
2513
+ import { jsxDEV as jsxDEV30 } from "react/jsx-dev-runtime";
2514
+ var PromptInputDropZone = ({
2515
+ label = "Drop files here",
2516
+ className,
2517
+ container,
2518
+ ...props
2519
+ }) => {
2520
+ const { isDraggingOver } = usePromptInputDropZone();
2521
+ const overlay = /* @__PURE__ */ jsxDEV30("div", {
2522
+ className: cn("absolute inset-0 z-10 pointer-events-none", "flex flex-col items-center justify-center gap-2", "border-2 border-dashed border-primary rounded-xl", "bg-primary/5 backdrop-blur-[2px] text-primary", "transition-opacity duration-200", isDraggingOver ? "opacity-100" : "opacity-0", className),
2523
+ "aria-hidden": !isDraggingOver,
2524
+ ...props,
2525
+ children: [
2526
+ /* @__PURE__ */ jsxDEV30(Upload, {
2527
+ className: "size-14"
2528
+ }, undefined, false, undefined, this),
2529
+ /* @__PURE__ */ jsxDEV30("span", {
2530
+ className: "text-sm font-medium mt-2",
2531
+ children: label
2532
+ }, undefined, false, undefined, this)
2533
+ ]
2534
+ }, undefined, true, undefined, this);
2535
+ if (container?.current) {
2536
+ return createPortal(overlay, container.current);
2537
+ }
2538
+ return overlay;
2539
+ };
2540
+ // src/ui/components/prompt-input/speech.tsx
2541
+ import { MicIcon as MicIcon2 } from "lucide-react";
2542
+ import { useCallback as useCallback6, useEffect as useEffect5, useRef as useRef5, useState as useState7 } from "react";
2543
+ import { jsxDEV as jsxDEV31 } from "react/jsx-dev-runtime";
2544
+ var PromptInputSpeechButton = ({
2545
+ className,
2546
+ onTranscriptionChange,
2547
+ lang = "en-US",
2548
+ ...props
2549
+ }) => {
2550
+ const [isListening, setIsListening] = useState7(false);
2551
+ const [recognition, setRecognition] = useState7(null);
2552
+ const recognitionRef = useRef5(null);
2553
+ const onTranscriptionChangeRef = useRef5(onTranscriptionChange);
2554
+ onTranscriptionChangeRef.current = onTranscriptionChange;
2555
+ const controller = useOptionalPromptInputController();
2556
+ useEffect5(() => {
2557
+ if (typeof window !== "undefined" && (("SpeechRecognition" in window) || ("webkitSpeechRecognition" in window))) {
2558
+ const SpeechRecognitionCtor = window.SpeechRecognition || window.webkitSpeechRecognition;
2559
+ const speechRecognition = new SpeechRecognitionCtor;
2560
+ speechRecognition.continuous = true;
2561
+ speechRecognition.interimResults = true;
2562
+ speechRecognition.lang = lang;
2563
+ speechRecognition.onstart = () => setIsListening(true);
2564
+ speechRecognition.onend = () => setIsListening(false);
2565
+ speechRecognition.onresult = (event) => {
2566
+ let finalTranscript = "";
2567
+ const results = Array.from(event.results);
2568
+ for (const result of results) {
2569
+ if (result.isFinal)
2570
+ finalTranscript += result[0]?.transcript ?? "";
2571
+ }
2572
+ if (finalTranscript) {
2573
+ if (controller) {
2574
+ const current = controller.textInput.value;
2575
+ const newValue = current + (current ? " " : "") + finalTranscript;
2576
+ controller.textInput.setInput(newValue);
2577
+ }
2578
+ onTranscriptionChangeRef.current?.(finalTranscript);
2579
+ }
2580
+ };
2581
+ speechRecognition.onerror = (event) => {
2582
+ console.error("Speech recognition error:", event.error);
2583
+ setIsListening(false);
2584
+ };
2585
+ recognitionRef.current = speechRecognition;
2586
+ setRecognition(speechRecognition);
2587
+ }
2588
+ return () => {
2589
+ if (recognitionRef.current)
2590
+ recognitionRef.current.stop();
2591
+ };
2592
+ }, [lang]);
2593
+ const toggleListening = useCallback6(() => {
2594
+ if (!recognition)
2595
+ return;
2596
+ if (isListening)
2597
+ recognition.stop();
2598
+ else
2599
+ recognition.start();
2600
+ }, [recognition, isListening]);
2601
+ return /* @__PURE__ */ jsxDEV31(PromptInputButton, {
2602
+ className: cn("relative transition-all duration-200", isListening && "animate-pulse bg-accent text-accent-foreground", className),
2603
+ disabled: !recognition,
2604
+ onClick: toggleListening,
2605
+ ...props,
2606
+ children: /* @__PURE__ */ jsxDEV31(MicIcon2, {
2607
+ className: "size-4"
2608
+ }, undefined, false, undefined, this)
2609
+ }, undefined, false, undefined, this);
2610
+ };
2611
+ // src/ui/components/prompt-input/model-select.tsx
2612
+ import { jsxDEV as jsxDEV32 } from "react/jsx-dev-runtime";
2613
+ var PromptInputModelSelect = (props) => /* @__PURE__ */ jsxDEV32(Select, {
2614
+ ...props
2615
+ }, undefined, false, undefined, this);
2616
+ var PromptInputModelSelectTrigger = ({
2617
+ className,
2618
+ ...props
2619
+ }) => /* @__PURE__ */ jsxDEV32(SelectTrigger, {
2620
+ className: cn("border-none bg-transparent font-medium text-muted-foreground shadow-none transition-colors", 'hover:bg-accent hover:text-foreground [&[aria-expanded="true"]]:bg-accent [&[aria-expanded="true"]]:text-foreground', className),
2621
+ ...props
2622
+ }, undefined, false, undefined, this);
2623
+ var PromptInputModelSelectContent = ({ className, ...props }) => /* @__PURE__ */ jsxDEV32(SelectContent, {
2624
+ className: cn(className),
2625
+ ...props
2626
+ }, undefined, false, undefined, this);
2627
+ var PromptInputModelSelectItem = ({ className, ...props }) => /* @__PURE__ */ jsxDEV32(SelectItem, {
2628
+ className: cn(className),
2629
+ ...props
2630
+ }, undefined, false, undefined, this);
2631
+ var PromptInputModelSelectValue = ({ className, ...props }) => /* @__PURE__ */ jsxDEV32(SelectValue, {
2632
+ className: cn(className),
2633
+ ...props
2634
+ }, undefined, false, undefined, this);
2635
+ // src/ui/components/prompt-input/tabs.tsx
2636
+ import { jsxDEV as jsxDEV33 } from "react/jsx-dev-runtime";
2637
+ var PromptInputTabsList = ({ className, ...props }) => /* @__PURE__ */ jsxDEV33("div", {
2638
+ className: cn(className),
2639
+ ...props
2640
+ }, undefined, false, undefined, this);
2641
+ var PromptInputTab = ({ className, ...props }) => /* @__PURE__ */ jsxDEV33("div", {
2642
+ className: cn(className),
2643
+ ...props
2644
+ }, undefined, false, undefined, this);
2645
+ var PromptInputTabLabel = ({ className, ...props }) => /* @__PURE__ */ jsxDEV33("h3", {
2646
+ className: cn("mb-2 px-3 font-medium text-muted-foreground text-xs", className),
2647
+ ...props
2648
+ }, undefined, false, undefined, this);
2649
+ var PromptInputTabBody = ({ className, ...props }) => /* @__PURE__ */ jsxDEV33("div", {
2650
+ className: cn("space-y-1", className),
2651
+ ...props
2652
+ }, undefined, false, undefined, this);
2653
+ var PromptInputTabItem = ({ className, ...props }) => /* @__PURE__ */ jsxDEV33("div", {
2654
+ className: cn("flex items-center gap-2 px-3 py-2 text-xs hover:bg-accent", className),
2655
+ ...props
2656
+ }, undefined, false, undefined, this);
2657
+ // src/ui/components/prompt-input/command.tsx
2658
+ import { jsxDEV as jsxDEV34 } from "react/jsx-dev-runtime";
2659
+ var PromptInputCommand = ({ className, ...props }) => /* @__PURE__ */ jsxDEV34(Command, {
2660
+ className: cn(className),
2661
+ ...props
2662
+ }, undefined, false, undefined, this);
2663
+ var PromptInputCommandInput = ({ className, ...props }) => /* @__PURE__ */ jsxDEV34(CommandInput, {
2664
+ className: cn(className),
2665
+ ...props
2666
+ }, undefined, false, undefined, this);
2667
+ var PromptInputCommandList = ({ className, ...props }) => /* @__PURE__ */ jsxDEV34(CommandList, {
2668
+ className: cn(className),
2669
+ ...props
2670
+ }, undefined, false, undefined, this);
2671
+ var PromptInputCommandEmpty = ({ className, ...props }) => /* @__PURE__ */ jsxDEV34(CommandEmpty, {
2672
+ className: cn(className),
2673
+ ...props
2674
+ }, undefined, false, undefined, this);
2675
+ var PromptInputCommandGroup = ({ className, ...props }) => /* @__PURE__ */ jsxDEV34(CommandGroup, {
2676
+ className: cn(className),
2677
+ ...props
2678
+ }, undefined, false, undefined, this);
2679
+ var PromptInputCommandItem = ({ className, ...props }) => /* @__PURE__ */ jsxDEV34(CommandItem, {
2680
+ className: cn(className),
2681
+ ...props
2682
+ }, undefined, false, undefined, this);
2683
+ var PromptInputCommandSeparator = ({ className, ...props }) => /* @__PURE__ */ jsxDEV34(CommandSeparator, {
2684
+ className: cn(className),
2685
+ ...props
2686
+ }, undefined, false, undefined, this);
2687
+ // src/ui/composed/agno-chat/agno-chat.tsx
2688
+ import { useCallback as useCallback7, useMemo as useMemo3, useRef as useRef6 } from "react";
2689
+ import { useAgnoChat, useAgnoToolExecution } from "@rodrigocoliveira/agno-react";
2690
+
2691
+ // src/ui/composed/agno-chat/context.ts
2692
+ import { createContext as createContext3, useContext as useContext3 } from "react";
2693
+ var AgnoChatContext = createContext3(null);
2694
+ function useAgnoChatContext() {
2695
+ const ctx = useContext3(AgnoChatContext);
2696
+ if (!ctx) {
2697
+ throw new Error("useAgnoChatContext must be used within an <AgnoChat> provider. " + "Wrap your component tree with <AgnoChat>.");
2698
+ }
2699
+ return ctx;
2700
+ }
2701
+
2702
+ // src/ui/composed/agno-chat/agno-chat.tsx
2703
+ import { jsxDEV as jsxDEV35 } from "react/jsx-dev-runtime";
2704
+ function AgnoChatRoot({
2705
+ children,
2706
+ toolHandlers = {},
2707
+ autoExecuteTools = true,
2708
+ className,
2709
+ ...divProps
2710
+ }) {
2711
+ const chat = useAgnoChat();
2712
+ const toolExec = useAgnoToolExecution(toolHandlers, autoExecuteTools);
2713
+ const containerRef = useRef6(null);
2714
+ const sendRef = useRef6(chat.sendMessage);
2715
+ sendRef.current = chat.sendMessage;
2716
+ const handleSend = useCallback7(async (message) => {
2717
+ try {
2718
+ await sendRef.current(message);
2719
+ } catch {}
2720
+ }, []);
2721
+ const {
2722
+ messages,
2723
+ sendMessage,
2724
+ clearMessages,
2725
+ cancelRun,
2726
+ isStreaming,
2727
+ isRefreshing,
2728
+ isCancelling,
2729
+ currentRunId,
2730
+ error,
2731
+ state
2732
+ } = chat;
2733
+ const {
2734
+ isPaused,
2735
+ isExecuting,
2736
+ pendingTools,
2737
+ executeAndContinue,
2738
+ executeTools,
2739
+ continueWithResults,
2740
+ executionError
2741
+ } = toolExec;
2742
+ const contextValue = useMemo3(() => ({
2743
+ messages,
2744
+ sendMessage,
2745
+ clearMessages,
2746
+ cancelRun,
2747
+ isStreaming,
2748
+ isRefreshing,
2749
+ isCancelling: isCancelling ?? false,
2750
+ currentRunId,
2751
+ error,
2752
+ state,
2753
+ isPaused,
2754
+ isExecuting,
2755
+ pendingTools,
2756
+ executeAndContinue,
2757
+ executeTools,
2758
+ continueWithResults,
2759
+ executionError,
2760
+ handleSend,
2761
+ inputDisabled: isStreaming || isPaused,
2762
+ dropZoneContainerRef: containerRef
2763
+ }), [
2764
+ messages,
2765
+ sendMessage,
2766
+ clearMessages,
2767
+ cancelRun,
2768
+ isStreaming,
2769
+ isRefreshing,
2770
+ isCancelling,
2771
+ currentRunId,
2772
+ error,
2773
+ state,
2774
+ isPaused,
2775
+ isExecuting,
2776
+ pendingTools,
2777
+ executeAndContinue,
2778
+ executeTools,
2779
+ continueWithResults,
2780
+ executionError,
2781
+ handleSend
2782
+ ]);
2783
+ return /* @__PURE__ */ jsxDEV35(AgnoChatContext.Provider, {
2784
+ value: contextValue,
2785
+ children: /* @__PURE__ */ jsxDEV35("div", {
2786
+ ref: containerRef,
2787
+ className: cn("relative h-full flex flex-col", className),
2788
+ ...divProps,
2789
+ children
2790
+ }, undefined, false, undefined, this)
2791
+ }, undefined, false, undefined, this);
2792
+ }
2793
+
2794
+ // src/ui/composed/agno-chat/messages.tsx
2795
+ import { useEffect as useEffect6, useRef as useRef7 } from "react";
2796
+
2797
+ // src/ui/composed/AgnoMessageItem.tsx
2798
+ import { useState as useState8 } from "react";
2799
+ import { GenerativeUIRenderer } from "@rodrigocoliveira/agno-react";
2800
+ import {
2801
+ AlertCircle,
2802
+ FileIcon as FileIcon3,
2803
+ FileText,
2804
+ Image as ImageIcon2,
2805
+ Lightbulb,
2806
+ Music,
2807
+ Paperclip,
2808
+ Video
2809
+ } from "lucide-react";
2810
+ import { jsxDEV as jsxDEV36, Fragment as Fragment5 } from "react/jsx-dev-runtime";
2811
+ var defaultFormatTimestamp = formatSmartTimestamp;
2812
+ var getToolState = (tool) => {
2813
+ return tool.tool_call_error ? "output-error" : "output-available";
2814
+ };
2815
+ function AgnoMessageItem({
2816
+ message,
2817
+ className,
2818
+ classNames,
2819
+ renderContent,
2820
+ renderToolCall,
2821
+ renderMedia,
2822
+ renderActions,
2823
+ userAvatar,
2824
+ assistantAvatar,
2825
+ showReasoning = true,
2826
+ showReferences = true,
2827
+ showTimestamp = true,
2828
+ showGenerativeUI = true,
2829
+ showToolCalls = true,
2830
+ showFilePreview = true,
2831
+ showImageLightbox = true,
2832
+ formatTimestamp
2833
+ }) {
2834
+ const isUser = message.role === "user";
2835
+ const hasError = message.streamingError;
2836
+ const toolsWithUI = message.tool_calls?.filter((tool) => tool.ui_component) || [];
2837
+ const [preview, setPreview] = useState8(null);
2838
+ const isCustomTimestamp = !!formatTimestamp;
2839
+ const resolvedFormatTimestamp = formatTimestamp ?? defaultFormatTimestamp;
2840
+ const openImageLightbox = (images, index) => {
2841
+ if (!showImageLightbox)
2842
+ return;
2843
+ setPreview({ type: "image", images, initialIndex: index });
2844
+ };
2845
+ const openFilePreview = (file) => {
2846
+ if (!showFilePreview)
2847
+ return;
2848
+ setPreview({ type: "file", file });
2849
+ };
2850
+ const closePreview = () => setPreview(null);
2851
+ return /* @__PURE__ */ jsxDEV36("div", {
2852
+ className: cn("py-5 first:pt-2", isUser ? "flex justify-end" : "", classNames?.root, className),
2853
+ children: [
2854
+ isUser ? /* @__PURE__ */ jsxDEV36("div", {
2855
+ className: "flex items-start gap-2.5 max-w-[80%] flex-row-reverse",
2856
+ children: [
2857
+ userAvatar,
2858
+ /* @__PURE__ */ jsxDEV36("div", {
2859
+ className: "space-y-1.5 flex flex-col items-end min-w-0",
2860
+ children: [
2861
+ (message.images && message.images.length > 0 || message.audio && message.audio.length > 0 || message.files && message.files.length > 0) && /* @__PURE__ */ jsxDEV36("div", {
2862
+ className: "flex flex-wrap gap-2 justify-end",
2863
+ children: [
2864
+ message.images?.map((img, idx) => /* @__PURE__ */ jsxDEV36(FilePreviewCard, {
2865
+ file: { name: img.revised_prompt || `Image ${idx + 1}`, type: "image/png", url: img.url },
2866
+ onClick: showImageLightbox ? () => openImageLightbox(message.images.map((i) => ({ url: i.url, alt: i.revised_prompt })), idx) : undefined
2867
+ }, `img-${idx}`, false, undefined, this)),
2868
+ message.audio?.map((audio, idx) => /* @__PURE__ */ jsxDEV36("div", {
2869
+ className: "flex items-center gap-1.5 rounded-lg border border-border bg-muted/50 px-2.5 py-1.5 text-xs text-foreground self-end",
2870
+ children: [
2871
+ /* @__PURE__ */ jsxDEV36(Music, {
2872
+ className: "h-3.5 w-3.5 text-muted-foreground"
2873
+ }, undefined, false, undefined, this),
2874
+ /* @__PURE__ */ jsxDEV36("span", {
2875
+ className: "truncate max-w-[150px]",
2876
+ children: audio.id || `Audio ${idx + 1}`
2877
+ }, undefined, false, undefined, this)
2878
+ ]
2879
+ }, `audio-${idx}`, true, undefined, this)),
2880
+ message.files?.map((file, idx) => showFilePreview ? /* @__PURE__ */ jsxDEV36(FilePreviewCard, {
2881
+ file: { name: file.name, type: file.type, url: file.url, size: file.size },
2882
+ onClick: () => openFilePreview({ name: file.name, type: file.type, url: file.url, size: file.size })
2883
+ }, `file-${idx}`, false, undefined, this) : /* @__PURE__ */ jsxDEV36("div", {
2884
+ className: "flex items-center gap-1.5 rounded-lg border border-border bg-muted/50 px-2.5 py-1.5 text-xs text-foreground self-end",
2885
+ children: [
2886
+ /* @__PURE__ */ jsxDEV36(FileIcon3, {
2887
+ className: "h-3.5 w-3.5 text-muted-foreground"
2888
+ }, undefined, false, undefined, this),
2889
+ /* @__PURE__ */ jsxDEV36("span", {
2890
+ className: "truncate max-w-[150px]",
2891
+ children: file.name
2892
+ }, undefined, false, undefined, this)
2893
+ ]
2894
+ }, `file-${idx}`, true, undefined, this))
2895
+ ]
2896
+ }, undefined, true, undefined, this),
2897
+ message.content && /* @__PURE__ */ jsxDEV36("div", {
2898
+ className: cn("rounded-2xl rounded-br-md px-4 py-2.5", classNames?.userBubble ?? "bg-primary text-primary-foreground", hasError && "opacity-70"),
2899
+ children: /* @__PURE__ */ jsxDEV36("p", {
2900
+ className: "text-sm whitespace-pre-wrap",
2901
+ children: message.content
2902
+ }, undefined, false, undefined, this)
2903
+ }, undefined, false, undefined, this),
2904
+ showTimestamp && /* @__PURE__ */ jsxDEV36("div", {
2905
+ className: "flex items-center justify-end gap-1.5 px-1",
2906
+ children: [
2907
+ /* @__PURE__ */ jsxDEV36(SmartTimestamp, {
2908
+ date: new Date(message.created_at * 1000),
2909
+ formatShort: isCustomTimestamp ? resolvedFormatTimestamp : undefined,
2910
+ className: "text-[11px] text-muted-foreground"
2911
+ }, undefined, false, undefined, this),
2912
+ hasError && /* @__PURE__ */ jsxDEV36(AlertCircle, {
2913
+ className: "h-3 w-3 text-destructive"
2914
+ }, undefined, false, undefined, this)
2915
+ ]
2916
+ }, undefined, true, undefined, this)
2917
+ ]
2918
+ }, undefined, true, undefined, this)
2919
+ ]
2920
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV36("div", {
2921
+ className: "flex items-start gap-3",
2922
+ children: [
2923
+ assistantAvatar,
2924
+ /* @__PURE__ */ jsxDEV36("div", {
2925
+ className: cn("flex-1 min-w-0 space-y-3", classNames?.assistantContainer),
2926
+ children: [
2927
+ renderContent ? renderContent(message) : /* @__PURE__ */ jsxDEV36(Fragment5, {
2928
+ children: [
2929
+ showReasoning && message.extra_data?.reasoning_steps && message.extra_data.reasoning_steps.length > 0 && /* @__PURE__ */ jsxDEV36("div", {
2930
+ className: cn("space-y-2 pt-1", classNames?.reasoning),
2931
+ children: [
2932
+ /* @__PURE__ */ jsxDEV36("div", {
2933
+ className: "flex items-center gap-2 text-xs font-medium text-muted-foreground",
2934
+ children: [
2935
+ /* @__PURE__ */ jsxDEV36(Lightbulb, {
2936
+ className: "h-3.5 w-3.5"
2937
+ }, undefined, false, undefined, this),
2938
+ "Reasoning (",
2939
+ message.extra_data.reasoning_steps.length,
2940
+ " steps)"
2941
+ ]
2942
+ }, undefined, true, undefined, this),
2943
+ /* @__PURE__ */ jsxDEV36(Accordion, {
2944
+ type: "multiple",
2945
+ className: "w-full",
2946
+ children: message.extra_data.reasoning_steps.map((step, idx) => /* @__PURE__ */ jsxDEV36(AccordionItem, {
2947
+ value: `reasoning-${idx}`,
2948
+ className: "border-muted",
2949
+ children: [
2950
+ /* @__PURE__ */ jsxDEV36(AccordionTrigger, {
2951
+ className: "text-xs py-1.5 hover:no-underline",
2952
+ children: step.title || `Step ${idx + 1}`
2953
+ }, undefined, false, undefined, this),
2954
+ /* @__PURE__ */ jsxDEV36(AccordionContent, {
2955
+ className: "space-y-1.5 text-xs text-muted-foreground",
2956
+ children: [
2957
+ step.action && /* @__PURE__ */ jsxDEV36("div", {
2958
+ children: [
2959
+ /* @__PURE__ */ jsxDEV36("span", {
2960
+ className: "font-medium text-foreground",
2961
+ children: "Action:"
2962
+ }, undefined, false, undefined, this),
2963
+ " ",
2964
+ step.action
2965
+ ]
2966
+ }, undefined, true, undefined, this),
2967
+ step.reasoning && /* @__PURE__ */ jsxDEV36("div", {
2968
+ children: [
2969
+ /* @__PURE__ */ jsxDEV36("span", {
2970
+ className: "font-medium text-foreground",
2971
+ children: "Reasoning:"
2972
+ }, undefined, false, undefined, this),
2973
+ " ",
2974
+ step.reasoning
2975
+ ]
2976
+ }, undefined, true, undefined, this),
2977
+ step.result && /* @__PURE__ */ jsxDEV36("div", {
2978
+ children: [
2979
+ /* @__PURE__ */ jsxDEV36("span", {
2980
+ className: "font-medium text-foreground",
2981
+ children: "Result:"
2982
+ }, undefined, false, undefined, this),
2983
+ " ",
2984
+ step.result
2985
+ ]
2986
+ }, undefined, true, undefined, this),
2987
+ step.confidence !== undefined && /* @__PURE__ */ jsxDEV36("div", {
2988
+ children: [
2989
+ /* @__PURE__ */ jsxDEV36("span", {
2990
+ className: "font-medium text-foreground",
2991
+ children: "Confidence:"
2992
+ }, undefined, false, undefined, this),
2993
+ " ",
2994
+ (step.confidence * 100).toFixed(1),
2995
+ "%"
2996
+ ]
2997
+ }, undefined, true, undefined, this)
2998
+ ]
2999
+ }, undefined, true, undefined, this)
3000
+ ]
3001
+ }, idx, true, undefined, this))
3002
+ }, undefined, false, undefined, this)
3003
+ ]
3004
+ }, undefined, true, undefined, this),
3005
+ message.content && /* @__PURE__ */ jsxDEV36("div", {
3006
+ className: "prose prose-sm dark:prose-invert max-w-none prose-p:leading-relaxed prose-pre:bg-muted prose-pre:border prose-pre:border-border",
3007
+ children: /* @__PURE__ */ jsxDEV36(Response, {
3008
+ children: message.content
3009
+ }, undefined, false, undefined, this)
3010
+ }, undefined, false, undefined, this),
3011
+ showGenerativeUI && toolsWithUI.length > 0 && /* @__PURE__ */ jsxDEV36("div", {
3012
+ className: "space-y-3",
3013
+ children: toolsWithUI.map((tool) => {
3014
+ const uiComponent = tool.ui_component;
3015
+ return /* @__PURE__ */ jsxDEV36("div", {
3016
+ children: uiComponent.layout === "artifact" ? /* @__PURE__ */ jsxDEV36(Artifact, {
3017
+ children: /* @__PURE__ */ jsxDEV36(GenerativeUIRenderer, {
3018
+ spec: uiComponent,
3019
+ className: "w-full p-2"
3020
+ }, undefined, false, undefined, this)
3021
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV36(GenerativeUIRenderer, {
3022
+ spec: uiComponent,
3023
+ className: "w-full"
3024
+ }, undefined, false, undefined, this)
3025
+ }, tool.tool_call_id, false, undefined, this);
3026
+ })
3027
+ }, undefined, false, undefined, this),
3028
+ renderMedia ? renderMedia(message) : (() => {
3029
+ const mediaClassName = classNames?.media;
3030
+ return /* @__PURE__ */ jsxDEV36(Fragment5, {
3031
+ children: [
3032
+ message.images && message.images.length > 0 && /* @__PURE__ */ jsxDEV36("div", {
3033
+ className: cn("space-y-2 pt-1", mediaClassName),
3034
+ children: [
3035
+ /* @__PURE__ */ jsxDEV36("div", {
3036
+ className: "flex items-center gap-2 text-xs font-medium text-muted-foreground",
3037
+ children: [
3038
+ /* @__PURE__ */ jsxDEV36(ImageIcon2, {
3039
+ className: "h-3.5 w-3.5"
3040
+ }, undefined, false, undefined, this),
3041
+ "Images (",
3042
+ message.images.length,
3043
+ ")"
3044
+ ]
3045
+ }, undefined, true, undefined, this),
3046
+ /* @__PURE__ */ jsxDEV36("div", {
3047
+ className: "grid grid-cols-2 gap-2",
3048
+ children: message.images.map((img, idx) => /* @__PURE__ */ jsxDEV36("div", {
3049
+ className: "space-y-1",
3050
+ children: [
3051
+ showImageLightbox ? /* @__PURE__ */ jsxDEV36("button", {
3052
+ type: "button",
3053
+ onClick: () => openImageLightbox(message.images.map((i) => ({ url: i.url, alt: i.revised_prompt })), idx),
3054
+ className: "group relative w-full overflow-hidden rounded-lg border border-border cursor-pointer hover:border-primary/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring transition-colors",
3055
+ children: /* @__PURE__ */ jsxDEV36("img", {
3056
+ src: img.url,
3057
+ alt: img.revised_prompt || "Generated image",
3058
+ className: "w-full rounded-lg"
3059
+ }, undefined, false, undefined, this)
3060
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV36("img", {
3061
+ src: img.url,
3062
+ alt: img.revised_prompt || "Generated image",
3063
+ className: "w-full rounded-lg border border-border"
3064
+ }, undefined, false, undefined, this),
3065
+ img.revised_prompt && /* @__PURE__ */ jsxDEV36("p", {
3066
+ className: "text-[11px] text-muted-foreground italic px-0.5",
3067
+ children: img.revised_prompt
3068
+ }, undefined, false, undefined, this)
3069
+ ]
3070
+ }, idx, true, undefined, this))
3071
+ }, undefined, false, undefined, this)
3072
+ ]
3073
+ }, undefined, true, undefined, this),
3074
+ message.videos && message.videos.length > 0 && /* @__PURE__ */ jsxDEV36("div", {
3075
+ className: cn("space-y-2 pt-1", mediaClassName),
3076
+ children: [
3077
+ /* @__PURE__ */ jsxDEV36("div", {
3078
+ className: "flex items-center gap-2 text-xs font-medium text-muted-foreground",
3079
+ children: [
3080
+ /* @__PURE__ */ jsxDEV36(Video, {
3081
+ className: "h-3.5 w-3.5"
3082
+ }, undefined, false, undefined, this),
3083
+ "Videos (",
3084
+ message.videos.length,
3085
+ ")"
3086
+ ]
3087
+ }, undefined, true, undefined, this),
3088
+ /* @__PURE__ */ jsxDEV36("div", {
3089
+ className: "space-y-2",
3090
+ children: message.videos.map((video, idx) => /* @__PURE__ */ jsxDEV36("div", {
3091
+ children: video.url ? /* @__PURE__ */ jsxDEV36("video", {
3092
+ src: video.url,
3093
+ controls: true,
3094
+ className: "w-full rounded-lg border border-border"
3095
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV36("div", {
3096
+ className: "bg-muted/50 border border-border p-2.5 rounded-lg text-xs text-muted-foreground",
3097
+ children: [
3098
+ "Video ID: ",
3099
+ video.id,
3100
+ " (ETA: ",
3101
+ video.eta,
3102
+ "s)"
3103
+ ]
3104
+ }, undefined, true, undefined, this)
3105
+ }, idx, false, undefined, this))
3106
+ }, undefined, false, undefined, this)
3107
+ ]
3108
+ }, undefined, true, undefined, this),
3109
+ message.audio && message.audio.length > 0 && /* @__PURE__ */ jsxDEV36("div", {
3110
+ className: cn("space-y-2 pt-1", mediaClassName),
3111
+ children: [
3112
+ /* @__PURE__ */ jsxDEV36("div", {
3113
+ className: "flex items-center gap-2 text-xs font-medium text-muted-foreground",
3114
+ children: [
3115
+ /* @__PURE__ */ jsxDEV36(Music, {
3116
+ className: "h-3.5 w-3.5"
3117
+ }, undefined, false, undefined, this),
3118
+ "Audio (",
3119
+ message.audio.length,
3120
+ ")"
3121
+ ]
3122
+ }, undefined, true, undefined, this),
3123
+ /* @__PURE__ */ jsxDEV36("div", {
3124
+ className: "space-y-2",
3125
+ children: message.audio.map((audio, idx) => /* @__PURE__ */ jsxDEV36("div", {
3126
+ children: audio.url ? /* @__PURE__ */ jsxDEV36("audio", {
3127
+ src: audio.url,
3128
+ controls: true,
3129
+ className: "w-full"
3130
+ }, undefined, false, undefined, this) : audio.base64_audio ? /* @__PURE__ */ jsxDEV36("audio", {
3131
+ src: `data:${audio.mime_type || "audio/wav"};base64,${audio.base64_audio}`,
3132
+ controls: true,
3133
+ className: "w-full"
3134
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV36("div", {
3135
+ className: "bg-muted/50 border border-border p-2.5 rounded-lg text-xs text-muted-foreground",
3136
+ children: "Audio data unavailable"
3137
+ }, undefined, false, undefined, this)
3138
+ }, idx, false, undefined, this))
3139
+ }, undefined, false, undefined, this)
3140
+ ]
3141
+ }, undefined, true, undefined, this),
3142
+ message.files && message.files.length > 0 && /* @__PURE__ */ jsxDEV36("div", {
3143
+ className: cn("space-y-2 pt-1", mediaClassName),
3144
+ children: [
3145
+ /* @__PURE__ */ jsxDEV36("div", {
3146
+ className: "flex items-center gap-2 text-xs font-medium text-muted-foreground",
3147
+ children: [
3148
+ /* @__PURE__ */ jsxDEV36(Paperclip, {
3149
+ className: "h-3.5 w-3.5"
3150
+ }, undefined, false, undefined, this),
3151
+ "Files (",
3152
+ message.files.length,
3153
+ ")"
3154
+ ]
3155
+ }, undefined, true, undefined, this),
3156
+ /* @__PURE__ */ jsxDEV36("div", {
3157
+ className: "flex flex-wrap gap-2",
3158
+ children: message.files.map((file, idx) => showFilePreview ? /* @__PURE__ */ jsxDEV36(FilePreviewCard, {
3159
+ file: { name: file.name, type: file.type, url: file.url, size: file.size },
3160
+ onClick: () => openFilePreview({ name: file.name, type: file.type, url: file.url, size: file.size })
3161
+ }, idx, false, undefined, this) : /* @__PURE__ */ jsxDEV36("div", {
3162
+ className: "flex items-center gap-2 rounded-lg border border-border px-3 py-2 text-xs bg-muted/30 hover:bg-muted/50 transition-colors",
3163
+ children: [
3164
+ /* @__PURE__ */ jsxDEV36(FileIcon3, {
3165
+ className: "h-3.5 w-3.5 shrink-0 text-muted-foreground"
3166
+ }, undefined, false, undefined, this),
3167
+ /* @__PURE__ */ jsxDEV36("span", {
3168
+ className: "truncate max-w-[180px]",
3169
+ children: file.name
3170
+ }, undefined, false, undefined, this),
3171
+ file.size && /* @__PURE__ */ jsxDEV36("span", {
3172
+ className: "text-muted-foreground/70",
3173
+ children: [
3174
+ "(",
3175
+ (file.size / 1024).toFixed(1),
3176
+ "KB)"
3177
+ ]
3178
+ }, undefined, true, undefined, this),
3179
+ file.url && /^https?:\/\//i.test(file.url) && /* @__PURE__ */ jsxDEV36("a", {
3180
+ href: file.url,
3181
+ target: "_blank",
3182
+ rel: "noopener noreferrer",
3183
+ className: "text-primary hover:underline font-medium",
3184
+ children: "View"
3185
+ }, undefined, false, undefined, this)
3186
+ ]
3187
+ }, idx, true, undefined, this))
3188
+ }, undefined, false, undefined, this)
3189
+ ]
3190
+ }, undefined, true, undefined, this),
3191
+ message.response_audio && /* @__PURE__ */ jsxDEV36("div", {
3192
+ className: cn("space-y-2 pt-1", mediaClassName),
3193
+ children: [
3194
+ /* @__PURE__ */ jsxDEV36("div", {
3195
+ className: "flex items-center gap-2 text-xs font-medium text-muted-foreground",
3196
+ children: [
3197
+ /* @__PURE__ */ jsxDEV36(Music, {
3198
+ className: "h-3.5 w-3.5"
3199
+ }, undefined, false, undefined, this),
3200
+ "Response Audio"
3201
+ ]
3202
+ }, undefined, true, undefined, this),
3203
+ message.response_audio.transcript && /* @__PURE__ */ jsxDEV36("div", {
3204
+ className: "text-xs italic bg-muted/50 border border-border p-2.5 rounded-lg text-muted-foreground",
3205
+ children: [
3206
+ '"',
3207
+ message.response_audio.transcript,
3208
+ '"'
3209
+ ]
3210
+ }, undefined, true, undefined, this),
3211
+ message.response_audio.content && /* @__PURE__ */ jsxDEV36("audio", {
3212
+ src: `data:audio/wav;base64,${message.response_audio.content}`,
3213
+ controls: true,
3214
+ className: "w-full"
3215
+ }, undefined, false, undefined, this)
3216
+ ]
3217
+ }, undefined, true, undefined, this)
3218
+ ]
3219
+ }, undefined, true, undefined, this);
3220
+ })(),
3221
+ showToolCalls && message.tool_calls && message.tool_calls.length > 0 && /* @__PURE__ */ jsxDEV36("div", {
3222
+ className: cn("space-y-2 pt-1", classNames?.toolCalls),
3223
+ children: message.tool_calls.map((tool, idx) => renderToolCall ? renderToolCall(tool, idx) : /* @__PURE__ */ jsxDEV36(Tool, {
3224
+ defaultOpen: idx === 0,
3225
+ children: [
3226
+ /* @__PURE__ */ jsxDEV36(ToolHeader, {
3227
+ title: tool.tool_name,
3228
+ type: "tool-use",
3229
+ state: getToolState(tool)
3230
+ }, undefined, false, undefined, this),
3231
+ /* @__PURE__ */ jsxDEV36(ToolContent, {
3232
+ children: [
3233
+ /* @__PURE__ */ jsxDEV36(ToolInput, {
3234
+ input: tool.tool_args
3235
+ }, undefined, false, undefined, this),
3236
+ tool.content && /* @__PURE__ */ jsxDEV36(ToolOutput, {
3237
+ output: tool.content,
3238
+ errorText: tool.tool_call_error ? "Tool execution failed" : undefined
3239
+ }, undefined, false, undefined, this)
3240
+ ]
3241
+ }, undefined, true, undefined, this)
3242
+ ]
3243
+ }, tool.tool_call_id || idx, true, undefined, this))
3244
+ }, undefined, false, undefined, this),
3245
+ showReferences && message.extra_data?.references && message.extra_data.references.length > 0 && /* @__PURE__ */ jsxDEV36("div", {
3246
+ className: cn("space-y-2 pt-1", classNames?.references),
3247
+ children: [
3248
+ /* @__PURE__ */ jsxDEV36("div", {
3249
+ className: "flex items-center gap-2 text-xs font-medium text-muted-foreground",
3250
+ children: [
3251
+ /* @__PURE__ */ jsxDEV36(FileText, {
3252
+ className: "h-3.5 w-3.5"
3253
+ }, undefined, false, undefined, this),
3254
+ "References (",
3255
+ message.extra_data.references.length,
3256
+ ")"
3257
+ ]
3258
+ }, undefined, true, undefined, this),
3259
+ /* @__PURE__ */ jsxDEV36("div", {
3260
+ className: "space-y-2",
3261
+ children: message.extra_data.references.map((refData, idx) => /* @__PURE__ */ jsxDEV36("div", {
3262
+ className: "text-xs space-y-1.5",
3263
+ children: [
3264
+ refData.query && /* @__PURE__ */ jsxDEV36("div", {
3265
+ className: "font-medium text-foreground",
3266
+ children: [
3267
+ "Query: ",
3268
+ refData.query
3269
+ ]
3270
+ }, undefined, true, undefined, this),
3271
+ refData.references.map((ref, refIdx) => /* @__PURE__ */ jsxDEV36("div", {
3272
+ className: "bg-muted/50 border border-border p-2.5 rounded-lg",
3273
+ children: [
3274
+ /* @__PURE__ */ jsxDEV36("div", {
3275
+ className: "italic text-muted-foreground mb-1",
3276
+ children: [
3277
+ '"',
3278
+ ref.content,
3279
+ '"'
3280
+ ]
3281
+ }, undefined, true, undefined, this),
3282
+ /* @__PURE__ */ jsxDEV36("div", {
3283
+ className: "text-muted-foreground/70",
3284
+ children: [
3285
+ "Source: ",
3286
+ ref.name,
3287
+ " (chunk ",
3288
+ ref.meta_data.chunk,
3289
+ "/",
3290
+ ref.meta_data.chunk_size,
3291
+ ")"
3292
+ ]
3293
+ }, undefined, true, undefined, this)
3294
+ ]
3295
+ }, refIdx, true, undefined, this))
3296
+ ]
3297
+ }, idx, true, undefined, this))
3298
+ }, undefined, false, undefined, this)
3299
+ ]
3300
+ }, undefined, true, undefined, this)
3301
+ ]
3302
+ }, undefined, true, undefined, this),
3303
+ (renderActions || showTimestamp || hasError) && /* @__PURE__ */ jsxDEV36("div", {
3304
+ className: "flex items-center gap-2 pt-1",
3305
+ children: [
3306
+ renderActions && /* @__PURE__ */ jsxDEV36("div", {
3307
+ className: cn("flex items-center gap-1", classNames?.actions),
3308
+ children: renderActions(message)
3309
+ }, undefined, false, undefined, this),
3310
+ hasError && /* @__PURE__ */ jsxDEV36("span", {
3311
+ className: "flex items-center gap-1 text-[11px] text-destructive",
3312
+ children: [
3313
+ /* @__PURE__ */ jsxDEV36(AlertCircle, {
3314
+ className: "h-3 w-3"
3315
+ }, undefined, false, undefined, this),
3316
+ "Error"
3317
+ ]
3318
+ }, undefined, true, undefined, this),
3319
+ showTimestamp && /* @__PURE__ */ jsxDEV36(SmartTimestamp, {
3320
+ date: new Date(message.created_at * 1000),
3321
+ formatShort: isCustomTimestamp ? resolvedFormatTimestamp : undefined,
3322
+ className: "text-[11px] text-muted-foreground"
3323
+ }, undefined, false, undefined, this)
3324
+ ]
3325
+ }, undefined, true, undefined, this)
3326
+ ]
3327
+ }, undefined, true, undefined, this)
3328
+ ]
3329
+ }, undefined, true, undefined, this),
3330
+ preview?.type === "image" && /* @__PURE__ */ jsxDEV36(ImageLightbox, {
3331
+ open: true,
3332
+ onOpenChange: (open) => {
3333
+ if (!open)
3334
+ closePreview();
3335
+ },
3336
+ images: preview.images,
3337
+ initialIndex: preview.initialIndex
3338
+ }, undefined, false, undefined, this),
3339
+ preview?.type === "file" && /* @__PURE__ */ jsxDEV36(FilePreviewModal, {
3340
+ open: true,
3341
+ onOpenChange: (open) => {
3342
+ if (!open)
3343
+ closePreview();
3344
+ },
3345
+ file: preview.file
3346
+ }, undefined, false, undefined, this)
3347
+ ]
3348
+ }, undefined, true, undefined, this);
3349
+ }
3350
+
3351
+ // src/ui/composed/agno-chat/suggested-prompts.tsx
3352
+ import { jsxDEV as jsxDEV37 } from "react/jsx-dev-runtime";
3353
+ function AgnoChatSuggestedPrompts({ className, prompts }) {
3354
+ const { handleSend } = useAgnoChatContext();
3355
+ if (prompts.length === 0)
3356
+ return null;
3357
+ return /* @__PURE__ */ jsxDEV37("div", {
3358
+ className: cn("grid grid-cols-2 gap-2 w-full max-w-md", className),
3359
+ children: prompts.map((prompt, idx) => /* @__PURE__ */ jsxDEV37("button", {
3360
+ onClick: () => handleSend(prompt.text),
3361
+ className: "flex items-center gap-2 px-3 py-2.5 rounded-xl border border-border bg-card hover:bg-accent/50 hover:border-primary/20 transition-all duration-200 text-left text-sm group",
3362
+ children: [
3363
+ prompt.icon && /* @__PURE__ */ jsxDEV37("span", {
3364
+ className: "text-muted-foreground group-hover:text-primary transition-colors",
3365
+ children: prompt.icon
3366
+ }, undefined, false, undefined, this),
3367
+ /* @__PURE__ */ jsxDEV37("span", {
3368
+ className: "text-muted-foreground group-hover:text-foreground transition-colors text-xs leading-snug",
3369
+ children: prompt.text
3370
+ }, undefined, false, undefined, this)
3371
+ ]
3372
+ }, idx, true, undefined, this))
3373
+ }, undefined, false, undefined, this);
3374
+ }
3375
+
3376
+ // src/ui/composed/agno-chat/messages.tsx
3377
+ import { Bot as Bot2 } from "lucide-react";
3378
+ import { jsxDEV as jsxDEV38 } from "react/jsx-dev-runtime";
3379
+ function ScrollOnNewUserMessage({ messageCount }) {
3380
+ const { scrollToBottom } = useStickToBottomContext2();
3381
+ const prevCount = useRef7(messageCount);
3382
+ useEffect6(() => {
3383
+ if (messageCount > prevCount.current) {
3384
+ scrollToBottom("smooth");
3385
+ }
3386
+ prevCount.current = messageCount;
3387
+ }, [messageCount, scrollToBottom]);
3388
+ return null;
3389
+ }
3390
+ var DEFAULT_PROMPTS = [
3391
+ { text: "What can you help me with?" },
3392
+ { text: "Explain how you work" }
3393
+ ];
3394
+ function AgnoChatMessages({
3395
+ className,
3396
+ renderMessage,
3397
+ userAvatar,
3398
+ assistantAvatar,
3399
+ messageItemProps,
3400
+ emptyState,
3401
+ suggestedPrompts = DEFAULT_PROMPTS,
3402
+ children,
3403
+ showThinkingIndicator = true,
3404
+ renderThinkingIndicator
3405
+ }) {
3406
+ const { messages, isStreaming } = useAgnoChatContext();
3407
+ const lastMessage = messages[messages.length - 1];
3408
+ const isThinking = showThinkingIndicator && isStreaming && (!lastMessage || lastMessage.role !== "user") && !lastMessage?.content;
3409
+ const resolvedEmptyState = children ?? emptyState ?? /* @__PURE__ */ jsxDEV38("div", {
3410
+ className: "flex flex-col items-center gap-6",
3411
+ children: [
3412
+ /* @__PURE__ */ jsxDEV38("div", {
3413
+ className: "relative",
3414
+ children: [
3415
+ /* @__PURE__ */ jsxDEV38("div", {
3416
+ className: "h-16 w-16 rounded-2xl bg-primary/10 flex items-center justify-center",
3417
+ children: /* @__PURE__ */ jsxDEV38(Bot2, {
3418
+ className: "h-8 w-8 text-primary"
3419
+ }, undefined, false, undefined, this)
3420
+ }, undefined, false, undefined, this),
3421
+ /* @__PURE__ */ jsxDEV38("div", {
3422
+ className: "absolute -bottom-1 -right-1 h-5 w-5 rounded-full bg-green-500 border-2 border-background flex items-center justify-center",
3423
+ children: /* @__PURE__ */ jsxDEV38("span", {
3424
+ className: "h-2 w-2 rounded-full bg-white animate-pulse"
3425
+ }, undefined, false, undefined, this)
3426
+ }, undefined, false, undefined, this)
3427
+ ]
3428
+ }, undefined, true, undefined, this),
3429
+ /* @__PURE__ */ jsxDEV38("div", {
3430
+ className: "space-y-2 text-center",
3431
+ children: [
3432
+ /* @__PURE__ */ jsxDEV38("h3", {
3433
+ className: "text-xl font-semibold tracking-tight",
3434
+ children: "Welcome to Agno Chat"
3435
+ }, undefined, false, undefined, this),
3436
+ /* @__PURE__ */ jsxDEV38("p", {
3437
+ className: "text-muted-foreground text-sm max-w-sm",
3438
+ children: "Start a conversation with your AI agent. Ask questions, explore ideas, or run tools."
3439
+ }, undefined, false, undefined, this)
3440
+ ]
3441
+ }, undefined, true, undefined, this),
3442
+ suggestedPrompts.length > 0 && /* @__PURE__ */ jsxDEV38(AgnoChatSuggestedPrompts, {
3443
+ prompts: suggestedPrompts
3444
+ }, undefined, false, undefined, this)
3445
+ ]
3446
+ }, undefined, true, undefined, this);
3447
+ return /* @__PURE__ */ jsxDEV38(Conversation, {
3448
+ className: cn("relative flex-1 w-full", className),
3449
+ children: [
3450
+ /* @__PURE__ */ jsxDEV38(ScrollOnNewUserMessage, {
3451
+ messageCount: messages.length
3452
+ }, undefined, false, undefined, this),
3453
+ /* @__PURE__ */ jsxDEV38(ConversationContent, {
3454
+ className: "max-w-3xl mx-auto",
3455
+ children: [
3456
+ messages.length === 0 ? /* @__PURE__ */ jsxDEV38(ConversationEmptyState, {
3457
+ children: resolvedEmptyState
3458
+ }, undefined, false, undefined, this) : messages.map((message, index) => {
3459
+ if (isThinking && index === messages.length - 1 && message === lastMessage)
3460
+ return null;
3461
+ return renderMessage ? renderMessage(message, index) : /* @__PURE__ */ jsxDEV38(AgnoMessageItem, {
3462
+ message,
3463
+ userAvatar,
3464
+ assistantAvatar,
3465
+ ...messageItemProps
3466
+ }, `msg-${index}-${message.created_at}`, false, undefined, this);
3467
+ }),
3468
+ isThinking && /* @__PURE__ */ jsxDEV38("div", {
3469
+ className: "py-2",
3470
+ children: renderThinkingIndicator ?? /* @__PURE__ */ jsxDEV38(StreamingIndicator, {
3471
+ avatar: assistantAvatar
3472
+ }, undefined, false, undefined, this)
3473
+ }, undefined, false, undefined, this)
3474
+ ]
3475
+ }, undefined, true, undefined, this),
3476
+ /* @__PURE__ */ jsxDEV38(ConversationScrollButton, {}, undefined, false, undefined, this)
3477
+ ]
3478
+ }, undefined, true, undefined, this);
3479
+ }
3480
+
3481
+ // src/ui/composed/agno-chat/empty-state.tsx
3482
+ import { jsxDEV as jsxDEV39 } from "react/jsx-dev-runtime";
3483
+ function AgnoChatEmptyState({ children, className, ...props }) {
3484
+ return /* @__PURE__ */ jsxDEV39("div", {
3485
+ className: cn("flex flex-col items-center gap-6", className),
3486
+ ...props,
3487
+ children
3488
+ }, undefined, false, undefined, this);
3489
+ }
3490
+
3491
+ // src/ui/composed/agno-chat/tool-status.tsx
3492
+ import { Loader2 as Loader22, Wrench } from "lucide-react";
3493
+ import { jsxDEV as jsxDEV40, Fragment as Fragment6 } from "react/jsx-dev-runtime";
3494
+ function AgnoChatToolStatus({ className }) {
3495
+ const { isPaused, isExecuting, pendingTools } = useAgnoChatContext();
3496
+ if (!isPaused && !isExecuting)
3497
+ return null;
3498
+ return /* @__PURE__ */ jsxDEV40("div", {
3499
+ className: cn("px-4 py-2.5 border-t border-border bg-primary/5", className),
3500
+ children: /* @__PURE__ */ jsxDEV40("div", {
3501
+ className: "flex items-center gap-2.5 text-sm max-w-3xl mx-auto",
3502
+ children: isExecuting ? /* @__PURE__ */ jsxDEV40(Fragment6, {
3503
+ children: [
3504
+ /* @__PURE__ */ jsxDEV40("div", {
3505
+ className: "h-5 w-5 rounded-full bg-primary/10 flex items-center justify-center",
3506
+ children: /* @__PURE__ */ jsxDEV40(Loader22, {
3507
+ className: "h-3 w-3 animate-spin text-primary"
3508
+ }, undefined, false, undefined, this)
3509
+ }, undefined, false, undefined, this),
3510
+ /* @__PURE__ */ jsxDEV40("span", {
3511
+ className: "text-muted-foreground",
3512
+ children: [
3513
+ "Executing",
3514
+ " ",
3515
+ /* @__PURE__ */ jsxDEV40("span", {
3516
+ className: "font-medium text-foreground",
3517
+ children: pendingTools.length
3518
+ }, undefined, false, undefined, this),
3519
+ " tool",
3520
+ pendingTools.length !== 1 ? "s" : "",
3521
+ "..."
3522
+ ]
3523
+ }, undefined, true, undefined, this)
3524
+ ]
3525
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV40(Fragment6, {
3526
+ children: [
3527
+ /* @__PURE__ */ jsxDEV40("div", {
3528
+ className: "h-5 w-5 rounded-full bg-amber-500/10 flex items-center justify-center",
3529
+ children: /* @__PURE__ */ jsxDEV40(Wrench, {
3530
+ className: "h-3 w-3 text-amber-600 dark:text-amber-400"
3531
+ }, undefined, false, undefined, this)
3532
+ }, undefined, false, undefined, this),
3533
+ /* @__PURE__ */ jsxDEV40("span", {
3534
+ className: "text-muted-foreground",
3535
+ children: [
3536
+ "Preparing",
3537
+ " ",
3538
+ /* @__PURE__ */ jsxDEV40("span", {
3539
+ className: "font-medium text-foreground",
3540
+ children: pendingTools.length
3541
+ }, undefined, false, undefined, this),
3542
+ " tool",
3543
+ pendingTools.length !== 1 ? "s" : "",
3544
+ "..."
3545
+ ]
3546
+ }, undefined, true, undefined, this)
3547
+ ]
3548
+ }, undefined, true, undefined, this)
3549
+ }, undefined, false, undefined, this)
3550
+ }, undefined, false, undefined, this);
3551
+ }
3552
+
3553
+ // src/ui/composed/agno-chat/error-bar.tsx
3554
+ import { jsxDEV as jsxDEV41 } from "react/jsx-dev-runtime";
3555
+ function AgnoChatErrorBar({ className }) {
3556
+ const { error, executionError } = useAgnoChatContext();
3557
+ const message = error || executionError;
3558
+ if (!message)
3559
+ return null;
3560
+ return /* @__PURE__ */ jsxDEV41("div", {
3561
+ className: cn("px-4 py-2.5 bg-destructive/5 border-t border-destructive/20", className),
3562
+ children: /* @__PURE__ */ jsxDEV41("p", {
3563
+ className: "text-sm text-destructive max-w-3xl mx-auto",
3564
+ children: message
3565
+ }, undefined, false, undefined, this)
3566
+ }, undefined, false, undefined, this);
3567
+ }
3568
+
3569
+ // src/ui/composed/AgnoChatInput.tsx
3570
+ import { CircleStop } from "lucide-react";
3571
+ import { jsxDEV as jsxDEV42 } from "react/jsx-dev-runtime";
3572
+ var DEFAULT_ACCEPTED_FILE_TYPES = "image/*,audio/*,.pdf,.doc,.docx,.txt,.csv,.xlsx,.xls,.ppt,.pptx,.md,.json,.xml";
3573
+ function dataUrlToBlob(dataUrl) {
3574
+ const [header, base64] = dataUrl.split(",");
3575
+ const mime = header.match(/:(.*?);/)?.[1] || "application/octet-stream";
3576
+ const bytes = atob(base64);
3577
+ const buf = new Uint8Array(bytes.length);
3578
+ for (let i = 0;i < bytes.length; i++) {
3579
+ buf[i] = bytes.charCodeAt(i);
3580
+ }
3581
+ return new Blob([buf], { type: mime });
3582
+ }
3583
+ function CancelButton({ onCancel }) {
3584
+ return /* @__PURE__ */ jsxDEV42(Button, {
3585
+ type: "button",
3586
+ variant: "destructive",
3587
+ size: "icon",
3588
+ className: "h-8 w-8 rounded-lg",
3589
+ onClick: onCancel,
3590
+ "aria-label": "Stop",
3591
+ children: /* @__PURE__ */ jsxDEV42(CircleStop, {
3592
+ className: "size-4"
3593
+ }, undefined, false, undefined, this)
3594
+ }, undefined, false, undefined, this);
3595
+ }
3596
+ function SubmitButton({ disabled, status }) {
3597
+ const { textInput } = usePromptInputController();
3598
+ const hasText = textInput.value.trim().length > 0;
3599
+ return /* @__PURE__ */ jsxDEV42(PromptInputSubmit, {
3600
+ disabled: disabled || !hasText,
3601
+ status
3602
+ }, undefined, false, undefined, this);
3603
+ }
3604
+ function AttachmentHeader() {
3605
+ const { files } = usePromptInputAttachments();
3606
+ if (files.length === 0)
3607
+ return null;
3608
+ return /* @__PURE__ */ jsxDEV42(PromptInputHeader, {
3609
+ children: /* @__PURE__ */ jsxDEV42(PromptInputAttachments, {
3610
+ children: (attachment) => /* @__PURE__ */ jsxDEV42(PromptInputAttachment, {
3611
+ data: attachment
3612
+ }, undefined, false, undefined, this)
3613
+ }, undefined, false, undefined, this)
3614
+ }, undefined, false, undefined, this);
3615
+ }
3616
+ function TranscribeAudioRecorder({
3617
+ endpoint,
3618
+ headers,
3619
+ disabled,
3620
+ parseResponse,
3621
+ onRequestPermission,
3622
+ labels
3623
+ }) {
3624
+ const { textInput } = usePromptInputController();
3625
+ return /* @__PURE__ */ jsxDEV42(AudioRecorder, {
3626
+ mode: "transcribe",
3627
+ transcriptionEndpoint: endpoint,
3628
+ transcriptionHeaders: headers,
3629
+ parseTranscriptionResponse: parseResponse,
3630
+ onRequestPermission,
3631
+ onRecordingComplete: () => {},
3632
+ onTranscriptionComplete: (text) => {
3633
+ const current = textInput.value;
3634
+ textInput.setInput(current + (current ? " " : "") + text);
3635
+ },
3636
+ disabled,
3637
+ labels
3638
+ }, undefined, false, undefined, this);
3639
+ }
3640
+ function AgnoChatInput({
3641
+ onSend,
3642
+ disabled,
3643
+ placeholder,
3644
+ className,
3645
+ fileUpload,
3646
+ showAudioRecorder = false,
3647
+ showAttachments = true,
3648
+ status,
3649
+ isStreaming,
3650
+ onCancel,
3651
+ allowCancelRun = false,
3652
+ extraTools,
3653
+ audioMode = "send",
3654
+ transcriptionEndpoint,
3655
+ transcriptionHeaders,
3656
+ parseTranscriptionResponse,
3657
+ onRequestPermission,
3658
+ audioRecorderLabels,
3659
+ dropZoneContainerRef,
3660
+ dropZoneProps
3661
+ }) {
3662
+ const handleSubmit = (message) => {
3663
+ const text = message.text?.trim() || "";
3664
+ const files = message.files || [];
3665
+ if (!text)
3666
+ return;
3667
+ if (files.length === 0) {
3668
+ onSend(text);
3669
+ return;
3670
+ }
3671
+ const formData = new FormData;
3672
+ formData.append("message", text);
3673
+ for (const file of files) {
3674
+ if (!file.url)
3675
+ continue;
3676
+ const blob = file.url.startsWith("data:") ? dataUrlToBlob(file.url) : null;
3677
+ if (!blob)
3678
+ continue;
3679
+ const fileName = file.filename || "file";
3680
+ formData.append("files", blob, fileName);
3681
+ }
3682
+ onSend(formData);
3683
+ };
3684
+ const handleAudioRecording = (blob) => {
3685
+ const formData = new FormData;
3686
+ formData.append("message", "Audio message");
3687
+ formData.append("files", blob, `recording-${Date.now()}.wav`);
3688
+ onSend(formData);
3689
+ };
3690
+ const computedStatus = status ?? (disabled ? "submitted" : undefined);
3691
+ const showCancelButton = allowCancelRun && isStreaming && onCancel;
3692
+ return /* @__PURE__ */ jsxDEV42(PromptInputProvider, {
3693
+ children: /* @__PURE__ */ jsxDEV42(PromptInput, {
3694
+ onSubmit: handleSubmit,
3695
+ accept: fileUpload?.accept ?? DEFAULT_ACCEPTED_FILE_TYPES,
3696
+ multiple: fileUpload?.multiple ?? true,
3697
+ maxFiles: fileUpload?.maxFiles,
3698
+ maxFileSize: fileUpload?.maxFileSize,
3699
+ globalDrop: !!dropZoneContainerRef,
3700
+ dragListenerTarget: dropZoneContainerRef,
3701
+ className: cn("w-full", className),
3702
+ children: [
3703
+ /* @__PURE__ */ jsxDEV42(AttachmentHeader, {}, undefined, false, undefined, this),
3704
+ /* @__PURE__ */ jsxDEV42(PromptInputBody, {
3705
+ children: /* @__PURE__ */ jsxDEV42(PromptInputTextarea, {
3706
+ placeholder: placeholder || "Type your message... (Enter to send, Shift+Enter for new line)",
3707
+ disabled
3708
+ }, undefined, false, undefined, this)
3709
+ }, undefined, false, undefined, this),
3710
+ /* @__PURE__ */ jsxDEV42(PromptInputFooter, {
3711
+ children: [
3712
+ /* @__PURE__ */ jsxDEV42(PromptInputTools, {
3713
+ children: [
3714
+ showAttachments && /* @__PURE__ */ jsxDEV42(PromptInputActionMenu, {
3715
+ children: [
3716
+ /* @__PURE__ */ jsxDEV42(PromptInputActionMenuTrigger, {}, undefined, false, undefined, this),
3717
+ /* @__PURE__ */ jsxDEV42(PromptInputActionMenuContent, {
3718
+ children: /* @__PURE__ */ jsxDEV42(PromptInputActionAddAttachments, {
3719
+ label: "Add files"
3720
+ }, undefined, false, undefined, this)
3721
+ }, undefined, false, undefined, this)
3722
+ ]
3723
+ }, undefined, true, undefined, this),
3724
+ showAudioRecorder && (audioMode === "transcribe" && transcriptionEndpoint ? /* @__PURE__ */ jsxDEV42(TranscribeAudioRecorder, {
3725
+ endpoint: transcriptionEndpoint,
3726
+ headers: transcriptionHeaders,
3727
+ disabled,
3728
+ parseResponse: parseTranscriptionResponse,
3729
+ onRequestPermission,
3730
+ labels: audioRecorderLabels
3731
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV42(AudioRecorder, {
3732
+ onRecordingComplete: handleAudioRecording,
3733
+ disabled,
3734
+ onRequestPermission,
3735
+ labels: audioRecorderLabels
3736
+ }, undefined, false, undefined, this)),
3737
+ extraTools
3738
+ ]
3739
+ }, undefined, true, undefined, this),
3740
+ showCancelButton ? /* @__PURE__ */ jsxDEV42(CancelButton, {
3741
+ onCancel
3742
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV42(SubmitButton, {
3743
+ disabled,
3744
+ status: computedStatus
3745
+ }, undefined, false, undefined, this)
3746
+ ]
3747
+ }, undefined, true, undefined, this),
3748
+ showAttachments && /* @__PURE__ */ jsxDEV42(PromptInputDropZone, {
3749
+ ...dropZoneProps,
3750
+ container: dropZoneContainerRef
3751
+ }, undefined, false, undefined, this)
3752
+ ]
3753
+ }, undefined, true, undefined, this)
3754
+ }, undefined, false, undefined, this);
3755
+ }
3756
+
3757
+ // src/ui/composed/agno-chat/input.tsx
3758
+ import { jsxDEV as jsxDEV43 } from "react/jsx-dev-runtime";
3759
+ function AgnoChatInputArea({
3760
+ className,
3761
+ children,
3762
+ placeholder,
3763
+ fileUpload,
3764
+ showAudioRecorder = false,
3765
+ showAttachments,
3766
+ extraTools,
3767
+ chatInputProps,
3768
+ audioMode,
3769
+ transcriptionEndpoint,
3770
+ transcriptionHeaders,
3771
+ parseTranscriptionResponse,
3772
+ onRequestPermission,
3773
+ audioRecorderLabels,
3774
+ allowCancelRun = false,
3775
+ dropZoneProps
3776
+ }) {
3777
+ const { handleSend, inputDisabled, isStreaming, isPaused, cancelRun, dropZoneContainerRef } = useAgnoChatContext();
3778
+ return /* @__PURE__ */ jsxDEV43("div", {
3779
+ className: cn("border-t border-border bg-background/80 backdrop-blur-sm", className),
3780
+ children: /* @__PURE__ */ jsxDEV43("div", {
3781
+ className: "mx-auto px-4 py-2",
3782
+ children: children ? children({ onSend: handleSend, disabled: inputDisabled, isStreaming, isPaused }) : /* @__PURE__ */ jsxDEV43(AgnoChatInput, {
3783
+ ...chatInputProps,
3784
+ onSend: handleSend,
3785
+ disabled: inputDisabled,
3786
+ isStreaming,
3787
+ onCancel: cancelRun,
3788
+ allowCancelRun,
3789
+ placeholder: placeholder ?? chatInputProps?.placeholder ?? "Message your agent...",
3790
+ fileUpload,
3791
+ showAudioRecorder,
3792
+ showAttachments,
3793
+ extraTools,
3794
+ audioMode,
3795
+ transcriptionEndpoint,
3796
+ transcriptionHeaders,
3797
+ parseTranscriptionResponse,
3798
+ onRequestPermission,
3799
+ audioRecorderLabels,
3800
+ dropZoneContainerRef,
3801
+ dropZoneProps
3802
+ }, undefined, false, undefined, this)
3803
+ }, undefined, false, undefined, this)
3804
+ }, undefined, false, undefined, this);
3805
+ }
3806
+
3807
+ // src/ui/composed/agno-chat/index.ts
3808
+ var AgnoChat = Object.assign(AgnoChatRoot, {
3809
+ Messages: AgnoChatMessages,
3810
+ EmptyState: AgnoChatEmptyState,
3811
+ SuggestedPrompts: AgnoChatSuggestedPrompts,
3812
+ ToolStatus: AgnoChatToolStatus,
3813
+ ErrorBar: AgnoChatErrorBar,
3814
+ Input: AgnoChatInputArea
3815
+ });
3816
+
3817
+ // src/ui/composed/AgnoChatInterface.tsx
3818
+ import { Bot as Bot3, Sparkles } from "lucide-react";
3819
+ import { jsxDEV as jsxDEV44 } from "react/jsx-dev-runtime";
3820
+ var DEFAULT_PROMPTS2 = [
3821
+ { icon: /* @__PURE__ */ jsxDEV44(Sparkles, {
3822
+ className: "h-3.5 w-3.5"
3823
+ }, undefined, false, undefined, this), text: "What can you help me with?" },
3824
+ { icon: /* @__PURE__ */ jsxDEV44(Bot3, {
3825
+ className: "h-3.5 w-3.5"
3826
+ }, undefined, false, undefined, this), text: "Explain how you work" }
3827
+ ];
3828
+ function AgnoChatInterface({
3829
+ className,
3830
+ classNames,
3831
+ renderMessage,
3832
+ renderInput,
3833
+ emptyState,
3834
+ headerSlot,
3835
+ inputToolbarSlot,
3836
+ suggestedPrompts = DEFAULT_PROMPTS2,
3837
+ toolHandlers = {},
3838
+ autoExecuteTools = true,
3839
+ placeholder,
3840
+ userAvatar,
3841
+ assistantAvatar,
3842
+ fileUpload,
3843
+ showAudioRecorder = true,
3844
+ showAttachments = true,
3845
+ messageItemProps,
3846
+ chatInputProps,
3847
+ dropZoneLabel
3848
+ }) {
3849
+ return /* @__PURE__ */ jsxDEV44(AgnoChat, {
3850
+ toolHandlers,
3851
+ autoExecuteTools,
3852
+ className: cn(classNames?.root, className),
3853
+ children: [
3854
+ headerSlot,
3855
+ /* @__PURE__ */ jsxDEV44(AgnoChat.Messages, {
3856
+ className: classNames?.messagesArea,
3857
+ renderMessage,
3858
+ userAvatar,
3859
+ assistantAvatar,
3860
+ messageItemProps,
3861
+ emptyState,
3862
+ suggestedPrompts
3863
+ }, undefined, false, undefined, this),
3864
+ /* @__PURE__ */ jsxDEV44(AgnoChat.ToolStatus, {
3865
+ className: classNames?.toolStatusBar
3866
+ }, undefined, false, undefined, this),
3867
+ /* @__PURE__ */ jsxDEV44(AgnoChat.ErrorBar, {
3868
+ className: classNames?.errorBar
3869
+ }, undefined, false, undefined, this),
3870
+ /* @__PURE__ */ jsxDEV44(AgnoChat.Input, {
3871
+ className: classNames?.inputArea,
3872
+ placeholder,
3873
+ fileUpload,
3874
+ showAudioRecorder,
3875
+ showAttachments,
3876
+ extraTools: inputToolbarSlot,
3877
+ chatInputProps,
3878
+ dropZoneProps: { className: classNames?.dropZone, label: dropZoneLabel },
3879
+ children: renderInput ? ({ onSend, disabled }) => renderInput({ onSend, disabled }) : undefined
3880
+ }, undefined, false, undefined, this)
3881
+ ]
3882
+ }, undefined, true, undefined, this);
3883
+ }
3884
+ export {
3885
+ useProviderAttachments,
3886
+ usePromptInputDropZone,
3887
+ usePromptInputController,
3888
+ usePromptInputAttachments,
3889
+ useAgnoChatContext,
3890
+ isPreviewable,
3891
+ getFilePreviewType,
3892
+ getFileExtension,
3893
+ formatSmartTimestamp,
3894
+ formatFullTimestamp,
3895
+ formatFileSize,
3896
+ cn,
3897
+ buttonVariants,
3898
+ badgeVariants,
3899
+ TooltipTrigger,
3900
+ TooltipProvider,
3901
+ TooltipContent,
3902
+ Tooltip,
3903
+ ToolOutput,
3904
+ ToolInput,
3905
+ ToolHeader,
3906
+ ToolContent,
3907
+ Tool,
3908
+ StreamingIndicator,
3909
+ SmartTimestamp,
3910
+ SelectValue,
3911
+ SelectTrigger,
3912
+ SelectSeparator,
3913
+ SelectScrollUpButton,
3914
+ SelectScrollDownButton,
3915
+ SelectLabel,
3916
+ SelectItem,
3917
+ SelectGroup,
3918
+ SelectContent,
3919
+ Select,
3920
+ Response,
3921
+ PromptInputTools,
3922
+ PromptInputTextarea,
3923
+ PromptInputTabsList,
3924
+ PromptInputTabLabel,
3925
+ PromptInputTabItem,
3926
+ PromptInputTabBody,
3927
+ PromptInputTab,
3928
+ PromptInputSubmit,
3929
+ PromptInputSpeechButton,
3930
+ PromptInputProvider,
3931
+ PromptInputModelSelectValue,
3932
+ PromptInputModelSelectTrigger,
3933
+ PromptInputModelSelectItem,
3934
+ PromptInputModelSelectContent,
3935
+ PromptInputModelSelect,
3936
+ PromptInputHeader,
3937
+ PromptInputFooter,
3938
+ PromptInputDropZone,
3939
+ PromptInputCommandSeparator,
3940
+ PromptInputCommandList,
3941
+ PromptInputCommandItem,
3942
+ PromptInputCommandInput,
3943
+ PromptInputCommandGroup,
3944
+ PromptInputCommandEmpty,
3945
+ PromptInputCommand,
3946
+ PromptInputButton,
3947
+ PromptInputBody,
3948
+ PromptInputAttachments,
3949
+ PromptInputAttachment,
3950
+ PromptInputActionMenuTrigger,
3951
+ PromptInputActionMenuItem,
3952
+ PromptInputActionMenuContent,
3953
+ PromptInputActionMenu,
3954
+ PromptInputActionAddAttachments,
3955
+ PromptInput,
3956
+ MessageContent,
3957
+ MessageAvatar,
3958
+ Message,
3959
+ InputGroupTextarea,
3960
+ InputGroupText,
3961
+ InputGroupInput,
3962
+ InputGroupButton,
3963
+ InputGroupAddon,
3964
+ InputGroup,
3965
+ ImageLightbox,
3966
+ HoverCardTrigger,
3967
+ HoverCardContent,
3968
+ HoverCard,
3969
+ FilePreviewModal,
3970
+ FilePreviewCard,
3971
+ DropdownMenuTrigger,
3972
+ DropdownMenuSubTrigger,
3973
+ DropdownMenuSubContent,
3974
+ DropdownMenuSub,
3975
+ DropdownMenuShortcut,
3976
+ DropdownMenuSeparator,
3977
+ DropdownMenuRadioItem,
3978
+ DropdownMenuRadioGroup,
3979
+ DropdownMenuPortal,
3980
+ DropdownMenuLabel,
3981
+ DropdownMenuItem,
3982
+ DropdownMenuGroup,
3983
+ DropdownMenuContent,
3984
+ DropdownMenuCheckboxItem,
3985
+ DropdownMenu,
3986
+ DialogTrigger,
3987
+ DialogTitle,
3988
+ DialogPortal,
3989
+ DialogOverlay,
3990
+ DialogHeader,
3991
+ DialogFooter,
3992
+ DialogDescription,
3993
+ DialogContent,
3994
+ DialogClose,
3995
+ Dialog,
3996
+ ConversationScrollButton,
3997
+ ConversationEmptyState,
3998
+ ConversationContent,
3999
+ Conversation,
4000
+ CommandShortcut,
4001
+ CommandSeparator,
4002
+ CommandList,
4003
+ CommandItem,
4004
+ CommandInput,
4005
+ CommandGroup,
4006
+ CommandEmpty,
4007
+ Command,
4008
+ CollapsibleTrigger2 as CollapsibleTrigger,
4009
+ CollapsibleContent2 as CollapsibleContent,
4010
+ Collapsible,
4011
+ CodeBlockCopyButton,
4012
+ CodeBlock,
4013
+ Button,
4014
+ Badge,
4015
+ AvatarImage,
4016
+ AvatarFallback,
4017
+ Avatar,
4018
+ AudioRecorder,
4019
+ ArtifactTitle,
4020
+ ArtifactHeader,
4021
+ ArtifactDescription,
4022
+ ArtifactContent,
4023
+ ArtifactClose,
4024
+ ArtifactActions,
4025
+ ArtifactAction,
4026
+ Artifact,
4027
+ AgnoMessageItem,
4028
+ AgnoChatToolStatus,
4029
+ AgnoChatSuggestedPrompts,
4030
+ AgnoChatRoot,
4031
+ AgnoChatMessages,
4032
+ AgnoChatInterface,
4033
+ AgnoChatInputArea,
4034
+ AgnoChatInput,
4035
+ AgnoChatErrorBar,
4036
+ AgnoChatEmptyState,
4037
+ AgnoChat,
4038
+ AccordionTrigger,
4039
+ AccordionItem,
4040
+ AccordionContent,
4041
+ Accordion
4042
+ };
4043
+
4044
+ //# debugId=2F56CC8E4E8AD83564756E2164756E21