@green-on-grey/ui-kit 1.7.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,57 @@
1
+ import type { ReactNode } from "react";
2
+ import type { TFunction } from "i18next";
3
+ import { type AgentModelOption, type AgentOption } from "./AgentMenu";
4
+ /** A model the agent can run on, as the service of the agent gives it
5
+ * (FTR.NAB.CHAT-0001 tech §2.2: `availableModels`, `model`, `defaultModel`). */
6
+ export interface AgentModel {
7
+ connectionId: string;
8
+ model: string;
9
+ name: string;
10
+ /** The connection the model comes through: grey under its name. */
11
+ connection: string;
12
+ caps: {
13
+ image: boolean;
14
+ reasoning: boolean;
15
+ contextWindow: number;
16
+ };
17
+ }
18
+ /** What the user chose; null — the default model. */
19
+ export type AgentModelChoice = Pick<AgentModel, "connectionId" | "model"> | null;
20
+ /** The models of the agent for the block «Model». */
21
+ export interface AgentModelState {
22
+ available: AgentModel[];
23
+ /** The model in use. */
24
+ model: AgentModel | null;
25
+ defaultModel: AgentModel | null;
26
+ /** The user chose the model; false — the default one. */
27
+ chosen: boolean;
28
+ /** The fill of the context of the main conversation, in tokens. */
29
+ contextTokens: number;
30
+ }
31
+ /** The key of a model of a connection in the menu. */
32
+ export declare const agentModelKey: (m: Pick<AgentModel, "connectionId" | "model">) => string;
33
+ /** The lines of the block «Model» (FTR.NAB.CHAT-0001 R16, R17, design §3.3): with a
34
+ * choice the first line is «Default» with the default model under it; a model
35
+ * whose window the context outgrows warns; one model is shown without a choice. */
36
+ export declare function agentModelOptions(t: TFunction, lng: string, s: AgentModelState): {
37
+ options: AgentModelOption[];
38
+ value: string;
39
+ };
40
+ /** The menu of the agent, the same in every product (FTR.NAB.CMN-0005 R15;
41
+ * FTR.HMR.SPEC-0001): the name, the options of the product as tiles in two
42
+ * columns, the model when the product gives `models`, and the hint. What the
43
+ * options mean only the product knows (R7): it passes them with their icons. The
44
+ * strings are the kit's; `hint` replaces the hint of the kit where the product
45
+ * saves the agent elsewhere. */
46
+ export declare function AgentSettingsMenu({ name, value, options, models, hint, onRename, onPick, onModel, onClose }: {
47
+ name: string;
48
+ value: string;
49
+ options: AgentOption[];
50
+ models?: AgentModelState;
51
+ hint?: ReactNode;
52
+ onRename: (name: string) => void;
53
+ onPick: (key: string) => void;
54
+ onModel?: (choice: AgentModelChoice) => void;
55
+ /** Must keep its identity between renders. */
56
+ onClose: () => void;
57
+ }): import("react").JSX.Element;
@@ -13,3 +13,5 @@ export declare function MessageView({ m, busy, onRetry, loadAttachment, onOpenAt
13
13
  loadAttachment?: LoadAttachment;
14
14
  onOpenAttachment?: (a: ChatAttachment) => void;
15
15
  }): import("react").JSX.Element;
16
+ /** A notice longer than this many lines is folded (FTR.NAB.CHAT-0002 design §3.1). */
17
+ export declare const NOTICE_LINES = 12;
@@ -2,8 +2,9 @@ export { Chat, VoiceButton } from "./Chat";
2
2
  export { ChatLayout, ConversationList, NewTopicModal } from "./ConversationList";
3
3
  export { AttachmentList, AttachmentPreview, fileSize, parseTable, previewIcon, previewKind, type LoadAttachment, type PreviewKind } from "./Attachments";
4
4
  export { AgentButton, AgentMenu, type AgentModelOption, type AgentModels, type AgentOption } from "./AgentMenu";
5
+ export { AgentSettingsMenu, agentModelKey, agentModelOptions, type AgentModel, type AgentModelChoice, type AgentModelState, } from "./AgentSettingsMenu";
5
6
  export { CommandPalette } from "./CommandPalette";
6
7
  export { ContextMeter, tokens } from "./ContextMeter";
7
- export { MessageView } from "./MessageView";
8
+ export { MessageView, NOTICE_LINES } from "./MessageView";
8
9
  export { useRecorder } from "./useRecorder";
9
10
  export type { ChatAttachment, ChatCommand, ChatConfirmation, ChatContext, ChatConversation, ChatEvent, ChatMark, ChatMessage, ChatProps, ChatStep, ChatUpload, ChatWait, ConversationListProps, } from "./types";
@@ -66,6 +66,9 @@ export interface ChatMessage {
66
66
  };
67
67
  /** The content of the product inside the message: a mail card, a digest. */
68
68
  content?: ReactNode;
69
+ /** `notice`: an answer that is a notice of a product, not words of the agent (FTR.NAB.CHAT-0002 R2):
70
+ * a card with a stripe, without the actions of an answer, folded past `NOTICE_LINES` lines. */
71
+ variant?: "notice";
69
72
  /** The tooltip of the bubble: the model of an answer (FTR.NAB.CHAT-0001 R18). */
70
73
  hint?: string;
71
74
  }
@@ -99,6 +102,11 @@ export interface ChatProps {
99
102
  header?: ReactNode;
100
103
  /** The second line of the empty conversation. */
101
104
  emptyHint?: ReactNode;
105
+ /** Replaces the whole empty conversation: the draft of a topic with its suggestions
106
+ * (FTR.HMR.DISC-0001 design §3.2). `emptyHint` is then not used. */
107
+ empty?: ReactNode;
108
+ /** The placeholder of the composer instead of «Message to <agent>»; a picked skill keeps its own. */
109
+ placeholder?: string;
102
110
  loading?: boolean;
103
111
  historyError?: ReactNode;
104
112
  hasOlder?: boolean;
package/dist/chat.js CHANGED
@@ -555,16 +555,16 @@ function te({ a: e, load: i, onClose: u }) {
555
555
  }
556
556
  //#endregion
557
557
  //#region src/chat/MessageView.tsx
558
- function G(e, t) {
558
+ function ne(e, t) {
559
559
  return new Intl.DateTimeFormat(y(t), {
560
560
  hour: "2-digit",
561
561
  minute: "2-digit"
562
562
  }).format(new Date(e));
563
563
  }
564
- function K(e, t) {
564
+ function re(e, t) {
565
565
  return t || e.length <= 3 ? e : e.slice(-2);
566
566
  }
567
- var q = {
567
+ var G = {
568
568
  done: {
569
569
  icon: "check",
570
570
  cls: "ok"
@@ -578,13 +578,13 @@ var q = {
578
578
  cls: "run"
579
579
  }
580
580
  };
581
- function ne({ m: e, busy: n, onRetry: i, loadAttachment: a, onOpenAttachment: u }) {
581
+ function ie({ m: e, busy: n, onRetry: i, loadAttachment: a, onOpenAttachment: u }) {
582
582
  let { t: d, i18n: f } = g(o), [p, m] = h(!1);
583
583
  if (e.role === "note") return /* @__PURE__ */ c("div", {
584
584
  className: "sysnote",
585
585
  children: e.text
586
586
  });
587
- if (e.role === "event" && e.event) return /* @__PURE__ */ c(J, { m: e });
587
+ if (e.role === "event" && e.event) return /* @__PURE__ */ c(ae, { m: e });
588
588
  let _ = e.mark && /* @__PURE__ */ l("div", {
589
589
  className: "chan",
590
590
  children: [
@@ -595,7 +595,7 @@ function ne({ m: e, busy: n, onRetry: i, loadAttachment: a, onOpenAttachment: u
595
595
  " ",
596
596
  e.mark.text,
597
597
  " · ",
598
- G(e.createdAt, f.language)
598
+ ne(e.createdAt, f.language)
599
599
  ]
600
600
  }), v = e.attachments && e.attachments.length > 0 && /* @__PURE__ */ c(V, {
601
601
  items: e.attachments,
@@ -625,6 +625,11 @@ function ne({ m: e, busy: n, onRetry: i, loadAttachment: a, onOpenAttachment: u
625
625
  })
626
626
  ]
627
627
  });
628
+ if (e.variant === "notice") return /* @__PURE__ */ c(q, {
629
+ m: e,
630
+ mark: _,
631
+ atts: v
632
+ });
628
633
  let y = e.steps ?? [], b = (e.status === "streaming" || e.status === "pending") && !e.text && !e.content;
629
634
  return /* @__PURE__ */ l("div", {
630
635
  className: "m a",
@@ -636,13 +641,13 @@ function ne({ m: e, busy: n, onRetry: i, loadAttachment: a, onOpenAttachment: u
636
641
  "aria-expanded": p,
637
642
  children: p ? d("chat.hideSteps") : d("chat.moreSteps", { count: y.length - 2 })
638
643
  }),
639
- K(y, p).map((e) => /* @__PURE__ */ l("div", {
644
+ re(y, p).map((e) => /* @__PURE__ */ l("div", {
640
645
  className: "tool",
641
646
  title: e.title,
642
647
  children: [/* @__PURE__ */ c(t, {
643
- name: q[e.status].icon,
648
+ name: G[e.status].icon,
644
649
  size: 14,
645
- className: q[e.status].cls
650
+ className: G[e.status].cls
646
651
  }), /* @__PURE__ */ c("span", {
647
652
  className: "tx",
648
653
  children: e.text
@@ -686,7 +691,28 @@ function ne({ m: e, busy: n, onRetry: i, loadAttachment: a, onOpenAttachment: u
686
691
  ]
687
692
  });
688
693
  }
689
- function J({ m: e }) {
694
+ var K = 12;
695
+ function q({ m: e, mark: t, atts: n }) {
696
+ let { t: i } = g(o), [a, s] = h(!1), u = !e.content && e.text.split("\n").length > 12;
697
+ return /* @__PURE__ */ l("div", {
698
+ className: "m a notice",
699
+ children: [
700
+ t,
701
+ e.content ?? /* @__PURE__ */ l("div", {
702
+ className: `bub${u && !a ? " folded" : ""}`,
703
+ children: [/* @__PURE__ */ c(r, { text: e.text }), u && /* @__PURE__ */ c("button", {
704
+ type: "button",
705
+ className: "textbtn",
706
+ "aria-expanded": a,
707
+ onClick: () => s((e) => !e),
708
+ children: i(a ? "chat.notice.less" : "chat.notice.more")
709
+ })]
710
+ }),
711
+ n
712
+ ]
713
+ });
714
+ }
715
+ function ae({ m: e }) {
690
716
  let { t: n, i18n: r } = g(o), [i, a] = h(!1), s = e.event;
691
717
  return /* @__PURE__ */ l("div", {
692
718
  className: "evdiv",
@@ -702,7 +728,7 @@ function J({ m: e }) {
702
728
  }),
703
729
  s.text,
704
730
  " · ",
705
- G(e.createdAt, r.language),
731
+ ne(e.createdAt, r.language),
706
732
  s.details && /* @__PURE__ */ l("button", {
707
733
  type: "button",
708
734
  className: "textbtn",
@@ -724,20 +750,20 @@ function J({ m: e }) {
724
750
  }
725
751
  //#endregion
726
752
  //#region src/chat/transcription.ts
727
- async function re(e, t, n) {
753
+ async function oe(e, t, n) {
728
754
  n.busy(!0);
729
755
  let r;
730
756
  try {
731
757
  r = await t(e);
732
758
  } catch (r) {
733
- n.busy(!1), n.failed(r instanceof Error && r.message ? r.message : void 0, () => void re(e, t, n));
759
+ n.busy(!1), n.failed(r instanceof Error && r.message ? r.message : void 0, () => void oe(e, t, n));
734
760
  return;
735
761
  }
736
762
  n.busy(!1), r !== null && (r ? n.text(r) : n.empty());
737
763
  }
738
764
  //#endregion
739
765
  //#region src/chat/useRecorder.ts
740
- function ie(e = 300, t) {
766
+ function se(e = 300, t) {
741
767
  let n = typeof window < "u" && "MediaRecorder" in window && !!navigator.mediaDevices?.getUserMedia, [r, i] = h(!1), [a, o] = h(0), [s, c] = h(0), [l, f] = h(!1), p = m(null), g = m([]), _ = m(void 0), v = m(null), y = m(null), b = m(!1), x = m(t);
742
768
  d(() => {
743
769
  x.current = t;
@@ -799,78 +825,78 @@ function ie(e = 300, t) {
799
825
  cancel: T
800
826
  };
801
827
  }
802
- function ae(e) {
828
+ function ce(e) {
803
829
  return `${Math.floor(e / 60)}:${String(e % 60).padStart(2, "0")}`;
804
830
  }
805
831
  //#endregion
806
832
  //#region src/chat/Chat.tsx
807
- function Y(n) {
833
+ function le(n) {
808
834
  let r = a(), i = e(), [o, u] = h(""), [g, y] = h([]), [b, S] = h(!1), [C, w] = h(null), [T, E] = h(0), [D, O] = h(!1), [k, A] = h(null), [j, ee] = h(!1), [M, N] = h(null), P = m(n.loadAttachment);
809
835
  d(() => {
810
836
  P.current = n.loadAttachment;
811
837
  });
812
- let F = !!n.loadAttachment, I = p(() => F ? (e) => P.current ? P.current(e) : Promise.reject(/* @__PURE__ */ Error("no loader")) : void 0, [F]), L = m(!1), R = m(null), z = m(null), B = m(null), V = n.voiceMaxSeconds ?? 300, H = ie(V, () => void ve()), { messages: U, busy: W = !1 } = n, G = W || U.some((e) => e.status === "pending" || e.status === "streaming"), K = n.onPendingChange;
813
- d(() => K?.(g), [g, K]);
814
- let q = U[0]?.id, J = U[U.length - 1], Y = J?.id, ce = J?.text.length, de = J?.steps?.length, X = m({ height: 0 });
838
+ let F = !!n.loadAttachment, I = p(() => F ? (e) => P.current ? P.current(e) : Promise.reject(/* @__PURE__ */ Error("no loader")) : void 0, [F]), L = m(!1), R = m(null), z = m(null), B = m(null), V = n.voiceMaxSeconds ?? 300, H = se(V, () => void ve()), { messages: U, busy: W = !1 } = n, ne = W || U.some((e) => e.status === "pending" || e.status === "streaming"), re = n.onPendingChange;
839
+ d(() => re?.(g), [g, re]);
840
+ let G = U[0]?.id, K = U[U.length - 1], q = K?.id, ae = K?.text.length, le = K?.steps?.length, fe = m({ height: 0 });
815
841
  f(() => {
816
842
  let e = R.current;
817
843
  if (!e) return;
818
- let t = X.current;
819
- e.scrollTop = t.first !== void 0 && q !== t.first && Y === t.last ? e.scrollTop + (e.scrollHeight - t.height) : e.scrollHeight, X.current = {
820
- first: q,
821
- last: Y,
844
+ let t = fe.current;
845
+ e.scrollTop = t.first !== void 0 && G !== t.first && q === t.last ? e.scrollTop + (e.scrollHeight - t.height) : e.scrollHeight, fe.current = {
846
+ first: G,
847
+ last: q,
822
848
  height: e.scrollHeight
823
849
  };
824
850
  }, [
825
851
  U.length,
852
+ G,
826
853
  q,
827
- Y,
828
- ce,
829
- de
854
+ ae,
855
+ le
830
856
  ]);
831
- let Z = n.commands && !C && o.startsWith("/") && !/\s/.test(o) ? o.slice(1) : null, Q = Z === null ? [] : _(n.commands ?? [], Z), $ = Z !== null && !D, fe = () => {
857
+ let J = n.commands && !C && o.startsWith("/") && !/\s/.test(o) ? o.slice(1) : null, Y = J === null ? [] : _(n.commands ?? [], J), X = J !== null && !D, he = () => {
832
858
  u(""), y([]), w(null), A(null), L.current = !1;
833
- }, pe = async (e, t) => {
859
+ }, Z = async (e, t) => {
834
860
  if (n.onCommand) try {
835
- await n.onCommand(e, t), fe();
861
+ await n.onCommand(e, t), he();
836
862
  } catch {}
837
- }, me = async (e, t = !1) => {
863
+ }, Q = async (e, t = !1) => {
838
864
  let r = e.trim();
839
865
  if (!(!r && g.length === 0 && !C || W || n.readOnly)) {
840
866
  if (!t && !C && n.commands && r.startsWith("/")) {
841
867
  let [e, ...t] = r.slice(1).split(/\s+/), i = n.commands.find((t) => t.kind === "command" && t.name === e);
842
- if (i) return pe(i.name, t.join(" "));
868
+ if (i) return Z(i.name, t.join(" "));
843
869
  if (e && !r.includes("\n")) {
844
870
  A("/" + e);
845
871
  return;
846
872
  }
847
873
  }
848
874
  try {
849
- await n.onSend(r, g.map((e) => e.id), L.current, C ?? void 0), fe();
875
+ await n.onSend(r, g.map((e) => e.id), L.current, C ?? void 0), he();
850
876
  } catch {}
851
877
  }
852
- }, he = (e) => {
853
- E(0), e.kind === "skill" ? (w(e.name), u("")) : e.takesText ? u("/" + e.name + " ") : pe(e.name, ""), B.current?.focus();
878
+ }, $ = (e) => {
879
+ E(0), e.kind === "skill" ? (w(e.name), u("")) : e.takesText ? u("/" + e.name + " ") : Z(e.name, ""), B.current?.focus();
854
880
  }, ge = (e) => {
855
- if ($ && Q.length > 0) {
881
+ if (X && Y.length > 0) {
856
882
  if (e.key === "ArrowDown" || e.key === "ArrowUp") {
857
883
  e.preventDefault();
858
884
  let t = e.key === "ArrowDown" ? 1 : -1;
859
- E((e) => (e + t + Q.length) % Q.length);
885
+ E((e) => (e + t + Y.length) % Y.length);
860
886
  return;
861
887
  }
862
888
  if (e.key === "Enter" && !e.shiftKey || e.key === "Tab") {
863
- e.preventDefault(), he(Q[Math.min(T, Q.length - 1)]);
889
+ e.preventDefault(), $(Y[Math.min(T, Y.length - 1)]);
864
890
  return;
865
891
  }
866
892
  }
867
- $ && e.key === "Escape" ? (e.preventDefault(), O(!0)) : e.key === "Backspace" && C && o === "" ? w(null) : e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing && !se() && (e.preventDefault(), me(o));
893
+ X && e.key === "Escape" ? (e.preventDefault(), O(!0)) : e.key === "Backspace" && C && o === "" ? w(null) : e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing && !de() && (e.preventDefault(), Q(o));
868
894
  };
869
- f(() => le(R.current, () => ue(B.current)), [o]), d(() => {
895
+ f(() => pe(R.current, () => me(B.current)), [o]), d(() => {
870
896
  let e = B.current;
871
897
  if (!e || typeof ResizeObserver > "u") return;
872
898
  let t = e.clientWidth, n = new ResizeObserver(() => {
873
- e.clientWidth !== t && (t = e.clientWidth, le(R.current, () => ue(e)));
899
+ e.clientWidth !== t && (t = e.clientWidth, pe(R.current, () => me(e)));
874
900
  });
875
901
  return n.observe(e), () => n.disconnect();
876
902
  }, [H.recording]);
@@ -894,7 +920,7 @@ function Y(n) {
894
920
  };
895
921
  async function ve() {
896
922
  let e = await H.stop();
897
- e && n.onTranscribe && await re(e, n.onTranscribe, {
923
+ e && n.onTranscribe && await oe(e, n.onTranscribe, {
898
924
  busy: ee,
899
925
  empty: () => i({
900
926
  kind: "error",
@@ -916,7 +942,7 @@ function Y(n) {
916
942
  }
917
943
  let ye = (e) => {
918
944
  e.key === "Escape" && H.recording && (e.preventDefault(), H.cancel());
919
- }, be = C ? r("chat.skillPlaceholder") : r("chat.placeholder", { name: n.agentName }), xe = V - H.seconds;
945
+ }, be = C ? r("chat.skillPlaceholder") : n.placeholder ?? r("chat.placeholder", { name: n.agentName }), xe = V - H.seconds;
920
946
  return /* @__PURE__ */ l("section", {
921
947
  className: "nb-chat",
922
948
  "aria-label": r("chat.title"),
@@ -938,7 +964,7 @@ function Y(n) {
938
964
  className: "err-text",
939
965
  children: n.historyError
940
966
  }),
941
- U.length === 0 && !n.loading && !n.historyError && /* @__PURE__ */ l("div", {
967
+ U.length === 0 && !n.loading && !n.historyError && (n.empty ?? /* @__PURE__ */ l("div", {
942
968
  className: "empty",
943
969
  children: [
944
970
  /* @__PURE__ */ c("div", {
@@ -948,8 +974,8 @@ function Y(n) {
948
974
  /* @__PURE__ */ c("b", { children: r("chat.emptyTitle", { name: n.agentName }) }),
949
975
  n.emptyHint
950
976
  ]
951
- }),
952
- U.map((e) => /* @__PURE__ */ c(ne, {
977
+ })),
978
+ U.map((e) => /* @__PURE__ */ c(ie, {
953
979
  m: e,
954
980
  busy: W,
955
981
  onRetry: n.onRetry && (() => n.onRetry?.(e.id)),
@@ -996,10 +1022,10 @@ function Y(n) {
996
1022
  }) : /* @__PURE__ */ l("div", {
997
1023
  className: "composer-wrap",
998
1024
  children: [
999
- $ && /* @__PURE__ */ c(v, {
1000
- items: Q,
1001
- active: Math.min(T, Math.max(Q.length - 1, 0)),
1002
- onPick: he,
1025
+ X && /* @__PURE__ */ c(v, {
1026
+ items: Y,
1027
+ active: Math.min(T, Math.max(Y.length - 1, 0)),
1028
+ onPick: $,
1003
1029
  onHover: E
1004
1030
  }),
1005
1031
  n.aboveComposer,
@@ -1035,7 +1061,7 @@ function Y(n) {
1035
1061
  children: [r("chat.unknownCommand", { name: k }), /* @__PURE__ */ c("button", {
1036
1062
  type: "button",
1037
1063
  className: "textbtn",
1038
- onClick: () => void me(o, !0),
1064
+ onClick: () => void Q(o, !0),
1039
1065
  children: r("chat.sendAsText")
1040
1066
  })]
1041
1067
  }),
@@ -1068,9 +1094,9 @@ function Y(n) {
1068
1094
  /* @__PURE__ */ l("span", {
1069
1095
  className: "tm",
1070
1096
  children: [
1071
- ae(H.seconds),
1097
+ ce(H.seconds),
1072
1098
  " / ",
1073
- ae(V)
1099
+ ce(V)
1074
1100
  ]
1075
1101
  }),
1076
1102
  /* @__PURE__ */ c("span", {
@@ -1124,7 +1150,7 @@ function Y(n) {
1124
1150
  placeholder: j ? r("chat.voice.recognizing") : be,
1125
1151
  "aria-label": be,
1126
1152
  disabled: j,
1127
- "aria-expanded": $,
1153
+ "aria-expanded": X,
1128
1154
  "aria-autocomplete": n.commands ? "list" : void 0,
1129
1155
  onChange: (e) => {
1130
1156
  u(e.target.value), O(!1), E(0), A(null);
@@ -1136,9 +1162,9 @@ function Y(n) {
1136
1162
  context: n.context,
1137
1163
  onCompact: n.onCompact,
1138
1164
  onReset: n.onReset,
1139
- busy: G
1165
+ busy: ne
1140
1166
  }),
1141
- n.onTranscribe && !H.recording && /* @__PURE__ */ c(oe, {
1167
+ n.onTranscribe && !H.recording && /* @__PURE__ */ c(ue, {
1142
1168
  supported: H.supported,
1143
1169
  recognizing: j,
1144
1170
  onStart: () => void H.start()
@@ -1152,7 +1178,7 @@ function Y(n) {
1152
1178
  className: "iconbtn fill",
1153
1179
  "aria-label": r("chat.send"),
1154
1180
  disabled: !o.trim() && g.length === 0 && !C || W || j,
1155
- onClick: () => me(o),
1181
+ onClick: () => Q(o),
1156
1182
  children: /* @__PURE__ */ c(t, { name: "send" })
1157
1183
  }))
1158
1184
  ]
@@ -1172,7 +1198,7 @@ function Y(n) {
1172
1198
  ]
1173
1199
  });
1174
1200
  }
1175
- function oe({ supported: e, recognizing: n, onStart: r }) {
1201
+ function ue({ supported: e, recognizing: n, onStart: r }) {
1176
1202
  let i = a();
1177
1203
  return n ? /* @__PURE__ */ l("span", {
1178
1204
  className: "voicewait",
@@ -1195,15 +1221,15 @@ function oe({ supported: e, recognizing: n, onStart: r }) {
1195
1221
  children: /* @__PURE__ */ c(t, { name: "mic" })
1196
1222
  });
1197
1223
  }
1198
- function se() {
1224
+ function de() {
1199
1225
  return typeof window < "u" && !!window.matchMedia?.("(hover: none) and (pointer: coarse)").matches;
1200
1226
  }
1201
- var ce = (e) => e.scrollHeight - e.scrollTop - e.clientHeight < 2;
1202
- function le(e, t) {
1203
- let n = !!e && ce(e);
1227
+ var fe = (e) => e.scrollHeight - e.scrollTop - e.clientHeight < 2;
1228
+ function pe(e, t) {
1229
+ let n = !!e && fe(e);
1204
1230
  t(), e && n && (e.scrollTop = e.scrollHeight);
1205
1231
  }
1206
- function ue(e) {
1232
+ function me(e) {
1207
1233
  if (!e) return;
1208
1234
  e.style.overflowY = "hidden", e.style.height = "auto";
1209
1235
  let t = e.scrollHeight + e.offsetHeight - e.clientHeight;
@@ -1211,7 +1237,7 @@ function ue(e) {
1211
1237
  }
1212
1238
  //#endregion
1213
1239
  //#region src/chat/ConversationList.tsx
1214
- function de({ conversations: e, currentId: n, open: r, onPick: i, onClose: o, onCreate: u }) {
1240
+ function J({ conversations: e, currentId: n, open: r, onPick: i, onClose: o, onCreate: u }) {
1215
1241
  let f = a(), [p, m] = h(!1);
1216
1242
  d(() => {
1217
1243
  if (!r) return;
@@ -1287,19 +1313,19 @@ function de({ conversations: e, currentId: n, open: r, onPick: i, onClose: o, on
1287
1313
  "aria-label": f("close"),
1288
1314
  onClick: o
1289
1315
  }),
1290
- p && u && /* @__PURE__ */ c(Z, {
1316
+ p && u && /* @__PURE__ */ c(X, {
1291
1317
  onClose: () => m(!1),
1292
1318
  onCreate: u
1293
1319
  })
1294
1320
  ] });
1295
1321
  }
1296
- function X({ narrow: e, children: t }) {
1322
+ function Y({ narrow: e, children: t }) {
1297
1323
  return /* @__PURE__ */ c("div", {
1298
1324
  className: `nb-app${e ? " narrow" : ""}`,
1299
1325
  children: t
1300
1326
  });
1301
1327
  }
1302
- function Z({ onClose: e, onCreate: t }) {
1328
+ function X({ onClose: e, onCreate: t }) {
1303
1329
  let r = a(), [i, o] = h(""), [u, d] = h(!1), [f, p] = h(null), m = async () => {
1304
1330
  if (i.trim() && !u) {
1305
1331
  d(!0), p(null);
@@ -1351,7 +1377,7 @@ function Z({ onClose: e, onCreate: t }) {
1351
1377
  }
1352
1378
  //#endregion
1353
1379
  //#region src/chat/AgentMenu.tsx
1354
- function Q({ icon: e, label: n, title: r, expanded: i, small: a, disabled: o, onClick: s }) {
1380
+ function he({ icon: e, label: n, title: r, expanded: i, small: a, disabled: o, onClick: s }) {
1355
1381
  return /* @__PURE__ */ c("button", {
1356
1382
  type: "button",
1357
1383
  className: `agentbtn${a ? " s" : ""}`,
@@ -1367,7 +1393,7 @@ function Q({ icon: e, label: n, title: r, expanded: i, small: a, disabled: o, on
1367
1393
  })
1368
1394
  });
1369
1395
  }
1370
- function $({ label: e, name: n, options: r, value: o, optionsLabel: u, hint: d, narrow: f, models: p, onRename: m, onPick: g, onClose: _ }) {
1396
+ function Z({ label: e, name: n, options: r, value: o, optionsLabel: u, hint: d, narrow: f, models: p, onRename: m, onPick: g, onClose: _ }) {
1371
1397
  let v = a(), [y, b] = h(n), x = i(!0, _);
1372
1398
  return /* @__PURE__ */ l("div", {
1373
1399
  className: `agentmenu${f ? " narrow" : ""}`,
@@ -1478,6 +1504,66 @@ function $({ label: e, name: n, options: r, value: o, optionsLabel: u, hint: d,
1478
1504
  });
1479
1505
  }
1480
1506
  //#endregion
1481
- export { Q as AgentButton, $ as AgentMenu, V as AttachmentList, te as AttachmentPreview, Y as Chat, X as ChatLayout, v as CommandPalette, x as ContextMeter, de as ConversationList, ne as MessageView, Z as NewTopicModal, oe as VoiceButton, A as fileSize, L as parseTable, O as previewIcon, E as previewKind, b as tokens, ie as useRecorder };
1507
+ //#region src/chat/AgentSettingsMenu.tsx
1508
+ var Q = (e) => `${e.connectionId}/${e.model}`;
1509
+ function $(e, t, n) {
1510
+ let r = (n) => [
1511
+ ...n.caps.image ? [{
1512
+ icon: "image",
1513
+ text: e("agent.capImage")
1514
+ }] : [],
1515
+ ...n.caps.reasoning ? [{
1516
+ icon: "brain",
1517
+ text: e("agent.capReasoning")
1518
+ }] : [],
1519
+ ...n.caps.contextWindow > 0 ? [{ text: b(n.caps.contextWindow, t) }] : []
1520
+ ], i = (t) => t.caps.contextWindow > 0 && n.contextTokens > .8 * t.caps.contextWindow ? e("agent.modelCompactWarn") : void 0, a = n.available.length > 1, o = n.available.map((e) => ({
1521
+ key: Q(e),
1522
+ label: e.name,
1523
+ sub: e.connection,
1524
+ badges: r(e),
1525
+ warn: a ? i(e) : void 0
1526
+ }));
1527
+ return {
1528
+ options: a ? [{
1529
+ key: "",
1530
+ label: e("agent.modelDefault"),
1531
+ sub: n.defaultModel?.name ?? "—",
1532
+ warn: n.defaultModel ? i(n.defaultModel) : void 0
1533
+ }, ...o] : o,
1534
+ value: n.chosen && n.model ? Q(n.model) : a ? "" : n.model ? Q(n.model) : ""
1535
+ };
1536
+ }
1537
+ function ge({ name: e, value: t, options: n, models: r, hint: i, onRename: o, onPick: s, onModel: l, onClose: u }) {
1538
+ let d = a(), { i18n: f } = g(), p = r && l ? $(d, f.language, r) : null;
1539
+ return /* @__PURE__ */ c(Z, {
1540
+ label: d("agent.menu"),
1541
+ name: e,
1542
+ value: t,
1543
+ optionsLabel: d("agent.options"),
1544
+ hint: i ?? d("agent.everywhere"),
1545
+ options: n,
1546
+ models: p ? {
1547
+ label: d("agent.model"),
1548
+ options: p.options,
1549
+ value: p.value,
1550
+ onPick: (e) => {
1551
+ if (!r || !l) return;
1552
+ if (!e) return l(null);
1553
+ let t = r.available.find((t) => Q(t) === e);
1554
+ t && l({
1555
+ connectionId: t.connectionId,
1556
+ model: t.model
1557
+ });
1558
+ },
1559
+ empty: d("agent.noModels")
1560
+ } : void 0,
1561
+ onRename: o,
1562
+ onPick: s,
1563
+ onClose: u
1564
+ });
1565
+ }
1566
+ //#endregion
1567
+ export { he as AgentButton, Z as AgentMenu, ge as AgentSettingsMenu, V as AttachmentList, te as AttachmentPreview, le as Chat, Y as ChatLayout, v as CommandPalette, x as ContextMeter, J as ConversationList, ie as MessageView, K as NOTICE_LINES, X as NewTopicModal, ue as VoiceButton, Q as agentModelKey, $ as agentModelOptions, A as fileSize, L as parseTable, O as previewIcon, E as previewKind, b as tokens, se as useRecorder };
1482
1568
 
1483
1569
  //# sourceMappingURL=chat.js.map