@smartspace/chat-ui 1.14.4-dev.3f92249 → 1.14.4-dev.5c029a3

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.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import MuiButton from '@mui/material/Button';
2
2
  import IconButton from '@mui/material/IconButton';
3
- import { Loader2, Cpu, ChevronDown, Check, Globe, Zap, SlidersHorizontal, X, Paperclip, Mic, Square, Send, Minimize2, AlertTriangle, FileImage, FileVideo, FileAudio, FileArchive, FileCode, FileSpreadsheet, Presentation, FileText, ChevronUp, ExternalLink, Download, ShieldAlert, Copy } from 'lucide-react';
4
- import * as React8 from 'react';
5
- import { createContext, forwardRef, useImperativeHandle, useRef, useState, useEffect, useMemo, useCallback, useContext, useSyncExternalStore } from 'react';
3
+ import { Loader2, ChevronDown, Check, Cpu, SlidersHorizontal, X, Globe, Zap, Paperclip, Mic, Square, Send, Minimize2, AlertTriangle, FileImage, FileVideo, FileAudio, FileArchive, FileCode, FileSpreadsheet, Presentation, FileText, ChevronUp, ExternalLink, Download, ShieldAlert, Copy } from 'lucide-react';
4
+ import * as React9 from 'react';
5
+ import React9__default, { createContext, forwardRef, useImperativeHandle, useRef, useState, useEffect, useMemo, useCallback, useContext, useSyncExternalStore } from 'react';
6
6
  import { createPortal } from 'react-dom';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
8
  import { useQuery, queryOptions, useQueryClient, useMutation, skipToken } from '@tanstack/react-query';
@@ -24,7 +24,6 @@ import '@milkdown/prose/inputrules';
24
24
  import { withJsonFormsControlProps, withJsonFormsLayoutProps, JsonForms, ResolvedJsonFormsDispatch } from '@jsonforms/react';
25
25
  import { rankWith, uiTypeIs, createAjv } from '@jsonforms/core';
26
26
  import { vanillaRenderers, vanillaCells } from '@jsonforms/vanilla-renderers';
27
- import { FormControl, InputLabel, Select, MenuItem, useTheme, Box, Skeleton as Skeleton$1 } from '@mui/material';
28
27
  import 'ace-builds/src-noconflict/ace';
29
28
  import 'ace-builds/src-noconflict/ext-language_tools';
30
29
  import 'ace-builds/src-noconflict/mode-json';
@@ -57,6 +56,7 @@ import relativeTime from 'dayjs/plugin/relativeTime';
57
56
  import utc from 'dayjs/plugin/utc';
58
57
  import { Slot } from '@radix-ui/react-slot';
59
58
  import { cva } from 'class-variance-authority';
59
+ import { useTheme, Box, Skeleton as Skeleton$1 } from '@mui/material';
60
60
 
61
61
  var __defProp = Object.defineProperty;
62
62
  var __export = (target, all5) => {
@@ -365,6 +365,19 @@ var MessageValueType = /* @__PURE__ */ ((MessageValueType2) => {
365
365
  MessageValueType2["INPUT"] = "Input";
366
366
  return MessageValueType2;
367
367
  })(MessageValueType || {});
368
+ var MessageResponseSourceType = /* @__PURE__ */ ((MessageResponseSourceType2) => {
369
+ MessageResponseSourceType2["BlobInternal"] = "BlobInternal";
370
+ MessageResponseSourceType2["WebExternal"] = "WebExternal";
371
+ MessageResponseSourceType2["File"] = "File";
372
+ MessageResponseSourceType2["URL"] = "URL";
373
+ return MessageResponseSourceType2;
374
+ })(MessageResponseSourceType || {});
375
+ var MessageAttribution = /* @__PURE__ */ ((MessageAttribution2) => {
376
+ MessageAttribution2["Supported"] = "supported";
377
+ MessageAttribution2["Partial"] = "partial";
378
+ MessageAttribution2["Unsupported"] = "unsupported";
379
+ return MessageAttribution2;
380
+ })(MessageAttribution || {});
368
381
 
369
382
  // src/domains/threads/queryKeys.ts
370
383
  var THREAD_LIST_PAGE_SIZE = 30;
@@ -2430,6 +2443,31 @@ function useFlowRunVariables(flowRunId) {
2430
2443
  enabled: !!flowRunId
2431
2444
  });
2432
2445
  }
2446
+
2447
+ // src/chat-variables/renders/fieldStyles.ts
2448
+ var scaleFor = (surface) => surface === "form" ? "comfortable" : "dense";
2449
+ var fieldLabelClass = (scale) => `block truncate font-medium text-muted-foreground ${scale === "dense" ? "mb-1 text-xs" : "mb-1.5 text-sm"}`;
2450
+ var CONTROL_BASE = "rounded-md border bg-background text-foreground transition-colors placeholder:text-muted-foreground ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-60";
2451
+ var borderClass = (hasError) => hasError ? "border-destructive" : "border-input";
2452
+ var fieldControlClass = (scale, hasError) => `w-full ${CONTROL_BASE} ${borderClass(hasError)} ${scale === "dense" ? "px-2.5 py-1.5 text-xs" : "px-3 py-2 text-sm"}`;
2453
+ var fieldTriggerClass = (scale, hasError) => `w-full ${CONTROL_BASE} ${borderClass(
2454
+ hasError
2455
+ )} flex items-center justify-between gap-2 text-left ${scale === "dense" ? "h-8 px-2.5 text-xs" : "h-10 px-3 text-sm"}`;
2456
+ var fieldNumberClass = (scale, hasError) => `${CONTROL_BASE} ${borderClass(hasError)} tabular-nums ${scale === "dense" ? "h-8 w-20 px-2 text-xs" : "h-10 w-24 px-2.5 text-sm"}`;
2457
+ var fieldHintClass = "mt-1 text-xs text-muted-foreground";
2458
+ var fieldErrorClass = "mt-1 text-xs text-destructive";
2459
+ var fieldRowClass = "flex items-center justify-between gap-3";
2460
+ var fieldRowLabelClass = (scale) => `min-w-0 flex-1 truncate font-medium text-muted-foreground ${scale === "dense" ? "text-xs" : "text-sm"}`;
2461
+ var pillClass = (opts) => `flex h-8 shrink-0 items-center gap-1.5 rounded-full border px-2.5 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary ${opts.active ? "border-primary/30 bg-primary/10 text-primary" : "border-border/70 bg-transparent text-muted-foreground hover:bg-secondary"} ${opts.hasError ? "border-destructive text-destructive" : ""} ${opts.disabled ? "cursor-not-allowed opacity-60" : ""}`;
2462
+ var pillLabelClass = "max-w-[9rem] truncate";
2463
+ var pillValueClass = "max-w-[9rem] truncate text-foreground";
2464
+ var switchTrackClass = (on, disabled) => `peer inline-flex h-6 w-11 shrink-0 items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background ${on ? "bg-primary" : "bg-input"} ${disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer"}`;
2465
+ var switchThumbClass = (on) => `pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform ${on ? "translate-x-5" : "translate-x-0"}`;
2466
+ var POPOVER_WIDTH_PX = 288;
2467
+ var POPOVER_MAX_HEIGHT_PX = 288;
2468
+ var popoverClass = "flex flex-col overflow-hidden rounded-xl border border-border bg-popover shadow-lg";
2469
+ var popoverRowClass = "flex w-full items-center gap-2.5 px-3 py-2 text-left transition-colors hover:bg-secondary/60";
2470
+ var popoverHeadingClass = "text-[10px] font-semibold uppercase tracking-wide text-muted-foreground";
2433
2471
  function iconFor(label) {
2434
2472
  const name = (label ?? "").toLowerCase();
2435
2473
  if (/search|web|browse|internet/.test(name)) return Globe;
@@ -2445,7 +2483,8 @@ var BooleanRenderer = ({
2445
2483
  errors,
2446
2484
  uischema,
2447
2485
  visible,
2448
- enabled
2486
+ enabled,
2487
+ config
2449
2488
  }) => {
2450
2489
  const onToggle = useCallback(() => {
2451
2490
  handleChange(path2, !data);
@@ -2456,13 +2495,17 @@ var BooleanRenderer = ({
2456
2495
  const hasError = !!errors && errors.length > 0;
2457
2496
  const isChecked = Boolean(data);
2458
2497
  const Icon = iconFor(label);
2498
+ const surface = (config ?? {}).surface ?? "form";
2499
+ const scale = scaleFor(surface);
2459
2500
  const tooltip = [label, description, hasError ? errors : null].filter(Boolean).join(" \u2014 ");
2460
- return /* @__PURE__ */ jsxs(
2501
+ const toggle = /* @__PURE__ */ jsx(
2461
2502
  "button",
2462
2503
  {
2463
2504
  id: `toggle-${path2}`,
2464
2505
  type: "button",
2465
- "aria-pressed": isChecked,
2506
+ role: surface === "bar" ? void 0 : "switch",
2507
+ "aria-pressed": surface === "bar" ? isChecked : void 0,
2508
+ "aria-checked": surface === "bar" ? void 0 : isChecked,
2466
2509
  "aria-label": label,
2467
2510
  title: tooltip || void 0,
2468
2511
  onClick: onToggle,
@@ -2472,16 +2515,28 @@ var BooleanRenderer = ({
2472
2515
  e.currentTarget.blur();
2473
2516
  }
2474
2517
  },
2475
- className: `boolean-switch flex h-8 shrink-0 items-center gap-1.5 rounded-full border px-2.5 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary ${isChecked ? "border-primary/30 bg-primary/10 text-primary" : "border-transparent bg-transparent text-muted-foreground hover:bg-secondary"} ${hasError ? "border-destructive text-destructive" : ""} ${isDisabled ? "cursor-not-allowed opacity-60" : ""}`,
2476
- children: [
2518
+ className: surface === "bar" ? `boolean-switch ${pillClass({
2519
+ active: isChecked,
2520
+ hasError,
2521
+ disabled: isDisabled
2522
+ })}` : switchTrackClass(isChecked, isDisabled),
2523
+ children: surface === "bar" ? /* @__PURE__ */ jsxs(Fragment, { children: [
2477
2524
  /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5 shrink-0" }),
2478
2525
  label && // Desktop-first: the app and the package each ship a full Tailwind
2479
- // build, so a base `hidden` can out-order `sm:inline`. `max-sm:hidden`
2480
- // is the form that survives both cascades.
2481
- /* @__PURE__ */ jsx("span", { className: "inline max-w-[9rem] truncate max-sm:hidden", children: label })
2482
- ]
2526
+ // build, so a base `hidden` can out-order `sm:inline`.
2527
+ // `max-sm:hidden` is the form that survives both cascades.
2528
+ /* @__PURE__ */ jsx("span", { className: `inline ${pillLabelClass} max-sm:hidden`, children: label })
2529
+ ] }) : /* @__PURE__ */ jsx("span", { className: switchThumbClass(isChecked) })
2483
2530
  }
2484
2531
  );
2532
+ if (surface === "bar") return toggle;
2533
+ return /* @__PURE__ */ jsxs("div", { className: "ss-jsonforms-field ss-jsonforms-boolean", children: [
2534
+ /* @__PURE__ */ jsxs("div", { className: fieldRowClass, children: [
2535
+ /* @__PURE__ */ jsx("label", { htmlFor: `toggle-${path2}`, className: fieldRowLabelClass(scale), children: label }),
2536
+ toggle
2537
+ ] }),
2538
+ hasError && /* @__PURE__ */ jsx("div", { className: fieldErrorClass, children: errors })
2539
+ ] });
2485
2540
  };
2486
2541
  var booleanRendererTester = rankWith(40, (uischema, schema) => {
2487
2542
  if (uischema.type !== "Control") return false;
@@ -2491,6 +2546,104 @@ var booleanRendererTester = rankWith(40, (uischema, schema) => {
2491
2546
  return fieldSchema?.type === "boolean";
2492
2547
  });
2493
2548
  var BooleanRendererControl = withJsonFormsControlProps(BooleanRenderer);
2549
+ var GAP_PX = 8;
2550
+ var MIN_TRIGGER_WIDTH_PX = 224;
2551
+ var MIN_PANEL_HEIGHT_PX = 180;
2552
+ var NestedPopoverContext = React9__default.createContext(null);
2553
+ function useAnchoredPopover({
2554
+ trigger,
2555
+ popover,
2556
+ width,
2557
+ maxHeight,
2558
+ role,
2559
+ label
2560
+ }) {
2561
+ const [isOpen, setIsOpen] = useState(false);
2562
+ const parentRegistry = useContext(NestedPopoverContext);
2563
+ const descendants = useRef(/* @__PURE__ */ new Set());
2564
+ const close = useCallback(() => setIsOpen(false), []);
2565
+ const toggle = useCallback(() => setIsOpen((open) => !open), []);
2566
+ const registry = useMemo(
2567
+ () => ({
2568
+ register: (el) => {
2569
+ descendants.current.add(el);
2570
+ parentRegistry?.register(el);
2571
+ },
2572
+ unregister: (el) => {
2573
+ descendants.current.delete(el);
2574
+ parentRegistry?.unregister(el);
2575
+ }
2576
+ }),
2577
+ [parentRegistry]
2578
+ );
2579
+ useEffect(() => {
2580
+ if (!isOpen || !parentRegistry) return;
2581
+ const el = popover.current;
2582
+ if (!el) return;
2583
+ parentRegistry.register(el);
2584
+ return () => parentRegistry.unregister(el);
2585
+ }, [isOpen, parentRegistry, popover]);
2586
+ useEffect(() => {
2587
+ if (!isOpen) return;
2588
+ const onPointerDown = (event) => {
2589
+ const target = event.target;
2590
+ if (trigger.current?.contains(target)) return;
2591
+ if (popover.current?.contains(target)) return;
2592
+ for (const el of descendants.current) {
2593
+ if (el.contains(target)) return;
2594
+ }
2595
+ close();
2596
+ };
2597
+ const onKeyDown = (event) => {
2598
+ if (event.key === "Escape") close();
2599
+ };
2600
+ document.addEventListener("mousedown", onPointerDown);
2601
+ document.addEventListener("keydown", onKeyDown);
2602
+ window.addEventListener("resize", close);
2603
+ return () => {
2604
+ document.removeEventListener("mousedown", onPointerDown);
2605
+ document.removeEventListener("keydown", onKeyDown);
2606
+ window.removeEventListener("resize", close);
2607
+ };
2608
+ }, [isOpen, close, trigger, popover]);
2609
+ const renderPopover = (children2) => {
2610
+ if (!isOpen) return null;
2611
+ const anchor = trigger.current?.getBoundingClientRect();
2612
+ if (!anchor) return null;
2613
+ const panelWidth = width === "trigger" ? Math.max(anchor.width, MIN_TRIGGER_WIDTH_PX) : width;
2614
+ const spaceAbove = anchor.top - GAP_PX * 2;
2615
+ const spaceBelow = window.innerHeight - anchor.bottom - GAP_PX * 2;
2616
+ const openAbove = spaceAbove >= MIN_PANEL_HEIGHT_PX || spaceAbove >= spaceBelow;
2617
+ const panelMaxHeight = Math.max(
2618
+ 0,
2619
+ Math.min(maxHeight, openAbove ? spaceAbove : spaceBelow)
2620
+ );
2621
+ return createPortal(
2622
+ /* @__PURE__ */ jsx(
2623
+ "div",
2624
+ {
2625
+ ref: popover,
2626
+ role,
2627
+ "aria-label": label,
2628
+ className: `fixed z-50 ${popoverClass}`,
2629
+ style: {
2630
+ width: panelWidth,
2631
+ maxWidth: `calc(100vw - ${GAP_PX * 4}px)`,
2632
+ left: Math.max(
2633
+ GAP_PX,
2634
+ Math.min(anchor.left, window.innerWidth - panelWidth - GAP_PX)
2635
+ ),
2636
+ ...openAbove ? { bottom: window.innerHeight - anchor.top + GAP_PX } : { top: anchor.bottom + GAP_PX },
2637
+ maxHeight: panelMaxHeight
2638
+ },
2639
+ children: /* @__PURE__ */ jsx(NestedPopoverContext.Provider, { value: registry, children: children2 })
2640
+ }
2641
+ ),
2642
+ document.body
2643
+ );
2644
+ };
2645
+ return { isOpen, close, toggle, renderPopover };
2646
+ }
2494
2647
  function hasConst(x) {
2495
2648
  return !!x && typeof x === "object" && "const" in x;
2496
2649
  }
@@ -2529,185 +2682,109 @@ var DropdownRenderer = ({
2529
2682
  label,
2530
2683
  description,
2531
2684
  errors,
2532
- uischema
2685
+ config,
2686
+ uischema,
2687
+ visible
2533
2688
  }) => {
2689
+ const triggerRef = useRef(null);
2690
+ const listRef = useRef(null);
2691
+ const surface = (config ?? {}).surface ?? "form";
2692
+ const scale = scaleFor(surface);
2693
+ const { isOpen, close, toggle, renderPopover } = useAnchoredPopover({
2694
+ trigger: triggerRef,
2695
+ popover: listRef,
2696
+ // A select's list lines up with its own control.
2697
+ width: "trigger",
2698
+ maxHeight: POPOVER_MAX_HEIGHT_PX,
2699
+ role: "listbox",
2700
+ label: label || "Options"
2701
+ });
2534
2702
  const options = toOptions(schema);
2535
- const handleSelectionChange = useCallback(
2536
- (event) => {
2537
- handleChange(path2, event.target.value);
2703
+ const select = useCallback(
2704
+ (value) => {
2705
+ handleChange(path2, value);
2706
+ close();
2538
2707
  },
2539
- [handleChange, path2]
2708
+ [handleChange, path2, close]
2540
2709
  );
2541
- const displayValue = data ?? "";
2710
+ if (!visible) return null;
2542
2711
  const readOnly = uischema?.access === "Read";
2543
2712
  const isDisabled = !enabled || readOnly;
2544
- return /* @__PURE__ */ jsxs(
2545
- FormControl,
2713
+ const hasError = !!errors;
2714
+ const selected = options.find((option) => option.const === data);
2715
+ const valueText = selected ? selected.title ?? String(selected.const) : data != null && data !== "" ? String(data) : "";
2716
+ const triggerId = `${path2}-trigger`;
2717
+ const isBar = surface === "bar";
2718
+ const placeholder = `Select ${(label || "value").toLowerCase()}\u2026`;
2719
+ const trigger = /* @__PURE__ */ jsxs(
2720
+ "button",
2546
2721
  {
2547
- variant: "outlined",
2548
- size: "small",
2549
- fullWidth: true,
2550
- error: !!errors,
2722
+ id: triggerId,
2723
+ ref: triggerRef,
2724
+ type: "button",
2551
2725
  disabled: isDisabled,
2552
- className: "compact-field",
2553
- sx: {
2554
- minWidth: "220px"
2555
- },
2726
+ onClick: toggle,
2727
+ "aria-haspopup": "listbox",
2728
+ "aria-expanded": isOpen,
2729
+ "aria-label": label,
2730
+ title: [label, valueText, hasError ? errors : null].filter(Boolean).join(" \u2014 ") || void 0,
2731
+ className: isBar ? `ss-jsonforms-select-trigger ${pillClass({
2732
+ active: isOpen,
2733
+ hasError,
2734
+ disabled: isDisabled
2735
+ })}` : `ss-jsonforms-select-trigger ${fieldTriggerClass(scale, hasError)}`,
2556
2736
  children: [
2737
+ isBar && label && /* @__PURE__ */ jsx("span", { className: `inline ${pillLabelClass} max-sm:hidden`, children: label }),
2557
2738
  /* @__PURE__ */ jsx(
2558
- InputLabel,
2739
+ "span",
2559
2740
  {
2560
- id: `${path2}-label`,
2561
- sx: {
2562
- color: "#6b7280",
2563
- fontSize: "0.875rem",
2564
- fontWeight: 500,
2565
- "&.Mui-focused": {
2566
- color: "#6366f1"
2567
- },
2568
- "&.Mui-error": {
2569
- color: "#ef4444"
2570
- }
2571
- },
2572
- children: label
2741
+ className: isBar ? pillValueClass : `min-w-0 flex-1 truncate ${valueText ? "" : "text-muted-foreground"}`,
2742
+ children: valueText || (isBar ? "\u2014" : placeholder)
2573
2743
  }
2574
2744
  ),
2575
2745
  /* @__PURE__ */ jsx(
2576
- Select,
2746
+ ChevronDown,
2577
2747
  {
2578
- labelId: `${path2}-label`,
2579
- value: displayValue,
2580
- onChange: handleSelectionChange,
2581
- label,
2582
- sx: {
2583
- "& .MuiOutlinedInput-root": {
2584
- backgroundColor: "#fafafa",
2585
- borderRadius: "8px",
2586
- transition: "all 0.2s ease-in-out",
2587
- height: "40px",
2588
- // Same height as model dropdown
2589
- "& fieldset": {
2590
- borderColor: "#e5e7eb",
2591
- borderWidth: "1px"
2592
- },
2593
- "&:hover": {
2594
- backgroundColor: "#ffffff",
2595
- "& fieldset": {
2596
- borderColor: "#9ca3af"
2597
- }
2598
- },
2599
- "&.Mui-focused": {
2600
- backgroundColor: "#ffffff",
2601
- "& fieldset": {
2602
- borderColor: "#6366f1",
2603
- borderWidth: "2px"
2604
- }
2605
- },
2606
- "&.Mui-error": {
2607
- "& fieldset": {
2608
- borderColor: "#ef4444"
2609
- }
2610
- }
2611
- },
2612
- "& .MuiSelect-select": {
2613
- backgroundColor: "#fafafa",
2614
- borderRadius: "8px",
2615
- transition: "all 0.2s ease-in-out",
2616
- height: "40px",
2617
- display: "flex",
2618
- alignItems: "center",
2619
- paddingRight: "32px !important",
2620
- "&:hover": {
2621
- backgroundColor: "#ffffff"
2622
- },
2623
- "&.Mui-focused": {
2624
- backgroundColor: "#ffffff"
2625
- }
2626
- },
2627
- "& .MuiOutlinedInput-notchedOutline": {
2628
- borderColor: "#e5e7eb",
2629
- borderWidth: "1px",
2630
- borderRadius: "8px"
2631
- },
2632
- "&:hover .MuiOutlinedInput-notchedOutline": {
2633
- borderColor: "#9ca3af"
2634
- },
2635
- "&.Mui-focused .MuiOutlinedInput-notchedOutline": {
2636
- borderColor: "#6366f1",
2637
- borderWidth: "2px"
2638
- },
2639
- "&.Mui-error .MuiOutlinedInput-notchedOutline": {
2640
- borderColor: "#ef4444"
2641
- },
2642
- "& .MuiSelect-icon": {
2643
- color: "#9ca3af",
2644
- "&:hover": {
2645
- color: "#6b7280"
2646
- }
2647
- }
2648
- },
2649
- MenuProps: {
2650
- PaperProps: {
2651
- sx: {
2652
- borderRadius: "8px",
2653
- boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)",
2654
- border: "1px solid #e5e7eb",
2655
- marginTop: "4px",
2656
- maxHeight: "280px"
2657
- }
2658
- },
2659
- MenuListProps: {
2660
- sx: {
2661
- padding: 0
2662
- }
2663
- }
2664
- },
2665
- children: options.map((option, index) => {
2666
- const raw2 = option.const;
2667
- const key = typeof raw2 === "string" || typeof raw2 === "number" ? String(raw2) : String(index);
2668
- const value = typeof raw2 === "string" || typeof raw2 === "number" ? raw2 : String(raw2 ?? index);
2669
- return /* @__PURE__ */ jsx(
2670
- MenuItem,
2671
- {
2672
- value,
2673
- sx: {
2674
- padding: "12px 16px",
2675
- fontSize: "0.875rem",
2676
- borderBottom: "1px solid #f3f4f6",
2677
- "&:last-child": {
2678
- borderBottom: "none"
2679
- },
2680
- "&:hover": {
2681
- backgroundColor: "#f8fafc"
2682
- },
2683
- "&.Mui-selected": {
2684
- backgroundColor: "#eff6ff",
2685
- "&:hover": {
2686
- backgroundColor: "#dbeafe"
2687
- }
2688
- }
2689
- },
2690
- children: option.title ?? String(raw2)
2691
- },
2692
- key
2693
- );
2694
- })
2695
- }
2696
- ),
2697
- (description || errors) && /* @__PURE__ */ jsx(
2698
- "div",
2699
- {
2700
- style: {
2701
- fontSize: "0.75rem",
2702
- marginTop: "4px",
2703
- color: errors ? "#ef4444" : "#6b7280"
2704
- },
2705
- children: errors || description
2748
+ className: `shrink-0 opacity-50 ${isBar ? "h-3 w-3" : "h-4 w-4"}`
2706
2749
  }
2707
2750
  )
2708
2751
  ]
2709
2752
  }
2710
2753
  );
2754
+ return /* @__PURE__ */ jsxs("div", { className: "ss-jsonforms-field ss-jsonforms-select compact-field", children: [
2755
+ !isBar && label && /* @__PURE__ */ jsx("label", { htmlFor: triggerId, className: fieldLabelClass(scale), children: label }),
2756
+ trigger,
2757
+ !isBar && (errors || description) && /* @__PURE__ */ jsx("div", { className: errors ? fieldErrorClass : fieldHintClass, children: errors || description }),
2758
+ renderPopover(
2759
+ /* @__PURE__ */ jsxs("div", { className: "min-h-0 overflow-y-auto py-1", children: [
2760
+ options.length === 0 && /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-xs text-muted-foreground", children: "No options available" }),
2761
+ options.map((option, index) => {
2762
+ const active = option.const === data;
2763
+ const text6 = option.title ?? String(option.const);
2764
+ return /* @__PURE__ */ jsxs(
2765
+ "button",
2766
+ {
2767
+ type: "button",
2768
+ role: "option",
2769
+ "aria-selected": active,
2770
+ onClick: () => select(option.const),
2771
+ className: popoverRowClass,
2772
+ children: [
2773
+ /* @__PURE__ */ jsx(
2774
+ Check,
2775
+ {
2776
+ className: `h-3.5 w-3.5 shrink-0 ${active ? "text-primary" : "opacity-0"}`
2777
+ }
2778
+ ),
2779
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-sm text-foreground", children: text6 })
2780
+ ]
2781
+ },
2782
+ typeof option.const === "string" || typeof option.const === "number" ? String(option.const) : `option-${index}`
2783
+ );
2784
+ })
2785
+ ] })
2786
+ )
2787
+ ] });
2711
2788
  };
2712
2789
  var dropdownRendererTester = rankWith(
2713
2790
  90,
@@ -2725,8 +2802,8 @@ var dropdownRendererTester = rankWith(
2725
2802
  return false;
2726
2803
  }
2727
2804
  const hasDropdownOptions = !!(fieldSchema.oneOf || fieldSchema.anyOf || fieldSchema.enum && Array.isArray(fieldSchema.enum));
2728
- const isModelSelector = typeof fieldSchema === "object" && fieldSchema && fieldSchema["x-model-selector"] === true || fieldSchema.title === "ModelId" || fieldSchema.format === "uuid";
2729
- return hasDropdownOptions && !isModelSelector;
2805
+ const isModelSelector2 = typeof fieldSchema === "object" && fieldSchema && fieldSchema["x-model-selector"] === true || fieldSchema.title === "ModelId" || fieldSchema.format === "uuid";
2806
+ return hasDropdownOptions && !isModelSelector2;
2730
2807
  }
2731
2808
  );
2732
2809
  var DropdownRendererControl = withJsonFormsControlProps(DropdownRenderer);
@@ -2761,7 +2838,8 @@ var JsonEditorRenderer = ({
2761
2838
  uischema,
2762
2839
  visible,
2763
2840
  enabled,
2764
- required
2841
+ required,
2842
+ config
2765
2843
  }) => {
2766
2844
  const [jsonValue, setJsonValue] = useState("");
2767
2845
  const [displayedParseError, setDisplayedParseError] = useState(
@@ -2815,43 +2893,19 @@ var JsonEditorRenderer = ({
2815
2893
  }
2816
2894
  const readOnly = uischema?.access === "Read";
2817
2895
  const isDisabled = !enabled || readOnly;
2896
+ const scale = scaleFor(
2897
+ (config ?? {}).surface ?? "form"
2898
+ );
2818
2899
  return /* @__PURE__ */ jsxs("div", { style: { marginBottom: "1rem" }, children: [
2819
- label && /* @__PURE__ */ jsxs(
2820
- "label",
2821
- {
2822
- style: {
2823
- display: "block",
2824
- color: "#475569",
2825
- fontSize: "0.875rem",
2826
- fontWeight: 500,
2827
- marginBottom: "0.375rem"
2828
- },
2829
- children: [
2830
- label,
2831
- required && /* @__PURE__ */ jsx("span", { style: { color: "#ef4444", marginLeft: "0.25rem" }, children: "*" })
2832
- ]
2833
- }
2834
- ),
2835
- description && /* @__PURE__ */ jsx(
2836
- "div",
2837
- {
2838
- style: {
2839
- color: "#6b7280",
2840
- fontSize: "0.75rem",
2841
- marginBottom: "0.5rem"
2842
- },
2843
- children: description
2844
- }
2845
- ),
2900
+ label && /* @__PURE__ */ jsxs("label", { className: fieldLabelClass(scale), children: [
2901
+ label,
2902
+ required && /* @__PURE__ */ jsx("span", { className: "ml-1 text-destructive", children: "*" })
2903
+ ] }),
2904
+ description && /* @__PURE__ */ jsx("div", { className: fieldHintClass, children: description }),
2846
2905
  /* @__PURE__ */ jsx(
2847
2906
  "div",
2848
2907
  {
2849
- style: {
2850
- border: errors || displayedParseError ? "1px solid #ef4444" : "1px solid #d1d5db",
2851
- borderRadius: "6px",
2852
- overflow: "hidden",
2853
- opacity: isDisabled ? 0.6 : 1
2854
- },
2908
+ className: `overflow-hidden rounded-md border ${errors || displayedParseError ? "border-destructive" : "border-input"} ${isDisabled ? "opacity-60" : ""}`,
2855
2909
  children: /* @__PURE__ */ jsx(
2856
2910
  AceEditor,
2857
2911
  {
@@ -2884,28 +2938,8 @@ var JsonEditorRenderer = ({
2884
2938
  )
2885
2939
  }
2886
2940
  ),
2887
- displayedParseError && /* @__PURE__ */ jsx(
2888
- "div",
2889
- {
2890
- style: {
2891
- color: "#ef4444",
2892
- fontSize: "0.75rem",
2893
- marginTop: "0.25rem"
2894
- },
2895
- children: displayedParseError
2896
- }
2897
- ),
2898
- errors && /* @__PURE__ */ jsx(
2899
- "div",
2900
- {
2901
- style: {
2902
- color: "#ef4444",
2903
- fontSize: "0.75rem",
2904
- marginTop: "0.25rem"
2905
- },
2906
- children: errors
2907
- }
2908
- )
2941
+ displayedParseError && /* @__PURE__ */ jsx("div", { className: fieldErrorClass, children: displayedParseError }),
2942
+ errors && /* @__PURE__ */ jsx("div", { className: fieldErrorClass, children: errors })
2909
2943
  ] });
2910
2944
  };
2911
2945
  var jsonEditorTester = rankWith(
@@ -2996,14 +3030,31 @@ var ModelIdRenderer = ({
2996
3030
  description,
2997
3031
  errors,
2998
3032
  uischema,
2999
- visible
3033
+ visible,
3034
+ config
3000
3035
  }) => {
3001
- const [isOpen, setIsOpen] = useState(false);
3002
3036
  const [searchValue, setSearchValue] = useState("");
3003
3037
  const [debouncedSearchValue, setDebouncedSearchValue] = useState("");
3004
- const containerRef = useRef(null);
3038
+ const triggerRef = useRef(null);
3005
3039
  const menuRef = useRef(null);
3006
3040
  const searchRef = useRef(null);
3041
+ const surface = (config ?? {}).surface ?? "bar";
3042
+ const scale = scaleFor(surface);
3043
+ const isBar = surface === "bar";
3044
+ const {
3045
+ isOpen,
3046
+ close: closeMenu,
3047
+ toggle,
3048
+ renderPopover
3049
+ } = useAnchoredPopover({
3050
+ trigger: triggerRef,
3051
+ popover: menuRef,
3052
+ // Wide enough for a provider glyph, a model name and its id underneath.
3053
+ width: POPOVER_WIDTH_PX,
3054
+ maxHeight: POPOVER_MAX_HEIGHT_PX,
3055
+ role: "listbox",
3056
+ label: "Models"
3057
+ });
3007
3058
  const debounceTimerRef = useRef(
3008
3059
  void 0
3009
3060
  );
@@ -3042,35 +3093,13 @@ var ModelIdRenderer = ({
3042
3093
  handleChange(path2, model.id);
3043
3094
  setSearchValue("");
3044
3095
  setDebouncedSearchValue("");
3045
- setIsOpen(false);
3096
+ closeMenu();
3046
3097
  },
3047
- [handleChange, path2]
3098
+ [handleChange, path2, closeMenu]
3048
3099
  );
3049
- const close = useCallback(() => {
3050
- setIsOpen(false);
3051
- setSearchValue("");
3052
- }, []);
3053
3100
  useEffect(() => {
3054
- if (!isOpen) return;
3055
- const onPointerDown = (event) => {
3056
- const target = event.target;
3057
- if (containerRef.current && !containerRef.current.contains(target) && !(menuRef.current && menuRef.current.contains(target))) {
3058
- close();
3059
- }
3060
- };
3061
- const onKeyDown = (event) => {
3062
- if (event.key === "Escape") close();
3063
- };
3064
- const onResize = () => close();
3065
- document.addEventListener("mousedown", onPointerDown);
3066
- document.addEventListener("keydown", onKeyDown);
3067
- window.addEventListener("resize", onResize);
3068
- return () => {
3069
- document.removeEventListener("mousedown", onPointerDown);
3070
- document.removeEventListener("keydown", onKeyDown);
3071
- window.removeEventListener("resize", onResize);
3072
- };
3073
- }, [isOpen, close]);
3101
+ if (!isOpen) setSearchValue("");
3102
+ }, [isOpen]);
3074
3103
  useEffect(() => {
3075
3104
  if (isOpen) searchRef.current?.focus();
3076
3105
  }, [isOpen]);
@@ -3079,53 +3108,58 @@ var ModelIdRenderer = ({
3079
3108
  const isDisabled = !enabled || readOnly;
3080
3109
  const hasError = !!errors && errors.length > 0;
3081
3110
  const selectedName = selectedModel ? selectedModel.displayName || selectedModel.name || "" : "";
3082
- const triggerText = selectedName || label || "Select model";
3111
+ const triggerText = selectedName || "Select model";
3083
3112
  const iconSrc = getModelIcon(selectedModel);
3084
3113
  const tooltip = [selectedName || label, description, hasError ? errors : null].filter(Boolean).join(" \u2014 ");
3085
- const anchorRect = isOpen ? containerRef.current?.getBoundingClientRect() : void 0;
3086
- return /* @__PURE__ */ jsxs("div", { className: "relative shrink-0", ref: containerRef, children: [
3087
- /* @__PURE__ */ jsxs(
3088
- "button",
3089
- {
3090
- type: "button",
3091
- onClick: () => setIsOpen((v) => !v),
3092
- disabled: isDisabled,
3093
- "aria-expanded": isOpen,
3094
- "aria-haspopup": "listbox",
3095
- "aria-label": label || "Select model",
3096
- title: tooltip || void 0,
3097
- className: `flex h-8 shrink-0 items-center gap-1.5 rounded-full border px-2.5 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary ${isOpen ? "border-primary/30 bg-primary/10 text-primary" : "border-border/70 bg-transparent text-muted-foreground hover:bg-secondary"} ${hasError ? "border-destructive text-destructive" : ""} ${isDisabled ? "cursor-not-allowed opacity-60" : ""}`,
3098
- children: [
3099
- iconSrc ? /* @__PURE__ */ jsx(
3100
- "img",
3101
- {
3102
- src: iconSrc,
3103
- alt: "",
3104
- className: "h-3.5 w-3.5 shrink-0 object-contain"
3105
- }
3106
- ) : /* @__PURE__ */ jsx(Cpu, { className: "h-3.5 w-3.5 shrink-0" }),
3107
- /* @__PURE__ */ jsx("span", { className: "inline max-w-[9rem] truncate max-sm:hidden", children: triggerText }),
3108
- /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3 shrink-0 opacity-60" })
3109
- ]
3110
- }
3111
- ),
3112
- isOpen && anchorRect && createPortal(
3113
- /* @__PURE__ */ jsxs(
3114
- "div",
3115
- {
3116
- ref: menuRef,
3117
- role: "listbox",
3118
- "aria-label": label || "Models",
3119
- className: "fixed z-50 w-72 max-w-[calc(100vw-2rem)] overflow-hidden rounded-xl border border-border bg-popover shadow-lg",
3120
- style: {
3121
- left: Math.max(
3122
- 8,
3123
- Math.min(anchorRect.left, window.innerWidth - 288 - 8)
3124
- ),
3125
- bottom: window.innerHeight - anchorRect.top + 8
3126
- },
3127
- children: [
3128
- /* @__PURE__ */ jsx("div", { className: "border-b border-border p-2", children: /* @__PURE__ */ jsx(
3114
+ const triggerLabel = !label || label === "ModelId" ? "Model" : label;
3115
+ const trigger = /* @__PURE__ */ jsxs(
3116
+ "button",
3117
+ {
3118
+ ref: triggerRef,
3119
+ id: `${path2}-trigger`,
3120
+ type: "button",
3121
+ onClick: toggle,
3122
+ disabled: isDisabled,
3123
+ "aria-expanded": isOpen,
3124
+ "aria-haspopup": "listbox",
3125
+ "aria-label": triggerLabel,
3126
+ title: tooltip || void 0,
3127
+ className: isBar ? pillClass({ active: isOpen, hasError, disabled: isDisabled }) : fieldTriggerClass(scale, hasError),
3128
+ children: [
3129
+ iconSrc ? /* @__PURE__ */ jsx(
3130
+ "img",
3131
+ {
3132
+ src: iconSrc,
3133
+ alt: "",
3134
+ className: "h-3.5 w-3.5 shrink-0 object-contain"
3135
+ }
3136
+ ) : /* @__PURE__ */ jsx(Cpu, { className: "h-3.5 w-3.5 shrink-0" }),
3137
+ /* @__PURE__ */ jsx(
3138
+ "span",
3139
+ {
3140
+ className: isBar ? `inline ${pillValueClass} max-sm:hidden` : "min-w-0 flex-1 truncate",
3141
+ children: triggerText
3142
+ }
3143
+ ),
3144
+ /* @__PURE__ */ jsx(
3145
+ ChevronDown,
3146
+ {
3147
+ className: `shrink-0 opacity-60 ${isBar ? "h-3 w-3" : "h-4 w-4"}`
3148
+ }
3149
+ )
3150
+ ]
3151
+ }
3152
+ );
3153
+ return /* @__PURE__ */ jsxs(
3154
+ "div",
3155
+ {
3156
+ className: isBar ? "ss-jsonforms-field ss-jsonforms-model relative shrink-0" : "ss-jsonforms-field ss-jsonforms-model compact-field",
3157
+ children: [
3158
+ !isBar && /* @__PURE__ */ jsx("label", { htmlFor: `${path2}-trigger`, className: fieldLabelClass(scale), children: triggerLabel }),
3159
+ trigger,
3160
+ renderPopover(
3161
+ /* @__PURE__ */ jsxs(Fragment, { children: [
3162
+ /* @__PURE__ */ jsx("div", { className: "shrink-0 border-b border-border p-2", children: /* @__PURE__ */ jsx(
3129
3163
  "input",
3130
3164
  {
3131
3165
  ref: searchRef,
@@ -3137,7 +3171,7 @@ var ModelIdRenderer = ({
3137
3171
  className: "h-8 w-full rounded-md border border-border bg-background px-2 text-xs text-foreground outline-none placeholder:text-muted-foreground focus:border-primary/40"
3138
3172
  }
3139
3173
  ) }),
3140
- /* @__PURE__ */ jsxs("div", { className: "max-h-72 overflow-y-auto", children: [
3174
+ /* @__PURE__ */ jsxs("div", { className: "min-h-0 overflow-y-auto", children: [
3141
3175
  isLoading && listModels.length === 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-6", children: /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin text-primary" }) }),
3142
3176
  !isLoading && listModels.length === 0 && /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-xs text-muted-foreground", children: searchValue ? "No models found" : "No models available" }),
3143
3177
  listModels.map((model) => {
@@ -3150,7 +3184,7 @@ var ModelIdRenderer = ({
3150
3184
  role: "option",
3151
3185
  "aria-selected": active,
3152
3186
  onClick: () => handleSelect(model),
3153
- className: "flex w-full items-center gap-2.5 px-3 py-2 text-left transition-colors hover:bg-secondary/60",
3187
+ className: popoverRowClass,
3154
3188
  children: [
3155
3189
  /* @__PURE__ */ jsx(
3156
3190
  Check,
@@ -3176,12 +3210,11 @@ var ModelIdRenderer = ({
3176
3210
  );
3177
3211
  })
3178
3212
  ] })
3179
- ]
3180
- }
3181
- ),
3182
- document.body
3183
- )
3184
- ] });
3213
+ ] })
3214
+ )
3215
+ ]
3216
+ }
3217
+ );
3185
3218
  };
3186
3219
  var modelIdRendererTester = rankWith(
3187
3220
  100,
@@ -3216,6 +3249,7 @@ var NumberRenderer = ({
3216
3249
  uischema,
3217
3250
  visible,
3218
3251
  enabled,
3252
+ config,
3219
3253
  required
3220
3254
  }) => {
3221
3255
  const isInteger = schema?.type === "integer";
@@ -3244,40 +3278,58 @@ var NumberRenderer = ({
3244
3278
  const max = fieldSchema?.maximum;
3245
3279
  const step = isInteger ? 1 : fieldSchema?.multipleOf ?? "any";
3246
3280
  const tooltip = [label, description, hasError ? errors : null].filter(Boolean).join(" \u2014 ");
3247
- return /* @__PURE__ */ jsxs(
3248
- "div",
3281
+ const surface = (config ?? {}).surface ?? "form";
3282
+ const scale = scaleFor(surface);
3283
+ const input = /* @__PURE__ */ jsx(
3284
+ "input",
3249
3285
  {
3250
- className: `ss-jsonforms-field ss-jsonforms-number flex h-8 shrink-0 items-center gap-1.5 rounded-full border px-2.5 text-xs font-medium transition-colors focus-within:border-primary/40 ${hasError ? "border-destructive" : "border-border/70"} ${isDisabled ? "opacity-60" : ""}`,
3251
- title: tooltip || void 0,
3252
- children: [
3253
- label && /* @__PURE__ */ jsxs(
3254
- "label",
3255
- {
3256
- htmlFor: `number-${path2}`,
3257
- className: `whitespace-nowrap ${hasError ? "text-destructive" : "text-muted-foreground"}`,
3258
- children: [
3259
- label,
3260
- required && /* @__PURE__ */ jsx("span", { className: "ml-1 text-destructive", children: "*" })
3261
- ]
3262
- }
3263
- ),
3264
- /* @__PURE__ */ jsx(
3265
- "input",
3266
- {
3267
- id: `number-${path2}`,
3268
- type: "number",
3269
- value: data ?? "",
3270
- onChange: handleInputChange,
3271
- disabled: isDisabled,
3272
- min,
3273
- max,
3274
- step,
3275
- className: "w-14 border-0 bg-transparent p-0 text-xs font-medium tabular-nums text-foreground outline-none disabled:cursor-not-allowed"
3276
- }
3277
- )
3278
- ]
3286
+ id: `number-${path2}`,
3287
+ type: "number",
3288
+ value: data ?? "",
3289
+ onChange: handleInputChange,
3290
+ disabled: isDisabled,
3291
+ min,
3292
+ max,
3293
+ step,
3294
+ className: surface === "bar" ? "w-14 border-0 bg-transparent p-0 text-xs font-medium tabular-nums text-foreground outline-none disabled:cursor-not-allowed" : fieldNumberClass(scale, hasError)
3279
3295
  }
3280
3296
  );
3297
+ if (surface === "bar") {
3298
+ return /* @__PURE__ */ jsxs(
3299
+ "div",
3300
+ {
3301
+ className: `ss-jsonforms-field ss-jsonforms-number ${pillClass({
3302
+ hasError,
3303
+ disabled: isDisabled
3304
+ })}`,
3305
+ title: tooltip || void 0,
3306
+ children: [
3307
+ label && /* @__PURE__ */ jsxs(
3308
+ "label",
3309
+ {
3310
+ htmlFor: `number-${path2}`,
3311
+ className: `${pillLabelClass} whitespace-nowrap ${hasError ? "text-destructive" : "text-muted-foreground"}`,
3312
+ children: [
3313
+ label,
3314
+ required && /* @__PURE__ */ jsx("span", { className: "ml-1 text-destructive", children: "*" })
3315
+ ]
3316
+ }
3317
+ ),
3318
+ input
3319
+ ]
3320
+ }
3321
+ );
3322
+ }
3323
+ return /* @__PURE__ */ jsxs("div", { className: "ss-jsonforms-field ss-jsonforms-number", children: [
3324
+ /* @__PURE__ */ jsxs("div", { className: fieldRowClass, children: [
3325
+ /* @__PURE__ */ jsxs("label", { htmlFor: `number-${path2}`, className: fieldRowLabelClass(scale), children: [
3326
+ label,
3327
+ required && /* @__PURE__ */ jsx("span", { className: "ml-1 text-destructive", children: "*" })
3328
+ ] }),
3329
+ input
3330
+ ] }),
3331
+ hasError && /* @__PURE__ */ jsx("div", { className: fieldErrorClass, children: errors })
3332
+ ] });
3281
3333
  };
3282
3334
  var numberRendererTester = rankWith(
3283
3335
  40,
@@ -3293,6 +3345,14 @@ var numberRendererTester = rankWith(
3293
3345
  }
3294
3346
  );
3295
3347
  var NumberRendererControl = withJsonFormsControlProps(NumberRenderer);
3348
+ var SCALE = {
3349
+ comfortable: { lineHeight: 20, padding: 8 },
3350
+ dense: { lineHeight: 16, padding: 6 }
3351
+ };
3352
+ var rowsToPx = (rows, scale) => rows * scale.lineHeight + scale.padding * 2 + 2;
3353
+ var MAX_VIEWPORT_SHARE = 0.5;
3354
+ var DEFAULT_MIN_ROWS = 3;
3355
+ var DEFAULT_MAX_ROWS = 9;
3296
3356
  var TextareaRenderer = ({
3297
3357
  data,
3298
3358
  handleChange,
@@ -3304,28 +3364,49 @@ var TextareaRenderer = ({
3304
3364
  uischema,
3305
3365
  visible,
3306
3366
  enabled,
3307
- required
3367
+ required,
3368
+ config
3308
3369
  }) => {
3309
3370
  const textareaRef = useRef(null);
3371
+ const textareaOptions = schema["ui:textarea"] ?? {};
3372
+ const formConfig = config ?? {};
3373
+ const scaleName = scaleFor(formConfig.surface ?? "form");
3374
+ const scale = SCALE[scaleName];
3375
+ const minRows = textareaOptions.minRows ?? formConfig.minRows ?? DEFAULT_MIN_ROWS;
3376
+ const maxRows = Math.max(
3377
+ minRows,
3378
+ textareaOptions.maxRows ?? formConfig.maxRows ?? DEFAULT_MAX_ROWS
3379
+ );
3380
+ const minHeight = rowsToPx(minRows, scale);
3381
+ const maxHeight = rowsToPx(maxRows, scale);
3382
+ const [viewportCap, setViewportCap] = useState(
3383
+ () => typeof window === "undefined" ? Number.POSITIVE_INFINITY : Math.round(window.innerHeight * MAX_VIEWPORT_SHARE)
3384
+ );
3385
+ const ceiling = Math.max(minHeight, Math.min(maxHeight, viewportCap));
3310
3386
  const autoResize = useCallback(() => {
3311
- if (textareaRef.current) {
3312
- textareaRef.current.style.height = "auto";
3313
- textareaRef.current.style.height = `${Math.min(
3314
- Math.max(textareaRef.current.scrollHeight, 80),
3315
- // Minimum height of 80px
3316
- 240
3317
- // Maximum height of 240px
3318
- )}px`;
3319
- }
3320
- }, []);
3387
+ const el = textareaRef.current;
3388
+ if (!el) return;
3389
+ el.style.height = "auto";
3390
+ el.style.height = `${Math.min(
3391
+ Math.max(el.scrollHeight, minHeight),
3392
+ ceiling
3393
+ )}px`;
3394
+ }, [minHeight, ceiling]);
3321
3395
  useEffect(() => {
3322
3396
  autoResize();
3323
3397
  }, [data, autoResize]);
3398
+ useEffect(() => {
3399
+ const onResize = () => {
3400
+ setViewportCap(Math.round(window.innerHeight * MAX_VIEWPORT_SHARE));
3401
+ autoResize();
3402
+ };
3403
+ window.addEventListener("resize", onResize);
3404
+ return () => window.removeEventListener("resize", onResize);
3405
+ }, [autoResize]);
3324
3406
  const handleInputChange = useCallback(
3325
3407
  (event) => {
3326
- const newValue = event.target.value;
3327
- handleChange(path2, newValue);
3328
- setTimeout(autoResize, 0);
3408
+ handleChange(path2, event.target.value);
3409
+ autoResize();
3329
3410
  },
3330
3411
  [handleChange, path2, autoResize]
3331
3412
  );
@@ -3335,89 +3416,34 @@ var TextareaRenderer = ({
3335
3416
  const readOnly = uischema?.access === "Read";
3336
3417
  const isDisabled = !enabled || readOnly;
3337
3418
  const hasError = errors && errors.length > 0;
3338
- const textareaOptions = schema["ui:textarea"] ?? {};
3339
3419
  const placeholder = textareaOptions.placeholder || schema?.description || `Enter ${label?.toLowerCase() || "text"}...`;
3340
- const minRows = textareaOptions.minRows || 3;
3341
3420
  return /* @__PURE__ */ jsxs("div", { className: "ss-jsonforms-field ss-jsonforms-textarea", children: [
3342
- label && /* @__PURE__ */ jsxs(
3343
- "label",
3344
- {
3345
- style: {
3346
- display: "block",
3347
- color: hasError ? "#ef4444" : "#475569",
3348
- fontSize: "0.875rem",
3349
- fontWeight: 500,
3350
- marginBottom: "0.375rem"
3351
- },
3352
- children: [
3353
- label,
3354
- required && /* @__PURE__ */ jsx("span", { style: { color: "#ef4444", marginLeft: "0.25rem" }, children: "*" })
3355
- ]
3356
- }
3357
- ),
3358
- description && /* @__PURE__ */ jsx(
3359
- "div",
3360
- {
3361
- style: {
3362
- color: "#6b7280",
3363
- fontSize: "0.75rem",
3364
- marginBottom: "0.5rem"
3365
- },
3366
- children: description
3367
- }
3368
- ),
3421
+ label && /* @__PURE__ */ jsxs("label", { htmlFor: path2, className: fieldLabelClass(scaleName), children: [
3422
+ label,
3423
+ required && /* @__PURE__ */ jsx("span", { className: "ml-1 text-destructive", children: "*" })
3424
+ ] }),
3425
+ description && /* @__PURE__ */ jsx("div", { className: fieldHintClass, children: description }),
3369
3426
  /* @__PURE__ */ jsx(
3370
3427
  "textarea",
3371
3428
  {
3429
+ id: path2,
3372
3430
  ref: textareaRef,
3373
3431
  value: data || "",
3374
3432
  onChange: handleInputChange,
3375
3433
  placeholder,
3376
3434
  disabled: isDisabled,
3377
3435
  rows: minRows,
3436
+ className: `resize-y ${fieldControlClass(scaleName, !!hasError)}`,
3378
3437
  style: {
3379
- width: "100%",
3380
- minHeight: "80px",
3381
- maxHeight: "240px",
3382
- resize: "vertical",
3383
- padding: "0.75rem",
3384
- border: hasError ? "2px solid #ef4444" : "1px solid #d1d5db",
3385
- borderRadius: "6px",
3386
- fontSize: "16px",
3387
- lineHeight: "1.5",
3388
- fontFamily: "inherit",
3389
- backgroundColor: isDisabled ? "#f9fafb" : "#ffffff",
3390
- color: isDisabled ? "#9ca3af" : "#111827",
3391
- outline: "none",
3392
- transition: "border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out",
3393
- boxShadow: hasError ? "0 0 0 1px #ef4444" : "none",
3438
+ minHeight: `${minHeight}px`,
3439
+ maxHeight: `${ceiling}px`,
3440
+ // iOS zooms a focused control under 16px; the design's fields are
3441
+ // 14px, so opt out of the adjustment rather than the design.
3394
3442
  WebkitTextSizeAdjust: "100%"
3395
- },
3396
- onFocus: (e) => {
3397
- if (!hasError) {
3398
- e.target.style.borderColor = "#6366f1";
3399
- e.target.style.boxShadow = "0 0 0 1px #6366f1";
3400
- }
3401
- },
3402
- onBlur: (e) => {
3403
- if (!hasError) {
3404
- e.target.style.borderColor = "#d1d5db";
3405
- e.target.style.boxShadow = "none";
3406
- }
3407
3443
  }
3408
3444
  }
3409
3445
  ),
3410
- hasError && /* @__PURE__ */ jsx(
3411
- "div",
3412
- {
3413
- style: {
3414
- color: "#ef4444",
3415
- fontSize: "0.75rem",
3416
- marginTop: "0.25rem"
3417
- },
3418
- children: errors
3419
- }
3420
- )
3446
+ hasError && /* @__PURE__ */ jsx("div", { className: fieldErrorClass, children: errors })
3421
3447
  ] });
3422
3448
  };
3423
3449
  var textareaRendererTester = rankWith(
@@ -3469,10 +3495,25 @@ var renderers = [
3469
3495
  ];
3470
3496
 
3471
3497
  // src/chat-variables/VariablesForm.vm.ts
3498
+ var MAX_INLINE_VARIABLES = 3;
3499
+ var isModelSelector = (schema) => schema.title === "ModelId" || schema["x-model-selector"] === true;
3500
+ function rowLayout(controls) {
3501
+ const innerRow = {
3502
+ type: "HorizontalLayout",
3503
+ elements: controls,
3504
+ options: { gap: "12px", alignItems: "flex-start" }
3505
+ };
3506
+ const ui = {
3507
+ type: "VerticalLayout",
3508
+ elements: [innerRow]
3509
+ };
3510
+ return ui;
3511
+ }
3472
3512
  function buildSimpleSchemaAndUi(vars, threadVars, useDefaults) {
3473
3513
  const names = Object.keys(vars || {});
3474
3514
  const properties2 = {};
3475
3515
  const controls = [];
3516
+ const inlineOnly = [];
3476
3517
  const initialData = {};
3477
3518
  const $defs = {};
3478
3519
  for (const name of names) {
@@ -3492,19 +3533,24 @@ function buildSimpleSchemaAndUi(vars, threadVars, useDefaults) {
3492
3533
  control.enabled = false;
3493
3534
  }
3494
3535
  controls.push(control);
3536
+ if (isModelSelector(properties2[name])) inlineOnly.push(control);
3495
3537
  }
3496
3538
  const schema = { type: "object", properties: properties2 };
3497
3539
  if (Object.keys($defs).length > 0) schema.$defs = $defs;
3498
- const innerRow = {
3499
- type: "HorizontalLayout",
3500
- elements: controls,
3501
- options: { gap: "12px", alignItems: "flex-start" }
3502
- };
3503
- const ui = {
3504
- type: "VerticalLayout",
3505
- elements: [innerRow]
3540
+ if (controls.length <= MAX_INLINE_VARIABLES) {
3541
+ return {
3542
+ schema,
3543
+ inlineControls: controls,
3544
+ overflowControls: [],
3545
+ initialData
3546
+ };
3547
+ }
3548
+ return {
3549
+ schema,
3550
+ inlineControls: inlineOnly,
3551
+ overflowControls: controls.filter((c) => !inlineOnly.includes(c)),
3552
+ initialData
3506
3553
  };
3507
- return { schema, uiSchema: ui, initialData };
3508
3554
  }
3509
3555
  function useChatVariablesFormVm({
3510
3556
  workspace,
@@ -3519,26 +3565,26 @@ function useChatVariablesFormVm({
3519
3565
  const { mutate: updateVariableMutation } = useUpdateFlowRunVariable();
3520
3566
  const querySettled = !isLoading && (threadVars !== void 0 || isError);
3521
3567
  const shouldUseDefaults = isError || threadVars && Object.keys(threadVars).length === 0;
3522
- const built = React8.useMemo(() => {
3568
+ const built = React9.useMemo(() => {
3523
3569
  return buildSimpleSchemaAndUi(
3524
3570
  workspace.variables,
3525
3571
  threadVars,
3526
3572
  shouldUseDefaults ?? false
3527
3573
  );
3528
3574
  }, [workspace.variables, threadVars, shouldUseDefaults]);
3529
- const [data, setData] = React8.useState(null);
3530
- React8.useEffect(() => {
3575
+ const [data, setData] = React9.useState(null);
3576
+ React9.useEffect(() => {
3531
3577
  if (querySettled) {
3532
3578
  setData(built.initialData);
3533
3579
  setVariables(built.initialData);
3534
3580
  }
3535
3581
  }, [querySettled, built.initialData, setVariables]);
3536
- const ajv = React8.useMemo(() => createAjv({ useDefaults: false }), []);
3537
- const prevRef = React8.useRef(null);
3538
- React8.useEffect(() => {
3582
+ const ajv = React9.useMemo(() => createAjv({ useDefaults: false }), []);
3583
+ const prevRef = React9.useRef(null);
3584
+ React9.useEffect(() => {
3539
3585
  prevRef.current = data;
3540
3586
  }, [data]);
3541
- const onChange = React8.useCallback(
3587
+ const onChange = React9.useCallback(
3542
3588
  ({ data: next2 }) => {
3543
3589
  if (prevRef.current && !isDraftThreadId(threadId)) {
3544
3590
  const keys2 = Object.keys(workspace.variables || {});
@@ -3559,29 +3605,96 @@ function useChatVariablesFormVm({
3559
3605
  },
3560
3606
  [workspace.variables, setVariables, updateVariableMutation, threadId]
3561
3607
  );
3562
- const config = React8.useMemo(
3608
+ const barConfig = React9.useMemo(
3563
3609
  () => ({
3564
3610
  restrict: true,
3565
3611
  trim: false,
3566
3612
  showUnfocusedDescription: true,
3567
- hideRequiredAsterisk: true
3613
+ hideRequiredAsterisk: true,
3614
+ surface: "bar",
3615
+ minRows: 1,
3616
+ maxRows: 6
3568
3617
  }),
3569
3618
  []
3570
3619
  );
3620
+ const panelConfig = React9.useMemo(
3621
+ () => ({ ...barConfig, surface: "panel" }),
3622
+ [barConfig]
3623
+ );
3624
+ const inlineUiSchema = React9.useMemo(
3625
+ () => built.inlineControls.length ? rowLayout(built.inlineControls) : null,
3626
+ [built.inlineControls]
3627
+ );
3628
+ const overflowUiSchema = React9.useMemo(
3629
+ () => built.overflowControls.length ? rowLayout(built.overflowControls) : null,
3630
+ [built.overflowControls]
3631
+ );
3571
3632
  return {
3572
3633
  schema: built.schema,
3573
- uiSchema: built.uiSchema,
3634
+ inlineUiSchema,
3635
+ overflowUiSchema,
3636
+ overflowCount: built.overflowControls.length,
3574
3637
  data,
3575
3638
  renderers,
3576
3639
  cells,
3577
3640
  ajv,
3578
3641
  onChange,
3579
- config,
3642
+ barConfig,
3643
+ panelConfig,
3580
3644
  isLoading,
3581
3645
  isReady: querySettled,
3582
3646
  isHydrated: data !== null
3583
3647
  };
3584
3648
  }
3649
+ function VariablesOverflowPanel({ count, children: children2 }) {
3650
+ const triggerRef = useRef(null);
3651
+ const panelRef = useRef(null);
3652
+ const { isOpen, close, toggle, renderPopover } = useAnchoredPopover({
3653
+ trigger: triggerRef,
3654
+ popover: panelRef,
3655
+ width: POPOVER_WIDTH_PX,
3656
+ maxHeight: POPOVER_MAX_HEIGHT_PX,
3657
+ role: "dialog",
3658
+ label: "Workspace variables"
3659
+ });
3660
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3661
+ /* @__PURE__ */ jsxs(
3662
+ "button",
3663
+ {
3664
+ ref: triggerRef,
3665
+ type: "button",
3666
+ onClick: toggle,
3667
+ "aria-expanded": isOpen,
3668
+ "aria-haspopup": "dialog",
3669
+ "aria-label": `Variables (${count})`,
3670
+ className: `flex h-8 shrink-0 items-center gap-1.5 rounded-full border px-2.5 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary ${isOpen ? "border-primary/30 bg-primary/10 text-primary" : "border-border/70 bg-transparent text-muted-foreground hover:bg-secondary"}`,
3671
+ children: [
3672
+ /* @__PURE__ */ jsx(SlidersHorizontal, { className: "h-3.5 w-3.5 shrink-0" }),
3673
+ /* @__PURE__ */ jsx("span", { className: "inline max-sm:hidden", children: "Variables" }),
3674
+ /* @__PURE__ */ jsx("span", { className: "rounded-full bg-secondary px-1.5 text-[10px] leading-4 tabular-nums", children: count })
3675
+ ]
3676
+ }
3677
+ ),
3678
+ renderPopover(
3679
+ /* @__PURE__ */ jsxs(Fragment, { children: [
3680
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-between border-b border-border px-3 py-2", children: [
3681
+ /* @__PURE__ */ jsx("span", { className: popoverHeadingClass, children: "Variables" }),
3682
+ /* @__PURE__ */ jsx(
3683
+ "button",
3684
+ {
3685
+ type: "button",
3686
+ onClick: close,
3687
+ "aria-label": "Close variables",
3688
+ className: "inline-flex h-5 w-5 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground",
3689
+ children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
3690
+ }
3691
+ )
3692
+ ] }),
3693
+ /* @__PURE__ */ jsx("div", { className: "ss-variables-panel min-h-0 overflow-y-auto p-3", children: children2 })
3694
+ ] })
3695
+ )
3696
+ ] });
3697
+ }
3585
3698
  var ChatVariablesForm = forwardRef(({ workspace, threadId, setVariables }, ref) => {
3586
3699
  const vm = useChatVariablesFormVm({ workspace, threadId, setVariables });
3587
3700
  useImperativeHandle(ref, () => ({
@@ -3597,19 +3710,32 @@ var ChatVariablesForm = forwardRef(({ workspace, threadId, setVariables }, ref)
3597
3710
  if (!vm.isHydrated) {
3598
3711
  return /* @__PURE__ */ jsx("div", { className: "flex justify-center items-center w-full h-8", children: /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin text-primary" }) });
3599
3712
  }
3600
- return /* @__PURE__ */ jsx("div", { className: "w-full jsonforms-compact", children: /* @__PURE__ */ jsx(
3601
- JsonForms,
3602
- {
3603
- schema: vm.schema,
3604
- uischema: vm.uiSchema,
3605
- data: vm.data,
3606
- renderers: vm.renderers,
3607
- cells: vm.cells,
3608
- ajv: vm.ajv,
3609
- onChange: vm.onChange,
3610
- config: vm.config
3611
- }
3612
- ) });
3713
+ const formProps = {
3714
+ schema: vm.schema,
3715
+ data: vm.data,
3716
+ renderers: vm.renderers,
3717
+ cells: vm.cells,
3718
+ ajv: vm.ajv,
3719
+ onChange: vm.onChange
3720
+ };
3721
+ return /* @__PURE__ */ jsxs("div", { className: "flex w-full min-w-0 items-center gap-1", children: [
3722
+ vm.inlineUiSchema && /* @__PURE__ */ jsx("div", { className: "min-w-0 jsonforms-compact", children: /* @__PURE__ */ jsx(
3723
+ JsonForms,
3724
+ {
3725
+ ...formProps,
3726
+ uischema: vm.inlineUiSchema,
3727
+ config: vm.barConfig
3728
+ }
3729
+ ) }),
3730
+ vm.overflowUiSchema && /* @__PURE__ */ jsx(VariablesOverflowPanel, { count: vm.overflowCount, children: /* @__PURE__ */ jsx("div", { className: "jsonforms-compact", children: /* @__PURE__ */ jsx(
3731
+ JsonForms,
3732
+ {
3733
+ ...formProps,
3734
+ uischema: vm.overflowUiSchema,
3735
+ config: vm.panelConfig
3736
+ }
3737
+ ) }) })
3738
+ ] });
3613
3739
  });
3614
3740
 
3615
3741
  // src/domains/workspaces/queryKeys.ts
@@ -4081,7 +4207,7 @@ function MessageComposer(_props = {}) {
4081
4207
  disabled,
4082
4208
  placeholder: "What would you like to do?",
4083
4209
  className: "md-editor--bare px-5 pb-3 pt-4 text-sm",
4084
- minHeight: 48
4210
+ minHeight: 24
4085
4211
  },
4086
4212
  `composer-md-${editorKey}`
4087
4213
  ) }),
@@ -18944,6 +19070,79 @@ var getMessageErrorText = (error) => {
18944
19070
  }
18945
19071
  return STATUS_CODE_TEXT[error.code] ?? GENERIC_ERROR_TEXT;
18946
19072
  };
19073
+ var FileInfoSchema = z.object({
19074
+ id: z.string(),
19075
+ name: z.string()
19076
+ });
19077
+ z.object({
19078
+ workspaceId: z.string().optional(),
19079
+ threadId: z.string().optional()
19080
+ });
19081
+
19082
+ // src/domains/messages/schemas.ts
19083
+ var MessageResponseSourceSchema = z.object({
19084
+ index: z.number(),
19085
+ datasetItemId: z.string().optional(),
19086
+ containerItemId: z.string().nullish(),
19087
+ flowRunId: z.string().optional(),
19088
+ file: FileInfoSchema.nullish(),
19089
+ url: z.string().nullish(),
19090
+ sourceType: z.nativeEnum(MessageResponseSourceType),
19091
+ // WS3c citation grounding (additive; absent on older responses).
19092
+ uri: z.string().nullish(),
19093
+ citedText: z.string().nullish(),
19094
+ attribution: z.nativeEnum(MessageAttribution).nullish(),
19095
+ // Where the cited item lives at its source (SharePoint web link, HubSpot record page).
19096
+ // Distinct from `url` (the source *is* that URL): this rides File sources so the card
19097
+ // can offer "open at source" beside the download of our copy. Absent when unknown.
19098
+ webUrl: z.string().nullish()
19099
+ });
19100
+ var MessageResponseSchema = z.object({
19101
+ content: z.string(),
19102
+ messageId: z.string(),
19103
+ sources: z.array(MessageResponseSourceSchema).nullish(),
19104
+ isReplying: z.boolean().nullish().default(false),
19105
+ requestedJsonSchema: z.string().nullish()
19106
+ });
19107
+ var MessageErrorMessageSchema = z.object({
19108
+ code: z.number(),
19109
+ // Stable machine-readable category (e.g. "llm.rate_limit"). Accept both
19110
+ // spellings: app-api serialises camelCase, the ai-api origin field is
19111
+ // snake_case — the mapper coalesces them.
19112
+ errorCode: z.string().nullish(),
19113
+ error_code: z.string().nullish(),
19114
+ message: z.string().nullish(),
19115
+ data: z.string().nullish(),
19116
+ blockId: z.string().nullish()
19117
+ });
19118
+ var MessageSchema = z.object({
19119
+ id: z.string().nullish(),
19120
+ createdAt: DateFromApi,
19121
+ createdBy: z.string().nullish(),
19122
+ hasComments: z.boolean().default(false),
19123
+ createdByUserId: z.string().nullish(),
19124
+ messageThreadId: z.string().nullish(),
19125
+ errors: z.array(MessageErrorMessageSchema).nullish(),
19126
+ values: z.array(
19127
+ z.object({
19128
+ id: z.string(),
19129
+ name: z.string(),
19130
+ type: z.nativeEnum(MessageValueType),
19131
+ value: z.any(),
19132
+ // Can be string (for Output), array (for Input), or object (for Variables)
19133
+ channels: z.record(z.string(), z.number()),
19134
+ createdAt: DateFromApi,
19135
+ createdBy: z.string(),
19136
+ createdByUserId: z.string().nullish()
19137
+ })
19138
+ ).nullish(),
19139
+ optimistic: z.boolean().optional().default(false)
19140
+ });
19141
+ z.object({
19142
+ text: z.string().nullish(),
19143
+ image: FileInfoSchema.nullish()
19144
+ });
19145
+ z.array(MessageSchema);
18947
19146
 
18948
19147
  // src/domains/messages/statuses.ts
18949
19148
  var asRecord = (value) => {
@@ -19087,7 +19286,7 @@ var buttonVariants = cva(
19087
19286
  }
19088
19287
  }
19089
19288
  );
19090
- var Button = React8.forwardRef(
19289
+ var Button = React9.forwardRef(
19091
19290
  ({ className, variant, size, asChild = false, ...props }, ref) => {
19092
19291
  const Comp = asChild ? Slot : "button";
19093
19292
  return /* @__PURE__ */ jsx(
@@ -19638,6 +19837,7 @@ function ChatMessageSources({
19638
19837
  ] })
19639
19838
  ] });
19640
19839
  }
19840
+ var USER_FORM_CONFIG = { surface: "form", minRows: 6, maxRows: 20 };
19641
19841
  var REVEAL_ON_HOVER = "opacity-100 focus-visible:opacity-100 [@media(hover:hover)]:opacity-0 [@media(hover:hover)]:group-hover:opacity-100";
19642
19842
  var MessageBubble = (props) => {
19643
19843
  const {
@@ -19691,7 +19891,7 @@ var MessageBubble = (props) => {
19691
19891
  );
19692
19892
  })
19693
19893
  ] }),
19694
- showForm && /* @__PURE__ */ jsxs("div", { className: "mt-4 border-t border-border pt-4", children: [
19894
+ showForm && /* @__PURE__ */ jsxs("div", { className: "ss-chat-message__user-form mt-4 border-t border-border pt-4", children: [
19695
19895
  /* @__PURE__ */ jsx(
19696
19896
  JsonForms,
19697
19897
  {
@@ -19700,6 +19900,7 @@ var MessageBubble = (props) => {
19700
19900
  renderers,
19701
19901
  cells,
19702
19902
  readonly: userInput !== void 0,
19903
+ config: USER_FORM_CONFIG,
19703
19904
  onChange: ({ data, errors }) => {
19704
19905
  setResponseFormData(data);
19705
19906
  setResponseFormValid(!errors?.length);
@@ -19832,6 +20033,10 @@ function coerceSources(x) {
19832
20033
  if (!Array.isArray(x)) return [];
19833
20034
  return x.filter(isMessageResponseSource);
19834
20035
  }
20036
+ var ENVELOPE_KEYS = Object.keys(MessageResponseSchema.shape);
20037
+ function isResponseEnvelope(keys2) {
20038
+ return keys2.length > 0 && keys2.every((key) => ENVELOPE_KEYS.includes(key));
20039
+ }
19835
20040
  var MessageItem = ({
19836
20041
  message,
19837
20042
  isLive = false
@@ -19939,9 +20144,16 @@ var MessageItem = ({
19939
20144
  });
19940
20145
  } else if (name === "response" && typeof v.value === "object" && v.value !== null && !Array.isArray(v.value)) {
19941
20146
  const resp = v.value;
19942
- const isContentPart = "text" in resp || "image" in resp;
19943
- pushContent(groupContent, isContentPart ? resp : resp.content);
19944
- groupSources = coerceSources(resp.sources);
20147
+ const keys2 = Object.keys(resp);
20148
+ const isEnvelope = isResponseEnvelope(keys2);
20149
+ if ("sources" in resp && (isEnvelope || "text" in resp || "image" in resp)) {
20150
+ groupSources = coerceSources(resp.sources);
20151
+ }
20152
+ if (isEnvelope) {
20153
+ pushContent(groupContent, resp.content);
20154
+ } else if (keys2.length > 0) {
20155
+ pushContent(groupContent, resp);
20156
+ }
19945
20157
  } else {
19946
20158
  pushContent(groupContent, v.value);
19947
20159
  }
@@ -20167,6 +20379,7 @@ function MessageList({
20167
20379
  ] }) });
20168
20380
  }
20169
20381
  if (safeMessages.length === 0 && !hadMessagesBefore) {
20382
+ const descriptionParagraphs = (activeWorkspace?.summary ?? "").split(/\n+/).map((paragraph2) => paragraph2.trim()).filter(Boolean);
20170
20383
  return (
20171
20384
  // A new thread opens the way the design does: the greeting and the
20172
20385
  // composer travel together as one narrower block centred in the canvas.
@@ -20179,6 +20392,14 @@ function MessageList({
20179
20392
  "data-ss-layer": "message-list",
20180
20393
  children: /* @__PURE__ */ jsxs("div", { className: "mx-auto mb-6 w-full max-w-2xl px-4 text-center", children: [
20181
20394
  /* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold text-foreground", children: "What\u2019s on the agenda today?" }),
20395
+ descriptionParagraphs.length > 0 && /* @__PURE__ */ jsx(
20396
+ "div",
20397
+ {
20398
+ className: "mx-auto mt-2 max-w-lg space-y-1.5 text-sm text-muted-foreground",
20399
+ "data-ss-layer": "workspace-description",
20400
+ children: descriptionParagraphs.map((paragraph2, index) => /* @__PURE__ */ jsx("p", { children: paragraph2 }, index))
20401
+ }
20402
+ ),
20182
20403
  activeWorkspace?.firstPrompt && /* @__PURE__ */ jsx("div", { className: "chat-prose mt-3 text-center", children: /* @__PURE__ */ jsx(MessageMarkdown, { value: activeWorkspace.firstPrompt }) })
20183
20404
  ] })
20184
20405
  }