@eshal-bot/chat-widget 0.1.42 → 0.1.44
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/chat-widget.esm.js +5 -5
- package/dist/chat-widget.js +215 -9
- package/dist/chat-widget.min.js +5 -5
- package/dist/chat-widget.umd.js +5 -5
- package/package.json +1 -1
package/dist/chat-widget.js
CHANGED
|
@@ -8537,6 +8537,144 @@
|
|
|
8537
8537
|
return pcm16Array.buffer;
|
|
8538
8538
|
}
|
|
8539
8539
|
|
|
8540
|
+
/**
|
|
8541
|
+
* Client-side Voice-Activity gate for the widget's voice (Bidi) session.
|
|
8542
|
+
*
|
|
8543
|
+
* Ported from packages/agent-sdk/src/voice/audio/vad.ts (`createSpeechGate`),
|
|
8544
|
+
* which was itself originally derived from this widget. The gate sits between
|
|
8545
|
+
* the mic worklet and the WebSocket: it forwards PCM ONLY inside a confirmed
|
|
8546
|
+
* speech turn and fires `onSpeechEnd` when the turn closes, so the caller can
|
|
8547
|
+
* tell the backend the utterance is done (an `audio_end` signal).
|
|
8548
|
+
*
|
|
8549
|
+
* Why the widget needs this: knowledge-api's non-streaming voice path only
|
|
8550
|
+
* transcribes a turn when it receives `audio_end` (or its flaky energy-VAD
|
|
8551
|
+
* backstop trips). Without a client gate the widget streamed mic audio forever
|
|
8552
|
+
* and the backend just buffered it ("Collecting Audio…") without ever
|
|
8553
|
+
* transcribing — so voice connected but never replied. The agent-sdk already
|
|
8554
|
+
* gates this way; this brings the widget to parity.
|
|
8555
|
+
*
|
|
8556
|
+
* Framework-free and side-effect-free (only calls the two callbacks) so it can
|
|
8557
|
+
* be reasoned about / tested in isolation.
|
|
8558
|
+
*/
|
|
8559
|
+
|
|
8560
|
+
const DEFAULT_SPEECH_GATE_CONFIG = {
|
|
8561
|
+
// RMS energy (0..1) at/above which a frame counts as voiced. Speech is
|
|
8562
|
+
// typically 0.05–0.3; quiet room tone sits well under 0.02.
|
|
8563
|
+
energyThreshold: 0.025,
|
|
8564
|
+
// Continuous voiced audio (ms) required to OPEN a turn — rejects coughs/clicks.
|
|
8565
|
+
speechStartMs: 200,
|
|
8566
|
+
// Continuous silence (ms) after speech that CLOSES the turn. Long enough to
|
|
8567
|
+
// ride over natural mid-sentence pauses, short enough to feel responsive.
|
|
8568
|
+
hangoverMs: 1000,
|
|
8569
|
+
// How much audio (ms) preceding turn-open to retain + flush so the leading
|
|
8570
|
+
// phoneme of the first word survives the start-detection delay.
|
|
8571
|
+
preRollMs: 300
|
|
8572
|
+
};
|
|
8573
|
+
|
|
8574
|
+
/** RMS amplitude of an Int16 PCM frame (ArrayBuffer), normalised to 0..1. */
|
|
8575
|
+
function computeRms(pcm) {
|
|
8576
|
+
const samples = new Int16Array(pcm);
|
|
8577
|
+
if (samples.length === 0) return 0;
|
|
8578
|
+
let sumSquares = 0;
|
|
8579
|
+
for (let i = 0; i < samples.length; i += 1) {
|
|
8580
|
+
const v = samples[i] / 0x8000; // normalise Int16 → -1..1
|
|
8581
|
+
sumSquares += v * v;
|
|
8582
|
+
}
|
|
8583
|
+
return Math.sqrt(sumSquares / samples.length);
|
|
8584
|
+
}
|
|
8585
|
+
|
|
8586
|
+
/**
|
|
8587
|
+
* Create a stateful speech gate. Returns `{ process, reset, isSpeaking }`.
|
|
8588
|
+
* `config.sampleRate` is required; everything else falls back to
|
|
8589
|
+
* DEFAULT_SPEECH_GATE_CONFIG.
|
|
8590
|
+
*
|
|
8591
|
+
* @param {{ sampleRate: number, energyThreshold?: number, speechStartMs?: number, hangoverMs?: number, preRollMs?: number }} config
|
|
8592
|
+
* @param {{ onVoiceFrame: (pcm: ArrayBuffer) => void, onSpeechEnd: () => void }} callbacks
|
|
8593
|
+
*/
|
|
8594
|
+
function createSpeechGate(config, callbacks) {
|
|
8595
|
+
var _config$energyThresho, _config$speechStartMs, _config$hangoverMs, _config$preRollMs;
|
|
8596
|
+
const cfg = {
|
|
8597
|
+
sampleRate: config.sampleRate,
|
|
8598
|
+
energyThreshold: (_config$energyThresho = config.energyThreshold) !== null && _config$energyThresho !== void 0 ? _config$energyThresho : DEFAULT_SPEECH_GATE_CONFIG.energyThreshold,
|
|
8599
|
+
speechStartMs: (_config$speechStartMs = config.speechStartMs) !== null && _config$speechStartMs !== void 0 ? _config$speechStartMs : DEFAULT_SPEECH_GATE_CONFIG.speechStartMs,
|
|
8600
|
+
hangoverMs: (_config$hangoverMs = config.hangoverMs) !== null && _config$hangoverMs !== void 0 ? _config$hangoverMs : DEFAULT_SPEECH_GATE_CONFIG.hangoverMs,
|
|
8601
|
+
preRollMs: (_config$preRollMs = config.preRollMs) !== null && _config$preRollMs !== void 0 ? _config$preRollMs : DEFAULT_SPEECH_GATE_CONFIG.preRollMs
|
|
8602
|
+
};
|
|
8603
|
+
let speaking = false;
|
|
8604
|
+
// While idle: how much consecutive voiced audio we've seen (to open).
|
|
8605
|
+
let voicedRunMs = 0;
|
|
8606
|
+
// While speaking: how much consecutive silence we've seen (to close).
|
|
8607
|
+
let silenceRunMs = 0;
|
|
8608
|
+
// Ring of recent frames kept only while idle, for pre-roll on open.
|
|
8609
|
+
let preRoll = [];
|
|
8610
|
+
let preRollMsBuffered = 0;
|
|
8611
|
+
|
|
8612
|
+
// Int16 → 2 bytes/sample; ms = samples / sampleRate * 1000.
|
|
8613
|
+
const frameDurationMs = pcm => pcm.byteLength / 2 / cfg.sampleRate * 1000;
|
|
8614
|
+
const reset = () => {
|
|
8615
|
+
speaking = false;
|
|
8616
|
+
voicedRunMs = 0;
|
|
8617
|
+
silenceRunMs = 0;
|
|
8618
|
+
preRoll = [];
|
|
8619
|
+
preRollMsBuffered = 0;
|
|
8620
|
+
};
|
|
8621
|
+
const process = pcm => {
|
|
8622
|
+
const durationMs = frameDurationMs(pcm);
|
|
8623
|
+
const voiced = computeRms(pcm) >= cfg.energyThreshold;
|
|
8624
|
+
if (!speaking) {
|
|
8625
|
+
// Keep a bounded pre-roll of the most recent audio so we don't clip the
|
|
8626
|
+
// onset once we decide this is speech.
|
|
8627
|
+
preRoll.push({
|
|
8628
|
+
pcm,
|
|
8629
|
+
durationMs
|
|
8630
|
+
});
|
|
8631
|
+
preRollMsBuffered += durationMs;
|
|
8632
|
+
while (preRollMsBuffered > cfg.preRollMs && preRoll.length > 1) {
|
|
8633
|
+
var _dropped$durationMs;
|
|
8634
|
+
const dropped = preRoll.shift();
|
|
8635
|
+
preRollMsBuffered -= (_dropped$durationMs = dropped === null || dropped === void 0 ? void 0 : dropped.durationMs) !== null && _dropped$durationMs !== void 0 ? _dropped$durationMs : 0;
|
|
8636
|
+
}
|
|
8637
|
+
if (voiced) {
|
|
8638
|
+
voicedRunMs += durationMs;
|
|
8639
|
+
if (voicedRunMs >= cfg.speechStartMs) {
|
|
8640
|
+
// Confirmed speech — open the turn and flush the pre-roll (which
|
|
8641
|
+
// contains the voiced onset) before going live.
|
|
8642
|
+
speaking = true;
|
|
8643
|
+
silenceRunMs = 0;
|
|
8644
|
+
for (const frame of preRoll) callbacks.onVoiceFrame(frame.pcm);
|
|
8645
|
+
preRoll = [];
|
|
8646
|
+
preRollMsBuffered = 0;
|
|
8647
|
+
}
|
|
8648
|
+
} else {
|
|
8649
|
+
// Need *sustained* energy — reset on any silent frame so a brief
|
|
8650
|
+
// transient can't accumulate its way over the threshold.
|
|
8651
|
+
voicedRunMs = 0;
|
|
8652
|
+
}
|
|
8653
|
+
return;
|
|
8654
|
+
}
|
|
8655
|
+
|
|
8656
|
+
// Inside a confirmed turn: forward everything, including short internal
|
|
8657
|
+
// pauses, until the hangover elapses.
|
|
8658
|
+
callbacks.onVoiceFrame(pcm);
|
|
8659
|
+
if (voiced) {
|
|
8660
|
+
silenceRunMs = 0;
|
|
8661
|
+
} else {
|
|
8662
|
+
silenceRunMs += durationMs;
|
|
8663
|
+
if (silenceRunMs >= cfg.hangoverMs) {
|
|
8664
|
+
speaking = false;
|
|
8665
|
+
voicedRunMs = 0;
|
|
8666
|
+
silenceRunMs = 0;
|
|
8667
|
+
callbacks.onSpeechEnd();
|
|
8668
|
+
}
|
|
8669
|
+
}
|
|
8670
|
+
};
|
|
8671
|
+
return {
|
|
8672
|
+
process,
|
|
8673
|
+
reset,
|
|
8674
|
+
isSpeaking: () => speaking
|
|
8675
|
+
};
|
|
8676
|
+
}
|
|
8677
|
+
|
|
8540
8678
|
/**
|
|
8541
8679
|
* Clean CJK (Chinese, Japanese, Korean) spaces
|
|
8542
8680
|
*/
|
|
@@ -8935,6 +9073,11 @@
|
|
|
8935
9073
|
openDelay,
|
|
8936
9074
|
darkMode,
|
|
8937
9075
|
enableVoiceInteraction = false,
|
|
9076
|
+
// behavior.provideCitations — forwarded as enable_citation on the chat
|
|
9077
|
+
// request so the backend skips citation generation when disabled. The
|
|
9078
|
+
// Sources render is also gated in MessageBubble (defence-in-depth, same
|
|
9079
|
+
// as the dashboard testing lab). Defaults to true.
|
|
9080
|
+
provideCitations = true,
|
|
8938
9081
|
onboardingQuestions = [],
|
|
8939
9082
|
onboardingEnabled = false,
|
|
8940
9083
|
collectionPrompt,
|
|
@@ -9054,6 +9197,11 @@
|
|
|
9054
9197
|
const audioRecorderNodeRef = reactExports.useRef(null);
|
|
9055
9198
|
const audioRecorderContextRef = reactExports.useRef(null);
|
|
9056
9199
|
const micStreamRef = reactExports.useRef(null);
|
|
9200
|
+
// Client-side VAD gate. Forwards only voiced PCM upstream and fires
|
|
9201
|
+
// `audio_end` on end-of-speech so the backend's non-streaming voice path
|
|
9202
|
+
// transcribes the turn (mirrors the agent-sdk). Without it the backend
|
|
9203
|
+
// buffers audio forever and never responds.
|
|
9204
|
+
const speechGateRef = reactExports.useRef(null);
|
|
9057
9205
|
const currentInputMessageIdRef = reactExports.useRef(null);
|
|
9058
9206
|
const currentAssistantMessageIdRef = reactExports.useRef(null);
|
|
9059
9207
|
const isAudioReadyRef = reactExports.useRef(false);
|
|
@@ -9458,6 +9606,11 @@
|
|
|
9458
9606
|
message: trimmed,
|
|
9459
9607
|
type: apiType,
|
|
9460
9608
|
conversationId: bidiSessionId,
|
|
9609
|
+
// Citation toggle (behavior.provideCitations). Mirrors the testing
|
|
9610
|
+
// lab's useChat.ts so knowledge-api skips citation generation when
|
|
9611
|
+
// the admin disabled them. The Sources panel is also gated client-
|
|
9612
|
+
// side in MessageBubble (defence-in-depth). Defaults to on.
|
|
9613
|
+
enable_citation: provideCitations !== null && provideCitations !== void 0 ? provideCitations : true,
|
|
9461
9614
|
// Identify this as a widget call so the knowledge-api side
|
|
9462
9615
|
// (chat_utils.EXTERNAL_CHAT_CHANNELS in services/
|
|
9463
9616
|
// knowledge-api) can enforce the visibility ACL — private
|
|
@@ -9562,7 +9715,7 @@
|
|
|
9562
9715
|
setIsLoading(false);
|
|
9563
9716
|
}
|
|
9564
9717
|
}
|
|
9565
|
-
}, [apiBaseUrl, apiKey, getNextMessageId, organizationId, messages, bidiSessionId, routingChoice, widgetFilter]);
|
|
9718
|
+
}, [apiBaseUrl, apiKey, getNextMessageId, organizationId, messages, bidiSessionId, routingChoice, widgetFilter, provideCitations]);
|
|
9566
9719
|
const handleOnboardingFormSubmit = reactExports.useCallback(async answers => {
|
|
9567
9720
|
const questions = getOnboardingQuestions(onboardingQuestions);
|
|
9568
9721
|
if (questions.length === 0) return;
|
|
@@ -10183,7 +10336,7 @@
|
|
|
10183
10336
|
}));
|
|
10184
10337
|
}, []);
|
|
10185
10338
|
const stopVoiceSession = reactExports.useCallback(() => {
|
|
10186
|
-
var _audioPlayerNodeRef$c, _audioPlayerContextRe, _audioRecorderNodeRef, _audioRecorderContext;
|
|
10339
|
+
var _audioPlayerNodeRef$c, _audioPlayerContextRe, _audioRecorderNodeRef, _audioRecorderContext, _speechGateRef$curren;
|
|
10187
10340
|
setIsVoiceSessionActive(false);
|
|
10188
10341
|
setIsLoading(false);
|
|
10189
10342
|
isVoiceSessionActiveRef.current = false;
|
|
@@ -10207,6 +10360,8 @@
|
|
|
10207
10360
|
audioRecorderContextRef.current = null;
|
|
10208
10361
|
stopMicrophone(micStreamRef.current);
|
|
10209
10362
|
micStreamRef.current = null;
|
|
10363
|
+
(_speechGateRef$curren = speechGateRef.current) === null || _speechGateRef$curren === void 0 || _speechGateRef$curren.reset();
|
|
10364
|
+
speechGateRef.current = null;
|
|
10210
10365
|
isAudioReadyRef.current = false;
|
|
10211
10366
|
}, []);
|
|
10212
10367
|
const handleBidiEvent = reactExports.useCallback(event => {
|
|
@@ -10386,11 +10541,22 @@
|
|
|
10386
10541
|
}
|
|
10387
10542
|
}, [appendAssistantContent, appendUserTranscription, handleContentParts, handleInterrupted, handleTurnComplete, stopVoiceSession]);
|
|
10388
10543
|
const handleRecorderAudio = reactExports.useCallback(pcmData => {
|
|
10389
|
-
|
|
10390
|
-
|
|
10544
|
+
if (!isVoiceSessionActiveRef.current) {
|
|
10545
|
+
return;
|
|
10546
|
+
}
|
|
10547
|
+
// Route mic frames through the VAD gate: it forwards only voiced frames
|
|
10548
|
+
// (onVoiceFrame → ws.send) and fires onSpeechEnd → audio_end so the
|
|
10549
|
+
// backend finalizes the turn. Fall back to raw streaming only if the
|
|
10550
|
+
// gate somehow wasn't built.
|
|
10551
|
+
const gate = speechGateRef.current;
|
|
10552
|
+
if (gate) {
|
|
10553
|
+
gate.process(pcmData);
|
|
10391
10554
|
return;
|
|
10392
10555
|
}
|
|
10393
|
-
ws.
|
|
10556
|
+
const ws = websocketRef.current;
|
|
10557
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
10558
|
+
ws.send(pcmData);
|
|
10559
|
+
}
|
|
10394
10560
|
}, []);
|
|
10395
10561
|
const initializeAudioPipeline = reactExports.useCallback(async () => {
|
|
10396
10562
|
if (isAudioReadyRef.current || typeof window === "undefined") {
|
|
@@ -10401,6 +10567,30 @@
|
|
|
10401
10567
|
audioPlayerNodeRef.current = playerNode;
|
|
10402
10568
|
audioPlayerContextRef.current = playerContext;
|
|
10403
10569
|
await playerContext.resume();
|
|
10570
|
+
|
|
10571
|
+
// Build the VAD gate before the recorder starts producing frames.
|
|
10572
|
+
// onVoiceFrame streams voiced PCM upstream; onSpeechEnd tells the backend
|
|
10573
|
+
// the utterance is complete so it transcribes + responds. The recorder
|
|
10574
|
+
// runs at 16 kHz (see audio-recorder.js).
|
|
10575
|
+
const sendVoicePcm = pcm => {
|
|
10576
|
+
const ws = websocketRef.current;
|
|
10577
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
10578
|
+
ws.send(pcm);
|
|
10579
|
+
}
|
|
10580
|
+
};
|
|
10581
|
+
speechGateRef.current = createSpeechGate({
|
|
10582
|
+
sampleRate: 16000
|
|
10583
|
+
}, {
|
|
10584
|
+
onVoiceFrame: sendVoicePcm,
|
|
10585
|
+
onSpeechEnd: () => {
|
|
10586
|
+
const ws = websocketRef.current;
|
|
10587
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
10588
|
+
ws.send(JSON.stringify({
|
|
10589
|
+
type: "audio_end"
|
|
10590
|
+
}));
|
|
10591
|
+
}
|
|
10592
|
+
}
|
|
10593
|
+
});
|
|
10404
10594
|
const [recorderNode, recorderContext, micStream] = await startAudioRecorderWorklet(handleRecorderAudio);
|
|
10405
10595
|
audioRecorderNodeRef.current = recorderNode;
|
|
10406
10596
|
audioRecorderContextRef.current = recorderContext;
|
|
@@ -54632,6 +54822,7 @@
|
|
|
54632
54822
|
organizationId,
|
|
54633
54823
|
onPromptSuggestionClick,
|
|
54634
54824
|
allowFeedback = true,
|
|
54825
|
+
provideCitations = true,
|
|
54635
54826
|
onFeedback,
|
|
54636
54827
|
headerTextColor
|
|
54637
54828
|
} = _ref17;
|
|
@@ -54740,7 +54931,7 @@
|
|
|
54740
54931
|
}), message.decisionResponse && /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
54741
54932
|
className: "mt-2 text-xs ".concat(isDark ? "text-gray-400" : "text-gray-500"),
|
|
54742
54933
|
children: ["Selected: ", message.decisionResponse.selectedOption]
|
|
54743
|
-
}), ((_message$sources = message.sources) === null || _message$sources === void 0 ? void 0 : _message$sources.length) > 0 && /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
|
|
54934
|
+
}), provideCitations !== false && ((_message$sources = message.sources) === null || _message$sources === void 0 ? void 0 : _message$sources.length) > 0 && /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
|
|
54744
54935
|
children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
54745
54936
|
className: "mt-3",
|
|
54746
54937
|
style: {
|
|
@@ -54765,7 +54956,7 @@
|
|
|
54765
54956
|
textColor: messageTextColor,
|
|
54766
54957
|
fontFamily: messageFontFamily,
|
|
54767
54958
|
fontSize: messageFontSize
|
|
54768
|
-
}), ((_message$sources2 = message.sources) === null || _message$sources2 === void 0 ? void 0 : _message$sources2.length) > 0 && /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
|
|
54959
|
+
}), provideCitations !== false && ((_message$sources2 = message.sources) === null || _message$sources2 === void 0 ? void 0 : _message$sources2.length) > 0 && /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
|
|
54769
54960
|
children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
54770
54961
|
className: "mt-3",
|
|
54771
54962
|
style: {
|
|
@@ -54908,6 +55099,7 @@
|
|
|
54908
55099
|
organizationId,
|
|
54909
55100
|
onPromptSuggestionClick,
|
|
54910
55101
|
allowFeedback,
|
|
55102
|
+
provideCitations,
|
|
54911
55103
|
onFeedback,
|
|
54912
55104
|
headerTextColor
|
|
54913
55105
|
} = _ref19;
|
|
@@ -54951,6 +55143,7 @@
|
|
|
54951
55143
|
organizationId: organizationId,
|
|
54952
55144
|
onPromptSuggestionClick: onPromptSuggestionClick,
|
|
54953
55145
|
allowFeedback: allowFeedback,
|
|
55146
|
+
provideCitations: provideCitations,
|
|
54954
55147
|
onFeedback: onFeedback,
|
|
54955
55148
|
headerTextColor: headerTextColor
|
|
54956
55149
|
});
|
|
@@ -55806,6 +55999,7 @@
|
|
|
55806
55999
|
onPromptSuggestionClick,
|
|
55807
56000
|
conversationResetKey,
|
|
55808
56001
|
allowFeedback,
|
|
56002
|
+
provideCitations,
|
|
55809
56003
|
onFeedback,
|
|
55810
56004
|
headerTextColor,
|
|
55811
56005
|
// Inline filter slots — rendered in the initial-state region
|
|
@@ -55961,6 +56155,7 @@
|
|
|
55961
56155
|
apiBaseUrl: apiBaseUrl,
|
|
55962
56156
|
organizationId: organizationId,
|
|
55963
56157
|
allowFeedback: allowFeedback,
|
|
56158
|
+
provideCitations: provideCitations,
|
|
55964
56159
|
onFeedback: onFeedback,
|
|
55965
56160
|
headerTextColor: headerTextColor
|
|
55966
56161
|
}, message.id)), (() => {
|
|
@@ -59582,6 +59777,7 @@
|
|
|
59582
59777
|
onResetConversation,
|
|
59583
59778
|
autoPromptEnabled = true,
|
|
59584
59779
|
allowFeedback = true,
|
|
59780
|
+
provideCitations = true,
|
|
59585
59781
|
onFeedback,
|
|
59586
59782
|
onRefreshChat,
|
|
59587
59783
|
onCopyChat,
|
|
@@ -60120,6 +60316,7 @@
|
|
|
60120
60316
|
organizationId: organizationId,
|
|
60121
60317
|
conversationResetKey: conversationId,
|
|
60122
60318
|
allowFeedback: allowFeedback,
|
|
60319
|
+
provideCitations: provideCitations,
|
|
60123
60320
|
onFeedback: onFeedback,
|
|
60124
60321
|
headerTextColor: headerTextColor,
|
|
60125
60322
|
beforePromptsSlot: showInlineFilter ? /*#__PURE__*/jsxRuntimeExports.jsx(CategoryFilterInline, {
|
|
@@ -60457,7 +60654,7 @@
|
|
|
60457
60654
|
|
|
60458
60655
|
// Map API response to widget props (use props as overrides if provided)
|
|
60459
60656
|
const widgetConfig = reactExports.useMemo(() => {
|
|
60460
|
-
var _agentConfig$config, _cfg$identity, _cfg$branding, _cfg$typography, _cfg$messages, _cfg$voice, _cfg$onboarding, _cfg$disclaimer, _cfg$csat, _cfg$inactivity, _cfg$behavior, _cfg$security, _cfg$layout, _ref2, _messages$bundles$loc, _messages$bundles, _messages$bundles$en, _messages$bundles2, _ref3, _ref4, _ref5, _ref6, _branding$chatbotAvat, _branding$chatbotAvat2, _ref7, _ref8, _ref9, _ref0, _ref1, _ref10, _ref11, _ref12, _ref13, _ref14, _ref15, _ref16, _ref17, _ref18, _inactivity$timeoutVa, _inactivity$timeoutUn, _ref19, _ref20, _ref21, _ref22, _ref23, _ref24, _ref25, _ref26, _csat$enabled, _csat$format, _csat$prompt, _csat$triggerType, _csat$idleTimeoutMins, _csat$followUpEnabled, _csat$followUpPrompt, _behavior$autoPromptE, _behavior$allowFeedba;
|
|
60657
|
+
var _agentConfig$config, _cfg$identity, _cfg$branding, _cfg$typography, _cfg$messages, _cfg$voice, _cfg$onboarding, _cfg$disclaimer, _cfg$csat, _cfg$inactivity, _cfg$behavior, _cfg$security, _cfg$layout, _ref2, _messages$bundles$loc, _messages$bundles, _messages$bundles$en, _messages$bundles2, _ref3, _ref4, _ref5, _ref6, _branding$chatbotAvat, _branding$chatbotAvat2, _ref7, _ref8, _ref9, _ref0, _ref1, _ref10, _ref11, _ref12, _ref13, _ref14, _ref15, _ref16, _ref17, _ref18, _inactivity$timeoutVa, _inactivity$timeoutUn, _ref19, _ref20, _ref21, _ref22, _ref23, _ref24, _ref25, _ref26, _csat$enabled, _csat$format, _csat$prompt, _csat$triggerType, _csat$idleTimeoutMins, _csat$followUpEnabled, _csat$followUpPrompt, _behavior$autoPromptE, _behavior$allowFeedba, _behavior$provideCita;
|
|
60461
60658
|
if (!agentConfig) {
|
|
60462
60659
|
return null;
|
|
60463
60660
|
}
|
|
@@ -60548,7 +60745,12 @@
|
|
|
60548
60745
|
csatFollowUpEnabled: (_csat$followUpEnabled = csat.followUpEnabled) !== null && _csat$followUpEnabled !== void 0 ? _csat$followUpEnabled : false,
|
|
60549
60746
|
csatFollowUpPrompt: (_csat$followUpPrompt = csat.followUpPrompt) !== null && _csat$followUpPrompt !== void 0 ? _csat$followUpPrompt : null,
|
|
60550
60747
|
autoPromptEnabled: (_behavior$autoPromptE = behavior.autoPromptEnabled) !== null && _behavior$autoPromptE !== void 0 ? _behavior$autoPromptE : true,
|
|
60551
|
-
allowFeedback: (_behavior$allowFeedba = behavior.allowFeedback) !== null && _behavior$allowFeedba !== void 0 ? _behavior$allowFeedba : true
|
|
60748
|
+
allowFeedback: (_behavior$allowFeedba = behavior.allowFeedback) !== null && _behavior$allowFeedba !== void 0 ? _behavior$allowFeedba : true,
|
|
60749
|
+
// behavior.provideCitations — when false, hide the Sources panel on
|
|
60750
|
+
// every message and tell the backend to skip citation generation.
|
|
60751
|
+
// Defaults to true so agents that haven't set the field keep showing
|
|
60752
|
+
// citations (matches the testing-lab / chatbot-preview default).
|
|
60753
|
+
provideCitations: (_behavior$provideCita = behavior.provideCitations) !== null && _behavior$provideCita !== void 0 ? _behavior$provideCita : true
|
|
60552
60754
|
};
|
|
60553
60755
|
}, [agentConfig, darkMode, primaryColor, position, companyName, conciergeName, companyLogo, welcomeMessage, quickQuestions, quickQuestionsEnabled, textColor, agentMessageBubbleColor, userMessageBoxColor, assistantTextColor, userTextColor, fontFamily, fontSize, defaultLanguage, orgId, headerTextBold, headerTextItalic, enableVoiceInteraction, disclaimerEnabled, disclaimerText, disclaimerPosition, disclaimerLinkLabel, disclaimerLinkUrl, showPoweredBy, onboardingQuestions, onboardingEnabled, collectionPrompt, allowedDomains, agentMessageBubbleFontFamily, agentMessageBubbleFontSize, userMessageBubbleFontFamily, userMessageBubbleFontSize
|
|
60554
60756
|
// CSAT dependencies
|
|
@@ -60632,6 +60834,9 @@
|
|
|
60632
60834
|
onboardingQuestions: widgetConfig.onboardingQuestions,
|
|
60633
60835
|
onboardingEnabled: widgetConfig.onboardingEnabled,
|
|
60634
60836
|
collectionPrompt: widgetConfig.collectionPrompt,
|
|
60837
|
+
// Gates the chat request's enable_citation flag (text path). Voice
|
|
60838
|
+
// already reads provideCitations from the DB in voice_chat.py.
|
|
60839
|
+
provideCitations: widgetConfig.provideCitations,
|
|
60635
60840
|
inactivityTimeoutValue: widgetConfig.inactivityTimeoutValue,
|
|
60636
60841
|
inactivityTimeoutUnit: widgetConfig.inactivityTimeoutUnit,
|
|
60637
60842
|
// Sliding-window cap for the localStorage transcript. Comes from
|
|
@@ -60798,6 +61003,7 @@
|
|
|
60798
61003
|
onResetConversation: resetConversation,
|
|
60799
61004
|
autoPromptEnabled: widgetConfig.autoPromptEnabled,
|
|
60800
61005
|
allowFeedback: widgetConfig.allowFeedback,
|
|
61006
|
+
provideCitations: widgetConfig.provideCitations,
|
|
60801
61007
|
onFeedback: handleMessageFeedback,
|
|
60802
61008
|
onRefreshChat: handleRefreshChat,
|
|
60803
61009
|
onCopyChat: handleCopyChat
|