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