@smartspace/chat-ui 1.14.4-pr.453.668909 → 1.14.6-main.1a6776c

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import MuiButton from '@mui/material/Button';
2
- import IconButton2 from '@mui/material/IconButton';
3
- import { Loader2, ChevronDown, Check, Cpu, SlidersHorizontal, X, Globe, Zap, Square, Mic, Paperclip, Send, Minimize2, AlertTriangle, FileImage, FileVideo, FileAudio, FileArchive, FileCode, FileSpreadsheet, Presentation, FileText, ChevronUp, ExternalLink, Download, ShieldAlert, Copy } from 'lucide-react';
2
+ import IconButton from '@mui/material/IconButton';
3
+ import { Loader2, ChevronDown, Check, Cpu, SlidersHorizontal, X, Globe, Zap, Paperclip, Mic, Square, Send, Minimize2, AlertTriangle, FileImage, FileVideo, FileAudio, FileArchive, FileCode, FileSpreadsheet, Presentation, FileText, ChevronUp, ExternalLink, Download, ShieldAlert, Copy } from 'lucide-react';
4
4
  import * as React9 from 'react';
5
5
  import React9__default, { createContext, forwardRef, useImperativeHandle, useRef, useState, useEffect, useMemo, useCallback, useContext, useSyncExternalStore } from 'react';
6
6
  import { createPortal } from 'react-dom';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
- import { useQuery, queryOptions, useQueryClient, useMutation, skipToken } from '@tanstack/react-query';
8
+ import { useQuery, queryOptions, useQueryClient, useMutation } from '@tanstack/react-query';
9
9
  import { toast } from 'sonner';
10
10
  import { ChatZod } from '@smartspace/api-client';
11
11
  import { z } from 'zod';
@@ -17,7 +17,7 @@ import { codeBlockSchema, commonmark } from '@milkdown/preset-commonmark';
17
17
  import { Slice, NodeType } from '@milkdown/prose/model';
18
18
  import { MilkdownProvider, useEditor, Milkdown } from '@milkdown/react';
19
19
  import { PluginKey, Plugin } from '@milkdown/prose/state';
20
- import { DecorationSet, Decoration } from '@milkdown/prose/view';
20
+ import { Decoration, DecorationSet } from '@milkdown/prose/view';
21
21
  import 'crypto';
22
22
  import '@milkdown/prose';
23
23
  import '@milkdown/prose/inputrules';
@@ -600,9 +600,14 @@ var useThread = ({
600
600
  };
601
601
  var useThreadIsRunning = (workspaceId, threadId) => {
602
602
  const queryClient = useQueryClient();
603
+ const service = useChatService();
603
604
  const { data: detailThread } = useQuery({
604
- queryKey: threadsKeys.detail(workspaceId ?? "", threadId ?? ""),
605
- queryFn: skipToken
605
+ ...threadDetailOptions({
606
+ service,
607
+ workspaceId: workspaceId ?? "",
608
+ threadId: threadId ?? ""
609
+ }),
610
+ enabled: false
606
611
  });
607
612
  const listThread = workspaceId && threadId ? getThreadPlaceholderFromListCache(queryClient, workspaceId, threadId) : void 0;
608
613
  const { data: optimistic } = useQuery({
@@ -837,37 +842,6 @@ function useMessages(threadId) {
837
842
  });
838
843
  }
839
844
 
840
- // src/domains/speech/queryKeys.ts
841
- var speechKeys = {
842
- all: ["speech"],
843
- config: () => [...speechKeys.all, "config"]
844
- };
845
-
846
- // src/domains/speech/queries.ts
847
- var unavailable = { enabled: false, defaultLocale: "en-US" };
848
- var isNotFound = (error) => error?.type === "NotFound" || error?.response?.status === 404;
849
- function useSpeechConfig() {
850
- const service = useChatService();
851
- const supported = !!service.getSpeechConfig && !!service.getSpeechToken;
852
- return useQuery({
853
- ...queryOptions({
854
- queryKey: speechKeys.config(),
855
- queryFn: async () => {
856
- try {
857
- return await service.getSpeechConfig?.() ?? unavailable;
858
- } catch (error) {
859
- if (isNotFound(error)) return unavailable;
860
- throw error;
861
- }
862
- },
863
- staleTime: Infinity,
864
- retry: (failureCount) => failureCount < 2,
865
- retryDelay: 1e3
866
- }),
867
- enabled: supported
868
- });
869
- }
870
-
871
845
  // ../../node_modules/.pnpm/@milkdown+exception@7.20.0/node_modules/@milkdown/exception/lib/index.js
872
846
  var ErrorCode = /* @__PURE__ */ (function(ErrorCode2) {
873
847
  ErrorCode2["docTypeError"] = "docTypeError";
@@ -1001,75 +975,6 @@ var autolink = $prose(() => {
1001
975
  }
1002
976
  });
1003
977
  });
1004
- var dictationGhostKey = new PluginKey("dictationGhost");
1005
- function buildDecorations2(state, text6) {
1006
- const doc = state.doc;
1007
- const from = state.selection.head;
1008
- const before = from > 0 ? doc.textBetween(from - 1, from, " ") : "";
1009
- const display = before !== "" && !/\s/.test(before) ? ` ${text6}` : text6;
1010
- const widget = Decoration.widget(
1011
- from,
1012
- () => {
1013
- const span = document.createElement("span");
1014
- span.className = "md-editor__dictation-ghost";
1015
- span.setAttribute("aria-hidden", "true");
1016
- span.appendChild(document.createTextNode(display));
1017
- const dots = document.createElement("span");
1018
- dots.className = "md-editor__dictation-dots";
1019
- for (let i = 0; i < 3; i += 1)
1020
- dots.appendChild(document.createElement("span"));
1021
- span.appendChild(dots);
1022
- return span;
1023
- },
1024
- {
1025
- // Render after the caret so typing still lands where the user expects.
1026
- side: 1,
1027
- // Keyed by content so ProseMirror reuses the node between renders instead
1028
- // of tearing it down on every interim result.
1029
- key: `dictation-ghost:${display}`
1030
- }
1031
- );
1032
- const decorations = [widget];
1033
- const $head = state.selection.$head;
1034
- if ($head.depth > 0) {
1035
- decorations.push(
1036
- Decoration.node($head.before(), $head.after(), {
1037
- class: "md-editor__has-dictation-ghost"
1038
- })
1039
- );
1040
- }
1041
- return DecorationSet.create(doc, decorations);
1042
- }
1043
- var dictationGhost = $prose(() => {
1044
- return new Plugin({
1045
- key: dictationGhostKey,
1046
- state: {
1047
- init: () => "",
1048
- apply(tr, previous2) {
1049
- const meta = tr.getMeta(dictationGhostKey);
1050
- if (meta) return meta.text;
1051
- if (tr.docChanged || tr.selectionSet) return "";
1052
- return previous2;
1053
- }
1054
- },
1055
- props: {
1056
- decorations(state) {
1057
- const text6 = dictationGhostKey.getState(state) ?? "";
1058
- if (!text6) return DecorationSet.empty;
1059
- return buildDecorations2(state, text6);
1060
- }
1061
- }
1062
- });
1063
- });
1064
- function setDictationGhost(view, text6) {
1065
- const current = dictationGhostKey.getState(view.state) ?? "";
1066
- if (current === text6) return;
1067
- const tr = view.state.tr.setMeta(dictationGhostKey, {
1068
- text: text6
1069
- });
1070
- tr.setMeta("addToHistory", false);
1071
- view.dispatch(tr);
1072
- }
1073
978
 
1074
979
  // src/shared/markdown/extensions/fileTag.ts
1075
980
  var fileTag = $node("fileTag", () => ({
@@ -1979,7 +1884,7 @@ function EditorInner({
1979
1884
  } catch {
1980
1885
  }
1981
1886
  });
1982
- }).use(commonmark).use(history).use(clipboard).use(listener).use(autolink).use(dictationGhost).use(fileTag).use(ssImageNode).use(ssImageView).use(htmlPreviewView).use(enableMentions ? mention : fileTag);
1887
+ }).use(commonmark).use(history).use(clipboard).use(listener).use(autolink).use(fileTag).use(ssImageNode).use(ssImageView).use(htmlPreviewView).use(enableMentions ? mention : fileTag);
1983
1888
  },
1984
1889
  [isEditable]
1985
1890
  );
@@ -2189,25 +2094,6 @@ function EditorInner({
2189
2094
  return value ?? "";
2190
2095
  }
2191
2096
  },
2192
- insertText: (text6) => {
2193
- const view = viewRef.current;
2194
- if (!view || !isEditable || !text6) return;
2195
- try {
2196
- const { from } = view.state.selection;
2197
- const before = from > 0 ? view.state.doc.textBetween(from - 1, from, " ") : "";
2198
- const needsSpace = before !== "" && !/\s/.test(before);
2199
- insertTextAtSelection(view, (needsSpace ? " " : "") + text6);
2200
- } catch {
2201
- }
2202
- },
2203
- setDictationGhost: (text6) => {
2204
- const view = viewRef.current;
2205
- if (!view || !isEditable) return;
2206
- try {
2207
- setDictationGhost(view, text6);
2208
- } catch {
2209
- }
2210
- },
2211
2097
  clear: () => {
2212
2098
  const view = viewRef.current;
2213
2099
  if (!view) return;
@@ -2551,239 +2437,6 @@ var MarkdownEditor = forwardRef((props, ref) => {
2551
2437
  return /* @__PURE__ */ jsx(MilkdownProvider, { children: /* @__PURE__ */ jsx(EditorInner, { ...props, editorHandleRef: ref }) });
2552
2438
  });
2553
2439
  MarkdownEditor.displayName = "MarkdownEditor";
2554
-
2555
- // src/shared/speech/speechTokenCredential.ts
2556
- var REFRESH_SKEW_MS = 2 * 6e4;
2557
- var ASSUMED_LIFETIME_MS = 10 * 6e4;
2558
- var toAccessToken = (t) => {
2559
- const parsed = Date.parse(t.expiresOn);
2560
- return {
2561
- token: t.token,
2562
- // Without this, an unparseable expiry makes every cache check fail and
2563
- // re-fetches a token on each SDK reconnect.
2564
- expiresOnTimestamp: Number.isNaN(parsed) ? Date.now() + ASSUMED_LIFETIME_MS : parsed
2565
- };
2566
- };
2567
- function createSpeechTokenCredential(fetchToken, seed) {
2568
- let cached = seed ? toAccessToken(seed) : null;
2569
- let inflight = null;
2570
- return {
2571
- getToken: async () => {
2572
- if (cached && cached.expiresOnTimestamp - Date.now() > REFRESH_SKEW_MS) {
2573
- return cached;
2574
- }
2575
- if (!inflight) {
2576
- inflight = fetchToken().then((t) => {
2577
- cached = toAccessToken(t);
2578
- return cached;
2579
- }).finally(() => {
2580
- inflight = null;
2581
- });
2582
- }
2583
- return inflight;
2584
- }
2585
- };
2586
- }
2587
-
2588
- // src/shared/speech/useDictation.ts
2589
- var isSupported = () => typeof window !== "undefined" && window.isSecureContext && !!navigator.mediaDevices?.getUserMedia;
2590
- function classifyTokenFailure(error) {
2591
- const code3 = error?.code;
2592
- if (code3 === "SP500") return "unavailable";
2593
- if (error?.type === "NotFound") {
2594
- return "unavailable";
2595
- }
2596
- return "unavailable-temporarily";
2597
- }
2598
- function useDictation({
2599
- endpoint,
2600
- locale,
2601
- getToken,
2602
- onPhrase,
2603
- onInterim,
2604
- maxDurationMs = 18e4,
2605
- idleTimeoutMs = 2e4
2606
- }) {
2607
- const [state, setState] = useState("idle");
2608
- const [error, setError] = useState(null);
2609
- const sessionRef = useRef(null);
2610
- const generationRef = useRef(0);
2611
- const onPhraseRef = useRef(onPhrase);
2612
- const onInterimRef = useRef(onInterim);
2613
- useEffect(() => {
2614
- onPhraseRef.current = onPhrase;
2615
- onInterimRef.current = onInterim;
2616
- });
2617
- const clearInterim = useCallback(() => onInterimRef.current?.(""), []);
2618
- const supported = isSupported();
2619
- const available = supported && !!endpoint && !!getToken;
2620
- const stop = useCallback(() => {
2621
- generationRef.current += 1;
2622
- const session = sessionRef.current;
2623
- sessionRef.current = null;
2624
- clearInterim();
2625
- setState("idle");
2626
- if (!session) return;
2627
- window.clearTimeout(session.timers.idle);
2628
- window.clearTimeout(session.timers.max);
2629
- session.stream.getTracks().forEach((t) => t.stop());
2630
- session.recognizer.stopContinuousRecognitionAsync(
2631
- () => session.recognizer.close(),
2632
- () => session.recognizer.close()
2633
- );
2634
- }, [clearInterim]);
2635
- const start = useCallback(async () => {
2636
- if (!available || sessionRef.current) return;
2637
- const generation = ++generationRef.current;
2638
- const superseded = () => generationRef.current !== generation;
2639
- setError(null);
2640
- setState("starting");
2641
- let stream;
2642
- try {
2643
- stream = await navigator.mediaDevices.getUserMedia({
2644
- audio: {
2645
- echoCancellation: true,
2646
- noiseSuppression: true,
2647
- autoGainControl: true
2648
- }
2649
- });
2650
- } catch (e) {
2651
- if (superseded()) return;
2652
- const name = e?.name;
2653
- setError(
2654
- name === "NotAllowedError" || name === "SecurityError" ? "permission-denied" : name === "NotFoundError" || name === "OverconstrainedError" ? "no-microphone" : "unknown"
2655
- );
2656
- setState("idle");
2657
- return;
2658
- }
2659
- if (superseded()) {
2660
- stream.getTracks().forEach((t) => t.stop());
2661
- return;
2662
- }
2663
- let token;
2664
- try {
2665
- token = await getToken();
2666
- } catch (e) {
2667
- stream.getTracks().forEach((t) => t.stop());
2668
- if (superseded()) return;
2669
- setError(classifyTokenFailure(e));
2670
- setState("idle");
2671
- return;
2672
- }
2673
- if (superseded()) {
2674
- stream.getTracks().forEach((t) => t.stop());
2675
- return;
2676
- }
2677
- let recognizer = null;
2678
- let published = null;
2679
- try {
2680
- const sdk = await import('microsoft-cognitiveservices-speech-sdk');
2681
- if (superseded()) {
2682
- stream.getTracks().forEach((t) => t.stop());
2683
- return;
2684
- }
2685
- const speechConfig = sdk.SpeechConfig.fromEndpoint(
2686
- new URL(endpoint),
2687
- createSpeechTokenCredential(
2688
- getToken,
2689
- token
2690
- )
2691
- );
2692
- speechConfig.speechRecognitionLanguage = locale;
2693
- speechConfig.setProfanity(sdk.ProfanityOption.Raw);
2694
- speechConfig.setProperty(
2695
- sdk.PropertyId.Speech_SegmentationSilenceTimeoutMs,
2696
- "700"
2697
- );
2698
- recognizer = new sdk.SpeechRecognizer(
2699
- speechConfig,
2700
- sdk.AudioConfig.fromStreamInput(stream)
2701
- );
2702
- const session = { recognizer, stream, timers: {} };
2703
- const armIdle = () => {
2704
- window.clearTimeout(session.timers.idle);
2705
- session.timers.idle = window.setTimeout(stop, idleTimeoutMs);
2706
- };
2707
- const isLive = () => sessionRef.current === session;
2708
- sessionRef.current = session;
2709
- published = session;
2710
- const goLive = () => {
2711
- if (!isLive()) return;
2712
- session.timers.max ??= window.setTimeout(stop, maxDurationMs);
2713
- armIdle();
2714
- setState("listening");
2715
- };
2716
- recognizer.sessionStarted = () => goLive();
2717
- recognizer.recognizing = (_sender, event) => {
2718
- if (!isLive()) return;
2719
- onInterimRef.current?.(event.result.text ?? "");
2720
- armIdle();
2721
- };
2722
- recognizer.recognized = (_sender, event) => {
2723
- if (!isLive()) return;
2724
- const text6 = event.result.text?.trim();
2725
- clearInterim();
2726
- if (event.result.reason === sdk.ResultReason.RecognizedSpeech && text6) {
2727
- onPhraseRef.current(text6);
2728
- }
2729
- armIdle();
2730
- };
2731
- recognizer.canceled = (_sender, event) => {
2732
- if (!isLive()) return;
2733
- if (event.reason === sdk.CancellationReason.Error) {
2734
- console.warn("[dictation] cancelled, errorCode:", event.errorCode);
2735
- setError(
2736
- event.errorCode === sdk.CancellationErrorCode.ConnectionFailure ? "network" : event.errorCode === sdk.CancellationErrorCode.AuthenticationFailure ? "unavailable-temporarily" : "unknown"
2737
- );
2738
- }
2739
- stop();
2740
- };
2741
- recognizer.sessionStopped = () => {
2742
- if (isLive()) stop();
2743
- };
2744
- try {
2745
- const connection = sdk.Connection.fromRecognizer(recognizer);
2746
- connection.connected = () => goLive();
2747
- connection.openConnection();
2748
- } catch {
2749
- }
2750
- await new Promise(
2751
- (resolve, reject) => session.recognizer.startContinuousRecognitionAsync(resolve, reject)
2752
- );
2753
- goLive();
2754
- } catch (e) {
2755
- stream.getTracks().forEach((t) => t.stop());
2756
- try {
2757
- recognizer?.close();
2758
- } catch {
2759
- }
2760
- if (published) {
2761
- window.clearTimeout(published.timers.idle);
2762
- window.clearTimeout(published.timers.max);
2763
- if (sessionRef.current === published) sessionRef.current = null;
2764
- }
2765
- if (superseded()) return;
2766
- console.warn("[dictation] failed to start:", e);
2767
- setError((prev) => prev ?? "unavailable-temporarily");
2768
- setState("idle");
2769
- }
2770
- }, [
2771
- available,
2772
- clearInterim,
2773
- endpoint,
2774
- getToken,
2775
- idleTimeoutMs,
2776
- locale,
2777
- maxDurationMs,
2778
- stop
2779
- ]);
2780
- useEffect(() => stop, [stop]);
2781
- const toggle = useCallback(() => {
2782
- if (state === "idle") void start();
2783
- else stop();
2784
- }, [start, state, stop]);
2785
- return { supported, available, state, error, start, stop, toggle };
2786
- }
2787
2440
  function useFlowRunVariables(flowRunId) {
2788
2441
  const service = useChatService();
2789
2442
  return useQuery({
@@ -4089,56 +3742,6 @@ var ChatVariablesForm = forwardRef(({ workspace, threadId, setVariables }, ref)
4089
3742
  ) }) })
4090
3743
  ] });
4091
3744
  });
4092
- var dictationErrorMessages = {
4093
- "permission-denied": "Microphone access is blocked \u2014 allow it in your browser settings and try again",
4094
- "no-microphone": "No microphone was found",
4095
- network: "Could not reach the speech service \u2014 try again",
4096
- "unavailable-temporarily": "Dictation is starting up \u2014 try again in a moment",
4097
- unavailable: "Dictation is not available on this workspace",
4098
- unknown: "Dictation stopped unexpectedly \u2014 try again"
4099
- };
4100
- function DictationButton({
4101
- state,
4102
- error,
4103
- disabled,
4104
- onToggle,
4105
- size = "sm"
4106
- }) {
4107
- const listening = state === "listening";
4108
- const starting = state === "starting";
4109
- const label = listening ? "Stop dictation" : "Dictate a message";
4110
- const dims = size === "sm" ? "h-8 w-8" : "h-9 w-9";
4111
- const icon = size === "sm" ? "h-4 w-4" : "h-5 w-5";
4112
- return /* @__PURE__ */ jsxs(
4113
- IconButton2,
4114
- {
4115
- type: "button",
4116
- onClick: onToggle,
4117
- disabled,
4118
- "aria-pressed": listening,
4119
- "aria-label": label,
4120
- title: error ? dictationErrorMessages[error] : label,
4121
- className: `relative ${dims} rounded-full transition-colors ${listening ? "bg-destructive text-destructive-foreground hover:bg-destructive/90" : "text-muted-foreground hover:bg-secondary"}`,
4122
- children: [
4123
- starting && /* @__PURE__ */ jsx(
4124
- "span",
4125
- {
4126
- "aria-hidden": "true",
4127
- className: "absolute inset-0 animate-spin rounded-full border-2 border-transparent border-t-current opacity-70"
4128
- }
4129
- ),
4130
- listening && /* @__PURE__ */ jsx(
4131
- "span",
4132
- {
4133
- "aria-hidden": "true",
4134
- className: "absolute inset-0 animate-ping rounded-full bg-destructive/30"
4135
- }
4136
- ),
4137
- listening ? /* @__PURE__ */ jsx(Square, { className: `relative ${icon} fill-current` }) : /* @__PURE__ */ jsx(Mic, { className: `relative ${icon}` })
4138
- ]
4139
- }
4140
- );
4141
- }
4142
3745
 
4143
3746
  // src/domains/workspaces/queryKeys.ts
4144
3747
  var workspaceKeys = {
@@ -4371,39 +3974,6 @@ function MessageComposer(_props = {}) {
4371
3974
  cancelReset();
4372
3975
  }
4373
3976
  }, [isSending, cancelAccepted, cancelErrored, cancelReset]);
4374
- const attachEditor = useCallback(
4375
- (handle2) => {
4376
- if (handle2) editorRef.current = handle2;
4377
- },
4378
- // Both flags matter: the portal mounts on `isMobile && isFullscreen`, and
4379
- // nothing resets isFullscreen when the breakpoint flips, so crossing it
4380
- // while fullscreen would unmount the portal editor without re-attaching the
4381
- // inline one — leaving a destroyed handle and silently swallowing phrases.
4382
- // eslint-disable-next-line react-hooks/exhaustive-deps
4383
- [isFullscreen, isMobile]
4384
- );
4385
- const { data: speechConfig } = useSpeechConfig();
4386
- const getSpeechToken = useMemo(
4387
- () => chatService.getSpeechToken?.bind(chatService),
4388
- [chatService]
4389
- );
4390
- const dictation = useDictation({
4391
- endpoint: speechConfig?.enabled ? speechConfig.endpoint : null,
4392
- locale: speechConfig?.defaultLocale ?? "en-US",
4393
- getToken: getSpeechToken,
4394
- // Final phrases become real text; provisional ones render as greyed ghost
4395
- // text at the caret and never enter the document.
4396
- onPhrase: (text6) => editorRef.current?.insertText(`${text6} `),
4397
- onInterim: (text6) => editorRef.current?.setDictationGhost(text6)
4398
- });
4399
- const { stop: stopDictation } = dictation;
4400
- const handleDictationToggle = () => {
4401
- if (dictation.state === "idle") editorRef.current?.focus();
4402
- dictation.toggle();
4403
- };
4404
- useEffect(() => {
4405
- if (disabled) stopDictation();
4406
- }, [disabled, stopDictation]);
4407
3977
  useEffect(() => {
4408
3978
  if (typeof window === "undefined") return;
4409
3979
  window.__ssDownloadFile = (id) => getFileBlobUrl(id);
@@ -4523,7 +4093,6 @@ function MessageComposer(_props = {}) {
4523
4093
  const latestText = editorRef.current?.getMarkdown() ?? newMessage;
4524
4094
  const sent = handleSendMessage(latestText, uploadedAttachments);
4525
4095
  if (!sent) return;
4526
- stopDictation();
4527
4096
  handleClearAttachments();
4528
4097
  setEditorKey((k) => k + 1);
4529
4098
  };
@@ -4630,7 +4199,7 @@ function MessageComposer(_props = {}) {
4630
4199
  /* @__PURE__ */ jsx("div", { className: "max-h-[400px] w-full overflow-y-auto", children: /* @__PURE__ */ jsx(
4631
4200
  MarkdownEditor,
4632
4201
  {
4633
- ref: attachEditor,
4202
+ ref: editorRef,
4634
4203
  value: newMessage,
4635
4204
  onChange: (md) => setNewMessage(md),
4636
4205
  onKeyDown: handleComposerKeyDown,
@@ -4647,12 +4216,10 @@ function MessageComposer(_props = {}) {
4647
4216
  },
4648
4217
  `composer-md-${editorKey}`
4649
4218
  ) }),
4650
- /* @__PURE__ */ jsx("div", { role: "status", className: "sr-only", children: dictation.state === "listening" ? "Listening" : dictation.state === "starting" ? "Starting dictation" : "" }),
4651
- dictation.error && /* @__PURE__ */ jsx("div", { role: "alert", className: "px-5 pb-1 text-xs text-destructive", children: dictationErrorMessages[dictation.error] }),
4652
4219
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-3 pb-3", children: [
4653
4220
  /* @__PURE__ */ jsxs("div", { className: "ss-composer__actions flex min-w-0 flex-1 items-center gap-1", children: [
4654
4221
  supportsFiles && /* @__PURE__ */ jsx(
4655
- IconButton2,
4222
+ IconButton,
4656
4223
  {
4657
4224
  type: "button",
4658
4225
  onClick: handlePickFilesClick,
@@ -4673,27 +4240,19 @@ function MessageComposer(_props = {}) {
4673
4240
  )
4674
4241
  ] }),
4675
4242
  /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [
4676
- dictation.available ? /* @__PURE__ */ jsx(
4677
- DictationButton,
4678
- {
4679
- state: dictation.state,
4680
- error: dictation.error,
4681
- disabled,
4682
- onToggle: handleDictationToggle
4683
- }
4684
- ) : /* @__PURE__ */ jsx(
4685
- IconButton2,
4243
+ /* @__PURE__ */ jsx(
4244
+ IconButton,
4686
4245
  {
4687
4246
  type: "button",
4688
4247
  disabled: true,
4689
4248
  "aria-label": "Dictate a message",
4690
- title: "Dictation is not available",
4249
+ title: "Dictation is not available yet",
4691
4250
  className: "h-8 w-8 cursor-not-allowed rounded-full text-muted-foreground",
4692
4251
  children: /* @__PURE__ */ jsx(Mic, { className: "h-4 w-4" })
4693
4252
  }
4694
4253
  ),
4695
4254
  canStop ? /* @__PURE__ */ jsx(
4696
- IconButton2,
4255
+ IconButton,
4697
4256
  {
4698
4257
  onClick: handleStopRun,
4699
4258
  className: "chat-send h-8 w-8 rounded-full",
@@ -4707,7 +4266,7 @@ function MessageComposer(_props = {}) {
4707
4266
  )
4708
4267
  }
4709
4268
  ) : /* @__PURE__ */ jsx(
4710
- IconButton2,
4269
+ IconButton,
4711
4270
  {
4712
4271
  onClick: handleSendMessageAndClear,
4713
4272
  className: `chat-send h-8 w-8 rounded-full ${sendDisabled ? "cursor-not-allowed" : ""}`,
@@ -4736,7 +4295,7 @@ function MessageComposer(_props = {}) {
4736
4295
  },
4737
4296
  children: /* @__PURE__ */ jsxs("div", { className: "relative h-full w-full bg-background border shadow-lg", children: [
4738
4297
  /* @__PURE__ */ jsx(
4739
- IconButton2,
4298
+ IconButton,
4740
4299
  {
4741
4300
  type: "button",
4742
4301
  size: "small",
@@ -4754,7 +4313,7 @@ function MessageComposer(_props = {}) {
4754
4313
  /* @__PURE__ */ jsx("div", { className: "flex-1 p-4", children: /* @__PURE__ */ jsx(
4755
4314
  MarkdownEditor,
4756
4315
  {
4757
- ref: attachEditor,
4316
+ ref: editorRef,
4758
4317
  value: newMessage,
4759
4318
  onChange: (md) => setNewMessage(md),
4760
4319
  onKeyDown: handleComposerKeyDown,
@@ -4769,18 +4328,10 @@ function MessageComposer(_props = {}) {
4769
4328
  },
4770
4329
  `composer-md-${editorKey}`
4771
4330
  ) }),
4772
- dictation.error && /* @__PURE__ */ jsx(
4773
- "div",
4774
- {
4775
- "aria-hidden": "true",
4776
- className: "px-4 pb-1 text-xs text-destructive",
4777
- children: dictationErrorMessages[dictation.error]
4778
- }
4779
- ),
4780
4331
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-t bg-background", children: [
4781
4332
  /* @__PURE__ */ jsx("div", { className: "flex-1" }),
4782
4333
  supportsFiles && /* @__PURE__ */ jsx(
4783
- IconButton2,
4334
+ IconButton,
4784
4335
  {
4785
4336
  type: "button",
4786
4337
  onClick: handlePickFilesClick,
@@ -4795,18 +4346,8 @@ function MessageComposer(_props = {}) {
4795
4346
  )
4796
4347
  }
4797
4348
  ),
4798
- dictation.available && /* @__PURE__ */ jsx(
4799
- DictationButton,
4800
- {
4801
- size: "md",
4802
- state: dictation.state,
4803
- error: dictation.error,
4804
- disabled,
4805
- onToggle: handleDictationToggle
4806
- }
4807
- ),
4808
4349
  canStop ? /* @__PURE__ */ jsx(
4809
- IconButton2,
4350
+ IconButton,
4810
4351
  {
4811
4352
  onClick: handleStopRun,
4812
4353
  className: "chat-send h-9 w-9 rounded-full",
@@ -4820,7 +4361,7 @@ function MessageComposer(_props = {}) {
4820
4361
  )
4821
4362
  }
4822
4363
  ) : /* @__PURE__ */ jsx(
4823
- IconButton2,
4364
+ IconButton,
4824
4365
  {
4825
4366
  onClick: handleSendMessageAndClear,
4826
4367
  className: `chat-send h-9 w-9 rounded-full ${sendDisabled ? "cursor-not-allowed" : ""}`,
@@ -20509,14 +20050,14 @@ var MessageItem = ({
20509
20050
  const { data: workspace } = useWorkspace(workspaceId);
20510
20051
  const chatbotName = getChatbotName(workspace?.name);
20511
20052
  const { addInputToMessageMutation } = useAddInputToMessage();
20512
- const onSubmitUserForm = (messageId) => (name, value) => {
20053
+ const onSubmitUserForm = (messageId, channels = {}) => (name, value) => {
20513
20054
  if (!threadId || !messageId) return;
20514
20055
  addInputToMessageMutation.mutate({
20515
20056
  threadId,
20516
20057
  messageId,
20517
20058
  name,
20518
20059
  value,
20519
- channels: {}
20060
+ channels
20520
20061
  });
20521
20062
  };
20522
20063
  const safeTime = (d) => {
@@ -20647,7 +20188,7 @@ var MessageItem = ({
20647
20188
  userOutput: v.value && typeof v.value === "object" ? v.value : null,
20648
20189
  chatbotName,
20649
20190
  userInput: userInput?.value,
20650
- onSubmitUserForm: onSubmitUserForm(message.id ?? "")
20191
+ onSubmitUserForm: onSubmitUserForm(message.id ?? "", v.channels)
20651
20192
  },
20652
20193
  `user-${message.id ?? "msg"}-${keyCounter++}`
20653
20194
  )
@@ -21155,6 +20696,6 @@ function getUserPhotoUrl(userId) {
21155
20696
  return `${base2}/users/${userId}/photo`;
21156
20697
  }
21157
20698
 
21158
- export { ChatProvider, ChatVariablesForm, DRAFT_THREAD_PREFIX, DateFromApi, DictationButton, MarkdownEditor, MessageComposer, MessageList, MessageListSkeleton, MessageMarkdown, MessageValueType, NEW_THREAD_ID, THREAD_LIST_PAGE_SIZE, applyDeltaToMessage, applyThreadToCache, createDraftThreadId, createSpeechTokenCredential, createThreadId, downloadFileBlobOptions, filesKeys, flowRunsKeys, getMessageErrorText, getModelIcon, getRetryStatusText, getThreadPlaceholderFromListCache, getUserPhotoUrl, invalidateWorkspaceThreadLists, isDraftThreadId, mapFileInfoDtoToModel, mapMentionUserDtoToModel, mapMessageDtoToModel, mapMessageErrorDtoToModel, mapMessageValueDtoToModel, mapMessagesDtoToModels, mapSignalRThreadSummaryToModel, mapThreadDtoToModel, mapThreadsResponseDtoToModel, mapWorkspaceDtoToModel, mapWorkspacesDtoToModels, markDraftThreadId, messagesKeys, messagesListOptions, messagesMutationsKeys, modelsKeys, parseDateTime, parseDateTimeHuman, parseRetryStatus, randomUUID, setThreadOptimisticRunning, setThreadRunningInLists, speechKeys, taggableUsersOptions, threadDetailOptions, threadsKeys, unmarkDraftThreadId, useAddInputToMessage, useChatContext, useChatIdentity, useChatService, useDictation, useDownloadFileBlobQuery, useFileMutations, useFlowRunVariables, useIsDraftThreadId, useMessages, useModels, useSendMessage, useSpeechConfig, useTaggableWorkspaceUsers, useThread, useThreadIsRunning, useUpdateFlowRunVariable, useWorkspace, utcDate, workspaceDetailOptions, workspaceKeys };
20699
+ export { ChatProvider, ChatVariablesForm, DRAFT_THREAD_PREFIX, DateFromApi, MarkdownEditor, MessageComposer, MessageList, MessageListSkeleton, MessageMarkdown, MessageValueType, NEW_THREAD_ID, THREAD_LIST_PAGE_SIZE, applyDeltaToMessage, applyThreadToCache, createDraftThreadId, createThreadId, downloadFileBlobOptions, filesKeys, flowRunsKeys, getMessageErrorText, getModelIcon, getRetryStatusText, getThreadPlaceholderFromListCache, getUserPhotoUrl, invalidateWorkspaceThreadLists, isDraftThreadId, mapFileInfoDtoToModel, mapMentionUserDtoToModel, mapMessageDtoToModel, mapMessageErrorDtoToModel, mapMessageValueDtoToModel, mapMessagesDtoToModels, mapSignalRThreadSummaryToModel, mapThreadDtoToModel, mapThreadsResponseDtoToModel, mapWorkspaceDtoToModel, mapWorkspacesDtoToModels, markDraftThreadId, messagesKeys, messagesListOptions, messagesMutationsKeys, modelsKeys, parseDateTime, parseDateTimeHuman, parseRetryStatus, randomUUID, setThreadOptimisticRunning, setThreadRunningInLists, taggableUsersOptions, threadDetailOptions, threadsKeys, unmarkDraftThreadId, useAddInputToMessage, useChatContext, useChatIdentity, useChatService, useDownloadFileBlobQuery, useFileMutations, useFlowRunVariables, useIsDraftThreadId, useMessages, useModels, useSendMessage, useTaggableWorkspaceUsers, useThread, useThreadIsRunning, useUpdateFlowRunVariable, useWorkspace, utcDate, workspaceDetailOptions, workspaceKeys };
21159
20700
  //# sourceMappingURL=index.js.map
21160
20701
  //# sourceMappingURL=index.js.map