@agents24/chat-react 0.5.0 → 0.5.1

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 (133) hide show
  1. package/README.md +90 -21
  2. package/compatibility.json +10 -10
  3. package/dist/chunk-SSUO4EPD.js +189 -0
  4. package/dist/chunk-SSUO4EPD.js.map +1 -0
  5. package/dist/chunk-ZCNHLFRB.js +108 -0
  6. package/dist/chunk-ZCNHLFRB.js.map +1 -0
  7. package/dist/index.cjs +112 -95
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.ts +0 -1
  10. package/dist/index.js +362 -68
  11. package/dist/index.js.map +1 -1
  12. package/dist/mcp-oauth.d.ts +13 -0
  13. package/dist/runtime/index.cjs +594 -0
  14. package/dist/runtime/index.cjs.map +1 -0
  15. package/dist/runtime/index.d.ts +2 -0
  16. package/dist/runtime/index.js +458 -0
  17. package/dist/runtime/index.js.map +1 -0
  18. package/dist/runtime/input-contract.d.ts +20 -0
  19. package/dist/runtime/use-agent-chat-runtime.d.ts +83 -0
  20. package/dist/scaffold/app.d.ts +30 -0
  21. package/dist/scaffold/components/chat/chat-composer.d.ts +21 -0
  22. package/dist/scaffold/components/chat/chat-message.d.ts +21 -0
  23. package/dist/scaffold/components/chat/chat-shell.d.ts +8 -0
  24. package/dist/scaffold/components/chat/collapsible-user-message.d.ts +3 -0
  25. package/dist/scaffold/components/chat/external-link-dialog.d.ts +2 -0
  26. package/dist/scaffold/components/chat/identity-control.d.ts +4 -0
  27. package/dist/scaffold/components/chat/message-parts.d.ts +12 -0
  28. package/dist/scaffold/components/chat/theme-menu.d.ts +1 -0
  29. package/dist/scaffold/components/chat/thread-sidebar.d.ts +16 -0
  30. package/dist/scaffold/components/chat/timeline-loading.d.ts +7 -0
  31. package/dist/scaffold/components/chat/turn-outline.d.ts +4 -0
  32. package/dist/scaffold/components/theme-provider.d.ts +20 -0
  33. package/dist/scaffold/components/ui/attachment.d.ts +24 -0
  34. package/dist/scaffold/components/ui/bubble.d.ts +17 -0
  35. package/dist/scaffold/components/ui/button-group.d.ts +11 -0
  36. package/dist/scaffold/components/ui/button.d.ts +10 -0
  37. package/dist/scaffold/components/ui/dialog.d.ts +17 -0
  38. package/dist/scaffold/components/ui/dropdown-menu.d.ts +29 -0
  39. package/dist/scaffold/components/ui/input.d.ts +3 -0
  40. package/dist/scaffold/components/ui/marker.d.ts +11 -0
  41. package/dist/scaffold/components/ui/message-scroller.d.ts +10 -0
  42. package/dist/scaffold/components/ui/message.d.ts +10 -0
  43. package/dist/scaffold/components/ui/popover.d.ts +6 -0
  44. package/dist/scaffold/components/ui/select.d.ts +8 -0
  45. package/dist/scaffold/components/ui/separator.d.ts +4 -0
  46. package/dist/scaffold/components/ui/sheet.d.ts +14 -0
  47. package/dist/scaffold/components/ui/sidebar.d.ts +69 -0
  48. package/dist/scaffold/components/ui/skeleton.d.ts +2 -0
  49. package/dist/scaffold/components/ui/textarea.d.ts +3 -0
  50. package/dist/scaffold/components/ui/tooltip.d.ts +15 -0
  51. package/dist/scaffold/hooks/use-mobile.d.ts +1 -0
  52. package/dist/scaffold/identity.d.ts +10 -0
  53. package/dist/scaffold/index.cjs +2270 -0
  54. package/dist/scaffold/index.cjs.map +1 -0
  55. package/dist/scaffold/index.d.ts +14 -0
  56. package/dist/scaffold/index.js +2244 -0
  57. package/dist/scaffold/index.js.map +1 -0
  58. package/dist/scaffold/lib/utils.d.ts +2 -0
  59. package/dist/styles.css +137 -378
  60. package/dist/types.d.ts +3 -13
  61. package/dist/ui/adapters.d.ts +1 -1
  62. package/dist/ui/agent-chat-actions.d.ts +12 -5
  63. package/dist/ui/agent-chat-composer.d.ts +2 -1
  64. package/dist/ui/agent-chat-context-compression-row.d.ts +5 -0
  65. package/dist/ui/agent-chat-context-status.d.ts +13 -0
  66. package/dist/ui/agent-chat-message.d.ts +7 -5
  67. package/dist/ui/agent-response-timeline.d.ts +29 -7
  68. package/dist/ui/ask-user-interaction-state.d.ts +20 -0
  69. package/dist/ui/ask-user-interaction.d.ts +8 -0
  70. package/dist/ui/index.cjs +1391 -271
  71. package/dist/ui/index.cjs.map +1 -1
  72. package/dist/ui/index.d.ts +5 -0
  73. package/dist/ui/index.js +2380 -65
  74. package/dist/ui/index.js.map +1 -1
  75. package/dist/ui/tool-sessions.d.ts +70 -0
  76. package/dist/ui/use-audio-recorder.d.ts +8 -0
  77. package/package.json +27 -12
  78. package/scaffold/components.json +25 -0
  79. package/scaffold/manifest.json +28 -0
  80. package/scaffold/src/app.tsx +71 -0
  81. package/scaffold/src/chat.css +54 -0
  82. package/scaffold/src/components/chat/chat-composer.tsx +237 -0
  83. package/scaffold/src/components/chat/chat-message.tsx +76 -0
  84. package/scaffold/src/components/chat/chat-shell.tsx +257 -0
  85. package/scaffold/src/components/chat/collapsible-user-message.tsx +37 -0
  86. package/scaffold/src/components/chat/external-link-dialog.tsx +48 -0
  87. package/scaffold/src/components/chat/identity-control.tsx +69 -0
  88. package/scaffold/src/components/chat/message-parts.tsx +83 -0
  89. package/scaffold/src/components/chat/theme-menu.tsx +79 -0
  90. package/scaffold/src/components/chat/thread-sidebar.tsx +114 -0
  91. package/scaffold/src/components/chat/timeline-loading.ts +17 -0
  92. package/scaffold/src/components/chat/turn-outline.tsx +73 -0
  93. package/scaffold/src/components/theme-provider.tsx +91 -0
  94. package/scaffold/src/components/ui/attachment.tsx +204 -0
  95. package/scaffold/src/components/ui/bubble.tsx +125 -0
  96. package/scaffold/src/components/ui/button-group.tsx +83 -0
  97. package/scaffold/src/components/ui/button.tsx +65 -0
  98. package/scaffold/src/components/ui/dialog.tsx +171 -0
  99. package/scaffold/src/components/ui/dropdown-menu.tsx +271 -0
  100. package/scaffold/src/components/ui/input.tsx +19 -0
  101. package/scaffold/src/components/ui/marker.tsx +69 -0
  102. package/scaffold/src/components/ui/message-scroller.tsx +129 -0
  103. package/scaffold/src/components/ui/message.tsx +92 -0
  104. package/scaffold/src/components/ui/popover.tsx +40 -0
  105. package/scaffold/src/components/ui/select.tsx +92 -0
  106. package/scaffold/src/components/ui/separator.tsx +28 -0
  107. package/scaffold/src/components/ui/sheet.tsx +150 -0
  108. package/scaffold/src/components/ui/sidebar.tsx +677 -0
  109. package/scaffold/src/components/ui/skeleton.tsx +13 -0
  110. package/scaffold/src/components/ui/textarea.tsx +18 -0
  111. package/scaffold/src/components/ui/tooltip.tsx +56 -0
  112. package/scaffold/src/hooks/use-mobile.ts +24 -0
  113. package/scaffold/src/identity.ts +17 -0
  114. package/scaffold/src/index.css +222 -0
  115. package/scaffold/src/index.tsx +39 -0
  116. package/scaffold/src/lib/utils.ts +6 -0
  117. package/scaffold/styles.css +3 -0
  118. package/dist/chunk-CHAU7FNW.js +0 -140
  119. package/dist/chunk-CHAU7FNW.js.map +0 -1
  120. package/dist/chunk-LI67M74F.js +0 -445
  121. package/dist/chunk-LI67M74F.js.map +0 -1
  122. package/dist/chunk-R7WFL3YR.js +0 -1327
  123. package/dist/chunk-R7WFL3YR.js.map +0 -1
  124. package/dist/renderers.d.ts +0 -10
  125. package/dist/templates/agent-chat-app.d.ts +0 -18
  126. package/dist/templates/agent-chat-layout.d.ts +0 -77
  127. package/dist/templates/agent-chat-shell.d.ts +0 -37
  128. package/dist/templates/appearance-control.d.ts +0 -5
  129. package/dist/templates/index.cjs +0 -2600
  130. package/dist/templates/index.cjs.map +0 -1
  131. package/dist/templates/index.d.ts +0 -4
  132. package/dist/templates/index.js +0 -846
  133. package/dist/templates/index.js.map +0 -1
@@ -0,0 +1,2244 @@
1
+ // scaffold/src/app.tsx
2
+ import {
3
+ useAgentChatRuntime
4
+ } from "@agents24/chat-react/runtime";
5
+ import {
6
+ Agents24Provider
7
+ } from "@agents24/react";
8
+
9
+ // scaffold/src/components/chat/chat-shell.tsx
10
+ import {
11
+ agentChatRuntimeErrorMessage
12
+ } from "@agents24/chat-react/runtime";
13
+ import { CircleAlert, LoaderCircle as LoaderCircle3, SquarePen as SquarePen2, X as X2 } from "lucide-react";
14
+
15
+ // scaffold/src/components/chat/chat-composer.tsx
16
+ import { ArrowUp, LoaderCircle, Mic, Square, X } from "lucide-react";
17
+ import * as React2 from "react";
18
+ import { AgentChatContextStatus, useAudioRecorder } from "@agents24/chat-react/ui";
19
+ import { canonicalInputMimeType, inputMimeTypes, validateAgentChatSubmission } from "@agents24/chat-react/runtime";
20
+
21
+ // scaffold/src/components/ui/button.tsx
22
+ import { cva } from "class-variance-authority";
23
+ import { Slot } from "radix-ui";
24
+
25
+ // scaffold/src/lib/utils.ts
26
+ import { clsx } from "clsx";
27
+ import { twMerge } from "tailwind-merge";
28
+ function cn(...inputs) {
29
+ return twMerge(clsx(inputs));
30
+ }
31
+
32
+ // scaffold/src/components/ui/button.tsx
33
+ import { jsx } from "react/jsx-runtime";
34
+ var buttonVariants = cva(
35
+ "group/button inline-flex shrink-0 items-center justify-center rounded-4xl border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
36
+ {
37
+ variants: {
38
+ variant: {
39
+ default: "bg-primary text-primary-foreground hover:bg-primary/80",
40
+ outline: "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-transparent dark:hover:bg-input/30",
41
+ secondary: "bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
42
+ ghost: "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
43
+ destructive: "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
44
+ link: "text-primary underline-offset-4 hover:underline"
45
+ },
46
+ size: {
47
+ default: "h-9 gap-1.5 px-3 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5",
48
+ xs: "h-6 gap-1 px-2.5 text-xs has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3",
49
+ sm: "h-8 gap-1 px-3 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
50
+ lg: "h-10 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
51
+ icon: "size-9",
52
+ "icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
53
+ "icon-sm": "size-8",
54
+ "icon-lg": "size-10"
55
+ }
56
+ },
57
+ defaultVariants: {
58
+ variant: "default",
59
+ size: "default"
60
+ }
61
+ }
62
+ );
63
+ function Button({
64
+ className,
65
+ variant = "default",
66
+ size = "default",
67
+ asChild = false,
68
+ ...props
69
+ }) {
70
+ const Comp = asChild ? Slot.Root : "button";
71
+ return /* @__PURE__ */ jsx(
72
+ Comp,
73
+ {
74
+ "data-slot": "button",
75
+ "data-variant": variant,
76
+ "data-size": size,
77
+ className: cn(buttonVariants({ variant, size, className })),
78
+ ...props
79
+ }
80
+ );
81
+ }
82
+
83
+ // scaffold/src/components/ui/select.tsx
84
+ import { CheckIcon, ChevronDownIcon } from "lucide-react";
85
+ import { Select as SelectPrimitive } from "radix-ui";
86
+
87
+ // scaffold/src/components/theme-provider.tsx
88
+ import * as React from "react";
89
+ import { jsx as jsx2 } from "react/jsx-runtime";
90
+ var ThemeContext = React.createContext(null);
91
+ var storageKey = "agents24-chat-appearance";
92
+ function storedAppearance() {
93
+ try {
94
+ const stored = window.localStorage.getItem(storageKey);
95
+ return stored === "light" || stored === "dark" || stored === "system" ? stored : "system";
96
+ } catch {
97
+ return "system";
98
+ }
99
+ }
100
+ function ThemeProvider({
101
+ children,
102
+ controller,
103
+ theme = "soft"
104
+ }) {
105
+ const [internalAppearance, setInternalAppearance] = React.useState("system");
106
+ const [resolvedAppearance, setResolvedAppearance] = React.useState("light");
107
+ const [mounted, setMounted] = React.useState(false);
108
+ const [portalContainer, setPortalContainer] = React.useState(null);
109
+ const appearance = controller?.appearance ?? internalAppearance;
110
+ React.useEffect(() => {
111
+ if (!controller) setInternalAppearance(storedAppearance());
112
+ setMounted(true);
113
+ }, [controller]);
114
+ React.useEffect(() => {
115
+ if (!mounted || typeof window === "undefined" || typeof window.matchMedia !== "function") return;
116
+ const media = window.matchMedia("(prefers-color-scheme: dark)");
117
+ const apply = () => setResolvedAppearance(
118
+ appearance === "system" ? media.matches ? "dark" : "light" : appearance
119
+ );
120
+ apply();
121
+ media.addEventListener("change", apply);
122
+ return () => media.removeEventListener("change", apply);
123
+ }, [appearance, mounted]);
124
+ const change = React.useCallback((next) => {
125
+ if (controller) {
126
+ controller.setAppearance(next);
127
+ return;
128
+ }
129
+ try {
130
+ window.localStorage.setItem(storageKey, next);
131
+ } catch {
132
+ }
133
+ setInternalAppearance(next);
134
+ }, [controller]);
135
+ return /* @__PURE__ */ jsx2(ThemeContext.Provider, { value: { appearance, portalContainer, setAppearance: change }, children: /* @__PURE__ */ jsx2(
136
+ "div",
137
+ {
138
+ ref: setPortalContainer,
139
+ className: `${resolvedAppearance} size-full`,
140
+ "data-agents24-theme": theme,
141
+ "data-agents24-theme-root": "",
142
+ children
143
+ }
144
+ ) });
145
+ }
146
+ function useTheme() {
147
+ const context = React.useContext(ThemeContext);
148
+ if (!context) throw new Error("useTheme must be used inside ThemeProvider");
149
+ return context;
150
+ }
151
+ function useThemePortalContainer() {
152
+ return useTheme().portalContainer;
153
+ }
154
+
155
+ // scaffold/src/components/ui/select.tsx
156
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
157
+ function Select(props) {
158
+ return /* @__PURE__ */ jsx3(SelectPrimitive.Root, { "data-slot": "select", ...props });
159
+ }
160
+ function SelectValue(props) {
161
+ return /* @__PURE__ */ jsx3(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
162
+ }
163
+ function SelectTrigger({
164
+ children,
165
+ className,
166
+ ...props
167
+ }) {
168
+ return /* @__PURE__ */ jsxs(
169
+ SelectPrimitive.Trigger,
170
+ {
171
+ className: cn(
172
+ "flex h-8 w-full items-center justify-between gap-2 rounded-lg bg-transparent px-2.5 text-xs text-foreground outline-none transition-colors hover:bg-muted/50 focus-visible:bg-muted/50 disabled:cursor-not-allowed disabled:opacity-50 data-[placeholder]:text-muted-foreground [&>span]:min-w-0 [&>span]:truncate",
173
+ className
174
+ ),
175
+ "data-slot": "select-trigger",
176
+ ...props,
177
+ children: [
178
+ children,
179
+ /* @__PURE__ */ jsx3(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx3(ChevronDownIcon, { className: "size-3.5 shrink-0 text-muted-foreground" }) })
180
+ ]
181
+ }
182
+ );
183
+ }
184
+ function SelectContent({
185
+ align = "start",
186
+ children,
187
+ className,
188
+ sideOffset = 4,
189
+ ...props
190
+ }) {
191
+ const container = useThemePortalContainer();
192
+ return /* @__PURE__ */ jsx3(SelectPrimitive.Portal, { container: container || void 0, children: /* @__PURE__ */ jsx3(
193
+ SelectPrimitive.Content,
194
+ {
195
+ align,
196
+ className: cn(
197
+ "z-50 max-h-64 min-w-[var(--radix-select-trigger-width)] overflow-hidden rounded-xl border border-border/50 bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:animate-in data-[side=bottom]:fade-in-0 data-[side=bottom]:slide-in-from-top-1 data-[side=top]:animate-in data-[side=top]:fade-in-0 data-[side=top]:slide-in-from-bottom-1",
198
+ className
199
+ ),
200
+ "data-slot": "select-content",
201
+ position: "popper",
202
+ sideOffset,
203
+ ...props,
204
+ children: /* @__PURE__ */ jsx3(SelectPrimitive.Viewport, { className: "max-h-60 overflow-y-auto p-0.5", children })
205
+ }
206
+ ) });
207
+ }
208
+ function SelectItem({
209
+ children,
210
+ className,
211
+ ...props
212
+ }) {
213
+ return /* @__PURE__ */ jsxs(
214
+ SelectPrimitive.Item,
215
+ {
216
+ className: cn(
217
+ "relative flex cursor-default select-none items-center rounded-lg py-1.5 pr-8 pl-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
218
+ className
219
+ ),
220
+ "data-slot": "select-item",
221
+ ...props,
222
+ children: [
223
+ /* @__PURE__ */ jsx3(SelectPrimitive.ItemText, { className: "min-w-0 truncate", children }),
224
+ /* @__PURE__ */ jsx3("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsx3(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx3(CheckIcon, { className: "size-3.5" }) }) })
225
+ ]
226
+ }
227
+ );
228
+ }
229
+
230
+ // scaffold/src/components/ui/textarea.tsx
231
+ import { jsx as jsx4 } from "react/jsx-runtime";
232
+ function Textarea({ className, ...props }) {
233
+ return /* @__PURE__ */ jsx4(
234
+ "textarea",
235
+ {
236
+ "data-slot": "textarea",
237
+ className: cn(
238
+ "flex field-sizing-content min-h-16 w-full resize-none rounded-2xl border border-transparent bg-input/50 px-3 py-3 text-base transition-[color,box-shadow,background-color] outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/30 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
239
+ className
240
+ ),
241
+ ...props
242
+ }
243
+ );
244
+ }
245
+
246
+ // scaffold/src/components/ui/tooltip.tsx
247
+ import { Slot as Slot2 } from "radix-ui";
248
+ import { jsx as jsx5 } from "react/jsx-runtime";
249
+ function TooltipProvider({ children }) {
250
+ return children;
251
+ }
252
+ function Tooltip({ className, ...props }) {
253
+ return /* @__PURE__ */ jsx5(
254
+ "span",
255
+ {
256
+ "data-slot": "tooltip",
257
+ className: cn("group/tooltip relative inline-flex", className),
258
+ ...props
259
+ }
260
+ );
261
+ }
262
+ function TooltipTrigger({
263
+ asChild: _asChild,
264
+ ...props
265
+ }) {
266
+ return /* @__PURE__ */ jsx5(Slot2.Root, { "data-slot": "tooltip-trigger", ...props });
267
+ }
268
+ function TooltipContent({
269
+ className,
270
+ align: _align,
271
+ side = "top",
272
+ sideOffset: _sideOffset,
273
+ ...props
274
+ }) {
275
+ return /* @__PURE__ */ jsx5(
276
+ "span",
277
+ {
278
+ role: "tooltip",
279
+ "data-side": side,
280
+ "data-slot": "tooltip-content",
281
+ className: cn(
282
+ "pointer-events-none absolute z-50 hidden w-max max-w-xs items-center gap-1.5 rounded-xl bg-foreground px-3 py-1.5 text-xs text-background group-hover/tooltip:inline-flex group-focus-within/tooltip:inline-flex",
283
+ "data-[side=top]:bottom-full data-[side=top]:left-1/2 data-[side=top]:mb-2 data-[side=top]:-translate-x-1/2",
284
+ "data-[side=bottom]:top-full data-[side=bottom]:left-1/2 data-[side=bottom]:mt-2 data-[side=bottom]:-translate-x-1/2",
285
+ "data-[side=left]:end-full data-[side=left]:top-1/2 data-[side=left]:me-2 data-[side=left]:-translate-y-1/2",
286
+ "data-[side=right]:start-full data-[side=right]:top-1/2 data-[side=right]:ms-2 data-[side=right]:-translate-y-1/2",
287
+ className
288
+ ),
289
+ ...props
290
+ }
291
+ );
292
+ }
293
+
294
+ // scaffold/src/components/chat/chat-composer.tsx
295
+ import { Fragment, jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
296
+ function ChatComposer({
297
+ inputContract,
298
+ disabled,
299
+ contextWindow,
300
+ forceExpanded = false,
301
+ isCancelling = false,
302
+ isRunning,
303
+ modelId,
304
+ models,
305
+ onModelChange,
306
+ onStop,
307
+ onSubmit,
308
+ utilityRow = "inline"
309
+ }) {
310
+ const [text, setText] = React2.useState("");
311
+ const [files, setFiles] = React2.useState([]);
312
+ const [attachmentError, setAttachmentError] = React2.useState(null);
313
+ const inputRef = React2.useRef(null);
314
+ const textareaRef = React2.useRef(null);
315
+ const submittingRef = React2.useRef(false);
316
+ const draftRevisionRef = React2.useRef(0);
317
+ const attachmentMimeTypes = inputMimeTypes(inputContract);
318
+ const allowAttachments = attachmentMimeTypes.length > 0;
319
+ const recordingAllowed = inputContract.modalities.audio.recording_enabled;
320
+ const addRecording = React2.useCallback((file) => {
321
+ draftRevisionRef.current += 1;
322
+ setFiles((current) => [...current, file]);
323
+ }, []);
324
+ const recorder = useAudioRecorder(addRecording);
325
+ const isExpanded = forceExpanded || text.includes("\n") || text.length > 62;
326
+ const validationError = validateAgentChatSubmission(
327
+ inputContract,
328
+ text,
329
+ files.map((file) => ({ data: file, mediaType: file.type }))
330
+ );
331
+ const modelSelector = models.length > 0 ? /* @__PURE__ */ jsx6("div", { className: "w-fit max-w-40", children: /* @__PURE__ */ jsxs2(
332
+ Select,
333
+ {
334
+ disabled: disabled || isRunning,
335
+ onValueChange: onModelChange,
336
+ value: modelId || void 0,
337
+ children: [
338
+ /* @__PURE__ */ jsx6(SelectTrigger, { "aria-label": "Runtime model", children: /* @__PURE__ */ jsx6(SelectValue, { placeholder: "Model" }) }),
339
+ /* @__PURE__ */ jsx6(SelectContent, { align: "start", children: models.map((model) => /* @__PURE__ */ jsx6(SelectItem, { value: model.id, children: model.label }, model.id)) })
340
+ ]
341
+ }
342
+ ) }) : null;
343
+ const hasContextWindow = Number.isFinite(Number(contextWindow?.max_tokens)) && Number(contextWindow?.max_tokens) > 0;
344
+ const showUtilityRow = utilityRow === "below";
345
+ const submit = async () => {
346
+ if (disabled || isRunning || submittingRef.current || validationError) return;
347
+ const value = text;
348
+ const selectedFiles = files;
349
+ const clearedRevision = draftRevisionRef.current + 1;
350
+ draftRevisionRef.current = clearedRevision;
351
+ submittingRef.current = true;
352
+ setText("");
353
+ setFiles([]);
354
+ textareaRef.current?.focus();
355
+ try {
356
+ await onSubmit(value, selectedFiles);
357
+ } catch {
358
+ if (draftRevisionRef.current === clearedRevision) {
359
+ draftRevisionRef.current += 1;
360
+ setText(value);
361
+ setFiles(selectedFiles);
362
+ }
363
+ } finally {
364
+ submittingRef.current = false;
365
+ }
366
+ };
367
+ return /* @__PURE__ */ jsxs2(
368
+ "div",
369
+ {
370
+ className: "mx-auto w-full max-w-3xl px-4 pb-[max(1rem,env(safe-area-inset-bottom))] sm:px-6",
371
+ "data-agents24-chat-composer": "",
372
+ children: [
373
+ allowAttachments && files.length > 0 && /* @__PURE__ */ jsx6("div", { className: "mb-2 flex min-w-0 gap-2 overflow-x-auto", children: files.map((file, index) => /* @__PURE__ */ jsxs2("div", { className: "flex max-w-48 items-center gap-2 border bg-card px-2 py-1 text-xs", children: [
374
+ /* @__PURE__ */ jsx6("span", { className: "truncate", children: file.name }),
375
+ /* @__PURE__ */ jsx6(Button, { variant: "ghost", size: "icon-xs", "aria-label": `Remove ${file.name}`, onClick: () => {
376
+ draftRevisionRef.current += 1;
377
+ setFiles((current) => current.filter((_, itemIndex) => itemIndex !== index));
378
+ }, children: /* @__PURE__ */ jsx6(X, {}) })
379
+ ] }, `${file.name}-${index}`)) }),
380
+ attachmentError || recorder.error ? /* @__PURE__ */ jsx6("p", { className: "mb-2 text-xs text-destructive", role: "alert", children: attachmentError || recorder.error }) : null,
381
+ /* @__PURE__ */ jsxs2(
382
+ "div",
383
+ {
384
+ "data-expanded": isExpanded || void 0,
385
+ className: cn(
386
+ "agents24-composer-grid grid min-w-0 items-center gap-2 rounded-xl border bg-background shadow-sm",
387
+ isExpanded ? "p-2" : "p-1.5"
388
+ ),
389
+ children: [
390
+ allowAttachments ? /* @__PURE__ */ jsxs2(Fragment, { children: [
391
+ /* @__PURE__ */ jsx6(
392
+ "input",
393
+ {
394
+ ref: inputRef,
395
+ className: "sr-only",
396
+ type: "file",
397
+ multiple: true,
398
+ accept: attachmentMimeTypes.join(","),
399
+ onChange: (event) => {
400
+ const selected = Array.from(event.target.files ?? []);
401
+ const accepted = selected.filter((file) => attachmentMimeTypes.includes(canonicalInputMimeType(file.type)));
402
+ draftRevisionRef.current += 1;
403
+ setFiles((current) => [...current, ...accepted]);
404
+ setAttachmentError(
405
+ accepted.length === selected.length ? null : "One or more selected file types are not supported by this Agent."
406
+ );
407
+ event.currentTarget.value = "";
408
+ }
409
+ }
410
+ ),
411
+ /* @__PURE__ */ jsx6("div", { className: "agents24-composer-attach flex min-w-0 items-center", children: /* @__PURE__ */ jsx6(Button, { className: "bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground", variant: "ghost", size: "icon", "aria-label": "Attach files", disabled: disabled || isRunning, onClick: () => inputRef.current?.click(), children: /* @__PURE__ */ jsx6("span", { "aria-hidden": true, children: "+" }) }) })
412
+ ] }) : /* @__PURE__ */ jsx6("span", { "aria-hidden": "true", className: "agents24-composer-attach" }),
413
+ /* @__PURE__ */ jsx6(
414
+ Textarea,
415
+ {
416
+ ref: textareaRef,
417
+ value: text,
418
+ rows: 1,
419
+ placeholder: "Message the agent",
420
+ "aria-label": "Message",
421
+ disabled,
422
+ className: cn(
423
+ "agents24-composer-textarea max-h-56 min-h-9 field-sizing-content resize-none overflow-y-auto border-0 bg-transparent px-2 shadow-none focus-visible:ring-0 dark:bg-transparent",
424
+ isExpanded ? "py-2" : "h-9 py-2"
425
+ ),
426
+ onChange: (event) => {
427
+ draftRevisionRef.current += 1;
428
+ setText(event.target.value);
429
+ },
430
+ onKeyDown: (event) => {
431
+ if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
432
+ event.preventDefault();
433
+ void submit();
434
+ }
435
+ }
436
+ }
437
+ ),
438
+ /* @__PURE__ */ jsxs2("div", { className: "agents24-composer-actions flex items-center gap-1", children: [
439
+ utilityRow === "inline" ? /* @__PURE__ */ jsx6(AgentChatContextStatus, { contextWindow }) : null,
440
+ utilityRow === "inline" ? modelSelector : null,
441
+ recordingAllowed ? /* @__PURE__ */ jsx6(
442
+ Button,
443
+ {
444
+ variant: recorder.isRecording ? "default" : "ghost",
445
+ size: "icon",
446
+ "aria-label": recorder.isRecording ? "Stop recording" : "Record audio",
447
+ disabled: disabled || isRunning,
448
+ onClick: () => {
449
+ if (recorder.isRecording) recorder.stop();
450
+ else void recorder.start();
451
+ },
452
+ children: recorder.isRecording ? /* @__PURE__ */ jsx6(Square, { className: "fill-current" }) : /* @__PURE__ */ jsx6(Mic, {})
453
+ }
454
+ ) : null,
455
+ isRunning ? /* @__PURE__ */ jsx6(
456
+ Button,
457
+ {
458
+ size: "icon",
459
+ "aria-label": isCancelling ? "Cancelling response" : "Stop response",
460
+ disabled: disabled || isCancelling,
461
+ onClick: onStop,
462
+ children: isCancelling ? /* @__PURE__ */ jsx6(LoaderCircle, { className: "animate-spin" }) : /* @__PURE__ */ jsx6(Square, { className: "fill-current" })
463
+ }
464
+ ) : validationError ? /* @__PURE__ */ jsxs2(Tooltip, { tabIndex: 0, children: [
465
+ /* @__PURE__ */ jsx6(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx6(Button, { size: "icon", "aria-label": "Send message", disabled: true, onClick: () => void submit(), children: /* @__PURE__ */ jsx6(ArrowUp, {}) }) }),
466
+ /* @__PURE__ */ jsx6(TooltipContent, { children: validationError })
467
+ ] }) : /* @__PURE__ */ jsx6(Button, { size: "icon", "aria-label": "Send message", disabled, onClick: () => void submit(), children: /* @__PURE__ */ jsx6(ArrowUp, {}) })
468
+ ] })
469
+ ]
470
+ }
471
+ ),
472
+ showUtilityRow ? /* @__PURE__ */ jsxs2(
473
+ "div",
474
+ {
475
+ "aria-hidden": !modelSelector && !hasContextWindow ? "true" : void 0,
476
+ className: "mt-2 flex min-h-8 items-center justify-between gap-2 px-1",
477
+ "data-agents24-chat-composer-utility": "",
478
+ children: [
479
+ /* @__PURE__ */ jsx6("div", { className: "min-w-0", children: modelSelector }),
480
+ /* @__PURE__ */ jsx6(AgentChatContextStatus, { contextWindow })
481
+ ]
482
+ }
483
+ ) : null
484
+ ]
485
+ }
486
+ );
487
+ }
488
+
489
+ // scaffold/src/components/chat/chat-message.tsx
490
+ import { AgentChatDefaultActions, ChatAttachment, ChatAttachments } from "@agents24/chat-react/ui";
491
+
492
+ // scaffold/src/components/chat/message-parts.tsx
493
+ import {
494
+ AgentChatPart,
495
+ AgentResponseTimeline
496
+ } from "@agents24/chat-react/ui";
497
+
498
+ // scaffold/src/components/chat/collapsible-user-message.tsx
499
+ import { ChevronDown, ChevronUp } from "lucide-react";
500
+ import * as React3 from "react";
501
+ import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
502
+ var collapseThreshold = 360;
503
+ function CollapsibleUserMessage({ content }) {
504
+ const [expanded, setExpanded] = React3.useState(false);
505
+ const contentId = React3.useId();
506
+ const collapsible = content.length > collapseThreshold;
507
+ const Icon = expanded ? ChevronUp : ChevronDown;
508
+ return /* @__PURE__ */ jsxs3("div", { className: "flex min-w-0 flex-col gap-2", children: [
509
+ /* @__PURE__ */ jsx7(
510
+ "div",
511
+ {
512
+ id: contentId,
513
+ className: `max-w-none min-w-0 text-[15px] leading-7 whitespace-pre-wrap wrap-break-word ${collapsible && !expanded ? "agents24-user-message-collapsed" : ""}`,
514
+ children: content
515
+ }
516
+ ),
517
+ collapsible && /* @__PURE__ */ jsxs3(
518
+ Button,
519
+ {
520
+ variant: "ghost",
521
+ size: "sm",
522
+ type: "button",
523
+ "aria-controls": contentId,
524
+ "aria-expanded": expanded,
525
+ className: "h-auto w-fit px-0 py-0 text-muted-foreground hover:bg-transparent hover:text-foreground",
526
+ onClick: () => setExpanded((value) => !value),
527
+ children: [
528
+ expanded ? "Show less" : "Show more",
529
+ /* @__PURE__ */ jsx7(Icon, {})
530
+ ]
531
+ }
532
+ )
533
+ ] });
534
+ }
535
+
536
+ // scaffold/src/components/chat/external-link-dialog.tsx
537
+ import * as React4 from "react";
538
+
539
+ // scaffold/src/components/ui/dialog.tsx
540
+ import { Dialog as DialogPrimitive } from "radix-ui";
541
+ import { XIcon } from "lucide-react";
542
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
543
+ function Dialog({
544
+ ...props
545
+ }) {
546
+ return /* @__PURE__ */ jsx8(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
547
+ }
548
+ function DialogPortal({
549
+ container,
550
+ ...props
551
+ }) {
552
+ const themeContainer = useThemePortalContainer();
553
+ return /* @__PURE__ */ jsx8(DialogPrimitive.Portal, { container: container || themeContainer || void 0, "data-slot": "dialog-portal", ...props });
554
+ }
555
+ function DialogOverlay({
556
+ className,
557
+ ...props
558
+ }) {
559
+ return /* @__PURE__ */ jsx8(
560
+ DialogPrimitive.Overlay,
561
+ {
562
+ "data-slot": "dialog-overlay",
563
+ className: cn(
564
+ "fixed inset-0 isolate z-50 bg-black/30 duration-100 supports-backdrop-filter:backdrop-blur-sm data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
565
+ className
566
+ ),
567
+ ...props
568
+ }
569
+ );
570
+ }
571
+ function DialogContent({
572
+ className,
573
+ children,
574
+ showCloseButton = true,
575
+ ...props
576
+ }) {
577
+ return /* @__PURE__ */ jsxs4(DialogPortal, { children: [
578
+ /* @__PURE__ */ jsx8(DialogOverlay, {}),
579
+ /* @__PURE__ */ jsxs4(
580
+ DialogPrimitive.Content,
581
+ {
582
+ "data-slot": "dialog-content",
583
+ className: cn(
584
+ "fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-6 rounded-4xl bg-popover p-6 text-sm text-popover-foreground shadow-xl ring-1 ring-foreground/5 duration-100 outline-none sm:max-w-md dark:ring-foreground/10 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
585
+ className
586
+ ),
587
+ ...props,
588
+ children: [
589
+ children,
590
+ showCloseButton && /* @__PURE__ */ jsx8(DialogPrimitive.Close, { "data-slot": "dialog-close", asChild: true, children: /* @__PURE__ */ jsxs4(
591
+ Button,
592
+ {
593
+ variant: "ghost",
594
+ className: "absolute top-4 right-4 bg-secondary",
595
+ size: "icon-sm",
596
+ children: [
597
+ /* @__PURE__ */ jsx8(
598
+ XIcon,
599
+ {}
600
+ ),
601
+ /* @__PURE__ */ jsx8("span", { className: "sr-only", children: "Close" })
602
+ ]
603
+ }
604
+ ) })
605
+ ]
606
+ }
607
+ )
608
+ ] });
609
+ }
610
+ function DialogHeader({ className, ...props }) {
611
+ return /* @__PURE__ */ jsx8(
612
+ "div",
613
+ {
614
+ "data-slot": "dialog-header",
615
+ className: cn("flex flex-col gap-1.5", className),
616
+ ...props
617
+ }
618
+ );
619
+ }
620
+ function DialogFooter({
621
+ className,
622
+ showCloseButton = false,
623
+ children,
624
+ ...props
625
+ }) {
626
+ return /* @__PURE__ */ jsxs4(
627
+ "div",
628
+ {
629
+ "data-slot": "dialog-footer",
630
+ className: cn(
631
+ "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
632
+ className
633
+ ),
634
+ ...props,
635
+ children: [
636
+ children,
637
+ showCloseButton && /* @__PURE__ */ jsx8(DialogPrimitive.Close, { asChild: true, children: /* @__PURE__ */ jsx8(Button, { variant: "outline", children: "Close" }) })
638
+ ]
639
+ }
640
+ );
641
+ }
642
+ function DialogTitle({
643
+ className,
644
+ ...props
645
+ }) {
646
+ return /* @__PURE__ */ jsx8(
647
+ DialogPrimitive.Title,
648
+ {
649
+ "data-slot": "dialog-title",
650
+ className: cn(
651
+ "font-heading text-base leading-none font-medium",
652
+ className
653
+ ),
654
+ ...props
655
+ }
656
+ );
657
+ }
658
+ function DialogDescription({
659
+ className,
660
+ ...props
661
+ }) {
662
+ return /* @__PURE__ */ jsx8(
663
+ DialogPrimitive.Description,
664
+ {
665
+ "data-slot": "dialog-description",
666
+ className: cn(
667
+ "text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
668
+ className
669
+ ),
670
+ ...props
671
+ }
672
+ );
673
+ }
674
+
675
+ // scaffold/src/components/chat/external-link-dialog.tsx
676
+ import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
677
+ function ExternalLinkDialog({ isOpen, onClose, onConfirm, url }) {
678
+ const [copied, setCopied] = React4.useState(false);
679
+ React4.useEffect(() => {
680
+ if (!isOpen) setCopied(false);
681
+ }, [isOpen]);
682
+ const copyUrl = async () => {
683
+ await navigator.clipboard.writeText(url);
684
+ setCopied(true);
685
+ };
686
+ const openUrl = () => {
687
+ onConfirm();
688
+ onClose();
689
+ };
690
+ return /* @__PURE__ */ jsx9(Dialog, { open: isOpen, onOpenChange: (open) => {
691
+ if (!open) onClose();
692
+ }, children: /* @__PURE__ */ jsxs5(DialogContent, { className: "max-h-[calc(100dvh-2rem)] min-w-0 overflow-hidden sm:max-w-md", children: [
693
+ /* @__PURE__ */ jsxs5(DialogHeader, { children: [
694
+ /* @__PURE__ */ jsx9(DialogTitle, { children: "Open external link?" }),
695
+ /* @__PURE__ */ jsx9(DialogDescription, { children: "You\u2019re about to visit an external website." })
696
+ ] }),
697
+ /* @__PURE__ */ jsx9("div", { className: "max-h-32 overflow-auto rounded-md bg-muted p-3 font-mono text-xs wrap-break-word", children: url }),
698
+ /* @__PURE__ */ jsxs5(DialogFooter, { children: [
699
+ /* @__PURE__ */ jsx9(Button, { variant: "outline", onClick: () => void copyUrl(), children: copied ? "Copied" : "Copy link" }),
700
+ /* @__PURE__ */ jsx9(Button, { onClick: openUrl, children: "Open link" })
701
+ ] })
702
+ ] }) });
703
+ }
704
+
705
+ // scaffold/src/components/chat/message-parts.tsx
706
+ import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
707
+ var linkSafety = {
708
+ enabled: true,
709
+ renderModal: (props) => /* @__PURE__ */ jsx10(ExternalLinkDialog, { ...props })
710
+ };
711
+ function ScaffoldTimeline(props) {
712
+ return /* @__PURE__ */ jsx10(
713
+ AgentResponseTimeline,
714
+ {
715
+ ...props,
716
+ responseProps: {
717
+ className: "text-[15px] leading-7",
718
+ linkSafety
719
+ }
720
+ }
721
+ );
722
+ }
723
+ function MessageParts({
724
+ message,
725
+ getHitlActionState,
726
+ isLoading,
727
+ onHitlAction,
728
+ Timeline = ScaffoldTimeline
729
+ }) {
730
+ if (message.role === "assistant") {
731
+ return /* @__PURE__ */ jsx10(
732
+ Timeline,
733
+ {
734
+ getHitlActionState,
735
+ isLoading,
736
+ message,
737
+ onHitlAction: (part, response) => {
738
+ void onHitlAction(part, response).catch(() => void 0);
739
+ },
740
+ parts: message.parts
741
+ }
742
+ );
743
+ }
744
+ const text = message.parts.filter((part) => part.kind === "text").map((part) => part.kind === "text" ? part.text : "").join("") || message.content;
745
+ const supportingParts = message.parts.filter((part) => part.kind !== "text" && part.kind !== "data");
746
+ return /* @__PURE__ */ jsxs6(Fragment2, { children: [
747
+ supportingParts.map((part) => /* @__PURE__ */ jsx10(
748
+ AgentChatPart,
749
+ {
750
+ getHitlActionState,
751
+ message,
752
+ onHitlAction: (hitlPart, response) => {
753
+ void onHitlAction(hitlPart, response).catch(() => void 0);
754
+ },
755
+ part
756
+ },
757
+ part.id
758
+ )),
759
+ text ? /* @__PURE__ */ jsx10(CollapsibleUserMessage, { content: text }) : null
760
+ ] });
761
+ }
762
+
763
+ // scaffold/src/components/ui/bubble.tsx
764
+ import { cva as cva2 } from "class-variance-authority";
765
+ import { Slot as Slot3 } from "radix-ui";
766
+ import { jsx as jsx11 } from "react/jsx-runtime";
767
+ var bubbleVariants = cva2(
768
+ "group/bubble relative flex w-fit max-w-[80%] min-w-0 flex-col gap-1 group-data-[align=end]/message:self-end data-[align=end]:self-end data-[variant=ghost]:max-w-full",
769
+ {
770
+ variants: {
771
+ variant: {
772
+ default: "*:data-[slot=bubble-content]:bg-primary *:data-[slot=bubble-content]:text-primary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-primary/80",
773
+ secondary: "*:data-[slot=bubble-content]:bg-secondary *:data-[slot=bubble-content]:text-secondary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)]",
774
+ muted: "*:data-[slot=bubble-content]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--muted),var(--foreground)_5%)]",
775
+ tinted: "*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.93_calc(c*0.4)_h)] *:data-[slot=bubble-content]:text-foreground dark:*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.3_calc(c*0.4)_h)] [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.88_calc(c*0.5)_h)] dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.35_calc(c*0.5)_h)]",
776
+ outline: "*:data-[slot=bubble-content]:border-border *:data-[slot=bubble-content]:bg-background [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-input/30",
777
+ ghost: "border-none *:data-[slot=bubble-content]:rounded-none *:data-[slot=bubble-content]:bg-transparent *:data-[slot=bubble-content]:p-0 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted/50",
778
+ destructive: "*:data-[slot=bubble-content]:bg-destructive/10 *:data-[slot=bubble-content]:text-destructive dark:*:data-[slot=bubble-content]:bg-destructive/20 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/20 dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/30"
779
+ }
780
+ },
781
+ defaultVariants: {
782
+ variant: "default"
783
+ }
784
+ }
785
+ );
786
+ function Bubble({
787
+ variant = "default",
788
+ align = "start",
789
+ className,
790
+ ...props
791
+ }) {
792
+ return /* @__PURE__ */ jsx11(
793
+ "div",
794
+ {
795
+ "data-slot": "bubble",
796
+ "data-variant": variant,
797
+ "data-align": align,
798
+ className: cn(bubbleVariants({ variant }), className),
799
+ ...props
800
+ }
801
+ );
802
+ }
803
+ function BubbleContent({
804
+ asChild = false,
805
+ className,
806
+ ...props
807
+ }) {
808
+ const Comp = asChild ? Slot3.Root : "div";
809
+ return /* @__PURE__ */ jsx11(
810
+ Comp,
811
+ {
812
+ "data-slot": "bubble-content",
813
+ className: cn(
814
+ "w-fit max-w-full min-w-0 overflow-hidden rounded-3xl border border-transparent px-3.5 py-2.5 text-sm leading-relaxed wrap-break-word group-data-[align=end]/bubble:self-end [button]:text-left [button,a]:transition-colors [button,a]:outline-none [button,a]:focus-visible:border-ring [button,a]:focus-visible:ring-3 [button,a]:focus-visible:ring-ring/30",
815
+ className
816
+ ),
817
+ ...props
818
+ }
819
+ );
820
+ }
821
+ var bubbleReactionsVariants = cva2(
822
+ "absolute z-10 flex w-fit shrink-0 items-center justify-center gap-1 rounded-full bg-muted px-1.5 py-0.5 text-sm ring-3 ring-card has-[button]:p-0",
823
+ {
824
+ variants: {
825
+ side: {
826
+ top: "top-0 -translate-y-3/4",
827
+ bottom: "bottom-0 translate-y-3/4"
828
+ },
829
+ align: {
830
+ start: "left-3",
831
+ end: "right-3"
832
+ }
833
+ },
834
+ defaultVariants: {
835
+ side: "bottom",
836
+ align: "end"
837
+ }
838
+ }
839
+ );
840
+
841
+ // scaffold/src/components/ui/message.tsx
842
+ import { jsx as jsx12 } from "react/jsx-runtime";
843
+ function Message({
844
+ className,
845
+ align = "start",
846
+ ...props
847
+ }) {
848
+ return /* @__PURE__ */ jsx12(
849
+ "div",
850
+ {
851
+ "data-slot": "message",
852
+ "data-align": align,
853
+ className: cn(
854
+ "group/message relative flex w-full min-w-0 gap-2 text-sm data-[align=end]:flex-row-reverse",
855
+ className
856
+ ),
857
+ ...props
858
+ }
859
+ );
860
+ }
861
+ function MessageContent({ className, ...props }) {
862
+ return /* @__PURE__ */ jsx12(
863
+ "div",
864
+ {
865
+ "data-slot": "message-content",
866
+ className: cn(
867
+ "flex w-full min-w-0 flex-col gap-2.5 wrap-break-word group-data-[align=end]/message:*:data-slot:self-end",
868
+ className
869
+ ),
870
+ ...props
871
+ }
872
+ );
873
+ }
874
+ function MessageFooter({ className, ...props }) {
875
+ return /* @__PURE__ */ jsx12(
876
+ "div",
877
+ {
878
+ "data-slot": "message-footer",
879
+ className: cn(
880
+ "flex max-w-full min-w-0 items-center px-3.5 text-xs font-medium text-muted-foreground group-has-data-[variant=ghost]/message:px-0 group-data-[align=end]/message:justify-end",
881
+ className
882
+ ),
883
+ ...props
884
+ }
885
+ );
886
+ }
887
+
888
+ // scaffold/src/components/chat/chat-message.tsx
889
+ import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
890
+ function ChatMessage({
891
+ allowFeedback,
892
+ getHitlActionState,
893
+ isLoading,
894
+ message,
895
+ onHitlAction,
896
+ onRegenerate,
897
+ onSetFeedback,
898
+ Timeline
899
+ }) {
900
+ const isUser = message.role === "user";
901
+ return /* @__PURE__ */ jsx13(Message, { align: isUser ? "end" : "start", children: /* @__PURE__ */ jsxs7(MessageContent, { children: [
902
+ isUser && message.attachments?.length ? /* @__PURE__ */ jsx13(ChatAttachments, { className: "mb-2 justify-end", children: message.attachments.map((attachment, index) => /* @__PURE__ */ jsx13(
903
+ ChatAttachment,
904
+ {
905
+ data: attachment
906
+ },
907
+ String(attachment.id || attachment.url || attachment.filename || index)
908
+ )) }) : null,
909
+ /* @__PURE__ */ jsx13(Bubble, { variant: isUser ? "secondary" : "ghost", align: isUser ? "end" : "start", className: isUser ? "max-w-[min(75%,42rem)]" : "max-w-full overflow-visible", children: /* @__PURE__ */ jsx13(BubbleContent, { className: isUser ? "px-4 py-2.5" : "w-full overflow-visible", children: /* @__PURE__ */ jsx13(
910
+ MessageParts,
911
+ {
912
+ getHitlActionState,
913
+ isLoading,
914
+ message,
915
+ onHitlAction,
916
+ Timeline
917
+ }
918
+ ) }) }),
919
+ !isUser && message.isFinal !== false && /* @__PURE__ */ jsx13(MessageFooter, { className: "gap-1 opacity-70 transition-opacity group-hover/message:opacity-100", children: /* @__PURE__ */ jsx13(
920
+ AgentChatDefaultActions,
921
+ {
922
+ handlers: {
923
+ feedback: message.feedback,
924
+ onCopy: (content) => {
925
+ void navigator.clipboard.writeText(content).catch(() => void 0);
926
+ },
927
+ onRetry: () => onRegenerate(),
928
+ onSetFeedback: allowFeedback ? (_message, input) => onSetFeedback(input) : void 0
929
+ },
930
+ message
931
+ }
932
+ ) })
933
+ ] }) });
934
+ }
935
+
936
+ // scaffold/src/components/chat/theme-menu.tsx
937
+ import { Laptop, Moon, Sun } from "lucide-react";
938
+ import * as React5 from "react";
939
+ import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
940
+ var options = [
941
+ { value: "system", label: "System", icon: Laptop },
942
+ { value: "light", label: "Light", icon: Sun },
943
+ { value: "dark", label: "Dark", icon: Moon }
944
+ ];
945
+ function ThemeMenu() {
946
+ const { appearance, setAppearance } = useTheme();
947
+ const [open, setOpen] = React5.useState(false);
948
+ const rootRef = React5.useRef(null);
949
+ const firstItemRef = React5.useRef(null);
950
+ const menuId = React5.useId();
951
+ const ActiveIcon = options.find((item) => item.value === appearance)?.icon ?? Laptop;
952
+ React5.useEffect(() => {
953
+ if (!open) return;
954
+ firstItemRef.current?.focus();
955
+ const closeOnOutsidePointer = (event) => {
956
+ if (!rootRef.current?.contains(event.target)) setOpen(false);
957
+ };
958
+ const closeOnEscape = (event) => {
959
+ if (event.key === "Escape") setOpen(false);
960
+ };
961
+ document.addEventListener("pointerdown", closeOnOutsidePointer);
962
+ document.addEventListener("keydown", closeOnEscape);
963
+ return () => {
964
+ document.removeEventListener("pointerdown", closeOnOutsidePointer);
965
+ document.removeEventListener("keydown", closeOnEscape);
966
+ };
967
+ }, [open]);
968
+ const label = appearance === "system" ? "System" : appearance === "light" ? "Light" : "Dark";
969
+ return /* @__PURE__ */ jsxs8("div", { ref: rootRef, className: "relative", children: [
970
+ /* @__PURE__ */ jsx14(
971
+ Button,
972
+ {
973
+ "aria-controls": menuId,
974
+ "aria-expanded": open,
975
+ "aria-haspopup": "menu",
976
+ "aria-label": `Appearance: ${label}`,
977
+ onClick: () => setOpen((value) => !value),
978
+ size: "icon-sm",
979
+ variant: "ghost",
980
+ children: /* @__PURE__ */ jsx14(ActiveIcon, {})
981
+ }
982
+ ),
983
+ open ? /* @__PURE__ */ jsx14(
984
+ "div",
985
+ {
986
+ id: menuId,
987
+ className: "absolute end-0 top-full z-50 mt-1 flex min-w-44 flex-col rounded-xl border bg-popover p-1 text-popover-foreground shadow-md",
988
+ role: "menu",
989
+ children: options.map(({ value, label: optionLabel, icon: Icon }, index) => /* @__PURE__ */ jsxs8(
990
+ Button,
991
+ {
992
+ ref: index === 0 ? firstItemRef : void 0,
993
+ "aria-current": appearance === value ? "true" : void 0,
994
+ className: "w-full justify-start",
995
+ onClick: () => {
996
+ setAppearance(value);
997
+ setOpen(false);
998
+ },
999
+ role: "menuitem",
1000
+ size: "sm",
1001
+ variant: "ghost",
1002
+ children: [
1003
+ /* @__PURE__ */ jsx14(Icon, {}),
1004
+ " ",
1005
+ optionLabel
1006
+ ]
1007
+ },
1008
+ value
1009
+ ))
1010
+ }
1011
+ ) : null
1012
+ ] });
1013
+ }
1014
+
1015
+ // scaffold/src/components/chat/thread-sidebar.tsx
1016
+ import { getThreadActivity } from "@agents24/react";
1017
+ import { LoaderCircle as LoaderCircle2, SquarePen, Trash2 } from "lucide-react";
1018
+
1019
+ // scaffold/src/components/chat/identity-control.tsx
1020
+ import { LogIn, LogOut, UserRound } from "lucide-react";
1021
+
1022
+ // scaffold/src/components/ui/dropdown-menu.tsx
1023
+ import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
1024
+ import { CheckIcon as CheckIcon2, ChevronRightIcon } from "lucide-react";
1025
+ import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
1026
+ function DropdownMenu({
1027
+ ...props
1028
+ }) {
1029
+ return /* @__PURE__ */ jsx15(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
1030
+ }
1031
+ function DropdownMenuTrigger({
1032
+ ...props
1033
+ }) {
1034
+ return /* @__PURE__ */ jsx15(
1035
+ DropdownMenuPrimitive.Trigger,
1036
+ {
1037
+ "data-slot": "dropdown-menu-trigger",
1038
+ ...props
1039
+ }
1040
+ );
1041
+ }
1042
+ function DropdownMenuContent({
1043
+ className,
1044
+ align = "start",
1045
+ sideOffset = 4,
1046
+ ...props
1047
+ }) {
1048
+ const themeContainer = useThemePortalContainer();
1049
+ return /* @__PURE__ */ jsx15(DropdownMenuPrimitive.Portal, { container: themeContainer || void 0, children: /* @__PURE__ */ jsx15(
1050
+ DropdownMenuPrimitive.Content,
1051
+ {
1052
+ "data-slot": "dropdown-menu-content",
1053
+ sideOffset,
1054
+ align,
1055
+ className: cn("z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) min-w-48 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-3xl bg-popover p-1.5 text-popover-foreground shadow-lg ring-1 ring-foreground/5 duration-100 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 data-[state=closed]:overflow-hidden dark:ring-foreground/10 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className),
1056
+ ...props
1057
+ }
1058
+ ) });
1059
+ }
1060
+ function DropdownMenuItem({
1061
+ className,
1062
+ inset,
1063
+ variant = "default",
1064
+ ...props
1065
+ }) {
1066
+ return /* @__PURE__ */ jsx15(
1067
+ DropdownMenuPrimitive.Item,
1068
+ {
1069
+ "data-slot": "dropdown-menu-item",
1070
+ "data-inset": inset,
1071
+ "data-variant": variant,
1072
+ className: cn(
1073
+ "group/dropdown-menu-item relative flex cursor-default items-center gap-2.5 rounded-2xl px-3 py-2 text-sm font-medium outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-9.5 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
1074
+ className
1075
+ ),
1076
+ ...props
1077
+ }
1078
+ );
1079
+ }
1080
+ function DropdownMenuLabel({
1081
+ className,
1082
+ inset,
1083
+ ...props
1084
+ }) {
1085
+ return /* @__PURE__ */ jsx15(
1086
+ DropdownMenuPrimitive.Label,
1087
+ {
1088
+ "data-slot": "dropdown-menu-label",
1089
+ "data-inset": inset,
1090
+ className: cn(
1091
+ "px-3 py-2.5 text-xs text-muted-foreground data-inset:pl-9.5",
1092
+ className
1093
+ ),
1094
+ ...props
1095
+ }
1096
+ );
1097
+ }
1098
+ function DropdownMenuSeparator({
1099
+ className,
1100
+ ...props
1101
+ }) {
1102
+ return /* @__PURE__ */ jsx15(
1103
+ DropdownMenuPrimitive.Separator,
1104
+ {
1105
+ "data-slot": "dropdown-menu-separator",
1106
+ className: cn("-mx-1.5 my-1.5 h-px bg-border/50", className),
1107
+ ...props
1108
+ }
1109
+ );
1110
+ }
1111
+
1112
+ // scaffold/src/components/ui/sidebar.tsx
1113
+ import * as React7 from "react";
1114
+ import { cva as cva3 } from "class-variance-authority";
1115
+ import { Slot as Slot4 } from "radix-ui";
1116
+
1117
+ // scaffold/src/hooks/use-mobile.ts
1118
+ import * as React6 from "react";
1119
+ var MOBILE_BREAKPOINT = 768;
1120
+ function useIsMobile() {
1121
+ const [isMobile, setIsMobile] = React6.useState(void 0);
1122
+ React6.useEffect(() => {
1123
+ const onChange = () => {
1124
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
1125
+ };
1126
+ if (typeof window.matchMedia !== "function") {
1127
+ onChange();
1128
+ window.addEventListener("resize", onChange);
1129
+ return () => window.removeEventListener("resize", onChange);
1130
+ }
1131
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
1132
+ mql.addEventListener("change", onChange);
1133
+ onChange();
1134
+ return () => mql.removeEventListener("change", onChange);
1135
+ }, []);
1136
+ return !!isMobile;
1137
+ }
1138
+
1139
+ // scaffold/src/components/ui/input.tsx
1140
+ import { jsx as jsx16 } from "react/jsx-runtime";
1141
+
1142
+ // scaffold/src/components/ui/separator.tsx
1143
+ import { Separator as SeparatorPrimitive } from "radix-ui";
1144
+ import { jsx as jsx17 } from "react/jsx-runtime";
1145
+
1146
+ // scaffold/src/components/ui/sheet.tsx
1147
+ import { Dialog as SheetPrimitive } from "radix-ui";
1148
+ import { XIcon as XIcon2 } from "lucide-react";
1149
+ import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
1150
+ function Sheet({ ...props }) {
1151
+ return /* @__PURE__ */ jsx18(SheetPrimitive.Root, { "data-slot": "sheet", ...props });
1152
+ }
1153
+ function SheetPortal({
1154
+ container,
1155
+ ...props
1156
+ }) {
1157
+ const themeContainer = useThemePortalContainer();
1158
+ return /* @__PURE__ */ jsx18(SheetPrimitive.Portal, { container: container || themeContainer || void 0, "data-slot": "sheet-portal", ...props });
1159
+ }
1160
+ function SheetOverlay({
1161
+ className,
1162
+ ...props
1163
+ }) {
1164
+ return /* @__PURE__ */ jsx18(
1165
+ SheetPrimitive.Overlay,
1166
+ {
1167
+ "data-slot": "sheet-overlay",
1168
+ className: cn(
1169
+ "fixed inset-0 z-50 bg-black/30 duration-100 supports-backdrop-filter:backdrop-blur-sm data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
1170
+ className
1171
+ ),
1172
+ ...props
1173
+ }
1174
+ );
1175
+ }
1176
+ function SheetContent({
1177
+ className,
1178
+ children,
1179
+ side = "right",
1180
+ showCloseButton = true,
1181
+ ...props
1182
+ }) {
1183
+ return /* @__PURE__ */ jsxs10(SheetPortal, { children: [
1184
+ /* @__PURE__ */ jsx18(SheetOverlay, {}),
1185
+ /* @__PURE__ */ jsxs10(
1186
+ SheetPrimitive.Content,
1187
+ {
1188
+ "data-slot": "sheet-content",
1189
+ "data-side": side,
1190
+ className: cn(
1191
+ "fixed z-50 flex flex-col bg-popover bg-clip-padding text-sm text-popover-foreground shadow-xl transition duration-200 ease-in-out data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-[side=bottom]:data-open:slide-in-from-bottom-10 data-[side=left]:data-open:slide-in-from-left-10 data-[side=right]:data-open:slide-in-from-right-10 data-[side=top]:data-open:slide-in-from-top-10 data-closed:animate-out data-closed:fade-out-0 data-[side=bottom]:data-closed:slide-out-to-bottom-10 data-[side=left]:data-closed:slide-out-to-left-10 data-[side=right]:data-closed:slide-out-to-right-10 data-[side=top]:data-closed:slide-out-to-top-10",
1192
+ className
1193
+ ),
1194
+ ...props,
1195
+ children: [
1196
+ children,
1197
+ showCloseButton && /* @__PURE__ */ jsx18(SheetPrimitive.Close, { "data-slot": "sheet-close", asChild: true, children: /* @__PURE__ */ jsxs10(
1198
+ Button,
1199
+ {
1200
+ variant: "ghost",
1201
+ className: "absolute top-4 right-4 bg-secondary",
1202
+ size: "icon-sm",
1203
+ children: [
1204
+ /* @__PURE__ */ jsx18(
1205
+ XIcon2,
1206
+ {}
1207
+ ),
1208
+ /* @__PURE__ */ jsx18("span", { className: "sr-only", children: "Close" })
1209
+ ]
1210
+ }
1211
+ ) })
1212
+ ]
1213
+ }
1214
+ )
1215
+ ] });
1216
+ }
1217
+ function SheetHeader({ className, ...props }) {
1218
+ return /* @__PURE__ */ jsx18(
1219
+ "div",
1220
+ {
1221
+ "data-slot": "sheet-header",
1222
+ className: cn("flex flex-col gap-1.5 p-6", className),
1223
+ ...props
1224
+ }
1225
+ );
1226
+ }
1227
+ function SheetTitle({
1228
+ className,
1229
+ ...props
1230
+ }) {
1231
+ return /* @__PURE__ */ jsx18(
1232
+ SheetPrimitive.Title,
1233
+ {
1234
+ "data-slot": "sheet-title",
1235
+ className: cn(
1236
+ "font-heading text-base font-medium text-foreground",
1237
+ className
1238
+ ),
1239
+ ...props
1240
+ }
1241
+ );
1242
+ }
1243
+ function SheetDescription({
1244
+ className,
1245
+ ...props
1246
+ }) {
1247
+ return /* @__PURE__ */ jsx18(
1248
+ SheetPrimitive.Description,
1249
+ {
1250
+ "data-slot": "sheet-description",
1251
+ className: cn("text-sm text-muted-foreground", className),
1252
+ ...props
1253
+ }
1254
+ );
1255
+ }
1256
+
1257
+ // scaffold/src/components/ui/skeleton.tsx
1258
+ import { jsx as jsx19 } from "react/jsx-runtime";
1259
+
1260
+ // scaffold/src/components/ui/sidebar.tsx
1261
+ import { PanelLeftIcon } from "lucide-react";
1262
+ import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
1263
+ var SIDEBAR_COOKIE_NAME = "sidebar_state";
1264
+ var SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
1265
+ var SIDEBAR_KEYBOARD_SHORTCUT = "b";
1266
+ var SidebarContext = React7.createContext(null);
1267
+ function useSidebar() {
1268
+ const context = React7.useContext(SidebarContext);
1269
+ if (!context) {
1270
+ throw new Error("useSidebar must be used within a SidebarProvider.");
1271
+ }
1272
+ return context;
1273
+ }
1274
+ function SidebarProvider({
1275
+ defaultOpen = true,
1276
+ open: openProp,
1277
+ onOpenChange: setOpenProp,
1278
+ className,
1279
+ children,
1280
+ ...props
1281
+ }) {
1282
+ const isMobile = useIsMobile();
1283
+ const [openMobile, setOpenMobile] = React7.useState(false);
1284
+ const [_open, _setOpen] = React7.useState(defaultOpen);
1285
+ const open = openProp ?? _open;
1286
+ const setOpen = React7.useCallback(
1287
+ (value) => {
1288
+ const openState = typeof value === "function" ? value(open) : value;
1289
+ if (setOpenProp) {
1290
+ setOpenProp(openState);
1291
+ } else {
1292
+ _setOpen(openState);
1293
+ }
1294
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
1295
+ },
1296
+ [setOpenProp, open]
1297
+ );
1298
+ const toggleSidebar = React7.useCallback(() => {
1299
+ return isMobile ? setOpenMobile((open2) => !open2) : setOpen((open2) => !open2);
1300
+ }, [isMobile, setOpen, setOpenMobile]);
1301
+ React7.useEffect(() => {
1302
+ const handleKeyDown = (event) => {
1303
+ if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
1304
+ event.preventDefault();
1305
+ toggleSidebar();
1306
+ }
1307
+ };
1308
+ window.addEventListener("keydown", handleKeyDown);
1309
+ return () => window.removeEventListener("keydown", handleKeyDown);
1310
+ }, [toggleSidebar]);
1311
+ const state = open ? "expanded" : "collapsed";
1312
+ const contextValue = React7.useMemo(
1313
+ () => ({
1314
+ state,
1315
+ open,
1316
+ setOpen,
1317
+ isMobile,
1318
+ openMobile,
1319
+ setOpenMobile,
1320
+ toggleSidebar
1321
+ }),
1322
+ [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
1323
+ );
1324
+ return /* @__PURE__ */ jsx20(SidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx20(
1325
+ "div",
1326
+ {
1327
+ "data-slot": "sidebar-wrapper",
1328
+ className: cn(
1329
+ "group/sidebar-wrapper flex min-h-svh w-full [--sidebar-width:16rem] [--sidebar-width-icon:3rem] has-data-[variant=inset]:bg-sidebar",
1330
+ className
1331
+ ),
1332
+ ...props,
1333
+ children
1334
+ }
1335
+ ) });
1336
+ }
1337
+ function Sidebar({
1338
+ side = "left",
1339
+ variant = "sidebar",
1340
+ collapsible = "offcanvas",
1341
+ className,
1342
+ children,
1343
+ dir,
1344
+ ...props
1345
+ }) {
1346
+ const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
1347
+ if (collapsible === "none") {
1348
+ return /* @__PURE__ */ jsx20(
1349
+ "div",
1350
+ {
1351
+ "data-slot": "sidebar",
1352
+ className: cn(
1353
+ "flex h-full w-(--sidebar-width) flex-col bg-sidebar text-sidebar-foreground",
1354
+ className
1355
+ ),
1356
+ ...props,
1357
+ children
1358
+ }
1359
+ );
1360
+ }
1361
+ if (isMobile) {
1362
+ return /* @__PURE__ */ jsx20(Sheet, { open: openMobile, onOpenChange: setOpenMobile, ...props, children: /* @__PURE__ */ jsxs11(
1363
+ SheetContent,
1364
+ {
1365
+ dir,
1366
+ "data-sidebar": "sidebar",
1367
+ "data-slot": "sidebar",
1368
+ "data-mobile": "true",
1369
+ className: "w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [--sidebar-width:18rem] [&>button]:hidden",
1370
+ side,
1371
+ children: [
1372
+ /* @__PURE__ */ jsxs11(SheetHeader, { className: "sr-only", children: [
1373
+ /* @__PURE__ */ jsx20(SheetTitle, { children: "Sidebar" }),
1374
+ /* @__PURE__ */ jsx20(SheetDescription, { children: "Displays the mobile sidebar." })
1375
+ ] }),
1376
+ /* @__PURE__ */ jsx20("div", { className: "flex h-full w-full flex-col", children })
1377
+ ]
1378
+ }
1379
+ ) });
1380
+ }
1381
+ return /* @__PURE__ */ jsxs11(
1382
+ "div",
1383
+ {
1384
+ className: "group peer hidden text-sidebar-foreground md:block",
1385
+ "data-state": state,
1386
+ "data-collapsible": state === "collapsed" ? collapsible : "",
1387
+ "data-variant": variant,
1388
+ "data-side": side,
1389
+ "data-slot": "sidebar",
1390
+ children: [
1391
+ /* @__PURE__ */ jsx20(
1392
+ "div",
1393
+ {
1394
+ "data-slot": "sidebar-gap",
1395
+ className: cn(
1396
+ "relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
1397
+ "group-data-[collapsible=offcanvas]:w-0",
1398
+ "group-data-[side=right]:rotate-180",
1399
+ variant === "floating" || variant === "inset" ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)"
1400
+ )
1401
+ }
1402
+ ),
1403
+ /* @__PURE__ */ jsx20(
1404
+ "div",
1405
+ {
1406
+ "data-slot": "sidebar-container",
1407
+ "data-side": side,
1408
+ className: cn(
1409
+ "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear data-[side=left]:left-0 data-[side=left]:group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)] data-[side=right]:right-0 data-[side=right]:group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)] md:flex",
1410
+ // Adjust the padding for floating and inset variants.
1411
+ variant === "floating" || variant === "inset" ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
1412
+ className
1413
+ ),
1414
+ ...props,
1415
+ children: /* @__PURE__ */ jsx20(
1416
+ "div",
1417
+ {
1418
+ "data-sidebar": "sidebar",
1419
+ "data-slot": "sidebar-inner",
1420
+ className: "flex size-full flex-col bg-sidebar group-data-[variant=floating]:rounded-2xl group-data-[variant=floating]:shadow-sm group-data-[variant=floating]:ring-1 group-data-[variant=floating]:ring-sidebar-border",
1421
+ children
1422
+ }
1423
+ )
1424
+ }
1425
+ )
1426
+ ]
1427
+ }
1428
+ );
1429
+ }
1430
+ function SidebarTrigger({
1431
+ className,
1432
+ onClick,
1433
+ ...props
1434
+ }) {
1435
+ const { toggleSidebar } = useSidebar();
1436
+ return /* @__PURE__ */ jsxs11(
1437
+ Button,
1438
+ {
1439
+ "data-sidebar": "trigger",
1440
+ "data-slot": "sidebar-trigger",
1441
+ variant: "ghost",
1442
+ size: "icon-sm",
1443
+ className: cn(className),
1444
+ onClick: (event) => {
1445
+ onClick?.(event);
1446
+ toggleSidebar();
1447
+ },
1448
+ ...props,
1449
+ children: [
1450
+ /* @__PURE__ */ jsx20(PanelLeftIcon, {}),
1451
+ /* @__PURE__ */ jsx20("span", { className: "sr-only", children: "Toggle Sidebar" })
1452
+ ]
1453
+ }
1454
+ );
1455
+ }
1456
+ function SidebarRail({ className, ...props }) {
1457
+ const { toggleSidebar } = useSidebar();
1458
+ return /* @__PURE__ */ jsx20(
1459
+ "button",
1460
+ {
1461
+ "data-sidebar": "rail",
1462
+ "data-slot": "sidebar-rail",
1463
+ "aria-label": "Toggle Sidebar",
1464
+ tabIndex: -1,
1465
+ onClick: toggleSidebar,
1466
+ title: "Toggle Sidebar",
1467
+ className: cn(
1468
+ "absolute inset-y-0 z-20 hidden w-4 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] hover:after:bg-sidebar-border sm:flex ltr:-translate-x-1/2 rtl:-translate-x-1/2",
1469
+ "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
1470
+ "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
1471
+ "group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full hover:group-data-[collapsible=offcanvas]:bg-sidebar",
1472
+ "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
1473
+ "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
1474
+ className
1475
+ ),
1476
+ ...props
1477
+ }
1478
+ );
1479
+ }
1480
+ function SidebarInset({ className, ...props }) {
1481
+ return /* @__PURE__ */ jsx20(
1482
+ "main",
1483
+ {
1484
+ "data-slot": "sidebar-inset",
1485
+ className: cn(
1486
+ "relative flex w-full flex-1 flex-col bg-background md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-2xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
1487
+ className
1488
+ ),
1489
+ ...props
1490
+ }
1491
+ );
1492
+ }
1493
+ function SidebarHeader({ className, ...props }) {
1494
+ return /* @__PURE__ */ jsx20(
1495
+ "div",
1496
+ {
1497
+ "data-slot": "sidebar-header",
1498
+ "data-sidebar": "header",
1499
+ className: cn(
1500
+ "flex flex-col gap-2 p-2 [--radius:var(--radius-xl)]",
1501
+ className
1502
+ ),
1503
+ ...props
1504
+ }
1505
+ );
1506
+ }
1507
+ function SidebarFooter({ className, ...props }) {
1508
+ return /* @__PURE__ */ jsx20(
1509
+ "div",
1510
+ {
1511
+ "data-slot": "sidebar-footer",
1512
+ "data-sidebar": "footer",
1513
+ className: cn("flex flex-col gap-2 p-2", className),
1514
+ ...props
1515
+ }
1516
+ );
1517
+ }
1518
+ function SidebarContent({ className, ...props }) {
1519
+ return /* @__PURE__ */ jsx20(
1520
+ "div",
1521
+ {
1522
+ "data-slot": "sidebar-content",
1523
+ "data-sidebar": "content",
1524
+ className: cn(
1525
+ "no-scrollbar flex min-h-0 flex-1 flex-col gap-2 overflow-auto [--radius:var(--radius-xl)] group-data-[collapsible=icon]:overflow-hidden",
1526
+ className
1527
+ ),
1528
+ ...props
1529
+ }
1530
+ );
1531
+ }
1532
+ function SidebarGroup({ className, ...props }) {
1533
+ return /* @__PURE__ */ jsx20(
1534
+ "div",
1535
+ {
1536
+ "data-slot": "sidebar-group",
1537
+ "data-sidebar": "group",
1538
+ className: cn("relative flex w-full min-w-0 flex-col p-2", className),
1539
+ ...props
1540
+ }
1541
+ );
1542
+ }
1543
+ function SidebarGroupContent({
1544
+ className,
1545
+ ...props
1546
+ }) {
1547
+ return /* @__PURE__ */ jsx20(
1548
+ "div",
1549
+ {
1550
+ "data-slot": "sidebar-group-content",
1551
+ "data-sidebar": "group-content",
1552
+ className: cn("w-full text-sm", className),
1553
+ ...props
1554
+ }
1555
+ );
1556
+ }
1557
+ function SidebarMenu({ className, ...props }) {
1558
+ return /* @__PURE__ */ jsx20(
1559
+ "ul",
1560
+ {
1561
+ "data-slot": "sidebar-menu",
1562
+ "data-sidebar": "menu",
1563
+ className: cn("flex w-full min-w-0 flex-col gap-0.5", className),
1564
+ ...props
1565
+ }
1566
+ );
1567
+ }
1568
+ function SidebarMenuItem({ className, ...props }) {
1569
+ return /* @__PURE__ */ jsx20(
1570
+ "li",
1571
+ {
1572
+ "data-slot": "sidebar-menu-item",
1573
+ "data-sidebar": "menu-item",
1574
+ className: cn("group/menu-item relative", className),
1575
+ ...props
1576
+ }
1577
+ );
1578
+ }
1579
+ var sidebarMenuButtonVariants = cva3(
1580
+ "peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-xl px-3 py-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:font-medium data-active:text-sidebar-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate",
1581
+ {
1582
+ variants: {
1583
+ variant: {
1584
+ default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
1585
+ outline: "bg-background shadow-[0_0_0_1px_var(--sidebar-border)] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_var(--sidebar-accent)]"
1586
+ },
1587
+ size: {
1588
+ default: "h-9 text-sm",
1589
+ sm: "h-8 text-xs",
1590
+ lg: "h-14 px-3 text-sm group-data-[collapsible=icon]:p-0!"
1591
+ }
1592
+ },
1593
+ defaultVariants: {
1594
+ variant: "default",
1595
+ size: "default"
1596
+ }
1597
+ }
1598
+ );
1599
+ function SidebarMenuButton({
1600
+ asChild = false,
1601
+ isActive = false,
1602
+ variant = "default",
1603
+ size = "default",
1604
+ tooltip,
1605
+ className,
1606
+ ...props
1607
+ }) {
1608
+ const Comp = asChild ? Slot4.Root : "button";
1609
+ const { isMobile, state } = useSidebar();
1610
+ const button = /* @__PURE__ */ jsx20(
1611
+ Comp,
1612
+ {
1613
+ "data-slot": "sidebar-menu-button",
1614
+ "data-sidebar": "menu-button",
1615
+ "data-size": size,
1616
+ "data-active": isActive,
1617
+ className: cn(sidebarMenuButtonVariants({ variant, size }), className),
1618
+ ...props
1619
+ }
1620
+ );
1621
+ if (!tooltip) {
1622
+ return button;
1623
+ }
1624
+ if (typeof tooltip === "string") {
1625
+ tooltip = {
1626
+ children: tooltip
1627
+ };
1628
+ }
1629
+ return /* @__PURE__ */ jsxs11(Tooltip, { children: [
1630
+ /* @__PURE__ */ jsx20(TooltipTrigger, { asChild: true, children: button }),
1631
+ /* @__PURE__ */ jsx20(
1632
+ TooltipContent,
1633
+ {
1634
+ side: "right",
1635
+ align: "center",
1636
+ hidden: state !== "collapsed" || isMobile,
1637
+ ...tooltip
1638
+ }
1639
+ )
1640
+ ] });
1641
+ }
1642
+ function SidebarMenuAction({
1643
+ className,
1644
+ asChild = false,
1645
+ showOnHover = false,
1646
+ ...props
1647
+ }) {
1648
+ const Comp = asChild ? Slot4.Root : "button";
1649
+ return /* @__PURE__ */ jsx20(
1650
+ Comp,
1651
+ {
1652
+ "data-slot": "sidebar-menu-action",
1653
+ "data-sidebar": "menu-action",
1654
+ className: cn(
1655
+ "absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-xl p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform group-data-[collapsible=icon]:hidden peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[size=default]/menu-button:top-2 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1 after:absolute after:-inset-2 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 md:after:hidden [&>svg]:size-4 [&>svg]:shrink-0",
1656
+ showOnHover && "group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 peer-data-active/menu-button:text-sidebar-accent-foreground aria-expanded:opacity-100 md:opacity-0",
1657
+ className
1658
+ ),
1659
+ ...props
1660
+ }
1661
+ );
1662
+ }
1663
+
1664
+ // scaffold/src/components/chat/identity-control.tsx
1665
+ import { jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
1666
+ function identityLabel(identity) {
1667
+ if (identity.displayName) return identity.displayName;
1668
+ if (identity.state === "authenticated") return "Signed in";
1669
+ if (identity.state === "loading") return "Loading identity";
1670
+ if (identity.state === "error") return "Identity unavailable";
1671
+ if (identity.state === "signed_out") return "Sign in";
1672
+ return "Guest";
1673
+ }
1674
+ function IdentityAvatar({ identity }) {
1675
+ const label = identityLabel(identity);
1676
+ if (identity.avatarUrl) {
1677
+ return /* @__PURE__ */ jsx21("img", { alt: "", className: "size-6 rounded-full object-cover", src: identity.avatarUrl });
1678
+ }
1679
+ return /* @__PURE__ */ jsx21("span", { className: "flex size-6 items-center justify-center rounded-full bg-sidebar-accent text-[10px] font-semibold", "aria-hidden": "true", children: identity.displayName ? identity.displayName.slice(0, 1).toUpperCase() : /* @__PURE__ */ jsx21(UserRound, { className: "size-3.5" }) });
1680
+ }
1681
+ function IdentityControl({ identity }) {
1682
+ const label = identityLabel(identity);
1683
+ const canSignOut = identity.state === "authenticated" && Boolean(identity.onSignOut);
1684
+ const canSignIn = (identity.state === "guest" || identity.state === "signed_out" || identity.state === "error") && Boolean(identity.onSignIn);
1685
+ return /* @__PURE__ */ jsx21(SidebarMenu, { className: "w-full min-w-0", children: /* @__PURE__ */ jsx21(SidebarMenuItem, { className: "w-full min-w-0", children: /* @__PURE__ */ jsxs12(DropdownMenu, { children: [
1686
+ /* @__PURE__ */ jsx21(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs12(
1687
+ SidebarMenuButton,
1688
+ {
1689
+ size: "lg",
1690
+ "aria-label": `Account: ${label}`,
1691
+ className: "w-full min-w-0 justify-start",
1692
+ children: [
1693
+ /* @__PURE__ */ jsx21(IdentityAvatar, { identity }),
1694
+ /* @__PURE__ */ jsxs12("span", { className: "min-w-0 flex-1 overflow-hidden text-start", children: [
1695
+ /* @__PURE__ */ jsx21("span", { className: "block truncate text-sm font-medium", children: label }),
1696
+ identity.secondaryText ? /* @__PURE__ */ jsx21("span", { className: "block truncate text-xs text-muted-foreground", children: identity.secondaryText }) : null
1697
+ ] })
1698
+ ]
1699
+ }
1700
+ ) }),
1701
+ /* @__PURE__ */ jsxs12(DropdownMenuContent, { align: "start", side: "top", sideOffset: 8, children: [
1702
+ /* @__PURE__ */ jsxs12(DropdownMenuLabel, { children: [
1703
+ /* @__PURE__ */ jsx21("span", { className: "block truncate", children: label }),
1704
+ identity.secondaryText ? /* @__PURE__ */ jsx21("span", { className: "mt-0.5 block truncate text-xs font-normal text-muted-foreground", children: identity.secondaryText }) : null
1705
+ ] }),
1706
+ canSignIn || canSignOut ? /* @__PURE__ */ jsx21(DropdownMenuSeparator, {}) : null,
1707
+ canSignIn ? /* @__PURE__ */ jsxs12(DropdownMenuItem, { onSelect: () => identity.onSignIn?.(), children: [
1708
+ /* @__PURE__ */ jsx21(LogIn, {}),
1709
+ "Sign in"
1710
+ ] }) : null,
1711
+ canSignOut ? /* @__PURE__ */ jsxs12(DropdownMenuItem, { onSelect: () => identity.onSignOut?.(), children: [
1712
+ /* @__PURE__ */ jsx21(LogOut, {}),
1713
+ "Sign out"
1714
+ ] }) : null
1715
+ ] })
1716
+ ] }) }) });
1717
+ }
1718
+
1719
+ // scaffold/src/components/chat/thread-sidebar.tsx
1720
+ import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
1721
+ function ThreadStatus({ thread }) {
1722
+ const activity = getThreadActivity(thread);
1723
+ if (!activity.isSpinning) return null;
1724
+ const label = activity.status === "cancelling" ? "Cancelling" : activity.status === "queued" ? "Queued" : "Running";
1725
+ return /* @__PURE__ */ jsx22(
1726
+ "span",
1727
+ {
1728
+ className: "pointer-events-none absolute end-1 top-1/2 hidden size-5 -translate-y-1/2 items-center justify-center text-muted-foreground transition-opacity group-hover/menu-item:opacity-0 md:flex",
1729
+ role: "status",
1730
+ "aria-label": label,
1731
+ title: label,
1732
+ children: /* @__PURE__ */ jsx22(LoaderCircle2, { className: "size-3.5 animate-spin" })
1733
+ }
1734
+ );
1735
+ }
1736
+ function ThreadSidebar({ activeThreadId, hasMore, identity, isLoading, isLoadingMore, onDelete, onLoadMore, onNew, onOpen, threads }) {
1737
+ const { setOpenMobile } = useSidebar();
1738
+ return /* @__PURE__ */ jsxs13(
1739
+ Sidebar,
1740
+ {
1741
+ "aria-label": "Conversations",
1742
+ collapsible: "offcanvas",
1743
+ "data-agents24-chat-sidebar": "",
1744
+ role: "navigation",
1745
+ children: [
1746
+ /* @__PURE__ */ jsxs13(SidebarHeader, { className: "gap-1 p-2", children: [
1747
+ /* @__PURE__ */ jsx22("div", { className: "h-8 shrink-0", "aria-hidden": "true" }),
1748
+ /* @__PURE__ */ jsxs13(Button, { className: "w-full justify-start", variant: "ghost", onClick: () => {
1749
+ onNew();
1750
+ setOpenMobile(false);
1751
+ }, children: [
1752
+ /* @__PURE__ */ jsx22(SquarePen, {}),
1753
+ " New chat"
1754
+ ] })
1755
+ ] }),
1756
+ /* @__PURE__ */ jsx22(SidebarContent, { children: /* @__PURE__ */ jsx22(SidebarGroup, { children: /* @__PURE__ */ jsxs13(SidebarGroupContent, { children: [
1757
+ /* @__PURE__ */ jsx22(SidebarMenu, { children: threads.map((thread) => /* @__PURE__ */ jsxs13(SidebarMenuItem, { children: [
1758
+ /* @__PURE__ */ jsx22(
1759
+ SidebarMenuButton,
1760
+ {
1761
+ className: "pr-8 pl-3",
1762
+ isActive: thread.id === activeThreadId,
1763
+ title: String(thread.title || "New conversation"),
1764
+ onClick: () => {
1765
+ void onOpen(thread.id).catch(() => void 0);
1766
+ setOpenMobile(false);
1767
+ },
1768
+ children: /* @__PURE__ */ jsx22("span", { className: "min-w-0 truncate", children: String(thread.title || "New conversation") })
1769
+ }
1770
+ ),
1771
+ /* @__PURE__ */ jsx22(ThreadStatus, { thread }),
1772
+ /* @__PURE__ */ jsx22(
1773
+ SidebarMenuAction,
1774
+ {
1775
+ showOnHover: true,
1776
+ className: "group-focus-within/menu-item:opacity-0 group-hover/menu-item:opacity-100",
1777
+ "aria-label": `Delete ${String(thread.title || "conversation")}`,
1778
+ onClick: (event) => {
1779
+ event.stopPropagation();
1780
+ if (window.confirm("Delete this conversation?")) void onDelete(thread.id).catch(() => void 0);
1781
+ },
1782
+ children: /* @__PURE__ */ jsx22(Trash2, {})
1783
+ }
1784
+ )
1785
+ ] }, thread.id)) }),
1786
+ !isLoading && threads.length === 0 && /* @__PURE__ */ jsx22("p", { className: "px-2 py-8 text-center text-xs text-muted-foreground", children: "No conversations" }),
1787
+ hasMore && /* @__PURE__ */ jsxs13(
1788
+ Button,
1789
+ {
1790
+ className: "mt-2 w-full",
1791
+ disabled: isLoadingMore,
1792
+ size: "sm",
1793
+ variant: "ghost",
1794
+ onClick: () => void onLoadMore().catch(() => void 0),
1795
+ children: [
1796
+ isLoadingMore && /* @__PURE__ */ jsx22(LoaderCircle2, { className: "animate-spin" }),
1797
+ "Load more"
1798
+ ]
1799
+ }
1800
+ )
1801
+ ] }) }) }),
1802
+ /* @__PURE__ */ jsx22(SidebarFooter, { className: "w-full min-w-0 p-2", children: /* @__PURE__ */ jsx22(IdentityControl, { identity }) }),
1803
+ /* @__PURE__ */ jsx22(SidebarRail, {})
1804
+ ]
1805
+ }
1806
+ );
1807
+ }
1808
+
1809
+ // scaffold/src/components/chat/turn-outline.tsx
1810
+ import { useState as useState8 } from "react";
1811
+
1812
+ // scaffold/src/components/ui/message-scroller.tsx
1813
+ import {
1814
+ MessageScroller as MessageScrollerPrimitive,
1815
+ useMessageScroller,
1816
+ useMessageScrollerScrollable,
1817
+ useMessageScrollerVisibility
1818
+ } from "@shadcn/react/message-scroller";
1819
+ import { ArrowDownIcon } from "lucide-react";
1820
+ import { Fragment as Fragment3, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
1821
+ function MessageScrollerProvider(props) {
1822
+ return /* @__PURE__ */ jsx23(MessageScrollerPrimitive.Provider, { ...props });
1823
+ }
1824
+ function MessageScroller({
1825
+ className,
1826
+ ...props
1827
+ }) {
1828
+ return /* @__PURE__ */ jsx23(
1829
+ MessageScrollerPrimitive.Root,
1830
+ {
1831
+ "data-slot": "message-scroller",
1832
+ className: cn(
1833
+ "group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden",
1834
+ className
1835
+ ),
1836
+ ...props
1837
+ }
1838
+ );
1839
+ }
1840
+ function MessageScrollerViewport({
1841
+ className,
1842
+ ...props
1843
+ }) {
1844
+ return /* @__PURE__ */ jsx23(
1845
+ MessageScrollerPrimitive.Viewport,
1846
+ {
1847
+ "data-slot": "message-scroller-viewport",
1848
+ className: cn(
1849
+ "size-full min-h-0 min-w-0 scroll-fade-b overflow-y-auto overscroll-contain contain-content [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
1850
+ className
1851
+ ),
1852
+ ...props
1853
+ }
1854
+ );
1855
+ }
1856
+ function MessageScrollerContent({
1857
+ className,
1858
+ ...props
1859
+ }) {
1860
+ return /* @__PURE__ */ jsx23(
1861
+ MessageScrollerPrimitive.Content,
1862
+ {
1863
+ "data-slot": "message-scroller-content",
1864
+ className: cn("flex h-max min-h-full flex-col gap-8", className),
1865
+ ...props
1866
+ }
1867
+ );
1868
+ }
1869
+ function MessageScrollerItem({
1870
+ className,
1871
+ scrollAnchor = false,
1872
+ ...props
1873
+ }) {
1874
+ return /* @__PURE__ */ jsx23(
1875
+ MessageScrollerPrimitive.Item,
1876
+ {
1877
+ "data-slot": "message-scroller-item",
1878
+ scrollAnchor,
1879
+ className: cn(
1880
+ "min-w-0 shrink-0 [contain-intrinsic-size:auto_10rem] [content-visibility:auto]",
1881
+ className
1882
+ ),
1883
+ ...props
1884
+ }
1885
+ );
1886
+ }
1887
+ function MessageScrollerButton({
1888
+ direction = "end",
1889
+ className,
1890
+ children,
1891
+ render,
1892
+ variant = "secondary",
1893
+ size = "icon-sm",
1894
+ ...props
1895
+ }) {
1896
+ return /* @__PURE__ */ jsx23(
1897
+ MessageScrollerPrimitive.Button,
1898
+ {
1899
+ "data-slot": "message-scroller-button",
1900
+ "data-direction": direction,
1901
+ "data-variant": variant,
1902
+ "data-size": size,
1903
+ direction,
1904
+ className: cn(
1905
+ "absolute inset-s-1/2 -translate-x-1/2 border-border bg-background text-foreground transition-[translate,scale,opacity] duration-200 hover:bg-muted hover:text-foreground data-[active=false]:pointer-events-none data-[active=false]:scale-95 data-[active=false]:opacity-0 data-[active=false]:duration-400 data-[active=false]:ease-[cubic-bezier(0.7,0,0.84,0)] data-[active=true]:translate-y-0 data-[active=true]:scale-100 data-[active=true]:opacity-100 data-[active=true]:ease-[cubic-bezier(0.23,1,0.32,1)] data-[direction=end]:bottom-4 data-[direction=end]:data-[active=false]:translate-y-full data-[direction=start]:top-4 data-[direction=start]:data-[active=false]:-translate-y-full rtl:translate-x-1/2 data-[direction=start]:[&_svg]:rotate-180",
1906
+ className
1907
+ ),
1908
+ render: render ?? /* @__PURE__ */ jsx23(Button, { variant, size }),
1909
+ ...props,
1910
+ children: children ?? /* @__PURE__ */ jsxs14(Fragment3, { children: [
1911
+ /* @__PURE__ */ jsx23(
1912
+ ArrowDownIcon,
1913
+ {}
1914
+ ),
1915
+ /* @__PURE__ */ jsx23("span", { className: "sr-only", children: direction === "end" ? "Scroll to end" : "Scroll to start" })
1916
+ ] })
1917
+ }
1918
+ );
1919
+ }
1920
+
1921
+ // scaffold/src/components/chat/turn-outline.tsx
1922
+ import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
1923
+ function turnsFromMessages(messages) {
1924
+ return messages.reduce((turns, message) => {
1925
+ if (message.role === "user") {
1926
+ turns.push({ id: message.id, label: message.content.trim() || `Turn ${turns.length + 1}`, messageIds: [message.id], response: "" });
1927
+ } else if (turns.length) {
1928
+ const turn = turns[turns.length - 1];
1929
+ turn.messageIds.push(message.id);
1930
+ if (!turn.response) turn.response = message.content.trim();
1931
+ }
1932
+ return turns;
1933
+ }, []);
1934
+ }
1935
+ function TurnOutline({ messages }) {
1936
+ const turns = turnsFromMessages(messages);
1937
+ const { scrollToMessage } = useMessageScroller();
1938
+ const { currentAnchorId, visibleMessageIds } = useMessageScrollerVisibility();
1939
+ const visible = new Set(visibleMessageIds);
1940
+ const [hoveredIndex, setHoveredIndex] = useState8(null);
1941
+ const focusIndex = hoveredIndex ?? -1;
1942
+ if (turns.length < 2) return null;
1943
+ return /* @__PURE__ */ jsx24("nav", { "aria-label": "Transcript outline", className: "pointer-events-none absolute end-2 top-1/2 z-20 hidden max-h-72 w-14 -translate-y-1/2 md:block xl:end-5", children: /* @__PURE__ */ jsx24("div", { className: "pointer-events-auto flex flex-col items-end gap-0.5 py-2", children: turns.map((turn, index) => {
1944
+ const active = turn.messageIds.some((id) => visible.has(id) || currentAnchorId === id);
1945
+ const distance = focusIndex >= 0 ? Math.abs(index - focusIndex) : Number.POSITIVE_INFINITY;
1946
+ const barWidth = focusIndex < 0 ? 12 : distance === 0 ? 50 : distance === 1 ? 36 : distance === 2 ? 23 : 10;
1947
+ const barOpacity = focusIndex < 0 ? active ? 1 : 0.4 : distance === 0 ? 1 : distance === 1 ? 0.78 : distance === 2 ? 0.58 : 0.36;
1948
+ return /* @__PURE__ */ jsxs15(Tooltip, { children: [
1949
+ /* @__PURE__ */ jsx24(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx24(
1950
+ "button",
1951
+ {
1952
+ type: "button",
1953
+ "aria-label": `Jump to ${turn.label}`,
1954
+ className: "group relative flex h-2 w-14 items-center justify-end outline-none after:pointer-events-auto after:absolute after:-inset-y-0.5 after:inset-x-0 after:content-['']",
1955
+ onBlur: () => setHoveredIndex(null),
1956
+ onFocus: () => setHoveredIndex(index),
1957
+ onMouseEnter: () => setHoveredIndex(index),
1958
+ onMouseLeave: () => setHoveredIndex(null),
1959
+ onClick: () => scrollToMessage(turn.id, { align: "start", behavior: "smooth" }),
1960
+ children: /* @__PURE__ */ jsx24(
1961
+ "span",
1962
+ {
1963
+ className: cn("h-0.5 rounded-full bg-muted-foreground/40 transition-[width,background-color,opacity] duration-150 ease-out group-hover:bg-foreground group-focus-visible:bg-foreground", active && "bg-foreground"),
1964
+ style: { opacity: barOpacity, width: barWidth }
1965
+ }
1966
+ )
1967
+ }
1968
+ ) }),
1969
+ /* @__PURE__ */ jsxs15(TooltipContent, { side: "left", className: "w-64 flex-col items-stretch gap-0 overflow-hidden p-3", children: [
1970
+ /* @__PURE__ */ jsx24("p", { className: "line-clamp-2 max-w-full wrap-break-word text-sm font-medium", children: turn.label }),
1971
+ turn.response && /* @__PURE__ */ jsx24("p", { className: "mt-1 line-clamp-2 max-w-full wrap-break-word text-xs opacity-70", children: turn.response })
1972
+ ] })
1973
+ ] }, turn.id);
1974
+ }) }) });
1975
+ }
1976
+
1977
+ // scaffold/src/components/chat/timeline-loading.ts
1978
+ function isScaffoldTimelineLoading({
1979
+ activeRunId,
1980
+ message,
1981
+ runState,
1982
+ streamingMessageId
1983
+ }) {
1984
+ if (runState !== "streaming" && runState !== "reconnecting") return false;
1985
+ return message.id === streamingMessageId || Boolean(message.runId && message.runId === activeRunId);
1986
+ }
1987
+
1988
+ // scaffold/src/components/chat/chat-shell.tsx
1989
+ import { Fragment as Fragment4, jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
1990
+ var LOADING_INPUT_CONTRACT = {
1991
+ version: "agents24.runtime-inputs.v2",
1992
+ modalities: {
1993
+ text: { enabled: false, required: false },
1994
+ files: { enabled: false, required: false, allowed_mime_types: [] },
1995
+ images: { enabled: false, required: false, allowed_mime_types: [] },
1996
+ audio: { enabled: false, required: false, allowed_mime_types: [], recording_enabled: false }
1997
+ },
1998
+ limits: { max_attachments_per_turn: 0, max_file_bytes: 0, max_total_bytes: 0 },
1999
+ retention: { mode: "thread_lifetime" }
2000
+ };
2001
+ function PersistentSidebarTrigger() {
2002
+ return /* @__PURE__ */ jsx25("div", { className: "pointer-events-none fixed start-3 top-0 z-[60] flex h-12 items-center", children: /* @__PURE__ */ jsx25(SidebarTrigger, { className: "pointer-events-auto [&_svg]:size-[18px]" }) });
2003
+ }
2004
+ function CollapsedHeaderActions({ onNew }) {
2005
+ const { isMobile, openMobile, state } = useSidebar();
2006
+ const sidebarVisible = isMobile ? openMobile : state === "expanded";
2007
+ if (sidebarVisible) return null;
2008
+ return /* @__PURE__ */ jsxs16(Fragment4, { children: [
2009
+ /* @__PURE__ */ jsx25("div", { className: "h-8 w-17 shrink-0", "aria-hidden": "true" }),
2010
+ /* @__PURE__ */ jsx25("div", { className: "pointer-events-none fixed start-12 top-0 z-[60] flex h-12 items-center", children: /* @__PURE__ */ jsx25(Button, { className: "pointer-events-auto", variant: "ghost", size: "icon-sm", "aria-label": "New chat", onClick: onNew, children: /* @__PURE__ */ jsx25(SquarePen2, {}) }) })
2011
+ ] });
2012
+ }
2013
+ function OperationErrorNotice({ runtime }) {
2014
+ const error = runtime.operationError || runtime.backgroundError;
2015
+ if (!error) return null;
2016
+ return /* @__PURE__ */ jsx25("div", { className: "pointer-events-none absolute inset-x-0 top-3 z-40 flex justify-center px-4", children: /* @__PURE__ */ jsxs16("div", { className: "pointer-events-auto flex max-w-lg items-start gap-2 rounded-lg border border-destructive/20 bg-background px-3 py-2 text-sm shadow-md", role: "alert", children: [
2017
+ /* @__PURE__ */ jsx25(CircleAlert, { className: "mt-0.5 size-4 shrink-0 text-destructive" }),
2018
+ /* @__PURE__ */ jsx25("span", { className: "min-w-0 flex-1 wrap-break-word", children: agentChatRuntimeErrorMessage(error) || "The chat could not complete that action." }),
2019
+ /* @__PURE__ */ jsx25(
2020
+ Button,
2021
+ {
2022
+ "aria-label": "Dismiss error",
2023
+ onClick: runtime.operationError ? runtime.clearOperationError : runtime.controller.clearBackgroundError,
2024
+ size: "icon-xs",
2025
+ variant: "ghost",
2026
+ children: /* @__PURE__ */ jsx25(X2, {})
2027
+ }
2028
+ )
2029
+ ] }) });
2030
+ }
2031
+ function ChatShell({
2032
+ components,
2033
+ identity,
2034
+ runtime
2035
+ }) {
2036
+ const { controller } = runtime;
2037
+ const isRunning = controller.runState === "streaming" || controller.runState === "reconnecting" || controller.runState === "paused" || controller.runState === "cancelling" || runtime.isSubmitting;
2038
+ const isCancelling = controller.runState === "cancelling";
2039
+ const activeTitle = controller.threads.find((thread) => thread.id === controller.activeThreadId)?.title;
2040
+ const hasBlockingError = Boolean(runtime.fatalError && controller.messages.length === 0);
2041
+ const isEmptyState = controller.activeThreadId === null && controller.messages.length === 0 && !hasBlockingError;
2042
+ return /* @__PURE__ */ jsxs16(
2043
+ SidebarProvider,
2044
+ {
2045
+ className: "h-svh min-h-0 overflow-hidden",
2046
+ "data-agents24-chat": "",
2047
+ "data-agents24-chat-layout": "",
2048
+ children: [
2049
+ /* @__PURE__ */ jsx25(PersistentSidebarTrigger, {}),
2050
+ /* @__PURE__ */ jsx25(
2051
+ ThreadSidebar,
2052
+ {
2053
+ activeThreadId: controller.activeThreadId,
2054
+ hasMore: controller.hasMoreThreads,
2055
+ identity,
2056
+ isLoading: controller.isLoadingThreads,
2057
+ isLoadingMore: controller.isLoadingMoreThreads,
2058
+ threads: controller.threads,
2059
+ onDelete: runtime.deleteThread,
2060
+ onLoadMore: controller.loadMoreThreads,
2061
+ onNew: runtime.newThread,
2062
+ onOpen: runtime.openThread
2063
+ }
2064
+ ),
2065
+ /* @__PURE__ */ jsxs16(SidebarInset, { className: "h-svh min-h-0 overflow-hidden bg-background", children: [
2066
+ /* @__PURE__ */ jsxs16(
2067
+ "header",
2068
+ {
2069
+ className: "flex h-12 shrink-0 items-center gap-2 border-b border-border/30 px-3 sm:px-4",
2070
+ "data-agents24-chat-header": "",
2071
+ children: [
2072
+ /* @__PURE__ */ jsx25(CollapsedHeaderActions, { onNew: runtime.newThread }),
2073
+ /* @__PURE__ */ jsx25("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx25("h1", { className: "truncate text-sm font-medium", children: String(activeTitle || "New chat") }) }),
2074
+ /* @__PURE__ */ jsx25(ThemeMenu, {})
2075
+ ]
2076
+ }
2077
+ ),
2078
+ /* @__PURE__ */ jsxs16(
2079
+ "section",
2080
+ {
2081
+ "aria-label": "Conversation",
2082
+ className: "relative flex min-h-0 flex-1 flex-col overflow-hidden",
2083
+ "data-agents24-chat-transcript": "",
2084
+ children: [
2085
+ /* @__PURE__ */ jsx25(OperationErrorNotice, { runtime }),
2086
+ isEmptyState ? /* @__PURE__ */ jsxs16("div", { className: "absolute inset-0 flex min-h-0 flex-col justify-center pb-20", children: [
2087
+ /* @__PURE__ */ jsx25("div", { className: "mx-auto mb-8 w-full max-w-3xl px-4 text-center sm:px-6", children: /* @__PURE__ */ jsx25("h2", { className: "text-3xl font-semibold tracking-tight sm:text-4xl", children: "Ready when you are." }) }),
2088
+ /* @__PURE__ */ jsx25(
2089
+ ChatComposer,
2090
+ {
2091
+ inputContract: runtime.inputContract || LOADING_INPUT_CONTRACT,
2092
+ contextWindow: runtime.contextWindow,
2093
+ disabled: runtime.isBootstrapping,
2094
+ forceExpanded: true,
2095
+ isCancelling,
2096
+ isRunning,
2097
+ onStop: () => {
2098
+ void controller.cancelRun().catch(() => void 0);
2099
+ },
2100
+ modelId: runtime.modelId,
2101
+ models: runtime.models,
2102
+ onModelChange: runtime.changeModel,
2103
+ onSubmit: (text, files) => runtime.submit({
2104
+ text,
2105
+ files: files.map((file) => ({
2106
+ data: file,
2107
+ mediaType: file.type || "application/octet-stream",
2108
+ name: file.name
2109
+ }))
2110
+ })
2111
+ }
2112
+ )
2113
+ ] }) : /* @__PURE__ */ jsxs16(Fragment4, { children: [
2114
+ /* @__PURE__ */ jsx25(
2115
+ MessageScrollerProvider,
2116
+ {
2117
+ autoScroll: true,
2118
+ defaultScrollPosition: "last-anchor",
2119
+ scrollPreviousItemPeek: 64,
2120
+ children: /* @__PURE__ */ jsxs16(MessageScroller, { className: "relative min-h-0 flex-1", children: [
2121
+ /* @__PURE__ */ jsx25(MessageScrollerViewport, { preserveScrollOnPrepend: true, children: /* @__PURE__ */ jsxs16(
2122
+ MessageScrollerContent,
2123
+ {
2124
+ className: "mx-auto w-full max-w-3xl gap-7 px-4 pt-8 pb-16 sm:px-6 sm:pt-12",
2125
+ children: [
2126
+ controller.hasOlderTurns && /* @__PURE__ */ jsxs16(Button, { className: "self-center", variant: "ghost", size: "sm", disabled: controller.isLoadingOlder, onClick: () => {
2127
+ void controller.loadOlder().catch(() => void 0);
2128
+ }, children: [
2129
+ controller.isLoadingOlder && /* @__PURE__ */ jsx25(LoaderCircle3, { className: "animate-spin" }),
2130
+ " Load earlier messages"
2131
+ ] }),
2132
+ runtime.isBootstrapping && /* @__PURE__ */ jsx25("div", { "aria-label": "Loading conversation", className: "flex flex-1 items-center justify-center py-24 text-muted-foreground", role: "status", children: /* @__PURE__ */ jsx25(LoaderCircle3, { className: "size-4 animate-spin" }) }),
2133
+ hasBlockingError && /* @__PURE__ */ jsxs16("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 py-24 text-center", children: [
2134
+ /* @__PURE__ */ jsx25(CircleAlert, { className: "size-5 text-destructive" }),
2135
+ /* @__PURE__ */ jsxs16("div", { children: [
2136
+ /* @__PURE__ */ jsx25("h2", { className: "font-medium", children: "Couldn\u2019t connect" }),
2137
+ /* @__PURE__ */ jsx25("p", { className: "mt-1 max-w-md text-sm text-muted-foreground", children: runtime.errorMessage })
2138
+ ] }),
2139
+ /* @__PURE__ */ jsx25(Button, { variant: "outline", onClick: () => void runtime.retryBootstrap(), children: "Try again" })
2140
+ ] }),
2141
+ controller.messages.map((message) => /* @__PURE__ */ jsx25(
2142
+ MessageScrollerItem,
2143
+ {
2144
+ messageId: message.id,
2145
+ scrollAnchor: message.role === "user",
2146
+ className: "overflow-visible [content-visibility:visible]",
2147
+ children: /* @__PURE__ */ jsx25(
2148
+ ChatMessage,
2149
+ {
2150
+ allowFeedback: runtime.allowFeedback,
2151
+ getHitlActionState: runtime.getHitlActionState,
2152
+ isLoading: isScaffoldTimelineLoading({
2153
+ activeRunId: controller.activeRunId,
2154
+ message,
2155
+ runState: controller.runState,
2156
+ streamingMessageId: controller.streamingMessageId
2157
+ }),
2158
+ message,
2159
+ onHitlAction: runtime.onHitlAction,
2160
+ onRegenerate: () => controller.regenerate(message),
2161
+ onSetFeedback: (input) => controller.setFeedback(message, input),
2162
+ Timeline: components?.Timeline
2163
+ }
2164
+ )
2165
+ },
2166
+ message.id
2167
+ ))
2168
+ ]
2169
+ }
2170
+ ) }),
2171
+ /* @__PURE__ */ jsx25(TurnOutline, { messages: controller.messages }),
2172
+ /* @__PURE__ */ jsx25(MessageScrollerButton, {})
2173
+ ] })
2174
+ }
2175
+ ),
2176
+ /* @__PURE__ */ jsx25("div", { className: "relative z-30 shrink-0 bg-background pt-3", children: /* @__PURE__ */ jsx25(
2177
+ ChatComposer,
2178
+ {
2179
+ inputContract: runtime.inputContract || LOADING_INPUT_CONTRACT,
2180
+ contextWindow: runtime.contextWindow,
2181
+ disabled: runtime.isBootstrapping || hasBlockingError,
2182
+ isCancelling,
2183
+ isRunning,
2184
+ onStop: () => {
2185
+ void controller.cancelRun().catch(() => void 0);
2186
+ },
2187
+ modelId: runtime.modelId,
2188
+ models: runtime.models,
2189
+ onModelChange: runtime.changeModel,
2190
+ onSubmit: (text, files) => runtime.submit({
2191
+ text,
2192
+ files: files.map((file) => ({
2193
+ data: file,
2194
+ mediaType: file.type || "application/octet-stream",
2195
+ name: file.name
2196
+ }))
2197
+ }),
2198
+ utilityRow: "below"
2199
+ }
2200
+ ) })
2201
+ ] })
2202
+ ]
2203
+ }
2204
+ )
2205
+ ] })
2206
+ ]
2207
+ }
2208
+ );
2209
+ }
2210
+
2211
+ // scaffold/src/identity.ts
2212
+ var GUEST_CHAT_IDENTITY = { state: "guest" };
2213
+
2214
+ // scaffold/src/app.tsx
2215
+ import { jsx as jsx26 } from "react/jsx-runtime";
2216
+ var createBrowserAbortController = () => new AbortController();
2217
+ function RuntimeChat({
2218
+ components,
2219
+ identity = GUEST_CHAT_IDENTITY,
2220
+ ...props
2221
+ }) {
2222
+ const runtime = useAgentChatRuntime({
2223
+ ...props,
2224
+ mcpRedirectUri: props.mcpRedirectUri || (typeof window === "undefined" ? void 0 : window.location.href)
2225
+ });
2226
+ return /* @__PURE__ */ jsx26(ChatShell, { components, identity, runtime });
2227
+ }
2228
+ function App(props) {
2229
+ const identity = props.identity || GUEST_CHAT_IDENTITY;
2230
+ return /* @__PURE__ */ jsx26(Agents24Provider, { client: props.client, createAbortController: createBrowserAbortController, children: /* @__PURE__ */ jsx26(RuntimeChat, { ...props }, identity.state) });
2231
+ }
2232
+
2233
+ // scaffold/src/index.tsx
2234
+ import { jsx as jsx27 } from "react/jsx-runtime";
2235
+ function Agents24ChatScaffold({ appearanceController, theme, ...props }) {
2236
+ return /* @__PURE__ */ jsx27(ThemeProvider, { controller: appearanceController, theme, children: /* @__PURE__ */ jsx27(TooltipProvider, { children: /* @__PURE__ */ jsx27(App, { ...props }) }) });
2237
+ }
2238
+ export {
2239
+ Agents24ChatScaffold,
2240
+ App as Agents24ChatScaffoldApp,
2241
+ ThemeProvider as Agents24ChatThemeProvider,
2242
+ TooltipProvider as Agents24ChatTooltipProvider
2243
+ };
2244
+ //# sourceMappingURL=index.js.map