@green-on-grey/ui-kit 1.1.0 → 1.2.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,14 @@
1
+ /** What the composer does with the outcome of a recognition. */
2
+ export interface TranscriptionHandlers {
3
+ busy(on: boolean): void;
4
+ /** The recognized text goes into the composer. */
5
+ text(text: string): void;
6
+ /** Nothing was recognized. */
7
+ empty(): void;
8
+ /** The recognition failed: the reason and a way to try the same recording again. */
9
+ failed(reason: string | undefined, retry: () => void): void;
10
+ }
11
+ /** Recognizes a recording (FTR.NAB.CHAT-0001 R20, design §3.1). A rejection of the
12
+ * product is a failure the user may retry: the recording stays with the retry until
13
+ * the toast is closed. `null` means the product has told the user itself. */
14
+ export declare function transcribe(recording: Blob, recognize: (b: Blob) => Promise<string | null>, on: TranscriptionHandlers): Promise<void>;
@@ -131,7 +131,8 @@ export interface ChatProps {
131
131
  onUpload?(file: File): Promise<ChatUpload | null>;
132
132
  /** The files attached to the message being written, after every change. */
133
133
  onPendingChange?(uploads: ChatUpload[]): void;
134
- /** The text of a recording; `null`: it failed and the product has told the user. */
134
+ /** The text of a recording; `null`: it failed and the product has told the user. A rejection
135
+ * with an `Error` is shown by the kit with its message and «Retry» on the same recording. */
135
136
  onTranscribe?(recording: Blob): Promise<string | null>;
136
137
  }
137
138
  export interface ConversationListProps {
package/dist/chat.js CHANGED
@@ -24,7 +24,7 @@ function _({ items: e, active: n, onPick: r, onHover: i }) {
24
24
  size: 14
25
25
  }) : /* @__PURE__ */ c("span", {
26
26
  className: "slash",
27
- children: "/"
27
+ "aria-hidden": "true"
28
28
  }),
29
29
  /* @__PURE__ */ c("span", {
30
30
  className: "nm",
@@ -337,8 +337,21 @@ function T({ m: e }) {
337
337
  });
338
338
  }
339
339
  //#endregion
340
+ //#region src/chat/transcription.ts
341
+ async function E(e, t, n) {
342
+ n.busy(!0);
343
+ let r;
344
+ try {
345
+ r = await t(e);
346
+ } catch (r) {
347
+ n.busy(!1), n.failed(r instanceof Error && r.message ? r.message : void 0, () => void E(e, t, n));
348
+ return;
349
+ }
350
+ n.busy(!1), r !== null && (r ? n.text(r) : n.empty());
351
+ }
352
+ //#endregion
340
353
  //#region src/chat/useRecorder.ts
341
- function E(e = 300, t) {
354
+ function D(e = 300, t) {
342
355
  let n = typeof window < "u" && "MediaRecorder" in window && !!navigator.mediaDevices?.getUserMedia, [r, i] = m(!1), [a, o] = m(0), [s, c] = m(0), [l, f] = m(!1), h = p(null), g = p([]), _ = p(void 0), v = p(null), y = p(null), b = p(!1), x = p(t);
343
356
  d(() => {
344
357
  x.current = t;
@@ -400,15 +413,15 @@ function E(e = 300, t) {
400
413
  cancel: T
401
414
  };
402
415
  }
403
- function D(e) {
416
+ function O(e) {
404
417
  return `${Math.floor(e / 60)}:${String(e % 60).padStart(2, "0")}`;
405
418
  }
406
419
  //#endregion
407
420
  //#region src/chat/Chat.tsx
408
- function O(n) {
409
- let r = a(), i = e(), [o, u] = m(""), [h, v] = m([]), [b, x] = m(!1), [S, C] = m(null), [T, O] = m(0), [k, A] = m(!1), [j, M] = m(null), [N, P] = m(!1), F = p(!1), I = p(null), L = p(null), R = p(null), z = n.voiceMaxSeconds ?? 300, B = E(z, () => void ae()), { messages: V, busy: H = !1 } = n, U = n.onPendingChange;
421
+ function k(n) {
422
+ let r = a(), i = e(), [o, u] = m(""), [h, v] = m([]), [b, x] = m(!1), [S, C] = m(null), [T, k] = m(0), [A, j] = m(!1), [M, N] = m(null), [P, ee] = m(!1), F = p(!1), I = p(null), L = p(null), R = p(null), z = n.voiceMaxSeconds ?? 300, B = D(z, () => void oe()), { messages: V, busy: H = !1 } = n, U = n.onPendingChange;
410
423
  d(() => U?.(h), [h, U]);
411
- let W = V[0]?.id, G = V[V.length - 1], K = G?.id, ee = G?.text.length, te = G?.steps?.length, q = p({ height: 0 });
424
+ let W = V[0]?.id, G = V[V.length - 1], K = G?.id, te = G?.text.length, ne = G?.steps?.length, q = p({ height: 0 });
412
425
  f(() => {
413
426
  let e = I.current;
414
427
  if (!e) return;
@@ -422,11 +435,11 @@ function O(n) {
422
435
  V.length,
423
436
  W,
424
437
  K,
425
- ee,
426
- te
438
+ te,
439
+ ne
427
440
  ]);
428
- let J = n.commands && !S && o.startsWith("/") && !/\s/.test(o) ? o.slice(1) : null, Y = J === null ? [] : g(n.commands ?? [], J), X = J !== null && !k, Z = () => {
429
- u(""), v([]), C(null), M(null), F.current = !1;
441
+ let J = n.commands && !S && o.startsWith("/") && !/\s/.test(o) ? o.slice(1) : null, Y = J === null ? [] : g(n.commands ?? [], J), X = J !== null && !A, Z = () => {
442
+ u(""), v([]), C(null), N(null), F.current = !1;
430
443
  }, Q = async (e, t) => {
431
444
  if (n.onCommand) try {
432
445
  await n.onCommand(e, t), Z();
@@ -438,7 +451,7 @@ function O(n) {
438
451
  let [e, ...t] = r.slice(1).split(/\s+/), i = n.commands.find((t) => t.kind === "command" && t.name === e);
439
452
  if (i) return Q(i.name, t.join(" "));
440
453
  if (e && !r.includes("\n")) {
441
- M("/" + e);
454
+ N("/" + e);
442
455
  return;
443
456
  }
444
457
  }
@@ -446,23 +459,23 @@ function O(n) {
446
459
  await n.onSend(r, h.map((e) => e.id), F.current, S ?? void 0), Z();
447
460
  } catch {}
448
461
  }
449
- }, ne = (e) => {
450
- O(0), e.kind === "skill" ? (C(e.name), u("")) : e.takesText ? u("/" + e.name + " ") : Q(e.name, ""), R.current?.focus();
451
462
  }, re = (e) => {
463
+ k(0), e.kind === "skill" ? (C(e.name), u("")) : e.takesText ? u("/" + e.name + " ") : Q(e.name, ""), R.current?.focus();
464
+ }, ie = (e) => {
452
465
  if (X && Y.length > 0) {
453
466
  if (e.key === "ArrowDown" || e.key === "ArrowUp") {
454
467
  e.preventDefault();
455
468
  let t = e.key === "ArrowDown" ? 1 : -1;
456
- O((e) => (e + t + Y.length) % Y.length);
469
+ k((e) => (e + t + Y.length) % Y.length);
457
470
  return;
458
471
  }
459
472
  if (e.key === "Enter" && !e.shiftKey || e.key === "Tab") {
460
- e.preventDefault(), ne(Y[Math.min(T, Y.length - 1)]);
473
+ e.preventDefault(), re(Y[Math.min(T, Y.length - 1)]);
461
474
  return;
462
475
  }
463
476
  }
464
- X && e.key === "Escape" ? (e.preventDefault(), A(!0)) : e.key === "Backspace" && S && o === "" ? C(null) : e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing && (e.preventDefault(), $(o));
465
- }, ie = async (e) => {
477
+ X && e.key === "Escape" ? (e.preventDefault(), j(!0)) : e.key === "Backspace" && S && o === "" ? C(null) : e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing && (e.preventDefault(), $(o));
478
+ }, ae = async (e) => {
466
479
  if (e?.length && n.onUpload) {
467
480
  x(!0);
468
481
  for (let t of Array.from(e)) {
@@ -480,19 +493,31 @@ function O(n) {
480
493
  x(!1), L.current && (L.current.value = "");
481
494
  }
482
495
  };
483
- async function ae() {
496
+ async function oe() {
484
497
  let e = await B.stop();
485
- if (!e || !n.onTranscribe) return;
486
- P(!0);
487
- let t = await n.onTranscribe(e).catch(() => null);
488
- P(!1), t !== null && (t ? (F.current = !0, u((e) => e.trim() ? e.trimEnd() + " " + t : t), R.current?.focus()) : i({
489
- kind: "error",
490
- title: r("chat.voice.notRecognized")
491
- }));
498
+ e && n.onTranscribe && await E(e, n.onTranscribe, {
499
+ busy: ee,
500
+ empty: () => i({
501
+ kind: "error",
502
+ title: r("chat.voice.notRecognized")
503
+ }),
504
+ failed: (e, t) => i({
505
+ kind: "error",
506
+ title: e ?? r("chat.voice.failed"),
507
+ actions: [{
508
+ label: r("chat.voice.retry"),
509
+ primary: !0,
510
+ onClick: t
511
+ }]
512
+ }),
513
+ text: (e) => {
514
+ F.current = !0, u((t) => t.trim() ? t.trimEnd() + " " + e : e), R.current?.focus();
515
+ }
516
+ });
492
517
  }
493
- let oe = (e) => {
518
+ let se = (e) => {
494
519
  e.key === "Escape" && B.recording && (e.preventDefault(), B.cancel());
495
- }, se = S ? r("chat.skillPlaceholder") : r("chat.placeholder", { name: n.agentName }), ce = z - B.seconds;
520
+ }, ce = S ? r("chat.skillPlaceholder") : r("chat.placeholder", { name: n.agentName }), le = z - B.seconds;
496
521
  return /* @__PURE__ */ l("section", {
497
522
  className: "nb-chat",
498
523
  "aria-label": r("chat.title"),
@@ -573,8 +598,8 @@ function O(n) {
573
598
  X && /* @__PURE__ */ c(_, {
574
599
  items: Y,
575
600
  active: Math.min(T, Math.max(Y.length - 1, 0)),
576
- onPick: ne,
577
- onHover: O
601
+ onPick: re,
602
+ onHover: k
578
603
  }),
579
604
  n.aboveComposer,
580
605
  h.length > 0 && /* @__PURE__ */ c("div", {
@@ -603,10 +628,10 @@ function O(n) {
603
628
  ]
604
629
  }, e.id))
605
630
  }),
606
- j && /* @__PURE__ */ l("div", {
631
+ M && /* @__PURE__ */ l("div", {
607
632
  className: "cmd-unknown",
608
633
  role: "status",
609
- children: [r("chat.unknownCommand", { name: j }), /* @__PURE__ */ c("button", {
634
+ children: [r("chat.unknownCommand", { name: M }), /* @__PURE__ */ c("button", {
610
635
  type: "button",
611
636
  className: "textbtn",
612
637
  onClick: () => void $(o, !0),
@@ -628,10 +653,10 @@ function O(n) {
628
653
  multiple: !0,
629
654
  hidden: !0,
630
655
  accept: n.upload?.accept,
631
- onChange: (e) => ie(e.target.files)
656
+ onChange: (e) => ae(e.target.files)
632
657
  })] }),
633
658
  B.recording ? /* @__PURE__ */ l("div", {
634
- className: `recbar${ce <= 15 ? " ending" : ""}`,
659
+ className: `recbar${le <= 15 ? " ending" : ""}`,
635
660
  role: "status",
636
661
  "aria-label": r("chat.voice.recordingNow"),
637
662
  children: [
@@ -642,9 +667,9 @@ function O(n) {
642
667
  /* @__PURE__ */ l("span", {
643
668
  className: "tm",
644
669
  children: [
645
- D(B.seconds),
670
+ O(B.seconds),
646
671
  " / ",
647
- D(z)
672
+ O(z)
648
673
  ]
649
674
  }),
650
675
  /* @__PURE__ */ c("span", {
@@ -661,8 +686,8 @@ function O(n) {
661
686
  /* @__PURE__ */ c("button", {
662
687
  type: "button",
663
688
  className: "btn primary sm",
664
- onKeyDown: oe,
665
- onClick: () => void ae(),
689
+ onKeyDown: se,
690
+ onClick: () => void oe(),
666
691
  children: r("chat.voice.done")
667
692
  })
668
693
  ]
@@ -694,15 +719,15 @@ function O(n) {
694
719
  ref: R,
695
720
  rows: 1,
696
721
  value: o,
697
- placeholder: N ? r("chat.voice.recognizing") : se,
698
- "aria-label": se,
699
- disabled: N,
722
+ placeholder: P ? r("chat.voice.recognizing") : ce,
723
+ "aria-label": ce,
724
+ disabled: P,
700
725
  "aria-expanded": X,
701
726
  "aria-autocomplete": n.commands ? "list" : void 0,
702
727
  onChange: (e) => {
703
- u(e.target.value), A(!1), O(0), M(null);
728
+ u(e.target.value), j(!1), k(0), N(null);
704
729
  },
705
- onKeyDown: re
730
+ onKeyDown: ie
706
731
  })]
707
732
  }),
708
733
  n.context && !B.recording && /* @__PURE__ */ c(y, {
@@ -712,7 +737,7 @@ function O(n) {
712
737
  }),
713
738
  n.onTranscribe && !B.recording && /* @__PURE__ */ c("button", {
714
739
  className: "iconbtn",
715
- disabled: !B.supported || N,
740
+ disabled: !B.supported || P,
716
741
  "aria-label": r("chat.voice.start"),
717
742
  title: B.supported ? r("chat.voice.start") : r("chat.voice.unsupported"),
718
743
  onClick: () => void B.start(),
@@ -744,7 +769,7 @@ function O(n) {
744
769
  }
745
770
  //#endregion
746
771
  //#region src/chat/ConversationList.tsx
747
- function k({ conversations: e, currentId: n, open: r, onPick: i, onClose: o, onCreate: u }) {
772
+ function A({ conversations: e, currentId: n, open: r, onPick: i, onClose: o, onCreate: u }) {
748
773
  let f = a(), [p, h] = m(!1);
749
774
  d(() => {
750
775
  if (!r) return;
@@ -820,19 +845,19 @@ function k({ conversations: e, currentId: n, open: r, onPick: i, onClose: o, onC
820
845
  "aria-label": f("close"),
821
846
  onClick: o
822
847
  }),
823
- p && u && /* @__PURE__ */ c(j, {
848
+ p && u && /* @__PURE__ */ c(M, {
824
849
  onClose: () => h(!1),
825
850
  onCreate: u
826
851
  })
827
852
  ] });
828
853
  }
829
- function A({ narrow: e, children: t }) {
854
+ function j({ narrow: e, children: t }) {
830
855
  return /* @__PURE__ */ c("div", {
831
856
  className: `nb-app${e ? " narrow" : ""}`,
832
857
  children: t
833
858
  });
834
859
  }
835
- function j({ onClose: e, onCreate: t }) {
860
+ function M({ onClose: e, onCreate: t }) {
836
861
  let r = a(), [i, o] = m(""), [u, d] = m(!1), [f, p] = m(null), h = async () => {
837
862
  if (i.trim() && !u) {
838
863
  d(!0), p(null);
@@ -884,7 +909,7 @@ function j({ onClose: e, onCreate: t }) {
884
909
  }
885
910
  //#endregion
886
911
  //#region src/chat/AgentMenu.tsx
887
- function M({ icon: e, label: n, title: r, expanded: i, small: a, disabled: o, onClick: s }) {
912
+ function N({ icon: e, label: n, title: r, expanded: i, small: a, disabled: o, onClick: s }) {
888
913
  return /* @__PURE__ */ c("button", {
889
914
  type: "button",
890
915
  className: `agentbtn${a ? " s" : ""}`,
@@ -900,7 +925,7 @@ function M({ icon: e, label: n, title: r, expanded: i, small: a, disabled: o, on
900
925
  })
901
926
  });
902
927
  }
903
- function N({ label: e, name: n, options: r, value: o, optionsLabel: u, hint: d, narrow: f, models: p, onRename: h, onPick: g, onClose: _ }) {
928
+ function P({ label: e, name: n, options: r, value: o, optionsLabel: u, hint: d, narrow: f, models: p, onRename: h, onPick: g, onClose: _ }) {
904
929
  let v = a(), [y, b] = m(n), x = i(!0, _);
905
930
  return /* @__PURE__ */ l("div", {
906
931
  className: `agentmenu${f ? " narrow" : ""}`,
@@ -1011,6 +1036,6 @@ function N({ label: e, name: n, options: r, value: o, optionsLabel: u, hint: d,
1011
1036
  });
1012
1037
  }
1013
1038
  //#endregion
1014
- export { M as AgentButton, N as AgentMenu, O as Chat, A as ChatLayout, _ as CommandPalette, y as ContextMeter, k as ConversationList, w as MessageView, j as NewTopicModal, v as tokens, E as useRecorder };
1039
+ export { N as AgentButton, P as AgentMenu, k as Chat, j as ChatLayout, _ as CommandPalette, y as ContextMeter, A as ConversationList, w as MessageView, M as NewTopicModal, v as tokens, D as useRecorder };
1015
1040
 
1016
1041
  //# sourceMappingURL=chat.js.map
package/dist/chat.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"chat.js","names":["_Fragment","_Fragment","_Fragment","_Fragment","useToast","Icon","Modal","Markdown","useOutside","useKitT","UIKIT_NS","matchCommands","q","query","commands","c","CommandPalette","t","items","skills","row","i","active","e","onPick","onHover","tokens","lng","n","ContextMeter","useTranslation","open","setOpen","useState","ref","share","context","pct","level","i18n","v","onCompact","onReset","intlLocale","markTime","language","iso","visibleSteps","steps","STEP","MessageView","m","EventDivider","mark","atts","a","Fragment","waiting","s","onRetry","busy","ev","useRecorder","supported","recording","setRecording","seconds","setSeconds","setLevel","error","setError","rec","useRef","chunks","timer","audio","stopped","discard","limit","onLimit","cleanup","useCallback","tr","start","stream","r","blob","analyser","Ctx","samples","began","limited","peak","maxSeconds","stop","resolve","cancel","useEffect","clock","Chat","toast","text","setText","pending","setPending","uploading","setUploading","skill","setSkill","setActive","paletteClosed","setPaletteClosed","unknown","setUnknown","recognizing","setRecognizing","voice","listRef","fileRef","fieldRef","props","recorder","stopAndTranscribe","onPendingChange","first","messages","tail","last","tailText","tailSteps","lastLayout","el","was","paletteOpen","clear","runCommand","name","rest","send","msg","body","asText","word","cmd","f","pick","keys","d","attach","files","x","voiceKey","placeholder","left","y","ConversationList","creating","setCreating","onKey","onClose","item","currentId","inGroup","conversations","g","topics","archive","onCreate","NewTopicModal","ChatLayout","narrow","title","setTitle","create","AgentButton","small","label","expanded","icon","AgentMenu","draft","setDraft","next","onRename","optionsLabel","options","value","o","models","single","on","b","hint"],"sources":["../src/chat/CommandPalette.tsx","../src/chat/ContextMeter.tsx","../src/chat/MessageView.tsx","../src/chat/useRecorder.ts","../src/chat/Chat.tsx","../src/chat/ConversationList.tsx","../src/chat/AgentMenu.tsx"],"sourcesContent":["import { Icon } from \"../components/Icon\";\nimport { useKitT } from \"../i18n\";\nimport type { ChatCommand } from \"./types\";\n\n/** The items of the palette that match what is typed after \"/\". */\nexport function matchCommands(commands: ChatCommand[], query: string): ChatCommand[] {\n const q = query.toLowerCase();\n return commands.filter((c) => c.name.toLowerCase().includes(q) || (c.description ?? \"\").toLowerCase().includes(q));\n}\n\n/** The palette of commands and skills over the composer (FTR.NAB.CHAT-0001 R4,\n * design §3.1). The composer owns the keys: arrows move `active`, Enter and Tab\n * pick it, Esc closes. */\nexport function CommandPalette({ items, active, onPick, onHover }: {\n items: ChatCommand[];\n active: number;\n onPick: (c: ChatCommand) => void;\n onHover: (i: number) => void;\n}) {\n const t = useKitT();\n const commands = items.filter((c) => c.kind === \"command\");\n const skills = items.filter((c) => c.kind === \"skill\");\n const row = (c: ChatCommand, i: number) => (\n <button key={c.kind + c.name} type=\"button\" role=\"option\" aria-selected={i === active} className={`palette-row${i === active ? \" on\" : \"\"}`}\n // the field keeps the focus: the pick happens before the blur\n onMouseDown={(e) => { e.preventDefault(); onPick(c); }} onMouseEnter={() => onHover(i)}>\n {c.kind === \"skill\" ? <Icon name=\"spark\" size={14} /> : <span className=\"slash\">/</span>}\n <span className=\"nm\">{c.kind === \"command\" ? \"/\" + c.name : c.name}</span>\n <span className=\"ds\">{c.description}</span>\n {c.source && <span className=\"src\">{c.source}</span>}\n </button>\n );\n return (\n <div className=\"palette\" role=\"listbox\" aria-label={t(\"chat.palette.title\")}>\n {items.length === 0 && <div className=\"palette-empty\">{t(\"chat.palette.empty\")}</div>}\n {commands.length > 0 && <div className=\"palette-h\">{t(\"chat.palette.commands\")}</div>}\n {commands.map((c) => row(c, items.indexOf(c)))}\n {items.length > 0 && <div className=\"palette-h\">{t(\"chat.palette.skills\")}</div>}\n {skills.length === 0 && items.length > 0 && <div className=\"palette-empty\">{t(\"chat.palette.noSkills\")}</div>}\n {skills.map((c) => row(c, items.indexOf(c)))}\n </div>\n );\n}\n","import { useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { Icon } from \"../components/Icon\";\nimport { useOutside } from \"../components/ui\";\nimport { UIKIT_NS, useKitT } from \"../i18n\";\nimport type { ChatContext } from \"./types\";\n\n/** A number of tokens shortly: 42K, 1.2M in the language of the interface. */\nexport function tokens(n: number, lng: string): string {\n return new Intl.NumberFormat(lng === \"zh\" ? \"zh-CN\" : lng, { notation: \"compact\", maximumFractionDigits: 1 }).format(n);\n}\n\n/** The fill of the context window by a ring next to the send button\n * (FTR.NAB.CHAT-0001 R3, design §3.1): grey, amber from 70 %, red from 90 %.\n * A click shows the numbers; a full context offers to compact or to reset. */\nexport function ContextMeter({ context, onCompact, onReset }: { context: ChatContext; onCompact?: () => void; onReset?: () => void }) {\n const t = useKitT();\n const { i18n } = useTranslation(UIKIT_NS);\n const [open, setOpen] = useState(false);\n const ref = useOutside<HTMLDivElement>(open, () => setOpen(false));\n const share = context.window > 0 ? Math.min(1, context.tokens / context.window) : 0;\n const pct = Math.round(share * 100);\n const level = share >= 0.9 ? \"full\" : share >= 0.7 ? \"warn\" : \"\";\n const r = 7;\n const c = 2 * Math.PI * r;\n const lng = i18n.language;\n return (\n <div className=\"ctxmeter\" ref={ref}>\n <button type=\"button\" className={`ctxring ${level}`} aria-expanded={open} onClick={() => setOpen((v) => !v)}\n aria-label={t(\"chat.context.meter\", { used: tokens(context.tokens, lng), total: tokens(context.window, lng), pct })}\n title={t(\"chat.context.meter\", { used: tokens(context.tokens, lng), total: tokens(context.window, lng), pct })}>\n <svg viewBox=\"0 0 18 18\" aria-hidden=\"true\">\n <circle className=\"bg\" cx=\"9\" cy=\"9\" r={r} />\n <circle className=\"fg\" cx=\"9\" cy=\"9\" r={r} strokeDasharray={`${(c * share).toFixed(1)} ${c.toFixed(1)}`} transform=\"rotate(-90 9 9)\" />\n </svg>\n </button>\n {open && (\n <div className=\"ctxtip\" role=\"dialog\">\n <div>{t(\"chat.context.meter\", { used: tokens(context.tokens, lng), total: tokens(context.window, lng), pct })}</div>\n {level === \"full\" && <div className=\"small muted\" style={{ marginTop: 4 }}>{t(\"chat.context.full\")}</div>}\n {level === \"full\" && (onCompact || onReset) && (\n <div className=\"row\" style={{ marginTop: 8, gap: 6 }}>\n {onCompact && <button type=\"button\" className=\"btn sm\" onClick={() => { setOpen(false); onCompact(); }}><Icon name=\"compress\" size={14} />{t(\"chat.context.compact\")}</button>}\n {onReset && <button type=\"button\" className=\"btn sm ghost\" onClick={() => { setOpen(false); onReset(); }}><Icon name=\"undo\" size={14} />{t(\"chat.context.reset\")}</button>}\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","import { useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { Icon } from \"../components/Icon\";\nimport { Markdown } from \"../components/Markdown\";\nimport { UIKIT_NS } from \"../i18n\";\nimport type { ChatMessage, ChatStep } from \"./types\";\n\n/** The locale of Intl formatting for a language code of the products. */\nconst intlLocale = (lng: string) => (lng === \"zh\" ? \"zh-CN\" : lng);\n\n/** The time of a caption: hours and minutes in the language of the interface. */\nexport function markTime(iso: string, language: string): string {\n return new Intl.DateTimeFormat(intlLocale(language), { hour: \"2-digit\", minute: \"2-digit\" }).format(new Date(iso));\n}\n\n/** More than three steps are folded to the last two (design §6.4). */\nexport function visibleSteps(steps: ChatStep[], open: boolean): ChatStep[] {\n return open || steps.length <= 3 ? steps : steps.slice(-2);\n}\n\n/** The icon of a step and its colour class by the state of the step. */\nconst STEP = {\n done: { icon: \"check\", cls: \"ok\" },\n error: { icon: \"alert\", cls: \"er\" },\n running: { icon: \"clock\", cls: \"run\" },\n} as const;\n\n/** One message of the conversation (design §6.4). */\nexport function MessageView({ m, busy, onRetry }: { m: ChatMessage; busy: boolean; onRetry?: () => void }) {\n const { t, i18n } = useTranslation(UIKIT_NS);\n const [open, setOpen] = useState(false);\n if (m.role === \"note\") return <div className=\"sysnote\">{m.text}</div>;\n if (m.role === \"event\" && m.event) return <EventDivider m={m} />;\n const mark = m.mark && <div className=\"chan\"><Icon name={m.mark.icon} size={12} /> {m.mark.text} · {markTime(m.createdAt, i18n.language)}</div>;\n const atts = m.attachments && m.attachments.length > 0 && (\n <div className=\"atts\">\n {m.attachments.map((a) => <a key={a.id} href={a.href}><Icon name=\"clip\" size={12} /> {a.fileName}</a>)}\n </div>\n );\n if (m.role === \"user\") {\n return (\n <div className=\"m u\">\n {mark}\n {m.content}\n {m.text && <div className=\"bub\">{m.text}</div>}\n {atts}\n {m.wait && (\n <div className={`turnstate${m.wait.state === \"queued\" ? \" q\" : \"\"}`} role=\"status\">\n {m.wait.state === \"queued\"\n ? <><Icon name=\"clock\" size={12} />{t(\"chat.wait.queued\", { count: m.wait.position })}</>\n : <><span className=\"spin\" aria-hidden=\"true\" />{t(\"chat.wait.starting\")}</>}\n </div>\n )}\n </div>\n );\n }\n const steps = m.steps ?? [];\n const waiting = (m.status === \"streaming\" || m.status === \"pending\") && !m.text && !m.content;\n return (\n <div className=\"m a\">\n {mark}\n {steps.length > 3 && (\n <button className=\"tools-fold\" onClick={() => setOpen((v) => !v)} aria-expanded={open}>\n {open ? t(\"chat.hideSteps\") : t(\"chat.moreSteps\", { count: steps.length - 2 })}\n </button>\n )}\n {visibleSteps(steps, open).map((s) => (\n <div key={s.id} className=\"tool\" title={s.title}>\n <Icon name={STEP[s.status].icon} size={14} className={STEP[s.status].cls} />\n <span className=\"tx\">{s.text}</span>\n </div>\n ))}\n {waiting && <div className=\"bub\"><span className=\"typing\" aria-label={t(\"chat.typing\")}><i /><i /><i /></span></div>}\n {m.content ?? (m.text && <div className=\"bub\" title={m.hint}><Markdown text={m.text} /></div>)}\n {atts}\n {m.error && (\n <div className={`llmerr${m.error.transient ? \" amber\" : \"\"}`} role=\"alert\" style={{ marginTop: 6 }}>\n <span>{m.error.text}</span>\n {onRetry && (\n <div className=\"row\">\n <button className=\"btn sm\" disabled={busy} onClick={onRetry}><Icon name=\"refresh\" size={14} />{t(\"chat.retry\")}</button>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n\n/** An event of the conversation: a line with a chip; the details unfold\n * (FTR.NAB.CHAT-0001 design §3.2). */\nfunction EventDivider({ m }: { m: ChatMessage }) {\n const { t, i18n } = useTranslation(UIKIT_NS);\n const [open, setOpen] = useState(false);\n const ev = m.event!;\n return (\n <div className=\"evdiv\">\n <div className=\"evline\" role=\"separator\">\n <span className=\"evchip\">\n <Icon name={ev.icon} size={12} />\n {ev.text} · {markTime(m.createdAt, i18n.language)}\n {ev.details && (\n <button type=\"button\" className=\"textbtn\" aria-expanded={open} onClick={() => setOpen((v) => !v)}>\n {t(\"chat.event.details\")} {open ? \"▴\" : \"▾\"}\n </button>\n )}\n </span>\n </div>\n {open && ev.details && <div className=\"evdetails\">{ev.details}</div>}\n </div>\n );\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\n\n/** Recording with MediaRecorder (FTR.NAB.CHAT-0001 R20): started and stopped\n * by the user, stopped by itself at `maxSeconds`; the level of the voice is\n * sampled for the bar of the recording. */\nexport function useRecorder(maxSeconds = 300, onLimit?: () => void) {\n const supported = typeof window !== \"undefined\" && \"MediaRecorder\" in window && !!navigator.mediaDevices?.getUserMedia;\n const [recording, setRecording] = useState(false);\n const [seconds, setSeconds] = useState(0);\n const [level, setLevel] = useState(0);\n const [error, setError] = useState(false);\n const rec = useRef<MediaRecorder | null>(null);\n const chunks = useRef<Blob[]>([]);\n const timer = useRef<number | undefined>(undefined);\n const audio = useRef<AudioContext | null>(null);\n const stopped = useRef<((b: Blob | null) => void) | null>(null);\n const discard = useRef(false);\n const limit = useRef(onLimit);\n useEffect(() => {\n limit.current = onLimit;\n });\n\n const cleanup = useCallback(() => {\n window.clearInterval(timer.current);\n rec.current?.stream.getTracks().forEach((tr) => tr.stop());\n rec.current = null;\n void audio.current?.close().catch(() => undefined);\n audio.current = null;\n setRecording(false);\n setLevel(0);\n }, []);\n\n const start = useCallback(async () => {\n if (!supported || rec.current) return;\n setError(false);\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n const r = new MediaRecorder(stream);\n chunks.current = [];\n discard.current = false;\n r.ondataavailable = (e) => e.data.size > 0 && chunks.current.push(e.data);\n r.onstop = () => {\n const blob = !discard.current && chunks.current.length ? new Blob(chunks.current, { type: r.mimeType || \"audio/webm\" }) : null;\n cleanup();\n stopped.current?.(blob);\n stopped.current = null;\n };\n let analyser: AnalyserNode | null = null;\n try {\n const Ctx = window.AudioContext ?? (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (Ctx) {\n audio.current = new Ctx();\n analyser = audio.current.createAnalyser();\n analyser.fftSize = 256;\n audio.current.createMediaStreamSource(stream).connect(analyser);\n }\n } catch {\n analyser = null; // the bar stays flat without Web Audio\n }\n const samples = analyser ? new Uint8Array(analyser.fftSize) : null;\n rec.current = r;\n r.start();\n setSeconds(0);\n setRecording(true);\n const began = Date.now();\n let limited = false;\n timer.current = window.setInterval(() => {\n const s = Math.floor((Date.now() - began) / 1000);\n setSeconds(s);\n if (analyser && samples) {\n analyser.getByteTimeDomainData(samples);\n let peak = 0;\n for (const v of samples) peak = Math.max(peak, Math.abs(v - 128));\n setLevel(Math.min(1, peak / 64));\n }\n if (s >= maxSeconds && !limited) {\n limited = true;\n limit.current?.();\n }\n }, 100);\n } catch {\n setError(true);\n cleanup();\n }\n }, [supported, cleanup, maxSeconds]);\n\n const stop = useCallback(() => new Promise<Blob | null>((resolve) => {\n const r = rec.current;\n if (!r || r.state === \"inactive\") return resolve(null);\n stopped.current = resolve;\n r.stop();\n }), []);\n\n /** Ends the recording and drops it. */\n const cancel = useCallback(() => {\n discard.current = true;\n void stop();\n }, [stop]);\n\n useEffect(() => () => cleanup(), [cleanup]);\n\n return { supported, recording, seconds, level, error, start, stop, cancel };\n}\n\n/** m:ss of a number of seconds. */\nexport function clock(seconds: number): string {\n return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, \"0\")}`;\n}\n","import { useEffect, useLayoutEffect, useRef, useState, type KeyboardEvent } from \"react\";\nimport { Icon } from \"../components/Icon\";\nimport { useToast } from \"../components/ui\";\nimport { useKitT } from \"../i18n\";\nimport { CommandPalette, matchCommands } from \"./CommandPalette\";\nimport { ContextMeter } from \"./ContextMeter\";\nimport { MessageView } from \"./MessageView\";\nimport type { ChatCommand, ChatProps, ChatUpload } from \"./types\";\nimport { clock, useRecorder } from \"./useRecorder\";\n\n/** The conversation: the messages and the composer (FTR.NAB.CMN-0005 R11–R13,\n * design §6; FTR.NAB.CHAT-0001 design §3.1). The behaviour is the one of the\n * chat of Nabu. A control exists only when the product gave its handler: no\n * `onCancel` — no cancel button, no `commands` — no palette. */\nexport function Chat(props: ChatProps) {\n const t = useKitT();\n const toast = useToast();\n const [text, setText] = useState(\"\");\n const [pending, setPending] = useState<ChatUpload[]>([]);\n const [uploading, setUploading] = useState(false);\n const [skill, setSkill] = useState<string | null>(null);\n const [active, setActive] = useState(0);\n const [paletteClosed, setPaletteClosed] = useState(false);\n const [unknown, setUnknown] = useState<string | null>(null);\n const [recognizing, setRecognizing] = useState(false);\n const voice = useRef(false);\n const listRef = useRef<HTMLDivElement>(null);\n const fileRef = useRef<HTMLInputElement>(null);\n const fieldRef = useRef<HTMLTextAreaElement>(null);\n const maxSeconds = props.voiceMaxSeconds ?? 300;\n const recorder = useRecorder(maxSeconds, () => void stopAndTranscribe());\n const { messages, busy = false } = props;\n const onPendingChange = props.onPendingChange;\n useEffect(() => onPendingChange?.(pending), [pending, onPendingChange]);\n\n const first = messages[0]?.id;\n const tail = messages[messages.length - 1];\n const last = tail?.id;\n const tailText = tail?.text.length;\n const tailSteps = tail?.steps?.length;\n // The ends and the height of the list at the last layout: earlier messages\n // loaded above it keep the place of the list.\n const lastLayout = useRef<{ first?: string; last?: string; height: number }>({ height: 0 });\n // The list follows new messages and the growth of the last one: the dependencies are the trigger.\n useLayoutEffect(() => {\n const el = listRef.current;\n if (!el) return;\n const was = lastLayout.current;\n // history is prepended when the start of the list changed and its end did not;\n // another conversation changes both\n const prepended = was.first !== undefined && first !== was.first && last === was.last;\n el.scrollTop = prepended ? el.scrollTop + (el.scrollHeight - was.height) : el.scrollHeight;\n lastLayout.current = { first, last, height: el.scrollHeight };\n // oxlint-disable-next-line react/exhaustive-effect-dependencies -- the length and the growth of the tail only trigger\n }, [messages.length, first, last, tailText, tailSteps]);\n\n // R4: \"/\" at the start of the field without a space opens the palette\n const query = props.commands && !skill && text.startsWith(\"/\") && !/\\s/.test(text) ? text.slice(1) : null;\n const items = query !== null ? matchCommands(props.commands ?? [], query) : [];\n const paletteOpen = query !== null && !paletteClosed;\n\n const clear = () => {\n setText(\"\");\n setPending([]);\n setSkill(null);\n setUnknown(null);\n voice.current = false;\n };\n\n const runCommand = async (name: string, rest: string) => {\n if (!props.onCommand) return;\n try {\n await props.onCommand(name, rest);\n clear();\n } catch {\n // the product has told the user; the text stays\n }\n };\n\n const send = async (body: string, asText = false) => {\n const msg = body.trim();\n if ((!msg && pending.length === 0 && !skill) || busy || props.readOnly) return;\n // R4: a command typed in full runs; an unknown one waits for «Send as text»\n if (!asText && !skill && props.commands && msg.startsWith(\"/\")) {\n const [word, ...rest] = msg.slice(1).split(/\\s+/);\n const cmd = props.commands.find((c) => c.kind === \"command\" && c.name === word);\n if (cmd) return runCommand(cmd.name, rest.join(\" \"));\n if (word && !msg.includes(\"\\n\")) {\n setUnknown(\"/\" + word);\n return;\n }\n }\n try {\n await props.onSend(msg, pending.map((f) => f.id), voice.current, skill ?? undefined);\n clear();\n } catch {\n // the product has told the user; the text stays in the composer\n }\n };\n\n const pick = (c: ChatCommand) => {\n setActive(0);\n if (c.kind === \"skill\") {\n setSkill(c.name);\n setText(\"\");\n } else if (c.takesText) {\n setText(\"/\" + c.name + \" \");\n } else {\n void runCommand(c.name, \"\");\n }\n fieldRef.current?.focus();\n };\n\n const keys = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (paletteOpen && items.length > 0) {\n if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\") {\n e.preventDefault();\n const d = e.key === \"ArrowDown\" ? 1 : -1;\n setActive((a) => (a + d + items.length) % items.length);\n return;\n }\n if ((e.key === \"Enter\" && !e.shiftKey) || e.key === \"Tab\") {\n e.preventDefault();\n pick(items[Math.min(active, items.length - 1)]);\n return;\n }\n }\n if (paletteOpen && e.key === \"Escape\") {\n e.preventDefault();\n setPaletteClosed(true);\n return;\n }\n if (e.key === \"Backspace\" && skill && text === \"\") {\n setSkill(null); // design §3.1: Backspace in the empty field takes the skill off\n return;\n }\n if (e.key === \"Enter\" && !e.shiftKey && !e.nativeEvent.isComposing) {\n e.preventDefault();\n void send(text);\n }\n };\n\n const attach = async (files: FileList | null) => {\n if (!files?.length || !props.onUpload) return;\n setUploading(true);\n for (const f of Array.from(files)) {\n if (props.upload && f.size > props.upload.maxBytes) {\n toast({ kind: \"error\", title: t(\"chat.tooLarge\"), text: f.name });\n continue;\n }\n const a = await props.onUpload(f).catch(() => null);\n if (a) setPending((x) => [...x, a]);\n }\n setUploading(false);\n if (fileRef.current) fileRef.current.value = \"\";\n };\n\n // R20: the recognized text goes into the field; the user checks and sends it\n async function stopAndTranscribe() {\n const blob = await recorder.stop();\n if (!blob || !props.onTranscribe) return;\n setRecognizing(true);\n const r = await props.onTranscribe(blob).catch(() => null);\n setRecognizing(false);\n if (r === null) return;\n if (!r) {\n toast({ kind: \"error\", title: t(\"chat.voice.notRecognized\") });\n return;\n }\n voice.current = true;\n setText((x) => (x.trim() ? x.trimEnd() + \" \" + r : r));\n fieldRef.current?.focus();\n }\n\n const voiceKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\" && recorder.recording) {\n e.preventDefault();\n recorder.cancel();\n }\n };\n\n const placeholder = skill ? t(\"chat.skillPlaceholder\") : t(\"chat.placeholder\", { name: props.agentName });\n const left = maxSeconds - recorder.seconds;\n return (\n <section className=\"nb-chat\" aria-label={t(\"chat.title\")}>\n {props.header}\n <div className=\"msgs\" ref={listRef} aria-live=\"polite\">\n {props.hasOlder && props.onLoadOlder && (\n <button className=\"btn ghost sm\" style={{ alignSelf: \"center\" }} disabled={props.loadingOlder} onClick={props.onLoadOlder}>\n {t(\"chat.loadOlder\")}\n </button>\n )}\n {props.historyError && <div className=\"err-text\">{props.historyError}</div>}\n {messages.length === 0 && !props.loading && !props.historyError && (\n <div className=\"empty\"><div className=\"ic\"><Icon name=\"spark\" /></div><b>{t(\"chat.emptyTitle\", { name: props.agentName })}</b>{props.emptyHint}</div>\n )}\n {messages.map((m) => <MessageView key={m.id} m={m} busy={busy} onRetry={props.onRetry && (() => props.onRetry?.(m.id))} />)}\n {props.onConfirm && (props.confirmations ?? []).map((c) => (\n <div className=\"confirm\" key={c.id} role=\"group\" aria-label={t(\"chat.confirm.title\")}>\n <div className=\"h\"><Icon name=\"alert\" size={16} />{t(\"chat.confirm.title\")}</div>\n <div>{t(\"chat.confirm.text\", { action: c.summary })}</div>\n {c.preview !== undefined && <pre>{c.preview}</pre>}\n <div className=\"acts\">\n {/* never tied to `busy`: the agent asks in the middle of its turn */}\n <button className=\"btn sm primary\" onClick={() => props.onConfirm?.(c.id, true)}>{t(\"chat.confirm.approve\")}</button>\n <button className=\"btn sm\" onClick={() => props.onConfirm?.(c.id, false)}>{t(\"chat.confirm.reject\")}</button>\n </div>\n </div>\n ))}\n </div>\n\n {props.readOnly ? (\n <div className=\"composer\" style={{ justifyContent: \"space-between\", alignItems: \"center\" }}>{props.readOnly}</div>\n ) : (\n <div className=\"composer-wrap\">\n {paletteOpen && <CommandPalette items={items} active={Math.min(active, Math.max(items.length - 1, 0))} onPick={pick} onHover={setActive} />}\n {props.aboveComposer}\n {pending.length > 0 && (\n <div className=\"pending-files\">\n {pending.map((f) => (\n <span key={f.id} className=\"chip\">\n <Icon name=\"clip\" size={12} />{f.fileName}\n <button className=\"iconbtn\" style={{ width: 18, height: 18 }} aria-label={t(\"remove\")}\n onClick={() => setPending((x) => x.filter((y) => y.id !== f.id))}><Icon name=\"x\" size={12} /></button>\n </span>\n ))}\n </div>\n )}\n {unknown && (\n <div className=\"cmd-unknown\" role=\"status\">\n {t(\"chat.unknownCommand\", { name: unknown })}\n <button type=\"button\" className=\"textbtn\" onClick={() => void send(text, true)}>{t(\"chat.sendAsText\")}</button>\n </div>\n )}\n <div className=\"composer\">\n {props.onUpload && !recorder.recording && (\n <>\n <button className=\"iconbtn\" aria-label={t(\"chat.attach\")} disabled={uploading} onClick={() => fileRef.current?.click()}><Icon name=\"clip\" /></button>\n <input ref={fileRef} type=\"file\" multiple hidden accept={props.upload?.accept} onChange={(e) => attach(e.target.files)} />\n </>\n )}\n {recorder.recording ? (\n <div className={`recbar${left <= 15 ? \" ending\" : \"\"}`} role=\"status\" aria-label={t(\"chat.voice.recordingNow\")}>\n <span className=\"dot\" aria-hidden=\"true\" />\n <span className=\"tm\">{clock(recorder.seconds)} / {clock(maxSeconds)}</span>\n <span className=\"lvl\" aria-hidden=\"true\"><i style={{ transform: `scaleX(${Math.max(0.04, recorder.level)})` }} /></span>\n <button type=\"button\" className=\"btn ghost sm\" onClick={recorder.cancel}>{t(\"cancel\")}</button>\n <button type=\"button\" className=\"btn primary sm\" onKeyDown={voiceKey} onClick={() => void stopAndTranscribe()}>{t(\"chat.voice.done\")}</button>\n </div>\n ) : (\n <div className={`field${skill ? \" with-skill\" : \"\"}`}>\n {skill && (\n <span className=\"chip skill-chip\">\n <Icon name=\"spark\" size={12} />{skill}\n <button className=\"iconbtn\" style={{ width: 18, height: 18 }} aria-label={t(\"remove\")} onClick={() => setSkill(null)}><Icon name=\"x\" size={12} /></button>\n </span>\n )}\n <textarea ref={fieldRef} rows={1} value={text} placeholder={recognizing ? t(\"chat.voice.recognizing\") : placeholder} aria-label={placeholder}\n disabled={recognizing} aria-expanded={paletteOpen} aria-autocomplete={props.commands ? \"list\" : undefined}\n onChange={(e) => { setText(e.target.value); setPaletteClosed(false); setActive(0); setUnknown(null); }}\n onKeyDown={keys} />\n </div>\n )}\n {props.context && !recorder.recording && <ContextMeter context={props.context} onCompact={props.onCompact} onReset={props.onReset} />}\n {props.onTranscribe && !recorder.recording && (\n <button className=\"iconbtn\" disabled={!recorder.supported || recognizing}\n aria-label={t(\"chat.voice.start\")} title={recorder.supported ? t(\"chat.voice.start\") : t(\"chat.voice.unsupported\")}\n onClick={() => void recorder.start()}>\n <Icon name=\"mic\" />\n </button>\n )}\n {!recorder.recording && (props.onCancel && busy ? (\n <button className=\"iconbtn fill\" aria-label={t(\"chat.stop\")} onClick={props.onCancel}><Icon name=\"stop\" /></button>\n ) : (\n <button className=\"iconbtn fill\" aria-label={t(\"chat.send\")} disabled={(!text.trim() && pending.length === 0 && !skill) || busy} onClick={() => send(text)}>\n <Icon name=\"send\" />\n </button>\n ))}\n </div>\n {recorder.error && <div className=\"err-text\" style={{ padding: \"0 12px 8px\" }}>{t(\"chat.voice.micDenied\")}</div>}\n </div>\n )}\n </section>\n );\n}\n","import { useEffect, useState, type ReactNode } from \"react\";\nimport { Icon } from \"../components/Icon\";\nimport { Modal } from \"../components/ui\";\nimport { useKitT } from \"../i18n\";\nimport type { ChatConversation, ConversationListProps } from \"./types\";\n\n/** The conversations of the user: the main one, the topics, the archive (design\n * §6.2). In a wide place the list stands left of the messages; on a phone and in\n * a narrow place it lies over them while open and closes by a pick, a tap\n * beside it or Escape. */\nexport function ConversationList({ conversations, currentId, open, onPick, onClose, onCreate }: ConversationListProps) {\n const t = useKitT();\n const [creating, setCreating] = useState(false);\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && onClose();\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [open, onClose]);\n\n const item = (c: ChatConversation) => (\n <button key={c.id} className={`it${c.id === currentId ? \" on\" : \"\"}${c.group === \"archive\" ? \" arch\" : \"\"}`}\n onClick={() => onPick(c.id)} aria-current={c.id === currentId}>\n <Icon name={c.icon ?? \"msg2\"} size={16} />\n <span className=\"nm\">{c.title}</span>\n {!!c.unread && <span className=\"unread\" aria-label={t(\"chat.unread\", { count: c.unread })}>{c.unread}</span>}\n <span className=\"sub\">{c.when}</span>\n </button>\n );\n const inGroup = (g: ChatConversation[\"group\"]) => conversations.filter((c) => c.group === g);\n const topics = inGroup(\"topic\");\n const archive = inGroup(\"archive\");\n return (\n <>\n <nav className={`nb-side${open ? \" open\" : \"\"}`} aria-label={t(\"chat.conversations\")}>\n {onCreate && (\n <button className=\"btn sm\" style={{ width: \"100%\", justifyContent: \"center\" }} onClick={() => setCreating(true)}>\n <Icon name=\"plus\" size={15} />{t(\"chat.newTopic\")}\n </button>\n )}\n <div className=\"h\">{t(\"chat.conversation\")}</div>\n {inGroup(\"main\").map(item)}\n <div className=\"h\">{t(\"chat.topics\")}</div>\n {topics.length === 0 && <div className=\"small muted\" style={{ padding: \"0 10px\" }}>{t(\"chat.noTopics\")}</div>}\n {topics.map(item)}\n {archive.length > 0 && <div className=\"h\">{t(\"chat.archive\")}</div>}\n {archive.map(item)}\n </nav>\n {/* over the messages: a tap beside the list closes it */}\n {open && <button type=\"button\" className=\"nb-scrim\" aria-label={t(\"close\")} onClick={onClose} />}\n {creating && onCreate && <NewTopicModal onClose={() => setCreating(false)} onCreate={onCreate} />}\n </>\n );\n}\n\n/** The place of a chat: the list of conversations, the conversation and what the\n * product puts beside them. `narrow` is for a side panel: the list lies over the\n * messages as on a phone, whatever the width of the window. */\nexport function ChatLayout({ narrow, children }: { narrow?: boolean; children: ReactNode }) {\n return <div className={`nb-app${narrow ? \" narrow\" : \"\"}`}>{children}</div>;\n}\n\n/** The dialog of a new topic: one field, Enter creates. */\nexport function NewTopicModal({ onClose, onCreate }: { onClose: () => void; onCreate: (title: string) => Promise<void> }) {\n const t = useKitT();\n const [title, setTitle] = useState(\"\");\n const [pending, setPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const create = async () => {\n if (!title.trim() || pending) return;\n setPending(true);\n setError(null);\n try {\n await onCreate(title.trim());\n onClose();\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n setPending(false);\n }\n };\n return (\n <Modal title={t(\"chat.newTopic\")} onClose={onClose} footer={<>\n <button className=\"btn ghost\" onClick={onClose}>{t(\"cancel\")}</button>\n <button className=\"btn primary\" disabled={!title.trim() || pending} onClick={create}>{t(\"create\")}</button>\n </>}>\n <div className=\"field\">\n <label htmlFor=\"topic-title\">{t(\"chat.topicTitle\")}</label>\n <input id=\"topic-title\" className=\"inp\" value={title} maxLength={120} onChange={(e) => setTitle(e.target.value)}\n onKeyDown={(e) => e.key === \"Enter\" && create()} />\n <div className=\"hint\">{t(\"chat.topicHint\")}</div>\n </div>\n {error && <div className=\"err-text\">{error}</div>}\n </Modal>\n );\n}\n","import { useState, type ReactNode } from \"react\";\nimport { Icon, type IconName } from \"../components/Icon\";\nimport { useOutside } from \"../components/ui\";\nimport { useKitT } from \"../i18n\";\n\n/** One of the ways an agent can look and talk; what it means only the product knows (R7). */\nexport interface AgentOption { key: string; label: string; icon: IconName }\n\n/** A model the user may choose for the agent (FTR.NAB.CHAT-0001 R16, design §3.3). */\nexport interface AgentModelOption {\n key: string;\n label: string;\n /** The connection or the default model, grey under the name. */\n sub?: string;\n /** The capabilities: images, reasoning, the window. */\n badges?: { icon?: IconName; text: string }[];\n /** Under the row of the chosen model: the context will be compacted. */\n warn?: ReactNode;\n}\n\n/** The block «Model» of the menu: one model is shown without a choice; none — the text of the product. */\nexport interface AgentModels {\n label: ReactNode;\n options: AgentModelOption[];\n value: string;\n onPick: (key: string) => void;\n empty?: ReactNode;\n}\n\n/** The round button of the agent: its icon, and the menu behind it. */\nexport function AgentButton({ icon, label, title, expanded, small, disabled, onClick }: {\n icon: IconName; label: string; title?: string; expanded?: boolean; small?: boolean; disabled?: boolean; onClick?: () => void;\n}) {\n return (\n <button type=\"button\" className={`agentbtn${small ? \" s\" : \"\"}`} disabled={disabled} aria-label={label} aria-expanded={expanded} title={title}\n // the menu closes on an outside mousedown; keep this click a toggle\n onMouseDown={(e) => expanded && e.stopPropagation()} onClick={onClick}>\n <Icon name={icon} size={small ? 15 : 18} />\n </button>\n );\n}\n\n/** The menu of the agent (FTR.NAB.CMN-0005 R15, design §6.6): its name and a\n * choice among the options of the product, as tiles with icons. The name is\n * saved on Enter and on leaving the field; a pick is saved at once. */\nexport function AgentMenu({ label, name, options, value, optionsLabel, hint, narrow, models, onRename, onPick, onClose }: {\n /** The name of the dialog for a screen reader. */\n label: string;\n name: string;\n options: AgentOption[];\n value: string;\n optionsLabel: ReactNode;\n hint?: ReactNode;\n /** A narrow place — a side panel: the options go in one column. */\n narrow?: boolean;\n /** The choice of the model after the options. */\n models?: AgentModels;\n onRename: (name: string) => void;\n onPick: (key: string) => void;\n /** Must keep its identity between renders. */\n onClose: () => void;\n}) {\n const t = useKitT();\n const [draft, setDraft] = useState(name);\n const ref = useOutside<HTMLDivElement>(true, onClose);\n const save = () => {\n const next = draft.trim();\n if (next && next !== name) onRename(next);\n };\n return (\n <div className={`agentmenu${narrow ? \" narrow\" : \"\"}`} ref={ref} role=\"dialog\" aria-label={label}>\n <div className=\"lab\">{t(\"agentName\")}</div>\n <input className=\"inp\" value={draft} maxLength={40} autoFocus aria-label={t(\"agentName\")}\n onChange={(e) => setDraft(e.target.value)} onBlur={save}\n onKeyDown={(e) => e.key === \"Enter\" && (e.target as HTMLInputElement).blur()} />\n <div className=\"lab\" style={{ marginTop: 14 }}>{optionsLabel}</div>\n <div className=\"agentoptions\">\n {options.map((o) => (\n <button key={o.key} type=\"button\" className={`agentoption${value === o.key ? \" on\" : \"\"}`} aria-pressed={value === o.key} onClick={() => onPick(o.key)}>\n <span className=\"ic\"><Icon name={o.icon} size={15} /></span>\n {o.label}\n </button>\n ))}\n </div>\n {models && (\n <>\n <div className=\"lab\" style={{ marginTop: 14 }}>{models.label}</div>\n {models.options.length === 0 && <div className=\"hint\">{models.empty}</div>}\n <div className=\"agentmodels\" role=\"radiogroup\">\n {models.options.map((m) => {\n const single = models.options.length === 1;\n const on = single || models.value === m.key;\n return (\n <button key={m.key} type=\"button\" role=\"radio\" aria-checked={on} disabled={single} className={`agentmodel${on ? \" on\" : \"\"}`}\n onClick={() => !on && models.onPick(m.key)}>\n {!single && <span className={`radio${on ? \" on\" : \"\"}`} aria-hidden=\"true\" />}\n <span className=\"body\">\n <span className=\"nm\">{m.label}</span>\n {m.sub && <span className=\"sub\">{m.sub}</span>}\n {m.badges && m.badges.length > 0 && (\n <span className=\"badges\">\n {m.badges.map((b) => <span key={b.text} className=\"cap\">{b.icon && <Icon name={b.icon} size={11} />}{b.text}</span>)}\n </span>\n )}\n {on && m.warn && <span className=\"warn\">{m.warn}</span>}\n </span>\n </button>\n );\n })}\n </div>\n </>\n )}\n {hint && <div className=\"hint\" style={{ marginTop: 10 }}>{hint}</div>}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"chat.js","names":["_Fragment","_Fragment","_Fragment","_Fragment","useToast","Icon","Modal","Markdown","useOutside","useKitT","UIKIT_NS","matchCommands","q","query","commands","c","CommandPalette","t","items","skills","row","i","active","e","onPick","onHover","tokens","lng","n","ContextMeter","useTranslation","open","setOpen","useState","ref","share","context","pct","level","i18n","v","onCompact","onReset","intlLocale","markTime","language","iso","visibleSteps","steps","STEP","MessageView","m","EventDivider","mark","atts","a","Fragment","waiting","s","onRetry","busy","ev","transcribe","recognize","recording","on","useRecorder","supported","setRecording","seconds","setSeconds","setLevel","error","setError","rec","useRef","chunks","timer","audio","stopped","discard","limit","onLimit","cleanup","useCallback","tr","start","stream","r","blob","analyser","Ctx","samples","began","limited","peak","maxSeconds","stop","resolve","cancel","useEffect","clock","Chat","toast","text","setText","pending","setPending","uploading","setUploading","skill","setSkill","setActive","paletteClosed","setPaletteClosed","unknown","setUnknown","recognizing","setRecognizing","voice","listRef","fileRef","fieldRef","props","recorder","stopAndTranscribe","onPendingChange","first","messages","tail","last","tailText","tailSteps","lastLayout","el","was","paletteOpen","clear","runCommand","name","rest","send","msg","body","asText","word","cmd","f","pick","keys","d","attach","files","x","reason","retry","voiceKey","placeholder","left","y","ConversationList","creating","setCreating","onKey","onClose","item","currentId","inGroup","conversations","g","topics","archive","onCreate","NewTopicModal","ChatLayout","narrow","title","setTitle","create","AgentButton","small","label","expanded","icon","AgentMenu","draft","setDraft","next","onRename","optionsLabel","options","value","o","models","single","b","hint"],"sources":["../src/chat/CommandPalette.tsx","../src/chat/ContextMeter.tsx","../src/chat/MessageView.tsx","../src/chat/transcription.ts","../src/chat/useRecorder.ts","../src/chat/Chat.tsx","../src/chat/ConversationList.tsx","../src/chat/AgentMenu.tsx"],"sourcesContent":["import { Icon } from \"../components/Icon\";\nimport { useKitT } from \"../i18n\";\nimport type { ChatCommand } from \"./types\";\n\n/** The items of the palette that match what is typed after \"/\". */\nexport function matchCommands(commands: ChatCommand[], query: string): ChatCommand[] {\n const q = query.toLowerCase();\n return commands.filter((c) => c.name.toLowerCase().includes(q) || (c.description ?? \"\").toLowerCase().includes(q));\n}\n\n/** The palette of commands and skills over the composer (FTR.NAB.CHAT-0001 R4,\n * design §3.1). The composer owns the keys: arrows move `active`, Enter and Tab\n * pick it, Esc closes. */\nexport function CommandPalette({ items, active, onPick, onHover }: {\n items: ChatCommand[];\n active: number;\n onPick: (c: ChatCommand) => void;\n onHover: (i: number) => void;\n}) {\n const t = useKitT();\n const commands = items.filter((c) => c.kind === \"command\");\n const skills = items.filter((c) => c.kind === \"skill\");\n const row = (c: ChatCommand, i: number) => (\n <button key={c.kind + c.name} type=\"button\" role=\"option\" aria-selected={i === active} className={`palette-row${i === active ? \" on\" : \"\"}`}\n // the field keeps the focus: the pick happens before the blur\n onMouseDown={(e) => { e.preventDefault(); onPick(c); }} onMouseEnter={() => onHover(i)}>\n {/* the name of a command starts with «/» itself: its column stays empty, the names line up with the skills */}\n {c.kind === \"skill\" ? <Icon name=\"spark\" size={14} /> : <span className=\"slash\" aria-hidden=\"true\" />}\n <span className=\"nm\">{c.kind === \"command\" ? \"/\" + c.name : c.name}</span>\n <span className=\"ds\">{c.description}</span>\n {c.source && <span className=\"src\">{c.source}</span>}\n </button>\n );\n return (\n <div className=\"palette\" role=\"listbox\" aria-label={t(\"chat.palette.title\")}>\n {items.length === 0 && <div className=\"palette-empty\">{t(\"chat.palette.empty\")}</div>}\n {commands.length > 0 && <div className=\"palette-h\">{t(\"chat.palette.commands\")}</div>}\n {commands.map((c) => row(c, items.indexOf(c)))}\n {items.length > 0 && <div className=\"palette-h\">{t(\"chat.palette.skills\")}</div>}\n {skills.length === 0 && items.length > 0 && <div className=\"palette-empty\">{t(\"chat.palette.noSkills\")}</div>}\n {skills.map((c) => row(c, items.indexOf(c)))}\n </div>\n );\n}\n","import { useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { Icon } from \"../components/Icon\";\nimport { useOutside } from \"../components/ui\";\nimport { UIKIT_NS, useKitT } from \"../i18n\";\nimport type { ChatContext } from \"./types\";\n\n/** A number of tokens shortly: 42K, 1.2M in the language of the interface. */\nexport function tokens(n: number, lng: string): string {\n return new Intl.NumberFormat(lng === \"zh\" ? \"zh-CN\" : lng, { notation: \"compact\", maximumFractionDigits: 1 }).format(n);\n}\n\n/** The fill of the context window by a ring next to the send button\n * (FTR.NAB.CHAT-0001 R3, design §3.1): grey, amber from 70 %, red from 90 %.\n * A click shows the numbers; a full context offers to compact or to reset. */\nexport function ContextMeter({ context, onCompact, onReset }: { context: ChatContext; onCompact?: () => void; onReset?: () => void }) {\n const t = useKitT();\n const { i18n } = useTranslation(UIKIT_NS);\n const [open, setOpen] = useState(false);\n const ref = useOutside<HTMLDivElement>(open, () => setOpen(false));\n const share = context.window > 0 ? Math.min(1, context.tokens / context.window) : 0;\n const pct = Math.round(share * 100);\n const level = share >= 0.9 ? \"full\" : share >= 0.7 ? \"warn\" : \"\";\n const r = 7;\n const c = 2 * Math.PI * r;\n const lng = i18n.language;\n return (\n <div className=\"ctxmeter\" ref={ref}>\n <button type=\"button\" className={`ctxring ${level}`} aria-expanded={open} onClick={() => setOpen((v) => !v)}\n aria-label={t(\"chat.context.meter\", { used: tokens(context.tokens, lng), total: tokens(context.window, lng), pct })}\n title={t(\"chat.context.meter\", { used: tokens(context.tokens, lng), total: tokens(context.window, lng), pct })}>\n <svg viewBox=\"0 0 18 18\" aria-hidden=\"true\">\n <circle className=\"bg\" cx=\"9\" cy=\"9\" r={r} />\n <circle className=\"fg\" cx=\"9\" cy=\"9\" r={r} strokeDasharray={`${(c * share).toFixed(1)} ${c.toFixed(1)}`} transform=\"rotate(-90 9 9)\" />\n </svg>\n </button>\n {open && (\n <div className=\"ctxtip\" role=\"dialog\">\n <div>{t(\"chat.context.meter\", { used: tokens(context.tokens, lng), total: tokens(context.window, lng), pct })}</div>\n {level === \"full\" && <div className=\"small muted\" style={{ marginTop: 4 }}>{t(\"chat.context.full\")}</div>}\n {level === \"full\" && (onCompact || onReset) && (\n <div className=\"row\" style={{ marginTop: 8, gap: 6 }}>\n {onCompact && <button type=\"button\" className=\"btn sm\" onClick={() => { setOpen(false); onCompact(); }}><Icon name=\"compress\" size={14} />{t(\"chat.context.compact\")}</button>}\n {onReset && <button type=\"button\" className=\"btn sm ghost\" onClick={() => { setOpen(false); onReset(); }}><Icon name=\"undo\" size={14} />{t(\"chat.context.reset\")}</button>}\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","import { useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { Icon } from \"../components/Icon\";\nimport { Markdown } from \"../components/Markdown\";\nimport { UIKIT_NS } from \"../i18n\";\nimport type { ChatMessage, ChatStep } from \"./types\";\n\n/** The locale of Intl formatting for a language code of the products. */\nconst intlLocale = (lng: string) => (lng === \"zh\" ? \"zh-CN\" : lng);\n\n/** The time of a caption: hours and minutes in the language of the interface. */\nexport function markTime(iso: string, language: string): string {\n return new Intl.DateTimeFormat(intlLocale(language), { hour: \"2-digit\", minute: \"2-digit\" }).format(new Date(iso));\n}\n\n/** More than three steps are folded to the last two (design §6.4). */\nexport function visibleSteps(steps: ChatStep[], open: boolean): ChatStep[] {\n return open || steps.length <= 3 ? steps : steps.slice(-2);\n}\n\n/** The icon of a step and its colour class by the state of the step. */\nconst STEP = {\n done: { icon: \"check\", cls: \"ok\" },\n error: { icon: \"alert\", cls: \"er\" },\n running: { icon: \"clock\", cls: \"run\" },\n} as const;\n\n/** One message of the conversation (design §6.4). */\nexport function MessageView({ m, busy, onRetry }: { m: ChatMessage; busy: boolean; onRetry?: () => void }) {\n const { t, i18n } = useTranslation(UIKIT_NS);\n const [open, setOpen] = useState(false);\n if (m.role === \"note\") return <div className=\"sysnote\">{m.text}</div>;\n if (m.role === \"event\" && m.event) return <EventDivider m={m} />;\n const mark = m.mark && <div className=\"chan\"><Icon name={m.mark.icon} size={12} /> {m.mark.text} · {markTime(m.createdAt, i18n.language)}</div>;\n const atts = m.attachments && m.attachments.length > 0 && (\n <div className=\"atts\">\n {m.attachments.map((a) => <a key={a.id} href={a.href}><Icon name=\"clip\" size={12} /> {a.fileName}</a>)}\n </div>\n );\n if (m.role === \"user\") {\n return (\n <div className=\"m u\">\n {mark}\n {m.content}\n {m.text && <div className=\"bub\">{m.text}</div>}\n {atts}\n {m.wait && (\n <div className={`turnstate${m.wait.state === \"queued\" ? \" q\" : \"\"}`} role=\"status\">\n {m.wait.state === \"queued\"\n ? <><Icon name=\"clock\" size={12} />{t(\"chat.wait.queued\", { count: m.wait.position })}</>\n : <><span className=\"spin\" aria-hidden=\"true\" />{t(\"chat.wait.starting\")}</>}\n </div>\n )}\n </div>\n );\n }\n const steps = m.steps ?? [];\n const waiting = (m.status === \"streaming\" || m.status === \"pending\") && !m.text && !m.content;\n return (\n <div className=\"m a\">\n {mark}\n {steps.length > 3 && (\n <button className=\"tools-fold\" onClick={() => setOpen((v) => !v)} aria-expanded={open}>\n {open ? t(\"chat.hideSteps\") : t(\"chat.moreSteps\", { count: steps.length - 2 })}\n </button>\n )}\n {visibleSteps(steps, open).map((s) => (\n <div key={s.id} className=\"tool\" title={s.title}>\n <Icon name={STEP[s.status].icon} size={14} className={STEP[s.status].cls} />\n <span className=\"tx\">{s.text}</span>\n </div>\n ))}\n {waiting && <div className=\"bub\"><span className=\"typing\" aria-label={t(\"chat.typing\")}><i /><i /><i /></span></div>}\n {m.content ?? (m.text && <div className=\"bub\" title={m.hint}><Markdown text={m.text} /></div>)}\n {atts}\n {m.error && (\n <div className={`llmerr${m.error.transient ? \" amber\" : \"\"}`} role=\"alert\" style={{ marginTop: 6 }}>\n <span>{m.error.text}</span>\n {onRetry && (\n <div className=\"row\">\n <button className=\"btn sm\" disabled={busy} onClick={onRetry}><Icon name=\"refresh\" size={14} />{t(\"chat.retry\")}</button>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n\n/** An event of the conversation: a line with a chip; the details unfold\n * (FTR.NAB.CHAT-0001 design §3.2). */\nfunction EventDivider({ m }: { m: ChatMessage }) {\n const { t, i18n } = useTranslation(UIKIT_NS);\n const [open, setOpen] = useState(false);\n const ev = m.event!;\n return (\n <div className=\"evdiv\">\n <div className=\"evline\" role=\"separator\">\n <span className=\"evchip\">\n <Icon name={ev.icon} size={12} />\n {ev.text} · {markTime(m.createdAt, i18n.language)}\n {ev.details && (\n <button type=\"button\" className=\"textbtn\" aria-expanded={open} onClick={() => setOpen((v) => !v)}>\n {t(\"chat.event.details\")} {open ? \"▴\" : \"▾\"}\n </button>\n )}\n </span>\n </div>\n {open && ev.details && <div className=\"evdetails\">{ev.details}</div>}\n </div>\n );\n}\n","/** What the composer does with the outcome of a recognition. */\nexport interface TranscriptionHandlers {\n busy(on: boolean): void;\n /** The recognized text goes into the composer. */\n text(text: string): void;\n /** Nothing was recognized. */\n empty(): void;\n /** The recognition failed: the reason and a way to try the same recording again. */\n failed(reason: string | undefined, retry: () => void): void;\n}\n\n/** Recognizes a recording (FTR.NAB.CHAT-0001 R20, design §3.1). A rejection of the\n * product is a failure the user may retry: the recording stays with the retry until\n * the toast is closed. `null` means the product has told the user itself. */\nexport async function transcribe(recording: Blob, recognize: (b: Blob) => Promise<string | null>, on: TranscriptionHandlers): Promise<void> {\n on.busy(true);\n let r: string | null;\n try {\n r = await recognize(recording);\n } catch (e) {\n on.busy(false);\n on.failed(e instanceof Error && e.message ? e.message : undefined, () => void transcribe(recording, recognize, on));\n return;\n }\n on.busy(false);\n if (r === null) return;\n if (!r) on.empty();\n else on.text(r);\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\n\n/** Recording with MediaRecorder (FTR.NAB.CHAT-0001 R20): started and stopped\n * by the user, stopped by itself at `maxSeconds`; the level of the voice is\n * sampled for the bar of the recording. */\nexport function useRecorder(maxSeconds = 300, onLimit?: () => void) {\n const supported = typeof window !== \"undefined\" && \"MediaRecorder\" in window && !!navigator.mediaDevices?.getUserMedia;\n const [recording, setRecording] = useState(false);\n const [seconds, setSeconds] = useState(0);\n const [level, setLevel] = useState(0);\n const [error, setError] = useState(false);\n const rec = useRef<MediaRecorder | null>(null);\n const chunks = useRef<Blob[]>([]);\n const timer = useRef<number | undefined>(undefined);\n const audio = useRef<AudioContext | null>(null);\n const stopped = useRef<((b: Blob | null) => void) | null>(null);\n const discard = useRef(false);\n const limit = useRef(onLimit);\n useEffect(() => {\n limit.current = onLimit;\n });\n\n const cleanup = useCallback(() => {\n window.clearInterval(timer.current);\n rec.current?.stream.getTracks().forEach((tr) => tr.stop());\n rec.current = null;\n void audio.current?.close().catch(() => undefined);\n audio.current = null;\n setRecording(false);\n setLevel(0);\n }, []);\n\n const start = useCallback(async () => {\n if (!supported || rec.current) return;\n setError(false);\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n const r = new MediaRecorder(stream);\n chunks.current = [];\n discard.current = false;\n r.ondataavailable = (e) => e.data.size > 0 && chunks.current.push(e.data);\n r.onstop = () => {\n const blob = !discard.current && chunks.current.length ? new Blob(chunks.current, { type: r.mimeType || \"audio/webm\" }) : null;\n cleanup();\n stopped.current?.(blob);\n stopped.current = null;\n };\n let analyser: AnalyserNode | null = null;\n try {\n const Ctx = window.AudioContext ?? (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (Ctx) {\n audio.current = new Ctx();\n analyser = audio.current.createAnalyser();\n analyser.fftSize = 256;\n audio.current.createMediaStreamSource(stream).connect(analyser);\n }\n } catch {\n analyser = null; // the bar stays flat without Web Audio\n }\n const samples = analyser ? new Uint8Array(analyser.fftSize) : null;\n rec.current = r;\n r.start();\n setSeconds(0);\n setRecording(true);\n const began = Date.now();\n let limited = false;\n timer.current = window.setInterval(() => {\n const s = Math.floor((Date.now() - began) / 1000);\n setSeconds(s);\n if (analyser && samples) {\n analyser.getByteTimeDomainData(samples);\n let peak = 0;\n for (const v of samples) peak = Math.max(peak, Math.abs(v - 128));\n setLevel(Math.min(1, peak / 64));\n }\n if (s >= maxSeconds && !limited) {\n limited = true;\n limit.current?.();\n }\n }, 100);\n } catch {\n setError(true);\n cleanup();\n }\n }, [supported, cleanup, maxSeconds]);\n\n const stop = useCallback(() => new Promise<Blob | null>((resolve) => {\n const r = rec.current;\n if (!r || r.state === \"inactive\") return resolve(null);\n stopped.current = resolve;\n r.stop();\n }), []);\n\n /** Ends the recording and drops it. */\n const cancel = useCallback(() => {\n discard.current = true;\n void stop();\n }, [stop]);\n\n useEffect(() => () => cleanup(), [cleanup]);\n\n return { supported, recording, seconds, level, error, start, stop, cancel };\n}\n\n/** m:ss of a number of seconds. */\nexport function clock(seconds: number): string {\n return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, \"0\")}`;\n}\n","import { useEffect, useLayoutEffect, useRef, useState, type KeyboardEvent } from \"react\";\nimport { Icon } from \"../components/Icon\";\nimport { useToast } from \"../components/ui\";\nimport { useKitT } from \"../i18n\";\nimport { CommandPalette, matchCommands } from \"./CommandPalette\";\nimport { ContextMeter } from \"./ContextMeter\";\nimport { MessageView } from \"./MessageView\";\nimport { transcribe } from \"./transcription\";\nimport type { ChatCommand, ChatProps, ChatUpload } from \"./types\";\nimport { clock, useRecorder } from \"./useRecorder\";\n\n/** The conversation: the messages and the composer (FTR.NAB.CMN-0005 R11–R13,\n * design §6; FTR.NAB.CHAT-0001 design §3.1). The behaviour is the one of the\n * chat of Nabu. A control exists only when the product gave its handler: no\n * `onCancel` — no cancel button, no `commands` — no palette. */\nexport function Chat(props: ChatProps) {\n const t = useKitT();\n const toast = useToast();\n const [text, setText] = useState(\"\");\n const [pending, setPending] = useState<ChatUpload[]>([]);\n const [uploading, setUploading] = useState(false);\n const [skill, setSkill] = useState<string | null>(null);\n const [active, setActive] = useState(0);\n const [paletteClosed, setPaletteClosed] = useState(false);\n const [unknown, setUnknown] = useState<string | null>(null);\n const [recognizing, setRecognizing] = useState(false);\n const voice = useRef(false);\n const listRef = useRef<HTMLDivElement>(null);\n const fileRef = useRef<HTMLInputElement>(null);\n const fieldRef = useRef<HTMLTextAreaElement>(null);\n const maxSeconds = props.voiceMaxSeconds ?? 300;\n const recorder = useRecorder(maxSeconds, () => void stopAndTranscribe());\n const { messages, busy = false } = props;\n const onPendingChange = props.onPendingChange;\n useEffect(() => onPendingChange?.(pending), [pending, onPendingChange]);\n\n const first = messages[0]?.id;\n const tail = messages[messages.length - 1];\n const last = tail?.id;\n const tailText = tail?.text.length;\n const tailSteps = tail?.steps?.length;\n // The ends and the height of the list at the last layout: earlier messages\n // loaded above it keep the place of the list.\n const lastLayout = useRef<{ first?: string; last?: string; height: number }>({ height: 0 });\n // The list follows new messages and the growth of the last one: the dependencies are the trigger.\n useLayoutEffect(() => {\n const el = listRef.current;\n if (!el) return;\n const was = lastLayout.current;\n // history is prepended when the start of the list changed and its end did not;\n // another conversation changes both\n const prepended = was.first !== undefined && first !== was.first && last === was.last;\n el.scrollTop = prepended ? el.scrollTop + (el.scrollHeight - was.height) : el.scrollHeight;\n lastLayout.current = { first, last, height: el.scrollHeight };\n // oxlint-disable-next-line react/exhaustive-effect-dependencies -- the length and the growth of the tail only trigger\n }, [messages.length, first, last, tailText, tailSteps]);\n\n // R4: \"/\" at the start of the field without a space opens the palette\n const query = props.commands && !skill && text.startsWith(\"/\") && !/\\s/.test(text) ? text.slice(1) : null;\n const items = query !== null ? matchCommands(props.commands ?? [], query) : [];\n const paletteOpen = query !== null && !paletteClosed;\n\n const clear = () => {\n setText(\"\");\n setPending([]);\n setSkill(null);\n setUnknown(null);\n voice.current = false;\n };\n\n const runCommand = async (name: string, rest: string) => {\n if (!props.onCommand) return;\n try {\n await props.onCommand(name, rest);\n clear();\n } catch {\n // the product has told the user; the text stays\n }\n };\n\n const send = async (body: string, asText = false) => {\n const msg = body.trim();\n if ((!msg && pending.length === 0 && !skill) || busy || props.readOnly) return;\n // R4: a command typed in full runs; an unknown one waits for «Send as text»\n if (!asText && !skill && props.commands && msg.startsWith(\"/\")) {\n const [word, ...rest] = msg.slice(1).split(/\\s+/);\n const cmd = props.commands.find((c) => c.kind === \"command\" && c.name === word);\n if (cmd) return runCommand(cmd.name, rest.join(\" \"));\n if (word && !msg.includes(\"\\n\")) {\n setUnknown(\"/\" + word);\n return;\n }\n }\n try {\n await props.onSend(msg, pending.map((f) => f.id), voice.current, skill ?? undefined);\n clear();\n } catch {\n // the product has told the user; the text stays in the composer\n }\n };\n\n const pick = (c: ChatCommand) => {\n setActive(0);\n if (c.kind === \"skill\") {\n setSkill(c.name);\n setText(\"\");\n } else if (c.takesText) {\n setText(\"/\" + c.name + \" \");\n } else {\n void runCommand(c.name, \"\");\n }\n fieldRef.current?.focus();\n };\n\n const keys = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (paletteOpen && items.length > 0) {\n if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\") {\n e.preventDefault();\n const d = e.key === \"ArrowDown\" ? 1 : -1;\n setActive((a) => (a + d + items.length) % items.length);\n return;\n }\n if ((e.key === \"Enter\" && !e.shiftKey) || e.key === \"Tab\") {\n e.preventDefault();\n pick(items[Math.min(active, items.length - 1)]);\n return;\n }\n }\n if (paletteOpen && e.key === \"Escape\") {\n e.preventDefault();\n setPaletteClosed(true);\n return;\n }\n if (e.key === \"Backspace\" && skill && text === \"\") {\n setSkill(null); // design §3.1: Backspace in the empty field takes the skill off\n return;\n }\n if (e.key === \"Enter\" && !e.shiftKey && !e.nativeEvent.isComposing) {\n e.preventDefault();\n void send(text);\n }\n };\n\n const attach = async (files: FileList | null) => {\n if (!files?.length || !props.onUpload) return;\n setUploading(true);\n for (const f of Array.from(files)) {\n if (props.upload && f.size > props.upload.maxBytes) {\n toast({ kind: \"error\", title: t(\"chat.tooLarge\"), text: f.name });\n continue;\n }\n const a = await props.onUpload(f).catch(() => null);\n if (a) setPending((x) => [...x, a]);\n }\n setUploading(false);\n if (fileRef.current) fileRef.current.value = \"\";\n };\n\n // R20: the recognized text goes into the field; the user checks and sends it\n async function stopAndTranscribe() {\n const blob = await recorder.stop();\n if (!blob || !props.onTranscribe) return;\n await transcribe(blob, props.onTranscribe, {\n busy: setRecognizing,\n empty: () => toast({ kind: \"error\", title: t(\"chat.voice.notRecognized\") }),\n // design §3.1: the recording stays until the toast is closed\n failed: (reason, retry) => toast({ kind: \"error\", title: reason ?? t(\"chat.voice.failed\"), actions: [{ label: t(\"chat.voice.retry\"), primary: true, onClick: retry }] }),\n text: (r) => {\n voice.current = true;\n setText((x) => (x.trim() ? x.trimEnd() + \" \" + r : r));\n fieldRef.current?.focus();\n },\n });\n }\n\n const voiceKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\" && recorder.recording) {\n e.preventDefault();\n recorder.cancel();\n }\n };\n\n const placeholder = skill ? t(\"chat.skillPlaceholder\") : t(\"chat.placeholder\", { name: props.agentName });\n const left = maxSeconds - recorder.seconds;\n return (\n <section className=\"nb-chat\" aria-label={t(\"chat.title\")}>\n {props.header}\n <div className=\"msgs\" ref={listRef} aria-live=\"polite\">\n {props.hasOlder && props.onLoadOlder && (\n <button className=\"btn ghost sm\" style={{ alignSelf: \"center\" }} disabled={props.loadingOlder} onClick={props.onLoadOlder}>\n {t(\"chat.loadOlder\")}\n </button>\n )}\n {props.historyError && <div className=\"err-text\">{props.historyError}</div>}\n {messages.length === 0 && !props.loading && !props.historyError && (\n <div className=\"empty\"><div className=\"ic\"><Icon name=\"spark\" /></div><b>{t(\"chat.emptyTitle\", { name: props.agentName })}</b>{props.emptyHint}</div>\n )}\n {messages.map((m) => <MessageView key={m.id} m={m} busy={busy} onRetry={props.onRetry && (() => props.onRetry?.(m.id))} />)}\n {props.onConfirm && (props.confirmations ?? []).map((c) => (\n <div className=\"confirm\" key={c.id} role=\"group\" aria-label={t(\"chat.confirm.title\")}>\n <div className=\"h\"><Icon name=\"alert\" size={16} />{t(\"chat.confirm.title\")}</div>\n <div>{t(\"chat.confirm.text\", { action: c.summary })}</div>\n {c.preview !== undefined && <pre>{c.preview}</pre>}\n <div className=\"acts\">\n {/* never tied to `busy`: the agent asks in the middle of its turn */}\n <button className=\"btn sm primary\" onClick={() => props.onConfirm?.(c.id, true)}>{t(\"chat.confirm.approve\")}</button>\n <button className=\"btn sm\" onClick={() => props.onConfirm?.(c.id, false)}>{t(\"chat.confirm.reject\")}</button>\n </div>\n </div>\n ))}\n </div>\n\n {props.readOnly ? (\n <div className=\"composer\" style={{ justifyContent: \"space-between\", alignItems: \"center\" }}>{props.readOnly}</div>\n ) : (\n <div className=\"composer-wrap\">\n {paletteOpen && <CommandPalette items={items} active={Math.min(active, Math.max(items.length - 1, 0))} onPick={pick} onHover={setActive} />}\n {props.aboveComposer}\n {pending.length > 0 && (\n <div className=\"pending-files\">\n {pending.map((f) => (\n <span key={f.id} className=\"chip\">\n <Icon name=\"clip\" size={12} />{f.fileName}\n <button className=\"iconbtn\" style={{ width: 18, height: 18 }} aria-label={t(\"remove\")}\n onClick={() => setPending((x) => x.filter((y) => y.id !== f.id))}><Icon name=\"x\" size={12} /></button>\n </span>\n ))}\n </div>\n )}\n {unknown && (\n <div className=\"cmd-unknown\" role=\"status\">\n {t(\"chat.unknownCommand\", { name: unknown })}\n <button type=\"button\" className=\"textbtn\" onClick={() => void send(text, true)}>{t(\"chat.sendAsText\")}</button>\n </div>\n )}\n <div className=\"composer\">\n {props.onUpload && !recorder.recording && (\n <>\n <button className=\"iconbtn\" aria-label={t(\"chat.attach\")} disabled={uploading} onClick={() => fileRef.current?.click()}><Icon name=\"clip\" /></button>\n <input ref={fileRef} type=\"file\" multiple hidden accept={props.upload?.accept} onChange={(e) => attach(e.target.files)} />\n </>\n )}\n {recorder.recording ? (\n <div className={`recbar${left <= 15 ? \" ending\" : \"\"}`} role=\"status\" aria-label={t(\"chat.voice.recordingNow\")}>\n <span className=\"dot\" aria-hidden=\"true\" />\n <span className=\"tm\">{clock(recorder.seconds)} / {clock(maxSeconds)}</span>\n <span className=\"lvl\" aria-hidden=\"true\"><i style={{ transform: `scaleX(${Math.max(0.04, recorder.level)})` }} /></span>\n <button type=\"button\" className=\"btn ghost sm\" onClick={recorder.cancel}>{t(\"cancel\")}</button>\n <button type=\"button\" className=\"btn primary sm\" onKeyDown={voiceKey} onClick={() => void stopAndTranscribe()}>{t(\"chat.voice.done\")}</button>\n </div>\n ) : (\n <div className={`field${skill ? \" with-skill\" : \"\"}`}>\n {skill && (\n <span className=\"chip skill-chip\">\n <Icon name=\"spark\" size={12} />{skill}\n <button className=\"iconbtn\" style={{ width: 18, height: 18 }} aria-label={t(\"remove\")} onClick={() => setSkill(null)}><Icon name=\"x\" size={12} /></button>\n </span>\n )}\n <textarea ref={fieldRef} rows={1} value={text} placeholder={recognizing ? t(\"chat.voice.recognizing\") : placeholder} aria-label={placeholder}\n disabled={recognizing} aria-expanded={paletteOpen} aria-autocomplete={props.commands ? \"list\" : undefined}\n onChange={(e) => { setText(e.target.value); setPaletteClosed(false); setActive(0); setUnknown(null); }}\n onKeyDown={keys} />\n </div>\n )}\n {props.context && !recorder.recording && <ContextMeter context={props.context} onCompact={props.onCompact} onReset={props.onReset} />}\n {props.onTranscribe && !recorder.recording && (\n <button className=\"iconbtn\" disabled={!recorder.supported || recognizing}\n aria-label={t(\"chat.voice.start\")} title={recorder.supported ? t(\"chat.voice.start\") : t(\"chat.voice.unsupported\")}\n onClick={() => void recorder.start()}>\n <Icon name=\"mic\" />\n </button>\n )}\n {!recorder.recording && (props.onCancel && busy ? (\n <button className=\"iconbtn fill\" aria-label={t(\"chat.stop\")} onClick={props.onCancel}><Icon name=\"stop\" /></button>\n ) : (\n <button className=\"iconbtn fill\" aria-label={t(\"chat.send\")} disabled={(!text.trim() && pending.length === 0 && !skill) || busy} onClick={() => send(text)}>\n <Icon name=\"send\" />\n </button>\n ))}\n </div>\n {recorder.error && <div className=\"err-text\" style={{ padding: \"0 12px 8px\" }}>{t(\"chat.voice.micDenied\")}</div>}\n </div>\n )}\n </section>\n );\n}\n","import { useEffect, useState, type ReactNode } from \"react\";\nimport { Icon } from \"../components/Icon\";\nimport { Modal } from \"../components/ui\";\nimport { useKitT } from \"../i18n\";\nimport type { ChatConversation, ConversationListProps } from \"./types\";\n\n/** The conversations of the user: the main one, the topics, the archive (design\n * §6.2). In a wide place the list stands left of the messages; on a phone and in\n * a narrow place it lies over them while open and closes by a pick, a tap\n * beside it or Escape. */\nexport function ConversationList({ conversations, currentId, open, onPick, onClose, onCreate }: ConversationListProps) {\n const t = useKitT();\n const [creating, setCreating] = useState(false);\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && onClose();\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [open, onClose]);\n\n const item = (c: ChatConversation) => (\n <button key={c.id} className={`it${c.id === currentId ? \" on\" : \"\"}${c.group === \"archive\" ? \" arch\" : \"\"}`}\n onClick={() => onPick(c.id)} aria-current={c.id === currentId}>\n <Icon name={c.icon ?? \"msg2\"} size={16} />\n <span className=\"nm\">{c.title}</span>\n {!!c.unread && <span className=\"unread\" aria-label={t(\"chat.unread\", { count: c.unread })}>{c.unread}</span>}\n <span className=\"sub\">{c.when}</span>\n </button>\n );\n const inGroup = (g: ChatConversation[\"group\"]) => conversations.filter((c) => c.group === g);\n const topics = inGroup(\"topic\");\n const archive = inGroup(\"archive\");\n return (\n <>\n <nav className={`nb-side${open ? \" open\" : \"\"}`} aria-label={t(\"chat.conversations\")}>\n {onCreate && (\n <button className=\"btn sm\" style={{ width: \"100%\", justifyContent: \"center\" }} onClick={() => setCreating(true)}>\n <Icon name=\"plus\" size={15} />{t(\"chat.newTopic\")}\n </button>\n )}\n <div className=\"h\">{t(\"chat.conversation\")}</div>\n {inGroup(\"main\").map(item)}\n <div className=\"h\">{t(\"chat.topics\")}</div>\n {topics.length === 0 && <div className=\"small muted\" style={{ padding: \"0 10px\" }}>{t(\"chat.noTopics\")}</div>}\n {topics.map(item)}\n {archive.length > 0 && <div className=\"h\">{t(\"chat.archive\")}</div>}\n {archive.map(item)}\n </nav>\n {/* over the messages: a tap beside the list closes it */}\n {open && <button type=\"button\" className=\"nb-scrim\" aria-label={t(\"close\")} onClick={onClose} />}\n {creating && onCreate && <NewTopicModal onClose={() => setCreating(false)} onCreate={onCreate} />}\n </>\n );\n}\n\n/** The place of a chat: the list of conversations, the conversation and what the\n * product puts beside them. `narrow` is for a side panel: the list lies over the\n * messages as on a phone, whatever the width of the window. */\nexport function ChatLayout({ narrow, children }: { narrow?: boolean; children: ReactNode }) {\n return <div className={`nb-app${narrow ? \" narrow\" : \"\"}`}>{children}</div>;\n}\n\n/** The dialog of a new topic: one field, Enter creates. */\nexport function NewTopicModal({ onClose, onCreate }: { onClose: () => void; onCreate: (title: string) => Promise<void> }) {\n const t = useKitT();\n const [title, setTitle] = useState(\"\");\n const [pending, setPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const create = async () => {\n if (!title.trim() || pending) return;\n setPending(true);\n setError(null);\n try {\n await onCreate(title.trim());\n onClose();\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n setPending(false);\n }\n };\n return (\n <Modal title={t(\"chat.newTopic\")} onClose={onClose} footer={<>\n <button className=\"btn ghost\" onClick={onClose}>{t(\"cancel\")}</button>\n <button className=\"btn primary\" disabled={!title.trim() || pending} onClick={create}>{t(\"create\")}</button>\n </>}>\n <div className=\"field\">\n <label htmlFor=\"topic-title\">{t(\"chat.topicTitle\")}</label>\n <input id=\"topic-title\" className=\"inp\" value={title} maxLength={120} onChange={(e) => setTitle(e.target.value)}\n onKeyDown={(e) => e.key === \"Enter\" && create()} />\n <div className=\"hint\">{t(\"chat.topicHint\")}</div>\n </div>\n {error && <div className=\"err-text\">{error}</div>}\n </Modal>\n );\n}\n","import { useState, type ReactNode } from \"react\";\nimport { Icon, type IconName } from \"../components/Icon\";\nimport { useOutside } from \"../components/ui\";\nimport { useKitT } from \"../i18n\";\n\n/** One of the ways an agent can look and talk; what it means only the product knows (R7). */\nexport interface AgentOption { key: string; label: string; icon: IconName }\n\n/** A model the user may choose for the agent (FTR.NAB.CHAT-0001 R16, design §3.3). */\nexport interface AgentModelOption {\n key: string;\n label: string;\n /** The connection or the default model, grey under the name. */\n sub?: string;\n /** The capabilities: images, reasoning, the window. */\n badges?: { icon?: IconName; text: string }[];\n /** Under the row of the chosen model: the context will be compacted. */\n warn?: ReactNode;\n}\n\n/** The block «Model» of the menu: one model is shown without a choice; none — the text of the product. */\nexport interface AgentModels {\n label: ReactNode;\n options: AgentModelOption[];\n value: string;\n onPick: (key: string) => void;\n empty?: ReactNode;\n}\n\n/** The round button of the agent: its icon, and the menu behind it. */\nexport function AgentButton({ icon, label, title, expanded, small, disabled, onClick }: {\n icon: IconName; label: string; title?: string; expanded?: boolean; small?: boolean; disabled?: boolean; onClick?: () => void;\n}) {\n return (\n <button type=\"button\" className={`agentbtn${small ? \" s\" : \"\"}`} disabled={disabled} aria-label={label} aria-expanded={expanded} title={title}\n // the menu closes on an outside mousedown; keep this click a toggle\n onMouseDown={(e) => expanded && e.stopPropagation()} onClick={onClick}>\n <Icon name={icon} size={small ? 15 : 18} />\n </button>\n );\n}\n\n/** The menu of the agent (FTR.NAB.CMN-0005 R15, design §6.6): its name and a\n * choice among the options of the product, as tiles with icons. The name is\n * saved on Enter and on leaving the field; a pick is saved at once. */\nexport function AgentMenu({ label, name, options, value, optionsLabel, hint, narrow, models, onRename, onPick, onClose }: {\n /** The name of the dialog for a screen reader. */\n label: string;\n name: string;\n options: AgentOption[];\n value: string;\n optionsLabel: ReactNode;\n hint?: ReactNode;\n /** A narrow place — a side panel: the options go in one column. */\n narrow?: boolean;\n /** The choice of the model after the options. */\n models?: AgentModels;\n onRename: (name: string) => void;\n onPick: (key: string) => void;\n /** Must keep its identity between renders. */\n onClose: () => void;\n}) {\n const t = useKitT();\n const [draft, setDraft] = useState(name);\n const ref = useOutside<HTMLDivElement>(true, onClose);\n const save = () => {\n const next = draft.trim();\n if (next && next !== name) onRename(next);\n };\n return (\n <div className={`agentmenu${narrow ? \" narrow\" : \"\"}`} ref={ref} role=\"dialog\" aria-label={label}>\n <div className=\"lab\">{t(\"agentName\")}</div>\n <input className=\"inp\" value={draft} maxLength={40} autoFocus aria-label={t(\"agentName\")}\n onChange={(e) => setDraft(e.target.value)} onBlur={save}\n onKeyDown={(e) => e.key === \"Enter\" && (e.target as HTMLInputElement).blur()} />\n <div className=\"lab\" style={{ marginTop: 14 }}>{optionsLabel}</div>\n <div className=\"agentoptions\">\n {options.map((o) => (\n <button key={o.key} type=\"button\" className={`agentoption${value === o.key ? \" on\" : \"\"}`} aria-pressed={value === o.key} onClick={() => onPick(o.key)}>\n <span className=\"ic\"><Icon name={o.icon} size={15} /></span>\n {o.label}\n </button>\n ))}\n </div>\n {models && (\n <>\n <div className=\"lab\" style={{ marginTop: 14 }}>{models.label}</div>\n {models.options.length === 0 && <div className=\"hint\">{models.empty}</div>}\n <div className=\"agentmodels\" role=\"radiogroup\">\n {models.options.map((m) => {\n const single = models.options.length === 1;\n const on = single || models.value === m.key;\n return (\n <button key={m.key} type=\"button\" role=\"radio\" aria-checked={on} disabled={single} className={`agentmodel${on ? \" on\" : \"\"}`}\n onClick={() => !on && models.onPick(m.key)}>\n {!single && <span className={`radio${on ? \" on\" : \"\"}`} aria-hidden=\"true\" />}\n <span className=\"body\">\n <span className=\"nm\">{m.label}</span>\n {m.sub && <span className=\"sub\">{m.sub}</span>}\n {m.badges && m.badges.length > 0 && (\n <span className=\"badges\">\n {m.badges.map((b) => <span key={b.text} className=\"cap\">{b.icon && <Icon name={b.icon} size={11} />}{b.text}</span>)}\n </span>\n )}\n {on && m.warn && <span className=\"warn\">{m.warn}</span>}\n </span>\n </button>\n );\n })}\n </div>\n </>\n )}\n {hint && <div className=\"hint\" style={{ marginTop: 10 }}>{hint}</div>}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -47,6 +47,8 @@ export declare const resources: {
47
47
  done: string;
48
48
  recognizing: string;
49
49
  recordingNow: string;
50
+ failed: string;
51
+ retry: string;
50
52
  };
51
53
  confirm: {
52
54
  title: string;
@@ -125,6 +127,8 @@ export declare const resources: {
125
127
  done: string;
126
128
  recognizing: string;
127
129
  recordingNow: string;
130
+ failed: string;
131
+ retry: string;
128
132
  };
129
133
  confirm: {
130
134
  title: string;
@@ -203,6 +207,8 @@ export declare const resources: {
203
207
  done: string;
204
208
  recognizing: string;
205
209
  recordingNow: string;
210
+ failed: string;
211
+ retry: string;
206
212
  };
207
213
  confirm: {
208
214
  title: string;
@@ -281,6 +287,8 @@ export declare const resources: {
281
287
  done: string;
282
288
  recognizing: string;
283
289
  recordingNow: string;
290
+ failed: string;
291
+ retry: string;
284
292
  };
285
293
  confirm: {
286
294
  title: string;
@@ -359,6 +367,8 @@ export declare const resources: {
359
367
  done: string;
360
368
  recognizing: string;
361
369
  recordingNow: string;
370
+ failed: string;
371
+ retry: string;
362
372
  };
363
373
  confirm: {
364
374
  title: string;
package/dist/locales.js CHANGED
@@ -47,7 +47,9 @@ var t = {
47
47
  start: "Record a voice message",
48
48
  done: "Stop",
49
49
  recognizing: "Recognizing…",
50
- recordingNow: "Recording"
50
+ recordingNow: "Recording",
51
+ failed: "The voice message could not be recognized",
52
+ retry: "Retry"
51
53
  },
52
54
  confirm: {
53
55
  title: "Confirm the action",
@@ -123,7 +125,9 @@ var t = {
123
125
  start: "Записать голосом",
124
126
  done: "Стоп",
125
127
  recognizing: "Распознаём…",
126
- recordingNow: "Запись"
128
+ recordingNow: "Запись",
129
+ failed: "Не удалось распознать голосовое сообщение",
130
+ retry: "Повторить"
127
131
  },
128
132
  confirm: {
129
133
  title: "Подтвердите действие",
@@ -199,7 +203,9 @@ var t = {
199
203
  start: "Sprachnachricht aufnehmen",
200
204
  done: "Stopp",
201
205
  recognizing: "Wird erkannt…",
202
- recordingNow: "Aufnahme"
206
+ recordingNow: "Aufnahme",
207
+ failed: "Die Sprachnachricht konnte nicht erkannt werden",
208
+ retry: "Wiederholen"
203
209
  },
204
210
  confirm: {
205
211
  title: "Aktion bestätigen",
@@ -275,7 +281,9 @@ var t = {
275
281
  start: "Grabar un mensaje de voz",
276
282
  done: "Detener",
277
283
  recognizing: "Reconociendo…",
278
- recordingNow: "Grabando"
284
+ recordingNow: "Grabando",
285
+ failed: "No se pudo reconocer el mensaje de voz",
286
+ retry: "Reintentar"
279
287
  },
280
288
  confirm: {
281
289
  title: "Confirme la acción",
@@ -351,7 +359,9 @@ var t = {
351
359
  start: "录制语音",
352
360
  done: "停止",
353
361
  recognizing: "正在识别…",
354
- recordingNow: "录音中"
362
+ recordingNow: "录音中",
363
+ failed: "无法识别语音消息",
364
+ retry: "重试"
355
365
  },
356
366
  confirm: {
357
367
  title: "确认操作",
@@ -1 +1 @@
1
- {"version":3,"file":"locales.js","names":["loading","cancel","create","close","remove","agentName","topbar","chat","loading","cancel","create","close","remove","agentName","topbar","chat","loading","cancel","create","close","remove","agentName","topbar","chat","loading","cancel","create","close","remove","agentName","topbar","chat","UIKIT_NS","resources","\"delete\"","\"sections\"","\"profile\"","\"title\"","\"conversations\"","\"conversation\"","\"topics\"","\"archive\"","\"noTopics\"","\"newTopic\"","\"topicTitle\"","\"topicHint\"","\"loadOlder\"","\"emptyTitle\"","\"placeholder\"","\"send\"","\"attach\"","\"typing\"","\"moreSteps\"","\"hideSteps\"","\"unread\"","\"retry\"","\"tooLarge\"","\"stop\"","\"voice\"","\"hold\"","\"recording\"","\"review\"","\"notRecognized\"","\"micDenied\"","\"unsupported\"","\"start\"","\"done\"","\"recognizing\"","\"recordingNow\"","\"confirm\"","\"text\"","\"approve\"","\"reject\"","\"wait\"","\"starting\"","\"queued\"","\"palette\"","\"commands\"","\"skills\"","\"noSkills\"","\"empty\"","\"unknownCommand\"","\"sendAsText\"","\"skillPlaceholder\"","\"context\"","\"meter\"","\"full\"","\"compact\"","\"reset\"","\"event\"","\"details\""],"sources":["../src/locales/en.json","../src/locales/ru.json","../src/locales/de.json","../src/locales/es.json","../src/locales/zh.json","../src/locales/index.ts"],"sourcesContent":["{\n \"loading\": \"Loading…\",\n \"cancel\": \"Cancel\",\n \"create\": \"Create\",\n \"close\": \"Close\",\n \"delete\": \"Delete\",\n \"remove\": \"Remove\",\n \"agentName\": \"Agent name\",\n \"topbar\": {\n \"sections\": \"Sections\",\n \"profile\": \"Profile\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Conversations\",\n \"conversation\": \"Conversation\",\n \"topics\": \"Topics\",\n \"archive\": \"Archive\",\n \"noTopics\": \"No topics yet\",\n \"newTopic\": \"New topic\",\n \"topicTitle\": \"Topic\",\n \"topicHint\": \"A topic has its own history and the same memory and space.\",\n \"loadOlder\": \"Earlier messages\",\n \"emptyTitle\": \"Hi, I am {name}\",\n \"placeholder\": \"Message {name}…\",\n \"send\": \"Send\",\n \"attach\": \"Attach files\",\n \"typing\": \"The agent is typing\",\n \"moreSteps\": \"{count, plural, one {# more step} other {# more steps}}\",\n \"hideSteps\": \"Hide steps\",\n \"unread\": \"{count, plural, one {# unread answer} other {# unread answers}}\",\n \"retry\": \"Retry\",\n \"tooLarge\": \"The file is too large.\",\n \"stop\": \"Stop\",\n \"voice\": {\n \"hold\": \"Hold to record\",\n \"stop\": \"Stop recording\",\n \"recording\": \"Recording… {seconds} s\",\n \"review\": \"Check the transcript before sending\",\n \"notRecognized\": \"The speech was not recognized\",\n \"micDenied\": \"No access to the microphone\",\n \"unsupported\": \"Voice input is not supported in this browser\",\n \"start\": \"Record a voice message\",\n \"done\": \"Stop\",\n \"recognizing\": \"Recognizing…\",\n \"recordingNow\": \"Recording\"\n },\n \"confirm\": {\n \"title\": \"Confirm the action\",\n \"text\": \"The agent wants to perform: {action}\",\n \"approve\": \"Execute\",\n \"reject\": \"Reject\"\n },\n \"wait\": {\n \"starting\": \"The agent is starting…\",\n \"queued\": \"{count, plural, =0 {In the queue · you are next} one {In the queue · # ahead of you} other {In the queue · # ahead of you}}\"\n },\n \"palette\": {\n \"title\": \"Commands and skills\",\n \"commands\": \"Commands\",\n \"skills\": \"Skills\",\n \"noSkills\": \"No skills are granted to you\",\n \"empty\": \"Nothing found\"\n },\n \"unknownCommand\": \"Unknown command {name}\",\n \"sendAsText\": \"Send as text\",\n \"skillPlaceholder\": \"What to do with the skill?\",\n \"context\": {\n \"meter\": \"Context: {used} of {total} tokens ({pct}%)\",\n \"full\": \"Answers get more expensive and the agent may get confused.\",\n \"compact\": \"Compact\",\n \"reset\": \"Start over\"\n },\n \"event\": {\n \"details\": \"Summary\"\n }\n }\n}\n","{\n \"loading\": \"Загрузка…\",\n \"cancel\": \"Отмена\",\n \"create\": \"Создать\",\n \"close\": \"Закрыть\",\n \"delete\": \"Удалить\",\n \"remove\": \"Убрать\",\n \"agentName\": \"Имя агента\",\n \"topbar\": {\n \"sections\": \"Разделы\",\n \"profile\": \"Профиль\"\n },\n \"chat\": {\n \"title\": \"Чат\",\n \"conversations\": \"Разговоры\",\n \"conversation\": \"Разговор\",\n \"topics\": \"Темы\",\n \"archive\": \"Архив\",\n \"noTopics\": \"Тем пока нет\",\n \"newTopic\": \"Новая тема\",\n \"topicTitle\": \"Тема\",\n \"topicHint\": \"У темы своя история, а память и пространство — те же.\",\n \"loadOlder\": \"Более ранние сообщения\",\n \"emptyTitle\": \"Привет, я {name}\",\n \"placeholder\": \"Сообщение для {name}…\",\n \"send\": \"Отправить\",\n \"attach\": \"Прикрепить файлы\",\n \"typing\": \"Агент печатает\",\n \"moreSteps\": \"{count, plural, one {ещё # шаг} few {ещё # шага} many {ещё # шагов} other {ещё # шага}}\",\n \"hideSteps\": \"Скрыть шаги\",\n \"unread\": \"{count, plural, one {# непрочитанный ответ} few {# непрочитанных ответа} many {# непрочитанных ответов} other {# непрочитанных ответа}}\",\n \"retry\": \"Повторить\",\n \"tooLarge\": \"Файл слишком большой.\",\n \"stop\": \"Остановить\",\n \"voice\": {\n \"hold\": \"Удерживайте для записи\",\n \"stop\": \"Остановить запись\",\n \"recording\": \"Запись… {seconds} с\",\n \"review\": \"Проверьте расшифровку перед отправкой\",\n \"notRecognized\": \"Речь не распознана\",\n \"micDenied\": \"Нет доступа к микрофону\",\n \"unsupported\": \"Голосовой ввод не поддерживается этим браузером\",\n \"start\": \"Записать голосом\",\n \"done\": \"Стоп\",\n \"recognizing\": \"Распознаём…\",\n \"recordingNow\": \"Запись\"\n },\n \"confirm\": {\n \"title\": \"Подтвердите действие\",\n \"text\": \"Агент хочет выполнить: {action}\",\n \"approve\": \"Выполнить\",\n \"reject\": \"Отклонить\"\n },\n \"wait\": {\n \"starting\": \"Агент запускается…\",\n \"queued\": \"{count, plural, =0 {В очереди · вы следующий} other {В очереди · перед вами #}}\"\n },\n \"palette\": {\n \"title\": \"Команды и скиллы\",\n \"commands\": \"Команды\",\n \"skills\": \"Скиллы\",\n \"noSkills\": \"Вам не выдан ни один скилл\",\n \"empty\": \"Ничего не найдено\"\n },\n \"unknownCommand\": \"Неизвестная команда {name}\",\n \"sendAsText\": \"Отправить как текст\",\n \"skillPlaceholder\": \"Что сделать по скиллу?\",\n \"context\": {\n \"meter\": \"Контекст: {used} из {total} токенов ({pct} %)\",\n \"full\": \"Ответы дорожают, агент может путаться.\",\n \"compact\": \"Сжать\",\n \"reset\": \"Начать заново\"\n },\n \"event\": {\n \"details\": \"Изложение\"\n }\n }\n}\n","{\n \"loading\": \"Wird geladen…\",\n \"cancel\": \"Abbrechen\",\n \"create\": \"Erstellen\",\n \"close\": \"Schließen\",\n \"delete\": \"Löschen\",\n \"remove\": \"Entfernen\",\n \"agentName\": \"Name des Agenten\",\n \"topbar\": {\n \"sections\": \"Bereiche\",\n \"profile\": \"Profil\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Gespräche\",\n \"conversation\": \"Gespräch\",\n \"topics\": \"Themen\",\n \"archive\": \"Archiv\",\n \"noTopics\": \"Noch keine Themen\",\n \"newTopic\": \"Neues Thema\",\n \"topicTitle\": \"Thema\",\n \"topicHint\": \"Ein Thema hat einen eigenen Verlauf, aber dasselbe Gedächtnis und denselben Arbeitsbereich.\",\n \"loadOlder\": \"Frühere Nachrichten\",\n \"emptyTitle\": \"Hallo, ich bin {name}\",\n \"placeholder\": \"Nachricht an {name}…\",\n \"send\": \"Senden\",\n \"attach\": \"Dateien anhängen\",\n \"typing\": \"Der Agent schreibt\",\n \"moreSteps\": \"{count, plural, one {# weiterer Schritt} other {# weitere Schritte}}\",\n \"hideSteps\": \"Schritte ausblenden\",\n \"unread\": \"{count, plural, one {# ungelesene Antwort} other {# ungelesene Antworten}}\",\n \"retry\": \"Wiederholen\",\n \"tooLarge\": \"Die Datei ist zu groß.\",\n \"stop\": \"Stoppen\",\n \"voice\": {\n \"hold\": \"Zum Aufnehmen gedrückt halten\",\n \"stop\": \"Aufnahme beenden\",\n \"recording\": \"Aufnahme… {seconds} s\",\n \"review\": \"Prüfen Sie die Transkription vor dem Senden\",\n \"notRecognized\": \"Die Sprache wurde nicht erkannt\",\n \"micDenied\": \"Kein Zugriff auf das Mikrofon\",\n \"unsupported\": \"Spracheingabe wird von diesem Browser nicht unterstützt\",\n \"start\": \"Sprachnachricht aufnehmen\",\n \"done\": \"Stopp\",\n \"recognizing\": \"Wird erkannt…\",\n \"recordingNow\": \"Aufnahme\"\n },\n \"confirm\": {\n \"title\": \"Aktion bestätigen\",\n \"text\": \"Der Agent möchte ausführen: {action}\",\n \"approve\": \"Ausführen\",\n \"reject\": \"Ablehnen\"\n },\n \"wait\": {\n \"starting\": \"Der Agent startet…\",\n \"queued\": \"{count, plural, =0 {In der Warteschlange · Sie sind als Nächstes dran} other {In der Warteschlange · # vor Ihnen}}\"\n },\n \"palette\": {\n \"title\": \"Befehle und Skills\",\n \"commands\": \"Befehle\",\n \"skills\": \"Skills\",\n \"noSkills\": \"Ihnen ist kein Skill freigegeben\",\n \"empty\": \"Nichts gefunden\"\n },\n \"unknownCommand\": \"Unbekannter Befehl {name}\",\n \"sendAsText\": \"Als Text senden\",\n \"skillPlaceholder\": \"Was soll mit dem Skill getan werden?\",\n \"context\": {\n \"meter\": \"Kontext: {used} von {total} Tokens ({pct} %)\",\n \"full\": \"Antworten werden teurer, der Agent kann durcheinanderkommen.\",\n \"compact\": \"Komprimieren\",\n \"reset\": \"Neu beginnen\"\n },\n \"event\": {\n \"details\": \"Zusammenfassung\"\n }\n }\n}\n","{\n \"loading\": \"Cargando…\",\n \"cancel\": \"Cancelar\",\n \"create\": \"Crear\",\n \"close\": \"Cerrar\",\n \"delete\": \"Eliminar\",\n \"remove\": \"Quitar\",\n \"agentName\": \"Nombre del agente\",\n \"topbar\": {\n \"sections\": \"Secciones\",\n \"profile\": \"Perfil\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Conversaciones\",\n \"conversation\": \"Conversación\",\n \"topics\": \"Temas\",\n \"archive\": \"Archivo\",\n \"noTopics\": \"Aún no hay temas\",\n \"newTopic\": \"Nuevo tema\",\n \"topicTitle\": \"Tema\",\n \"topicHint\": \"Un tema tiene su propio historial y la misma memoria y espacio.\",\n \"loadOlder\": \"Mensajes anteriores\",\n \"emptyTitle\": \"Hola, soy {name}\",\n \"placeholder\": \"Mensaje para {name}…\",\n \"send\": \"Enviar\",\n \"attach\": \"Adjuntar archivos\",\n \"typing\": \"El agente está escribiendo\",\n \"moreSteps\": \"{count, plural, one {# paso más} other {# pasos más}}\",\n \"hideSteps\": \"Ocultar pasos\",\n \"unread\": \"{count, plural, one {# respuesta sin leer} other {# respuestas sin leer}}\",\n \"retry\": \"Reintentar\",\n \"tooLarge\": \"El archivo es demasiado grande.\",\n \"stop\": \"Detener\",\n \"voice\": {\n \"hold\": \"Mantenga pulsado para grabar\",\n \"stop\": \"Detener la grabación\",\n \"recording\": \"Grabando… {seconds} s\",\n \"review\": \"Revise la transcripción antes de enviar\",\n \"notRecognized\": \"No se reconoció la voz\",\n \"micDenied\": \"Sin acceso al micrófono\",\n \"unsupported\": \"Este navegador no admite la entrada de voz\",\n \"start\": \"Grabar un mensaje de voz\",\n \"done\": \"Detener\",\n \"recognizing\": \"Reconociendo…\",\n \"recordingNow\": \"Grabando\"\n },\n \"confirm\": {\n \"title\": \"Confirme la acción\",\n \"text\": \"El agente quiere ejecutar: {action}\",\n \"approve\": \"Ejecutar\",\n \"reject\": \"Rechazar\"\n },\n \"wait\": {\n \"starting\": \"El agente se está iniciando…\",\n \"queued\": \"{count, plural, =0 {En cola · usted es el siguiente} other {En cola · # por delante}}\"\n },\n \"palette\": {\n \"title\": \"Comandos y skills\",\n \"commands\": \"Comandos\",\n \"skills\": \"Skills\",\n \"noSkills\": \"No tiene skills disponibles\",\n \"empty\": \"No se encontró nada\"\n },\n \"unknownCommand\": \"Comando desconocido {name}\",\n \"sendAsText\": \"Enviar como texto\",\n \"skillPlaceholder\": \"¿Qué hacer con el skill?\",\n \"context\": {\n \"meter\": \"Contexto: {used} de {total} tokens ({pct} %)\",\n \"full\": \"Las respuestas se encarecen y el agente puede confundirse.\",\n \"compact\": \"Compactar\",\n \"reset\": \"Empezar de nuevo\"\n },\n \"event\": {\n \"details\": \"Resumen\"\n }\n }\n}\n","{\n \"loading\": \"加载中…\",\n \"cancel\": \"取消\",\n \"create\": \"创建\",\n \"close\": \"关闭\",\n \"delete\": \"删除\",\n \"remove\": \"移除\",\n \"agentName\": \"智能体名称\",\n \"topbar\": {\n \"sections\": \"栏目\",\n \"profile\": \"个人资料\"\n },\n \"chat\": {\n \"title\": \"聊天\",\n \"conversations\": \"对话\",\n \"conversation\": \"对话\",\n \"topics\": \"话题\",\n \"archive\": \"归档\",\n \"noTopics\": \"暂无话题\",\n \"newTopic\": \"新话题\",\n \"topicTitle\": \"话题\",\n \"topicHint\": \"话题有独立的历史记录,记忆和空间与主对话相同。\",\n \"loadOlder\": \"更早的消息\",\n \"emptyTitle\": \"你好,我是 {name}\",\n \"placeholder\": \"给 {name} 发消息…\",\n \"send\": \"发送\",\n \"attach\": \"附加文件\",\n \"typing\": \"智能体正在输入\",\n \"moreSteps\": \"{count, plural, other {另外 # 个步骤}}\",\n \"hideSteps\": \"隐藏步骤\",\n \"unread\": \"{count} 条未读回复\",\n \"retry\": \"重试\",\n \"tooLarge\": \"文件太大。\",\n \"stop\": \"停止\",\n \"voice\": {\n \"hold\": \"按住录音\",\n \"stop\": \"停止录音\",\n \"recording\": \"录音中… {seconds} 秒\",\n \"review\": \"发送前请检查转写文本\",\n \"notRecognized\": \"未能识别语音\",\n \"micDenied\": \"无法访问麦克风\",\n \"unsupported\": \"此浏览器不支持语音输入\",\n \"start\": \"录制语音\",\n \"done\": \"停止\",\n \"recognizing\": \"正在识别…\",\n \"recordingNow\": \"录音中\"\n },\n \"confirm\": {\n \"title\": \"确认操作\",\n \"text\": \"代理想要执行:{action}\",\n \"approve\": \"执行\",\n \"reject\": \"拒绝\"\n },\n \"wait\": {\n \"starting\": \"代理正在启动…\",\n \"queued\": \"{count, plural, =0 {排队中 · 您是下一位} other {排队中 · 前面还有 # 位}}\"\n },\n \"palette\": {\n \"title\": \"命令和技能\",\n \"commands\": \"命令\",\n \"skills\": \"技能\",\n \"noSkills\": \"您没有可用的技能\",\n \"empty\": \"未找到\"\n },\n \"unknownCommand\": \"未知命令 {name}\",\n \"sendAsText\": \"作为文本发送\",\n \"skillPlaceholder\": \"用这个技能做什么?\",\n \"context\": {\n \"meter\": \"上下文:{used} / {total} 个令牌({pct}%)\",\n \"full\": \"回答变得更贵,代理可能会混淆。\",\n \"compact\": \"压缩\",\n \"reset\": \"重新开始\"\n },\n \"event\": {\n \"details\": \"摘要\"\n }\n }\n}\n","import en from \"./en.json\";\nimport ru from \"./ru.json\";\nimport de from \"./de.json\";\nimport es from \"./es.json\";\nimport zh from \"./zh.json\";\n\n/** Strings of the components in the five languages of the products. A product adds\n * them to its i18next instance under the namespace `uikit`. */\nexport const resources = { en, ru, de, es, zh };\nexport type KitLanguage = keyof typeof resources;\nexport { UIKIT_NS } from \"../i18n\";\n"],"mappings":";;;AKQA,IAAaiC,IAAY;CAAE,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;AAAG"}
1
+ {"version":3,"file":"locales.js","names":["loading","cancel","create","close","remove","agentName","topbar","chat","loading","cancel","create","close","remove","agentName","topbar","chat","loading","cancel","create","close","remove","agentName","topbar","chat","loading","cancel","create","close","remove","agentName","topbar","chat","UIKIT_NS","resources","\"delete\"","\"sections\"","\"profile\"","\"title\"","\"conversations\"","\"conversation\"","\"topics\"","\"archive\"","\"noTopics\"","\"newTopic\"","\"topicTitle\"","\"topicHint\"","\"loadOlder\"","\"emptyTitle\"","\"placeholder\"","\"send\"","\"attach\"","\"typing\"","\"moreSteps\"","\"hideSteps\"","\"unread\"","\"retry\"","\"tooLarge\"","\"stop\"","\"voice\"","\"hold\"","\"recording\"","\"review\"","\"notRecognized\"","\"micDenied\"","\"unsupported\"","\"start\"","\"done\"","\"recognizing\"","\"recordingNow\"","\"failed\"","\"confirm\"","\"text\"","\"approve\"","\"reject\"","\"wait\"","\"starting\"","\"queued\"","\"palette\"","\"commands\"","\"skills\"","\"noSkills\"","\"empty\"","\"unknownCommand\"","\"sendAsText\"","\"skillPlaceholder\"","\"context\"","\"meter\"","\"full\"","\"compact\"","\"reset\"","\"event\"","\"details\""],"sources":["../src/locales/en.json","../src/locales/ru.json","../src/locales/de.json","../src/locales/es.json","../src/locales/zh.json","../src/locales/index.ts"],"sourcesContent":["{\n \"loading\": \"Loading…\",\n \"cancel\": \"Cancel\",\n \"create\": \"Create\",\n \"close\": \"Close\",\n \"delete\": \"Delete\",\n \"remove\": \"Remove\",\n \"agentName\": \"Agent name\",\n \"topbar\": {\n \"sections\": \"Sections\",\n \"profile\": \"Profile\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Conversations\",\n \"conversation\": \"Conversation\",\n \"topics\": \"Topics\",\n \"archive\": \"Archive\",\n \"noTopics\": \"No topics yet\",\n \"newTopic\": \"New topic\",\n \"topicTitle\": \"Topic\",\n \"topicHint\": \"A topic has its own history and the same memory and space.\",\n \"loadOlder\": \"Earlier messages\",\n \"emptyTitle\": \"Hi, I am {name}\",\n \"placeholder\": \"Message {name}…\",\n \"send\": \"Send\",\n \"attach\": \"Attach files\",\n \"typing\": \"The agent is typing\",\n \"moreSteps\": \"{count, plural, one {# more step} other {# more steps}}\",\n \"hideSteps\": \"Hide steps\",\n \"unread\": \"{count, plural, one {# unread answer} other {# unread answers}}\",\n \"retry\": \"Retry\",\n \"tooLarge\": \"The file is too large.\",\n \"stop\": \"Stop\",\n \"voice\": {\n \"hold\": \"Hold to record\",\n \"stop\": \"Stop recording\",\n \"recording\": \"Recording… {seconds} s\",\n \"review\": \"Check the transcript before sending\",\n \"notRecognized\": \"The speech was not recognized\",\n \"micDenied\": \"No access to the microphone\",\n \"unsupported\": \"Voice input is not supported in this browser\",\n \"start\": \"Record a voice message\",\n \"done\": \"Stop\",\n \"recognizing\": \"Recognizing…\",\n \"recordingNow\": \"Recording\",\n \"failed\": \"The voice message could not be recognized\",\n \"retry\": \"Retry\"\n },\n \"confirm\": {\n \"title\": \"Confirm the action\",\n \"text\": \"The agent wants to perform: {action}\",\n \"approve\": \"Execute\",\n \"reject\": \"Reject\"\n },\n \"wait\": {\n \"starting\": \"The agent is starting…\",\n \"queued\": \"{count, plural, =0 {In the queue · you are next} one {In the queue · # ahead of you} other {In the queue · # ahead of you}}\"\n },\n \"palette\": {\n \"title\": \"Commands and skills\",\n \"commands\": \"Commands\",\n \"skills\": \"Skills\",\n \"noSkills\": \"No skills are granted to you\",\n \"empty\": \"Nothing found\"\n },\n \"unknownCommand\": \"Unknown command {name}\",\n \"sendAsText\": \"Send as text\",\n \"skillPlaceholder\": \"What to do with the skill?\",\n \"context\": {\n \"meter\": \"Context: {used} of {total} tokens ({pct}%)\",\n \"full\": \"Answers get more expensive and the agent may get confused.\",\n \"compact\": \"Compact\",\n \"reset\": \"Start over\"\n },\n \"event\": {\n \"details\": \"Summary\"\n }\n }\n}\n","{\n \"loading\": \"Загрузка…\",\n \"cancel\": \"Отмена\",\n \"create\": \"Создать\",\n \"close\": \"Закрыть\",\n \"delete\": \"Удалить\",\n \"remove\": \"Убрать\",\n \"agentName\": \"Имя агента\",\n \"topbar\": {\n \"sections\": \"Разделы\",\n \"profile\": \"Профиль\"\n },\n \"chat\": {\n \"title\": \"Чат\",\n \"conversations\": \"Разговоры\",\n \"conversation\": \"Разговор\",\n \"topics\": \"Темы\",\n \"archive\": \"Архив\",\n \"noTopics\": \"Тем пока нет\",\n \"newTopic\": \"Новая тема\",\n \"topicTitle\": \"Тема\",\n \"topicHint\": \"У темы своя история, а память и пространство — те же.\",\n \"loadOlder\": \"Более ранние сообщения\",\n \"emptyTitle\": \"Привет, я {name}\",\n \"placeholder\": \"Сообщение для {name}…\",\n \"send\": \"Отправить\",\n \"attach\": \"Прикрепить файлы\",\n \"typing\": \"Агент печатает\",\n \"moreSteps\": \"{count, plural, one {ещё # шаг} few {ещё # шага} many {ещё # шагов} other {ещё # шага}}\",\n \"hideSteps\": \"Скрыть шаги\",\n \"unread\": \"{count, plural, one {# непрочитанный ответ} few {# непрочитанных ответа} many {# непрочитанных ответов} other {# непрочитанных ответа}}\",\n \"retry\": \"Повторить\",\n \"tooLarge\": \"Файл слишком большой.\",\n \"stop\": \"Остановить\",\n \"voice\": {\n \"hold\": \"Удерживайте для записи\",\n \"stop\": \"Остановить запись\",\n \"recording\": \"Запись… {seconds} с\",\n \"review\": \"Проверьте расшифровку перед отправкой\",\n \"notRecognized\": \"Речь не распознана\",\n \"micDenied\": \"Нет доступа к микрофону\",\n \"unsupported\": \"Голосовой ввод не поддерживается этим браузером\",\n \"start\": \"Записать голосом\",\n \"done\": \"Стоп\",\n \"recognizing\": \"Распознаём…\",\n \"recordingNow\": \"Запись\",\n \"failed\": \"Не удалось распознать голосовое сообщение\",\n \"retry\": \"Повторить\"\n },\n \"confirm\": {\n \"title\": \"Подтвердите действие\",\n \"text\": \"Агент хочет выполнить: {action}\",\n \"approve\": \"Выполнить\",\n \"reject\": \"Отклонить\"\n },\n \"wait\": {\n \"starting\": \"Агент запускается…\",\n \"queued\": \"{count, plural, =0 {В очереди · вы следующий} other {В очереди · перед вами #}}\"\n },\n \"palette\": {\n \"title\": \"Команды и скиллы\",\n \"commands\": \"Команды\",\n \"skills\": \"Скиллы\",\n \"noSkills\": \"Вам не выдан ни один скилл\",\n \"empty\": \"Ничего не найдено\"\n },\n \"unknownCommand\": \"Неизвестная команда {name}\",\n \"sendAsText\": \"Отправить как текст\",\n \"skillPlaceholder\": \"Что сделать по скиллу?\",\n \"context\": {\n \"meter\": \"Контекст: {used} из {total} токенов ({pct} %)\",\n \"full\": \"Ответы дорожают, агент может путаться.\",\n \"compact\": \"Сжать\",\n \"reset\": \"Начать заново\"\n },\n \"event\": {\n \"details\": \"Изложение\"\n }\n }\n}\n","{\n \"loading\": \"Wird geladen…\",\n \"cancel\": \"Abbrechen\",\n \"create\": \"Erstellen\",\n \"close\": \"Schließen\",\n \"delete\": \"Löschen\",\n \"remove\": \"Entfernen\",\n \"agentName\": \"Name des Agenten\",\n \"topbar\": {\n \"sections\": \"Bereiche\",\n \"profile\": \"Profil\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Gespräche\",\n \"conversation\": \"Gespräch\",\n \"topics\": \"Themen\",\n \"archive\": \"Archiv\",\n \"noTopics\": \"Noch keine Themen\",\n \"newTopic\": \"Neues Thema\",\n \"topicTitle\": \"Thema\",\n \"topicHint\": \"Ein Thema hat einen eigenen Verlauf, aber dasselbe Gedächtnis und denselben Arbeitsbereich.\",\n \"loadOlder\": \"Frühere Nachrichten\",\n \"emptyTitle\": \"Hallo, ich bin {name}\",\n \"placeholder\": \"Nachricht an {name}…\",\n \"send\": \"Senden\",\n \"attach\": \"Dateien anhängen\",\n \"typing\": \"Der Agent schreibt\",\n \"moreSteps\": \"{count, plural, one {# weiterer Schritt} other {# weitere Schritte}}\",\n \"hideSteps\": \"Schritte ausblenden\",\n \"unread\": \"{count, plural, one {# ungelesene Antwort} other {# ungelesene Antworten}}\",\n \"retry\": \"Wiederholen\",\n \"tooLarge\": \"Die Datei ist zu groß.\",\n \"stop\": \"Stoppen\",\n \"voice\": {\n \"hold\": \"Zum Aufnehmen gedrückt halten\",\n \"stop\": \"Aufnahme beenden\",\n \"recording\": \"Aufnahme… {seconds} s\",\n \"review\": \"Prüfen Sie die Transkription vor dem Senden\",\n \"notRecognized\": \"Die Sprache wurde nicht erkannt\",\n \"micDenied\": \"Kein Zugriff auf das Mikrofon\",\n \"unsupported\": \"Spracheingabe wird von diesem Browser nicht unterstützt\",\n \"start\": \"Sprachnachricht aufnehmen\",\n \"done\": \"Stopp\",\n \"recognizing\": \"Wird erkannt…\",\n \"recordingNow\": \"Aufnahme\",\n \"failed\": \"Die Sprachnachricht konnte nicht erkannt werden\",\n \"retry\": \"Wiederholen\"\n },\n \"confirm\": {\n \"title\": \"Aktion bestätigen\",\n \"text\": \"Der Agent möchte ausführen: {action}\",\n \"approve\": \"Ausführen\",\n \"reject\": \"Ablehnen\"\n },\n \"wait\": {\n \"starting\": \"Der Agent startet…\",\n \"queued\": \"{count, plural, =0 {In der Warteschlange · Sie sind als Nächstes dran} other {In der Warteschlange · # vor Ihnen}}\"\n },\n \"palette\": {\n \"title\": \"Befehle und Skills\",\n \"commands\": \"Befehle\",\n \"skills\": \"Skills\",\n \"noSkills\": \"Ihnen ist kein Skill freigegeben\",\n \"empty\": \"Nichts gefunden\"\n },\n \"unknownCommand\": \"Unbekannter Befehl {name}\",\n \"sendAsText\": \"Als Text senden\",\n \"skillPlaceholder\": \"Was soll mit dem Skill getan werden?\",\n \"context\": {\n \"meter\": \"Kontext: {used} von {total} Tokens ({pct} %)\",\n \"full\": \"Antworten werden teurer, der Agent kann durcheinanderkommen.\",\n \"compact\": \"Komprimieren\",\n \"reset\": \"Neu beginnen\"\n },\n \"event\": {\n \"details\": \"Zusammenfassung\"\n }\n }\n}\n","{\n \"loading\": \"Cargando…\",\n \"cancel\": \"Cancelar\",\n \"create\": \"Crear\",\n \"close\": \"Cerrar\",\n \"delete\": \"Eliminar\",\n \"remove\": \"Quitar\",\n \"agentName\": \"Nombre del agente\",\n \"topbar\": {\n \"sections\": \"Secciones\",\n \"profile\": \"Perfil\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Conversaciones\",\n \"conversation\": \"Conversación\",\n \"topics\": \"Temas\",\n \"archive\": \"Archivo\",\n \"noTopics\": \"Aún no hay temas\",\n \"newTopic\": \"Nuevo tema\",\n \"topicTitle\": \"Tema\",\n \"topicHint\": \"Un tema tiene su propio historial y la misma memoria y espacio.\",\n \"loadOlder\": \"Mensajes anteriores\",\n \"emptyTitle\": \"Hola, soy {name}\",\n \"placeholder\": \"Mensaje para {name}…\",\n \"send\": \"Enviar\",\n \"attach\": \"Adjuntar archivos\",\n \"typing\": \"El agente está escribiendo\",\n \"moreSteps\": \"{count, plural, one {# paso más} other {# pasos más}}\",\n \"hideSteps\": \"Ocultar pasos\",\n \"unread\": \"{count, plural, one {# respuesta sin leer} other {# respuestas sin leer}}\",\n \"retry\": \"Reintentar\",\n \"tooLarge\": \"El archivo es demasiado grande.\",\n \"stop\": \"Detener\",\n \"voice\": {\n \"hold\": \"Mantenga pulsado para grabar\",\n \"stop\": \"Detener la grabación\",\n \"recording\": \"Grabando… {seconds} s\",\n \"review\": \"Revise la transcripción antes de enviar\",\n \"notRecognized\": \"No se reconoció la voz\",\n \"micDenied\": \"Sin acceso al micrófono\",\n \"unsupported\": \"Este navegador no admite la entrada de voz\",\n \"start\": \"Grabar un mensaje de voz\",\n \"done\": \"Detener\",\n \"recognizing\": \"Reconociendo…\",\n \"recordingNow\": \"Grabando\",\n \"failed\": \"No se pudo reconocer el mensaje de voz\",\n \"retry\": \"Reintentar\"\n },\n \"confirm\": {\n \"title\": \"Confirme la acción\",\n \"text\": \"El agente quiere ejecutar: {action}\",\n \"approve\": \"Ejecutar\",\n \"reject\": \"Rechazar\"\n },\n \"wait\": {\n \"starting\": \"El agente se está iniciando…\",\n \"queued\": \"{count, plural, =0 {En cola · usted es el siguiente} other {En cola · # por delante}}\"\n },\n \"palette\": {\n \"title\": \"Comandos y skills\",\n \"commands\": \"Comandos\",\n \"skills\": \"Skills\",\n \"noSkills\": \"No tiene skills disponibles\",\n \"empty\": \"No se encontró nada\"\n },\n \"unknownCommand\": \"Comando desconocido {name}\",\n \"sendAsText\": \"Enviar como texto\",\n \"skillPlaceholder\": \"¿Qué hacer con el skill?\",\n \"context\": {\n \"meter\": \"Contexto: {used} de {total} tokens ({pct} %)\",\n \"full\": \"Las respuestas se encarecen y el agente puede confundirse.\",\n \"compact\": \"Compactar\",\n \"reset\": \"Empezar de nuevo\"\n },\n \"event\": {\n \"details\": \"Resumen\"\n }\n }\n}\n","{\n \"loading\": \"加载中…\",\n \"cancel\": \"取消\",\n \"create\": \"创建\",\n \"close\": \"关闭\",\n \"delete\": \"删除\",\n \"remove\": \"移除\",\n \"agentName\": \"智能体名称\",\n \"topbar\": {\n \"sections\": \"栏目\",\n \"profile\": \"个人资料\"\n },\n \"chat\": {\n \"title\": \"聊天\",\n \"conversations\": \"对话\",\n \"conversation\": \"对话\",\n \"topics\": \"话题\",\n \"archive\": \"归档\",\n \"noTopics\": \"暂无话题\",\n \"newTopic\": \"新话题\",\n \"topicTitle\": \"话题\",\n \"topicHint\": \"话题有独立的历史记录,记忆和空间与主对话相同。\",\n \"loadOlder\": \"更早的消息\",\n \"emptyTitle\": \"你好,我是 {name}\",\n \"placeholder\": \"给 {name} 发消息…\",\n \"send\": \"发送\",\n \"attach\": \"附加文件\",\n \"typing\": \"智能体正在输入\",\n \"moreSteps\": \"{count, plural, other {另外 # 个步骤}}\",\n \"hideSteps\": \"隐藏步骤\",\n \"unread\": \"{count} 条未读回复\",\n \"retry\": \"重试\",\n \"tooLarge\": \"文件太大。\",\n \"stop\": \"停止\",\n \"voice\": {\n \"hold\": \"按住录音\",\n \"stop\": \"停止录音\",\n \"recording\": \"录音中… {seconds} 秒\",\n \"review\": \"发送前请检查转写文本\",\n \"notRecognized\": \"未能识别语音\",\n \"micDenied\": \"无法访问麦克风\",\n \"unsupported\": \"此浏览器不支持语音输入\",\n \"start\": \"录制语音\",\n \"done\": \"停止\",\n \"recognizing\": \"正在识别…\",\n \"recordingNow\": \"录音中\",\n \"failed\": \"无法识别语音消息\",\n \"retry\": \"重试\"\n },\n \"confirm\": {\n \"title\": \"确认操作\",\n \"text\": \"代理想要执行:{action}\",\n \"approve\": \"执行\",\n \"reject\": \"拒绝\"\n },\n \"wait\": {\n \"starting\": \"代理正在启动…\",\n \"queued\": \"{count, plural, =0 {排队中 · 您是下一位} other {排队中 · 前面还有 # 位}}\"\n },\n \"palette\": {\n \"title\": \"命令和技能\",\n \"commands\": \"命令\",\n \"skills\": \"技能\",\n \"noSkills\": \"您没有可用的技能\",\n \"empty\": \"未找到\"\n },\n \"unknownCommand\": \"未知命令 {name}\",\n \"sendAsText\": \"作为文本发送\",\n \"skillPlaceholder\": \"用这个技能做什么?\",\n \"context\": {\n \"meter\": \"上下文:{used} / {total} 个令牌({pct}%)\",\n \"full\": \"回答变得更贵,代理可能会混淆。\",\n \"compact\": \"压缩\",\n \"reset\": \"重新开始\"\n },\n \"event\": {\n \"details\": \"摘要\"\n }\n }\n}\n","import en from \"./en.json\";\nimport ru from \"./ru.json\";\nimport de from \"./de.json\";\nimport es from \"./es.json\";\nimport zh from \"./zh.json\";\n\n/** Strings of the components in the five languages of the products. A product adds\n * them to its i18next instance under the namespace `uikit`. */\nexport const resources = { en, ru, de, es, zh };\nexport type KitLanguage = keyof typeof resources;\nexport { UIKIT_NS } from \"../i18n\";\n"],"mappings":";;;AKQA,IAAaiC,IAAY;CAAE,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;AAAG"}
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.0",
2
+ "version": "1.2.0",
3
3
  "classes": [
4
4
  "a",
5
5
  "action",
package/dist/styles.css CHANGED
@@ -1308,7 +1308,8 @@ select.inp.inherit {
1308
1308
  the dividers of events, the bar of a recording, the models of the agent. */
1309
1309
  .composer-wrap{position:relative;border-top:1px solid var(--border)}
1310
1310
  .composer-wrap .composer{border-top:0}
1311
- .composer .field{flex:1;display:flex;align-items:flex-end;gap:6px;min-width:0}
1311
+ /* .field of the forms has a margin under it: in the composer the field stands on the line of the buttons */
1312
+ .composer .field{flex:1;display:flex;align-items:flex-end;gap:6px;min-width:0;margin-bottom:0}
1312
1313
  .composer .field textarea{min-width:0}
1313
1314
  .composer .field.with-skill{flex-wrap:wrap}
1314
1315
  .skill-chip{background:var(--violet-soft);color:var(--violet-text);border-color:transparent;align-self:center}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@green-on-grey/ui-kit",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "UI kit of the Nabu and Hammurapi products: styles, components, the chat and the sign-in screen",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {