@timbal-ai/timbal-react 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -32,11 +32,12 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  ARTIFACT_AGENT_INSTRUCTIONS: () => ARTIFACT_AGENT_INSTRUCTIONS,
34
34
  ARTIFACT_FENCE_LANGUAGES: () => ARTIFACT_FENCE_LANGUAGES,
35
- ActionBarPrimitive: () => import_react26.ActionBarPrimitive,
35
+ ActionBarPrimitive: () => import_react45.ActionBarPrimitive,
36
36
  ArtifactCard: () => ArtifactCard,
37
37
  ArtifactRegistryProvider: () => ArtifactRegistryProvider,
38
38
  ArtifactView: () => ArtifactView,
39
- AssistantRuntimeProvider: () => import_react26.AssistantRuntimeProvider,
39
+ AssistantRuntimeProvider: () => import_react45.AssistantRuntimeProvider,
40
+ AuiIf: () => import_react45.AuiIf,
40
41
  AuthGuard: () => AuthGuard,
41
42
  Avatar: () => Avatar,
42
43
  AvatarFallback: () => AvatarFallback,
@@ -44,9 +45,7 @@ __export(index_exports, {
44
45
  Button: () => Button,
45
46
  ChartArtifactView: () => ChartArtifactView,
46
47
  Composer: () => Composer,
47
- ComposerAddAttachment: () => ComposerAddAttachment,
48
- ComposerAttachments: () => ComposerAttachments,
49
- ComposerPrimitive: () => import_react26.ComposerPrimitive,
48
+ ComposerPrimitive: () => import_react45.ComposerPrimitive,
50
49
  DEFAULT_UPLOAD_ACCEPT: () => DEFAULT_UPLOAD_ACCEPT,
51
50
  Dialog: () => Dialog,
52
51
  DialogClose: () => DialogClose,
@@ -58,18 +57,22 @@ __export(index_exports, {
58
57
  HtmlArtifactView: () => HtmlArtifactView,
59
58
  JsonArtifactView: () => JsonArtifactView,
60
59
  MarkdownText: () => MarkdownText,
61
- MessagePrimitive: () => import_react26.MessagePrimitive,
60
+ MessagePrimitive: () => import_react45.MessagePrimitive,
61
+ ModeToggle: () => ModeToggle,
62
62
  QuestionArtifactView: () => QuestionArtifactView,
63
63
  SessionProvider: () => SessionProvider,
64
64
  Shimmer: () => Shimmer,
65
+ StudioSidebar: () => StudioSidebar,
66
+ StudioWelcome: () => StudioWelcome,
65
67
  Suggestions: () => Suggestions,
66
- SyntaxHighlighter: () => syntax_highlighter_default,
67
68
  TableArtifactView: () => TableArtifactView,
68
69
  Thread: () => Thread,
69
- ThreadPrimitive: () => import_react26.ThreadPrimitive,
70
+ ThreadPrimitive: () => import_react45.ThreadPrimitive,
70
71
  TimbalChat: () => TimbalChat,
71
72
  TimbalChatShell: () => TimbalChatShell,
73
+ TimbalMark: () => TimbalMark,
72
74
  TimbalRuntimeProvider: () => TimbalRuntimeProvider,
75
+ TimbalStudioShell: () => TimbalStudioShell,
73
76
  ToolArtifactFallback: () => ToolArtifactFallback,
74
77
  ToolFallback: () => ToolFallback,
75
78
  Tooltip: () => Tooltip,
@@ -81,10 +84,8 @@ __export(index_exports, {
81
84
  UiCustomNodeRegistryProvider: () => UiCustomNodeRegistryProvider,
82
85
  UiEventProvider: () => UiEventProvider,
83
86
  UiNodeView: () => UiNodeView,
84
- UserMessageAttachments: () => UserMessageAttachments,
85
87
  WorkforceSelector: () => WorkforceSelector,
86
88
  authFetch: () => authFetch,
87
- buttonVariants: () => buttonVariants,
88
89
  clearTokens: () => clearTokens,
89
90
  cn: () => cn,
90
91
  createDefaultAttachmentAdapter: () => createDefaultAttachmentAdapter,
@@ -108,14 +109,16 @@ __export(index_exports, {
108
109
  setRefreshToken: () => setRefreshToken,
109
110
  splitMarkdownByArtifacts: () => splitMarkdownByArtifacts,
110
111
  useArtifactRegistry: () => useArtifactRegistry,
111
- useComposerRuntime: () => import_react26.useComposerRuntime,
112
- useMessageRuntime: () => import_react26.useMessageRuntime,
112
+ useComposerRuntime: () => import_react45.useComposerRuntime,
113
+ useMessageRuntime: () => import_react45.useMessageRuntime,
114
+ useOptionalSession: () => useOptionalSession,
113
115
  useResolvedSuggestions: () => useResolvedSuggestions,
114
116
  useSession: () => useSession,
115
- useThread: () => import_react26.useThread,
116
- useThreadRuntime: () => import_react26.useThreadRuntime,
117
+ useThread: () => import_react45.useThread,
118
+ useThreadRuntime: () => import_react45.useThreadRuntime,
117
119
  useTimbalRuntime: () => useTimbalRuntime,
118
120
  useTimbalStream: () => useTimbalStream,
121
+ useToolRunning: () => useToolRunning,
119
122
  useUiCustomNodeRegistry: () => useUiCustomNodeRegistry,
120
123
  useUiDispatch: () => useUiDispatch,
121
124
  useUiEventEmitter: () => useUiEventEmitter,
@@ -982,6 +985,12 @@ function findParentIdFromAuiParent(messages, auiParentId) {
982
985
  // src/index.ts
983
986
  var import_timbal_sdk2 = require("@timbal-ai/timbal-sdk");
984
987
 
988
+ // src/components/thread.tsx
989
+ var import_react25 = require("react");
990
+ var import_react26 = require("@assistant-ui/react");
991
+ var import_lucide_react8 = require("lucide-react");
992
+ var import_react27 = require("motion/react");
993
+
985
994
  // src/components/attachment.tsx
986
995
  var import_react4 = require("react");
987
996
  var import_lucide_react2 = require("lucide-react");
@@ -1189,83 +1198,166 @@ function AvatarFallback({
1189
1198
 
1190
1199
  // src/components/tooltip-icon-button.tsx
1191
1200
  var import_react3 = require("react");
1192
- var import_react_slot = require("@radix-ui/react-slot");
1193
1201
 
1194
- // src/ui/button.tsx
1195
- var import_class_variance_authority = require("class-variance-authority");
1202
+ // src/ui/timbal-v2-button.tsx
1203
+ var React = __toESM(require("react"), 1);
1196
1204
  var import_radix_ui4 = require("radix-ui");
1205
+
1206
+ // src/design/button-tokens.ts
1207
+ var TIMBAL_V2_SIZE_HEIGHT = {
1208
+ xs: "min-h-8 h-8",
1209
+ sm: "min-h-9 h-9",
1210
+ md: "min-h-10 h-10",
1211
+ lg: "min-h-11 h-11"
1212
+ };
1213
+ var TIMBAL_V2_SIZE_ICON = {
1214
+ xs: "min-h-8 min-w-8 size-8",
1215
+ sm: "min-h-8 min-w-8 size-8",
1216
+ md: "min-h-10 min-w-10 size-10",
1217
+ lg: "min-h-11 min-w-11 size-11"
1218
+ };
1219
+ var TIMBAL_V2_SIZE_LABEL_PX = {
1220
+ xs: "px-3",
1221
+ sm: "px-4",
1222
+ md: "px-5",
1223
+ lg: "px-6"
1224
+ };
1225
+ var TIMBAL_V2_FILL = {
1226
+ primary: [
1227
+ "bg-gradient-to-b from-primary-fill-from to-primary-fill-to",
1228
+ "group-hover/tbv2:from-primary-fill-hover-from group-hover/tbv2:to-primary-fill-hover-to",
1229
+ "group-active/tbv2:from-primary-fill-active-from group-active/tbv2:to-primary-fill-active-to"
1230
+ ].join(" "),
1231
+ informative: [
1232
+ "bg-primary",
1233
+ "group-active/tbv2:[background-image:linear-gradient(to_top,rgba(0,0,0,0.08),transparent_55%)]"
1234
+ ].join(" "),
1235
+ destructive: [
1236
+ "bg-gradient-to-b from-elevated-from to-elevated-to",
1237
+ "group-hover/tbv2:from-destructive-fill-hover-from group-hover/tbv2:to-destructive-fill-hover-to",
1238
+ "group-active/tbv2:from-destructive-fill-active-from group-active/tbv2:to-destructive-fill-active-to"
1239
+ ].join(" "),
1240
+ secondary: [
1241
+ "bg-gradient-to-b from-elevated-from to-elevated-to",
1242
+ "group-hover/tbv2:from-secondary-fill-hover-from group-hover/tbv2:to-secondary-fill-hover-to",
1243
+ "group-active/tbv2:from-secondary-fill-active-from group-active/tbv2:to-secondary-fill-active-to"
1244
+ ].join(" "),
1245
+ ghost: [
1246
+ "bg-transparent",
1247
+ "group-hover/tbv2:bg-ghost-fill-hover",
1248
+ "group-active/tbv2:bg-ghost-fill-active"
1249
+ ].join(" "),
1250
+ link: "bg-transparent"
1251
+ };
1252
+ var TIMBAL_V2_LABEL = {
1253
+ primary: "text-primary-foreground",
1254
+ informative: "text-primary-foreground",
1255
+ destructive: "text-destructive",
1256
+ secondary: "text-foreground",
1257
+ ghost: "text-foreground",
1258
+ link: "text-foreground underline decoration-foreground/25 underline-offset-2 group-hover/tbv2:decoration-foreground/45"
1259
+ };
1260
+ var TIMBAL_V2_BORDER = {
1261
+ primary: "",
1262
+ informative: "border border-foreground/15",
1263
+ destructive: "border border-destructive/45",
1264
+ secondary: "border border-border",
1265
+ ghost: "",
1266
+ link: ""
1267
+ };
1268
+ var TIMBAL_V2_SHADOW = {
1269
+ primary: "shadow-card",
1270
+ informative: "shadow-card",
1271
+ destructive: "shadow-card",
1272
+ secondary: "shadow-card",
1273
+ ghost: "",
1274
+ link: ""
1275
+ };
1276
+ var TIMBAL_V2_SECONDARY_CHROME = [
1277
+ "bg-gradient-to-b from-elevated-from to-elevated-to border border-border shadow-card",
1278
+ "transition-[background-color,box-shadow,border-color] duration-200 ease-in-out",
1279
+ "hover:from-secondary-fill-hover-from hover:to-secondary-fill-hover-to",
1280
+ "active:from-secondary-fill-active-from active:to-secondary-fill-active-to"
1281
+ ].join(" ");
1282
+
1283
+ // src/ui/timbal-v2-button.tsx
1197
1284
  var import_jsx_runtime5 = require("react/jsx-runtime");
1198
- var buttonVariants = (0, import_class_variance_authority.cva)(
1199
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
1200
- {
1201
- variants: {
1202
- variant: {
1203
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
1204
- destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
1205
- outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
1206
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
1207
- ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
1208
- link: "text-primary underline-offset-4 hover:underline"
1209
- },
1210
- size: {
1211
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
1212
- xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
1213
- sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
1214
- lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
1215
- icon: "size-9",
1216
- "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
1217
- "icon-sm": "size-8",
1218
- "icon-lg": "size-10"
1219
- }
1220
- },
1221
- defaultVariants: {
1222
- variant: "default",
1223
- size: "default"
1224
- }
1225
- }
1226
- );
1227
- function Button({
1228
- className,
1229
- variant = "default",
1230
- size = "default",
1285
+ var TimbalV2Button = React.forwardRef(function TimbalV2Button2({
1286
+ variant = "secondary",
1287
+ size = "sm",
1288
+ isIconOnly = false,
1289
+ isLoading = false,
1290
+ fullWidth = false,
1231
1291
  asChild = false,
1292
+ className,
1293
+ disabled,
1294
+ type = "button",
1295
+ children,
1232
1296
  ...props
1233
- }) {
1297
+ }, ref) {
1298
+ const isDisabled = disabled || isLoading;
1234
1299
  const Comp = asChild ? import_radix_ui4.Slot.Root : "button";
1235
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1300
+ const sizeClass = isIconOnly ? TIMBAL_V2_SIZE_ICON[size] : TIMBAL_V2_SIZE_HEIGHT[size];
1301
+ const radiusClass = variant === "link" || variant === "ghost" ? "rounded-md" : "rounded-full";
1302
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1236
1303
  Comp,
1237
1304
  {
1238
- "data-slot": "button",
1305
+ ref,
1306
+ type: asChild ? void 0 : type,
1307
+ disabled: asChild ? void 0 : isDisabled,
1308
+ "aria-disabled": asChild && isDisabled ? true : void 0,
1309
+ "data-slot": "timbal-v2-button",
1239
1310
  "data-variant": variant,
1240
- "data-size": size,
1241
- className: cn(buttonVariants({ variant, size, className })),
1242
- ...props
1311
+ className: cn(
1312
+ "group/tbv2 relative box-border inline-flex flex-col items-stretch overflow-hidden border-0 bg-transparent p-0 text-sm font-normal shadow-none transition duration-200 ease-in-out",
1313
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/60 focus-visible:ring-offset-1 focus-visible:ring-offset-background",
1314
+ sizeClass,
1315
+ radiusClass,
1316
+ TIMBAL_V2_BORDER[variant],
1317
+ TIMBAL_V2_SHADOW[variant],
1318
+ fullWidth && "w-full",
1319
+ isDisabled && "pointer-events-none opacity-50",
1320
+ className
1321
+ ),
1322
+ ...props,
1323
+ children: [
1324
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1325
+ "span",
1326
+ {
1327
+ "aria-hidden": true,
1328
+ className: cn(
1329
+ "pointer-events-none absolute inset-0 transition duration-200 ease-in-out",
1330
+ TIMBAL_V2_FILL[variant]
1331
+ )
1332
+ }
1333
+ ),
1334
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1335
+ "span",
1336
+ {
1337
+ className: cn(
1338
+ "relative z-10 flex min-h-0 flex-1 items-center justify-center gap-1 leading-tight",
1339
+ !isIconOnly && TIMBAL_V2_SIZE_LABEL_PX[size],
1340
+ TIMBAL_V2_LABEL[variant]
1341
+ ),
1342
+ children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "size-4 animate-spin rounded-full border-2 border-current border-t-transparent" }) : children
1343
+ }
1344
+ )
1345
+ ]
1243
1346
  }
1244
1347
  );
1245
- }
1348
+ });
1246
1349
 
1247
1350
  // src/components/tooltip-icon-button.tsx
1248
1351
  var import_jsx_runtime6 = require("react/jsx-runtime");
1249
- var TooltipIconButton = (0, import_react3.forwardRef)(({ children, tooltip, side = "bottom", className, ...rest }, ref) => {
1352
+ var TooltipIconButton = (0, import_react3.forwardRef)(function TooltipIconButton2({ tooltip, side = "bottom", variant = "secondary", children, ...props }, ref) {
1250
1353
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Tooltip, { children: [
1251
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1252
- Button,
1253
- {
1254
- variant: "ghost",
1255
- size: "icon",
1256
- ...rest,
1257
- className: cn("aui-button-icon size-6 p-1", className),
1258
- ref,
1259
- children: [
1260
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_slot.Slottable, { children }),
1261
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "aui-sr-only sr-only", children: tooltip })
1262
- ]
1263
- }
1264
- ) }),
1354
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(TimbalV2Button, { ref, variant, size: "sm", isIconOnly: true, ...props, children: [
1355
+ children,
1356
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "sr-only", children: tooltip })
1357
+ ] }) }),
1265
1358
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TooltipContent, { side, children: tooltip })
1266
1359
  ] });
1267
1360
  });
1268
- TooltipIconButton.displayName = "TooltipIconButton";
1269
1361
 
1270
1362
  // src/components/attachment.tsx
1271
1363
  var import_jsx_runtime7 = require("react/jsx-runtime");
@@ -1395,9 +1487,9 @@ var AttachmentRemove = () => {
1395
1487
  TooltipIconButton,
1396
1488
  {
1397
1489
  tooltip: "Remove file",
1398
- className: "aui-attachment-tile-remove absolute top-1.5 right-1.5 size-3.5 rounded-full bg-white text-muted-foreground opacity-100 shadow-sm hover:bg-white! [&_svg]:text-black hover:[&_svg]:text-destructive",
1490
+ className: "aui-attachment-tile-remove absolute top-1.5 right-1.5 size-3.5 rounded-full bg-card text-foreground opacity-100 shadow-card hover:bg-card! [&_svg]:text-foreground hover:[&_svg]:text-destructive",
1399
1491
  side: "top",
1400
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react2.XIcon, { className: "aui-attachment-remove-icon size-3 dark:stroke-[2.5px]" })
1492
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react2.XIcon, { className: "aui-attachment-remove-icon size-3" })
1401
1493
  }
1402
1494
  ) });
1403
1495
  };
@@ -1418,11 +1510,10 @@ var ComposerAddAttachment = () => {
1418
1510
  {
1419
1511
  tooltip: "Add Attachment",
1420
1512
  side: "bottom",
1421
- variant: "ghost",
1422
- size: "icon",
1423
- className: "aui-composer-add-attachment size-8.5 rounded-full p-1 font-semibold text-xs hover:bg-muted-foreground/15 dark:border-muted-foreground/15 dark:hover:bg-muted-foreground/30",
1513
+ variant: "secondary",
1514
+ className: "aui-composer-add-attachment shrink-0 text-muted-foreground",
1424
1515
  "aria-label": "Add Attachment",
1425
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react2.PlusIcon, { className: "aui-attachment-add-icon size-5 stroke-[1.5px]" })
1516
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react2.PlusIcon, { className: "aui-attachment-add-icon size-4 stroke-[1.5]" })
1426
1517
  }
1427
1518
  ) });
1428
1519
  };
@@ -1769,86 +1860,205 @@ function formatTick(v, unit) {
1769
1860
  var import_react7 = require("react");
1770
1861
  var import_react8 = require("@assistant-ui/react");
1771
1862
  var import_lucide_react3 = require("lucide-react");
1863
+
1864
+ // src/design/classes.ts
1865
+ var studioTopbarPillHeightClass = "h-[var(--studio-chrome-pill-height)] min-h-[var(--studio-chrome-pill-height)]";
1866
+ var studioTopbarIconPillClass = "shrink-0 flex-none size-[var(--studio-chrome-pill-height)] min-h-[var(--studio-chrome-pill-height)] min-w-[var(--studio-chrome-pill-height)]";
1867
+ var studioPlaygroundGradientClass = "bg-gradient-to-b from-playground-from via-playground-via to-playground-to";
1868
+ var studioComposeInputShellClass = cn(
1869
+ "flex w-full flex-col rounded-2xl bg-composer-bg shadow-card-elevated outline-none",
1870
+ "border border-composer-border",
1871
+ "transition-[box-shadow,border-color]",
1872
+ "focus-within:border-composer-border-focus focus-within:ring-2 focus-within:ring-foreground/5"
1873
+ );
1874
+ var studioSecondaryChromeClass = TIMBAL_V2_SECONDARY_CHROME;
1875
+ var studioIntegrationSurfaceSolid = "bg-gradient-to-b from-elevated-from to-elevated-to shadow-card";
1876
+ var studioIntegrationBorder = "border border-border";
1877
+ var studioIntegrationCardClass = cn(
1878
+ "rounded-xl",
1879
+ studioIntegrationSurfaceSolid,
1880
+ studioIntegrationBorder
1881
+ );
1882
+ var studioIntegrationIconTileClass = cn(
1883
+ "flex size-9 shrink-0 items-center justify-center rounded-lg",
1884
+ studioIntegrationSurfaceSolid,
1885
+ studioIntegrationBorder
1886
+ );
1887
+ var studioListRowButtonClass = cn(
1888
+ "flex w-full cursor-pointer items-center gap-3 rounded-xl px-3 py-2.5 text-left",
1889
+ studioIntegrationCardClass,
1890
+ "transition-[background-color,box-shadow,border-color] duration-200 ease-in-out",
1891
+ "hover:border-foreground/20",
1892
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background"
1893
+ );
1894
+ var studioComposerIoWellClass = cn(
1895
+ "rounded-lg",
1896
+ studioIntegrationSurfaceSolid,
1897
+ studioIntegrationBorder
1898
+ );
1899
+ var studioToolCardShellClass = cn(
1900
+ studioIntegrationCardClass,
1901
+ "my-2 min-h-0 overflow-hidden"
1902
+ );
1903
+ var studioSidebarPanelClass = cn(
1904
+ "bg-sidebar text-sidebar-foreground",
1905
+ "border border-sidebar-border",
1906
+ "shadow-card-elevated"
1907
+ );
1908
+ var studioSidebarNavItemClass = cn(
1909
+ "flex items-center rounded-lg text-sm",
1910
+ "transition-[color,background-color,box-shadow,border-color] duration-200 ease-in-out",
1911
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2"
1912
+ );
1913
+ function studioSidebarNavItemLayout(iconOnly) {
1914
+ return iconOnly ? "box-border size-8 min-h-8 min-w-8 shrink-0 justify-center rounded-lg p-0 focus-visible:ring-offset-0" : "w-full gap-2 px-2.5 py-2";
1915
+ }
1916
+ var studioSidebarNavItemSurfaceClass = cn(
1917
+ "bg-gradient-to-b from-elevated-from to-elevated-to text-foreground",
1918
+ "border border-border",
1919
+ "shadow-card"
1920
+ );
1921
+ var studioSidebarNavItemIdleClass = cn(
1922
+ "border border-transparent text-muted-foreground shadow-none",
1923
+ "hover:text-foreground",
1924
+ "hover:bg-gradient-to-b hover:from-elevated-from hover:to-elevated-to",
1925
+ "hover:border-border hover:shadow-card"
1926
+ );
1927
+ var studioSidebarCollapsedRailItemClass = cn(
1928
+ "border border-border shadow-card bg-sidebar-accent"
1929
+ );
1930
+ var studioSidebarCollapsedRailItemIdleClass = cn(
1931
+ studioSidebarCollapsedRailItemClass,
1932
+ "text-muted-foreground hover:text-foreground"
1933
+ );
1934
+ var studioSidebarCollapsedRailItemActiveClass = cn(
1935
+ studioSidebarCollapsedRailItemClass,
1936
+ studioSidebarNavItemSurfaceClass,
1937
+ "text-foreground"
1938
+ );
1939
+ var studioSidebarNavItemActiveClass = studioSidebarNavItemSurfaceClass;
1940
+ var studioTimelineRowButtonClass = "group flex w-full min-w-0 cursor-pointer items-center justify-start rounded-md border-0 bg-transparent py-1 text-left shadow-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2";
1941
+ var studioTimelineTextClass = "text-xs font-normal leading-snug";
1942
+ var studioTimelineActionClass = cn(
1943
+ studioTimelineTextClass,
1944
+ "shrink-0 text-foreground/70 transition-colors duration-150 group-hover:text-foreground/80"
1945
+ );
1946
+ var studioTimelineShimmerActionClass = cn(
1947
+ studioTimelineTextClass,
1948
+ "shrink-0"
1949
+ );
1950
+ var studioTimelineDetailClass = cn(
1951
+ studioTimelineTextClass,
1952
+ "min-w-0 truncate text-muted-foreground transition-colors duration-150"
1953
+ );
1954
+ function studioTimelineChevronClass(expanded) {
1955
+ return cn(
1956
+ "ml-0.5 size-3 min-h-3 min-w-3 shrink-0 transition-all duration-150",
1957
+ expanded ? "rotate-90 text-foreground opacity-60" : "text-muted-foreground opacity-0 group-hover:opacity-70"
1958
+ );
1959
+ }
1960
+ var studioTimelineBodyPadClass = "flex flex-col gap-2 pt-0.5 pb-0.5";
1961
+ var studioArtifactShellClass = cn(
1962
+ studioIntegrationCardClass,
1963
+ "my-2 w-full min-w-0 overflow-hidden"
1964
+ );
1965
+ var studioQuestionOptionClass = "flex w-full items-center gap-2 rounded-lg border border-transparent px-2 py-1.5 text-left text-sm transition-[background-color,border-color,box-shadow] duration-200 hover:bg-muted/70 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2";
1966
+ var studioQuestionOptionSelectedClass = cn(
1967
+ studioQuestionOptionClass,
1968
+ "border-border bg-accent ring-1 ring-foreground/10"
1969
+ );
1970
+
1971
+ // src/artifacts/question-artifact.tsx
1772
1972
  var import_jsx_runtime10 = require("react/jsx-runtime");
1973
+ function optionKey(option, index) {
1974
+ const id = option.id?.trim();
1975
+ return id ? id : `__option-${index}`;
1976
+ }
1977
+ var OptionRadio = ({ selected }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1978
+ "span",
1979
+ {
1980
+ className: cn(
1981
+ "flex size-4 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
1982
+ selected ? "border-foreground bg-foreground text-background" : "border-border bg-background"
1983
+ ),
1984
+ "aria-hidden": true,
1985
+ children: selected ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.CheckIcon, { className: "size-2.5 stroke-[3]" }) : null
1986
+ }
1987
+ );
1773
1988
  var QuestionArtifactView = ({
1774
1989
  artifact
1775
1990
  }) => {
1776
1991
  const runtime = (0, import_react8.useThreadRuntime)();
1777
1992
  const [selected, setSelected] = (0, import_react7.useState)([]);
1778
- const [submitted, setSubmitted] = (0, import_react7.useState)(null);
1993
+ const [submittedIds, setSubmittedIds] = (0, import_react7.useState)(null);
1779
1994
  const isMulti = artifact.multi === true;
1780
- const send = (labels) => {
1781
- if (labels.length === 0) return;
1782
- const text = labels.join(", ");
1783
- setSubmitted(text);
1784
- runtime.append({ role: "user", content: [{ type: "text", text }] });
1785
- };
1786
- const onPick = (option) => {
1787
- if (submitted) return;
1788
- if (!isMulti) {
1789
- send([option.label]);
1790
- return;
1791
- }
1792
- setSelected(
1793
- (prev) => prev.includes(option.id) ? prev.filter((id) => id !== option.id) : [...prev, option.id]
1794
- );
1795
- };
1796
- const onConfirm = () => {
1797
- const labels = artifact.options.filter((o) => selected.includes(o.id)).map((o) => o.label);
1798
- send(labels);
1799
- };
1800
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ArtifactCard, { kind: "question", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "aui-artifact-question p-3", children: [
1801
- artifact.prompt && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "aui-artifact-question-prompt mb-2 text-sm text-foreground/85", children: artifact.prompt }),
1802
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "aui-artifact-question-options flex flex-col gap-1.5", children: artifact.options.map((option) => {
1803
- const isSelected = isMulti && selected.includes(option.id);
1804
- const isDisabled = Boolean(submitted);
1995
+ const isDisabled = submittedIds !== null;
1996
+ const send = (0, import_react7.useCallback)(
1997
+ (keys) => {
1998
+ if (keys.length === 0) return;
1999
+ const labels = artifact.options.map((option, index) => ({ option, key: optionKey(option, index) })).filter(({ key }) => keys.includes(key)).map(({ option }) => option.label);
2000
+ setSubmittedIds(keys);
2001
+ runtime.append({
2002
+ role: "user",
2003
+ content: [{ type: "text", text: labels.join(", ") }]
2004
+ });
2005
+ },
2006
+ [artifact.options, runtime]
2007
+ );
2008
+ const onPick = (0, import_react7.useCallback)(
2009
+ (key) => {
2010
+ if (isDisabled) return;
2011
+ if (!isMulti) {
2012
+ send([key]);
2013
+ return;
2014
+ }
2015
+ setSelected(
2016
+ (prev) => prev.includes(key) ? prev.filter((id) => id !== key) : [...prev, key]
2017
+ );
2018
+ },
2019
+ [isDisabled, isMulti, send]
2020
+ );
2021
+ const onConfirm = (0, import_react7.useCallback)(() => {
2022
+ send(selected);
2023
+ }, [selected, send]);
2024
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: studioArtifactShellClass, "data-artifact-kind": "question", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "px-2.5 py-2", children: [
2025
+ artifact.prompt ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "mb-2 text-sm font-normal leading-snug text-foreground", children: artifact.prompt }) : null,
2026
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex flex-col gap-0.5", role: "list", children: artifact.options.map((option, index) => {
2027
+ const key = optionKey(option, index);
2028
+ const isSelected = submittedIds ? submittedIds.includes(key) : isMulti && selected.includes(key);
1805
2029
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1806
2030
  "button",
1807
2031
  {
1808
2032
  type: "button",
2033
+ role: "listitem",
1809
2034
  disabled: isDisabled,
1810
- onClick: () => onPick(option),
2035
+ onClick: () => onPick(key),
1811
2036
  className: cn(
1812
- "aui-artifact-question-option flex items-center gap-2 rounded-lg border px-3 py-2 text-left text-sm transition-colors",
1813
- "border-border/60 hover:border-primary/40 hover:bg-muted/40",
1814
- isSelected && "border-primary/60 bg-primary/5",
1815
- isDisabled && "cursor-not-allowed opacity-60 hover:border-border/60 hover:bg-transparent"
2037
+ isSelected ? studioQuestionOptionSelectedClass : studioQuestionOptionClass,
2038
+ isDisabled && (isSelected ? "cursor-default" : "cursor-not-allowed opacity-50")
1816
2039
  ),
1817
2040
  children: [
1818
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1819
- "span",
1820
- {
1821
- className: cn(
1822
- "flex size-4 shrink-0 items-center justify-center rounded-full border",
1823
- isSelected ? "border-primary bg-primary text-primary-foreground" : "border-border"
1824
- ),
1825
- "aria-hidden": true,
1826
- children: isSelected && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.CheckIcon, { className: "size-3" })
1827
- }
1828
- ),
1829
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "aui-artifact-question-option-text flex-1", children: [
1830
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "font-medium text-foreground/90", children: option.label }),
1831
- option.description && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "text-xs text-muted-foreground", children: option.description })
2041
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(OptionRadio, { selected: isSelected }),
2042
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "min-w-0 flex-1 text-left", children: [
2043
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "block font-normal text-foreground", children: option.label }),
2044
+ option.description ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "mt-0.5 block text-xs text-muted-foreground", children: option.description }) : null
1832
2045
  ] })
1833
2046
  ]
1834
2047
  },
1835
- option.id
2048
+ key
1836
2049
  );
1837
2050
  }) }),
1838
- isMulti && !submitted && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-2 flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1839
- Button,
2051
+ isMulti && !submittedIds ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-2 flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2052
+ TimbalV2Button,
1840
2053
  {
1841
2054
  type: "button",
2055
+ variant: "primary",
1842
2056
  size: "sm",
1843
2057
  disabled: selected.length === 0,
1844
2058
  onClick: onConfirm,
1845
2059
  children: "Confirm"
1846
2060
  }
1847
- ) }),
1848
- submitted && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { className: "aui-artifact-question-submitted mt-2 text-xs text-muted-foreground", children: [
1849
- "Sent: ",
1850
- submitted
1851
- ] })
2061
+ ) }) : null
1852
2062
  ] }) });
1853
2063
  };
1854
2064
 
@@ -2019,29 +2229,84 @@ function useUiCustomNodeRegistry() {
2019
2229
  var import_react10 = require("react");
2020
2230
  var import_react11 = require("motion/react");
2021
2231
  var import_react12 = require("@assistant-ui/react");
2232
+
2233
+ // src/ui/button.tsx
2234
+ var import_class_variance_authority = require("class-variance-authority");
2235
+ var import_radix_ui5 = require("radix-ui");
2022
2236
  var import_jsx_runtime15 = require("react/jsx-runtime");
2237
+ var buttonVariants = (0, import_class_variance_authority.cva)(
2238
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/30 aria-invalid:border-destructive",
2239
+ {
2240
+ variants: {
2241
+ variant: {
2242
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
2243
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 focus-visible:ring-destructive/30",
2244
+ outline: "border border-border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
2245
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
2246
+ ghost: "hover:bg-accent hover:text-accent-foreground",
2247
+ link: "text-primary underline-offset-4 hover:underline"
2248
+ },
2249
+ size: {
2250
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
2251
+ xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
2252
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
2253
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
2254
+ icon: "size-9",
2255
+ "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
2256
+ "icon-sm": "size-8",
2257
+ "icon-lg": "size-10"
2258
+ }
2259
+ },
2260
+ defaultVariants: {
2261
+ variant: "default",
2262
+ size: "default"
2263
+ }
2264
+ }
2265
+ );
2266
+ function Button({
2267
+ className,
2268
+ variant = "default",
2269
+ size = "default",
2270
+ asChild = false,
2271
+ ...props
2272
+ }) {
2273
+ const Comp = asChild ? import_radix_ui5.Slot.Root : "button";
2274
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2275
+ Comp,
2276
+ {
2277
+ "data-slot": "button",
2278
+ "data-variant": variant,
2279
+ "data-size": size,
2280
+ className: cn(buttonVariants({ variant, size, className })),
2281
+ ...props
2282
+ }
2283
+ );
2284
+ }
2285
+
2286
+ // src/artifacts/ui/nodes.tsx
2287
+ var import_jsx_runtime16 = require("react/jsx-runtime");
2023
2288
  var UiNodeView = ({ node }) => {
2024
2289
  switch (node.kind) {
2025
2290
  case "box":
2026
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(BoxNode, { node });
2291
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(BoxNode, { node });
2027
2292
  case "text":
2028
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TextNode, { node });
2293
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TextNode, { node });
2029
2294
  case "heading":
2030
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(HeadingNode, { node });
2295
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(HeadingNode, { node });
2031
2296
  case "badge":
2032
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(BadgeNode, { node });
2297
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(BadgeNode, { node });
2033
2298
  case "button":
2034
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ButtonNode, { node });
2299
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ButtonNode, { node });
2035
2300
  case "toggle":
2036
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ToggleNode, { node });
2301
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToggleNode, { node });
2037
2302
  case "slider":
2038
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SliderNode, { node });
2303
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SliderNode, { node });
2039
2304
  case "tooltip":
2040
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipNode, { node });
2305
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TooltipNode, { node });
2041
2306
  case "draggable":
2042
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DraggableNode, { node });
2307
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DraggableNode, { node });
2043
2308
  case "custom":
2044
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(CustomNode, { node });
2309
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CustomNode, { node });
2045
2310
  default:
2046
2311
  return null;
2047
2312
  }
@@ -2101,7 +2366,7 @@ var JUSTIFY_CLS = {
2101
2366
  };
2102
2367
  var BoxNode = ({ node }) => {
2103
2368
  const dir = node.direction ?? "col";
2104
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2369
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2105
2370
  "div",
2106
2371
  {
2107
2372
  className: cn(
@@ -2116,7 +2381,7 @@ var BoxNode = ({ node }) => {
2116
2381
  gap: node.gap !== void 0 ? `${node.gap * 0.25}rem` : void 0,
2117
2382
  padding: node.padding !== void 0 ? `${node.padding * 0.25}rem` : void 0
2118
2383
  },
2119
- children: node.children?.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(UiNodeView, { node: child }, child.id ?? i))
2384
+ children: node.children?.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UiNodeView, { node: child }, child.id ?? i))
2120
2385
  }
2121
2386
  );
2122
2387
  };
@@ -2135,7 +2400,7 @@ var TEXT_WEIGHT = {
2135
2400
  var TextNode = ({ node }) => {
2136
2401
  const state = useUiState();
2137
2402
  const value = resolveBindable(node.value, state);
2138
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2403
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2139
2404
  "span",
2140
2405
  {
2141
2406
  className: cn(
@@ -2166,13 +2431,13 @@ var HeadingNode = ({ node }) => {
2166
2431
  );
2167
2432
  switch (level) {
2168
2433
  case 1:
2169
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h1", { className: cls, children: value });
2434
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h1", { className: cls, children: value });
2170
2435
  case 2:
2171
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h2", { className: cls, children: value });
2436
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h2", { className: cls, children: value });
2172
2437
  case 3:
2173
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h3", { className: cls, children: value });
2438
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h3", { className: cls, children: value });
2174
2439
  case 4:
2175
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h4", { className: cls, children: value });
2440
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h4", { className: cls, children: value });
2176
2441
  }
2177
2442
  };
2178
2443
  var BADGE_TONE = {
@@ -2185,7 +2450,7 @@ var BADGE_TONE = {
2185
2450
  var BadgeNode = ({ node }) => {
2186
2451
  const state = useUiState();
2187
2452
  const value = String(resolveBindable(node.value, state) ?? "");
2188
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2453
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2189
2454
  "span",
2190
2455
  {
2191
2456
  className: cn(
@@ -2202,7 +2467,7 @@ var ButtonNode = ({ node }) => {
2202
2467
  const run = useActionRunner();
2203
2468
  const label = String(resolveBindable(node.label, state) ?? "");
2204
2469
  const disabled = node.disabled !== void 0 ? Boolean(resolveBindable(node.disabled, state)) : false;
2205
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2470
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2206
2471
  Button,
2207
2472
  {
2208
2473
  variant: node.variant ?? "default",
@@ -2224,7 +2489,7 @@ var ToggleNode = ({ node }) => {
2224
2489
  dispatch({ type: "toggle", path: node.binding });
2225
2490
  run(node.onChange);
2226
2491
  };
2227
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2492
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2228
2493
  "label",
2229
2494
  {
2230
2495
  className: cn(
@@ -2232,7 +2497,7 @@ var ToggleNode = ({ node }) => {
2232
2497
  node.className
2233
2498
  ),
2234
2499
  children: [
2235
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2500
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2236
2501
  "button",
2237
2502
  {
2238
2503
  type: "button",
@@ -2243,7 +2508,7 @@ var ToggleNode = ({ node }) => {
2243
2508
  "relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border transition-colors",
2244
2509
  value ? "border-primary bg-primary" : "border-border bg-muted hover:bg-muted/80"
2245
2510
  ),
2246
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2511
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2247
2512
  "span",
2248
2513
  {
2249
2514
  className: cn(
@@ -2255,7 +2520,7 @@ var ToggleNode = ({ node }) => {
2255
2520
  )
2256
2521
  }
2257
2522
  ),
2258
- label && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-foreground/85", children: label })
2523
+ label && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-foreground/85", children: label })
2259
2524
  ]
2260
2525
  }
2261
2526
  );
@@ -2275,12 +2540,12 @@ var SliderNode = ({ node }) => {
2275
2540
  const next = Number(e.target.value);
2276
2541
  dispatch({ type: "set", path: node.binding, value: next });
2277
2542
  };
2278
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: cn("aui-ui-slider flex flex-col gap-1", node.className), children: [
2279
- (label || showValue) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [
2280
- label && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: label }),
2281
- showValue && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "font-mono", children: value })
2543
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: cn("aui-ui-slider flex flex-col gap-1", node.className), children: [
2544
+ (label || showValue) && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [
2545
+ label && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: label }),
2546
+ showValue && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "font-mono", children: value })
2282
2547
  ] }),
2283
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2548
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2284
2549
  "input",
2285
2550
  {
2286
2551
  type: "range",
@@ -2302,9 +2567,9 @@ var SliderNode = ({ node }) => {
2302
2567
  var TooltipNode = ({ node }) => {
2303
2568
  const state = useUiState();
2304
2569
  const content = String(resolveBindable(node.content, state) ?? "");
2305
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Tooltip, { children: [
2306
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: cn("aui-ui-tooltip-trigger inline-flex", node.className), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(UiNodeView, { node: node.child }) }) }),
2307
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipContent, { side: node.side ?? "top", children: content })
2570
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Tooltip, { children: [
2571
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: cn("aui-ui-tooltip-trigger inline-flex", node.className), children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UiNodeView, { node: node.child }) }) }),
2572
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TooltipContent, { side: node.side ?? "top", children: content })
2308
2573
  ] }) });
2309
2574
  };
2310
2575
  var DraggableNode = ({ node }) => {
@@ -2312,7 +2577,7 @@ var DraggableNode = ({ node }) => {
2312
2577
  const snapBack = node.snapBack ?? true;
2313
2578
  const axis = node.axis ?? "both";
2314
2579
  const dragProp = axis === "both" ? true : axis;
2315
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2580
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2316
2581
  import_react11.motion.div,
2317
2582
  {
2318
2583
  drag: dragProp,
@@ -2324,7 +2589,7 @@ var DraggableNode = ({ node }) => {
2324
2589
  "aui-ui-draggable inline-block cursor-grab touch-none",
2325
2590
  node.className
2326
2591
  ),
2327
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(UiNodeView, { node: node.child })
2592
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UiNodeView, { node: node.child })
2328
2593
  }
2329
2594
  );
2330
2595
  };
@@ -2334,8 +2599,8 @@ var CustomNode = ({ node }) => {
2334
2599
  const Renderer = registry[node.name];
2335
2600
  if (!Renderer) return null;
2336
2601
  const resolvedProps = resolveProps(node.props ?? {}, state);
2337
- const children = node.children?.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(UiNodeView, { node: child }, child.id ?? i));
2338
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Renderer, { props: resolvedProps, children });
2602
+ const children = node.children?.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UiNodeView, { node: child }, child.id ?? i));
2603
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Renderer, { props: resolvedProps, children });
2339
2604
  };
2340
2605
  function resolveProps(props, state) {
2341
2606
  const out = {};
@@ -2346,17 +2611,17 @@ function resolveProps(props, state) {
2346
2611
  }
2347
2612
 
2348
2613
  // src/artifacts/ui/ui-artifact.tsx
2349
- var import_jsx_runtime16 = require("react/jsx-runtime");
2614
+ var import_jsx_runtime17 = require("react/jsx-runtime");
2350
2615
  var UiArtifactView = ({ artifact }) => {
2351
2616
  const [state, dispatch] = (0, import_react13.useReducer)(
2352
2617
  uiStateReducer,
2353
2618
  artifact.initialState ?? {}
2354
2619
  );
2355
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ArtifactCard, { title: artifact.title, kind: "ui", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UiStateProvider, { state, dispatch, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "aui-ui-root p-3", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UiNodeView, { node: artifact.root }) }) }) });
2620
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ArtifactCard, { title: artifact.title, kind: "ui", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(UiStateProvider, { state, dispatch, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "aui-ui-root p-3", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(UiNodeView, { node: artifact.root }) }) }) });
2356
2621
  };
2357
2622
 
2358
2623
  // src/artifacts/registry.tsx
2359
- var import_jsx_runtime17 = require("react/jsx-runtime");
2624
+ var import_jsx_runtime18 = require("react/jsx-runtime");
2360
2625
  var defaultArtifactRenderers = {
2361
2626
  chart: ChartArtifactView,
2362
2627
  question: QuestionArtifactView,
@@ -2374,7 +2639,7 @@ var ArtifactRegistryProvider = ({ renderers, override, children }) => {
2374
2639
  if (override) return renderers;
2375
2640
  return { ...defaultArtifactRenderers, ...renderers };
2376
2641
  }, [renderers, override]);
2377
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ArtifactRegistryContext.Provider, { value: merged, children });
2642
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ArtifactRegistryContext.Provider, { value: merged, children });
2378
2643
  };
2379
2644
  function useArtifactRegistry() {
2380
2645
  return (0, import_react14.useContext)(ArtifactRegistryContext);
@@ -2383,7 +2648,7 @@ var ArtifactView = ({ artifact }) => {
2383
2648
  const registry = useArtifactRegistry();
2384
2649
  const Renderer = registry[artifact.type] ?? registry.json;
2385
2650
  if (!Renderer) return null;
2386
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Renderer, { artifact });
2651
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Renderer, { artifact });
2387
2652
  };
2388
2653
 
2389
2654
  // src/artifacts/parse.ts
@@ -2499,7 +2764,7 @@ var import_c = __toESM(require("shiki/langs/c.mjs"), 1);
2499
2764
  var import_cpp = __toESM(require("shiki/langs/cpp.mjs"), 1);
2500
2765
  var import_vitesse_dark = __toESM(require("shiki/themes/vitesse-dark.mjs"), 1);
2501
2766
  var import_vitesse_light = __toESM(require("shiki/themes/vitesse-light.mjs"), 1);
2502
- var import_jsx_runtime18 = require("react/jsx-runtime");
2767
+ var import_jsx_runtime19 = require("react/jsx-runtime");
2503
2768
  var SHIKI_THEME_DARK = "vitesse-dark";
2504
2769
  var SHIKI_THEME_LIGHT = "vitesse-light";
2505
2770
  var highlighterPromise = null;
@@ -2568,13 +2833,13 @@ var ShikiSyntaxHighlighter = ({
2568
2833
  try {
2569
2834
  const parsed = JSON.parse(code);
2570
2835
  if (isArtifact(parsed)) {
2571
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ArtifactView, { artifact: parsed });
2836
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ArtifactView, { artifact: parsed });
2572
2837
  }
2573
2838
  } catch {
2574
2839
  }
2575
2840
  }
2576
2841
  if (html) {
2577
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2842
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2578
2843
  "div",
2579
2844
  {
2580
2845
  className: "shiki-wrapper [&>pre]:!m-0 [&>pre]:!rounded-t-none [&>pre]:!rounded-b-lg [&>pre]:!border [&>pre]:!border-t-0 [&>pre]:!border-border/50 [&>pre]:!p-3 [&>pre]:!text-xs [&>pre]:!leading-relaxed [&>pre]:overflow-x-auto",
@@ -2582,14 +2847,14 @@ var ShikiSyntaxHighlighter = ({
2582
2847
  }
2583
2848
  );
2584
2849
  }
2585
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Pre, { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Code2, { children: code }) });
2850
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pre, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Code2, { children: code }) });
2586
2851
  };
2587
2852
  var syntax_highlighter_default = ShikiSyntaxHighlighter;
2588
2853
 
2589
2854
  // src/components/markdown-text.tsx
2590
- var import_jsx_runtime19 = require("react/jsx-runtime");
2855
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2591
2856
  var MarkdownTextImpl = () => {
2592
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2857
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2593
2858
  import_react_markdown.MarkdownTextPrimitive,
2594
2859
  {
2595
2860
  remarkPlugins: [import_remark_gfm.default, import_remark_math.default],
@@ -2610,20 +2875,20 @@ var CodeHeader = ({ language, code }) => {
2610
2875
  if (!code || isCopied) return;
2611
2876
  copyToClipboard(code);
2612
2877
  };
2613
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "aui-code-header flex items-center justify-between rounded-t-lg border border-b-0 border-border/50 bg-zinc-100 px-4 py-2 dark:bg-zinc-800/80", children: [
2614
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "flex items-center gap-2 text-xs font-semibold tracking-wide text-muted-foreground/80 uppercase", children: [
2615
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "inline-block h-2 w-2 rounded-full bg-primary/40" }),
2878
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "aui-code-header flex items-center justify-between rounded-t-lg border border-b-0 border-border/50 bg-code-header-bg px-4 py-2", children: [
2879
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "flex items-center gap-2 text-xs font-semibold tracking-wide text-muted-foreground/80 uppercase", children: [
2880
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "inline-block h-2 w-2 rounded-full bg-primary/40" }),
2616
2881
  language
2617
2882
  ] }),
2618
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2883
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2619
2884
  TooltipIconButton,
2620
2885
  {
2621
2886
  tooltip: isCopied ? "Copied!" : "Copy",
2622
2887
  onClick: onCopy,
2623
2888
  className: "transition-colors hover:text-foreground",
2624
2889
  children: [
2625
- !isCopied && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react4.CopyIcon, { className: "h-3.5 w-3.5" }),
2626
- isCopied && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react4.CheckIcon, { className: "h-3.5 w-3.5 text-emerald-500" })
2890
+ !isCopied && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react4.CopyIcon, { className: "h-3.5 w-3.5" }),
2891
+ isCopied && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react4.CheckIcon, { className: "h-3.5 w-3.5 text-emerald-500" })
2627
2892
  ]
2628
2893
  }
2629
2894
  )
@@ -2643,7 +2908,7 @@ var useCopyToClipboard = ({
2643
2908
  return { isCopied, copyToClipboard };
2644
2909
  };
2645
2910
  var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownComponents)({
2646
- h1: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2911
+ h1: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2647
2912
  "h1",
2648
2913
  {
2649
2914
  className: cn(
@@ -2653,7 +2918,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2653
2918
  ...props
2654
2919
  }
2655
2920
  ),
2656
- h2: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2921
+ h2: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2657
2922
  "h2",
2658
2923
  {
2659
2924
  className: cn(
@@ -2663,7 +2928,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2663
2928
  ...props
2664
2929
  }
2665
2930
  ),
2666
- h3: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2931
+ h3: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2667
2932
  "h3",
2668
2933
  {
2669
2934
  className: cn(
@@ -2673,7 +2938,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2673
2938
  ...props
2674
2939
  }
2675
2940
  ),
2676
- h4: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2941
+ h4: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2677
2942
  "h4",
2678
2943
  {
2679
2944
  className: cn(
@@ -2683,7 +2948,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2683
2948
  ...props
2684
2949
  }
2685
2950
  ),
2686
- h5: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2951
+ h5: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2687
2952
  "h5",
2688
2953
  {
2689
2954
  className: cn(
@@ -2693,7 +2958,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2693
2958
  ...props
2694
2959
  }
2695
2960
  ),
2696
- h6: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2961
+ h6: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2697
2962
  "h6",
2698
2963
  {
2699
2964
  className: cn(
@@ -2703,7 +2968,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2703
2968
  ...props
2704
2969
  }
2705
2970
  ),
2706
- p: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2971
+ p: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2707
2972
  "p",
2708
2973
  {
2709
2974
  className: cn(
@@ -2713,7 +2978,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2713
2978
  ...props
2714
2979
  }
2715
2980
  ),
2716
- a: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2981
+ a: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2717
2982
  "a",
2718
2983
  {
2719
2984
  className: cn(
@@ -2725,7 +2990,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2725
2990
  ...props
2726
2991
  }
2727
2992
  ),
2728
- blockquote: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2993
+ blockquote: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2729
2994
  "blockquote",
2730
2995
  {
2731
2996
  className: cn(
@@ -2735,7 +3000,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2735
3000
  ...props
2736
3001
  }
2737
3002
  ),
2738
- ul: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3003
+ ul: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2739
3004
  "ul",
2740
3005
  {
2741
3006
  className: cn(
@@ -2745,7 +3010,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2745
3010
  ...props
2746
3011
  }
2747
3012
  ),
2748
- ol: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3013
+ ol: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2749
3014
  "ol",
2750
3015
  {
2751
3016
  className: cn(
@@ -2755,7 +3020,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2755
3020
  ...props
2756
3021
  }
2757
3022
  ),
2758
- hr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3023
+ hr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2759
3024
  "hr",
2760
3025
  {
2761
3026
  className: cn(
@@ -2765,14 +3030,14 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2765
3030
  ...props
2766
3031
  }
2767
3032
  ),
2768
- table: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "my-4 w-full overflow-x-auto rounded-lg border border-border/50", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3033
+ table: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "my-4 w-full overflow-x-auto rounded-lg border border-border/50", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2769
3034
  "table",
2770
3035
  {
2771
3036
  className: cn("aui-md-table w-full border-collapse text-sm", className),
2772
3037
  ...props
2773
3038
  }
2774
3039
  ) }),
2775
- th: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3040
+ th: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2776
3041
  "th",
2777
3042
  {
2778
3043
  className: cn(
@@ -2782,7 +3047,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2782
3047
  ...props
2783
3048
  }
2784
3049
  ),
2785
- td: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3050
+ td: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2786
3051
  "td",
2787
3052
  {
2788
3053
  className: cn(
@@ -2792,7 +3057,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2792
3057
  ...props
2793
3058
  }
2794
3059
  ),
2795
- tr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3060
+ tr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2796
3061
  "tr",
2797
3062
  {
2798
3063
  className: cn(
@@ -2802,8 +3067,8 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2802
3067
  ...props
2803
3068
  }
2804
3069
  ),
2805
- li: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("li", { className: cn("aui-md-li leading-[1.7]", className), ...props }),
2806
- sup: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3070
+ li: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("li", { className: cn("aui-md-li leading-[1.7]", className), ...props }),
3071
+ sup: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2807
3072
  "sup",
2808
3073
  {
2809
3074
  className: cn(
@@ -2813,11 +3078,11 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2813
3078
  ...props
2814
3079
  }
2815
3080
  ),
2816
- pre: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3081
+ pre: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2817
3082
  "pre",
2818
3083
  {
2819
3084
  className: cn(
2820
- "aui-md-pre overflow-x-auto rounded-t-none rounded-b-lg border border-t-0 border-border/50 bg-zinc-50 p-4 text-[13px] leading-relaxed dark:bg-zinc-900/80",
3085
+ "aui-md-pre overflow-x-auto rounded-t-none rounded-b-lg border border-t-0 border-border/50 bg-code-block-bg p-4 text-[13px] leading-relaxed",
2821
3086
  className
2822
3087
  ),
2823
3088
  ...props
@@ -2825,30 +3090,31 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
2825
3090
  ),
2826
3091
  code: function Code({ className, ...props }) {
2827
3092
  const isCodeBlock = (0, import_react_markdown.useIsMarkdownCodeBlock)();
2828
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3093
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2829
3094
  "code",
2830
3095
  {
2831
3096
  className: cn(
2832
- !isCodeBlock && "aui-md-inline-code rounded-[5px] border border-border/60 bg-muted/60 px-[0.4em] py-[0.15em] font-mono text-[0.85em] font-medium text-foreground/90 dark:bg-muted/40",
3097
+ !isCodeBlock && "aui-md-inline-code rounded-[5px] border border-border/60 bg-muted/60 px-[0.4em] py-[0.15em] font-mono text-[0.85em] font-medium text-foreground/90",
2833
3098
  className
2834
3099
  ),
2835
3100
  ...props
2836
3101
  }
2837
3102
  );
2838
3103
  },
2839
- strong: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("strong", { className: cn("font-semibold text-foreground", className), ...props }),
2840
- em: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("em", { className: cn("italic", className), ...props }),
3104
+ strong: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("strong", { className: cn("font-semibold text-foreground", className), ...props }),
3105
+ em: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("em", { className: cn("italic", className), ...props }),
2841
3106
  CodeHeader
2842
3107
  });
2843
3108
 
2844
3109
  // src/components/tool-fallback.tsx
2845
- var import_react19 = require("react");
3110
+ var import_react20 = require("react");
2846
3111
  var import_lucide_react5 = require("lucide-react");
3112
+ var import_react21 = require("@assistant-ui/react");
2847
3113
 
2848
3114
  // src/ui/shimmer.tsx
2849
3115
  var import_react17 = require("motion/react");
2850
3116
  var import_react18 = require("react");
2851
- var import_jsx_runtime20 = require("react/jsx-runtime");
3117
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2852
3118
  var ShimmerComponent = ({
2853
3119
  children,
2854
3120
  as: Component = "p",
@@ -2863,7 +3129,7 @@ var ShimmerComponent = ({
2863
3129
  () => (children?.length ?? 0) * spread,
2864
3130
  [children, spread]
2865
3131
  );
2866
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3132
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2867
3133
  MotionComponent,
2868
3134
  {
2869
3135
  animate: { backgroundPosition: "0% center" },
@@ -2888,78 +3154,130 @@ var ShimmerComponent = ({
2888
3154
  };
2889
3155
  var Shimmer = (0, import_react18.memo)(ShimmerComponent);
2890
3156
 
2891
- // src/components/tool-fallback.tsx
2892
- var import_jsx_runtime21 = require("react/jsx-runtime");
2893
- var ToolFallbackImpl = ({
2894
- toolName,
2895
- argsText,
2896
- result,
2897
- status
2898
- }) => {
2899
- const isRunning = status?.type === "running";
2900
- const isError = status?.type === "incomplete" && status.reason !== "cancelled";
2901
- if (isRunning) {
2902
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "aui-tool-fallback-running flex items-center gap-2 py-1 text-sm text-muted-foreground", children: [
2903
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react5.WrenchIcon, { className: "size-4" }),
2904
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Shimmer, { as: "span", duration: 1.8, spread: 2.5, children: `Using tool: ${toolName}` })
2905
- ] });
3157
+ // src/components/motion.tsx
3158
+ var import_react19 = require("motion/react");
3159
+ var import_jsx_runtime22 = require("react/jsx-runtime");
3160
+ var luxuryEase = [0.16, 1, 0.3, 1];
3161
+ var TOOL_ENTER_MS = 0.78;
3162
+ var TOOL_EXIT_MS = 0.28;
3163
+ function toolPresenceTransition(reduced) {
3164
+ return {
3165
+ enter: {
3166
+ duration: reduced ? 0.35 : TOOL_ENTER_MS,
3167
+ ease: luxuryEase
3168
+ },
3169
+ exit: {
3170
+ duration: reduced ? 0.2 : TOOL_EXIT_MS,
3171
+ ease: [0.4, 0, 1, 1]
3172
+ }
3173
+ };
3174
+ }
3175
+ function toolMotionState(reduced, entering, variant) {
3176
+ if (reduced) {
3177
+ return entering ? { opacity: 0, y: variant === "executing" ? 8 : 10 } : { opacity: 1, y: 0 };
2906
3178
  }
2907
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2908
- ToolPanel,
3179
+ if (variant === "executing") {
3180
+ return entering ? { opacity: 0, y: 12 } : { opacity: 1, y: 0 };
3181
+ }
3182
+ return entering ? { opacity: 0, y: 14, filter: "blur(10px)" } : { opacity: 1, y: 0, filter: "blur(0px)" };
3183
+ }
3184
+ function ToolMotion({ children, className, motionKey }) {
3185
+ const reduced = (0, import_react19.useReducedMotion)() ?? false;
3186
+ const { enter, exit } = toolPresenceTransition(reduced);
3187
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3188
+ import_react19.motion.div,
2909
3189
  {
2910
- toolName,
2911
- argsText,
2912
- result,
2913
- isError
2914
- }
3190
+ className: cn("aui-tool-motion w-full min-w-0", className),
3191
+ initial: toolMotionState(reduced, true, "settled"),
3192
+ animate: toolMotionState(reduced, false, "settled"),
3193
+ exit: reduced ? { opacity: 0, y: 6, transition: exit } : { opacity: 0, y: 8, filter: "blur(6px)", transition: exit },
3194
+ transition: enter,
3195
+ style: { willChange: "opacity, transform, filter" },
3196
+ children
3197
+ },
3198
+ motionKey
2915
3199
  );
2916
- };
2917
- var ToolPanel = ({ toolName, argsText, result, isError }) => {
2918
- const [open, setOpen] = (0, import_react19.useState)(false);
2919
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
3200
+ }
3201
+ function ToolPresence({
3202
+ presenceKey,
3203
+ children,
3204
+ className,
3205
+ variant = "settled"
3206
+ }) {
3207
+ const reduced = (0, import_react19.useReducedMotion)() ?? false;
3208
+ const { enter, exit } = toolPresenceTransition(reduced);
3209
+ const enterTransition = variant === "executing" ? { duration: reduced ? 0.3 : 0.52, ease: luxuryEase } : enter;
3210
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react19.AnimatePresence, { mode: "wait", initial: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3211
+ import_react19.motion.div,
3212
+ {
3213
+ className: cn("aui-tool-presence w-full min-w-0", className),
3214
+ initial: toolMotionState(reduced, true, variant),
3215
+ animate: toolMotionState(reduced, false, variant),
3216
+ exit: reduced ? { opacity: 0, y: 6, transition: exit } : { opacity: 0, y: 8, filter: "blur(6px)", transition: exit },
3217
+ transition: enterTransition,
3218
+ style: {
3219
+ willChange: variant === "executing" ? "opacity, transform" : "opacity, transform, filter"
3220
+ },
3221
+ children
3222
+ },
3223
+ presenceKey
3224
+ ) });
3225
+ }
3226
+ function ToolBodyPresence({
3227
+ open,
3228
+ children,
3229
+ className
3230
+ }) {
3231
+ const reduced = (0, import_react19.useReducedMotion)() ?? false;
3232
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2920
3233
  "div",
2921
3234
  {
2922
3235
  className: cn(
2923
- "aui-tool-fallback-root my-2 overflow-hidden rounded-lg border border-border/60 bg-muted/30 text-sm",
2924
- isError && "border-destructive/50 bg-destructive/5"
3236
+ "aui-tool-body grid min-h-0 transition-[grid-template-rows]",
3237
+ open ? reduced ? "duration-200 ease-out" : "duration-[340ms] ease-[cubic-bezier(0.16,1,0.3,1)]" : reduced ? "duration-150 ease-[cubic-bezier(0.4,0,0.2,1)]" : "duration-200 ease-[cubic-bezier(0.4,0,0.2,1)]"
2925
3238
  ),
2926
- children: [
2927
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2928
- "button",
2929
- {
2930
- type: "button",
2931
- onClick: () => setOpen((v) => !v),
2932
- className: "aui-tool-fallback-header flex w-full items-center gap-2 px-3 py-2 text-left text-muted-foreground transition-colors hover:bg-muted/50",
2933
- "aria-expanded": open,
2934
- children: [
2935
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react5.WrenchIcon, { className: "size-3.5" }),
2936
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "aui-tool-fallback-name flex-1 truncate font-mono text-xs font-medium text-foreground/80", children: toolName }),
2937
- isError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "aui-tool-fallback-status text-xs font-medium text-destructive", children: "error" }),
2938
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2939
- import_lucide_react5.ChevronDownIcon,
2940
- {
2941
- className: cn(
2942
- "size-3.5 shrink-0 transition-transform",
2943
- open && "rotate-180"
2944
- )
2945
- }
2946
- )
2947
- ]
2948
- }
2949
- ),
2950
- open && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "aui-tool-fallback-body grid gap-2 border-t border-border/40 bg-background/50 px-3 py-2.5 text-xs", children: [
2951
- argsText && argsText !== "{}" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Section, { label: "Input", value: argsText }),
2952
- result !== void 0 && result !== null && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Section, { label: "Output", value: formatResult(result) })
2953
- ] })
2954
- ]
3239
+ style: { gridTemplateRows: open ? "1fr" : "0fr" },
3240
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "min-h-0 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3241
+ "div",
3242
+ {
3243
+ className: cn(
3244
+ className,
3245
+ "transition-opacity",
3246
+ open ? reduced ? "opacity-100 duration-200 ease-out" : "opacity-100 duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] delay-75" : reduced ? "opacity-0 duration-100 ease-in" : "opacity-0 duration-150 ease-[cubic-bezier(0.4,0,0.2,1)]"
3247
+ ),
3248
+ children
3249
+ }
3250
+ ) })
2955
3251
  }
2956
3252
  );
2957
- };
2958
- var Section = ({ label, value }) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "aui-tool-fallback-section", children: [
2959
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "aui-tool-fallback-section-label mb-0.5 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: label }),
2960
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("pre", { className: "aui-tool-fallback-section-value overflow-x-auto whitespace-pre-wrap break-words font-mono text-[11px] leading-relaxed text-foreground/85", children: value })
2961
- ] });
2962
- function formatResult(result) {
3253
+ }
3254
+
3255
+ // src/components/tool-fallback.tsx
3256
+ var import_jsx_runtime23 = require("react/jsx-runtime");
3257
+ function detectRunning({
3258
+ status,
3259
+ result,
3260
+ streamRunning
3261
+ }) {
3262
+ const isError = status?.type === "incomplete" && status.reason !== "cancelled";
3263
+ if (isError) return false;
3264
+ if (status?.type === "running") return true;
3265
+ if (status?.type === "complete") return false;
3266
+ return streamRunning && result === void 0;
3267
+ }
3268
+ function useToolRunning(props) {
3269
+ const { isRunning: streamRunning } = useTimbalRuntime();
3270
+ const partStatus = (0, import_react21.useAuiState)((s) => s.part.status);
3271
+ return detectRunning({
3272
+ status: partStatus ?? props.status,
3273
+ result: props.result,
3274
+ streamRunning
3275
+ });
3276
+ }
3277
+ function formatToolLabel(toolName) {
3278
+ return toolName.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
3279
+ }
3280
+ function formatToolResult(result) {
2963
3281
  if (typeof result === "string") return result;
2964
3282
  try {
2965
3283
  return JSON.stringify(result, null, 2);
@@ -2967,32 +3285,172 @@ function formatResult(result) {
2967
3285
  return String(result);
2968
3286
  }
2969
3287
  }
2970
- var ToolFallback = (0, import_react19.memo)(
3288
+ var TimelineActionLabel = ({ action, detail, shimmer = false }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "inline-flex min-w-0 max-w-full items-baseline gap-1", children: [
3289
+ action ? shimmer ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3290
+ Shimmer,
3291
+ {
3292
+ as: "span",
3293
+ className: cn(studioTimelineShimmerActionClass, "aui-tool-shimmer"),
3294
+ duration: 1.8,
3295
+ spread: 2.5,
3296
+ children: action
3297
+ }
3298
+ ) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: studioTimelineActionClass, children: action }) : null,
3299
+ detail ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: studioTimelineDetailClass, children: detail }) : null
3300
+ ] });
3301
+ var TimelineHoverChevron = ({ expanded }) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3302
+ import_lucide_react5.ChevronRightIcon,
3303
+ {
3304
+ className: studioTimelineChevronClass(expanded),
3305
+ "aria-hidden": true
3306
+ }
3307
+ );
3308
+ var ToolPanel = ({ toolName, argsText, result, isError }) => {
3309
+ const [open, setOpen] = (0, import_react20.useState)(false);
3310
+ const detail = formatToolLabel(toolName);
3311
+ const formattedArgs = (0, import_react20.useMemo)(() => {
3312
+ if (!argsText || argsText === "{}") return null;
3313
+ try {
3314
+ return JSON.stringify(JSON.parse(argsText), null, 2);
3315
+ } catch {
3316
+ return argsText;
3317
+ }
3318
+ }, [argsText]);
3319
+ const formattedResult = (0, import_react20.useMemo)(() => {
3320
+ if (result === void 0 || result === null) return null;
3321
+ return formatToolResult(result);
3322
+ }, [result]);
3323
+ const hasBody = Boolean(formattedArgs || formattedResult);
3324
+ const action = isError ? "Failed" : "Used";
3325
+ if (!hasBody) {
3326
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "aui-tool-row w-full min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TimelineActionLabel, { action, detail }) });
3327
+ }
3328
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "aui-tool-row w-full min-w-0", children: [
3329
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3330
+ "button",
3331
+ {
3332
+ type: "button",
3333
+ onClick: () => setOpen((v) => !v),
3334
+ "aria-expanded": open,
3335
+ "aria-label": `${action} ${detail}`,
3336
+ className: studioTimelineRowButtonClass,
3337
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
3338
+ "span",
3339
+ {
3340
+ className: cn(
3341
+ "inline-flex min-w-0 max-w-full items-center gap-0.5",
3342
+ studioTimelineTextClass,
3343
+ "text-foreground"
3344
+ ),
3345
+ children: [
3346
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TimelineActionLabel, { action, detail }),
3347
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TimelineHoverChevron, { expanded: open })
3348
+ ]
3349
+ }
3350
+ )
3351
+ }
3352
+ ),
3353
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
3354
+ ToolBodyPresence,
3355
+ {
3356
+ open,
3357
+ className: cn(studioTimelineBodyPadClass, "gap-2"),
3358
+ children: [
3359
+ formattedArgs ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3360
+ "div",
3361
+ {
3362
+ className: cn(
3363
+ studioComposerIoWellClass,
3364
+ "max-h-48 overflow-auto px-2.5 py-2"
3365
+ ),
3366
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("pre", { className: "whitespace-pre-wrap break-words font-mono text-[11px] font-normal leading-relaxed text-foreground", children: formattedArgs })
3367
+ }
3368
+ ) : null,
3369
+ formattedResult ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3370
+ "div",
3371
+ {
3372
+ className: cn(
3373
+ studioComposerIoWellClass,
3374
+ "max-h-48 overflow-auto px-2.5 py-2"
3375
+ ),
3376
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("pre", { className: "whitespace-pre-wrap break-words font-mono text-[11px] font-normal leading-relaxed text-foreground", children: formattedResult })
3377
+ }
3378
+ ) : null
3379
+ ]
3380
+ }
3381
+ )
3382
+ ] });
3383
+ };
3384
+ var ToolFallbackImpl = ({
3385
+ toolName,
3386
+ argsText,
3387
+ result,
3388
+ status
3389
+ }) => {
3390
+ const isRunning = useToolRunning({ status, result });
3391
+ const isError = status?.type === "incomplete" && status.reason !== "cancelled";
3392
+ const presenceKey = isRunning ? "running" : isError ? "error" : "complete";
3393
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3394
+ ToolPresence,
3395
+ {
3396
+ presenceKey,
3397
+ variant: isRunning ? "executing" : "settled",
3398
+ className: "py-0.5",
3399
+ children: isRunning ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "aui-tool-running", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3400
+ TimelineActionLabel,
3401
+ {
3402
+ action: "Using",
3403
+ detail: formatToolLabel(toolName),
3404
+ shimmer: true
3405
+ }
3406
+ ) }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3407
+ ToolPanel,
3408
+ {
3409
+ toolName,
3410
+ argsText,
3411
+ result,
3412
+ isError
3413
+ }
3414
+ )
3415
+ }
3416
+ );
3417
+ };
3418
+ var ToolFallback = (0, import_react20.memo)(
2971
3419
  ToolFallbackImpl
2972
3420
  );
2973
3421
  ToolFallback.displayName = "ToolFallback";
2974
3422
 
2975
3423
  // src/artifacts/tool-artifact.tsx
2976
- var import_jsx_runtime22 = require("react/jsx-runtime");
3424
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2977
3425
  var ToolArtifactFallback = (props) => {
2978
3426
  const registry = useArtifactRegistry();
2979
- const isRunning = props.status?.type === "running";
3427
+ const isRunning = useToolRunning({
3428
+ status: props.status,
3429
+ result: props.result
3430
+ });
2980
3431
  if (!isRunning) {
2981
3432
  const artifact = parseArtifactFromToolResult(props.result);
2982
3433
  if (artifact) {
2983
3434
  const Renderer = registry[artifact.type];
2984
3435
  if (Renderer) {
2985
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Renderer, { artifact });
3436
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3437
+ ToolMotion,
3438
+ {
3439
+ motionKey: `artifact-${artifact.type}`,
3440
+ className: "aui-tool-artifact",
3441
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Renderer, { artifact })
3442
+ }
3443
+ );
2986
3444
  }
2987
3445
  }
2988
3446
  }
2989
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolFallback, { ...props });
3447
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ToolFallback, { ...props });
2990
3448
  };
2991
3449
 
2992
3450
  // src/components/composer.tsx
2993
- var import_react20 = require("@assistant-ui/react");
3451
+ var import_react22 = require("@assistant-ui/react");
2994
3452
  var import_lucide_react6 = require("lucide-react");
2995
- var import_jsx_runtime23 = require("react/jsx-runtime");
3453
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2996
3454
  var Composer = ({
2997
3455
  placeholder = "Send a message...",
2998
3456
  showAttachments = true,
@@ -3001,21 +3459,24 @@ var Composer = ({
3001
3459
  noAutoFocus,
3002
3460
  className
3003
3461
  }) => {
3004
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3005
- import_react20.ComposerPrimitive.Root,
3462
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3463
+ import_react22.ComposerPrimitive.Root,
3006
3464
  {
3007
3465
  className: cn(
3008
- "aui-composer-root relative mt-3 flex w-full flex-col",
3466
+ "aui-composer-root relative flex w-full flex-col",
3009
3467
  className
3010
3468
  ),
3011
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
3012
- import_react20.ComposerPrimitive.AttachmentDropzone,
3469
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3470
+ import_react22.ComposerPrimitive.AttachmentDropzone,
3013
3471
  {
3014
- className: "aui-composer-attachment-dropzone flex w-full flex-col rounded-2xl border border-input bg-background px-1 pt-2 outline-none transition-shadow has-[textarea:focus-visible]:border-ring has-[textarea:focus-visible]:ring-2 has-[textarea:focus-visible]:ring-ring/20 data-[dragging=true]:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:bg-accent/50",
3472
+ className: cn(
3473
+ studioComposeInputShellClass,
3474
+ "data-[dragging=true]:border-2 data-[dragging=true]:border-dashed data-[dragging=true]:border-primary data-[dragging=true]:bg-accent/50"
3475
+ ),
3015
3476
  children: [
3016
- showAttachments && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ComposerAttachments, {}),
3017
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ComposerInput, { placeholder, autoFocus: !noAutoFocus }),
3018
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3477
+ showAttachments && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ComposerAttachments, {}),
3478
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ComposerInput, { placeholder, autoFocus: !noAutoFocus }),
3479
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3019
3480
  ComposerToolbar,
3020
3481
  {
3021
3482
  showAttachments,
@@ -3033,7 +3494,7 @@ var ComposerInput = ({
3033
3494
  placeholder,
3034
3495
  autoFocus
3035
3496
  }) => {
3036
- const composer = (0, import_react20.useComposerRuntime)();
3497
+ const composer = (0, import_react22.useComposerRuntime)();
3037
3498
  const onKeyDown = (e) => {
3038
3499
  if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
3039
3500
  e.preventDefault();
@@ -3045,11 +3506,11 @@ var ComposerInput = ({
3045
3506
  el.style.height = "auto";
3046
3507
  el.style.height = `${Math.min(el.scrollHeight, 240)}px`;
3047
3508
  };
3048
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3049
- import_react20.ComposerPrimitive.Input,
3509
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3510
+ import_react22.ComposerPrimitive.Input,
3050
3511
  {
3051
3512
  placeholder,
3052
- className: "aui-composer-input mb-1 max-h-60 min-h-12 w-full resize-none bg-transparent px-4 pt-2 pb-3 text-sm outline-none placeholder:text-muted-foreground focus-visible:ring-0",
3513
+ className: "aui-composer-input max-h-60 min-h-14 w-full resize-none bg-transparent px-3 pt-3 pb-1 text-sm outline-none placeholder:text-muted-foreground/70 focus-visible:ring-0",
3053
3514
  rows: 1,
3054
3515
  autoFocus,
3055
3516
  "aria-label": "Message input",
@@ -3059,96 +3520,92 @@ var ComposerInput = ({
3059
3520
  );
3060
3521
  };
3061
3522
  var ComposerToolbar = ({ showAttachments, toolbar, sendTooltip }) => {
3062
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "aui-composer-action-wrapper relative mx-2 mb-2 flex items-center gap-1", children: [
3063
- showAttachments && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ComposerAddAttachment, {}),
3064
- toolbar,
3065
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1" }),
3066
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ComposerSendOrCancel, { sendTooltip })
3523
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-composer-action-wrapper flex items-center justify-between gap-1 px-2.5 pb-2.5", children: [
3524
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-center gap-1", children: [
3525
+ showAttachments && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ComposerAddAttachment, {}),
3526
+ toolbar
3527
+ ] }),
3528
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ComposerSendOrCancel, { sendTooltip })
3067
3529
  ] });
3068
3530
  };
3069
3531
  var ComposerSendOrCancel = ({ sendTooltip }) => {
3070
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
3071
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react20.AuiIf, { condition: (s) => !s.thread.isRunning, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react20.ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3532
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
3533
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react22.AuiIf, { condition: (s) => !s.thread.isRunning, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react22.ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3072
3534
  TooltipIconButton,
3073
3535
  {
3074
3536
  tooltip: sendTooltip,
3075
- side: "bottom",
3537
+ variant: "primary",
3076
3538
  type: "submit",
3077
- variant: "default",
3078
- size: "icon",
3079
- className: "aui-composer-send size-8 rounded-full",
3539
+ className: "aui-composer-send shrink-0 disabled:opacity-30",
3080
3540
  "aria-label": "Send message",
3081
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react6.ArrowUpIcon, { className: "aui-composer-send-icon size-4" })
3541
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react6.ArrowUpIcon, { className: "aui-composer-send-icon size-4" })
3082
3542
  }
3083
3543
  ) }) }),
3084
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react20.AuiIf, { condition: (s) => s.thread.isRunning, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react20.ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3085
- Button,
3544
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react22.AuiIf, { condition: (s) => s.thread.isRunning, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react22.ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3545
+ TooltipIconButton,
3086
3546
  {
3087
- type: "button",
3088
- variant: "default",
3089
- size: "icon",
3090
- className: "aui-composer-cancel size-8 rounded-full",
3547
+ tooltip: "Stop generating",
3548
+ variant: "primary",
3549
+ className: "aui-composer-cancel shrink-0",
3091
3550
  "aria-label": "Stop generating",
3092
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react6.SquareIcon, { className: "aui-composer-cancel-icon size-3 fill-current" })
3551
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react6.SquareIcon, { className: "aui-composer-cancel-icon size-3 fill-current" })
3093
3552
  }
3094
3553
  ) }) })
3095
3554
  ] });
3096
3555
  };
3097
3556
 
3098
3557
  // src/components/suggestions.tsx
3099
- var import_react21 = require("react");
3100
- var import_react22 = require("@assistant-ui/react");
3101
- var import_jsx_runtime24 = require("react/jsx-runtime");
3558
+ var import_react23 = require("react");
3559
+ var import_react24 = require("@assistant-ui/react");
3560
+ var import_lucide_react7 = require("lucide-react");
3561
+ var import_jsx_runtime26 = require("react/jsx-runtime");
3102
3562
  var Suggestions = ({
3103
3563
  suggestions,
3104
- layout = "grid",
3105
3564
  className
3106
3565
  }) => {
3107
3566
  const items = useResolvedSuggestions(suggestions);
3108
3567
  if (!items || items.length === 0) return null;
3109
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3568
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3110
3569
  "div",
3111
3570
  {
3112
3571
  className: cn(
3113
- "aui-thread-suggestions w-full pb-4",
3114
- layout === "grid" ? "grid gap-2 @md:grid-cols-2" : "flex gap-2 overflow-x-auto pb-1 [&::-webkit-scrollbar]:hidden",
3572
+ "aui-thread-suggestions flex w-full flex-col gap-2 pb-2.5",
3115
3573
  className
3116
3574
  ),
3117
- children: items.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SuggestionChip, { suggestion: s, compact: layout === "row" }, s.title + i))
3575
+ role: "list",
3576
+ "aria-label": "Suggested prompts",
3577
+ children: items.map((suggestion, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SuggestionRow, { suggestion }, (suggestion.prompt ?? suggestion.title) + i))
3118
3578
  }
3119
3579
  );
3120
3580
  };
3121
- var SuggestionChip = ({
3122
- suggestion,
3123
- compact
3124
- }) => {
3125
- const runtime = (0, import_react22.useThreadRuntime)();
3581
+ var SuggestionRow = ({ suggestion }) => {
3582
+ const runtime = (0, import_react24.useThreadRuntime)();
3126
3583
  const onClick = () => {
3127
3584
  const text = suggestion.prompt ?? suggestion.title;
3128
3585
  runtime.append({ role: "user", content: [{ type: "text", text }] });
3129
3586
  };
3130
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "aui-thread-suggestion-display fade-in slide-in-from-bottom-2 animate-in fill-mode-both duration-200", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
3131
- Button,
3587
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
3588
+ "button",
3132
3589
  {
3133
- variant: "ghost",
3590
+ type: "button",
3591
+ role: "listitem",
3134
3592
  onClick,
3135
- className: cn(
3136
- "aui-thread-suggestion h-auto rounded-2xl border text-left text-sm transition-colors hover:bg-muted",
3137
- compact ? "shrink-0 flex-row items-center gap-2 whitespace-nowrap px-3 py-2" : "w-full flex-wrap items-start justify-start gap-1 px-4 py-3 @md:flex-col"
3138
- ),
3593
+ className: cn("aui-thread-suggestion", studioListRowButtonClass),
3139
3594
  children: [
3140
- suggestion.icon && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "aui-thread-suggestion-icon shrink-0 text-muted-foreground", children: suggestion.icon }),
3141
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "aui-thread-suggestion-text-1 font-medium", children: suggestion.title }),
3142
- suggestion.description && !compact && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "aui-thread-suggestion-text-2 text-muted-foreground", children: suggestion.description })
3595
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "aui-thread-suggestion-icon shrink-0 text-muted-foreground", children: suggestion.icon ?? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react7.ArrowUpIcon, { className: "size-4", strokeWidth: 1.75, "aria-hidden": true }) }),
3596
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: "aui-thread-suggestion-text min-w-0 flex-1 text-left", children: [
3597
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "aui-thread-suggestion-text-1 block truncate text-sm font-normal text-foreground", children: suggestion.title }),
3598
+ suggestion.description && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "aui-thread-suggestion-text-2 mt-0.5 block truncate text-xs text-muted-foreground", children: suggestion.description })
3599
+ ] })
3143
3600
  ]
3144
3601
  }
3145
- ) });
3602
+ );
3146
3603
  };
3147
3604
  function useResolvedSuggestions(source) {
3148
- const [resolved, setResolved] = (0, import_react21.useState)(
3605
+ const [resolved, setResolved] = (0, import_react23.useState)(
3149
3606
  () => Array.isArray(source) ? source : void 0
3150
3607
  );
3151
- (0, import_react21.useEffect)(() => {
3608
+ (0, import_react23.useEffect)(() => {
3152
3609
  if (!source) {
3153
3610
  setResolved(void 0);
3154
3611
  return;
@@ -3167,13 +3624,80 @@ function useResolvedSuggestions(source) {
3167
3624
  cancelled = true;
3168
3625
  };
3169
3626
  }, [source]);
3170
- return (0, import_react21.useMemo)(() => resolved, [resolved]);
3627
+ return (0, import_react23.useMemo)(() => resolved, [resolved]);
3628
+ }
3629
+
3630
+ // src/design/theme-sanity.ts
3631
+ var scheduled = false;
3632
+ var warned = false;
3633
+ function isDev() {
3634
+ if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
3635
+ return false;
3636
+ }
3637
+ return true;
3638
+ }
3639
+ function parseLuminance(color) {
3640
+ const value = color.trim();
3641
+ if (!value) return null;
3642
+ const oklch = value.match(/oklch\(\s*([0-9.]+)/i);
3643
+ if (oklch) {
3644
+ const lightness = Number.parseFloat(oklch[1]);
3645
+ if (Number.isFinite(lightness)) return lightness;
3646
+ }
3647
+ const rgb = value.match(/rgba?\(\s*([0-9.]+)[\s,]+([0-9.]+)[\s,]+([0-9.]+)/i);
3648
+ if (rgb) {
3649
+ const r = Number.parseFloat(rgb[1]) / 255;
3650
+ const g = Number.parseFloat(rgb[2]) / 255;
3651
+ const b = Number.parseFloat(rgb[3]) / 255;
3652
+ if ([r, g, b].every(Number.isFinite)) {
3653
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
3654
+ }
3655
+ }
3656
+ const hsl = value.match(/hsla?\(\s*[0-9.]+[\s,]+[0-9.]+%[\s,]+([0-9.]+)%/i);
3657
+ if (hsl) {
3658
+ const lightness = Number.parseFloat(hsl[1]) / 100;
3659
+ if (Number.isFinite(lightness)) return lightness;
3660
+ }
3661
+ return null;
3662
+ }
3663
+ function runCheck() {
3664
+ if (warned) return;
3665
+ if (typeof window === "undefined" || typeof document === "undefined") return;
3666
+ const root = document.documentElement;
3667
+ const styles = window.getComputedStyle(root);
3668
+ const background = styles.getPropertyValue("--background").trim();
3669
+ if (!background) {
3670
+ warned = true;
3671
+ console.warn(
3672
+ '[@timbal-ai/timbal-react] No `--background` CSS variable found on `<html>`. Did you `import "@timbal-ai/timbal-react/styles.css"` in your app entry? Components rely on semantic tokens (bg-background, text-foreground, \u2026) and will fall back to browser defaults.'
3673
+ );
3674
+ return;
3675
+ }
3676
+ const luminance = parseLuminance(background);
3677
+ if (luminance === null) return;
3678
+ const hasDarkClass = root.classList.contains("dark");
3679
+ const looksDark = luminance < 0.5;
3680
+ if (hasDarkClass !== looksDark) {
3681
+ warned = true;
3682
+ console.warn(
3683
+ `[@timbal-ai/timbal-react] Theme mismatch detected. \`<html>\` has${hasDarkClass ? "" : " no"} \`.dark\` class but the resolved \`--background\` is ${looksDark ? "dark" : "light"} (${background}). This usually means the consumer's CSS overrides \`--background\` only in one mode. Import \`@timbal-ai/timbal-react/styles.css\` for a complete light + dark token set, or declare matching \`:root\` AND \`.dark\` blocks in your own CSS.`
3684
+ );
3685
+ }
3686
+ }
3687
+ function scheduleThemeSanityCheck() {
3688
+ if (scheduled) return;
3689
+ if (!isDev()) return;
3690
+ if (typeof window === "undefined") return;
3691
+ scheduled = true;
3692
+ if (typeof queueMicrotask === "function") {
3693
+ queueMicrotask(() => setTimeout(runCheck, 0));
3694
+ } else {
3695
+ setTimeout(runCheck, 0);
3696
+ }
3171
3697
  }
3172
3698
 
3173
3699
  // src/components/thread.tsx
3174
- var import_react23 = require("@assistant-ui/react");
3175
- var import_lucide_react7 = require("lucide-react");
3176
- var import_jsx_runtime25 = require("react/jsx-runtime");
3700
+ var import_jsx_runtime27 = require("react/jsx-runtime");
3177
3701
  var Thread = ({
3178
3702
  className,
3179
3703
  maxWidth = "44rem",
@@ -3191,27 +3715,30 @@ var Thread = ({
3191
3715
  const EditComposerSlot = components?.EditComposer ?? EditComposer;
3192
3716
  const ScrollToBottomSlot = components?.ScrollToBottom ?? ThreadScrollToBottom;
3193
3717
  const SuggestionsSlot = components?.Suggestions ?? Suggestions;
3194
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3718
+ (0, import_react25.useEffect)(() => {
3719
+ scheduleThemeSanityCheck();
3720
+ }, []);
3721
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3195
3722
  ArtifactRegistryProvider,
3196
3723
  {
3197
3724
  renderers: artifacts?.renderers,
3198
3725
  override: artifacts?.override,
3199
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(UiEventProvider, { onEvent: onArtifactEvent ?? (() => {
3200
- }), children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3201
- import_react23.ThreadPrimitive.Root,
3726
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(UiEventProvider, { onEvent: onArtifactEvent ?? (() => {
3727
+ }), children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3728
+ import_react26.ThreadPrimitive.Root,
3202
3729
  {
3203
3730
  className: cn(
3204
3731
  "aui-root aui-thread-root @container flex h-full flex-col bg-background",
3205
3732
  className
3206
3733
  ),
3207
3734
  style: { ["--thread-max-width"]: maxWidth },
3208
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3209
- import_react23.ThreadPrimitive.Viewport,
3735
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
3736
+ import_react26.ThreadPrimitive.Viewport,
3210
3737
  {
3211
3738
  turnAnchor: "bottom",
3212
3739
  className: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll px-4 pt-4",
3213
3740
  children: [
3214
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3741
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3215
3742
  WelcomeSlot,
3216
3743
  {
3217
3744
  config: welcome,
@@ -3219,8 +3746,8 @@ var Thread = ({
3219
3746
  Suggestions: SuggestionsSlot
3220
3747
  }
3221
3748
  ),
3222
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3223
- import_react23.ThreadPrimitive.Messages,
3749
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3750
+ import_react26.ThreadPrimitive.Messages,
3224
3751
  {
3225
3752
  components: {
3226
3753
  UserMessage: UserMessageSlot,
@@ -3229,9 +3756,9 @@ var Thread = ({
3229
3756
  }
3230
3757
  }
3231
3758
  ),
3232
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react23.ThreadPrimitive.ViewportFooter, { className: "aui-thread-viewport-footer sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible rounded-t-3xl bg-background pb-4 md:pb-6", children: [
3233
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ScrollToBottomSlot, {}),
3234
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ComposerSlot, { placeholder: composerPlaceholder })
3759
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react26.ThreadPrimitive.ViewportFooter, { className: "aui-thread-viewport-footer sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible bg-transparent pb-4 md:pb-6", children: [
3760
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ScrollToBottomSlot, {}),
3761
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ComposerSlot, { placeholder: composerPlaceholder })
3235
3762
  ] })
3236
3763
  ]
3237
3764
  }
@@ -3242,105 +3769,164 @@ var Thread = ({
3242
3769
  );
3243
3770
  };
3244
3771
  var ThreadScrollToBottom = () => {
3245
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ThreadPrimitive.ScrollToBottom, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3772
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ThreadPrimitive.ScrollToBottom, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3246
3773
  TooltipIconButton,
3247
3774
  {
3248
3775
  tooltip: "Scroll to bottom",
3249
- variant: "outline",
3250
- className: "aui-thread-scroll-to-bottom absolute -top-12 z-10 self-center rounded-full p-4 disabled:invisible dark:bg-background dark:hover:bg-accent",
3251
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.ArrowDownIcon, {})
3776
+ variant: "secondary",
3777
+ className: "aui-thread-scroll-to-bottom absolute -top-12 z-10 self-center disabled:invisible",
3778
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.ArrowDownIcon, { className: "size-4" })
3252
3779
  }
3253
3780
  ) });
3254
3781
  };
3782
+ var welcomeStagger = {
3783
+ initial: {},
3784
+ animate: {
3785
+ transition: { staggerChildren: 0.16, delayChildren: 0.12 }
3786
+ }
3787
+ };
3788
+ var welcomeItem = {
3789
+ initial: { opacity: 0, y: 14 },
3790
+ animate: {
3791
+ opacity: 1,
3792
+ y: 0,
3793
+ transition: { duration: 0.9, ease: luxuryEase }
3794
+ }
3795
+ };
3796
+ var welcomeIcon = {
3797
+ initial: { opacity: 0, y: 10, scale: 0.96 },
3798
+ animate: {
3799
+ opacity: 1,
3800
+ y: 0,
3801
+ scale: 1,
3802
+ transition: { duration: 1.1, ease: luxuryEase }
3803
+ }
3804
+ };
3255
3805
  var ThreadWelcome = ({
3256
3806
  config,
3257
3807
  suggestions,
3258
3808
  Suggestions: SuggestionsSlot = Suggestions
3259
3809
  }) => {
3260
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.AuiIf, { condition: (s) => s.thread.isEmpty, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col", children: [
3261
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "aui-thread-welcome-center flex w-full grow flex-col items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-thread-welcome-message flex size-full flex-col items-center justify-center px-4 text-center", children: [
3262
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "fade-in animate-in fill-mode-both relative mb-6 flex size-14 items-center justify-center duration-300", children: [
3263
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "animate-ai-ring-glow absolute inset-0 rounded-2xl bg-gradient-to-br from-primary/15 to-primary/5 ring-1 ring-primary/15" }),
3264
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "animate-ai-pulse-ring absolute inset-0" }),
3265
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3266
- "svg",
3267
- {
3268
- xmlns: "http://www.w3.org/2000/svg",
3269
- viewBox: "0 0 24 24",
3270
- fill: "none",
3271
- stroke: "currentColor",
3272
- strokeWidth: "1.5",
3273
- strokeLinecap: "round",
3274
- strokeLinejoin: "round",
3275
- className: "animate-ai-breathe relative size-7 text-primary/75",
3276
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("path", { d: "M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z" })
3277
- }
3278
- )
3279
- ] }),
3280
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h1", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both font-semibold text-2xl duration-200", children: config?.heading ?? "How can I help you today?" }),
3281
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-muted-foreground mt-2 delay-75 duration-200", children: config?.subheading ?? "Send a message to start a conversation." })
3282
- ] }) }),
3283
- suggestions && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SuggestionsSlot, { suggestions })
3284
- ] }) });
3810
+ const isEmpty = (0, import_react26.useThread)((s) => s.messages.length === 0);
3811
+ if (!isEmpty) return null;
3812
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col", children: [
3813
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "aui-thread-welcome-center flex w-full grow flex-col items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
3814
+ import_react27.motion.div,
3815
+ {
3816
+ className: "aui-thread-welcome-message flex flex-col items-center justify-center px-4 text-center",
3817
+ variants: welcomeStagger,
3818
+ initial: "initial",
3819
+ animate: "animate",
3820
+ children: [
3821
+ config?.icon && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react27.motion.div, { variants: welcomeIcon, className: "mb-5", children: config.icon }),
3822
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3823
+ import_react27.motion.h1,
3824
+ {
3825
+ variants: welcomeItem,
3826
+ className: "aui-thread-welcome-message-inner font-semibold text-2xl",
3827
+ children: config?.heading ?? "How can I help you today?"
3828
+ }
3829
+ ),
3830
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3831
+ import_react27.motion.p,
3832
+ {
3833
+ variants: welcomeItem,
3834
+ className: "aui-thread-welcome-message-inner mt-2 text-muted-foreground",
3835
+ children: config?.subheading ?? "Send a message to start a conversation."
3836
+ }
3837
+ )
3838
+ ]
3839
+ }
3840
+ ) }),
3841
+ suggestions && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "aui-thread-welcome-suggestions mx-auto w-full max-w-(--thread-max-width) px-2", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SuggestionsSlot, { suggestions }) })
3842
+ ] });
3285
3843
  };
3286
3844
  var MessageError = () => {
3287
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.MessagePrimitive.Error, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ErrorPrimitive.Root, { className: "aui-message-error-root mt-2 rounded-md border border-destructive bg-destructive/10 p-3 text-destructive text-sm dark:bg-destructive/5 dark:text-red-200", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ErrorPrimitive.Message, { className: "aui-message-error-message line-clamp-2" }) }) });
3845
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.MessagePrimitive.Error, { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ErrorPrimitive.Root, { className: "aui-message-error-root mt-2 rounded-md border border-destructive bg-destructive/10 p-3 text-destructive text-sm", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ErrorPrimitive.Message, { className: "aui-message-error-message line-clamp-2" }) }) });
3288
3846
  };
3289
3847
  var AssistantMessage = () => {
3290
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3291
- import_react23.MessagePrimitive.Root,
3848
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
3849
+ import_react26.MessagePrimitive.Root,
3292
3850
  {
3293
3851
  className: "aui-assistant-message-root fade-in slide-in-from-bottom-1 relative mx-auto w-full max-w-(--thread-max-width) animate-in py-3 duration-150",
3294
3852
  "data-role": "assistant",
3295
3853
  children: [
3296
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-assistant-message-content wrap-break-word px-2 text-foreground leading-relaxed", children: [
3297
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3298
- import_react23.MessagePrimitive.Parts,
3854
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "aui-assistant-message-content wrap-break-word px-2 text-foreground leading-relaxed", children: [
3855
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3856
+ import_react26.MessagePrimitive.Parts,
3299
3857
  {
3300
3858
  components: {
3301
3859
  Text: MarkdownText,
3302
- tools: { Fallback: ToolArtifactFallback }
3860
+ // `Override` (not `Fallback`) replaces the default tool renderer
3861
+ // entirely so we never fall back to the assistant-ui boilerplate.
3862
+ tools: { Override: ToolArtifactFallback }
3303
3863
  }
3304
3864
  }
3305
3865
  ),
3306
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(MessageError, {})
3866
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MessageError, {})
3307
3867
  ] }),
3308
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "aui-assistant-message-footer mt-1 ml-2 flex", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AssistantActionBar, {}) })
3868
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "aui-assistant-message-footer mt-0 ml-1 flex", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AssistantActionBar, {}) })
3309
3869
  ]
3310
3870
  }
3311
3871
  );
3312
3872
  };
3873
+ var ASSISTANT_ACTION_ICON_CLASS = cn(
3874
+ "size-6 min-h-6 min-w-6 text-muted-foreground/45 hover:text-muted-foreground/80",
3875
+ // The v2 fill span sits inside `group/tbv2 > span:first-child`. We mute it
3876
+ // here so action-bar buttons read as subtle icons rather than full pills.
3877
+ "[&>span:first-child]:bg-transparent",
3878
+ "[&>span:first-child]:group-hover/tbv2:bg-muted/70"
3879
+ );
3313
3880
  var AssistantActionBar = () => {
3314
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3315
- import_react23.ActionBarPrimitive.Root,
3881
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
3882
+ import_react26.ActionBarPrimitive.Root,
3316
3883
  {
3317
3884
  hideWhenRunning: true,
3318
3885
  autohide: "not-last",
3319
- autohideFloat: "single-branch",
3320
- className: "aui-assistant-action-bar-root col-start-3 row-start-2 -ml-1 flex gap-1 text-muted-foreground data-floating:absolute data-floating:rounded-md data-floating:border data-floating:bg-background data-floating:p-1 data-floating:shadow-sm",
3886
+ className: "aui-assistant-action-bar-root flex items-center gap-0 bg-transparent px-0 py-0.5 text-muted-foreground/60",
3321
3887
  children: [
3322
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ActionBarPrimitive.Copy, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(TooltipIconButton, { tooltip: "Copy", children: [
3323
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.AuiIf, { condition: (s) => s.message.isCopied, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.CheckIcon, {}) }),
3324
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.AuiIf, { condition: (s) => !s.message.isCopied, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.CopyIcon, {}) })
3325
- ] }) }),
3326
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ActionBarPrimitive.Reload, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TooltipIconButton, { tooltip: "Refresh", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.RefreshCwIcon, {}) }) }),
3327
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react23.ActionBarMorePrimitive.Root, { children: [
3328
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ActionBarMorePrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3888
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ActionBarPrimitive.Copy, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
3889
+ TooltipIconButton,
3890
+ {
3891
+ tooltip: "Copy",
3892
+ variant: "ghost",
3893
+ className: ASSISTANT_ACTION_ICON_CLASS,
3894
+ children: [
3895
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.AuiIf, { condition: (s) => s.message.isCopied, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.CheckIcon, { className: "size-3" }) }),
3896
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.AuiIf, { condition: (s) => !s.message.isCopied, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.CopyIcon, { className: "size-3" }) })
3897
+ ]
3898
+ }
3899
+ ) }),
3900
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ActionBarPrimitive.Reload, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3901
+ TooltipIconButton,
3902
+ {
3903
+ tooltip: "Regenerate",
3904
+ variant: "ghost",
3905
+ className: ASSISTANT_ACTION_ICON_CLASS,
3906
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.RefreshCwIcon, { className: "size-3" })
3907
+ }
3908
+ ) }),
3909
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react26.ActionBarMorePrimitive.Root, { children: [
3910
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ActionBarMorePrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3329
3911
  TooltipIconButton,
3330
3912
  {
3331
3913
  tooltip: "More",
3332
- className: "data-[state=open]:bg-accent",
3333
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.MoreHorizontalIcon, {})
3914
+ variant: "ghost",
3915
+ className: cn(
3916
+ ASSISTANT_ACTION_ICON_CLASS,
3917
+ "data-[state=open]:text-muted-foreground/80"
3918
+ ),
3919
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.MoreHorizontalIcon, { className: "size-3" })
3334
3920
  }
3335
3921
  ) }),
3336
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3337
- import_react23.ActionBarMorePrimitive.Content,
3922
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3923
+ import_react26.ActionBarMorePrimitive.Content,
3338
3924
  {
3339
3925
  side: "bottom",
3340
3926
  align: "start",
3341
- className: "aui-action-bar-more-content z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
3342
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ActionBarPrimitive.ExportMarkdown, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react23.ActionBarMorePrimitive.Item, { className: "aui-action-bar-more-item flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground", children: [
3343
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.DownloadIcon, { className: "size-4" }),
3927
+ className: "aui-action-bar-more-content z-50 min-w-36 overflow-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-card-elevated",
3928
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ActionBarPrimitive.ExportMarkdown, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react26.ActionBarMorePrimitive.Item, { className: "aui-action-bar-more-item flex cursor-pointer select-none items-center gap-2 rounded-md px-2 py-1.5 text-sm outline-none hover:bg-muted focus:bg-muted", children: [
3929
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.DownloadIcon, { className: "size-4 shrink-0" }),
3344
3930
  "Export as Markdown"
3345
3931
  ] }) })
3346
3932
  }
@@ -3350,51 +3936,71 @@ var AssistantActionBar = () => {
3350
3936
  }
3351
3937
  );
3352
3938
  };
3939
+ var UserMessageText = () => {
3940
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "whitespace-pre-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.MessagePartPrimitive.Text, { smooth: false }) });
3941
+ };
3353
3942
  var UserMessage = () => {
3354
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3355
- import_react23.MessagePrimitive.Root,
3943
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
3944
+ import_react26.MessagePrimitive.Root,
3356
3945
  {
3357
- className: "aui-user-message-root fade-in slide-in-from-bottom-1 mx-auto grid w-full max-w-(--thread-max-width) animate-in auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 py-3 duration-150 [&:where(>*)]:col-start-2",
3946
+ className: "aui-user-message-root mx-auto flex w-full max-w-(--thread-max-width) flex-col items-end gap-2 px-2 py-3",
3358
3947
  "data-role": "user",
3359
3948
  children: [
3360
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(UserMessageAttachments, {}),
3361
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-user-message-content-wrapper relative col-start-2 min-w-0", children: [
3362
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "aui-user-message-content wrap-break-word rounded-2xl bg-muted px-4 py-2.5 text-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.MessagePrimitive.Parts, {}) }),
3363
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "aui-user-action-bar-wrapper absolute top-1/2 left-0 -translate-x-full -translate-y-1/2 pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(UserActionBar, {}) })
3364
- ] })
3949
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(UserMessageAttachments, {}),
3950
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
3951
+ import_react27.motion.div,
3952
+ {
3953
+ className: "aui-user-message-content relative inline-block max-w-[80%] rounded-2xl bg-bubble-user px-4 py-2.5 text-bubble-user-foreground",
3954
+ initial: { opacity: 0, y: 8, scale: 0.99 },
3955
+ animate: { opacity: 1, y: 0, scale: 1 },
3956
+ transition: { duration: 0.65, ease: luxuryEase },
3957
+ children: [
3958
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.MessagePrimitive.Parts, { components: { Text: UserMessageText } }),
3959
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "aui-user-action-bar-wrapper absolute top-1/2 left-0 -translate-x-full -translate-y-1/2 pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(UserActionBar, {}) })
3960
+ ]
3961
+ }
3962
+ )
3365
3963
  ]
3366
3964
  }
3367
3965
  );
3368
3966
  };
3369
3967
  var UserActionBar = () => {
3370
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3371
- import_react23.ActionBarPrimitive.Root,
3968
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3969
+ import_react26.ActionBarPrimitive.Root,
3372
3970
  {
3373
3971
  hideWhenRunning: true,
3374
3972
  autohide: "not-last",
3375
3973
  className: "aui-user-action-bar-root flex flex-col items-end",
3376
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ActionBarPrimitive.Edit, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TooltipIconButton, { tooltip: "Edit", className: "aui-user-action-edit p-4", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.PencilIcon, {}) }) })
3974
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ActionBarPrimitive.Edit, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3975
+ TooltipIconButton,
3976
+ {
3977
+ tooltip: "Edit",
3978
+ variant: "ghost",
3979
+ className: ASSISTANT_ACTION_ICON_CLASS,
3980
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.PencilIcon, { className: "size-3" })
3981
+ }
3982
+ ) })
3377
3983
  }
3378
3984
  );
3379
3985
  };
3380
3986
  var EditComposer = () => {
3381
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.MessagePrimitive.Root, { className: "aui-edit-composer-wrapper mx-auto flex w-full max-w-(--thread-max-width) flex-col px-2 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react23.ComposerPrimitive.Root, { className: "aui-edit-composer-root ml-auto flex w-full max-w-[85%] flex-col rounded-2xl bg-muted", children: [
3382
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3383
- import_react23.ComposerPrimitive.Input,
3987
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.MessagePrimitive.Root, { className: "aui-edit-composer-wrapper mx-auto flex w-full max-w-(--thread-max-width) flex-col px-2 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react26.ComposerPrimitive.Root, { className: "aui-edit-composer-root ml-auto flex w-full max-w-[85%] flex-col rounded-2xl bg-muted", children: [
3988
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3989
+ import_react26.ComposerPrimitive.Input,
3384
3990
  {
3385
3991
  className: "aui-edit-composer-input min-h-14 w-full resize-none bg-transparent p-4 text-foreground text-sm outline-none",
3386
3992
  autoFocus: true
3387
3993
  }
3388
3994
  ),
3389
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-edit-composer-footer mx-3 mb-3 flex items-center gap-2 self-end", children: [
3390
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Button, { variant: "ghost", size: "sm", children: "Cancel" }) }),
3391
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Button, { size: "sm", children: "Update" }) })
3995
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "aui-edit-composer-footer mx-3 mb-3 flex items-center gap-2 self-end", children: [
3996
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TimbalV2Button, { variant: "ghost", size: "sm", children: "Cancel" }) }),
3997
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react26.ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TimbalV2Button, { variant: "primary", size: "sm", children: "Update" }) })
3392
3998
  ] })
3393
3999
  ] }) });
3394
4000
  };
3395
4001
 
3396
4002
  // src/components/chat.tsx
3397
- var import_jsx_runtime26 = require("react/jsx-runtime");
4003
+ var import_jsx_runtime28 = require("react/jsx-runtime");
3398
4004
  function TimbalChat({
3399
4005
  workforceId,
3400
4006
  baseUrl,
@@ -3405,7 +4011,7 @@ function TimbalChat({
3405
4011
  debug,
3406
4012
  ...threadProps
3407
4013
  }) {
3408
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
4014
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3409
4015
  TimbalRuntimeProvider,
3410
4016
  {
3411
4017
  workforceId,
@@ -3415,23 +4021,1598 @@ function TimbalChat({
3415
4021
  attachmentsUploadUrl,
3416
4022
  attachmentsAccept,
3417
4023
  debug,
3418
- children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Thread, { ...threadProps })
4024
+ children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Thread, { ...threadProps })
3419
4025
  }
3420
4026
  );
3421
4027
  }
3422
4028
 
3423
- // src/artifacts/agent-instructions.ts
3424
- var ARTIFACT_AGENT_INSTRUCTIONS = `
3425
- ## Rich artifacts (Timbal chat UI)
3426
-
3427
- When you need charts, tables, choice widgets, or interactive controls, return a **JSON artifact object** instead of plain prose. The chat UI renders these automatically.
4029
+ // src/components/workforce-selector.tsx
4030
+ var import_lucide_react9 = require("lucide-react");
4031
+ var import_jsx_runtime29 = require("react/jsx-runtime");
4032
+ var WorkforceSelector = ({
4033
+ workforces,
4034
+ value,
4035
+ onChange,
4036
+ hideWhenSingle = true,
4037
+ className,
4038
+ placeholder = "Select agent"
4039
+ }) => {
4040
+ if (workforces.length === 0) return null;
4041
+ if (hideWhenSingle && workforces.length === 1) return null;
4042
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
4043
+ "div",
4044
+ {
4045
+ className: cn(
4046
+ "aui-workforce-selector relative inline-flex items-center",
4047
+ studioTopbarPillHeightClass,
4048
+ studioSecondaryChromeClass,
4049
+ "rounded-full",
4050
+ className
4051
+ ),
4052
+ children: [
4053
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
4054
+ "select",
4055
+ {
4056
+ className: "aui-workforce-selector-input h-full cursor-pointer appearance-none rounded-full border-none bg-transparent pr-8 pl-3.5 text-sm font-medium text-foreground outline-none focus:outline-none",
4057
+ value,
4058
+ onChange: (e) => onChange(e.target.value),
4059
+ "aria-label": placeholder,
4060
+ children: [
4061
+ !value && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: "", children: placeholder }),
4062
+ workforces.map((w) => {
4063
+ const id = idOf(w);
4064
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("option", { value: id, children: w.name ?? id }, id);
4065
+ })
4066
+ ]
4067
+ }
4068
+ ),
4069
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
4070
+ import_lucide_react9.ChevronDownIcon,
4071
+ {
4072
+ className: "aui-workforce-selector-icon pointer-events-none absolute right-3 size-3.5 text-muted-foreground/70",
4073
+ "aria-hidden": true
4074
+ }
4075
+ )
4076
+ ]
4077
+ }
4078
+ );
4079
+ };
4080
+ function idOf(item) {
4081
+ return item.id ?? item.uid ?? item.name ?? "";
4082
+ }
3428
4083
 
3429
- ### Delivery channels (either works)
4084
+ // src/hooks/use-workforces.ts
4085
+ var import_react28 = require("react");
4086
+ function useWorkforces(options = {}) {
4087
+ const { baseUrl = "/api", fetch: fetchFn, pickInitial, enabled = true } = options;
4088
+ const [workforces, setWorkforces] = (0, import_react28.useState)([]);
4089
+ const [selectedId, setSelectedId] = (0, import_react28.useState)("");
4090
+ const [isLoading, setIsLoading] = (0, import_react28.useState)(enabled);
4091
+ const [error, setError] = (0, import_react28.useState)(null);
4092
+ const fetchFnRef = (0, import_react28.useRef)(fetchFn ?? authFetch);
4093
+ (0, import_react28.useEffect)(() => {
4094
+ fetchFnRef.current = fetchFn ?? authFetch;
4095
+ }, [fetchFn]);
4096
+ const pickInitialRef = (0, import_react28.useRef)(pickInitial);
4097
+ (0, import_react28.useEffect)(() => {
4098
+ pickInitialRef.current = pickInitial;
4099
+ }, [pickInitial]);
4100
+ const load = (0, import_react28.useMemo)(() => {
4101
+ return async () => {
4102
+ if (!enabled) {
4103
+ setIsLoading(false);
4104
+ return;
4105
+ }
4106
+ setIsLoading(true);
4107
+ setError(null);
4108
+ try {
4109
+ const res = await fetchFnRef.current(`${baseUrl}/workforce`);
4110
+ if (!res.ok) throw new Error(`Failed to load workforces (${res.status})`);
4111
+ const data = await res.json();
4112
+ setWorkforces(data);
4113
+ setSelectedId((current) => {
4114
+ if (current && data.some((w) => idOf2(w) === current)) return current;
4115
+ const initial = pickInitialRef.current?.(data) ?? data.find((w) => w.type === "agent") ?? data[0];
4116
+ return initial ? idOf2(initial) : "";
4117
+ });
4118
+ } catch (err) {
4119
+ setError(err instanceof Error ? err : new Error(String(err)));
4120
+ } finally {
4121
+ setIsLoading(false);
4122
+ }
4123
+ };
4124
+ }, [baseUrl, enabled]);
4125
+ (0, import_react28.useEffect)(() => {
4126
+ load();
4127
+ }, [load]);
4128
+ const selected = (0, import_react28.useMemo)(
4129
+ () => workforces.find((w) => idOf2(w) === selectedId),
4130
+ [workforces, selectedId]
4131
+ );
4132
+ return {
4133
+ workforces,
4134
+ selectedId,
4135
+ setSelectedId,
4136
+ selected,
4137
+ isLoading,
4138
+ error,
4139
+ refresh: load
4140
+ };
4141
+ }
4142
+ function idOf2(item) {
4143
+ return item.id ?? item.uid ?? item.name ?? "";
4144
+ }
3430
4145
 
3431
- 1. **Tool result (preferred)** \u2014 return a single JSON object (or a JSON string) from a tool. The object must include a string \`type\` field.
3432
- 2. **Inline markdown fence** \u2014 embed the same JSON inside a fenced block:
4146
+ // src/design/tokens.ts
4147
+ var SIDEBAR_WIDTH_PX = 224;
4148
+ var SIDEBAR_WIDTH_COLLAPSED_PX = 52;
4149
+ var SIDEBAR_MOBILE_PX = 272;
4150
+ var SIDEBAR_GAP_PX = 12;
4151
+ var SIDEBAR_CONTENT_GAP_PX = 8;
4152
+ var TOPBAR_GAP_PX = 8;
4153
+ var TOPBAR_HEIGHT_PX = 48;
4154
+ var PILL_HEIGHT_PX = 40;
4155
+ var SIDEBAR_INSET_PX_EXPANDED = SIDEBAR_GAP_PX + SIDEBAR_WIDTH_PX + SIDEBAR_CONTENT_GAP_PX;
4156
+ var SIDEBAR_INSET_PX_COLLAPSED = SIDEBAR_GAP_PX + SIDEBAR_WIDTH_COLLAPSED_PX + SIDEBAR_CONTENT_GAP_PX;
4157
+ var px = (n) => `${n / 16}rem`;
4158
+ var SIDEBAR_WIDTH = px(SIDEBAR_WIDTH_PX);
4159
+ var SIDEBAR_WIDTH_COLLAPSED = px(SIDEBAR_WIDTH_COLLAPSED_PX);
4160
+ var SIDEBAR_GAP = px(SIDEBAR_GAP_PX);
4161
+ var SIDEBAR_CONTENT_GAP = px(SIDEBAR_CONTENT_GAP_PX);
4162
+ var TOPBAR_GAP = px(TOPBAR_GAP_PX);
4163
+ var TOPBAR_HEIGHT = px(TOPBAR_HEIGHT_PX);
4164
+ var PILL_HEIGHT = px(PILL_HEIGHT_PX);
4165
+ var SIDEBAR_INSET_EXPANDED = px(SIDEBAR_INSET_PX_EXPANDED);
4166
+ var SIDEBAR_INSET_COLLAPSED = px(SIDEBAR_INSET_PX_COLLAPSED);
4167
+ var studioChromeShellStyle = {
4168
+ "--studio-topbar-gap": TOPBAR_GAP,
4169
+ "--studio-topbar-height": TOPBAR_HEIGHT,
4170
+ "--studio-chrome-pill-height": PILL_HEIGHT,
4171
+ "--studio-inset-top": `calc(${TOPBAR_GAP} + ${TOPBAR_HEIGHT})`,
4172
+ "--studio-sidebar-gap": SIDEBAR_GAP,
4173
+ "--studio-sidebar-width": SIDEBAR_WIDTH,
4174
+ "--studio-sidebar-width-collapsed": SIDEBAR_WIDTH_COLLAPSED,
4175
+ "--studio-sidebar-content-gap": SIDEBAR_CONTENT_GAP,
4176
+ "--studio-inset-left": SIDEBAR_INSET_EXPANDED,
4177
+ "--studio-inset-left-collapsed": SIDEBAR_INSET_COLLAPSED
4178
+ };
4179
+ var STORAGE_KEYS = {
4180
+ sidebarCollapsed: "timbal-studio-sidebar-collapsed"
4181
+ };
4182
+ var DOM_IDS = {
4183
+ sidebarRuntimeAnchor: "timbal-studio-sidebar-runtime-anchor",
4184
+ topbarBrandAnchor: "timbal-studio-topbar-brand-anchor"
4185
+ };
3433
4186
 
3434
- \`\`\`timbal-artifact
4187
+ // src/components/chat-shell.tsx
4188
+ var import_jsx_runtime30 = require("react/jsx-runtime");
4189
+ var TimbalChatShell = ({
4190
+ workforceId,
4191
+ brand,
4192
+ headerActions,
4193
+ hideWorkforceSelector,
4194
+ className,
4195
+ headerClassName,
4196
+ baseUrl,
4197
+ fetch: fetch2,
4198
+ ...chatProps
4199
+ }) => {
4200
+ const { workforces, selectedId, setSelectedId } = useWorkforces({
4201
+ baseUrl,
4202
+ fetch: fetch2
4203
+ });
4204
+ const effectiveId = workforceId ?? selectedId;
4205
+ const showSelector = !hideWorkforceSelector && !workforceId && workforces.length > 0;
4206
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
4207
+ "div",
4208
+ {
4209
+ className: cn(
4210
+ "aui-chat-shell relative flex h-dvh flex-col overflow-hidden bg-background",
4211
+ className
4212
+ ),
4213
+ style: studioChromeShellStyle,
4214
+ children: [
4215
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
4216
+ "div",
4217
+ {
4218
+ className: cn(
4219
+ "pointer-events-none absolute inset-0 z-0",
4220
+ studioPlaygroundGradientClass
4221
+ ),
4222
+ "aria-hidden": true
4223
+ }
4224
+ ),
4225
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
4226
+ "header",
4227
+ {
4228
+ className: cn(
4229
+ "aui-chat-shell-header relative z-10 flex shrink-0 items-center justify-between px-4 pt-[var(--studio-topbar-gap)] pb-2",
4230
+ headerClassName
4231
+ ),
4232
+ style: { minHeight: "var(--studio-topbar-height)" },
4233
+ children: [
4234
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex min-w-0 items-center gap-2", children: [
4235
+ brand,
4236
+ showSelector && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
4237
+ WorkforceSelector,
4238
+ {
4239
+ workforces,
4240
+ value: selectedId,
4241
+ onChange: setSelectedId
4242
+ }
4243
+ )
4244
+ ] }),
4245
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "flex shrink-0 items-center gap-1", children: headerActions })
4246
+ ]
4247
+ }
4248
+ ),
4249
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
4250
+ TimbalChat,
4251
+ {
4252
+ workforceId: effectiveId,
4253
+ baseUrl,
4254
+ fetch: fetch2,
4255
+ className: "relative z-10 min-h-0 flex-1 bg-transparent",
4256
+ ...chatProps
4257
+ },
4258
+ effectiveId
4259
+ )
4260
+ ]
4261
+ }
4262
+ );
4263
+ };
4264
+
4265
+ // src/components/studio/studio-shell.tsx
4266
+ var import_react41 = require("react");
4267
+ var import_lucide_react13 = require("lucide-react");
4268
+ var import_react42 = require("motion/react");
4269
+
4270
+ // src/design/sidebar-motion.ts
4271
+ var STUDIO_SIDEBAR_EASE_ENTER = [0, 0, 0.2, 1];
4272
+ var STUDIO_SIDEBAR_EASE_EXIT = [0.4, 0, 1, 1];
4273
+ var STUDIO_SIDEBAR_EASE = [0.16, 1, 0.3, 1];
4274
+ var STUDIO_SIDEBAR_ENTRIES_OUT_S = 0.1;
4275
+ var STUDIO_SIDEBAR_WIDTH_S = 0.17;
4276
+ var STUDIO_SIDEBAR_ENTRY_ITEM_IN_S = 0.18;
4277
+ var STUDIO_SIDEBAR_STAGGER_S = 0.03;
4278
+ var STUDIO_SIDEBAR_EXPAND_REVEAL_FRAC = 0.5;
4279
+ var STUDIO_SIDEBAR_CONTENT_NUDGE_PX = 6;
4280
+ var studioSidebarEntriesContainerVariants = {
4281
+ hidden: {
4282
+ opacity: 0,
4283
+ transition: {
4284
+ duration: STUDIO_SIDEBAR_ENTRIES_OUT_S,
4285
+ ease: STUDIO_SIDEBAR_EASE_EXIT,
4286
+ staggerChildren: 0
4287
+ }
4288
+ },
4289
+ visible: {
4290
+ opacity: 1,
4291
+ transition: {
4292
+ duration: 0.06,
4293
+ ease: STUDIO_SIDEBAR_EASE_ENTER,
4294
+ staggerChildren: STUDIO_SIDEBAR_STAGGER_S,
4295
+ delayChildren: 0.02
4296
+ }
4297
+ }
4298
+ };
4299
+ var studioSidebarEntryItemVariants = {
4300
+ hidden: {
4301
+ opacity: 0,
4302
+ x: -STUDIO_SIDEBAR_CONTENT_NUDGE_PX,
4303
+ scale: 0.99
4304
+ },
4305
+ visible: {
4306
+ opacity: 1,
4307
+ x: 0,
4308
+ scale: 1,
4309
+ transition: {
4310
+ duration: STUDIO_SIDEBAR_ENTRY_ITEM_IN_S,
4311
+ ease: STUDIO_SIDEBAR_EASE_ENTER
4312
+ }
4313
+ }
4314
+ };
4315
+ function studioSidebarEntriesTransition(visible, reduced) {
4316
+ if (reduced) return { duration: 0.01 };
4317
+ return visible ? { duration: 0.06, ease: STUDIO_SIDEBAR_EASE_ENTER } : { duration: STUDIO_SIDEBAR_ENTRIES_OUT_S, ease: STUDIO_SIDEBAR_EASE_EXIT };
4318
+ }
4319
+ function studioSidebarWidthTransition(reduced, direction = "collapse") {
4320
+ if (reduced) return { duration: 0.01 };
4321
+ return {
4322
+ duration: direction === "expand" ? STUDIO_SIDEBAR_WIDTH_S : STUDIO_SIDEBAR_WIDTH_S * 0.94,
4323
+ ease: direction === "expand" ? STUDIO_SIDEBAR_EASE_ENTER : STUDIO_SIDEBAR_EASE_EXIT
4324
+ };
4325
+ }
4326
+ function studioSidebarDrawerTransition(reduced) {
4327
+ if (reduced) return { duration: 0.01 };
4328
+ return {
4329
+ duration: 0.22,
4330
+ ease: STUDIO_SIDEBAR_EASE
4331
+ };
4332
+ }
4333
+ function studioSidebarBackdropTransition(reduced) {
4334
+ if (reduced) return { duration: 0.01 };
4335
+ return { duration: 0.16, ease: STUDIO_SIDEBAR_EASE_EXIT };
4336
+ }
4337
+
4338
+ // src/hooks/use-sidebar-collapse-phase.ts
4339
+ var import_react29 = require("react");
4340
+ var WIDTH_OVERLAP_FRAC = 0.7;
4341
+ function useSidebarCollapsePhase(collapsed, reducedMotion) {
4342
+ const [widthCollapsed, setWidthCollapsed] = (0, import_react29.useState)(collapsed);
4343
+ const [entriesVisible, setEntriesVisible] = (0, import_react29.useState)(true);
4344
+ const collapsedTarget = (0, import_react29.useRef)(collapsed);
4345
+ const isFirstRender = (0, import_react29.useRef)(true);
4346
+ const widthTimerRef = (0, import_react29.useRef)(null);
4347
+ const revealTimerRef = (0, import_react29.useRef)(null);
4348
+ (0, import_react29.useEffect)(() => {
4349
+ collapsedTarget.current = collapsed;
4350
+ }, [collapsed]);
4351
+ const clearWidthTimer = () => {
4352
+ if (widthTimerRef.current !== null) {
4353
+ clearTimeout(widthTimerRef.current);
4354
+ widthTimerRef.current = null;
4355
+ }
4356
+ };
4357
+ const clearRevealTimer = () => {
4358
+ if (revealTimerRef.current !== null) {
4359
+ clearTimeout(revealTimerRef.current);
4360
+ revealTimerRef.current = null;
4361
+ }
4362
+ };
4363
+ const applyWidthTarget = (0, import_react29.useCallback)(() => {
4364
+ const willExpand = !collapsedTarget.current;
4365
+ setWidthCollapsed(collapsedTarget.current);
4366
+ clearRevealTimer();
4367
+ if (willExpand && !reducedMotion) {
4368
+ revealTimerRef.current = setTimeout(
4369
+ () => setEntriesVisible(true),
4370
+ STUDIO_SIDEBAR_WIDTH_S * 1e3 * STUDIO_SIDEBAR_EXPAND_REVEAL_FRAC
4371
+ );
4372
+ }
4373
+ }, [reducedMotion]);
4374
+ (0, import_react29.useEffect)(() => {
4375
+ clearWidthTimer();
4376
+ clearRevealTimer();
4377
+ if (reducedMotion) {
4378
+ setWidthCollapsed(collapsed);
4379
+ setEntriesVisible(true);
4380
+ return;
4381
+ }
4382
+ if (isFirstRender.current) {
4383
+ isFirstRender.current = false;
4384
+ setWidthCollapsed(collapsed);
4385
+ setEntriesVisible(true);
4386
+ return;
4387
+ }
4388
+ setEntriesVisible(false);
4389
+ widthTimerRef.current = setTimeout(
4390
+ applyWidthTarget,
4391
+ STUDIO_SIDEBAR_ENTRIES_OUT_S * 1e3 * WIDTH_OVERLAP_FRAC
4392
+ );
4393
+ return () => {
4394
+ clearWidthTimer();
4395
+ clearRevealTimer();
4396
+ };
4397
+ }, [collapsed, reducedMotion, applyWidthTarget]);
4398
+ const onEntriesBlurOutComplete = (0, import_react29.useCallback)(() => {
4399
+ applyWidthTarget();
4400
+ }, [applyWidthTarget]);
4401
+ const onPanelWidthComplete = (0, import_react29.useCallback)(() => {
4402
+ clearRevealTimer();
4403
+ setEntriesVisible(true);
4404
+ }, []);
4405
+ const isCollapsedRail = widthCollapsed;
4406
+ return {
4407
+ widthCollapsed,
4408
+ isCollapsedRail,
4409
+ entriesVisible,
4410
+ onEntriesBlurOutComplete,
4411
+ onPanelWidthComplete
4412
+ };
4413
+ }
4414
+
4415
+ // src/components/studio/sidebar-backdrop.tsx
4416
+ var import_react30 = require("motion/react");
4417
+ var import_jsx_runtime31 = require("react/jsx-runtime");
4418
+ var StudioSidebarBackdrop = ({
4419
+ open,
4420
+ onClose
4421
+ }) => {
4422
+ const reducedMotion = (0, import_react30.useReducedMotion)();
4423
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_react30.AnimatePresence, { children: open ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
4424
+ import_react30.motion.button,
4425
+ {
4426
+ type: "button",
4427
+ className: "fixed inset-0 z-40 bg-foreground/30 backdrop-blur-[2px] md:hidden",
4428
+ "aria-label": "Close menu",
4429
+ initial: { opacity: 0 },
4430
+ animate: { opacity: 1 },
4431
+ exit: { opacity: 0 },
4432
+ transition: studioSidebarBackdropTransition(!!reducedMotion),
4433
+ onClick: onClose
4434
+ }
4435
+ ) : null });
4436
+ };
4437
+
4438
+ // src/components/studio/sidebar-context.tsx
4439
+ var import_react31 = require("react");
4440
+ var StudioSidebarContext = (0, import_react31.createContext)({
4441
+ collapsed: false,
4442
+ isMobile: false,
4443
+ isCollapsedRail: false,
4444
+ iconOnlyLayout: false
4445
+ });
4446
+ function useStudioSidebarLayout() {
4447
+ return (0, import_react31.useContext)(StudioSidebarContext);
4448
+ }
4449
+
4450
+ // src/components/studio/sidebar.tsx
4451
+ var import_react35 = require("react");
4452
+ var import_react36 = require("motion/react");
4453
+
4454
+ // src/components/studio/sidebar-entries.tsx
4455
+ var import_react32 = require("motion/react");
4456
+ var import_jsx_runtime32 = require("react/jsx-runtime");
4457
+ var StudioSidebarEntries = ({
4458
+ visible,
4459
+ onBlurOutComplete,
4460
+ children,
4461
+ className
4462
+ }) => {
4463
+ const reducedMotion = (0, import_react32.useReducedMotion)();
4464
+ if (reducedMotion) {
4465
+ return visible ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: cn("flex min-h-0 flex-1 flex-col", className), children }) : null;
4466
+ }
4467
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
4468
+ import_react32.motion.div,
4469
+ {
4470
+ className: cn("flex min-h-0 flex-1 flex-col", className),
4471
+ initial: false,
4472
+ variants: studioSidebarEntriesContainerVariants,
4473
+ animate: visible ? "visible" : "hidden",
4474
+ transition: studioSidebarEntriesTransition(visible, false),
4475
+ onAnimationComplete: (definition) => {
4476
+ if (definition === "hidden") {
4477
+ onBlurOutComplete();
4478
+ }
4479
+ },
4480
+ style: { pointerEvents: visible ? "auto" : "none" },
4481
+ "aria-hidden": !visible,
4482
+ children
4483
+ }
4484
+ );
4485
+ };
4486
+
4487
+ // src/components/studio/sidebar-footer.tsx
4488
+ var import_lucide_react10 = require("lucide-react");
4489
+
4490
+ // src/auth/provider.tsx
4491
+ var import_react33 = require("react");
4492
+ var import_jsx_runtime33 = require("react/jsx-runtime");
4493
+ function isInsideIframe() {
4494
+ try {
4495
+ return typeof window !== "undefined" && window.self !== window.top;
4496
+ } catch {
4497
+ return true;
4498
+ }
4499
+ }
4500
+ var SessionContext = (0, import_react33.createContext)(void 0);
4501
+ var useSession = () => {
4502
+ const context = (0, import_react33.useContext)(SessionContext);
4503
+ if (context === void 0) {
4504
+ throw new Error("useSession must be used within a SessionProvider");
4505
+ }
4506
+ return context;
4507
+ };
4508
+ var useOptionalSession = () => {
4509
+ const context = (0, import_react33.useContext)(SessionContext);
4510
+ return context ?? null;
4511
+ };
4512
+ var SessionProvider = ({
4513
+ children,
4514
+ enabled = true
4515
+ }) => {
4516
+ const [user, setUser] = (0, import_react33.useState)(null);
4517
+ const [loading, setLoading] = (0, import_react33.useState)(enabled);
4518
+ const [embedded] = (0, import_react33.useState)(isInsideIframe);
4519
+ (0, import_react33.useEffect)(() => {
4520
+ if (!enabled) {
4521
+ setLoading(false);
4522
+ return;
4523
+ }
4524
+ let ignore = false;
4525
+ const restoreSession = async () => {
4526
+ try {
4527
+ const u = await fetchCurrentUser();
4528
+ if (ignore) return;
4529
+ if (u) {
4530
+ setUser(u);
4531
+ setLoading(false);
4532
+ return;
4533
+ }
4534
+ if (getRefreshToken()) {
4535
+ const ok = await refreshAccessToken();
4536
+ if (ignore) return;
4537
+ if (ok) {
4538
+ const refreshedUser = await fetchCurrentUser();
4539
+ if (ignore) return;
4540
+ if (refreshedUser) {
4541
+ setUser(refreshedUser);
4542
+ setLoading(false);
4543
+ return;
4544
+ }
4545
+ }
4546
+ }
4547
+ } catch {
4548
+ if (ignore) return;
4549
+ clearTokens();
4550
+ }
4551
+ if (!ignore && !embedded) {
4552
+ setLoading(false);
4553
+ }
4554
+ };
4555
+ restoreSession();
4556
+ let messageCleanup;
4557
+ if (embedded) {
4558
+ const handleMessage = async (event) => {
4559
+ if (ignore) return;
4560
+ if (event.data?.type !== "timbal:auth" || !event.data.token) return;
4561
+ setAccessToken(event.data.token);
4562
+ if (event.data.refreshToken) {
4563
+ setRefreshToken(event.data.refreshToken);
4564
+ }
4565
+ const u = await fetchCurrentUser();
4566
+ if (!ignore) {
4567
+ setUser(u);
4568
+ setLoading(false);
4569
+ }
4570
+ };
4571
+ window.addEventListener("message", handleMessage);
4572
+ window.parent.postMessage({ type: "timbal:request-session" }, "*");
4573
+ messageCleanup = () => window.removeEventListener("message", handleMessage);
4574
+ }
4575
+ return () => {
4576
+ ignore = true;
4577
+ messageCleanup?.();
4578
+ };
4579
+ }, [enabled, embedded]);
4580
+ const logout = (0, import_react33.useCallback)(() => {
4581
+ clearTokens();
4582
+ setUser(null);
4583
+ const returnTo = encodeURIComponent(
4584
+ window.location.pathname + window.location.search
4585
+ );
4586
+ fetch("/api/auth/logout", { method: "POST" }).finally(
4587
+ () => window.location.href = `/api/auth/login?return_to=${returnTo}`
4588
+ );
4589
+ }, []);
4590
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
4591
+ SessionContext.Provider,
4592
+ {
4593
+ value: {
4594
+ user,
4595
+ loading,
4596
+ isAuthenticated: !!user,
4597
+ isEmbedded: embedded,
4598
+ logout
4599
+ },
4600
+ children
4601
+ }
4602
+ );
4603
+ };
4604
+
4605
+ // src/components/studio/sidebar-layout.ts
4606
+ function studioSidebarIconOnlyLayout(isMobile, isCollapsedRail) {
4607
+ if (isMobile) return false;
4608
+ return isCollapsedRail;
4609
+ }
4610
+ var studioSidebarCollapsedRailInsetClass = "box-border w-full px-1.5";
4611
+ var studioSidebarCollapsedRailChipRowClass = "flex w-full justify-center";
4612
+ function studioSidebarNavItemClasses(iconOnly, isActive) {
4613
+ if (iconOnly) {
4614
+ return cn(
4615
+ studioSidebarNavItemClass,
4616
+ studioSidebarNavItemLayout(true),
4617
+ isActive ? studioSidebarCollapsedRailItemActiveClass : studioSidebarCollapsedRailItemIdleClass
4618
+ );
4619
+ }
4620
+ return cn(
4621
+ studioSidebarNavItemClass,
4622
+ studioSidebarNavItemLayout(false),
4623
+ isActive ? studioSidebarNavItemActiveClass : studioSidebarNavItemIdleClass
4624
+ );
4625
+ }
4626
+
4627
+ // src/components/studio/sidebar-entry-motion.tsx
4628
+ var import_react34 = require("motion/react");
4629
+ var import_jsx_runtime34 = require("react/jsx-runtime");
4630
+ var StudioSidebarEntryMotion = ({
4631
+ children,
4632
+ className
4633
+ }) => {
4634
+ const reducedMotion = (0, import_react34.useReducedMotion)();
4635
+ if (reducedMotion) {
4636
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className, children });
4637
+ }
4638
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_react34.motion.div, { variants: studioSidebarEntryItemVariants, className: cn(className), children });
4639
+ };
4640
+
4641
+ // src/components/studio/sidebar-tooltip.tsx
4642
+ var import_jsx_runtime35 = require("react/jsx-runtime");
4643
+ var StudioSidebarTooltip = ({
4644
+ label,
4645
+ enabled,
4646
+ children
4647
+ }) => {
4648
+ if (!enabled) return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_jsx_runtime35.Fragment, { children });
4649
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Tooltip, { children: [
4650
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TooltipTrigger, { asChild: true, children }),
4651
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TooltipContent, { side: "right", className: "text-xs", children: label })
4652
+ ] });
4653
+ };
4654
+
4655
+ // src/components/studio/sidebar-footer.tsx
4656
+ var import_jsx_runtime36 = require("react/jsx-runtime");
4657
+ function userInitials(name, email) {
4658
+ const fromName = name.trim().split(/\s+/).map((part) => part.charAt(0)).join("").slice(0, 2).toUpperCase();
4659
+ if (fromName) return fromName;
4660
+ return email.charAt(0).toUpperCase() || "?";
4661
+ }
4662
+ var StudioSidebarFooter = ({
4663
+ iconOnlyLayout,
4664
+ showTooltips,
4665
+ onSignOut,
4666
+ emptyCaption = null
4667
+ }) => {
4668
+ const session = useOptionalSession();
4669
+ const user = session?.user ?? null;
4670
+ const handleSignOut = () => {
4671
+ session?.logout();
4672
+ onSignOut?.();
4673
+ };
4674
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(StudioSidebarEntryMotion, { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
4675
+ "footer",
4676
+ {
4677
+ className: cn(
4678
+ "mt-auto w-full shrink-0 py-2.5",
4679
+ iconOnlyLayout ? studioSidebarCollapsedRailInsetClass : "px-2.5"
4680
+ ),
4681
+ children: user ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex flex-col gap-2", children: [
4682
+ iconOnlyLayout ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: studioSidebarCollapsedRailChipRowClass, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(Avatar, { size: "sm", className: "size-8", children: [
4683
+ user.user_photo_url ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AvatarImage, { src: user.user_photo_url, alt: user.user_name }) : null,
4684
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AvatarFallback, { className: "text-[10px]", children: userInitials(user.user_name, user.user_email) })
4685
+ ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex min-w-0 items-center gap-2.5", children: [
4686
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(Avatar, { size: "sm", children: [
4687
+ user.user_photo_url ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AvatarImage, { src: user.user_photo_url, alt: user.user_name }) : null,
4688
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AvatarFallback, { children: userInitials(user.user_name, user.user_email) })
4689
+ ] }),
4690
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "min-w-0 flex-1", children: [
4691
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "truncate text-sm font-medium text-foreground", children: user.user_name }),
4692
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "truncate text-xs text-muted-foreground", children: user.user_email })
4693
+ ] })
4694
+ ] }),
4695
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
4696
+ "div",
4697
+ {
4698
+ className: iconOnlyLayout ? studioSidebarCollapsedRailChipRowClass : void 0,
4699
+ children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(StudioSidebarTooltip, { label: "Sign out", enabled: showTooltips, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
4700
+ "button",
4701
+ {
4702
+ type: "button",
4703
+ onClick: handleSignOut,
4704
+ className: cn(
4705
+ studioSidebarNavItemClasses(iconOnlyLayout, false),
4706
+ iconOnlyLayout && "inline-flex"
4707
+ ),
4708
+ "aria-label": "Sign out",
4709
+ children: [
4710
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react10.LogOut, { className: "size-3.5 shrink-0" }),
4711
+ !iconOnlyLayout ? "Sign out" : null
4712
+ ]
4713
+ }
4714
+ ) })
4715
+ }
4716
+ )
4717
+ ] }) : !iconOnlyLayout && emptyCaption ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "px-1 text-xs text-muted-foreground", children: emptyCaption }) : null
4718
+ }
4719
+ ) });
4720
+ };
4721
+
4722
+ // src/components/studio/sidebar-header.tsx
4723
+ var import_lucide_react11 = require("lucide-react");
4724
+ var import_jsx_runtime37 = require("react/jsx-runtime");
4725
+ var sidebarHeaderClass = "flex h-12 shrink-0 items-center px-2";
4726
+ var toggleButtonClass = cn(
4727
+ "flex shrink-0 items-center justify-center rounded-lg text-muted-foreground transition-colors",
4728
+ "hover:bg-muted hover:text-foreground",
4729
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15"
4730
+ );
4731
+ var SidebarToggleButton = ({ ariaLabel, expanded, onClick, children }) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
4732
+ "button",
4733
+ {
4734
+ type: "button",
4735
+ onClick,
4736
+ className: cn(toggleButtonClass, "size-7"),
4737
+ "aria-label": ariaLabel,
4738
+ "aria-expanded": expanded,
4739
+ children
4740
+ }
4741
+ );
4742
+ var CollapsedBrandToggle = ({
4743
+ onExpand,
4744
+ brand
4745
+ }) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: studioSidebarCollapsedRailChipRowClass, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(StudioSidebarTooltip, { label: "Expand sidebar", enabled: true, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
4746
+ "button",
4747
+ {
4748
+ type: "button",
4749
+ onClick: onExpand,
4750
+ "aria-label": "Expand sidebar",
4751
+ "aria-expanded": false,
4752
+ className: cn(
4753
+ toggleButtonClass,
4754
+ "group relative inline-flex size-8 items-center justify-center overflow-hidden rounded-lg"
4755
+ ),
4756
+ children: [
4757
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
4758
+ "span",
4759
+ {
4760
+ "aria-hidden": true,
4761
+ className: cn(
4762
+ "pointer-events-none flex items-center justify-center",
4763
+ "transition-[opacity,transform] duration-200 ease-out",
4764
+ "group-hover:scale-90 group-hover:opacity-0"
4765
+ ),
4766
+ children: brand
4767
+ }
4768
+ ),
4769
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
4770
+ import_lucide_react11.ChevronRight,
4771
+ {
4772
+ "aria-hidden": true,
4773
+ className: cn(
4774
+ "pointer-events-none absolute inset-0 m-auto size-4",
4775
+ "opacity-0 transition-[opacity,transform] duration-200 ease-out",
4776
+ "group-hover:opacity-100"
4777
+ )
4778
+ }
4779
+ )
4780
+ ]
4781
+ }
4782
+ ) }) });
4783
+ var StudioSidebarHeader = ({
4784
+ isCollapsedRail,
4785
+ isMobile,
4786
+ mobileOpen,
4787
+ onToggle,
4788
+ brand
4789
+ }) => {
4790
+ if (isMobile) {
4791
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("header", { className: cn(sidebarHeaderClass, "justify-between gap-2 pr-2"), children: [
4792
+ brand,
4793
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
4794
+ SidebarToggleButton,
4795
+ {
4796
+ ariaLabel: "Close menu",
4797
+ expanded: mobileOpen,
4798
+ onClick: onToggle,
4799
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react11.X, { className: "size-3.5" })
4800
+ }
4801
+ )
4802
+ ] });
4803
+ }
4804
+ if (isCollapsedRail) {
4805
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
4806
+ "header",
4807
+ {
4808
+ className: cn(
4809
+ "flex h-12 shrink-0 items-center",
4810
+ studioSidebarCollapsedRailInsetClass
4811
+ ),
4812
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(CollapsedBrandToggle, { onExpand: onToggle, brand })
4813
+ }
4814
+ );
4815
+ }
4816
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("header", { className: cn(sidebarHeaderClass, "justify-between gap-1 pr-2"), children: [
4817
+ brand,
4818
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
4819
+ SidebarToggleButton,
4820
+ {
4821
+ ariaLabel: "Collapse sidebar",
4822
+ expanded: true,
4823
+ onClick: onToggle,
4824
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react11.ChevronLeft, { className: "size-4" })
4825
+ }
4826
+ )
4827
+ ] });
4828
+ };
4829
+
4830
+ // src/components/studio/sidebar-workforce.ts
4831
+ function workforceItemId(w) {
4832
+ return w.id ?? w.uid ?? w.name ?? "";
4833
+ }
4834
+ function workforceItemLabel(w) {
4835
+ return w.name ?? workforceItemId(w);
4836
+ }
4837
+ function workforceItemInitial(w) {
4838
+ const label = workforceItemLabel(w);
4839
+ return label.charAt(0).toUpperCase() || "?";
4840
+ }
4841
+
4842
+ // src/components/studio/sidebar-nav.tsx
4843
+ var import_jsx_runtime38 = require("react/jsx-runtime");
4844
+ var StudioSidebarNav = ({
4845
+ workforces,
4846
+ selectedId,
4847
+ onSelect,
4848
+ iconOnlyLayout,
4849
+ showTooltips
4850
+ }) => {
4851
+ if (workforces.length === 0) return null;
4852
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
4853
+ "nav",
4854
+ {
4855
+ className: cn(
4856
+ "flex min-h-0 flex-1 flex-col overflow-y-auto py-1",
4857
+ iconOnlyLayout ? cn(studioSidebarCollapsedRailInsetClass, "gap-1") : "gap-0.5 px-2"
4858
+ ),
4859
+ "aria-label": "Agents",
4860
+ children: workforces.map((w) => {
4861
+ const id = workforceItemId(w);
4862
+ const isActive = id === selectedId;
4863
+ const label = workforceItemLabel(w);
4864
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
4865
+ StudioSidebarEntryMotion,
4866
+ {
4867
+ className: iconOnlyLayout ? studioSidebarCollapsedRailChipRowClass : void 0,
4868
+ children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(StudioSidebarTooltip, { label, enabled: showTooltips, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
4869
+ "button",
4870
+ {
4871
+ type: "button",
4872
+ onClick: () => onSelect(id),
4873
+ "aria-pressed": isActive,
4874
+ "aria-label": label,
4875
+ className: cn(
4876
+ studioSidebarNavItemClasses(iconOnlyLayout, isActive),
4877
+ iconOnlyLayout && "inline-flex"
4878
+ ),
4879
+ children: iconOnlyLayout ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-xs font-semibold leading-none", children: workforceItemInitial(w) }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "min-w-0 truncate", children: label })
4880
+ }
4881
+ ) })
4882
+ },
4883
+ id
4884
+ );
4885
+ })
4886
+ }
4887
+ );
4888
+ };
4889
+
4890
+ // src/components/studio/timbal-mark.tsx
4891
+ var import_shaders_react = require("@paper-design/shaders-react");
4892
+ var import_jsx_runtime39 = require("react/jsx-runtime");
4893
+ var DEFAULT_SIZE = 64;
4894
+ var TRANSPARENT_BACK = "#00000000";
4895
+ var TIMBAL_SYMBOL_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAACWCAYAAAA8AXHiAAAH6ElEQVR4Aeyci7EcNRBFFxIBIgEygUiASCATyASIBOa4rFrZntmPPq1W93218o5nZyTd26dbmnX5fX3TjxyY4IDAmmCqurzdBJYomOKAwJpiqzoVWGJgigMCa4qt6lRgZWHAWKfAMjY8y3ACK0ukjXUKLGPDswwnsLJE2linwDI2PMtwAitLpI11Cixjw+/DxT4SWLHju0ydwHrP+p/euzzE1T8cKr492lsvgfWaXZj733Hp90fL9Pr1EPvn0QTWYcLoF8bS6Pdf/kjQAAnNv7RqVcW6do4q9ffxMe/HW5oXy323boF1zkvzEnDe3RZnS5X6fcRsBdbdRY6oTl1LAJ1s2NDdXaVq3QLr7kapUph8Pxv/iESiDVUqsG63sgQ0b1Rve/6QQEOrVG1DdrCGbFRrQzc5Zh9FlSKppkw5M1gYi8FTjHXaaalSJNTUKWYEC3P5spP3qeY667zsIadVqVpvNrCoUrTag+jHgIRm0z2ka7AGRpzqNG2jOnCeo7uiSi3RnQEszCVjydzRgfPaH1rRbFqlajMig0WVWmpubbThMRvzJVWq1hgVrFKlgKvWG/2YRHLxpBsNrOVLwCJySSBXT7qRwHKxBCwAiypFWzD09ZARwCpVysUScG318E+oUsv3Uleq3gPrqpd1512bO9GWsockqSYO0971zmBR/mnt6ve7k0RC87KvEV61bEewMNftEvCq8Q3XlSqF/obbbW/ZDSz2UWSs2yVgQvjQimb3VarWvgtYZCnm8uRXzz/6MXq3rM47gLXVEjCI9FKlqNCDurTtxjNYxdytloAB4aM6r65S3TK8grXtEtAZEZZ7Wmc362/3BlapUtsuAY0hDVGlau2ewApnbm30g+OyhySpHly210dewKL80/Zyr2+2JBKaQ+4hV4OFudtvVBv4KlUK/Q23+79lJVjso8jYUEvAk5CjFc0hq1StfQVYZCnm8uRXzyX6MXqbq/Nu5liDFX4JOAGgVCkq9MnHMU9ZgVXMDb8EfIYJ1TlNlaq1W4BFlcpoLss9rfY7zfFMsFSl0mD0pdBZYKXaqFa2so+iSpFU1el8hzPAwlgMzuQmeyl0k1ARdf/zrqiRYGGuq/+C9K4Zb11/v5g9JFCh/342+dEosDCWlslOljs0Z3vSfSnGvWCRpRmf+KhSGXW/BBUX9YCFuWQsmUtfGdo3h0g0q0odRjx6tYAFSFnNZXNOlX7kqT47HGgB67jtJnNv+nnkQCtYj/rUZ3LgFggsRdOTAwLLUzQCzUVgBQqmJykCy1M0As1FYAUKpicpAstTNALNRWAFCqYnKTPB8qRTczF2QGAZG55lOIGVJdLGOgWWseFZhhNYWSJtrFNgGRueZTiBlSXSM3We9C2wTkzRqX4HBFa/h+rhxAGBdWKKTvU7ILD6PVQPJw4IrBNTdKrfAYHV76F6OHFAYJ2Ysv+p9QoE1voYhJyBwAoZ1vWiBNb6GIScgcAKGdb1ogTW+hiEnIHAChnW9aIElk0M0o0isNKF3EawwLLxOd0oAitdyN8W/Ndxx9LfmnyMH/aFuX+EVXct7Lfjox+P9vZLFeu5ZcXcf59fGuYKKhRA8Xtmm0QJrGvbqFJd5l537foTKvN3xwzRf7y1vdKC9cSuUqW6zH0yhsePSaSfR0xMYH3qYvcS8Gl32/yNBPrqmC3vx1v/S2DdPRyyBNy72+aIKkUbOuEWsPg970MnsbizUqWGLAGLtbwzPNWpey91NWALWFd97Xh+qrmODSl7SJJqyjQzg0X5p00x1mmnJBKam79GeFVXRrAwd9oS8KrxC64rVQr904f3A9Z0qR8GYB9Fxk5bAj6M4usPtKJ5epWqZWcBiyzFXJ78av3Rj9G7pDpnAMt0CXBCaqlSVOglU4oMVjHXdAlYEsVPB6U6L6lS9TSigkWVWm5ubbTRMcs9zWi462GigaUqdR1r008igbVso2oasS8HYx9FlSKpvvx00ZkHYC2aUduwGIvBbXfveRd7KXSTUO4U7A4W5g79V3l3ETqfEHtIoEL/+RWLz+4MFsbSFltoOjzLHZrdP+nuCBZZmvGJjyVvG927gVWWADLXtFQsHAytVKmt9pC7gEWVwlz3S8BgANG9TZWqte8AVqlSmFzPPfoxiUSbrnPGAJ7BKkuAqtSMyE/u0ytYW21UB8aIfRRViqQa2K19Vx7BwlgMtndj3Ygs8+gmodbNYuDInsDCXH3ZOTC4K7vyAhbZSlvphfXYLHdoDrmHXA0WVWrLx+lOCnnSDa17JViYS8aSuZ1x2uZ2tKL5cZXaRs71RFeARZVKYe5ntrMxD12lar3WYJUqBVz1PKIfk0ipnnStwEqzBHyWISRQxifdmwVYqZaACiyqFK06ledwJlilSqVaAg50qFJp9lKH3tPXLLCymlv2kCTVqeFZTs4Ai/JPC+ThUykkEprDf43w1ImPF4wEC3MzLgGlSqH/o616GwUW+ygyNtMSgFY0q0qd5FEvWGQp5vLkd9J92FPozVidXw5oD1hZlwASiQr9sskZL2wBK+sSgO6UX3a2JEYrWCyBLePtfA/L387zN517C1imE7wYTKedOyCwnAdo1+kJrF0j53zeAst5gHadnsDaNXLO5y2wnAdo1+kJrF0j53zew8ByrlPTM3ZAYBkbnmU4gZUl0sY6BZax4VmGE1hZIm2sU2AZG55lOIGVJdLDdL7W0f8AAAD//x3VUCQAAAAGSURBVAMArsj7LTb9pqMAAAAASUVORK5CYII=";
4896
+ function TimbalMark({
4897
+ className,
4898
+ size = DEFAULT_SIZE,
4899
+ src = TIMBAL_SYMBOL_DATA_URI
4900
+ }) {
4901
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
4902
+ "div",
4903
+ {
4904
+ className: cn("relative shrink-0 bg-transparent", className),
4905
+ style: { width: size, height: size },
4906
+ role: "img",
4907
+ "aria-label": "Timbal",
4908
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
4909
+ import_shaders_react.LiquidMetal,
4910
+ {
4911
+ width: size,
4912
+ height: size,
4913
+ image: src,
4914
+ colorBack: TRANSPARENT_BACK,
4915
+ colorTint: "#ffffff",
4916
+ shape: "none",
4917
+ repetition: 2,
4918
+ softness: 0.1,
4919
+ shiftRed: 0.3,
4920
+ shiftBlue: 0.3,
4921
+ distortion: 0.07,
4922
+ contour: 0.4,
4923
+ angle: 70,
4924
+ speed: 1,
4925
+ scale: 0.6,
4926
+ fit: "contain",
4927
+ className: "size-full bg-transparent",
4928
+ style: { background: "transparent" },
4929
+ webGlContextAttributes: {
4930
+ alpha: true,
4931
+ premultipliedAlpha: false
4932
+ }
4933
+ }
4934
+ )
4935
+ }
4936
+ );
4937
+ }
4938
+
4939
+ // src/components/studio/sidebar.tsx
4940
+ var import_jsx_runtime40 = require("react/jsx-runtime");
4941
+ var DEFAULT_BREAKPOINT_PX = 768;
4942
+ function readPersistedCollapsed(key) {
4943
+ if (!key || typeof window === "undefined") return false;
4944
+ try {
4945
+ return window.localStorage.getItem(key) === "1";
4946
+ } catch {
4947
+ return false;
4948
+ }
4949
+ }
4950
+ function writePersistedCollapsed(key, collapsed) {
4951
+ if (!key || typeof window === "undefined") return;
4952
+ try {
4953
+ window.localStorage.setItem(key, collapsed ? "1" : "0");
4954
+ } catch {
4955
+ }
4956
+ }
4957
+ var StudioSidebarPanel = ({
4958
+ workforces,
4959
+ selectedId,
4960
+ onSelect,
4961
+ collapsed,
4962
+ onCollapsedChange,
4963
+ isMobile,
4964
+ mobileOpen,
4965
+ onMobileOpenChange,
4966
+ widthCollapsed,
4967
+ entriesVisible,
4968
+ onEntriesBlurOutComplete,
4969
+ onPanelWidthComplete,
4970
+ brand,
4971
+ emptyCaption = null
4972
+ }) => {
4973
+ const reducedMotion = (0, import_react36.useReducedMotion)();
4974
+ const isCollapsedRail = widthCollapsed && !isMobile;
4975
+ const iconOnlyLayout = studioSidebarIconOnlyLayout(isMobile, isCollapsedRail);
4976
+ const isDrawerOpen = isMobile && mobileOpen;
4977
+ const widthDirection = widthCollapsed ? "collapse" : "expand";
4978
+ const widthTransition = studioSidebarWidthTransition(
4979
+ !!reducedMotion,
4980
+ widthDirection
4981
+ );
4982
+ const handleToggle = () => {
4983
+ if (isMobile) {
4984
+ onMobileOpenChange(false);
4985
+ return;
4986
+ }
4987
+ onCollapsedChange(!collapsed);
4988
+ };
4989
+ const panelWidthPx = isMobile ? SIDEBAR_MOBILE_PX : widthCollapsed ? SIDEBAR_WIDTH_COLLAPSED_PX : SIDEBAR_WIDTH_PX;
4990
+ const brandNode = brand ?? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(TimbalMark, { size: 32 });
4991
+ const panel = /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
4992
+ import_react36.motion.div,
4993
+ {
4994
+ "data-sidebar-collapsed": isCollapsedRail ? "" : void 0,
4995
+ className: cn(
4996
+ "flex h-full flex-col overflow-hidden",
4997
+ studioSidebarPanelClass,
4998
+ isMobile ? "rounded-none rounded-r-2xl" : "rounded-2xl"
4999
+ ),
5000
+ initial: false,
5001
+ animate: { width: panelWidthPx },
5002
+ transition: widthTransition,
5003
+ style: { willChange: entriesVisible ? void 0 : "width" },
5004
+ onAnimationComplete: isMobile || entriesVisible ? void 0 : () => onPanelWidthComplete(),
5005
+ children: [
5006
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
5007
+ StudioSidebarHeader,
5008
+ {
5009
+ isCollapsedRail,
5010
+ isMobile,
5011
+ mobileOpen,
5012
+ onToggle: handleToggle,
5013
+ brand: brandNode
5014
+ }
5015
+ ),
5016
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
5017
+ StudioSidebarEntries,
5018
+ {
5019
+ visible: entriesVisible,
5020
+ onBlurOutComplete: onEntriesBlurOutComplete,
5021
+ children: [
5022
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
5023
+ "div",
5024
+ {
5025
+ id: DOM_IDS.sidebarRuntimeAnchor,
5026
+ className: cn(
5027
+ "min-h-0 shrink-0 empty:hidden",
5028
+ iconOnlyLayout ? "px-1.5 pt-1.5" : "px-2 pt-1.5"
5029
+ )
5030
+ }
5031
+ ),
5032
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
5033
+ StudioSidebarNav,
5034
+ {
5035
+ workforces,
5036
+ selectedId,
5037
+ onSelect,
5038
+ iconOnlyLayout,
5039
+ showTooltips: isCollapsedRail
5040
+ }
5041
+ ),
5042
+ workforces.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "min-h-0 flex-1" }) : null,
5043
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
5044
+ StudioSidebarFooter,
5045
+ {
5046
+ iconOnlyLayout,
5047
+ showTooltips: isCollapsedRail,
5048
+ onSignOut: isMobile ? () => onMobileOpenChange(false) : void 0,
5049
+ emptyCaption
5050
+ }
5051
+ )
5052
+ ]
5053
+ }
5054
+ )
5055
+ ]
5056
+ }
5057
+ );
5058
+ if (isMobile) {
5059
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
5060
+ import_react36.motion.aside,
5061
+ {
5062
+ className: "fixed inset-y-0 left-0 z-[60] flex",
5063
+ "aria-label": "Studio navigation",
5064
+ "aria-hidden": !mobileOpen,
5065
+ initial: false,
5066
+ animate: {
5067
+ x: isDrawerOpen ? 0 : -(SIDEBAR_MOBILE_PX + 32)
5068
+ },
5069
+ transition: studioSidebarDrawerTransition(!!reducedMotion),
5070
+ style: { pointerEvents: isDrawerOpen ? "auto" : "none" },
5071
+ children: panel
5072
+ }
5073
+ );
5074
+ }
5075
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
5076
+ "aside",
5077
+ {
5078
+ className: "absolute inset-y-0 left-0 z-[60] flex py-[var(--studio-sidebar-gap)] pl-[var(--studio-sidebar-gap)]",
5079
+ "aria-label": "Studio navigation",
5080
+ children: panel
5081
+ }
5082
+ );
5083
+ };
5084
+ var StudioSidebar = ({
5085
+ workforces: workforcesProp,
5086
+ selectedId: selectedIdProp,
5087
+ onSelect,
5088
+ defaultCollapsed = false,
5089
+ persistKey = STORAGE_KEYS.sidebarCollapsed,
5090
+ mobileBreakpointPx = DEFAULT_BREAKPOINT_PX,
5091
+ brand,
5092
+ emptyCaption,
5093
+ mobileOpen: mobileOpenProp,
5094
+ onMobileOpenChange: onMobileOpenChangeProp
5095
+ }) => {
5096
+ const reducedMotion = (0, import_react36.useReducedMotion)();
5097
+ const fetched = useWorkforces({ enabled: workforcesProp === void 0 });
5098
+ const workforces = workforcesProp ?? fetched.workforces;
5099
+ const [internalSelected, setInternalSelected] = (0, import_react35.useState)(
5100
+ selectedIdProp ?? ""
5101
+ );
5102
+ (0, import_react35.useEffect)(() => {
5103
+ if (selectedIdProp !== void 0) return;
5104
+ if (internalSelected) return;
5105
+ const first = workforces[0]?.id ?? workforces[0]?.uid ?? workforces[0]?.name;
5106
+ if (first) setInternalSelected(first);
5107
+ }, [workforces, selectedIdProp, internalSelected]);
5108
+ const selectedId = selectedIdProp ?? internalSelected ?? workforces[0]?.id ?? workforces[0]?.uid ?? workforces[0]?.name ?? "";
5109
+ const handleSelect = (0, import_react35.useCallback)(
5110
+ (id) => {
5111
+ if (selectedIdProp === void 0) setInternalSelected(id);
5112
+ onSelect?.(id);
5113
+ },
5114
+ [selectedIdProp, onSelect]
5115
+ );
5116
+ const [collapsed, setCollapsed] = (0, import_react35.useState)(() => {
5117
+ const persisted = readPersistedCollapsed(persistKey);
5118
+ return persisted || defaultCollapsed;
5119
+ });
5120
+ const handleCollapsedChange = (0, import_react35.useCallback)(
5121
+ (next) => {
5122
+ setCollapsed(next);
5123
+ writePersistedCollapsed(persistKey, next);
5124
+ },
5125
+ [persistKey]
5126
+ );
5127
+ const [isMobile, setIsMobile] = (0, import_react35.useState)(() => {
5128
+ if (typeof window === "undefined") return false;
5129
+ return window.innerWidth < mobileBreakpointPx;
5130
+ });
5131
+ (0, import_react35.useEffect)(() => {
5132
+ if (typeof window === "undefined") return;
5133
+ const onResize = () => setIsMobile(window.innerWidth < mobileBreakpointPx);
5134
+ onResize();
5135
+ window.addEventListener("resize", onResize);
5136
+ return () => window.removeEventListener("resize", onResize);
5137
+ }, [mobileBreakpointPx]);
5138
+ const [internalMobileOpen, setInternalMobileOpen] = (0, import_react35.useState)(false);
5139
+ const mobileOpen = mobileOpenProp ?? internalMobileOpen;
5140
+ const setMobileOpen = (0, import_react35.useCallback)(
5141
+ (next) => {
5142
+ if (mobileOpenProp === void 0) setInternalMobileOpen(next);
5143
+ onMobileOpenChangeProp?.(next);
5144
+ },
5145
+ [mobileOpenProp, onMobileOpenChangeProp]
5146
+ );
5147
+ const effectiveCollapsed = isMobile ? false : collapsed;
5148
+ const {
5149
+ widthCollapsed,
5150
+ entriesVisible: phaseEntriesVisible,
5151
+ onEntriesBlurOutComplete,
5152
+ onPanelWidthComplete
5153
+ } = useSidebarCollapsePhase(effectiveCollapsed, !!reducedMotion);
5154
+ const entriesVisible = isMobile || phaseEntriesVisible;
5155
+ const isCollapsedRail = widthCollapsed && !isMobile;
5156
+ const iconOnlyLayout = studioSidebarIconOnlyLayout(isMobile, isCollapsedRail);
5157
+ const contextValue = (0, import_react35.useMemo)(
5158
+ () => ({
5159
+ collapsed: effectiveCollapsed,
5160
+ isMobile,
5161
+ isCollapsedRail,
5162
+ iconOnlyLayout
5163
+ }),
5164
+ [effectiveCollapsed, isMobile, isCollapsedRail, iconOnlyLayout]
5165
+ );
5166
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(StudioSidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
5167
+ StudioSidebarPanel,
5168
+ {
5169
+ workforces,
5170
+ selectedId,
5171
+ onSelect: handleSelect,
5172
+ collapsed: effectiveCollapsed,
5173
+ onCollapsedChange: handleCollapsedChange,
5174
+ isMobile,
5175
+ mobileOpen,
5176
+ onMobileOpenChange: setMobileOpen,
5177
+ widthCollapsed,
5178
+ entriesVisible,
5179
+ onEntriesBlurOutComplete,
5180
+ onPanelWidthComplete,
5181
+ brand,
5182
+ emptyCaption
5183
+ }
5184
+ ) });
5185
+ };
5186
+
5187
+ // src/components/studio/sidebar-runtime-portal.tsx
5188
+ var import_react37 = require("react");
5189
+ var import_react_dom = require("react-dom");
5190
+ var import_lucide_react12 = require("lucide-react");
5191
+ var import_react38 = require("@assistant-ui/react");
5192
+ var import_jsx_runtime41 = require("react/jsx-runtime");
5193
+ var StudioSidebarRuntimePortal = ({
5194
+ label = "New chat"
5195
+ }) => {
5196
+ const { iconOnlyLayout } = useStudioSidebarLayout();
5197
+ const hasMessages = (0, import_react38.useThread)((s) => s.messages.length > 0);
5198
+ const { clear } = useTimbalRuntime();
5199
+ const [anchor, setAnchor] = (0, import_react37.useState)(null);
5200
+ const startNewChat = (0, import_react37.useCallback)(() => {
5201
+ clear();
5202
+ }, [clear]);
5203
+ (0, import_react37.useLayoutEffect)(() => {
5204
+ setAnchor(document.getElementById(DOM_IDS.sidebarRuntimeAnchor));
5205
+ }, []);
5206
+ if (!anchor || !hasMessages) return null;
5207
+ const button = /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
5208
+ "button",
5209
+ {
5210
+ type: "button",
5211
+ onClick: startNewChat,
5212
+ "aria-label": label,
5213
+ className: studioSidebarNavItemClasses(iconOnlyLayout, false),
5214
+ children: [
5215
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react12.MessageSquarePlus, { className: "size-3.5 shrink-0" }),
5216
+ !iconOnlyLayout ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "min-w-0 truncate", children: label }) : null
5217
+ ]
5218
+ }
5219
+ );
5220
+ return (0, import_react_dom.createPortal)(
5221
+ iconOnlyLayout ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(Tooltip, { children: [
5222
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(TooltipTrigger, { asChild: true, children: button }),
5223
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(TooltipContent, { side: "right", className: "text-xs", children: label })
5224
+ ] }) : button,
5225
+ anchor
5226
+ );
5227
+ };
5228
+
5229
+ // src/components/studio/welcome.tsx
5230
+ var import_react39 = require("motion/react");
5231
+ var import_react40 = require("@assistant-ui/react");
5232
+ var import_jsx_runtime42 = require("react/jsx-runtime");
5233
+ var luxuryEase2 = [0.16, 1, 0.3, 1];
5234
+ var welcomeStagger2 = {
5235
+ initial: {},
5236
+ animate: {
5237
+ transition: { staggerChildren: 0.16, delayChildren: 0.18 }
5238
+ }
5239
+ };
5240
+ var welcomeItem2 = {
5241
+ initial: { opacity: 0, y: 14 },
5242
+ animate: {
5243
+ opacity: 1,
5244
+ y: 0,
5245
+ transition: { duration: 0.9, ease: luxuryEase2 }
5246
+ }
5247
+ };
5248
+ var welcomeIcon2 = {
5249
+ initial: { opacity: 0, y: 10, scale: 0.96 },
5250
+ animate: {
5251
+ opacity: 1,
5252
+ y: 0,
5253
+ scale: 1,
5254
+ transition: { duration: 1.1, ease: luxuryEase2 }
5255
+ }
5256
+ };
5257
+ var StudioWelcome = ({ config, icon }) => {
5258
+ const isEmpty = (0, import_react40.useThread)((s) => s.messages.length === 0);
5259
+ if (!isEmpty) return null;
5260
+ const iconNode = icon ?? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
5261
+ TimbalMark,
5262
+ {
5263
+ size: 112,
5264
+ className: "max-md:scale-[0.58] max-md:origin-center"
5265
+ }
5266
+ );
5267
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "aui-thread-welcome-center flex w-full grow flex-col items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
5268
+ import_react39.motion.div,
5269
+ {
5270
+ className: "aui-thread-welcome-message flex flex-col items-center justify-center px-2 text-center sm:px-4",
5271
+ variants: welcomeStagger2,
5272
+ initial: "initial",
5273
+ animate: "animate",
5274
+ children: [
5275
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_react39.motion.div, { variants: welcomeIcon2, className: "mb-4 md:mb-5", children: iconNode }),
5276
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
5277
+ import_react39.motion.h1,
5278
+ {
5279
+ variants: welcomeItem2,
5280
+ className: "aui-thread-welcome-message-inner text-xl font-semibold sm:text-2xl",
5281
+ children: config?.heading ?? "How can I help you today?"
5282
+ }
5283
+ ),
5284
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
5285
+ import_react39.motion.p,
5286
+ {
5287
+ variants: welcomeItem2,
5288
+ className: "aui-thread-welcome-message-inner mt-2 text-muted-foreground",
5289
+ children: config?.subheading ?? "Send a message to start a conversation."
5290
+ }
5291
+ )
5292
+ ]
5293
+ }
5294
+ ) }) });
5295
+ };
5296
+
5297
+ // src/components/studio/studio-shell.tsx
5298
+ var import_jsx_runtime43 = require("react/jsx-runtime");
5299
+ var import_react43 = require("react");
5300
+ var DEFAULT_BREAKPOINT_PX2 = 768;
5301
+ function readPersistedCollapsed2(key) {
5302
+ if (!key || typeof window === "undefined") return false;
5303
+ try {
5304
+ return window.localStorage.getItem(key) === "1";
5305
+ } catch {
5306
+ return false;
5307
+ }
5308
+ }
5309
+ function writePersistedCollapsed2(key, collapsed) {
5310
+ if (!key || typeof window === "undefined") return;
5311
+ try {
5312
+ window.localStorage.setItem(key, collapsed ? "1" : "0");
5313
+ } catch {
5314
+ }
5315
+ }
5316
+ function makeComposerWithPortal(BaseComposer) {
5317
+ const Resolved = BaseComposer ?? Composer;
5318
+ return function StudioComposerWithSidebar(props) {
5319
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
5320
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(StudioSidebarRuntimePortal, {}),
5321
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Resolved, { ...props })
5322
+ ] });
5323
+ };
5324
+ }
5325
+ var TimbalStudioShell = ({
5326
+ workforceId,
5327
+ workforces: workforcesProp,
5328
+ workforcesFetch,
5329
+ workforcesBaseUrl,
5330
+ brand,
5331
+ headerActions,
5332
+ headerStart,
5333
+ defaultCollapsed = false,
5334
+ persistKey = STORAGE_KEYS.sidebarCollapsed,
5335
+ mobileBreakpointPx = DEFAULT_BREAKPOINT_PX2,
5336
+ sidebarEmptyCaption = null,
5337
+ welcome,
5338
+ components,
5339
+ ...chatProps
5340
+ }) => {
5341
+ const reducedMotion = (0, import_react42.useReducedMotion)();
5342
+ const shouldFetchWorkforces = !workforceId && workforcesProp === void 0;
5343
+ const fetched = useWorkforces({
5344
+ enabled: shouldFetchWorkforces,
5345
+ fetch: workforcesFetch,
5346
+ baseUrl: workforcesBaseUrl
5347
+ });
5348
+ const workforces = workforcesProp ?? fetched.workforces;
5349
+ const [internalSelected, setInternalSelected] = (0, import_react41.useState)(
5350
+ workforceId ?? ""
5351
+ );
5352
+ (0, import_react41.useEffect)(() => {
5353
+ if (workforceId) return;
5354
+ if (internalSelected) return;
5355
+ const first = workforces[0]?.id ?? workforces[0]?.uid ?? workforces[0]?.name;
5356
+ if (first) setInternalSelected(first);
5357
+ }, [workforces, workforceId, internalSelected]);
5358
+ const activeWorkforceId = workforceId ?? internalSelected ?? fetched.selectedId ?? "";
5359
+ const [collapsed, setCollapsed] = (0, import_react41.useState)(() => {
5360
+ const persisted = readPersistedCollapsed2(persistKey);
5361
+ return persisted || defaultCollapsed;
5362
+ });
5363
+ const [isMobile, setIsMobile] = (0, import_react41.useState)(() => {
5364
+ if (typeof window === "undefined") return false;
5365
+ return window.innerWidth < mobileBreakpointPx;
5366
+ });
5367
+ const [mobileSidebarOpen, setMobileSidebarOpen] = (0, import_react41.useState)(false);
5368
+ (0, import_react41.useEffect)(() => {
5369
+ if (typeof window === "undefined") return;
5370
+ const onResize = () => setIsMobile(window.innerWidth < mobileBreakpointPx);
5371
+ onResize();
5372
+ window.addEventListener("resize", onResize);
5373
+ return () => window.removeEventListener("resize", onResize);
5374
+ }, [mobileBreakpointPx]);
5375
+ (0, import_react41.useEffect)(() => {
5376
+ if (!isMobile) setMobileSidebarOpen(false);
5377
+ }, [isMobile]);
5378
+ (0, import_react41.useEffect)(() => {
5379
+ if (!mobileSidebarOpen) return;
5380
+ const onKeyDown = (e) => {
5381
+ if (e.key === "Escape") setMobileSidebarOpen(false);
5382
+ };
5383
+ window.addEventListener("keydown", onKeyDown);
5384
+ return () => window.removeEventListener("keydown", onKeyDown);
5385
+ }, [mobileSidebarOpen]);
5386
+ const effectiveCollapsed = isMobile ? false : collapsed;
5387
+ const {
5388
+ widthCollapsed,
5389
+ entriesVisible: phaseEntriesVisible,
5390
+ onEntriesBlurOutComplete,
5391
+ onPanelWidthComplete
5392
+ } = useSidebarCollapsePhase(effectiveCollapsed, !!reducedMotion);
5393
+ const entriesVisible = isMobile || phaseEntriesVisible;
5394
+ const isCollapsedRail = widthCollapsed && !isMobile;
5395
+ const iconOnlyLayout = studioSidebarIconOnlyLayout(isMobile, isCollapsedRail);
5396
+ const layoutDirection = widthCollapsed ? "collapse" : "expand";
5397
+ const layoutTransition = studioSidebarWidthTransition(
5398
+ !!reducedMotion,
5399
+ layoutDirection
5400
+ );
5401
+ const desktopInsetPx = widthCollapsed ? SIDEBAR_INSET_PX_COLLAPSED : SIDEBAR_INSET_PX_EXPANDED;
5402
+ const onCollapsedChange = (0, import_react41.useCallback)(
5403
+ (next) => {
5404
+ setCollapsed(next);
5405
+ writePersistedCollapsed2(persistKey, next);
5406
+ },
5407
+ [persistKey]
5408
+ );
5409
+ const handleSelectWorkforce = (0, import_react41.useCallback)(
5410
+ (id) => {
5411
+ if (!workforceId) setInternalSelected(id);
5412
+ if (isMobile) setMobileSidebarOpen(false);
5413
+ },
5414
+ [workforceId, isMobile]
5415
+ );
5416
+ const sidebarContext = (0, import_react41.useMemo)(
5417
+ () => ({
5418
+ collapsed: effectiveCollapsed,
5419
+ isMobile,
5420
+ isCollapsedRail,
5421
+ iconOnlyLayout
5422
+ }),
5423
+ [effectiveCollapsed, isMobile, isCollapsedRail, iconOnlyLayout]
5424
+ );
5425
+ const resolvedComponents = (0, import_react41.useMemo)(() => {
5426
+ const next = { Welcome: StudioWelcome, ...components };
5427
+ next.Composer = makeComposerWithPortal(components?.Composer);
5428
+ return next;
5429
+ }, [components]);
5430
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(StudioSidebarContext.Provider, { value: sidebarContext, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
5431
+ "div",
5432
+ {
5433
+ className: cn(
5434
+ "relative h-dvh overflow-hidden bg-background",
5435
+ isMobile && mobileSidebarOpen && "max-md:overflow-hidden"
5436
+ ),
5437
+ style: studioChromeShellStyle,
5438
+ children: [
5439
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
5440
+ "div",
5441
+ {
5442
+ className: "pointer-events-none absolute inset-0 z-0 bg-background",
5443
+ "aria-hidden": true
5444
+ }
5445
+ ),
5446
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
5447
+ "div",
5448
+ {
5449
+ className: cn(
5450
+ "pointer-events-none absolute inset-0 z-0",
5451
+ studioPlaygroundGradientClass
5452
+ ),
5453
+ "aria-hidden": true
5454
+ }
5455
+ ),
5456
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
5457
+ StudioSidebarBackdrop,
5458
+ {
5459
+ open: isMobile && mobileSidebarOpen,
5460
+ onClose: () => setMobileSidebarOpen(false)
5461
+ }
5462
+ ),
5463
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
5464
+ StudioSidebarPanel,
5465
+ {
5466
+ workforces,
5467
+ selectedId: activeWorkforceId,
5468
+ onSelect: handleSelectWorkforce,
5469
+ collapsed: effectiveCollapsed,
5470
+ onCollapsedChange,
5471
+ isMobile,
5472
+ mobileOpen: mobileSidebarOpen,
5473
+ onMobileOpenChange: setMobileSidebarOpen,
5474
+ widthCollapsed,
5475
+ entriesVisible,
5476
+ onEntriesBlurOutComplete,
5477
+ onPanelWidthComplete,
5478
+ brand,
5479
+ emptyCaption: sidebarEmptyCaption
5480
+ }
5481
+ ),
5482
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
5483
+ import_react42.motion.header,
5484
+ {
5485
+ className: cn(
5486
+ "absolute top-0 right-0 z-40 flex items-start justify-between gap-2",
5487
+ "px-3 pt-[var(--studio-topbar-gap)] md:px-4",
5488
+ "left-0"
5489
+ ),
5490
+ initial: false,
5491
+ animate: { left: isMobile ? 0 : desktopInsetPx },
5492
+ transition: layoutTransition,
5493
+ children: [
5494
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
5495
+ "div",
5496
+ {
5497
+ className: cn(
5498
+ "flex min-w-0 flex-1 items-center gap-2",
5499
+ studioTopbarPillHeightClass
5500
+ ),
5501
+ children: [
5502
+ isMobile && !mobileSidebarOpen ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
5503
+ TimbalV2Button,
5504
+ {
5505
+ variant: "secondary",
5506
+ size: "sm",
5507
+ isIconOnly: true,
5508
+ className: studioTopbarIconPillClass,
5509
+ onClick: () => setMobileSidebarOpen(true),
5510
+ "aria-label": "Open menu",
5511
+ "aria-expanded": false,
5512
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react13.Menu, { className: "size-4" })
5513
+ }
5514
+ ) : null,
5515
+ headerStart
5516
+ ]
5517
+ }
5518
+ ),
5519
+ headerActions ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "flex shrink-0 items-center gap-1", children: headerActions }) : null
5520
+ ]
5521
+ }
5522
+ ),
5523
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
5524
+ import_react42.motion.main,
5525
+ {
5526
+ className: cn(
5527
+ "relative z-10 flex h-full min-w-0 flex-col",
5528
+ "pt-[var(--studio-inset-top)]",
5529
+ "px-3 md:px-0"
5530
+ ),
5531
+ initial: false,
5532
+ animate: { paddingLeft: isMobile ? 12 : desktopInsetPx },
5533
+ transition: layoutTransition,
5534
+ children: activeWorkforceId ? /* @__PURE__ */ (0, import_react43.createElement)(
5535
+ TimbalChat,
5536
+ {
5537
+ ...chatProps,
5538
+ workforceId: activeWorkforceId,
5539
+ key: activeWorkforceId,
5540
+ welcome,
5541
+ components: resolvedComponents,
5542
+ className: cn("min-h-0 flex-1 bg-transparent", chatProps.className)
5543
+ }
5544
+ ) : null
5545
+ }
5546
+ )
5547
+ ]
5548
+ }
5549
+ ) });
5550
+ };
5551
+
5552
+ // src/components/studio/mode-toggle.tsx
5553
+ var import_react44 = require("react");
5554
+ var import_lucide_react14 = require("lucide-react");
5555
+ var import_jsx_runtime44 = require("react/jsx-runtime");
5556
+ var ModeToggle = ({
5557
+ theme,
5558
+ setTheme,
5559
+ className,
5560
+ label = "Toggle theme"
5561
+ }) => {
5562
+ const isControlled = theme !== void 0;
5563
+ const [internalIsDark, setInternalIsDark] = (0, import_react44.useState)(false);
5564
+ (0, import_react44.useEffect)(() => {
5565
+ if (isControlled) return;
5566
+ if (typeof document === "undefined") return;
5567
+ setInternalIsDark(document.documentElement.classList.contains("dark"));
5568
+ }, [isControlled]);
5569
+ const isDark = isControlled ? theme === "dark" : internalIsDark;
5570
+ const onClick = (0, import_react44.useCallback)(() => {
5571
+ const next = isDark ? "light" : "dark";
5572
+ if (setTheme) {
5573
+ setTheme(next);
5574
+ return;
5575
+ }
5576
+ if (typeof document === "undefined") return;
5577
+ document.documentElement.classList.toggle("dark", next === "dark");
5578
+ setInternalIsDark(next === "dark");
5579
+ }, [isDark, setTheme]);
5580
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
5581
+ TimbalV2Button,
5582
+ {
5583
+ variant: "secondary",
5584
+ size: "sm",
5585
+ isIconOnly: true,
5586
+ onClick,
5587
+ className: cn(
5588
+ studioTopbarPillHeightClass,
5589
+ studioTopbarIconPillClass,
5590
+ "relative",
5591
+ className
5592
+ ),
5593
+ "aria-label": label,
5594
+ title: label,
5595
+ children: [
5596
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_lucide_react14.Sun, { className: "size-3.5 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" }),
5597
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_lucide_react14.Moon, { className: "absolute size-3.5 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" }),
5598
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "sr-only", children: label })
5599
+ ]
5600
+ }
5601
+ );
5602
+ };
5603
+
5604
+ // src/artifacts/agent-instructions.ts
5605
+ var ARTIFACT_AGENT_INSTRUCTIONS = `
5606
+ ## Rich artifacts (Timbal chat UI)
5607
+
5608
+ When you need charts, tables, choice widgets, or interactive controls, return a **JSON artifact object** instead of plain prose. The chat UI renders these automatically.
5609
+
5610
+ ### Delivery channels (either works)
5611
+
5612
+ 1. **Tool result (preferred)** \u2014 return a single JSON object (or a JSON string) from a tool. The object must include a string \`type\` field.
5613
+ 2. **Inline markdown fence** \u2014 embed the same JSON inside a fenced block:
5614
+
5615
+ \`\`\`timbal-artifact
3435
5616
  {"type":"chart","data":[{"month":"Jan","sales":120}]}
3436
5617
  \`\`\`
3437
5618
 
@@ -3546,288 +5727,9 @@ When you call a tool that returns an artifact (\`make_chart\`, \`ask_question\`,
3546
5727
  4. Treat the widget as visible to the user; refer to it as "above" / "the chart" / "the choices" \u2014 never reproduce its contents.
3547
5728
  `.trim();
3548
5729
 
3549
- // src/index.ts
3550
- var import_react26 = require("@assistant-ui/react");
3551
-
3552
- // src/hooks/use-workforces.ts
3553
- var import_react24 = require("react");
3554
- function useWorkforces(options = {}) {
3555
- const { baseUrl = "/api", fetch: fetchFn, pickInitial } = options;
3556
- const [workforces, setWorkforces] = (0, import_react24.useState)([]);
3557
- const [selectedId, setSelectedId] = (0, import_react24.useState)("");
3558
- const [isLoading, setIsLoading] = (0, import_react24.useState)(true);
3559
- const [error, setError] = (0, import_react24.useState)(null);
3560
- const fetchFnRef = (0, import_react24.useRef)(fetchFn ?? authFetch);
3561
- (0, import_react24.useEffect)(() => {
3562
- fetchFnRef.current = fetchFn ?? authFetch;
3563
- }, [fetchFn]);
3564
- const pickInitialRef = (0, import_react24.useRef)(pickInitial);
3565
- (0, import_react24.useEffect)(() => {
3566
- pickInitialRef.current = pickInitial;
3567
- }, [pickInitial]);
3568
- const load = (0, import_react24.useMemo)(() => {
3569
- return async () => {
3570
- setIsLoading(true);
3571
- setError(null);
3572
- try {
3573
- const res = await fetchFnRef.current(`${baseUrl}/workforce`);
3574
- if (!res.ok) throw new Error(`Failed to load workforces (${res.status})`);
3575
- const data = await res.json();
3576
- setWorkforces(data);
3577
- setSelectedId((current) => {
3578
- if (current && data.some((w) => idOf(w) === current)) return current;
3579
- const initial = pickInitialRef.current?.(data) ?? data.find((w) => w.type === "agent") ?? data[0];
3580
- return initial ? idOf(initial) : "";
3581
- });
3582
- } catch (err) {
3583
- setError(err instanceof Error ? err : new Error(String(err)));
3584
- } finally {
3585
- setIsLoading(false);
3586
- }
3587
- };
3588
- }, [baseUrl]);
3589
- (0, import_react24.useEffect)(() => {
3590
- load();
3591
- }, [load]);
3592
- const selected = (0, import_react24.useMemo)(
3593
- () => workforces.find((w) => idOf(w) === selectedId),
3594
- [workforces, selectedId]
3595
- );
3596
- return {
3597
- workforces,
3598
- selectedId,
3599
- setSelectedId,
3600
- selected,
3601
- isLoading,
3602
- error,
3603
- refresh: load
3604
- };
3605
- }
3606
- function idOf(item) {
3607
- return item.id ?? item.uid ?? item.name ?? "";
3608
- }
3609
-
3610
- // src/components/workforce-selector.tsx
3611
- var import_lucide_react8 = require("lucide-react");
3612
- var import_jsx_runtime27 = require("react/jsx-runtime");
3613
- var WorkforceSelector = ({
3614
- workforces,
3615
- value,
3616
- onChange,
3617
- hideWhenSingle = true,
3618
- className,
3619
- placeholder = "Select agent"
3620
- }) => {
3621
- if (workforces.length === 0) return null;
3622
- if (hideWhenSingle && workforces.length === 1) return null;
3623
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: cn("aui-workforce-selector relative inline-flex items-center", className), children: [
3624
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
3625
- "select",
3626
- {
3627
- className: "aui-workforce-selector-input h-7 cursor-pointer appearance-none rounded-md border-none bg-transparent pr-5 pl-1.5 text-xs font-medium text-muted-foreground shadow-none outline-none ring-0 transition-colors hover:text-foreground focus:ring-0",
3628
- value,
3629
- onChange: (e) => onChange(e.target.value),
3630
- "aria-label": placeholder,
3631
- children: [
3632
- !value && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("option", { value: "", children: placeholder }),
3633
- workforces.map((w) => {
3634
- const id = idOf2(w);
3635
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("option", { value: id, children: w.name ?? id }, id);
3636
- })
3637
- ]
3638
- }
3639
- ),
3640
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.ChevronDownIcon, { className: "aui-workforce-selector-icon pointer-events-none absolute right-1 size-3 text-muted-foreground" })
3641
- ] });
3642
- };
3643
- function idOf2(item) {
3644
- return item.id ?? item.uid ?? item.name ?? "";
3645
- }
3646
-
3647
- // src/components/chat-shell.tsx
3648
- var import_jsx_runtime28 = require("react/jsx-runtime");
3649
- var TimbalChatShell = ({
3650
- workforceId,
3651
- brand,
3652
- headerActions,
3653
- hideWorkforceSelector,
3654
- className,
3655
- headerClassName,
3656
- baseUrl,
3657
- fetch: fetch2,
3658
- ...chatProps
3659
- }) => {
3660
- const {
3661
- workforces,
3662
- selectedId,
3663
- setSelectedId
3664
- } = useWorkforces({ baseUrl, fetch: fetch2 });
3665
- const effectiveId = workforceId ?? selectedId;
3666
- const showSelector = !hideWorkforceSelector && !workforceId && workforces.length > 0;
3667
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
3668
- "div",
3669
- {
3670
- className: cn(
3671
- "aui-chat-shell flex h-screen flex-col overflow-hidden",
3672
- className
3673
- ),
3674
- children: [
3675
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
3676
- "header",
3677
- {
3678
- className: cn(
3679
- "aui-chat-shell-header flex shrink-0 items-center justify-between border-b border-border/50 bg-background/90 px-5 py-2 backdrop-blur-md",
3680
- headerClassName
3681
- ),
3682
- children: [
3683
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center", children: [
3684
- brand,
3685
- showSelector && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
3686
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "mx-3.5 h-3.5 w-px bg-border" }),
3687
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3688
- WorkforceSelector,
3689
- {
3690
- workforces,
3691
- value: selectedId,
3692
- onChange: setSelectedId
3693
- }
3694
- )
3695
- ] })
3696
- ] }),
3697
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex items-center gap-0.5", children: headerActions })
3698
- ]
3699
- }
3700
- ),
3701
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3702
- TimbalChat,
3703
- {
3704
- workforceId: effectiveId,
3705
- baseUrl,
3706
- fetch: fetch2,
3707
- className: "min-h-0 flex-1",
3708
- ...chatProps
3709
- },
3710
- effectiveId
3711
- )
3712
- ]
3713
- }
3714
- );
3715
- };
3716
-
3717
- // src/auth/provider.tsx
3718
- var import_react25 = require("react");
3719
- var import_jsx_runtime29 = require("react/jsx-runtime");
3720
- function isInsideIframe() {
3721
- try {
3722
- return typeof window !== "undefined" && window.self !== window.top;
3723
- } catch {
3724
- return true;
3725
- }
3726
- }
3727
- var SessionContext = (0, import_react25.createContext)(void 0);
3728
- var useSession = () => {
3729
- const context = (0, import_react25.useContext)(SessionContext);
3730
- if (context === void 0) {
3731
- throw new Error("useSession must be used within a SessionProvider");
3732
- }
3733
- return context;
3734
- };
3735
- var SessionProvider = ({
3736
- children,
3737
- enabled = true
3738
- }) => {
3739
- const [user, setUser] = (0, import_react25.useState)(null);
3740
- const [loading, setLoading] = (0, import_react25.useState)(enabled);
3741
- const [embedded] = (0, import_react25.useState)(isInsideIframe);
3742
- (0, import_react25.useEffect)(() => {
3743
- if (!enabled) {
3744
- setLoading(false);
3745
- return;
3746
- }
3747
- let ignore = false;
3748
- const restoreSession = async () => {
3749
- try {
3750
- const u = await fetchCurrentUser();
3751
- if (ignore) return;
3752
- if (u) {
3753
- setUser(u);
3754
- setLoading(false);
3755
- return;
3756
- }
3757
- if (getRefreshToken()) {
3758
- const ok = await refreshAccessToken();
3759
- if (ignore) return;
3760
- if (ok) {
3761
- const refreshedUser = await fetchCurrentUser();
3762
- if (ignore) return;
3763
- if (refreshedUser) {
3764
- setUser(refreshedUser);
3765
- setLoading(false);
3766
- return;
3767
- }
3768
- }
3769
- }
3770
- } catch {
3771
- if (ignore) return;
3772
- clearTokens();
3773
- }
3774
- if (!ignore && !embedded) {
3775
- setLoading(false);
3776
- }
3777
- };
3778
- restoreSession();
3779
- let messageCleanup;
3780
- if (embedded) {
3781
- const handleMessage = async (event) => {
3782
- if (ignore) return;
3783
- if (event.data?.type !== "timbal:auth" || !event.data.token) return;
3784
- setAccessToken(event.data.token);
3785
- if (event.data.refreshToken) {
3786
- setRefreshToken(event.data.refreshToken);
3787
- }
3788
- const u = await fetchCurrentUser();
3789
- if (!ignore) {
3790
- setUser(u);
3791
- setLoading(false);
3792
- }
3793
- };
3794
- window.addEventListener("message", handleMessage);
3795
- window.parent.postMessage({ type: "timbal:request-session" }, "*");
3796
- messageCleanup = () => window.removeEventListener("message", handleMessage);
3797
- }
3798
- return () => {
3799
- ignore = true;
3800
- messageCleanup?.();
3801
- };
3802
- }, [enabled, embedded]);
3803
- const logout = (0, import_react25.useCallback)(() => {
3804
- clearTokens();
3805
- setUser(null);
3806
- const returnTo = encodeURIComponent(
3807
- window.location.pathname + window.location.search
3808
- );
3809
- fetch("/api/auth/logout", { method: "POST" }).finally(
3810
- () => window.location.href = `/api/auth/login?return_to=${returnTo}`
3811
- );
3812
- }, []);
3813
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
3814
- SessionContext.Provider,
3815
- {
3816
- value: {
3817
- user,
3818
- loading,
3819
- isAuthenticated: !!user,
3820
- isEmbedded: embedded,
3821
- logout
3822
- },
3823
- children
3824
- }
3825
- );
3826
- };
3827
-
3828
5730
  // src/auth/guard.tsx
3829
- var import_lucide_react9 = require("lucide-react");
3830
- var import_jsx_runtime30 = require("react/jsx-runtime");
5731
+ var import_lucide_react15 = require("lucide-react");
5732
+ var import_jsx_runtime45 = require("react/jsx-runtime");
3831
5733
  var AuthGuard = ({
3832
5734
  children,
3833
5735
  requireAuth = false,
@@ -3838,7 +5740,7 @@ var AuthGuard = ({
3838
5740
  return children;
3839
5741
  }
3840
5742
  if (loading) {
3841
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react9.Loader2, { className: "w-8 h-8 animate-spin" }) });
5743
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react15.Loader2, { className: "w-8 h-8 animate-spin" }) });
3842
5744
  }
3843
5745
  if (requireAuth && !isAuthenticated && !isEmbedded) {
3844
5746
  const returnTo = encodeURIComponent(
@@ -3849,6 +5751,9 @@ var AuthGuard = ({
3849
5751
  }
3850
5752
  return children;
3851
5753
  };
5754
+
5755
+ // src/index.ts
5756
+ var import_react45 = require("@assistant-ui/react");
3852
5757
  // Annotate the CommonJS export names for ESM import in node:
3853
5758
  0 && (module.exports = {
3854
5759
  ARTIFACT_AGENT_INSTRUCTIONS,
@@ -3858,6 +5763,7 @@ var AuthGuard = ({
3858
5763
  ArtifactRegistryProvider,
3859
5764
  ArtifactView,
3860
5765
  AssistantRuntimeProvider,
5766
+ AuiIf,
3861
5767
  AuthGuard,
3862
5768
  Avatar,
3863
5769
  AvatarFallback,
@@ -3865,8 +5771,6 @@ var AuthGuard = ({
3865
5771
  Button,
3866
5772
  ChartArtifactView,
3867
5773
  Composer,
3868
- ComposerAddAttachment,
3869
- ComposerAttachments,
3870
5774
  ComposerPrimitive,
3871
5775
  DEFAULT_UPLOAD_ACCEPT,
3872
5776
  Dialog,
@@ -3880,17 +5784,21 @@ var AuthGuard = ({
3880
5784
  JsonArtifactView,
3881
5785
  MarkdownText,
3882
5786
  MessagePrimitive,
5787
+ ModeToggle,
3883
5788
  QuestionArtifactView,
3884
5789
  SessionProvider,
3885
5790
  Shimmer,
5791
+ StudioSidebar,
5792
+ StudioWelcome,
3886
5793
  Suggestions,
3887
- SyntaxHighlighter,
3888
5794
  TableArtifactView,
3889
5795
  Thread,
3890
5796
  ThreadPrimitive,
3891
5797
  TimbalChat,
3892
5798
  TimbalChatShell,
5799
+ TimbalMark,
3893
5800
  TimbalRuntimeProvider,
5801
+ TimbalStudioShell,
3894
5802
  ToolArtifactFallback,
3895
5803
  ToolFallback,
3896
5804
  Tooltip,
@@ -3902,10 +5810,8 @@ var AuthGuard = ({
3902
5810
  UiCustomNodeRegistryProvider,
3903
5811
  UiEventProvider,
3904
5812
  UiNodeView,
3905
- UserMessageAttachments,
3906
5813
  WorkforceSelector,
3907
5814
  authFetch,
3908
- buttonVariants,
3909
5815
  clearTokens,
3910
5816
  cn,
3911
5817
  createDefaultAttachmentAdapter,
@@ -3931,12 +5837,14 @@ var AuthGuard = ({
3931
5837
  useArtifactRegistry,
3932
5838
  useComposerRuntime,
3933
5839
  useMessageRuntime,
5840
+ useOptionalSession,
3934
5841
  useResolvedSuggestions,
3935
5842
  useSession,
3936
5843
  useThread,
3937
5844
  useThreadRuntime,
3938
5845
  useTimbalRuntime,
3939
5846
  useTimbalStream,
5847
+ useToolRunning,
3940
5848
  useUiCustomNodeRegistry,
3941
5849
  useUiDispatch,
3942
5850
  useUiEventEmitter,