@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.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +6 -147
- package/dist/index.js +28 -487
- package/dist/index.js.map +1 -1
- package/package.json +2 -5
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import MuiButton from '@mui/material/Button';
|
|
2
|
-
import
|
|
3
|
-
import { Loader2, ChevronDown, Check, Cpu, SlidersHorizontal, X, Globe, Zap,
|
|
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
|
|
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 {
|
|
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
|
-
|
|
605
|
-
|
|
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(
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
4677
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|