@tangle-network/agent-app 0.46.6 → 0.46.7

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.
@@ -51,17 +51,21 @@ export declare function ComposerBand({ bandRef, resetKey, children, }: {
51
51
  export interface OptionChoice {
52
52
  value: ModelOptionValue;
53
53
  label: string;
54
+ icon?: LucideIcon;
54
55
  }
55
56
  /** A standalone enum picker using the studio composer's pill and menu grammar. */
56
- export declare function MenuPill<T extends string>({ label, value, choices, onSelect, className, }: {
57
+ export declare function MenuPill<T extends string>({ label, value, choices, onSelect, className, icon: Icon, trigger, }: {
57
58
  label: string;
58
59
  value: T;
59
60
  choices: readonly {
60
61
  value: T;
61
62
  label: string;
63
+ icon?: LucideIcon;
62
64
  }[];
63
65
  onSelect: (value: T) => void;
64
66
  className?: string;
67
+ icon?: LucideIcon;
68
+ trigger?: 'pill' | 'text';
65
69
  }): JSX.Element;
66
70
  /**
67
71
  * A value pill and the menu it opens.
@@ -71,12 +75,13 @@ export declare function MenuPill<T extends string>({ label, value, choices, onSe
71
75
  * and "5s" alone tells a screen-reader user nothing about which parameter it
72
76
  * belongs to.
73
77
  */
74
- export declare function OptionPill({ label, value, choices, onSelect, bandRef, custom, }: {
78
+ export declare function OptionPill({ label, value, choices, onSelect, bandRef, custom, icon: Icon, }: {
75
79
  label: string;
76
80
  value: ModelOptionValue | undefined;
77
81
  choices: readonly OptionChoice[];
78
82
  onSelect: (value: ModelOptionValue) => void;
79
83
  bandRef: RefObject<HTMLDivElement | null>;
84
+ icon?: LucideIcon;
80
85
  /** A trailing row that swaps the menu to a form (the gpt-image-2 custom
81
86
  * size). Absent for every parameter whose values are an enum. */
82
87
  custom?: {
@@ -4,10 +4,9 @@
4
4
  *
5
5
  * A chat card sets the expectation that the thing on the other side remembers
6
6
  * the conversation. This one does not, and the cost of learning that by
7
- * experiment is a wasted generation. So the notice sits above the composer as a
8
- * statement of fact rather than a warning `text-foreground`, not muted, since
9
- * a rule the reader must know before typing cannot be the quietest text on the
10
- * page.
7
+ * experiment is a wasted generation. The chip is a soft brand-tinted hint: its
8
+ * primary-tinted surface and primary icon keep it noticeable, while the hard
9
+ * border and shadow read as an alert and were cut after gtm QA (issue #465).
11
10
  *
12
11
  * The icon is INLINE in the text flow rather than a flex sibling, so a narrow
13
12
  * viewport wraps it with the sentence instead of stranding a lone glyph beside
@@ -108,7 +108,22 @@ function useStudioGenerations(loaderGenerations, options = {}) {
108
108
 
109
109
  // src/studio-react/studio-composer.tsx
110
110
  import { useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2, useState as useState3 } from "react";
111
- import { AudioLines, ArrowUp, Image as ImageIcon, TriangleAlert as TriangleAlert2, Video } from "lucide-react";
111
+ import {
112
+ AudioLines,
113
+ ArrowUp,
114
+ Clock,
115
+ Copy,
116
+ Gauge,
117
+ Image as ImageIcon,
118
+ Mic,
119
+ Monitor,
120
+ Ratio,
121
+ Scaling,
122
+ SlidersHorizontal,
123
+ Sparkles,
124
+ TriangleAlert as TriangleAlert2,
125
+ Video
126
+ } from "lucide-react";
112
127
 
113
128
  // src/studio-react/composer-option-controls.tsx
114
129
  import {
@@ -120,6 +135,7 @@ import {
120
135
  import { ImagePlus, TriangleAlert, Volume2, VolumeX, X } from "lucide-react";
121
136
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
122
137
  var PILL = "inline-flex h-7 flex-none items-center gap-1.5 whitespace-nowrap rounded-full border border-border bg-card px-2.5 text-[12.5px] font-medium text-foreground transition hover:bg-accent";
138
+ var PILL_LABEL = "[text-box:trim-both_cap_alphabetic]";
123
139
  var MENU_PANEL = `flex min-w-[184px] flex-col overflow-y-auto rounded-xl border border-border bg-popover p-1 text-popover-foreground ${OVERLAY_SHADOW}`;
124
140
  var MENU_HEADER = "px-2.5 pb-1 pt-1.5 text-[10.5px] font-semibold uppercase tracking-[0.08em] text-muted-foreground";
125
141
  function menuRowClass(selected) {
@@ -223,28 +239,34 @@ function MenuRows({
223
239
  choices,
224
240
  onSelect
225
241
  }) {
226
- return choices.map((choice) => /* @__PURE__ */ jsxs(
227
- "button",
228
- {
229
- type: "button",
230
- role: "menuitemradio",
231
- "aria-checked": choice.value === value,
232
- onClick: () => onSelect(choice.value),
233
- className: menuRowClass(choice.value === value),
234
- children: [
235
- /* @__PURE__ */ jsx("span", { className: "truncate", children: choice.label }),
236
- choice.value === value && /* @__PURE__ */ jsx(CheckGlyph, { className: "ml-auto h-3.5 w-3.5 shrink-0 text-primary" })
237
- ]
238
- },
239
- String(choice.value)
240
- ));
242
+ return choices.map((choice) => {
243
+ const Icon = choice.icon;
244
+ return /* @__PURE__ */ jsxs(
245
+ "button",
246
+ {
247
+ type: "button",
248
+ role: "menuitemradio",
249
+ "aria-checked": choice.value === value,
250
+ onClick: () => onSelect(choice.value),
251
+ className: menuRowClass(choice.value === value),
252
+ children: [
253
+ Icon && /* @__PURE__ */ jsx(Icon, { "aria-hidden": true, className: "h-3.5 w-3.5 shrink-0", strokeWidth: 1.5 }),
254
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: choice.label }),
255
+ choice.value === value && /* @__PURE__ */ jsx(CheckGlyph, { className: "ml-auto h-3.5 w-3.5 shrink-0 text-primary" })
256
+ ]
257
+ },
258
+ String(choice.value)
259
+ );
260
+ });
241
261
  }
242
262
  function MenuPill({
243
263
  label,
244
264
  value,
245
265
  choices,
246
266
  onSelect,
247
- className
267
+ className,
268
+ icon: Icon,
269
+ trigger = "pill"
248
270
  }) {
249
271
  const [open, setOpen] = useState2(false);
250
272
  const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen);
@@ -260,10 +282,11 @@ function MenuPill({
260
282
  title: label,
261
283
  "aria-label": label,
262
284
  onClick: () => setOpen(!open),
263
- className: `${PILL} ${className ?? ""}`,
285
+ className: `${trigger === "text" ? "inline-flex h-7 flex-none items-center gap-1 whitespace-nowrap rounded-full px-2 text-[12.5px] font-medium text-primary transition hover:bg-accent" : PILL} ${className ?? ""}`,
264
286
  children: [
265
- /* @__PURE__ */ jsx("span", { children: selected?.label ?? "\u2014" }),
266
- /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3 shrink-0 text-muted-foreground" })
287
+ Icon && /* @__PURE__ */ jsx(Icon, { "aria-hidden": true, className: "h-3.5 w-3.5 shrink-0 text-muted-foreground", strokeWidth: 1.5 }),
288
+ /* @__PURE__ */ jsx("span", { className: PILL_LABEL, children: selected?.label ?? "\u2014" }),
289
+ /* @__PURE__ */ jsx(ChevronDown, { className: `h-3 w-3 shrink-0 ${trigger === "text" ? "text-primary" : "text-muted-foreground"}` })
267
290
  ]
268
291
  }
269
292
  ),
@@ -300,7 +323,8 @@ function OptionPill({
300
323
  choices,
301
324
  onSelect,
302
325
  bandRef,
303
- custom
326
+ custom,
327
+ icon: Icon
304
328
  }) {
305
329
  const [open, setOpen] = useState2(false);
306
330
  const [customOpen, setCustomOpen] = useState2(false);
@@ -327,7 +351,8 @@ function OptionPill({
327
351
  },
328
352
  className: PILL,
329
353
  children: [
330
- /* @__PURE__ */ jsx("span", { children: selected?.label ?? "\u2014" }),
354
+ Icon && /* @__PURE__ */ jsx(Icon, { "aria-hidden": true, className: "h-3.5 w-3.5 shrink-0 text-muted-foreground", strokeWidth: 1.5 }),
355
+ /* @__PURE__ */ jsx("span", { className: PILL_LABEL, children: selected?.label ?? "\u2014" }),
331
356
  /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3 shrink-0 text-muted-foreground" })
332
357
  ]
333
358
  }
@@ -452,7 +477,7 @@ function AudioTogglePill({ on, onToggle }) {
452
477
  className: `${PILL} ${on ? "" : "text-muted-foreground"}`,
453
478
  children: [
454
479
  on ? /* @__PURE__ */ jsx(Volume2, { className: "h-4 w-4 shrink-0", strokeWidth: 1.5 }) : /* @__PURE__ */ jsx(VolumeX, { className: "h-4 w-4 shrink-0", strokeWidth: 1.5 }),
455
- /* @__PURE__ */ jsx("span", { children: on ? "Audio on" : "Audio off" })
480
+ /* @__PURE__ */ jsx("span", { className: PILL_LABEL, children: on ? "Audio on" : "Audio off" })
456
481
  ]
457
482
  }
458
483
  );
@@ -473,7 +498,7 @@ function ReferencePill({
473
498
  if (url) {
474
499
  return /* @__PURE__ */ jsxs("div", { className: `${PILL} border-primary bg-primary/10 pr-1.5 text-primary hover:bg-primary/10`, children: [
475
500
  /* @__PURE__ */ jsx("img", { src: url, alt: "", className: "h-[18px] w-[18px] shrink-0 rounded-[5px] object-cover" }),
476
- /* @__PURE__ */ jsx("span", { children: "Reference" }),
501
+ /* @__PURE__ */ jsx("span", { className: PILL_LABEL, children: "Reference" }),
477
502
  /* @__PURE__ */ jsx(
478
503
  "button",
479
504
  {
@@ -517,7 +542,7 @@ function ReferencePill({
517
542
  className: PILL,
518
543
  children: [
519
544
  /* @__PURE__ */ jsx(ImagePlus, { className: "h-4 w-4 shrink-0 text-muted-foreground", strokeWidth: 1.5 }),
520
- /* @__PURE__ */ jsx("span", { children: "Reference image" })
545
+ /* @__PURE__ */ jsx("span", { className: PILL_LABEL, children: "Reference image" })
521
546
  ]
522
547
  }
523
548
  ),
@@ -600,7 +625,7 @@ function ModelPill({
600
625
  children: [
601
626
  unavailable && /* @__PURE__ */ jsx(TriangleAlert, { "aria-hidden": true, className: "h-3.5 w-3.5 shrink-0 text-warning", strokeWidth: 2 }),
602
627
  provider && /* @__PURE__ */ jsx(ProviderLogo, { provider, size: 14 }),
603
- /* @__PURE__ */ jsx("span", { className: "max-w-[168px] truncate", children: displayName }),
628
+ /* @__PURE__ */ jsx("span", { className: `max-w-[168px] truncate ${PILL_LABEL}`, children: displayName }),
604
629
  /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3 shrink-0 text-muted-foreground" })
605
630
  ]
606
631
  }
@@ -683,6 +708,17 @@ var PARAM_LABELS = {
683
708
  voice: "Voice",
684
709
  speed: "Speed"
685
710
  };
711
+ var PARAM_ICONS = {
712
+ size: Scaling,
713
+ quality: Sparkles,
714
+ n: Copy,
715
+ duration: Clock,
716
+ resolution: Monitor,
717
+ aspect_ratio: Ratio,
718
+ mode: SlidersHorizontal,
719
+ voice: Mic,
720
+ speed: Gauge
721
+ };
686
722
  var SPEED_PRESETS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 4];
687
723
  function choicesFor(param, meta) {
688
724
  const { min, max } = meta;
@@ -940,6 +976,7 @@ function StudioComposer({
940
976
  OptionPill,
941
977
  {
942
978
  label: PARAM_LABELS[param] ?? param,
979
+ icon: PARAM_ICONS[param] ?? SlidersHorizontal,
943
980
  value: values[param],
944
981
  choices: choicesForPill(param, options?.[param], values[param]),
945
982
  onSelect: (value) => setOption(param, value),
@@ -1019,8 +1056,8 @@ function GenerationNoticeChip({ className }) {
1019
1056
  return /* @__PURE__ */ jsxs3(
1020
1057
  "p",
1021
1058
  {
1022
- className: `inline-block rounded-full border px-3.5 py-1.5 text-center text-[12.5px] font-medium leading-relaxed text-foreground shadow-sm ${className ?? ""}`,
1023
- style: { background: "var(--studio-notice-bg)", borderColor: "var(--studio-notice-border)" },
1059
+ className: `inline-block rounded-full px-3.5 py-1.5 text-center text-[12px] leading-relaxed text-muted-foreground ${className ?? ""}`,
1060
+ style: { background: "var(--studio-notice-bg)" },
1024
1061
  children: [
1025
1062
  /* @__PURE__ */ jsx3(Info, { className: "mr-1.5 inline-block h-[14px] w-[14px] align-[-2px] text-primary", strokeWidth: 1.5, "aria-hidden": true }),
1026
1063
  "Each prompt starts a new generation \u2014 this chat does not remember the last one."
@@ -2190,6 +2227,7 @@ function StudioToast({ record, leave }) {
2190
2227
  function StudioToastProvider({ children }) {
2191
2228
  const [toasts, setToasts] = useState8([]);
2192
2229
  const [dockLift, setDockLift] = useState8(null);
2230
+ const [mounted, setMounted] = useState8(false);
2193
2231
  const sequence = useRef7(0);
2194
2232
  const dismissed = useRef7(/* @__PURE__ */ new Set());
2195
2233
  const records = useRef7(/* @__PURE__ */ new Map());
@@ -2214,9 +2252,10 @@ function StudioToastProvider({ children }) {
2214
2252
  }, []);
2215
2253
  const dismiss = useCallback5((id) => leave(id, "dismissed"), [leave]);
2216
2254
  const value = useMemo5(() => ({ toast, dismiss, setDockLift }), [dismiss, toast]);
2255
+ useEffect9(() => setMounted(true), []);
2217
2256
  return /* @__PURE__ */ jsxs8(StudioToastContext.Provider, { value, children: [
2218
2257
  children,
2219
- typeof document !== "undefined" && createPortal3(
2258
+ mounted && createPortal3(
2220
2259
  /* @__PURE__ */ jsx9(
2221
2260
  "div",
2222
2261
  {
@@ -2671,7 +2710,18 @@ import {
2671
2710
  useMemo as useMemo9,
2672
2711
  useState as useState13
2673
2712
  } from "react";
2674
- import { ArrowLeft as ArrowLeft2, Download as Download3, FolderPlus as FolderPlus3, Search, Trash2 as Trash23, X as X4 } from "lucide-react";
2713
+ import {
2714
+ ArrowLeft as ArrowLeft2,
2715
+ AudioLines as AudioLines2,
2716
+ Download as Download3,
2717
+ FolderPlus as FolderPlus3,
2718
+ Image,
2719
+ LayoutGrid,
2720
+ Search,
2721
+ Trash2 as Trash23,
2722
+ Video as Video2,
2723
+ X as X4
2724
+ } from "lucide-react";
2675
2725
 
2676
2726
  // src/studio-react/use-generation-history.ts
2677
2727
  import { useCallback as useCallback10, useEffect as useEffect13, useMemo as useMemo8, useRef as useRef11, useState as useState12 } from "react";
@@ -2816,6 +2866,16 @@ var MORE_SKELETONS = 4;
2816
2866
  var BAR = "flex min-h-[44px] flex-wrap items-center justify-between gap-3 px-6 pb-[18px] pt-0.5 max-[900px]:px-4";
2817
2867
  var SEARCH_INPUT = "h-8 w-[260px] max-w-[52vw] rounded-full border border-border bg-card pl-8 pr-3 text-[13px] text-foreground outline-none placeholder:text-muted-foreground focus:border-primary focus:ring-[3px] focus:ring-ring/30 max-[640px]:w-full max-[640px]:max-w-none";
2818
2868
  var OUTLINE_PILL = "inline-flex h-8 items-center gap-1.5 rounded-full border border-border px-3 text-[12.5px] font-medium hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40";
2869
+ var FILTER_ICONS = {
2870
+ all: LayoutGrid,
2871
+ image: Image,
2872
+ video: Video2,
2873
+ speech: AudioLines2
2874
+ };
2875
+ var FILTER_CHOICES = MEDIA_TYPE_FILTERS.map((choice) => ({
2876
+ ...choice,
2877
+ icon: FILTER_ICONS[choice.value]
2878
+ }));
2819
2879
  var TYPE_NOUNS = {
2820
2880
  image: "images",
2821
2881
  video: "videos",
@@ -3066,8 +3126,9 @@ function StudioHistoryScreen({
3066
3126
  {
3067
3127
  label: "Filter by media type",
3068
3128
  value: type,
3069
- choices: MEDIA_TYPE_FILTERS,
3070
- onSelect: setType
3129
+ choices: FILTER_CHOICES,
3130
+ onSelect: setType,
3131
+ trigger: "text"
3071
3132
  }
3072
3133
  )
3073
3134
  ] })