@ai-matrx/agents 0.59.189 → 0.59.191

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.
@@ -191,7 +191,6 @@ import {
191
191
  SelectTrigger,
192
192
  SelectValue,
193
193
  Slider,
194
- Switch,
195
194
  Textarea,
196
195
  Tooltip,
197
196
  TooltipContent,
@@ -199,9 +198,19 @@ import {
199
198
  TooltipTrigger
200
199
  } from "@ai-matrx/design-system";
201
200
  import { AspectRatioSelect, OptionCombobox, isAspectRatioOptionSet } from "@ai-matrx/design-system/controls";
202
- import { humanizeIdentifier } from "@ai-matrx/kit/text-case";
203
- import { jsx, jsxs } from "react/jsx-runtime";
201
+
202
+ // settings/setting-state.ts
204
203
  var ENUM_OFF_VALUE = "none";
204
+ function isOffValue(value, control) {
205
+ if (value === false) return true;
206
+ if (value === ENUM_OFF_VALUE) {
207
+ return !control || control.type === "enum";
208
+ }
209
+ return false;
210
+ }
211
+
212
+ // settings/react/SettingControlInput.tsx
213
+ import { jsx, jsxs } from "react/jsx-runtime";
205
214
  var SELECT_MAX_OPTIONS = 12;
206
215
  function choiceFor(options) {
207
216
  if (isAspectRatioOptionSet(options)) return "aspect-ratio";
@@ -223,16 +232,13 @@ function flattenTypeObject(value) {
223
232
  }
224
233
  function SettingControlInput({
225
234
  settingKey,
226
- explicitState = false,
227
235
  control,
228
236
  value,
229
237
  onChange,
230
238
  disabled = false,
231
- id,
232
- size = "dense"
239
+ id
233
240
  }) {
234
241
  const inputId = id ?? `setting-control-${settingKey}`;
235
- const comfortable = size === "comfortable";
236
242
  if (control.type === "enum" && control.enum?.length) {
237
243
  const flattened = settingKey === "response_format" ? flattenTypeObject(value) : value;
238
244
  const stringValue = flattened === void 0 || flattened === null ? "" : String(flattened);
@@ -248,7 +254,7 @@ function SettingControlInput({
248
254
  variant: "inline",
249
255
  disabled,
250
256
  id: inputId,
251
- placeholder: explicitState ? "Not set" : "Default"
257
+ placeholder: "Default"
252
258
  }
253
259
  ) : choice === "searchable" ? /* @__PURE__ */ jsx(
254
260
  OptionCombobox,
@@ -256,11 +262,10 @@ function SettingControlInput({
256
262
  value: isValueMismatch ? "" : stringValue,
257
263
  onChange: emit,
258
264
  options: control.enum,
259
- getLabel: explicitState ? humanizeIdentifier : void 0,
260
265
  variant: "inline",
261
266
  disabled,
262
267
  id: inputId,
263
- placeholder: explicitState ? "Not set" : "Default"
268
+ placeholder: "Default"
264
269
  }
265
270
  ) : null;
266
271
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 items-center gap-1.5", children: [
@@ -275,21 +280,16 @@ function SettingControlInput({
275
280
  SelectTrigger,
276
281
  {
277
282
  id: inputId,
278
- className: comfortable ? "h-9 flex-1 rounded-lg border-border bg-background px-2.5 text-sm text-foreground shadow-none focus:ring-0 pointer-coarse:h-11 [&_svg]:h-4 [&_svg]:w-4" : "h-7 flex-1 border-0 bg-transparent px-1 text-xs font-medium text-foreground/80 shadow-none hover:bg-transparent hover:text-foreground focus:ring-0 [&_svg]:h-3 [&_svg]:w-3",
279
- children: /* @__PURE__ */ jsx(
280
- SelectValue,
281
- {
282
- placeholder: isValueMismatch ? stringValue : explicitState ? "Not set" : "Default"
283
- }
284
- )
283
+ className: "h-7 flex-1 border-0 bg-transparent px-1 text-xs font-medium text-foreground shadow-none hover:bg-transparent focus:ring-0 pointer-coarse:h-11 [&_svg]:h-3 [&_svg]:w-3",
284
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder: isValueMismatch ? stringValue : "Default" })
285
285
  }
286
286
  ),
287
- /* @__PURE__ */ jsx(SelectContent, { className: comfortable ? "text-sm" : "text-xs", children: control.enum.map((option) => /* @__PURE__ */ jsx(
287
+ /* @__PURE__ */ jsx(SelectContent, { className: "text-xs", children: control.enum.map((option) => /* @__PURE__ */ jsx(
288
288
  SelectItem,
289
289
  {
290
290
  value: option,
291
- className: comfortable ? "text-sm" : "py-1 text-xs",
292
- children: option === ENUM_OFF_VALUE ? "Off" : explicitState ? humanizeIdentifier(option) : option
291
+ className: "py-1 text-xs",
292
+ children: option === ENUM_OFF_VALUE ? "Off" : option
293
293
  },
294
294
  option
295
295
  )) })
@@ -307,22 +307,12 @@ function SettingControlInput({
307
307
  ] });
308
308
  }
309
309
  if (control.type === "boolean") {
310
- if (comfortable && !explicitState)
311
- return /* @__PURE__ */ jsx("div", { className: "flex flex-1 justify-end", children: /* @__PURE__ */ jsx(
312
- Switch,
313
- {
314
- id: inputId,
315
- checked: value === true,
316
- onCheckedChange: (next) => onChange(next),
317
- disabled
318
- }
319
- ) });
320
310
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
321
311
  /* @__PURE__ */ jsx(
322
312
  Checkbox,
323
313
  {
324
314
  id: inputId,
325
- checked: explicitState && value == null ? "indeterminate" : value === true,
315
+ checked: value === true,
326
316
  onCheckedChange: (c) => onChange(c === true),
327
317
  disabled,
328
318
  className: "cursor-pointer"
@@ -333,30 +323,12 @@ function SettingControlInput({
333
323
  {
334
324
  htmlFor: inputId,
335
325
  className: "cursor-pointer text-xs text-muted-foreground",
336
- children: explicitState ? value == null ? "Unknown" : value === true ? "Yes" : "No" : value === true ? "On" : "Off"
326
+ children: value === true ? "On" : "Off"
337
327
  }
338
328
  )
339
329
  ] });
340
330
  }
341
331
  if (control.type === "number" || control.type === "integer") {
342
- if (explicitState && typeof value !== "number")
343
- return /* @__PURE__ */ jsx(
344
- Input,
345
- {
346
- id: inputId,
347
- type: "number",
348
- value: "",
349
- placeholder: "Not set",
350
- min: control.min,
351
- max: control.max,
352
- step: control.type === "integer" ? 1 : "any",
353
- disabled,
354
- onChange: (event) => {
355
- if (event.target.value !== "") onChange(Number(event.target.value));
356
- },
357
- className: "h-8 text-sm"
358
- }
359
- );
360
332
  const numeric = typeof value === "number" ? value : void 0;
361
333
  const hasRange = control.min !== void 0 && control.max !== void 0;
362
334
  return /* @__PURE__ */ jsx(
@@ -371,8 +343,7 @@ function SettingControlInput({
371
343
  step: control.type === "integer" ? 1 : 0.01,
372
344
  isInteger: control.type === "integer",
373
345
  disabled,
374
- withSlider: hasRange,
375
- size
346
+ withSlider: hasRange
376
347
  }
377
348
  );
378
349
  }
@@ -409,7 +380,7 @@ function SettingControlInput({
409
380
  value: value === void 0 || value === null ? "" : String(value),
410
381
  onChange: (e) => onChange(e.target.value),
411
382
  disabled,
412
- className: comfortable ? "h-9 w-full px-2.5 text-sm pointer-coarse:h-11" : "h-7 w-full px-2 text-base sm:text-xs"
383
+ className: "h-7 w-full px-2 text-base pointer-coarse:h-11 sm:text-xs"
413
384
  }
414
385
  );
415
386
  }
@@ -467,11 +438,9 @@ function NumberInput({
467
438
  step = 1,
468
439
  isInteger = false,
469
440
  disabled = false,
470
- withSlider = false,
471
- size = "dense"
441
+ withSlider = false
472
442
  }) {
473
- const comfortable = size === "comfortable";
474
- const boxClass = comfortable ? "h-9 px-2.5 text-sm tabular-nums pointer-coarse:h-11" : "h-7 px-2 text-xs";
443
+ const boxClass = "h-7 px-2 text-xs tabular-nums pointer-coarse:h-11";
475
444
  const [draftState, setDraftState] = useState(() => ({
476
445
  sourceValue: value,
477
446
  text: value === void 0 ? "" : String(value)
@@ -493,7 +462,7 @@ function NumberInput({
493
462
  return /* @__PURE__ */ jsxs(
494
463
  "div",
495
464
  {
496
- className: comfortable ? "grid grid-cols-[1fr_6rem] items-center gap-3" : "grid grid-cols-[1fr_4rem] items-center gap-2",
465
+ className: "grid grid-cols-[1fr_4.5rem] items-center gap-2",
497
466
  children: [
498
467
  /* @__PURE__ */ jsx(
499
468
  Slider,
@@ -554,157 +523,566 @@ function NumberInput({
554
523
  }
555
524
 
556
525
  // settings/react/InputCapabilitiesEditor.tsx
557
- import { Button, Label as Label2, Switch as Switch2 } from "@ai-matrx/design-system";
526
+ import { Switch } from "@ai-matrx/design-system";
527
+ import { Button } from "@ai-matrx/design-system/controls";
528
+
529
+ // settings/react/settings-icons.tsx
558
530
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
559
- var cn = (...parts) => parts.filter(Boolean).join(" ");
560
531
  function Svg({ className, children }) {
561
- return /* @__PURE__ */ jsx2("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", className, children });
532
+ return /* @__PURE__ */ jsx2(
533
+ "svg",
534
+ {
535
+ xmlns: "http://www.w3.org/2000/svg",
536
+ viewBox: "0 0 24 24",
537
+ fill: "none",
538
+ stroke: "currentColor",
539
+ strokeWidth: 2,
540
+ strokeLinecap: "round",
541
+ strokeLinejoin: "round",
542
+ "aria-hidden": "true",
543
+ className,
544
+ children
545
+ }
546
+ );
562
547
  }
563
- var ImageIcon = ({ className }) => /* @__PURE__ */ jsxs2(Svg, { className, children: [
548
+ var CircleCheckGlyph = ({ className }) => /* @__PURE__ */ jsxs2(Svg, { className, children: [
549
+ /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "12", r: "10" }),
550
+ /* @__PURE__ */ jsx2("path", { d: "m16 9-5.5 5.5L8 12" })
551
+ ] });
552
+ var TriangleAlertGlyph = ({ className }) => /* @__PURE__ */ jsxs2(Svg, { className, children: [
553
+ /* @__PURE__ */ jsx2("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }),
554
+ /* @__PURE__ */ jsx2("path", { d: "M12 9v4" }),
555
+ /* @__PURE__ */ jsx2("path", { d: "M12 17h.01" })
556
+ ] });
557
+ var VariableGlyph = ({ className }) => /* @__PURE__ */ jsxs2(Svg, { className, children: [
558
+ /* @__PURE__ */ jsx2("path", { d: "M8 21s-4-3-4-9 4-9 4-9" }),
559
+ /* @__PURE__ */ jsx2("path", { d: "M16 3s4 3 4 9-4 9-4 9" }),
560
+ /* @__PURE__ */ jsx2("line", { x1: "15", x2: "9", y1: "9", y2: "15" }),
561
+ /* @__PURE__ */ jsx2("line", { x1: "9", x2: "15", y1: "9", y2: "15" })
562
+ ] });
563
+ var UnlinkGlyph = ({ className }) => /* @__PURE__ */ jsxs2(Svg, { className, children: [
564
+ /* @__PURE__ */ jsx2("path", { d: "m18.84 12.25 1.72-1.71h-.02a5.004 5.004 0 0 0-.12-7.07 5.006 5.006 0 0 0-6.95 0l-1.72 1.71" }),
565
+ /* @__PURE__ */ jsx2("path", { d: "m5.17 11.75-1.71 1.71a5.004 5.004 0 0 0 .12 7.07 5.006 5.006 0 0 0 6.95 0l1.71-1.71" }),
566
+ /* @__PURE__ */ jsx2("line", { x1: "8", x2: "8", y1: "2", y2: "5" }),
567
+ /* @__PURE__ */ jsx2("line", { x1: "2", x2: "5", y1: "8", y2: "8" }),
568
+ /* @__PURE__ */ jsx2("line", { x1: "16", x2: "16", y1: "19", y2: "22" }),
569
+ /* @__PURE__ */ jsx2("line", { x1: "19", x2: "22", y1: "16", y2: "16" })
570
+ ] });
571
+ var WrenchGlyph = ({ className }) => /* @__PURE__ */ jsx2(Svg, { className, children: /* @__PURE__ */ jsx2("path", { d: "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z" }) });
572
+ var Trash2Glyph = ({ className }) => /* @__PURE__ */ jsxs2(Svg, { className, children: [
573
+ /* @__PURE__ */ jsx2("path", { d: "M10 11v6" }),
574
+ /* @__PURE__ */ jsx2("path", { d: "M14 11v6" }),
575
+ /* @__PURE__ */ jsx2("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" }),
576
+ /* @__PURE__ */ jsx2("path", { d: "M3 6h18" }),
577
+ /* @__PURE__ */ jsx2("path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
578
+ ] });
579
+ var RotateCcwGlyph = ({ className }) => /* @__PURE__ */ jsxs2(Svg, { className, children: [
580
+ /* @__PURE__ */ jsx2("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
581
+ /* @__PURE__ */ jsx2("path", { d: "M3 3v5h5" })
582
+ ] });
583
+ var ImageGlyph = ({ className }) => /* @__PURE__ */ jsxs2(Svg, { className, children: [
564
584
  /* @__PURE__ */ jsx2("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }),
565
585
  /* @__PURE__ */ jsx2("circle", { cx: "9", cy: "9", r: "2" }),
566
586
  /* @__PURE__ */ jsx2("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" })
567
587
  ] });
568
- var FileText = ({ className }) => /* @__PURE__ */ jsxs2(Svg, { className, children: [
588
+ var FileTextGlyph = ({ className }) => /* @__PURE__ */ jsxs2(Svg, { className, children: [
569
589
  /* @__PURE__ */ jsx2("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
570
590
  /* @__PURE__ */ jsx2("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" }),
571
591
  /* @__PURE__ */ jsx2("path", { d: "M10 9H8" }),
572
592
  /* @__PURE__ */ jsx2("path", { d: "M16 13H8" }),
573
593
  /* @__PURE__ */ jsx2("path", { d: "M16 17H8" })
574
594
  ] });
575
- var Youtube = ({ className }) => /* @__PURE__ */ jsxs2(Svg, { className, children: [
595
+ var YoutubeGlyph = ({ className }) => /* @__PURE__ */ jsxs2(Svg, { className, children: [
576
596
  /* @__PURE__ */ jsx2("path", { d: "M2.5 17a24.12 24.12 0 0 1 0-10 2 2 0 0 1 1.4-1.4 49.56 49.56 0 0 1 16.2 0A2 2 0 0 1 21.5 7a24.12 24.12 0 0 1 0 10 2 2 0 0 1-1.4 1.4 49.55 49.55 0 0 1-16.2 0A2 2 0 0 1 2.5 17" }),
577
597
  /* @__PURE__ */ jsx2("path", { d: "m10 15 5-3-5-3z" })
578
598
  ] });
579
- var RotateCcw = ({ className }) => /* @__PURE__ */ jsxs2(Svg, { className, children: [
580
- /* @__PURE__ */ jsx2("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
581
- /* @__PURE__ */ jsx2("path", { d: "M3 3v5h5" })
582
- ] });
599
+
600
+ // settings/react/SettingRowFrame.tsx
601
+ import { Label as Label2 } from "@ai-matrx/design-system";
602
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
603
+ var cn = (...parts) => parts.filter(Boolean).join(" ");
604
+ function formatSettingValue(value) {
605
+ if (typeof value === "boolean") return value ? "On" : "Off";
606
+ if (value !== null && typeof value === "object") return JSON.stringify(value);
607
+ return String(value);
608
+ }
609
+ function SettingRowFrame({ rowKey, state, leading, label, children, actions }) {
610
+ return /* @__PURE__ */ jsxs3(
611
+ "div",
612
+ {
613
+ "data-setting-row": rowKey,
614
+ "data-setting-state": state,
615
+ className: "grid grid-cols-[1rem_minmax(0,1fr)_auto] items-start gap-x-2 gap-y-1 py-1 @md:grid-cols-[1rem_9rem_minmax(0,1fr)_auto]",
616
+ children: [
617
+ /* @__PURE__ */ jsx3("div", { className: "flex h-7 items-center", children: leading }),
618
+ /* @__PURE__ */ jsx3("div", { className: "flex min-h-7 min-w-0 items-center", children: label }),
619
+ children !== void 0 ? /* @__PURE__ */ jsx3("div", { className: "col-span-2 col-start-2 row-start-2 min-w-0 @md:col-span-1 @md:col-start-3 @md:row-start-1", children }) : null,
620
+ /* @__PURE__ */ jsx3("div", { className: "col-start-3 row-start-1 flex min-h-7 items-center justify-end @md:col-start-4", children: actions })
621
+ ]
622
+ }
623
+ );
624
+ }
625
+ function RowLabel({ htmlFor, muted, children }) {
626
+ return /* @__PURE__ */ jsx3(Label2, { htmlFor, className: cn("min-w-0 truncate type-body", muted ? "text-muted-foreground" : "text-foreground"), children });
627
+ }
628
+ function RowText({ children, mono }) {
629
+ return /* @__PURE__ */ jsx3("span", { className: cn("flex min-h-7 items-center truncate type-secondary text-muted-foreground", mono && "font-mono"), children });
630
+ }
631
+ function SettingsGroupSection({ id, title, children }) {
632
+ return /* @__PURE__ */ jsxs3("section", { "data-settings-group": id, className: title ? "mt-2 border-t border-border pt-2" : void 0, children: [
633
+ title ? /* @__PURE__ */ jsx3("h3", { className: "pb-1 type-title text-foreground", children: title }) : null,
634
+ children
635
+ ] });
636
+ }
637
+
638
+ // settings/react/InputCapabilitiesEditor.tsx
639
+ import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
583
640
  var GATE_META = {
584
641
  image_urls: {
585
642
  label: "Image URLs",
586
643
  description: "Offer the image-URL attachment input in chat.",
587
- Icon: ImageIcon
644
+ Icon: ImageGlyph
588
645
  },
589
646
  file_urls: {
590
647
  label: "File URLs",
591
648
  description: "Offer the file-URL attachment input in chat.",
592
- Icon: FileText
649
+ Icon: FileTextGlyph
593
650
  },
594
651
  youtube_videos: {
595
652
  label: "YouTube videos",
596
653
  description: "Offer the YouTube-URL attachment input in chat.",
597
- Icon: Youtube
654
+ Icon: YoutubeGlyph
598
655
  }
599
656
  };
600
657
  function InputCapabilitiesEditor({
601
658
  values,
602
659
  onChange,
603
- overriddenKeys,
660
+ changedKeys,
604
661
  onReset,
662
+ resetLabel = "Reset to agent",
663
+ error,
605
664
  idPrefix,
606
665
  title = "Input Capabilities",
607
- variant = "settings"
666
+ disabled = false
608
667
  }) {
609
- if (variant === "menu")
610
- return /* @__PURE__ */ jsxs2("div", { className: "border-t border-border px-3 pb-3", children: [
611
- /* @__PURE__ */ jsx2("p", { className: "pb-1 pt-3 type-secondary font-medium text-muted-foreground", children: title }),
612
- UI_GATE_EDITABLE_KEYS.map((key) => {
613
- const { label, Icon } = GATE_META[key];
614
- const overridden = overriddenKeys?.has(key) === true;
615
- const switchId = `${idPrefix}-${key}`;
616
- return /* @__PURE__ */ jsxs2(
617
- "div",
618
- {
619
- className: cn(
620
- "-mx-1.5 flex min-h-9 items-center gap-2.5 rounded-lg px-1.5 pointer-coarse:min-h-11",
621
- overridden && "bg-primary/5"
622
- ),
623
- children: [
624
- /* @__PURE__ */ jsx2(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
625
- /* @__PURE__ */ jsx2(
626
- Label2,
627
- {
628
- htmlFor: switchId,
629
- className: "min-w-0 flex-1 cursor-pointer truncate text-sm font-normal text-foreground",
630
- children: label
631
- }
632
- ),
633
- overridden && onReset ? /* @__PURE__ */ jsx2(
634
- "button",
635
- {
636
- type: "button",
637
- "aria-label": `Reset ${label} to agent default`,
638
- title: "Reset override",
639
- onClick: () => onReset(key),
640
- className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
641
- children: /* @__PURE__ */ jsx2(RotateCcw, { className: "h-4 w-4" })
642
- }
643
- ) : null,
644
- /* @__PURE__ */ jsx2(
645
- Switch2,
646
- {
647
- id: switchId,
648
- checked: values[key] === true,
649
- onCheckedChange: (next) => onChange(key, next),
650
- className: "shrink-0"
651
- }
652
- )
653
- ]
654
- },
655
- key
656
- );
657
- })
658
- ] });
659
- return /* @__PURE__ */ jsxs2("div", { className: "border-t pt-2 mt-2", children: [
660
- /* @__PURE__ */ jsx2("div", { className: "mb-2 type-secondary font-semibold text-foreground", children: title }),
661
- /* @__PURE__ */ jsx2("div", { className: "space-y-1", children: UI_GATE_EDITABLE_KEYS.map((key) => {
668
+ return /* @__PURE__ */ jsxs4(SettingsGroupSection, { id: "input-capabilities", title, children: [
669
+ UI_GATE_EDITABLE_KEYS.map((key) => {
662
670
  const { label, description, Icon } = GATE_META[key];
663
- const checked = values[key] === true;
664
- const overridden = overriddenKeys?.has(key) === true;
665
671
  const switchId = `${idPrefix}-${key}`;
666
- return /* @__PURE__ */ jsxs2(
667
- "div",
672
+ const changed = changedKeys?.has(key) === true;
673
+ return /* @__PURE__ */ jsx4(
674
+ SettingRowFrame,
668
675
  {
669
- className: "flex items-center gap-2 rounded px-1 py-1 hover:bg-muted/20",
670
- children: [
671
- /* @__PURE__ */ jsx2(Icon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
672
- /* @__PURE__ */ jsxs2(
673
- Label2,
674
- {
675
- htmlFor: switchId,
676
- className: "min-w-0 flex-1 cursor-pointer text-xs text-foreground",
677
- children: [
678
- label,
679
- /* @__PURE__ */ jsx2("span", { className: "block type-meta font-normal leading-tight text-muted-foreground", children: description })
680
- ]
681
- }
682
- ),
683
- overridden && onReset ? /* @__PURE__ */ jsx2(
676
+ rowKey: key,
677
+ state: values[key] === true ? "on" : "off",
678
+ leading: /* @__PURE__ */ jsx4(Icon, { className: "h-4 w-4 text-muted-foreground" }),
679
+ label: /* @__PURE__ */ jsx4(RowLabel, { htmlFor: switchId, children: label }),
680
+ actions: /* @__PURE__ */ jsxs4(Fragment, { children: [
681
+ changed && onReset ? /* @__PURE__ */ jsx4(
684
682
  Button,
685
683
  {
686
- variant: "ghost",
687
- size: "icon",
688
- className: "h-6 w-6",
689
- "aria-label": `Reset ${label} to agent default`,
684
+ variant: "quiet",
685
+ icon: /* @__PURE__ */ jsx4(RotateCcwGlyph, {}),
690
686
  onClick: () => onReset(key),
691
- children: /* @__PURE__ */ jsx2(RotateCcw, { className: "h-3 w-3" })
687
+ disabled,
688
+ "aria-label": `${resetLabel}: ${label}`,
689
+ title: resetLabel,
690
+ "data-setting-reset": key
692
691
  }
693
692
  ) : null,
694
- /* @__PURE__ */ jsx2(
695
- Switch2,
693
+ /* @__PURE__ */ jsx4(
694
+ Switch,
696
695
  {
697
696
  id: switchId,
698
- checked,
697
+ checked: values[key] === true,
699
698
  onCheckedChange: (next) => onChange(key, next),
700
- className: "shrink-0 data-[state=checked]:bg-primary"
699
+ disabled,
700
+ className: "shrink-0"
701
701
  }
702
702
  )
703
- ]
703
+ ] }),
704
+ children: /* @__PURE__ */ jsx4(RowText, { children: description })
704
705
  },
705
706
  key
706
707
  );
707
- }) })
708
+ }),
709
+ error ? /* @__PURE__ */ jsx4("p", { role: "alert", className: "py-1 type-meta text-destructive", children: error }) : null
710
+ ] });
711
+ }
712
+
713
+ // settings/react/ModelSettingsPanel.tsx
714
+ import { Checkbox as Checkbox2 } from "@ai-matrx/design-system";
715
+ import { Button as Button2, Chip } from "@ai-matrx/design-system/controls";
716
+
717
+ // settings/settings-catalogue.ts
718
+ import { humanizeIdentifier } from "@ai-matrx/kit/text-case";
719
+ var CONTROL_TYPES = [
720
+ "number",
721
+ "integer",
722
+ "boolean",
723
+ "string",
724
+ "enum",
725
+ "array",
726
+ "string_array",
727
+ "object_array"
728
+ ];
729
+ function isControlDefinitionShape(value) {
730
+ return typeof value.type === "string" && CONTROL_TYPES.includes(value.type);
731
+ }
732
+ var TEXT_GROUP = [
733
+ { key: "response_format", label: "Response Format" },
734
+ { key: "stop_sequences", label: "Stop Sequences" },
735
+ { key: "temperature", label: "Temperature" },
736
+ { key: "max_output_tokens", label: "Max Output Tokens" },
737
+ { key: "top_p", label: "Top P" },
738
+ { key: "top_k", label: "Top K" },
739
+ { key: "thinking_budget", label: "Thinking Budget" },
740
+ { key: "thinking_level", label: "Thinking Level" },
741
+ { key: "reasoning_effort", label: "Reasoning Effort" },
742
+ { key: "reasoning_summary", label: "Reasoning Summary" },
743
+ // Deep Research agents: charts and images inside the report.
744
+ { key: "visualization", label: "Charts and Images" },
745
+ { key: "verbosity", label: "Verbosity" },
746
+ { key: "tool_choice", label: "Tool Choice" }
747
+ ];
748
+ var FEATURE_FLAGS_GROUP = [
749
+ { key: "stream", label: "Stream Response" },
750
+ { key: "store", label: "Store Conversation" },
751
+ { key: "parallel_tool_calls", label: "Parallel Tool Calls" },
752
+ { key: "include_thoughts", label: "Include Thoughts" },
753
+ { key: "internal_web_search", label: "Internal Web Search" },
754
+ { key: "internal_url_context", label: "Internal URL Context" },
755
+ { key: "disable_safety_checker", label: "Disable Safety Checker" },
756
+ { key: "clear_thinking", label: "Clear Thinking" },
757
+ { key: "disable_reasoning", label: "Disable Reasoning" },
758
+ { key: "generate_audio", label: "Generate Audio" },
759
+ { key: "enhance_prompt", label: "Enhance Prompt" },
760
+ { key: "include_rai_reason", label: "Include RAI Reason" }
761
+ ];
762
+ var IMAGE_VIDEO_GROUP = [
763
+ { key: "size", label: "Size" },
764
+ { key: "quality", label: "Quality" },
765
+ { key: "count", label: "Count" },
766
+ { key: "steps", label: "Steps" },
767
+ { key: "guidance_scale", label: "Guidance Scale" },
768
+ { key: "seed", label: "Seed" },
769
+ { key: "width", label: "Width" },
770
+ { key: "height", label: "Height" },
771
+ { key: "fps", label: "FPS" },
772
+ { key: "seconds", label: "Duration (s) [legacy string]" },
773
+ { key: "output_quality", label: "Output Quality" },
774
+ { key: "negative_prompt", label: "Negative Prompt" },
775
+ { key: "aspect_ratio", label: "Aspect Ratio" },
776
+ { key: "ratio", label: "Aspect Ratio (Together/Runway)" },
777
+ { key: "resolution", label: "Resolution" },
778
+ { key: "image_size", label: "Image Size" },
779
+ { key: "num_outputs", label: "Outputs" },
780
+ { key: "number_of_images", label: "Number of Images" },
781
+ { key: "render_quality", label: "Render Quality" },
782
+ { key: "background", label: "Background" },
783
+ { key: "input_fidelity", label: "Input Fidelity" },
784
+ { key: "output_compression", label: "Output Compression" },
785
+ { key: "moderation", label: "Moderation" },
786
+ { key: "partial_images", label: "Partial Images" },
787
+ { key: "output_mime_type", label: "Output MIME Type" },
788
+ { key: "person_generation", label: "Person Generation" },
789
+ { key: "image_format", label: "Image Format" },
790
+ { key: "style", label: "Style" },
791
+ { key: "reference_strength", label: "Reference Strength" },
792
+ { key: "duration_seconds", label: "Duration (s)" },
793
+ { key: "duration", label: "Duration" },
794
+ { key: "encode_quality", label: "Encode Quality" },
795
+ { key: "video_action", label: "Video Action" },
796
+ { key: "reference_images", label: "Reference Images" },
797
+ { key: "frame_images", label: "Frame Images" },
798
+ { key: "image_loras", label: "Image LoRAs" }
799
+ ];
800
+ var AUDIO_GROUP = [
801
+ { key: "tts_voice", label: "Voice" },
802
+ { key: "performance_direction", label: "Performance Direction" },
803
+ { key: "speech_speed", label: "Speed" },
804
+ { key: "turn_pause_ms", label: "Pause Between Turns (ms)" },
805
+ { key: "language_code", label: "Language" },
806
+ { key: "audio_format", label: "Audio Format" }
807
+ ];
808
+ var SETTINGS_CATALOGUE = [
809
+ { id: "text", label: "", entries: TEXT_GROUP },
810
+ { id: "featureFlags", label: "Feature Flags", entries: FEATURE_FLAGS_GROUP },
811
+ { id: "imageVideo", label: "Image / Video Settings", entries: IMAGE_VIDEO_GROUP },
812
+ { id: "audio", label: "Audio Settings", entries: AUDIO_GROUP }
813
+ ];
814
+ var CATALOGUE_KEYS = new Set(
815
+ SETTINGS_CATALOGUE.flatMap((g) => g.entries.map((e) => e.key))
816
+ );
817
+ var CATCHALL_EXCLUDED = /* @__PURE__ */ new Set([
818
+ "rawControls",
819
+ "unmappedControls",
820
+ "model_id",
821
+ "model",
822
+ // chosen via the dedicated model picker, never a generic settings row
823
+ "multi_speaker",
824
+ // edited via the Voice editor alongside tts_voice
825
+ // Model-gated UI flags live in the ui_gates column + UiGatesEditor, never as
826
+ // settings rows — even when the model declares them as controls (e.g. every
827
+ // model now declares `tools` for the tool-support capability).
828
+ ...UI_GATE_KEYS
829
+ ]);
830
+ function lookupControl(controls, key) {
831
+ if (!controls) return null;
832
+ if (CATCHALL_EXCLUDED.has(key)) {
833
+ if (key === "rawControls" || key === "unmappedControls") return null;
834
+ }
835
+ const candidate = controls[key];
836
+ if (candidate && typeof candidate === "object" && !Array.isArray(candidate)) {
837
+ const c = candidate;
838
+ if (isControlDefinitionShape(c)) {
839
+ return c;
840
+ }
841
+ }
842
+ return null;
843
+ }
844
+ function hasMeaningfulValue(settings, key) {
845
+ if (!settings) return false;
846
+ const v = settings[key];
847
+ return v !== void 0 && v !== null;
848
+ }
849
+ function buildSettingsRows(controls, settings) {
850
+ const groups = SETTINGS_CATALOGUE.map((group) => ({
851
+ id: group.id,
852
+ label: group.label,
853
+ rows: group.entries.flatMap((entry) => {
854
+ const control = lookupControl(controls, entry.key);
855
+ if (!control) return [];
856
+ return [
857
+ {
858
+ key: entry.key,
859
+ label: entry.label,
860
+ group: group.id,
861
+ control,
862
+ supported: true,
863
+ hasValue: hasMeaningfulValue(settings, entry.key)
864
+ }
865
+ ];
866
+ })
867
+ }));
868
+ const declaredExtra = [];
869
+ if (controls) {
870
+ for (const key of Object.keys(controls)) {
871
+ if (CATALOGUE_KEYS.has(key) || CATCHALL_EXCLUDED.has(key)) continue;
872
+ if (lookupControl(controls, key)) declaredExtra.push(key);
873
+ }
874
+ }
875
+ if (declaredExtra.length > 0) {
876
+ const rows = declaredExtra.sort().map((key) => ({
877
+ key,
878
+ label: humanizeIdentifier(key),
879
+ group: "other",
880
+ control: lookupControl(controls, key),
881
+ supported: true,
882
+ hasValue: hasMeaningfulValue(settings, key)
883
+ }));
884
+ groups.push({ id: "other", label: "Other Settings", rows });
885
+ }
886
+ return groups;
887
+ }
888
+
889
+ // settings/react/ModelSettingsPanel.tsx
890
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
891
+ function StatusGlyph({ issue, source }) {
892
+ const title = issue ? issue.message : source ? `Valid \xB7 ${source}` : "Valid";
893
+ return /* @__PURE__ */ jsx5(
894
+ "span",
895
+ {
896
+ className: cn("inline-flex h-7 w-6 shrink-0 items-center justify-center", issue ? "text-warning" : "text-success"),
897
+ role: "img",
898
+ "aria-label": title,
899
+ title,
900
+ children: issue ? /* @__PURE__ */ jsx5(TriangleAlertGlyph, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx5(CircleCheckGlyph, { className: "h-3.5 w-3.5" })
901
+ }
902
+ );
903
+ }
904
+ function ModelSettingRow({ row, control, target, idPrefix, disabled }) {
905
+ const read = target.read(row.key, control);
906
+ const resetLabel = target.resetLabel ?? "Reset to agent";
907
+ const reset = read.changedHere && target.resetToInherited ? /* @__PURE__ */ jsx5(
908
+ Button2,
909
+ {
910
+ variant: "quiet",
911
+ icon: /* @__PURE__ */ jsx5(RotateCcwGlyph, {}),
912
+ onClick: () => target.resetToInherited?.(row.key),
913
+ disabled,
914
+ "aria-label": `${resetLabel}: ${row.label}`,
915
+ title: resetLabel,
916
+ "data-setting-reset": row.key
917
+ }
918
+ ) : null;
919
+ if (read.state === "bound") {
920
+ return /* @__PURE__ */ jsx5(
921
+ SettingRowFrame,
922
+ {
923
+ rowKey: row.key,
924
+ state: "bound",
925
+ leading: /* @__PURE__ */ jsx5(Checkbox2, { checked: true, disabled: true, "aria-label": `${row.label} is a run input` }),
926
+ label: /* @__PURE__ */ jsx5(RowLabel, { children: row.label }),
927
+ actions: /* @__PURE__ */ jsxs5(Fragment2, { children: [
928
+ reset,
929
+ target.unbind ? /* @__PURE__ */ jsx5(
930
+ Button2,
931
+ {
932
+ variant: "quiet",
933
+ icon: /* @__PURE__ */ jsx5(UnlinkGlyph, {}),
934
+ onClick: () => target.unbind?.(row.key, control),
935
+ disabled,
936
+ "aria-label": `Make ${row.label} a fixed setting`,
937
+ title: "Make a fixed setting"
938
+ }
939
+ ) : null
940
+ ] }),
941
+ children: /* @__PURE__ */ jsxs5("span", { className: "flex min-h-7 min-w-0 items-center gap-2", "data-bound-control": row.key, children: [
942
+ /* @__PURE__ */ jsx5(Chip, { tone: "primary", icon: /* @__PURE__ */ jsx5(VariableGlyph, {}), label: `{{${read.variableName}}}` }),
943
+ /* @__PURE__ */ jsx5("span", { className: "truncate type-meta text-muted-foreground", children: read.value === void 0 || read.value === null || read.value === "" ? "Model default" : formatSettingValue(read.value) })
944
+ ] })
945
+ }
946
+ );
947
+ }
948
+ const isSet = read.state === "set";
949
+ const value = isSet ? read.value : void 0;
950
+ const isOff = isSet && isOffValue(value, control);
951
+ const checkboxId = `${idPrefix}-setting-${row.key}`;
952
+ const canBind = Boolean(target.bind) && (target.canBind?.(row.key) ?? true);
953
+ return /* @__PURE__ */ jsx5(
954
+ SettingRowFrame,
955
+ {
956
+ rowKey: row.key,
957
+ state: isOff ? "off" : read.state,
958
+ leading: /* @__PURE__ */ jsx5(
959
+ Checkbox2,
960
+ {
961
+ id: checkboxId,
962
+ checked: isSet,
963
+ disabled,
964
+ onCheckedChange: (next) => next === true ? target.turnOn(row.key, control) : target.clear(row.key)
965
+ }
966
+ ),
967
+ label: /* @__PURE__ */ jsx5(RowLabel, { htmlFor: checkboxId, muted: !isSet, children: row.label }),
968
+ actions: /* @__PURE__ */ jsxs5(Fragment2, { children: [
969
+ /* @__PURE__ */ jsx5(StatusGlyph, { issue: read.issue, source: read.source }),
970
+ canBind ? /* @__PURE__ */ jsx5(
971
+ Button2,
972
+ {
973
+ variant: "quiet",
974
+ icon: /* @__PURE__ */ jsx5(VariableGlyph, {}),
975
+ onClick: () => target.bind?.(row.key, control),
976
+ disabled,
977
+ "aria-label": `Make ${row.label} a run input`,
978
+ title: "Make a run input",
979
+ "data-bind-control": row.key
980
+ }
981
+ ) : null,
982
+ isSet && read.issue?.fixable && target.fix ? /* @__PURE__ */ jsx5(
983
+ Button2,
984
+ {
985
+ variant: "quiet",
986
+ icon: /* @__PURE__ */ jsx5(WrenchGlyph, {}),
987
+ onClick: () => target.fix?.(row.key),
988
+ disabled,
989
+ "aria-label": `Fix ${row.label} automatically`,
990
+ title: "Fix automatically"
991
+ }
992
+ ) : null,
993
+ reset,
994
+ isSet ? /* @__PURE__ */ jsx5(
995
+ Button2,
996
+ {
997
+ variant: "quiet",
998
+ removes: true,
999
+ icon: /* @__PURE__ */ jsx5(Trash2Glyph, {}),
1000
+ onClick: () => target.clear(row.key),
1001
+ disabled,
1002
+ "aria-label": `Clear ${row.label} to not set`,
1003
+ title: "Clear to not set",
1004
+ "data-setting-clear": row.key
1005
+ }
1006
+ ) : null
1007
+ ] }),
1008
+ children: isSet ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
1009
+ /* @__PURE__ */ jsx5(
1010
+ SettingControlInput,
1011
+ {
1012
+ settingKey: row.key,
1013
+ control,
1014
+ value,
1015
+ onChange: (next) => target.change(row.key, next, control),
1016
+ disabled,
1017
+ id: `${idPrefix}-control-${row.key}`
1018
+ }
1019
+ ),
1020
+ read.issue ? /* @__PURE__ */ jsx5("p", { className: "pt-1 type-meta text-warning-ink", children: read.issue.message }) : null
1021
+ ] }) : /* @__PURE__ */ jsx5(RowText, { children: read.modelDefault !== void 0 && read.modelDefault !== null ? `Not set \xB7 Model default: ${formatSettingValue(read.modelDefault)}` : "Not set" })
1022
+ }
1023
+ );
1024
+ }
1025
+ function ExtraSettingRow({ rowKey, label, value, kind, onClear, onReset, resetLabel = "Reset to agent", disabled = false }) {
1026
+ return /* @__PURE__ */ jsx5(
1027
+ SettingRowFrame,
1028
+ {
1029
+ rowKey,
1030
+ state: kind,
1031
+ label: /* @__PURE__ */ jsx5(RowLabel, { children: label }),
1032
+ actions: /* @__PURE__ */ jsxs5(Fragment2, { children: [
1033
+ kind === "translated" ? /* @__PURE__ */ jsx5(Chip, { tone: "sky", label: "Translated", title: "Kept as set and sent as this model's closest equivalent" }) : /* @__PURE__ */ jsx5(Chip, { tone: "warning", label: "Not on this model", title: "This model has no such setting" }),
1034
+ onReset ? /* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: /* @__PURE__ */ jsx5(RotateCcwGlyph, {}), onClick: onReset, disabled, "aria-label": `${resetLabel}: ${label}`, title: resetLabel }) : /* @__PURE__ */ jsx5(Button2, { variant: "quiet", removes: true, icon: /* @__PURE__ */ jsx5(Trash2Glyph, {}), onClick: onClear, disabled, "aria-label": `Clear ${label}`, title: "Clear to not set" })
1035
+ ] }),
1036
+ children: /* @__PURE__ */ jsx5(RowText, { mono: true, children: isOffValue(value, null) ? "Off" : formatSettingValue(value) })
1037
+ }
1038
+ );
1039
+ }
1040
+ function ModelSettingsPanel({
1041
+ controls,
1042
+ values,
1043
+ target,
1044
+ idPrefix,
1045
+ model,
1046
+ notices,
1047
+ renderRow,
1048
+ capabilities,
1049
+ emptyNote,
1050
+ disabled = false
1051
+ }) {
1052
+ const groups = controls ? buildSettingsRows(controls, values).filter((group) => group.rows.length > 0) : [];
1053
+ return /* @__PURE__ */ jsxs5("div", { "data-model-settings-panel": "", className: "@container flex min-w-0 flex-col", children: [
1054
+ model ? /* @__PURE__ */ jsx5(SettingRowFrame, { rowKey: "model", label: /* @__PURE__ */ jsx5(RowLabel, { children: "Model" }), children: model }) : null,
1055
+ notices,
1056
+ groups.length === 0 && emptyNote ? /* @__PURE__ */ jsx5("div", { className: "py-2 type-secondary text-muted-foreground", children: emptyNote }) : null,
1057
+ groups.map((group) => /* @__PURE__ */ jsx5(SettingsGroupSection, { id: group.id, title: group.label || void 0, children: group.rows.map((row) => {
1058
+ const custom = renderRow?.(row);
1059
+ if (custom !== void 0) return /* @__PURE__ */ jsx5("div", { children: custom }, row.key);
1060
+ if (!row.control) return null;
1061
+ return /* @__PURE__ */ jsx5(
1062
+ ModelSettingRow,
1063
+ {
1064
+ row,
1065
+ control: row.control,
1066
+ target,
1067
+ idPrefix,
1068
+ disabled
1069
+ },
1070
+ row.key
1071
+ );
1072
+ }) }, group.id)),
1073
+ capabilities ? /* @__PURE__ */ jsx5(
1074
+ InputCapabilitiesEditor,
1075
+ {
1076
+ values: capabilities.values,
1077
+ onChange: capabilities.change,
1078
+ changedKeys: capabilities.changedKeys,
1079
+ onReset: capabilities.resetToInherited,
1080
+ resetLabel: target.resetLabel,
1081
+ error: capabilities.error,
1082
+ idPrefix: `${idPrefix}-capability`,
1083
+ disabled
1084
+ }
1085
+ ) : null
708
1086
  ] });
709
1087
  }
710
1088
 
@@ -734,9 +1112,14 @@ function memoEffective(entry) {
734
1112
  return hit;
735
1113
  }
736
1114
  export {
737
- ENUM_OFF_VALUE,
1115
+ ExtraSettingRow,
738
1116
  InputCapabilitiesEditor,
1117
+ ModelSettingsPanel,
739
1118
  SettingControlInput,
1119
+ SettingRowFrame,
1120
+ RowLabel as SettingRowLabel,
1121
+ SettingsGroupSection,
1122
+ formatSettingValue,
740
1123
  useEffectiveSettings,
741
1124
  useSettingsEntry,
742
1125
  useSettingsSelector