@eshal-bot/chat-widget 0.1.3 → 0.1.4

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.
@@ -644,19 +644,145 @@
644
644
  return null;
645
645
  };
646
646
 
647
+ /**
648
+ * Initializes the PCM audio player worklet that streams inline PCM chunks
649
+ * coming from the ADK websocket events.
650
+ */
651
+ async function startAudioPlayerWorklet() {
652
+ if (typeof window === 'undefined') {
653
+ throw new Error('Audio player can only be initialized in the browser');
654
+ }
655
+ const audioContext = new AudioContext({
656
+ sampleRate: 24000
657
+ });
658
+
659
+ // For webpack/vite, we need to use a different approach
660
+ // We'll inline the worklet code or use a blob URL
661
+ const workletCode = "\n class PCMPlayerProcessor extends AudioWorkletProcessor {\n constructor() {\n super();\n this.bufferSize = 24000 * 180;\n this.buffer = new Float32Array(this.bufferSize);\n this.writeIndex = 0;\n this.readIndex = 0;\n this.port.onmessage = (event) => {\n if (event.data?.command === 'endOfAudio') {\n this.readIndex = this.writeIndex;\n return;\n }\n const int16Samples = new Int16Array(event.data);\n this.enqueue(int16Samples);\n };\n }\n\n enqueue(samples) {\n for (let i = 0; i < samples.length; i += 1) {\n const floatVal = samples[i] / 32768;\n this.buffer[this.writeIndex] = floatVal;\n this.writeIndex = (this.writeIndex + 1) % this.bufferSize;\n if (this.writeIndex === this.readIndex) {\n this.readIndex = (this.readIndex + 1) % this.bufferSize;\n }\n }\n }\n\n process(inputs, outputs) {\n const output = outputs[0];\n const framesPerBlock = output[0].length;\n for (let frame = 0; frame < framesPerBlock; frame += 1) {\n output[0][frame] = this.buffer[this.readIndex];\n if (output.length > 1) {\n output[1][frame] = this.buffer[this.readIndex];\n }\n if (this.readIndex !== this.writeIndex) {\n this.readIndex = (this.readIndex + 1) % this.bufferSize;\n }\n }\n return true;\n }\n }\n\n registerProcessor('pcm-player-processor', PCMPlayerProcessor);\n ";
662
+ const blob = new Blob([workletCode], {
663
+ type: 'application/javascript'
664
+ });
665
+ const workletUrl = URL.createObjectURL(blob);
666
+ await audioContext.audioWorklet.addModule(workletUrl);
667
+ const audioPlayerNode = new AudioWorkletNode(audioContext, 'pcm-player-processor');
668
+ audioPlayerNode.connect(audioContext.destination);
669
+ URL.revokeObjectURL(workletUrl);
670
+ return [audioPlayerNode, audioContext];
671
+ }
672
+
673
+ /**
674
+ * Bootstraps the PCM recorder audio worklet, captures mic audio at 16kHz
675
+ * mono, and forwards buffers through the provided handler.
676
+ */
677
+ async function startAudioRecorderWorklet(onPcmChunk) {
678
+ if (typeof window === 'undefined') {
679
+ throw new Error('Audio recorder can only run in the browser');
680
+ }
681
+ const audioRecorderContext = new AudioContext({
682
+ sampleRate: 16000
683
+ });
684
+ const workletCode = "\n class PCMRecorderProcessor extends AudioWorkletProcessor {\n process(inputs) {\n if (!inputs.length || !inputs[0].length) {\n return true;\n }\n const inputChannel = inputs[0][0];\n this.port.postMessage(new Float32Array(inputChannel));\n return true;\n }\n }\n\n registerProcessor('pcm-recorder-processor', PCMRecorderProcessor);\n ";
685
+ const blob = new Blob([workletCode], {
686
+ type: 'application/javascript'
687
+ });
688
+ const workletUrl = URL.createObjectURL(blob);
689
+ await audioRecorderContext.audioWorklet.addModule(workletUrl);
690
+ const micStream = await navigator.mediaDevices.getUserMedia({
691
+ audio: {
692
+ channelCount: 1
693
+ }
694
+ });
695
+ const source = audioRecorderContext.createMediaStreamSource(micStream);
696
+ const audioRecorderNode = new AudioWorkletNode(audioRecorderContext, 'pcm-recorder-processor');
697
+ audioRecorderNode.port.onmessage = event => {
698
+ const pcmData = convertFloat32ToPCM(event.data);
699
+ onPcmChunk(pcmData);
700
+ };
701
+ source.connect(audioRecorderNode);
702
+ URL.revokeObjectURL(workletUrl);
703
+ return [audioRecorderNode, audioRecorderContext, micStream];
704
+ }
705
+
706
+ /**
707
+ * Stops all microphone tracks.
708
+ */
709
+ function stopMicrophone(stream) {
710
+ if (!stream) {
711
+ return;
712
+ }
713
+ stream.getTracks().forEach(track => track.stop());
714
+ }
715
+ const INT16_MAX = 0x7fff;
716
+ function convertFloat32ToPCM(float32Array) {
717
+ const pcm16Array = new Int16Array(float32Array.length);
718
+ for (let i = 0; i < float32Array.length; i += 1) {
719
+ pcm16Array[i] = Math.max(-1, Math.min(1, float32Array[i])) * INT16_MAX;
720
+ }
721
+ return pcm16Array.buffer;
722
+ }
723
+
724
+ var _process$env;
725
+
726
+ // BIDI WebSocket base URL - can be overridden via config
727
+ const BIDI_WS_BASE = typeof process !== 'undefined' && (_process$env = process.env) !== null && _process$env !== void 0 && _process$env.NEXT_PUBLIC_BIDI_WS_BASE ? process.env.NEXT_PUBLIC_BIDI_WS_BASE : 'wss://dev.eshal.ai/knowledge-api/ws';
728
+
729
+ /**
730
+ * Clean CJK (Chinese, Japanese, Korean) spaces
731
+ */
732
+ const cleanCJKSpaces = value => {
733
+ return value.replace(/([\u3000-\u303f\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uff00-\uffef])\s+([\u3000-\u303f\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uff00-\uffef])/g, '$1$2');
734
+ };
735
+
736
+ /**
737
+ * Convert base64 to ArrayBuffer
738
+ */
739
+ const base64ToArrayBuffer = base64 => {
740
+ if (typeof window === 'undefined') {
741
+ return new ArrayBuffer(0);
742
+ }
743
+ let normalized = base64.replace(/-/g, '+').replace(/_/g, '/');
744
+ while (normalized.length % 4 !== 0) {
745
+ normalized += '=';
746
+ }
747
+ const binary = window.atob(normalized);
748
+ const len = binary.length;
749
+ const bytes = new Uint8Array(len);
750
+ for (let i = 0; i < len; i += 1) {
751
+ bytes[i] = binary.charCodeAt(i);
752
+ }
753
+ return bytes.buffer;
754
+ };
755
+
756
+ /**
757
+ * Sanitize WebSocket base URL
758
+ */
759
+ const sanitizeWsBase = value => value.replace(/\/$/, '');
760
+
761
+ /**
762
+ * CN utility for conditional class names
763
+ */
764
+ const cn = function () {
765
+ for (var _len = arguments.length, classes = new Array(_len), _key = 0; _key < _len; _key++) {
766
+ classes[_key] = arguments[_key];
767
+ }
768
+ return classes.filter(Boolean).join(' ');
769
+ };
770
+
647
771
  const createMessage = _ref => {
648
772
  let {
649
773
  id,
650
774
  role,
651
775
  content,
652
- isProcessing = false
776
+ isProcessing = false,
777
+ metadata
653
778
  } = _ref;
654
779
  return {
655
780
  id,
656
781
  role,
657
782
  content,
658
783
  timestamp: new Date(),
659
- isProcessing
784
+ isProcessing,
785
+ metadata
660
786
  };
661
787
  };
662
788
  const useChatState = _ref2 => {
@@ -668,7 +794,8 @@
668
794
  organizationId,
669
795
  autoOpen,
670
796
  openDelay,
671
- darkMode
797
+ darkMode,
798
+ enableVoiceInteraction = false
672
799
  } = _ref2;
673
800
  const [isOpen, setIsOpen] = reactExports.useState(autoOpen);
674
801
  const [isMinimized, setIsMinimized] = reactExports.useState(false);
@@ -689,6 +816,31 @@
689
816
  const [isLoading, setIsLoading] = reactExports.useState(false);
690
817
  const widgetRef = reactExports.useRef(null);
691
818
  const messageIdRef = reactExports.useRef(1);
819
+
820
+ // Bidi/Voice state
821
+ const [isVoiceSessionActive, setIsVoiceSessionActive] = reactExports.useState(false);
822
+ const [bidiMessages, setBidiMessages] = reactExports.useState([]);
823
+ const [voiceStatus, setVoiceStatus] = reactExports.useState("idle"); // 'idle' | 'connecting' | 'connected' | 'error'
824
+ const [voiceError, setVoiceError] = reactExports.useState(null);
825
+ const [bidiSessionId] = reactExports.useState(() => "widget-session-".concat(Math.random().toString(36).slice(2, 9)));
826
+
827
+ // Bidi refs
828
+ const websocketRef = reactExports.useRef(null);
829
+ const audioPlayerNodeRef = reactExports.useRef(null);
830
+ const audioPlayerContextRef = reactExports.useRef(null);
831
+ const audioRecorderNodeRef = reactExports.useRef(null);
832
+ const audioRecorderContextRef = reactExports.useRef(null);
833
+ const micStreamRef = reactExports.useRef(null);
834
+ const currentInputMessageIdRef = reactExports.useRef(null);
835
+ const currentAssistantMessageIdRef = reactExports.useRef(null);
836
+ const isAudioReadyRef = reactExports.useRef(false);
837
+ const isVoiceSessionActiveRef = reactExports.useRef(false);
838
+ reactExports.useRef(null);
839
+ const websocketUrl = reactExports.useMemo(() => {
840
+ if (!organizationId) return null;
841
+ const normalizedBase = sanitizeWsBase(BIDI_WS_BASE);
842
+ return "".concat(normalizedBase, "/").concat(organizationId, "/").concat(bidiSessionId);
843
+ }, [organizationId, bidiSessionId]);
692
844
  const getNextMessageId = reactExports.useCallback(() => {
693
845
  const id = "msg-".concat(messageIdRef.current);
694
846
  messageIdRef.current += 1;
@@ -840,17 +992,386 @@
840
992
  const handleQuickQuestion = question => {
841
993
  void sendMessage(question);
842
994
  };
995
+
996
+ /**
997
+ * Handle user decision for HITL (Human-in-the-Loop)
998
+ */
999
+ const handleDecision = reactExports.useCallback(async (decisionId, optionId, optionValue) => {
1000
+ // Remove the decision message from the list
1001
+ setMessages(prev => prev.filter(msg => {
1002
+ var _msg$decisionData;
1003
+ return ((_msg$decisionData = msg.decisionData) === null || _msg$decisionData === void 0 ? void 0 : _msg$decisionData.decisionId) !== decisionId;
1004
+ }));
1005
+
1006
+ // Handle the decision based on the selected option
1007
+ if (optionValue === "connect_agent") {
1008
+ // User wants to connect with a human agent
1009
+ const responseMessage = createMessage({
1010
+ id: getNextMessageId(),
1011
+ role: "assistant",
1012
+ content: "Great! I'm setting up a connection with a live customer service agent. Please hold on for a moment while I transfer you."
1013
+ });
1014
+ setMessages(prev => [...prev, responseMessage]);
1015
+ } else if (optionValue === "decline") {
1016
+ // User declined to connect with a human agent
1017
+ const responseMessage = createMessage({
1018
+ id: getNextMessageId(),
1019
+ role: "assistant",
1020
+ content: "I understand. I apologize that I don't have specific information about your query in my knowledge base. Is there anything else I can help you with?"
1021
+ });
1022
+ setMessages(prev => [...prev, responseMessage]);
1023
+ }
1024
+ }, [getNextMessageId]);
1025
+
1026
+ // Bidi/Voice functions
1027
+ const finalizePendingInputMessage = reactExports.useCallback(() => {
1028
+ if (!currentInputMessageIdRef.current) {
1029
+ return;
1030
+ }
1031
+ setBidiMessages(prev => prev.map(message => message.id === currentInputMessageIdRef.current ? _objectSpread2(_objectSpread2({}, message), {}, {
1032
+ isProcessing: false
1033
+ }) : message));
1034
+ currentInputMessageIdRef.current = null;
1035
+ }, []);
1036
+ const appendUserTranscription = reactExports.useCallback(function (text) {
1037
+ let finished = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1038
+ if (!text) {
1039
+ return;
1040
+ }
1041
+ const chunk = cleanCJKSpaces(text);
1042
+ setBidiMessages(prev => {
1043
+ if (!currentInputMessageIdRef.current) {
1044
+ const newId = "bidi-input-".concat(Date.now());
1045
+ currentInputMessageIdRef.current = newId;
1046
+ const userMessage = createMessage({
1047
+ id: newId,
1048
+ role: "user",
1049
+ content: chunk,
1050
+ isProcessing: !finished,
1051
+ metadata: {
1052
+ source: "bidi",
1053
+ transcriptionType: "input"
1054
+ }
1055
+ });
1056
+ return [...prev, userMessage];
1057
+ }
1058
+ return prev.map(message => {
1059
+ if (message.id !== currentInputMessageIdRef.current) {
1060
+ return message;
1061
+ }
1062
+ const combined = cleanCJKSpaces("".concat(message.content || "").concat(chunk));
1063
+ return _objectSpread2(_objectSpread2({}, message), {}, {
1064
+ content: combined,
1065
+ timestamp: new Date(),
1066
+ isProcessing: !finished,
1067
+ metadata: _objectSpread2(_objectSpread2({}, message.metadata), {}, {
1068
+ transcriptionType: "input"
1069
+ })
1070
+ });
1071
+ });
1072
+ });
1073
+ if (finished) {
1074
+ currentInputMessageIdRef.current = null;
1075
+ }
1076
+ }, []);
1077
+ const appendAssistantContent = reactExports.useCallback(function (text) {
1078
+ let finished = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1079
+ if (!text) {
1080
+ return;
1081
+ }
1082
+ finalizePendingInputMessage();
1083
+ setBidiMessages(prev => {
1084
+ if (!currentAssistantMessageIdRef.current) {
1085
+ const newId = "bidi-assistant-".concat(Date.now());
1086
+ currentAssistantMessageIdRef.current = newId;
1087
+ const assistantMessage = createMessage({
1088
+ id: newId,
1089
+ role: "assistant",
1090
+ content: text,
1091
+ isProcessing: !finished,
1092
+ metadata: {
1093
+ source: "bidi"
1094
+ }
1095
+ });
1096
+ return [...prev, assistantMessage];
1097
+ }
1098
+ return prev.map(message => {
1099
+ if (message.id !== currentAssistantMessageIdRef.current) {
1100
+ return message;
1101
+ }
1102
+ return _objectSpread2(_objectSpread2({}, message), {}, {
1103
+ content: "".concat(message.content || "").concat(text),
1104
+ timestamp: new Date(),
1105
+ isProcessing: !finished
1106
+ });
1107
+ });
1108
+ });
1109
+ if (finished) {
1110
+ currentAssistantMessageIdRef.current = null;
1111
+ }
1112
+ }, [finalizePendingInputMessage]);
1113
+ const handleContentParts = reactExports.useCallback(parts => {
1114
+ parts.forEach(part => {
1115
+ var _part$inlineData, _part$inlineData$mime;
1116
+ if ((_part$inlineData = part.inlineData) !== null && _part$inlineData !== void 0 && _part$inlineData.data && (_part$inlineData$mime = part.inlineData.mimeType) !== null && _part$inlineData$mime !== void 0 && _part$inlineData$mime.startsWith("audio/pcm")) {
1117
+ if (audioPlayerNodeRef.current) {
1118
+ audioPlayerNodeRef.current.port.postMessage(base64ToArrayBuffer(part.inlineData.data));
1119
+ }
1120
+ }
1121
+ if (part.text) {
1122
+ appendAssistantContent(part.text, false);
1123
+ }
1124
+ });
1125
+ }, [appendAssistantContent]);
1126
+ const handleTurnComplete = reactExports.useCallback(() => {
1127
+ currentAssistantMessageIdRef.current = null;
1128
+ currentInputMessageIdRef.current = null;
1129
+ setBidiMessages(prev => prev.map(message => {
1130
+ var _message$metadata;
1131
+ return ((_message$metadata = message.metadata) === null || _message$metadata === void 0 ? void 0 : _message$metadata.source) === "bidi" && message.isProcessing ? _objectSpread2(_objectSpread2({}, message), {}, {
1132
+ isProcessing: false
1133
+ }) : message;
1134
+ }));
1135
+ }, []);
1136
+ const handleInterrupted = reactExports.useCallback(() => {
1137
+ if (audioPlayerNodeRef.current) {
1138
+ audioPlayerNodeRef.current.port.postMessage({
1139
+ command: "endOfAudio"
1140
+ });
1141
+ }
1142
+ currentAssistantMessageIdRef.current = null;
1143
+ currentInputMessageIdRef.current = null;
1144
+ setBidiMessages(prev => prev.map(message => {
1145
+ var _message$metadata2;
1146
+ return ((_message$metadata2 = message.metadata) === null || _message$metadata2 === void 0 ? void 0 : _message$metadata2.source) === "bidi" ? _objectSpread2(_objectSpread2({}, message), {}, {
1147
+ isProcessing: false,
1148
+ metadata: _objectSpread2(_objectSpread2({}, message.metadata), {}, {
1149
+ interrupted: true
1150
+ })
1151
+ }) : message;
1152
+ }));
1153
+ }, []);
1154
+ const handleBidiEvent = reactExports.useCallback(event => {
1155
+ var _event$inputTranscrip, _event$outputTranscri, _event$content;
1156
+ if (!event) {
1157
+ return;
1158
+ }
1159
+ if (event.turnComplete) {
1160
+ handleTurnComplete();
1161
+ return;
1162
+ }
1163
+ if (event.interrupted) {
1164
+ handleInterrupted();
1165
+ return;
1166
+ }
1167
+ if ((_event$inputTranscrip = event.inputTranscription) !== null && _event$inputTranscrip !== void 0 && _event$inputTranscrip.text) {
1168
+ appendUserTranscription(event.inputTranscription.text, Boolean(event.inputTranscription.finished));
1169
+ }
1170
+ if ((_event$outputTranscri = event.outputTranscription) !== null && _event$outputTranscri !== void 0 && _event$outputTranscri.text) {
1171
+ appendAssistantContent(event.outputTranscription.text, Boolean(event.outputTranscription.finished));
1172
+ }
1173
+ if ((_event$content = event.content) !== null && _event$content !== void 0 && _event$content.parts) {
1174
+ handleContentParts(event.content.parts);
1175
+ }
1176
+ }, [appendAssistantContent, appendUserTranscription, handleContentParts, handleInterrupted, handleTurnComplete]);
1177
+ const handleRecorderAudio = reactExports.useCallback(pcmData => {
1178
+ const ws = websocketRef.current;
1179
+ if (!isVoiceSessionActiveRef.current || !ws || ws.readyState !== WebSocket.OPEN) {
1180
+ return;
1181
+ }
1182
+ ws.send(pcmData);
1183
+ }, []);
1184
+ const initializeAudioPipeline = reactExports.useCallback(async () => {
1185
+ if (isAudioReadyRef.current || typeof window === "undefined") {
1186
+ return;
1187
+ }
1188
+ try {
1189
+ const [playerNode, playerContext] = await startAudioPlayerWorklet();
1190
+ audioPlayerNodeRef.current = playerNode;
1191
+ audioPlayerContextRef.current = playerContext;
1192
+ await playerContext.resume();
1193
+ const [recorderNode, recorderContext, micStream] = await startAudioRecorderWorklet(handleRecorderAudio);
1194
+ audioRecorderNodeRef.current = recorderNode;
1195
+ audioRecorderContextRef.current = recorderContext;
1196
+ micStreamRef.current = micStream;
1197
+ await recorderContext.resume();
1198
+ isAudioReadyRef.current = true;
1199
+ } catch (error) {
1200
+ console.error("Failed to initialize audio pipeline", error);
1201
+ throw error;
1202
+ }
1203
+ }, [handleRecorderAudio]);
1204
+ const connectWebsocket = reactExports.useCallback(() => {
1205
+ if (typeof window === "undefined" || !websocketUrl) {
1206
+ return;
1207
+ }
1208
+ if (websocketRef.current && websocketRef.current.readyState === WebSocket.OPEN) {
1209
+ return;
1210
+ }
1211
+ setVoiceStatus("connecting");
1212
+ setVoiceError(null);
1213
+ try {
1214
+ const ws = new WebSocket(websocketUrl);
1215
+ websocketRef.current = ws;
1216
+ ws.onopen = () => {
1217
+ setVoiceStatus("connected");
1218
+ };
1219
+ ws.onmessage = event => {
1220
+ try {
1221
+ const payload = JSON.parse(event.data);
1222
+ handleBidiEvent(payload);
1223
+ } catch (error) {
1224
+ console.error("Failed to parse ADK event", error);
1225
+ }
1226
+ };
1227
+ ws.onerror = () => {
1228
+ setVoiceStatus("error");
1229
+ setVoiceError("Voice session connection error");
1230
+ };
1231
+ ws.onclose = () => {
1232
+ websocketRef.current = null;
1233
+ setVoiceStatus("idle");
1234
+ if (isVoiceSessionActiveRef.current) {
1235
+ setTimeout(() => {
1236
+ connectWebsocket();
1237
+ }, 5000);
1238
+ }
1239
+ };
1240
+ } catch (error) {
1241
+ console.error("Failed to open voice websocket", error);
1242
+ setVoiceStatus("error");
1243
+ setVoiceError(error instanceof Error ? error.message : "Unable to start voice session");
1244
+ }
1245
+ }, [handleBidiEvent, websocketUrl]);
1246
+ const startVoiceSession = reactExports.useCallback(async () => {
1247
+ if (!enableVoiceInteraction || !organizationId) {
1248
+ return;
1249
+ }
1250
+ setVoiceError(null);
1251
+ setVoiceStatus(prev => prev === "connected" ? prev : "connecting");
1252
+ setIsVoiceSessionActive(true);
1253
+ isVoiceSessionActiveRef.current = true;
1254
+ setBidiMessages(prev => {
1255
+ if (prev.length > 0) {
1256
+ return prev;
1257
+ }
1258
+ if (!welcomeMessage || welcomeMessage.trim() === "") {
1259
+ return [];
1260
+ }
1261
+ const welcomeMsg = createMessage({
1262
+ id: "bidi-welcome-".concat(Date.now()),
1263
+ role: "assistant",
1264
+ content: welcomeMessage,
1265
+ metadata: {
1266
+ source: "bidi"
1267
+ }
1268
+ });
1269
+ return [welcomeMsg];
1270
+ });
1271
+ connectWebsocket();
1272
+ try {
1273
+ await initializeAudioPipeline();
1274
+ } catch (error) {
1275
+ console.error("Failed to start audio pipeline", error);
1276
+ setVoiceError(error instanceof Error ? error.message : "Unable to access microphone");
1277
+ setVoiceStatus("error");
1278
+ }
1279
+ }, [enableVoiceInteraction, organizationId, welcomeMessage, connectWebsocket, initializeAudioPipeline]);
1280
+ const stopVoiceSession = reactExports.useCallback(() => {
1281
+ var _audioPlayerNodeRef$c, _audioPlayerContextRe, _audioRecorderNodeRef, _audioRecorderContext;
1282
+ setIsVoiceSessionActive(false);
1283
+ isVoiceSessionActiveRef.current = false;
1284
+ setVoiceStatus("idle");
1285
+ setVoiceError(null);
1286
+ if (websocketRef.current && websocketRef.current.readyState === WebSocket.OPEN) {
1287
+ websocketRef.current.close();
1288
+ }
1289
+ websocketRef.current = null;
1290
+ (_audioPlayerNodeRef$c = audioPlayerNodeRef.current) === null || _audioPlayerNodeRef$c === void 0 || _audioPlayerNodeRef$c.disconnect();
1291
+ (_audioPlayerContextRe = audioPlayerContextRef.current) === null || _audioPlayerContextRe === void 0 || _audioPlayerContextRe.close();
1292
+ audioPlayerNodeRef.current = null;
1293
+ audioPlayerContextRef.current = null;
1294
+ (_audioRecorderNodeRef = audioRecorderNodeRef.current) === null || _audioRecorderNodeRef === void 0 || _audioRecorderNodeRef.disconnect();
1295
+ (_audioRecorderContext = audioRecorderContextRef.current) === null || _audioRecorderContext === void 0 || _audioRecorderContext.close();
1296
+ audioRecorderNodeRef.current = null;
1297
+ audioRecorderContextRef.current = null;
1298
+ stopMicrophone(micStreamRef.current);
1299
+ micStreamRef.current = null;
1300
+ isAudioReadyRef.current = false;
1301
+ }, []);
1302
+ const handleVoiceToggle = reactExports.useCallback(() => {
1303
+ if (isVoiceSessionActive) {
1304
+ stopVoiceSession();
1305
+ return;
1306
+ }
1307
+ if (voiceStatus === "connecting") {
1308
+ return;
1309
+ }
1310
+ void startVoiceSession();
1311
+ }, [isVoiceSessionActive, startVoiceSession, stopVoiceSession, voiceStatus]);
1312
+ const sendBidiTextMessage = reactExports.useCallback(text => {
1313
+ const trimmed = text.trim();
1314
+ if (!trimmed) {
1315
+ return;
1316
+ }
1317
+ const ws = websocketRef.current;
1318
+ if (!ws || ws.readyState !== WebSocket.OPEN) {
1319
+ setVoiceError("Voice session is not connected yet");
1320
+ return;
1321
+ }
1322
+ ws.send(JSON.stringify({
1323
+ type: "text",
1324
+ text: trimmed
1325
+ }));
1326
+ const userMessage = createMessage({
1327
+ id: "bidi-user-".concat(Date.now()),
1328
+ role: "user",
1329
+ content: trimmed,
1330
+ metadata: {
1331
+ source: "bidi"
1332
+ }
1333
+ });
1334
+ setBidiMessages(prev => [...prev, userMessage]);
1335
+ setInputValue("");
1336
+ }, []);
1337
+
1338
+ // Cleanup on unmount
1339
+ reactExports.useEffect(() => {
1340
+ isVoiceSessionActiveRef.current = isVoiceSessionActive;
1341
+ }, [isVoiceSessionActive]);
1342
+ reactExports.useEffect(() => {
1343
+ return () => {
1344
+ var _audioPlayerNodeRef$c2, _audioPlayerContextRe2, _audioRecorderNodeRef2, _audioRecorderContext2;
1345
+ if (websocketRef.current && websocketRef.current.readyState === WebSocket.OPEN) {
1346
+ websocketRef.current.close();
1347
+ }
1348
+ (_audioPlayerNodeRef$c2 = audioPlayerNodeRef.current) === null || _audioPlayerNodeRef$c2 === void 0 || _audioPlayerNodeRef$c2.disconnect();
1349
+ (_audioPlayerContextRe2 = audioPlayerContextRef.current) === null || _audioPlayerContextRe2 === void 0 || _audioPlayerContextRe2.close();
1350
+ (_audioRecorderNodeRef2 = audioRecorderNodeRef.current) === null || _audioRecorderNodeRef2 === void 0 || _audioRecorderNodeRef2.disconnect();
1351
+ (_audioRecorderContext2 = audioRecorderContextRef.current) === null || _audioRecorderContext2 === void 0 || _audioRecorderContext2.close();
1352
+ stopMicrophone(micStreamRef.current);
1353
+ micStreamRef.current = null;
1354
+ isAudioReadyRef.current = false;
1355
+ };
1356
+ }, []);
843
1357
  const memoizedQuickQuestions = reactExports.useMemo(() => quickQuestions, [quickQuestions]);
1358
+
1359
+ // Determine which messages to use
1360
+ const activeMessages = isVoiceSessionActive ? bidiMessages : messages;
844
1361
  return {
845
1362
  // State
846
1363
  isOpen,
847
1364
  isMinimized,
848
1365
  isDark,
849
- messages,
1366
+ messages: activeMessages,
850
1367
  inputValue,
851
1368
  isLoading,
852
1369
  widgetRef,
853
1370
  quickQuestions: memoizedQuickQuestions,
1371
+ // Bidi/Voice state
1372
+ isVoiceSessionActive,
1373
+ voiceStatus,
1374
+ voiceError,
854
1375
  // Actions
855
1376
  setInputValue,
856
1377
  handleSend,
@@ -859,7 +1380,11 @@
859
1380
  toggleChat,
860
1381
  toggleTheme,
861
1382
  toggleMinimize,
862
- closeChat
1383
+ closeChat,
1384
+ handleDecision,
1385
+ // Bidi/Voice actions
1386
+ handleVoiceToggle,
1387
+ sendBidiTextMessage
863
1388
  };
864
1389
  };
865
1390
 
@@ -923,13 +1448,13 @@
923
1448
  */
924
1449
 
925
1450
 
926
- const Bot = createLucideIcon("Bot", [
927
- ["path", { d: "M12 8V4H8", key: "hb8ula" }],
928
- ["rect", { width: "16", height: "12", x: "4", y: "8", rx: "2", key: "enze0r" }],
929
- ["path", { d: "M2 14h2", key: "vft8re" }],
930
- ["path", { d: "M20 14h2", key: "4cs60a" }],
931
- ["path", { d: "M15 13v2", key: "1xurst" }],
932
- ["path", { d: "M9 13v2", key: "rq6x2g" }]
1451
+ const AudioLines = createLucideIcon("AudioLines", [
1452
+ ["path", { d: "M2 10v3", key: "1fnikh" }],
1453
+ ["path", { d: "M6 6v11", key: "11sgs0" }],
1454
+ ["path", { d: "M10 3v18", key: "yhl04a" }],
1455
+ ["path", { d: "M14 8v7", key: "3a1oy3" }],
1456
+ ["path", { d: "M18 5v13", key: "123xd1" }],
1457
+ ["path", { d: "M22 10v3", key: "154ddg" }]
933
1458
  ]);
934
1459
 
935
1460
  /**
@@ -940,11 +1465,8 @@
940
1465
  */
941
1466
 
942
1467
 
943
- const Maximize2 = createLucideIcon("Maximize2", [
944
- ["polyline", { points: "15 3 21 3 21 9", key: "mznyad" }],
945
- ["polyline", { points: "9 21 3 21 3 15", key: "1avn1i" }],
946
- ["line", { x1: "21", x2: "14", y1: "3", y2: "10", key: "ota7mn" }],
947
- ["line", { x1: "3", x2: "10", y1: "21", y2: "14", key: "1atl0r" }]
1468
+ const Loader2 = createLucideIcon("Loader2", [
1469
+ ["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]
948
1470
  ]);
949
1471
 
950
1472
  /**
@@ -955,10 +1477,11 @@
955
1477
  */
956
1478
 
957
1479
 
958
- const MessageCircleQuestion = createLucideIcon("MessageCircleQuestion", [
959
- ["path", { d: "M7.9 20A9 9 0 1 0 4 16.1L2 22Z", key: "vv11sd" }],
960
- ["path", { d: "M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3", key: "1u773s" }],
961
- ["path", { d: "M12 17h.01", key: "p32p05" }]
1480
+ const Maximize2 = createLucideIcon("Maximize2", [
1481
+ ["polyline", { points: "15 3 21 3 21 9", key: "mznyad" }],
1482
+ ["polyline", { points: "9 21 3 21 3 15", key: "1avn1i" }],
1483
+ ["line", { x1: "21", x2: "14", y1: "3", y2: "10", key: "ota7mn" }],
1484
+ ["line", { x1: "3", x2: "10", y1: "21", y2: "14", key: "1atl0r" }]
962
1485
  ]);
963
1486
 
964
1487
  /**
@@ -1059,323 +1582,6 @@
1059
1582
  ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
1060
1583
  ]);
1061
1584
 
1062
- var jsxRuntime = {exports: {}};
1063
-
1064
- var reactJsxRuntime_production_min = {};
1065
-
1066
- /**
1067
- * @license React
1068
- * react-jsx-runtime.production.min.js
1069
- *
1070
- * Copyright (c) Facebook, Inc. and its affiliates.
1071
- *
1072
- * This source code is licensed under the MIT license found in the
1073
- * LICENSE file in the root directory of this source tree.
1074
- */
1075
- var f=reactExports,k=Symbol.for("react.element"),l=Symbol.for("react.fragment"),m=Object.prototype.hasOwnProperty,n=f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,p={key:!0,ref:!0,__self:!0,__source:!0};
1076
- function q(c,a,g){var b,d={},e=null,h=null;void 0!==g&&(e=""+g);void 0!==a.key&&(e=""+a.key);void 0!==a.ref&&(h=a.ref);for(b in a)m.call(a,b)&&!p.hasOwnProperty(b)&&(d[b]=a[b]);if(c&&c.defaultProps)for(b in a=c.defaultProps,a)void 0===d[b]&&(d[b]=a[b]);return {$$typeof:k,type:c,key:e,ref:h,props:d,_owner:n.current}}reactJsxRuntime_production_min.Fragment=l;reactJsxRuntime_production_min.jsx=q;reactJsxRuntime_production_min.jsxs=q;
1077
-
1078
- {
1079
- jsxRuntime.exports = reactJsxRuntime_production_min;
1080
- }
1081
-
1082
- var jsxRuntimeExports = jsxRuntime.exports;
1083
-
1084
- const LOGO_MAX_HEIGHT = "3.5rem";
1085
- const LOGO_MAX_HEIGHT_COMPACT = "2.5rem";
1086
- const LOGO_MAX_WIDTH_DEFAULT = "4.5rem";
1087
- const LOGO_MAX_WIDTH_DEFAULT_COMPACT = "3rem";
1088
- const LOGO_MAX_WIDTH_WIDE = "9rem";
1089
- const LOGO_MAX_WIDTH_WIDE_COMPACT = "5.5rem";
1090
- const STATUS_DOT_SIZE = "0.8rem";
1091
- const STATUS_DOT_SIZE_COMPACT = "0.65rem";
1092
- const STATUS_DOT_BORDER_WIDTH = "2px";
1093
- const STATUS_DOT_BORDER_WIDTH_COMPACT = "1.5px";
1094
- const STATUS_DOT_DEFAULT_COLOR = "#34d399";
1095
- const STATUS_DOT_OFFSET = "38%";
1096
- const STATUS_DOT_OFFSET_COMPACT = "22%";
1097
- const LogoImage = _ref => {
1098
- let {
1099
- src,
1100
- showStatusDot = false,
1101
- statusColor = STATUS_DOT_DEFAULT_COLOR,
1102
- size = "default"
1103
- } = _ref;
1104
- const [aspect, setAspect] = reactExports.useState("square");
1105
- const isCompact = size === "compact";
1106
- reactExports.useEffect(() => {
1107
- if (typeof window === "undefined" || !src) {
1108
- return;
1109
- }
1110
- const img = new Image();
1111
- img.src = src;
1112
- img.onload = () => {
1113
- if (img.width > img.height) {
1114
- setAspect("wide");
1115
- } else if (img.height > img.width) {
1116
- setAspect("tall");
1117
- } else {
1118
- setAspect("square");
1119
- }
1120
- };
1121
- }, [src]);
1122
- const containerStyle = {
1123
- position: "relative",
1124
- display: "inline-flex"
1125
- };
1126
- const imageStyle = {
1127
- display: "block",
1128
- objectFit: "contain",
1129
- height: "auto",
1130
- width: "auto",
1131
- maxHeight: isCompact ? LOGO_MAX_HEIGHT_COMPACT : LOGO_MAX_HEIGHT,
1132
- maxWidth: isCompact ? LOGO_MAX_WIDTH_DEFAULT_COMPACT : LOGO_MAX_WIDTH_DEFAULT
1133
- };
1134
- if (aspect === "wide") {
1135
- imageStyle.maxWidth = isCompact ? LOGO_MAX_WIDTH_WIDE_COMPACT : LOGO_MAX_WIDTH_WIDE;
1136
- }
1137
- if (aspect === "tall") {
1138
- imageStyle.maxHeight = isCompact ? "3rem" : "4rem";
1139
- imageStyle.maxWidth = isCompact ? "3rem" : "4rem";
1140
- }
1141
- return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
1142
- style: containerStyle,
1143
- children: [/*#__PURE__*/jsxRuntimeExports.jsx("img", {
1144
- src: src,
1145
- alt: "Logo",
1146
- style: imageStyle,
1147
- loading: "lazy"
1148
- }), showStatusDot && /*#__PURE__*/jsxRuntimeExports.jsx("span", {
1149
- style: {
1150
- position: "absolute",
1151
- bottom: 0,
1152
- right: 0,
1153
- width: isCompact ? STATUS_DOT_SIZE_COMPACT : STATUS_DOT_SIZE,
1154
- height: isCompact ? STATUS_DOT_SIZE_COMPACT : STATUS_DOT_SIZE,
1155
- borderRadius: "9999px",
1156
- backgroundColor: statusColor,
1157
- border: "".concat(isCompact ? STATUS_DOT_BORDER_WIDTH_COMPACT : STATUS_DOT_BORDER_WIDTH, " solid #ffffff"),
1158
- transform: "translate(".concat(isCompact ? STATUS_DOT_OFFSET_COMPACT : STATUS_DOT_OFFSET, ", ").concat(isCompact ? STATUS_DOT_OFFSET_COMPACT : STATUS_DOT_OFFSET, ")"),
1159
- pointerEvents: "none"
1160
- }
1161
- })]
1162
- });
1163
- };
1164
-
1165
- const IS_BROWSER = typeof window !== "undefined";
1166
- const SYSTEM_FONT_FAMILIES = new Set(["Arial", "Helvetica", "Times New Roman", "Georgia", "Courier New", "Verdana", "Trebuchet MS", "Palatino", "Garamond", "Tahoma", "Lucida Sans", "Lucida Grande", "Lucida Console", "Gill Sans", "Impact", "Comic Sans MS", "system-ui"].map(font => font.toLowerCase()));
1167
- const GENERIC_FONT_KEYWORDS = ["sans-serif", "serif", "monospace", "cursive", "fantasy"];
1168
- const GOOGLE_FONT_WEIGHTS = "300,400,500,600,700";
1169
- const loadedFonts = new Set();
1170
- let webFontLoaderPromise = null;
1171
- const shouldSkipLoading = fontFamily => {
1172
- const normalized = fontFamily.trim().toLowerCase();
1173
- if (!normalized) return true;
1174
- if (SYSTEM_FONT_FAMILIES.has(normalized)) return true;
1175
- return GENERIC_FONT_KEYWORDS.some(keyword => normalized.includes(keyword));
1176
- };
1177
- const toGoogleFontQuery = fontFamily => fontFamily.trim().replace(/\s+/g, "+");
1178
- function useGoogleFont(fontFamily) {
1179
- reactExports.useEffect(() => {
1180
- var _fontFamily$split$;
1181
- if (!IS_BROWSER || !fontFamily) {
1182
- return;
1183
- }
1184
- const baseFont = (_fontFamily$split$ = fontFamily.split(",")[0]) === null || _fontFamily$split$ === void 0 ? void 0 : _fontFamily$split$.trim();
1185
- if (!baseFont || loadedFonts.has(baseFont)) {
1186
- return;
1187
- }
1188
- if (shouldSkipLoading(baseFont)) {
1189
- loadedFonts.add(baseFont);
1190
- return;
1191
- }
1192
- let isMounted = true;
1193
- const loadFont = async () => {
1194
- try {
1195
- if (!webFontLoaderPromise) {
1196
- webFontLoaderPromise = Promise.resolve().then(function () { return webfontloader; });
1197
- }
1198
- const webFontModule = await webFontLoaderPromise;
1199
- const WebFont = webFontModule && "default" in webFontModule ? webFontModule.default : webFontModule;
1200
- const googleQuery = toGoogleFontQuery(baseFont);
1201
- WebFont.load({
1202
- google: {
1203
- families: ["".concat(googleQuery, ":").concat(GOOGLE_FONT_WEIGHTS)]
1204
- },
1205
- fontactive: family => {
1206
- if (isMounted) {
1207
- loadedFonts.add(family);
1208
- }
1209
- },
1210
- fontinactive: family => {
1211
- if (isMounted) {
1212
- loadedFonts.add(family);
1213
- }
1214
- console.warn("Warning: failed to load Google Font: ".concat(family));
1215
- }
1216
- });
1217
- } catch (error) {
1218
- console.error("Warning: WebFont loader error:", error);
1219
- }
1220
- };
1221
- void loadFont();
1222
- return () => {
1223
- isMounted = false;
1224
- };
1225
- }, [fontFamily]);
1226
- }
1227
-
1228
- const lightenColor = function (color) {
1229
- let amount = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.12;
1230
- if (!color) {
1231
- return color;
1232
- }
1233
- const hexMatch = color.trim().match(/^#([0-9a-f]{3,8})$/i);
1234
- if (!hexMatch) {
1235
- return color;
1236
- }
1237
- let hex = hexMatch[1];
1238
- if (hex.length === 3) {
1239
- hex = hex.split("").map(char => char + char).join("");
1240
- }
1241
- if (hex.length === 8) {
1242
- hex = hex.slice(0, 6);
1243
- }
1244
- if (hex.length !== 6) {
1245
- return color;
1246
- }
1247
- const num = parseInt(hex, 16);
1248
- const r = num >> 16 & 255;
1249
- const g = num >> 8 & 255;
1250
- const b = num & 255;
1251
- const mix = channel => {
1252
- const mixed = Math.round(channel + (255 - channel) * amount);
1253
- return Math.min(255, Math.max(0, mixed));
1254
- };
1255
- const [lr, lg, lb] = [mix(r), mix(g), mix(b)];
1256
- const toHex = channel => channel.toString(16).padStart(2, "0");
1257
- return "#".concat(toHex(lr)).concat(toHex(lg)).concat(toHex(lb));
1258
- };
1259
- const ChatHeader = _ref => {
1260
- let {
1261
- conciergeName,
1262
- companyName,
1263
- companyLogo,
1264
- primaryColor,
1265
- isDark,
1266
- isMinimized = false,
1267
- textColor,
1268
- fontFamily,
1269
- fontSize,
1270
- onToggleTheme,
1271
- onMinimize,
1272
- onClose
1273
- } = _ref;
1274
- useGoogleFont(fontFamily);
1275
- return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
1276
- className: "text-white ".concat(isMinimized ? "px-4 py-2.5" : "px-5 py-4", " flex items-center justify-between relative overflow-hidden rounded-t-2xl"),
1277
- style: {
1278
- background: "linear-gradient(135deg, ".concat(primaryColor, " 0%, ").concat(lightenColor(primaryColor, 0.2), " 100%)"),
1279
- fontFamily
1280
- },
1281
- children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
1282
- className: "absolute inset-0 pointer-events-none transition-opacity duration-200 ".concat(isMinimized ? "opacity-0" : "opacity-100", " bg-gradient-to-br from-white/10 to-transparent")
1283
- }), /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
1284
- className: "flex items-center ".concat(isMinimized ? "gap-1.5" : "gap-3", " relative z-10 min-w-0"),
1285
- children: [companyLogo ? /*#__PURE__*/jsxRuntimeExports.jsx(LogoImage, {
1286
- src: companyLogo,
1287
- showStatusDot: true,
1288
- statusColor: "#34d399",
1289
- size: isMinimized ? "compact" : "default"
1290
- }) : /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
1291
- className: "relative",
1292
- children: [/*#__PURE__*/jsxRuntimeExports.jsx(MessageCircle, {
1293
- className: "transition-all ".concat(isMinimized ? "w-8 h-8" : "w-10 h-10")
1294
- }), /*#__PURE__*/jsxRuntimeExports.jsx("span", {
1295
- className: "absolute rounded-full",
1296
- style: {
1297
- bottom: 0,
1298
- right: 0,
1299
- width: isMinimized ? "0.65rem" : "0.8rem",
1300
- height: isMinimized ? "0.65rem" : "0.8rem",
1301
- backgroundColor: "#34d399",
1302
- border: isMinimized ? "1.5px solid #ffffff" : "2px solid #ffffff",
1303
- transform: "translate(".concat(isMinimized ? "22%" : "38%", ", ").concat(isMinimized ? "22%" : "38%", ")"),
1304
- pointerEvents: "none"
1305
- }
1306
- })]
1307
- }), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
1308
- className: "flex items-center gap-2 min-w-0",
1309
- children: /*#__PURE__*/jsxRuntimeExports.jsx("h3", {
1310
- className: "font-semibold leading-tight truncate",
1311
- style: {
1312
- fontSize: fontSize ? "calc(".concat(fontSize, " + ").concat(isMinimized ? "6px" : "10px", ")") : isMinimized ? "13px" : "15px",
1313
- color: textColor || "#FFFFFF"
1314
- },
1315
- children: conciergeName
1316
- })
1317
- })]
1318
- }), /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
1319
- className: "flex items-center ".concat(isMinimized ? "gap-3" : "gap-4", " relative z-10 text-white"),
1320
- children: [/*#__PURE__*/jsxRuntimeExports.jsx("span", {
1321
- role: "button",
1322
- tabIndex: 0,
1323
- "aria-label": "Toggle theme",
1324
- onClick: onToggleTheme,
1325
- onKeyDown: event => {
1326
- if (event.key === "Enter" || event.key === " ") {
1327
- event.preventDefault();
1328
- onToggleTheme === null || onToggleTheme === void 0 || onToggleTheme(event);
1329
- }
1330
- },
1331
- className: "inline-flex h-8 w-8 items-center justify-center cursor-pointer transition-opacity duration-200 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40 rounded-full",
1332
- children: isDark ? /*#__PURE__*/jsxRuntimeExports.jsx(Sun, {
1333
- className: "w-4 h-4",
1334
- strokeWidth: 1.6
1335
- }) : /*#__PURE__*/jsxRuntimeExports.jsx(Moon, {
1336
- className: "w-4 h-4",
1337
- strokeWidth: 1.6
1338
- })
1339
- }), onMinimize && /*#__PURE__*/jsxRuntimeExports.jsx("span", {
1340
- role: "button",
1341
- tabIndex: 0,
1342
- "aria-label": isMinimized ? "Expand" : "Minimize",
1343
- onClick: onMinimize,
1344
- onKeyDown: event => {
1345
- if (event.key === "Enter" || event.key === " ") {
1346
- event.preventDefault();
1347
- onMinimize === null || onMinimize === void 0 || onMinimize(event);
1348
- }
1349
- },
1350
- className: "inline-flex h-8 w-8 items-center justify-center cursor-pointer transition-opacity duration-200 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40 rounded-full",
1351
- children: isMinimized ? /*#__PURE__*/jsxRuntimeExports.jsx(Maximize2, {
1352
- className: "w-4 h-4",
1353
- strokeWidth: 1.6
1354
- }) : /*#__PURE__*/jsxRuntimeExports.jsx(Minimize2, {
1355
- className: "w-4 h-4",
1356
- strokeWidth: 1.6
1357
- })
1358
- }), /*#__PURE__*/jsxRuntimeExports.jsx("span", {
1359
- role: "button",
1360
- tabIndex: 0,
1361
- "aria-label": "Close",
1362
- onClick: onClose,
1363
- onKeyDown: event => {
1364
- if (event.key === "Enter" || event.key === " ") {
1365
- event.preventDefault();
1366
- onClose === null || onClose === void 0 || onClose(event);
1367
- }
1368
- },
1369
- className: "inline-flex h-8 w-8 items-center justify-center cursor-pointer transition-opacity duration-200 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40 rounded-full",
1370
- children: /*#__PURE__*/jsxRuntimeExports.jsx(X, {
1371
- className: "w-4 h-4",
1372
- strokeWidth: 1.6
1373
- })
1374
- })]
1375
- })]
1376
- });
1377
- };
1378
-
1379
1585
  function ok$2() {}
1380
1586
 
1381
1587
  function unreachable() {}
@@ -4508,6 +4714,28 @@
4508
4714
  ]
4509
4715
  };
4510
4716
 
4717
+ var jsxRuntime = {exports: {}};
4718
+
4719
+ var reactJsxRuntime_production_min = {};
4720
+
4721
+ /**
4722
+ * @license React
4723
+ * react-jsx-runtime.production.min.js
4724
+ *
4725
+ * Copyright (c) Facebook, Inc. and its affiliates.
4726
+ *
4727
+ * This source code is licensed under the MIT license found in the
4728
+ * LICENSE file in the root directory of this source tree.
4729
+ */
4730
+ var f=reactExports,k=Symbol.for("react.element"),l=Symbol.for("react.fragment"),m=Object.prototype.hasOwnProperty,n=f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,p={key:!0,ref:!0,__self:!0,__source:!0};
4731
+ function q(c,a,g){var b,d={},e=null,h=null;void 0!==g&&(e=""+g);void 0!==a.key&&(e=""+a.key);void 0!==a.ref&&(h=a.ref);for(b in a)m.call(a,b)&&!p.hasOwnProperty(b)&&(d[b]=a[b]);if(c&&c.defaultProps)for(b in a=c.defaultProps,a)void 0===d[b]&&(d[b]=a[b]);return {$$typeof:k,type:c,key:e,ref:h,props:d,_owner:n.current}}reactJsxRuntime_production_min.Fragment=l;reactJsxRuntime_production_min.jsx=q;reactJsxRuntime_production_min.jsxs=q;
4732
+
4733
+ {
4734
+ jsxRuntime.exports = reactJsxRuntime_production_min;
4735
+ }
4736
+
4737
+ var jsxRuntimeExports = jsxRuntime.exports;
4738
+
4511
4739
  /**
4512
4740
  * @typedef {import('mdast').Nodes} Nodes
4513
4741
  *
@@ -55074,24 +55302,91 @@
55074
55302
  }
55075
55303
  };
55076
55304
 
55305
+ const IS_BROWSER = typeof window !== "undefined";
55306
+ const SYSTEM_FONT_FAMILIES = new Set(["Arial", "Helvetica", "Times New Roman", "Georgia", "Courier New", "Verdana", "Trebuchet MS", "Palatino", "Garamond", "Tahoma", "Lucida Sans", "Lucida Grande", "Lucida Console", "Gill Sans", "Impact", "Comic Sans MS", "system-ui"].map(font => font.toLowerCase()));
55307
+ const GENERIC_FONT_KEYWORDS = ["sans-serif", "serif", "monospace", "cursive", "fantasy"];
55308
+ const GOOGLE_FONT_WEIGHTS = "300,400,500,600,700";
55309
+ const loadedFonts = new Set();
55310
+ let webFontLoaderPromise = null;
55311
+ const shouldSkipLoading = fontFamily => {
55312
+ const normalized = fontFamily.trim().toLowerCase();
55313
+ if (!normalized) return true;
55314
+ if (SYSTEM_FONT_FAMILIES.has(normalized)) return true;
55315
+ return GENERIC_FONT_KEYWORDS.some(keyword => normalized.includes(keyword));
55316
+ };
55317
+ const toGoogleFontQuery = fontFamily => fontFamily.trim().replace(/\s+/g, "+");
55318
+ function useGoogleFont(fontFamily) {
55319
+ reactExports.useEffect(() => {
55320
+ var _fontFamily$split$;
55321
+ if (!IS_BROWSER || !fontFamily) {
55322
+ return;
55323
+ }
55324
+ const baseFont = (_fontFamily$split$ = fontFamily.split(",")[0]) === null || _fontFamily$split$ === void 0 ? void 0 : _fontFamily$split$.trim();
55325
+ if (!baseFont || loadedFonts.has(baseFont)) {
55326
+ return;
55327
+ }
55328
+ if (shouldSkipLoading(baseFont)) {
55329
+ loadedFonts.add(baseFont);
55330
+ return;
55331
+ }
55332
+ let isMounted = true;
55333
+ const loadFont = async () => {
55334
+ try {
55335
+ if (!webFontLoaderPromise) {
55336
+ webFontLoaderPromise = Promise.resolve().then(function () { return webfontloader; });
55337
+ }
55338
+ const webFontModule = await webFontLoaderPromise;
55339
+ const WebFont = webFontModule && "default" in webFontModule ? webFontModule.default : webFontModule;
55340
+ const googleQuery = toGoogleFontQuery(baseFont);
55341
+ WebFont.load({
55342
+ google: {
55343
+ families: ["".concat(googleQuery, ":").concat(GOOGLE_FONT_WEIGHTS)]
55344
+ },
55345
+ fontactive: family => {
55346
+ if (isMounted) {
55347
+ loadedFonts.add(family);
55348
+ }
55349
+ },
55350
+ fontinactive: family => {
55351
+ if (isMounted) {
55352
+ loadedFonts.add(family);
55353
+ }
55354
+ console.warn("Warning: failed to load Google Font: ".concat(family));
55355
+ }
55356
+ });
55357
+ } catch (error) {
55358
+ console.error("Warning: WebFont loader error:", error);
55359
+ }
55360
+ };
55361
+ void loadFont();
55362
+ return () => {
55363
+ isMounted = false;
55364
+ };
55365
+ }, [fontFamily]);
55366
+ }
55367
+
55077
55368
  const _excluded = ["node", "children"],
55078
55369
  _excluded2 = ["node", "children"],
55079
55370
  _excluded3 = ["node", "children"],
55080
55371
  _excluded4 = ["node", "children"],
55081
- _excluded5 = ["className", "children"],
55372
+ _excluded5 = ["node", "children"],
55082
55373
  _excluded6 = ["node", "children"],
55083
55374
  _excluded7 = ["node", "children"],
55084
55375
  _excluded8 = ["node", "children"],
55085
55376
  _excluded9 = ["node", "children"],
55086
55377
  _excluded0 = ["node", "children"],
55087
55378
  _excluded1 = ["node", "children"],
55088
- _excluded10 = ["node", "children"];
55379
+ _excluded10 = ["node", "children"],
55380
+ _excluded11 = ["className", "children"];
55089
55381
  const StreamingMarkdown = _ref => {
55090
55382
  let {
55091
55383
  content,
55092
55384
  isStreaming,
55093
55385
  isDark = false,
55094
- isRtl = false
55386
+ isRtl = false,
55387
+ textColor,
55388
+ fontFamily,
55389
+ fontSize
55095
55390
  } = _ref;
55096
55391
  const [displayedContent, setDisplayedContent] = reactExports.useState("");
55097
55392
  const [showCursor, setShowCursor] = reactExports.useState(false);
@@ -55100,19 +55395,23 @@
55100
55395
  const animationFrameRef = reactExports.useRef(null);
55101
55396
  const lastUpdateRef = reactExports.useRef(0);
55102
55397
  reactExports.useEffect(() => {
55398
+ // Reset if content changes significantly
55103
55399
  if (content !== contentRef.current) {
55104
55400
  contentRef.current = content;
55401
+ // If we're already past the new content length, show it all
55105
55402
  if (indexRef.current >= content.length) {
55106
55403
  setDisplayedContent(content);
55107
55404
  setShowCursor(false);
55108
55405
  return;
55109
55406
  }
55407
+ // If new content is shorter, reset
55110
55408
  if (content.length < displayedContent.length) {
55111
55409
  indexRef.current = 0;
55112
55410
  setDisplayedContent("");
55113
55411
  }
55114
55412
  }
55115
55413
  if (!isStreaming) {
55414
+ // Not streaming - show full content immediately
55116
55415
  setDisplayedContent(content);
55117
55416
  setShowCursor(false);
55118
55417
  if (animationFrameRef.current) {
@@ -55120,20 +55419,25 @@
55120
55419
  }
55121
55420
  return;
55122
55421
  }
55422
+
55423
+ // Streaming mode - animate character by character
55123
55424
  setShowCursor(true);
55124
55425
  const animate = timestamp => {
55426
+ // Throttle updates for smooth 60fps animation
55125
55427
  if (timestamp - lastUpdateRef.current < 16) {
55126
55428
  animationFrameRef.current = requestAnimationFrame(animate);
55127
55429
  return;
55128
55430
  }
55129
55431
  lastUpdateRef.current = timestamp;
55130
55432
  if (indexRef.current < content.length) {
55433
+ // Add 2-5 characters per frame for natural speed
55131
55434
  const charsToAdd = Math.max(2, Math.floor(Math.random() * 4));
55132
55435
  const newIndex = Math.min(indexRef.current + charsToAdd, content.length);
55133
55436
  setDisplayedContent(content.slice(0, newIndex));
55134
55437
  indexRef.current = newIndex;
55135
55438
  animationFrameRef.current = requestAnimationFrame(animate);
55136
55439
  } else {
55440
+ // Finished streaming
55137
55441
  setShowCursor(false);
55138
55442
  }
55139
55443
  };
@@ -55143,7 +55447,7 @@
55143
55447
  cancelAnimationFrame(animationFrameRef.current);
55144
55448
  }
55145
55449
  };
55146
- }, [content, displayedContent.length, isStreaming]);
55450
+ }, [content, isStreaming]);
55147
55451
  return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
55148
55452
  className: "relative",
55149
55453
  style: {
@@ -55152,126 +55456,142 @@
55152
55456
  },
55153
55457
  children: [/*#__PURE__*/jsxRuntimeExports.jsx(Markdown, {
55154
55458
  remarkPlugins: [remarkGfm],
55155
- className: "markdown-body text-sm leading-relaxed space-y-3 ".concat(isDark ? "text-gray-100" : "text-gray-800"),
55459
+ className: "prose prose-sm max-w-none [&>*:last-child]:!mb-0 [&>*:first-child]:!mt-0",
55460
+ style: {
55461
+ color: textColor || (isDark ? "#f3f4f6" : "#1A1A1A"),
55462
+ fontFamily: fontFamily || "Inter",
55463
+ fontSize: fontSize || "14px",
55464
+ margin: 0,
55465
+ padding: 0
55466
+ },
55156
55467
  components: {
55157
- p(_ref2) {
55468
+ a(_ref2) {
55158
55469
  let {
55159
55470
  node,
55160
55471
  children
55161
55472
  } = _ref2,
55162
55473
  props = _objectWithoutProperties$1(_ref2, _excluded);
55163
- return /*#__PURE__*/jsxRuntimeExports.jsx("p", _objectSpread2(_objectSpread2({
55164
- className: "mb-2 leading-relaxed ".concat(isDark ? "text-gray-100" : "text-gray-800")
55474
+ return /*#__PURE__*/jsxRuntimeExports.jsx("a", _objectSpread2(_objectSpread2({
55475
+ className: isDark ? "text-blue-400 hover:text-blue-300 hover:underline" : "text-blue-600 hover:underline",
55476
+ target: "_blank",
55477
+ rel: "noopener noreferrer"
55165
55478
  }, props), {}, {
55166
55479
  children: children
55167
55480
  }));
55168
55481
  },
55169
- h1(_ref3) {
55482
+ p(_ref3) {
55170
55483
  let {
55171
55484
  node,
55172
55485
  children
55173
55486
  } = _ref3,
55174
55487
  props = _objectWithoutProperties$1(_ref3, _excluded2);
55175
- return /*#__PURE__*/jsxRuntimeExports.jsx("h1", _objectSpread2(_objectSpread2({
55176
- className: "text-xl font-semibold mt-3 mb-2 ".concat(isDark ? "text-gray-100" : "text-gray-900")
55488
+ return /*#__PURE__*/jsxRuntimeExports.jsx("p", _objectSpread2(_objectSpread2({
55489
+ className: "leading-relaxed [&:not(:last-child)]:mb-2 [&:first-child]:!mt-0",
55490
+ style: {
55491
+ color: textColor || (isDark ? "#f3f4f6" : "#1A1A1A"),
55492
+ fontFamily: fontFamily || "Inter",
55493
+ fontSize: fontSize || "14px",
55494
+ margin: 0,
55495
+ marginTop: 0,
55496
+ padding: 0
55497
+ }
55177
55498
  }, props), {}, {
55178
55499
  children: children
55179
55500
  }));
55180
55501
  },
55181
- h2(_ref4) {
55502
+ ul(_ref4) {
55182
55503
  let {
55183
55504
  node,
55184
55505
  children
55185
55506
  } = _ref4,
55186
55507
  props = _objectWithoutProperties$1(_ref4, _excluded3);
55187
- return /*#__PURE__*/jsxRuntimeExports.jsx("h2", _objectSpread2(_objectSpread2({
55188
- className: "text-lg font-semibold mt-3 mb-2 ".concat(isDark ? "text-gray-100" : "text-gray-900")
55508
+ return /*#__PURE__*/jsxRuntimeExports.jsx("ul", _objectSpread2(_objectSpread2({
55509
+ className: "list-disc pl-5 space-y-1 [&:first-child]:!mt-0",
55510
+ style: {
55511
+ marginTop: 0
55512
+ }
55189
55513
  }, props), {}, {
55190
55514
  children: children
55191
55515
  }));
55192
55516
  },
55193
- h3(_ref5) {
55517
+ ol(_ref5) {
55194
55518
  let {
55195
55519
  node,
55196
55520
  children
55197
55521
  } = _ref5,
55198
55522
  props = _objectWithoutProperties$1(_ref5, _excluded4);
55199
- return /*#__PURE__*/jsxRuntimeExports.jsx("h3", _objectSpread2(_objectSpread2({
55200
- className: "text-base font-semibold mt-3 mb-2 ".concat(isDark ? "text-gray-100" : "text-gray-900")
55523
+ return /*#__PURE__*/jsxRuntimeExports.jsx("ol", _objectSpread2(_objectSpread2({
55524
+ className: "list-decimal pl-5 space-y-1 [&:first-child]:!mt-0",
55525
+ style: {
55526
+ marginTop: 0
55527
+ }
55201
55528
  }, props), {}, {
55202
55529
  children: children
55203
55530
  }));
55204
55531
  },
55205
- code(_ref6) {
55532
+ li(_ref6) {
55206
55533
  let {
55207
- className,
55534
+ node,
55208
55535
  children
55209
55536
  } = _ref6,
55210
55537
  props = _objectWithoutProperties$1(_ref6, _excluded5);
55211
- const match = /language-(\w+)/.exec(className || "");
55212
- if (match) {
55213
- return /*#__PURE__*/jsxRuntimeExports.jsx(SyntaxHighlighter, _objectSpread2(_objectSpread2({
55214
- style: oneDark,
55215
- language: match[1],
55216
- PreTag: "div",
55217
- wrapLines: true
55218
- }, props), {}, {
55219
- children: String(children).replace(/\n$/, "")
55220
- }));
55221
- }
55222
- return /*#__PURE__*/jsxRuntimeExports.jsx("code", _objectSpread2(_objectSpread2({
55223
- className: className
55538
+ return /*#__PURE__*/jsxRuntimeExports.jsx("li", _objectSpread2(_objectSpread2({
55539
+ className: "mb-1",
55540
+ style: {
55541
+ color: textColor || (isDark ? "#f3f4f6" : "#1A1A1A"),
55542
+ fontFamily: fontFamily || "Inter",
55543
+ fontSize: fontSize || "14px"
55544
+ }
55224
55545
  }, props), {}, {
55225
55546
  children: children
55226
55547
  }));
55227
55548
  },
55228
- a(_ref7) {
55549
+ h1(_ref7) {
55229
55550
  let {
55230
55551
  node,
55231
55552
  children
55232
55553
  } = _ref7,
55233
55554
  props = _objectWithoutProperties$1(_ref7, _excluded6);
55234
- return /*#__PURE__*/jsxRuntimeExports.jsx("a", _objectSpread2(_objectSpread2({
55235
- className: isDark ? "text-blue-400 hover:text-blue-300 hover:underline" : "text-blue-600 hover:underline",
55236
- target: "_blank",
55237
- rel: "noopener noreferrer"
55555
+ return /*#__PURE__*/jsxRuntimeExports.jsx("h1", _objectSpread2(_objectSpread2({
55556
+ className: "text-xl font-bold mb-2 [&:first-child]:!mt-0",
55557
+ style: {
55558
+ color: textColor || (isDark ? "#f3f4f6" : "#1A1A1A"),
55559
+ fontFamily: fontFamily || "Inter",
55560
+ marginTop: "0.75rem"
55561
+ }
55238
55562
  }, props), {}, {
55239
55563
  children: children
55240
55564
  }));
55241
55565
  },
55242
- ul(_ref8) {
55566
+ h2(_ref8) {
55243
55567
  let {
55244
55568
  node,
55245
55569
  children
55246
55570
  } = _ref8,
55247
55571
  props = _objectWithoutProperties$1(_ref8, _excluded7);
55248
- return /*#__PURE__*/jsxRuntimeExports.jsx("ul", _objectSpread2(_objectSpread2({
55249
- className: "list-disc space-y-1",
55572
+ return /*#__PURE__*/jsxRuntimeExports.jsx("h2", _objectSpread2(_objectSpread2({
55573
+ className: "text-lg font-semibold mb-2 [&:first-child]:!mt-0",
55250
55574
  style: {
55251
- listStyleType: "disc",
55252
- paddingInlineStart: isRtl ? undefined : "1.25rem",
55253
- paddingInlineEnd: isRtl ? "1.25rem" : undefined,
55254
- marginTop: "0.5rem",
55255
- marginBottom: "0.5rem"
55575
+ color: textColor || (isDark ? "#f3f4f6" : "#1A1A1A"),
55576
+ fontFamily: fontFamily || "Inter",
55577
+ marginTop: "0.75rem"
55256
55578
  }
55257
55579
  }, props), {}, {
55258
55580
  children: children
55259
55581
  }));
55260
55582
  },
55261
- ol(_ref9) {
55583
+ h3(_ref9) {
55262
55584
  let {
55263
55585
  node,
55264
55586
  children
55265
55587
  } = _ref9,
55266
55588
  props = _objectWithoutProperties$1(_ref9, _excluded8);
55267
- return /*#__PURE__*/jsxRuntimeExports.jsx("ol", _objectSpread2(_objectSpread2({
55268
- className: "list-decimal space-y-1",
55589
+ return /*#__PURE__*/jsxRuntimeExports.jsx("h3", _objectSpread2(_objectSpread2({
55590
+ className: "text-base font-semibold mb-2 [&:first-child]:!mt-0",
55269
55591
  style: {
55270
- listStyleType: "decimal",
55271
- paddingInlineStart: isRtl ? undefined : "1.25rem",
55272
- paddingInlineEnd: isRtl ? "1.25rem" : undefined,
55273
- marginTop: "0.5rem",
55274
- marginBottom: "0.5rem"
55592
+ color: textColor || (isDark ? "#f3f4f6" : "#1A1A1A"),
55593
+ fontFamily: fontFamily || "Inter",
55594
+ marginTop: "0.75rem"
55275
55595
  }
55276
55596
  }, props), {}, {
55277
55597
  children: children
@@ -55327,6 +55647,29 @@
55327
55647
  }, props), {}, {
55328
55648
  children: children
55329
55649
  }));
55650
+ },
55651
+ code(_ref12) {
55652
+ let {
55653
+ className,
55654
+ children
55655
+ } = _ref12,
55656
+ props = _objectWithoutProperties$1(_ref12, _excluded11);
55657
+ const match = /language-(\w+)/.exec(className || "");
55658
+ if (match) {
55659
+ return /*#__PURE__*/jsxRuntimeExports.jsx(SyntaxHighlighter, _objectSpread2(_objectSpread2({
55660
+ style: oneDark,
55661
+ language: match[1],
55662
+ PreTag: "div",
55663
+ wrapLines: true
55664
+ }, props), {}, {
55665
+ children: String(children).replace(/\n$/, "")
55666
+ }));
55667
+ }
55668
+ return /*#__PURE__*/jsxRuntimeExports.jsx("code", _objectSpread2(_objectSpread2({
55669
+ className: className
55670
+ }, props), {}, {
55671
+ children: children
55672
+ }));
55330
55673
  }
55331
55674
  },
55332
55675
  children: displayedContent
@@ -55338,34 +55681,54 @@
55338
55681
  })]
55339
55682
  });
55340
55683
  };
55341
- const TypingIndicator = _ref12 => {
55342
- let {
55343
- isDark
55344
- } = _ref12;
55684
+ const TypingIndicator = _ref13 => {
55345
55685
  return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
55346
55686
  className: "flex gap-1.5",
55347
55687
  children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
55348
55688
  className: "w-2 h-2 rounded-full bg-gray-400 animate-bounce",
55349
55689
  style: {
55350
- animationDelay: "0ms",
55351
- backgroundColor: isDark ? "#9CA3AF" : "#9CA3AF"
55690
+ animationDelay: "0ms"
55352
55691
  }
55353
55692
  }), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
55354
55693
  className: "w-2 h-2 rounded-full bg-gray-400 animate-bounce",
55355
55694
  style: {
55356
- animationDelay: "150ms",
55357
- backgroundColor: isDark ? "#9CA3AF" : "#9CA3AF"
55695
+ animationDelay: "150ms"
55358
55696
  }
55359
55697
  }), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
55360
55698
  className: "w-2 h-2 rounded-full bg-gray-400 animate-bounce",
55361
55699
  style: {
55362
- animationDelay: "300ms",
55363
- backgroundColor: isDark ? "#9CA3AF" : "#9CA3AF"
55700
+ animationDelay: "300ms"
55364
55701
  }
55365
55702
  })]
55366
55703
  });
55367
55704
  };
55368
- const AssistantMessage = _ref13 => {
55705
+
55706
+ // Decision widget component for HITL (Human-in-the-Loop)
55707
+ const DecisionWidget = _ref14 => {
55708
+ let {
55709
+ question,
55710
+ options,
55711
+ onDecision,
55712
+ disabled,
55713
+ isDark = false
55714
+ } = _ref14;
55715
+ return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
55716
+ className: "mt-3 p-3 rounded-lg border ".concat(isDark ? "bg-blue-900/30 border-blue-700/50" : "bg-blue-50 border-blue-200"),
55717
+ children: [/*#__PURE__*/jsxRuntimeExports.jsx("p", {
55718
+ className: "text-sm font-medium mb-2 ".concat(isDark ? "text-gray-100" : "text-gray-900"),
55719
+ children: question
55720
+ }), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
55721
+ className: "space-y-2",
55722
+ children: options.map(option => /*#__PURE__*/jsxRuntimeExports.jsx("button", {
55723
+ onClick: () => onDecision(option.id, option.label),
55724
+ disabled: disabled,
55725
+ className: "w-full text-left px-3 py-2 text-sm rounded transition-all ".concat(isDark ? "bg-gray-800 border border-gray-700 hover:bg-blue-900/50 hover:border-blue-600 disabled:opacity-50 disabled:cursor-not-allowed" : "bg-white border border-gray-300 hover:bg-blue-50 hover:border-blue-400 disabled:opacity-50 disabled:cursor-not-allowed"),
55726
+ children: option.label
55727
+ }, option.id))
55728
+ })]
55729
+ });
55730
+ };
55731
+ const AssistantMessage = _ref15 => {
55369
55732
  let {
55370
55733
  message,
55371
55734
  formatTime,
@@ -55373,28 +55736,47 @@
55373
55736
  primaryColor,
55374
55737
  agentMessageBubbleColor,
55375
55738
  textColor,
55739
+ assistantTextColor,
55376
55740
  fontFamily,
55377
55741
  fontSize,
55378
- isRtl
55379
- } = _ref13;
55742
+ isRtl,
55743
+ onDecision,
55744
+ companyLogo,
55745
+ conciergeName,
55746
+ companyName
55747
+ } = _ref15;
55380
55748
  const displayContent = typeof message.content === "string" ? message.content : "";
55381
55749
  const isTypingMessage = message.isProcessing && (!displayContent || displayContent.length === 0);
55382
- const bubbleColor = agentMessageBubbleColor || (isDark ? "#1f2937" : "#FFFFFF");
55383
- const messageTextColor = textColor || (isDark ? "#f3f4f6" : "#1f2937");
55384
- const messageFontFamily = fontFamily || "Inter";
55385
- const messageFontSize = fontSize || "14px";
55750
+ const bubbleColor = agentMessageBubbleColor !== undefined && agentMessageBubbleColor !== null ? agentMessageBubbleColor : isDark ? "#1f2937" : "#FFFFFF";
55751
+ const messageTextColor = assistantTextColor !== undefined && assistantTextColor !== null ? assistantTextColor : textColor !== undefined && textColor !== null ? textColor : isDark ? "#f3f4f6" : "#1A1A1A";
55752
+ const messageFontFamily = fontFamily !== undefined && fontFamily !== null ? fontFamily : "Inter";
55753
+ const messageFontSize = fontSize !== undefined && fontSize !== null ? fontSize : "14px";
55386
55754
  useGoogleFont(messageFontFamily);
55387
55755
  return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
55388
55756
  className: "flex gap-3 flex-row animate-in",
55389
55757
  children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
55390
55758
  className: "flex-shrink-0 mt-1",
55391
55759
  children: /*#__PURE__*/jsxRuntimeExports.jsx("div", {
55392
- className: "w-8 h-8 rounded-full flex items-center justify-center ".concat(isDark ? "bg-gray-700" : "bg-gray-200"),
55393
- children: /*#__PURE__*/jsxRuntimeExports.jsx(Bot, {
55394
- className: "w-4 h-4",
55760
+ className: "w-8 h-8 rounded-full flex items-center justify-center overflow-hidden ".concat(isDark ? "bg-gray-700" : "bg-gray-200"),
55761
+ children: companyLogo ? /*#__PURE__*/jsxRuntimeExports.jsx("div", {
55762
+ className: "w-full h-full flex items-center justify-center",
55763
+ children: /*#__PURE__*/jsxRuntimeExports.jsx("img", {
55764
+ src: companyLogo,
55765
+ alt: "Company logo",
55766
+ className: "w-full h-full object-cover rounded-full",
55767
+ style: {
55768
+ maxWidth: "100%",
55769
+ maxHeight: "100%"
55770
+ }
55771
+ })
55772
+ }) : /*#__PURE__*/jsxRuntimeExports.jsx("div", {
55773
+ className: "w-full h-full flex items-center justify-center text-white font-semibold",
55395
55774
  style: {
55396
- color: primaryColor
55397
- }
55775
+ backgroundColor: primaryColor,
55776
+ fontSize: "14px",
55777
+ fontFamily: fontFamily || "Inter"
55778
+ },
55779
+ children: (conciergeName || companyName || "A").charAt(0).toUpperCase()
55398
55780
  })
55399
55781
  })
55400
55782
  }), /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
@@ -55411,35 +55793,64 @@
55411
55793
  },
55412
55794
  children: isTypingMessage ? /*#__PURE__*/jsxRuntimeExports.jsx(TypingIndicator, {
55413
55795
  isDark: isDark
55414
- }) : displayContent ? /*#__PURE__*/jsxRuntimeExports.jsx(StreamingMarkdown, {
55415
- content: displayContent,
55416
- isStreaming: message.isProcessing,
55417
- isDark: isDark,
55418
- isRtl: isRtl
55419
- }) : null
55796
+ }) : /*#__PURE__*/jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, {
55797
+ children: message.requiresDecision && message.decisionData && onDecision ? /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
55798
+ children: [displayContent && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
55799
+ className: "mb-3",
55800
+ children: /*#__PURE__*/jsxRuntimeExports.jsx(StreamingMarkdown, {
55801
+ content: displayContent,
55802
+ isStreaming: message.isProcessing,
55803
+ isDark: isDark,
55804
+ isRtl: isRtl,
55805
+ textColor: messageTextColor,
55806
+ fontFamily: messageFontFamily,
55807
+ fontSize: messageFontSize
55808
+ })
55809
+ }), /*#__PURE__*/jsxRuntimeExports.jsx(DecisionWidget, {
55810
+ question: message.decisionData.question,
55811
+ options: message.decisionData.options,
55812
+ onDecision: (optionId, optionValue) => onDecision(message.decisionData.decisionId, optionId, optionValue),
55813
+ disabled: !!message.decisionResponse,
55814
+ isDark: isDark
55815
+ }), message.decisionResponse && /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
55816
+ className: "mt-2 text-xs ".concat(isDark ? "text-gray-400" : "text-gray-500"),
55817
+ children: ["Selected: ", message.decisionResponse.selectedOption]
55818
+ })]
55819
+ }) : displayContent ? /*#__PURE__*/jsxRuntimeExports.jsx(StreamingMarkdown, {
55820
+ content: displayContent,
55821
+ isStreaming: message.isProcessing,
55822
+ isDark: isDark,
55823
+ isRtl: isRtl,
55824
+ textColor: messageTextColor,
55825
+ fontFamily: messageFontFamily,
55826
+ fontSize: messageFontSize
55827
+ }) : null
55828
+ })
55420
55829
  }), /*#__PURE__*/jsxRuntimeExports.jsx("p", {
55421
55830
  className: "text-[11px] mt-1.5 px-1 ".concat(isDark ? "text-gray-500" : "text-gray-400"),
55831
+ dir: "ltr",
55422
55832
  children: formatTime(message.timestamp)
55423
55833
  })]
55424
55834
  })]
55425
55835
  });
55426
55836
  };
55427
- const UserMessage = _ref14 => {
55837
+ const UserMessage = _ref16 => {
55428
55838
  let {
55429
55839
  message,
55430
55840
  formatTime,
55431
55841
  userMessageBoxColor,
55432
55842
  primaryColor,
55433
55843
  textColor,
55844
+ userTextColor,
55434
55845
  fontFamily,
55435
55846
  fontSize,
55436
55847
  isDark,
55437
55848
  isRtl
55438
- } = _ref14;
55439
- const primary = userMessageBoxColor || primaryColor || "#2563eb";
55440
- const messageTextColor = textColor || "#FFFFFF";
55441
- const messageFontFamily = fontFamily || "Inter";
55442
- const messageFontSize = fontSize || "14px";
55849
+ } = _ref16;
55850
+ const primary = userMessageBoxColor !== undefined && userMessageBoxColor !== null ? userMessageBoxColor : primaryColor !== undefined && primaryColor !== null ? primaryColor : "#2563eb";
55851
+ const messageTextColor = userTextColor !== undefined && userTextColor !== null ? userTextColor : textColor !== undefined && textColor !== null ? textColor : "#FFFFFF";
55852
+ const messageFontFamily = fontFamily !== undefined && fontFamily !== null ? fontFamily : "Inter";
55853
+ const messageFontSize = fontSize !== undefined && fontSize !== null ? fontSize : "14px";
55443
55854
  useGoogleFont(messageFontFamily);
55444
55855
  return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
55445
55856
  className: "flex gap-3 flex-row-reverse animate-in",
@@ -55458,26 +55869,31 @@
55458
55869
  style: {
55459
55870
  background: "linear-gradient(135deg, ".concat(primary, " 0%, ").concat(primary, "dd 100%)"),
55460
55871
  fontFamily: messageFontFamily,
55461
- fontSize: messageFontSize,
55462
55872
  textAlign: isRtl ? "right" : "left",
55463
55873
  direction: isRtl ? "rtl" : "ltr"
55464
55874
  },
55465
55875
  children: /*#__PURE__*/jsxRuntimeExports.jsx("p", {
55466
- className: "leading-relaxed whitespace-pre-wrap break-words",
55876
+ className: "whitespace-pre-wrap break-words",
55467
55877
  style: {
55468
55878
  color: messageTextColor,
55469
- textAlign: isRtl ? "right" : "left"
55879
+ fontFamily: messageFontFamily,
55880
+ fontSize: messageFontSize,
55881
+ lineHeight: "1.5",
55882
+ textAlign: isRtl ? "right" : "left",
55883
+ margin: 0,
55884
+ padding: 0
55470
55885
  },
55471
55886
  children: message.content
55472
55887
  })
55473
55888
  }), /*#__PURE__*/jsxRuntimeExports.jsx("p", {
55474
55889
  className: "text-[11px] mt-1.5 px-1 ".concat(isDark ? "text-gray-500" : "text-gray-400"),
55890
+ dir: "ltr",
55475
55891
  children: formatTime(message.timestamp)
55476
55892
  })]
55477
55893
  })]
55478
55894
  });
55479
55895
  };
55480
- const MessageBubble = _ref15 => {
55896
+ const MessageBubble = _ref17 => {
55481
55897
  let {
55482
55898
  message,
55483
55899
  isDark,
@@ -55485,11 +55901,17 @@
55485
55901
  agentMessageBubbleColor,
55486
55902
  userMessageBoxColor,
55487
55903
  textColor,
55904
+ assistantTextColor,
55905
+ userTextColor,
55488
55906
  fontFamily,
55489
55907
  fontSize,
55490
55908
  formatTime,
55491
- isRtl
55492
- } = _ref15;
55909
+ isRtl,
55910
+ onDecision,
55911
+ companyLogo,
55912
+ conciergeName,
55913
+ companyName
55914
+ } = _ref17;
55493
55915
  if (!message) {
55494
55916
  return null;
55495
55917
  }
@@ -55500,6 +55922,7 @@
55500
55922
  userMessageBoxColor: userMessageBoxColor,
55501
55923
  primaryColor: primaryColor,
55502
55924
  textColor: textColor,
55925
+ userTextColor: userTextColor,
55503
55926
  fontFamily: fontFamily,
55504
55927
  fontSize: fontSize,
55505
55928
  isDark: isDark,
@@ -55513,9 +55936,14 @@
55513
55936
  primaryColor: primaryColor,
55514
55937
  agentMessageBubbleColor: agentMessageBubbleColor,
55515
55938
  textColor: textColor,
55939
+ assistantTextColor: assistantTextColor,
55516
55940
  fontFamily: fontFamily,
55517
55941
  fontSize: fontSize,
55518
- isRtl: isRtl
55942
+ isRtl: isRtl,
55943
+ onDecision: onDecision,
55944
+ companyLogo: companyLogo,
55945
+ conciergeName: conciergeName,
55946
+ companyName: companyName
55519
55947
  });
55520
55948
  };
55521
55949
 
@@ -55696,6 +56124,7 @@
55696
56124
  };
55697
56125
  };
55698
56126
  const QuickQuestions = _ref3 => {
56127
+ var _ref4;
55699
56128
  let {
55700
56129
  questions = [],
55701
56130
  isDark = false,
@@ -55706,12 +56135,15 @@
55706
56135
  fontFamily = "Inter",
55707
56136
  fontSize = "14px",
55708
56137
  textColor,
55709
- isRtl = false
56138
+ isRtl = false,
56139
+ questionTextColor,
56140
+ questionBoxColor
55710
56141
  } = _ref3;
55711
56142
  if (!questions.length || isTyping) {
55712
56143
  return null;
55713
56144
  }
55714
- const resolvedTextColor = textColor !== null && textColor !== void 0 ? textColor : isDark ? "#f3f4f6" : "#111827";
56145
+ const resolvedTextColor = (_ref4 = questionTextColor !== null && questionTextColor !== void 0 ? questionTextColor : textColor) !== null && _ref4 !== void 0 ? _ref4 : isDark ? "#f3f4f6" : "#111827";
56146
+ const resolvedQuestionBoxColor = questionBoxColor !== null && questionBoxColor !== void 0 ? questionBoxColor : isDark ? "#374151" : "#e5e7eb";
55715
56147
  const palette = reactExports.useMemo(() => getQuickQuestionPalette(resolvedTextColor, isDark), [resolvedTextColor, isDark]);
55716
56148
  const applyHoverState = (element, isHover) => {
55717
56149
  element.style.backgroundColor = isHover ? palette.hoverBackground : palette.background;
@@ -55760,11 +56192,19 @@
55760
56192
  })]
55761
56193
  });
55762
56194
  }
55763
- return /*#__PURE__*/jsxRuntimeExports.jsx("div", {
55764
- className: "space-y-3 flex flex-col items-start",
56195
+
56196
+ // Vertical layout (default)
56197
+ return /*#__PURE__*/jsxRuntimeExports.jsx("div", _objectSpread2(_objectSpread2({
56198
+ className: "space-y-3 flex flex-col items-start pl-[50px]"
56199
+ }, isRtl && {
56200
+ style: {
56201
+ paddingLeft: "0",
56202
+ paddingRight: "50px"
56203
+ }
56204
+ }), {}, {
55765
56205
  children: questions.map((question, index) => /*#__PURE__*/jsxRuntimeExports.jsxs("button", {
55766
56206
  onClick: () => onQuestionClick === null || onQuestionClick === void 0 ? void 0 : onQuestionClick(question),
55767
- className: "group relative text-sm px-5 py-3 rounded-2xl font-medium transition-all duration-300 hover:scale-[1.02] active:scale-[0.98] whitespace-normal max-w-[85%] overflow-hidden backdrop-blur-sm ".concat(isRtl ? "text-right" : "text-left"),
56207
+ className: "group relative text-sm px-3 py-3 rounded-2xl font-medium transition-all duration-300 hover:scale-[1.02] active:scale-[0.98] whitespace-normal max-w-[85%] overflow-hidden backdrop-blur-sm ".concat(isRtl ? "text-right" : "text-left"),
55768
56208
  style: {
55769
56209
  direction: isRtl ? "rtl" : "ltr",
55770
56210
  backgroundColor: palette.background,
@@ -55778,26 +56218,61 @@
55778
56218
  applyHoverState(e.currentTarget, false);
55779
56219
  },
55780
56220
  children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
55781
- className: "absolute inset-0 bg-gradient-to-br from-white/0 via-white/0 to-white/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300 rounded-2xl"
55782
- }), /*#__PURE__*/jsxRuntimeExports.jsxs("span", {
56221
+ style: {
56222
+ backgroundColor: "#F5F5F5",
56223
+ border: "1px solid ".concat(resolvedQuestionBoxColor)
56224
+ },
56225
+ className: "absolute inset-0 transition-opacity duration-300 rounded-2xl"
56226
+ }), /*#__PURE__*/jsxRuntimeExports.jsx("span", {
55783
56227
  className: "relative z-10 flex items-center gap-2.5 text-left",
55784
- children: [/*#__PURE__*/jsxRuntimeExports.jsx(MessageCircleQuestion, {
55785
- className: "h-4 w-4 opacity-60 group-hover:opacity-100 transition-opacity duration-300 flex-shrink-0",
55786
- style: {
55787
- color: primaryColor
55788
- }
55789
- }), /*#__PURE__*/jsxRuntimeExports.jsx("span", {
56228
+ children: /*#__PURE__*/jsxRuntimeExports.jsx("span", {
55790
56229
  className: "flex-1 leading-snug ".concat(isRtl ? "text-right" : "text-left"),
55791
56230
  style: {
55792
56231
  direction: isRtl ? "rtl" : "ltr",
55793
- color: resolvedTextColor,
56232
+ color: "#1A1A1A",
55794
56233
  fontFamily,
55795
56234
  fontSize
55796
56235
  },
55797
56236
  children: question
55798
- })]
56237
+ })
55799
56238
  })]
55800
56239
  }, index))
56240
+ }));
56241
+ };
56242
+
56243
+ const LoadingState = _ref => {
56244
+ let {
56245
+ title,
56246
+ description,
56247
+ isAnimated = false
56248
+ } = _ref;
56249
+ return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
56250
+ className: "flex flex-col items-center justify-center py-12 px-4",
56251
+ children: [isAnimated && /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
56252
+ className: "flex gap-1.5 mb-4",
56253
+ children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
56254
+ className: "w-2 h-2 rounded-full bg-gray-400 animate-bounce",
56255
+ style: {
56256
+ animationDelay: "0ms"
56257
+ }
56258
+ }), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
56259
+ className: "w-2 h-2 rounded-full bg-gray-400 animate-bounce",
56260
+ style: {
56261
+ animationDelay: "150ms"
56262
+ }
56263
+ }), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
56264
+ className: "w-2 h-2 rounded-full bg-gray-400 animate-bounce",
56265
+ style: {
56266
+ animationDelay: "300ms"
56267
+ }
56268
+ })]
56269
+ }), title && /*#__PURE__*/jsxRuntimeExports.jsx("h3", {
56270
+ className: "text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",
56271
+ children: title
56272
+ }), description && /*#__PURE__*/jsxRuntimeExports.jsx("p", {
56273
+ className: "text-xs text-gray-500 dark:text-gray-400 text-center max-w-xs",
56274
+ children: description
56275
+ })]
55801
56276
  });
55802
56277
  };
55803
56278
 
@@ -55810,6 +56285,8 @@
55810
56285
  agentMessageBubbleColor,
55811
56286
  userMessageBoxColor,
55812
56287
  textColor,
56288
+ assistantTextColor,
56289
+ userTextColor,
55813
56290
  fontFamily,
55814
56291
  fontSize,
55815
56292
  formatTime,
@@ -55817,9 +56294,20 @@
55817
56294
  quickQuestions = [],
55818
56295
  shouldShowQuickQuestions = false,
55819
56296
  onQuickQuestion,
55820
- quickQuestionsLayout = "vertical"
56297
+ quickQuestionsLayout = "vertical",
56298
+ onDecision,
56299
+ disclaimerText,
56300
+ disclaimerPosition = "top",
56301
+ resolvedAgentBubbleColor,
56302
+ resolvedUserMessageColor,
56303
+ resolvedTextColor,
56304
+ isVoiceSessionActive = false,
56305
+ voiceStatus = "idle",
56306
+ messagesContainerRef,
56307
+ companyLogo,
56308
+ conciergeName,
56309
+ companyName
55821
56310
  } = _ref;
55822
- const containerRef = reactExports.useRef(null);
55823
56311
  const messagesEndRef = reactExports.useRef(null);
55824
56312
  const shouldAutoScrollRef = reactExports.useRef(true);
55825
56313
  const autoScrollKey = reactExports.useMemo(() => messages.map(message => {
@@ -55827,15 +56315,15 @@
55827
56315
  return "".concat(message.id, ":").concat((_message$content$leng = (_message$content = message.content) === null || _message$content === void 0 ? void 0 : _message$content.length) !== null && _message$content$leng !== void 0 ? _message$content$leng : 0, ":").concat(message.isProcessing ? 1 : 0);
55828
56316
  }).join("|"), [messages]);
55829
56317
  const updateAutoScrollIntent = reactExports.useCallback(() => {
55830
- const container = containerRef.current;
56318
+ const container = messagesContainerRef === null || messagesContainerRef === void 0 ? void 0 : messagesContainerRef.current;
55831
56319
  if (!container) {
55832
56320
  return;
55833
56321
  }
55834
56322
  const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight;
55835
56323
  shouldAutoScrollRef.current = distanceFromBottom < 160;
55836
- }, []);
56324
+ }, [messagesContainerRef]);
55837
56325
  reactExports.useEffect(() => {
55838
- const container = containerRef.current;
56326
+ const container = messagesContainerRef === null || messagesContainerRef === void 0 ? void 0 : messagesContainerRef.current;
55839
56327
  if (!container) {
55840
56328
  return undefined;
55841
56329
  }
@@ -55846,7 +56334,7 @@
55846
56334
  return () => {
55847
56335
  container.removeEventListener("scroll", updateAutoScrollIntent);
55848
56336
  };
55849
- }, [updateAutoScrollIntent]);
56337
+ }, [updateAutoScrollIntent, messagesContainerRef]);
55850
56338
  reactExports.useEffect(() => {
55851
56339
  if (!shouldAutoScrollRef.current) {
55852
56340
  return undefined;
@@ -55865,20 +56353,55 @@
55865
56353
  window.cancelAnimationFrame(frame);
55866
56354
  };
55867
56355
  }, [autoScrollKey, isLoading]);
55868
- return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
55869
- ref: containerRef,
55870
- className: "chat-messages flex-1 overflow-y-auto px-5 py-4 space-y-4 min-h-0 ".concat(isDark ? "bg-gray-900" : "bg-gradient-to-b from-gray-50/50 to-white", " break-words"),
55871
- children: [messages.map(message => /*#__PURE__*/jsxRuntimeExports.jsx(MessageBubble, {
56356
+ return /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
56357
+ children: [isVoiceSessionActive && messages.length === 0 && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
56358
+ className: "flex flex-col items-center justify-center h-full",
56359
+ children: /*#__PURE__*/jsxRuntimeExports.jsx(LoadingState, {
56360
+ title: "Starting voice session...",
56361
+ description: "Allow microphone access or begin speaking to continue.",
56362
+ isAnimated: true
56363
+ })
56364
+ }), disclaimerText && disclaimerPosition === "top" && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
56365
+ className: "flex justify-center",
56366
+ children: /*#__PURE__*/jsxRuntimeExports.jsx("div", {
56367
+ className: "rounded-lg px-2 py-1 max-w-[85%] border",
56368
+ style: {
56369
+ backgroundColor: agentMessageBubbleColor !== undefined && agentMessageBubbleColor !== null ? agentMessageBubbleColor : resolvedAgentBubbleColor || "#F5F5F5",
56370
+ color: assistantTextColor !== undefined && assistantTextColor !== null ? assistantTextColor : "#1A1A1A",
56371
+ fontFamily: fontFamily !== undefined && fontFamily !== null ? fontFamily : "Inter",
56372
+ fontSize: fontSize !== undefined && fontSize !== null ? "calc(".concat(fontSize, " - 2px)") : "12px",
56373
+ direction: isRtl ? "rtl" : "ltr",
56374
+ textAlign: "center",
56375
+ borderColor: isDark ? "#374151" : "#e5e7eb"
56376
+ },
56377
+ children: /*#__PURE__*/jsxRuntimeExports.jsx("p", {
56378
+ className: "leading-relaxed whitespace-pre-wrap break-words",
56379
+ dir: isRtl ? "rtl" : "ltr",
56380
+ style: {
56381
+ color: assistantTextColor !== undefined && assistantTextColor !== null ? assistantTextColor : "#1A1A1A",
56382
+ fontFamily: fontFamily !== undefined && fontFamily !== null ? fontFamily : "Inter",
56383
+ fontSize: fontSize !== undefined && fontSize !== null ? "calc(".concat(fontSize, " - 2px)") : "12px"
56384
+ },
56385
+ children: disclaimerText
56386
+ })
56387
+ })
56388
+ }), messages.map(message => /*#__PURE__*/jsxRuntimeExports.jsx(MessageBubble, {
55872
56389
  message: message,
55873
56390
  isDark: isDark,
55874
56391
  primaryColor: primaryColor,
55875
56392
  agentMessageBubbleColor: agentMessageBubbleColor,
55876
56393
  userMessageBoxColor: userMessageBoxColor,
55877
56394
  textColor: textColor,
56395
+ assistantTextColor: assistantTextColor,
56396
+ userTextColor: userTextColor,
55878
56397
  fontFamily: fontFamily,
55879
56398
  fontSize: fontSize,
55880
56399
  formatTime: formatTime,
55881
- isRtl: isRtl
56400
+ isRtl: isRtl,
56401
+ onDecision: onDecision,
56402
+ companyLogo: companyLogo,
56403
+ conciergeName: conciergeName,
56404
+ companyName: companyName
55882
56405
  }, message.id)), shouldShowQuickQuestions && quickQuestions.length > 0 && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
55883
56406
  className: "pt-1",
55884
56407
  children: /*#__PURE__*/jsxRuntimeExports.jsx(QuickQuestions, {
@@ -55891,7 +56414,9 @@
55891
56414
  fontFamily: fontFamily,
55892
56415
  fontSize: fontSize,
55893
56416
  textColor: textColor,
55894
- isRtl: isRtl
56417
+ isRtl: isRtl,
56418
+ questionTextColor: assistantTextColor,
56419
+ questionBoxColor: agentMessageBubbleColor
55895
56420
  })
55896
56421
  }), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
55897
56422
  ref: messagesEndRef,
@@ -55914,7 +56439,15 @@
55914
56439
  textColor,
55915
56440
  fontFamily,
55916
56441
  fontSize,
55917
- isRtl = false
56442
+ isRtl = false,
56443
+ enableVoiceInteraction = false,
56444
+ isVoiceSessionActive = false,
56445
+ voiceStatus = "idle",
56446
+ voiceError = null,
56447
+ onVoiceToggle,
56448
+ onBidiSubmit,
56449
+ disclaimerText,
56450
+ disclaimerPosition = "top"
55918
56451
  } = _ref;
55919
56452
  const textareaRef = reactExports.useRef(null);
55920
56453
  useGoogleFont(fontFamily);
@@ -55924,17 +56457,29 @@
55924
56457
  (_textareaRef$current = textareaRef.current) === null || _textareaRef$current === void 0 || _textareaRef$current.focus();
55925
56458
  }
55926
56459
  }, [isOpen, isMinimized]);
56460
+
56461
+ // Auto-resize textarea
55927
56462
  reactExports.useEffect(() => {
55928
56463
  const textarea = textareaRef.current;
55929
56464
  if (textarea) {
56465
+ // Reset height to auto to get accurate scrollHeight
55930
56466
  textarea.style.height = "auto";
55931
- textarea.style.height = "".concat(Math.min(textarea.scrollHeight, 120), "px");
56467
+ // Calculate new height based on scrollHeight
56468
+ const scrollHeight = textarea.scrollHeight;
56469
+ // Ensure minimum height when there's text (lineHeight 1.4 means we need at least ~20px per line)
56470
+ const minHeightWithText = inputValue.trim().length > 0 ? 20 : 48;
56471
+ const newHeight = Math.max(minHeightWithText, Math.min(scrollHeight, 120));
56472
+ textarea.style.height = "".concat(newHeight, "px");
55932
56473
  }
55933
56474
  }, [inputValue]);
55934
56475
  const handleKeyPress = event => {
55935
56476
  if (event.key === "Enter" && !event.shiftKey) {
55936
56477
  event.preventDefault();
55937
- onSend();
56478
+ if (isVoiceSessionActive && onBidiSubmit) {
56479
+ onBidiSubmit();
56480
+ } else {
56481
+ onSend();
56482
+ }
55938
56483
  }
55939
56484
  };
55940
56485
  const handleChange = event => {
@@ -55942,15 +56487,15 @@
55942
56487
  };
55943
56488
  const isDisabled = !inputValue.trim() || isLoading;
55944
56489
  const separatorColor = isDark ? "#374151" : "#e5e7eb";
55945
- return /*#__PURE__*/jsxRuntimeExports.jsx("div", {
56490
+ return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
55946
56491
  className: "px-5 py-4 border-t flex-shrink-0 ".concat(isDark ? "border-gray-700 bg-gray-900" : "border-gray-200 bg-white"),
55947
56492
  style: {
55948
56493
  borderTopColor: separatorColor,
55949
56494
  borderTopWidth: "1px",
55950
56495
  borderTopStyle: "solid"
55951
56496
  },
55952
- children: /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
55953
- className: "flex gap-2.5 items-end",
56497
+ children: [/*#__PURE__*/jsxRuntimeExports.jsxs("div", {
56498
+ className: "flex items-center gap-1.5",
55954
56499
  children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
55955
56500
  className: "flex-1 flex items-center min-h-[48px] ".concat(isDark ? "bg-gray-800" : "bg-gray-50", " rounded-2xl border transition-all duration-200"),
55956
56501
  style: {
@@ -55965,35 +56510,316 @@
55965
56510
  onKeyDown: handleKeyPress,
55966
56511
  placeholder: placeholder || "Type your message...",
55967
56512
  rows: 1,
55968
- disabled: isLoading,
56513
+ disabled: isLoading || isVoiceSessionActive && voiceStatus !== "connected",
55969
56514
  dir: isRtl ? "rtl" : "ltr",
55970
- className: "w-full px-4 py-0 bg-transparent rounded-xl leading-normal ".concat(isDark ? "text-gray-100" : "text-gray-900", " placeholder-gray-400 resize-none outline-none scrollbar-hide"),
56515
+ className: "w-full px-4 bg-transparent rounded-xl leading-normal ".concat(isDark ? "text-gray-100" : "text-gray-900", " placeholder-gray-400 resize-none outline-none scrollbar-hide"),
55971
56516
  style: {
56517
+ height: "auto",
55972
56518
  maxHeight: "120px",
55973
- lineHeight: "48px",
56519
+ minHeight: "48px",
56520
+ paddingTop: inputValue.trim().length > 0 ? "12px" : "0px",
56521
+ paddingBottom: inputValue.trim().length > 0 ? "12px" : "0px",
56522
+ lineHeight: inputValue.trim().length > 0 ? "1.4" : "48px",
55974
56523
  fontFamily: fontFamily || "Inter",
55975
56524
  fontSize: fontSize || "14px",
55976
- color: textColor || (isDark ? "#f3f4f6" : "#111827"),
55977
- textAlign: isRtl ? "right" : "left"
56525
+ color: textColor || (isDark ? "#F5F5F5" : "#1A1A1A"),
56526
+ textAlign: isRtl ? "right" : "left",
56527
+ direction: isRtl ? "rtl" : "ltr",
56528
+ wordSpacing: "0",
56529
+ letterSpacing: "0"
55978
56530
  }
55979
56531
  })
56532
+ }), enableVoiceInteraction && /*#__PURE__*/jsxRuntimeExports.jsx("button", {
56533
+ type: "button",
56534
+ onClick: onVoiceToggle,
56535
+ className: "h-10 w-10 rounded-xl flex items-center justify-center transition-all duration-200 shadow-md ".concat(isVoiceSessionActive ? "bg-red-500 text-white hover:bg-red-600" : isDark ? "bg-gray-800 text-gray-200 hover:bg-gray-700" : "bg-white text-gray-600 hover:bg-gray-100", " ").concat(voiceStatus === "connecting" ? "opacity-60 cursor-not-allowed shadow-none" : ""),
56536
+ disabled: voiceStatus === "connecting",
56537
+ children: voiceStatus === "connecting" ? /*#__PURE__*/jsxRuntimeExports.jsx(Loader2, {
56538
+ className: "w-4 h-4 animate-spin"
56539
+ }) : /*#__PURE__*/jsxRuntimeExports.jsx(AudioLines, {
56540
+ className: "w-4 h-4"
56541
+ })
55980
56542
  }), /*#__PURE__*/jsxRuntimeExports.jsx("button", {
55981
- onClick: onSend,
55982
- disabled: isDisabled,
55983
- className: "h-12 w-12 p-0 rounded-xl transition-all duration-200 flex items-center justify-center shadow-lg disabled:opacity-40 disabled:cursor-not-allowed disabled:shadow-none ".concat(!isDisabled ? "scale-100" : "scale-95"),
56543
+ onClick: isVoiceSessionActive && onBidiSubmit ? onBidiSubmit : onSend,
56544
+ disabled: isDisabled || isVoiceSessionActive && voiceStatus !== "connected",
56545
+ className: "h-10 w-10 rounded-xl transition-all duration-200 flex items-center justify-center shadow-md disabled:opacity-40 disabled:cursor-not-allowed disabled:shadow-none ".concat(inputValue.trim() ? "scale-100" : "scale-95"),
55984
56546
  style: {
55985
- backgroundColor: !isDisabled ? primaryColor : isDark ? "#374151" : "#e5e7eb",
55986
- color: !isDisabled ? "white" : "#9ca3af"
56547
+ backgroundColor: inputValue.trim() ? primaryColor : isDark ? "#374151" : "#e5e7eb",
56548
+ color: inputValue.trim() ? "white" : "#9ca3af"
55987
56549
  },
55988
56550
  "aria-label": "Send message",
55989
56551
  children: /*#__PURE__*/jsxRuntimeExports.jsx(Send, {
55990
- className: "w-5 h-5"
56552
+ className: "w-4 h-4 transition-transform",
56553
+ style: isRtl ? {
56554
+ transform: "rotate(-90deg)"
56555
+ } : undefined
55991
56556
  })
55992
56557
  })]
55993
- })
56558
+ }), isVoiceSessionActive && /*#__PURE__*/jsxRuntimeExports.jsxs("p", {
56559
+ className: "text-[11px] mt-2 px-1 ".concat(voiceStatus === "connected" ? "text-green-500" : "text-gray-500", " flex items-center gap-1"),
56560
+ children: [/*#__PURE__*/jsxRuntimeExports.jsx("span", {
56561
+ className: "w-1.5 h-1.5 rounded-full bg-current inline-flex"
56562
+ }), voiceStatus === "connected" ? "Voice session live — speak or type to converse." : "Connecting to voice session..."]
56563
+ }), voiceError && /*#__PURE__*/jsxRuntimeExports.jsx("p", {
56564
+ className: "text-[11px] mt-1 px-1 text-red-500",
56565
+ children: voiceError
56566
+ }), disclaimerText && disclaimerPosition === "footer" && /*#__PURE__*/jsxRuntimeExports.jsx("p", {
56567
+ className: "text-xs mt-2 text-center",
56568
+ style: {
56569
+ color: isDark ? "#FFFFFF" : "#000000",
56570
+ fontFamily: fontFamily || "Inter",
56571
+ fontSize: fontSize ? "calc(".concat(fontSize, " - 2px)") : "12px",
56572
+ direction: isRtl ? "rtl" : "ltr"
56573
+ },
56574
+ dir: isRtl ? "rtl" : "ltr",
56575
+ children: disclaimerText
56576
+ })]
55994
56577
  });
55995
56578
  };
55996
56579
 
56580
+ const LOGO_MAX_HEIGHT = "3.5rem";
56581
+ const LOGO_MAX_HEIGHT_COMPACT = "2.5rem";
56582
+ const LOGO_MAX_WIDTH_DEFAULT = "4.5rem";
56583
+ const LOGO_MAX_WIDTH_DEFAULT_COMPACT = "3rem";
56584
+ const LOGO_MAX_WIDTH_WIDE = "9rem";
56585
+ const LOGO_MAX_WIDTH_WIDE_COMPACT = "5.5rem";
56586
+ const STATUS_DOT_SIZE = "0.8rem";
56587
+ const STATUS_DOT_SIZE_COMPACT = "0.65rem";
56588
+ const STATUS_DOT_BORDER_WIDTH = "2px";
56589
+ const STATUS_DOT_BORDER_WIDTH_COMPACT = "1.5px";
56590
+ const STATUS_DOT_DEFAULT_COLOR = "#34d399";
56591
+ const STATUS_DOT_OFFSET = "38%";
56592
+ const STATUS_DOT_OFFSET_COMPACT = "22%";
56593
+ const LogoImage = _ref => {
56594
+ let {
56595
+ src,
56596
+ showStatusDot = false,
56597
+ statusColor = STATUS_DOT_DEFAULT_COLOR,
56598
+ size = "default"
56599
+ } = _ref;
56600
+ const [aspect, setAspect] = reactExports.useState("square");
56601
+ const isCompact = size === "compact";
56602
+ reactExports.useEffect(() => {
56603
+ if (typeof window === "undefined" || !src) {
56604
+ return;
56605
+ }
56606
+ const img = new Image();
56607
+ img.src = src;
56608
+ img.onload = () => {
56609
+ if (img.width > img.height) {
56610
+ setAspect("wide");
56611
+ } else if (img.height > img.width) {
56612
+ setAspect("tall");
56613
+ } else {
56614
+ setAspect("square");
56615
+ }
56616
+ };
56617
+ }, [src]);
56618
+ const containerStyle = {
56619
+ position: "relative",
56620
+ display: "inline-flex"
56621
+ };
56622
+ const imageStyle = {
56623
+ display: "block",
56624
+ objectFit: "cover",
56625
+ height: "100%",
56626
+ width: "100%",
56627
+ // borderRadius:'50%',
56628
+ maxHeight: isCompact ? LOGO_MAX_HEIGHT_COMPACT : LOGO_MAX_HEIGHT,
56629
+ maxWidth: isCompact ? LOGO_MAX_WIDTH_DEFAULT_COMPACT : LOGO_MAX_WIDTH_DEFAULT
56630
+ };
56631
+ if (aspect === "wide") {
56632
+ imageStyle.maxWidth = isCompact ? LOGO_MAX_WIDTH_WIDE_COMPACT : LOGO_MAX_WIDTH_WIDE;
56633
+ }
56634
+ if (aspect === "tall") {
56635
+ imageStyle.maxHeight = isCompact ? "3rem" : "4rem";
56636
+ imageStyle.maxWidth = isCompact ? "3rem" : "4rem";
56637
+ }
56638
+ return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
56639
+ style: containerStyle,
56640
+ children: [/*#__PURE__*/jsxRuntimeExports.jsx("img", {
56641
+ src: src,
56642
+ alt: "Logo",
56643
+ style: imageStyle,
56644
+ loading: "lazy"
56645
+ }), showStatusDot && /*#__PURE__*/jsxRuntimeExports.jsx("span", {
56646
+ style: {
56647
+ position: "absolute",
56648
+ bottom: 0,
56649
+ right: 0,
56650
+ width: isCompact ? STATUS_DOT_SIZE_COMPACT : STATUS_DOT_SIZE,
56651
+ height: isCompact ? STATUS_DOT_SIZE_COMPACT : STATUS_DOT_SIZE,
56652
+ borderRadius: "9999px",
56653
+ backgroundColor: statusColor,
56654
+ border: "".concat(isCompact ? STATUS_DOT_BORDER_WIDTH_COMPACT : STATUS_DOT_BORDER_WIDTH, " solid #ffffff"),
56655
+ transform: "translate(".concat(isCompact ? STATUS_DOT_OFFSET_COMPACT : STATUS_DOT_OFFSET, ", ").concat(isCompact ? STATUS_DOT_OFFSET_COMPACT : STATUS_DOT_OFFSET, ")"),
56656
+ pointerEvents: "none"
56657
+ }
56658
+ })]
56659
+ });
56660
+ };
56661
+
56662
+ const ChatHeader = _ref => {
56663
+ let {
56664
+ conciergeName,
56665
+ companyName,
56666
+ companyLogo,
56667
+ primaryColor,
56668
+ isDark,
56669
+ isMinimized = false,
56670
+ textColor,
56671
+ fontFamily,
56672
+ fontSize,
56673
+ onToggleTheme,
56674
+ onMinimize,
56675
+ onClose,
56676
+ headerTextBold = false,
56677
+ headerTextItalic = false
56678
+ } = _ref;
56679
+ useGoogleFont(fontFamily);
56680
+ const agentData = {
56681
+ fontFamily,
56682
+ fontSize,
56683
+ headerTextBold,
56684
+ headerTextItalic,
56685
+ textColor
56686
+ };
56687
+ return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
56688
+ className: "text-white ".concat(isMinimized ? "px-4 py-2.5" : "px-5 py-4", " flex items-center justify-between relative overflow-hidden rounded-t-2xl"),
56689
+ style: {
56690
+ background: "linear-gradient(135deg, ".concat(primaryColor, " 0%, ").concat(primaryColor, "dd 100%)"),
56691
+ fontFamily
56692
+ },
56693
+ children: [/*#__PURE__*/jsxRuntimeExports.jsxs("div", {
56694
+ className: "flex gap-2 w-96",
56695
+ children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
56696
+ className: "absolute inset-0 bg-gradient-to-br from-white/10 to-transparent pointer-events-none"
56697
+ }), companyLogo && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
56698
+ className: "w-[48px] h-[48px] rounded-full overflow-hidden flex items-center justify-center bg-white/10",
56699
+ children: /*#__PURE__*/jsxRuntimeExports.jsx(LogoImage, {
56700
+ src: companyLogo
56701
+ })
56702
+ }), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
56703
+ className: "flex items-center gap-2 ".concat(!companyLogo ? "px-3" : ""),
56704
+ style: {
56705
+ fontFamily: (agentData === null || agentData === void 0 ? void 0 : agentData.fontFamily) || "Inter"
56706
+ },
56707
+ children: /*#__PURE__*/jsxRuntimeExports.jsx("h3", {
56708
+ className: cn("font-semibold leading-tight", (agentData === null || agentData === void 0 ? void 0 : agentData.headerTextBold) && "font-bold", (agentData === null || agentData === void 0 ? void 0 : agentData.headerTextItalic) && "italic"),
56709
+ style: {
56710
+ fontSize: agentData !== null && agentData !== void 0 && agentData.fontSize ? "calc(".concat(agentData.fontSize, " + 2px)") : "15px",
56711
+ color: (agentData === null || agentData === void 0 ? void 0 : agentData.textColor) || "#FFFFFF"
56712
+ },
56713
+ children: companyName
56714
+ })
56715
+ })]
56716
+ }), /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
56717
+ className: "flex items-center gap-0 relative z-10 text-white flex-shrink-0 ml-1",
56718
+ children: [/*#__PURE__*/jsxRuntimeExports.jsx("span", {
56719
+ role: "button",
56720
+ tabIndex: 0,
56721
+ "aria-label": "Toggle theme",
56722
+ onClick: onToggleTheme,
56723
+ onKeyDown: event => {
56724
+ if (event.key === "Enter" || event.key === " ") {
56725
+ event.preventDefault();
56726
+ onToggleTheme === null || onToggleTheme === void 0 || onToggleTheme(event);
56727
+ }
56728
+ },
56729
+ className: "inline-flex h-7 w-7 items-center justify-center cursor-pointer transition-opacity duration-200 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40 rounded-full",
56730
+ children: isDark ? /*#__PURE__*/jsxRuntimeExports.jsx(Sun, {
56731
+ className: "w-3.5 h-3.5",
56732
+ strokeWidth: 1.6
56733
+ }) : /*#__PURE__*/jsxRuntimeExports.jsx(Moon, {
56734
+ className: "w-3.5 h-3.5",
56735
+ strokeWidth: 1.6
56736
+ })
56737
+ }), onMinimize && /*#__PURE__*/jsxRuntimeExports.jsx("span", {
56738
+ role: "button",
56739
+ tabIndex: 0,
56740
+ "aria-label": isMinimized ? "Expand" : "Minimize",
56741
+ onClick: onMinimize,
56742
+ onKeyDown: event => {
56743
+ if (event.key === "Enter" || event.key === " ") {
56744
+ event.preventDefault();
56745
+ onMinimize === null || onMinimize === void 0 || onMinimize(event);
56746
+ }
56747
+ },
56748
+ className: "inline-flex h-7 w-7 items-center justify-center cursor-pointer transition-opacity duration-200 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40 rounded-full",
56749
+ children: isMinimized ? /*#__PURE__*/jsxRuntimeExports.jsx(Maximize2, {
56750
+ className: "w-3.5 h-3.5",
56751
+ strokeWidth: 1.6
56752
+ }) : /*#__PURE__*/jsxRuntimeExports.jsx(Minimize2, {
56753
+ className: "w-3.5 h-3.5",
56754
+ strokeWidth: 1.6
56755
+ })
56756
+ }), /*#__PURE__*/jsxRuntimeExports.jsx("span", {
56757
+ role: "button",
56758
+ tabIndex: 0,
56759
+ "aria-label": "Close",
56760
+ onClick: onClose,
56761
+ onKeyDown: event => {
56762
+ if (event.key === "Enter" || event.key === " ") {
56763
+ event.preventDefault();
56764
+ onClose === null || onClose === void 0 || onClose(event);
56765
+ }
56766
+ },
56767
+ className: "inline-flex h-7 w-7 items-center justify-center cursor-pointer transition-opacity duration-200 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40 rounded-full",
56768
+ children: /*#__PURE__*/jsxRuntimeExports.jsx(X, {
56769
+ className: "w-3.5 h-3.5",
56770
+ strokeWidth: 1.6
56771
+ })
56772
+ })]
56773
+ })]
56774
+ });
56775
+ };
56776
+
56777
+ /**
56778
+ * Auto-scroll hook that scrolls to bottom when dependencies change
56779
+ */
56780
+ function useAutoScroll(containerRef) {
56781
+ let dependencies = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
56782
+ let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
56783
+ const {
56784
+ enabled = true,
56785
+ threshold = 30,
56786
+ behavior = "smooth",
56787
+ delay = 0
56788
+ } = options;
56789
+ const shouldScrollRef = reactExports.useRef(true);
56790
+ reactExports.useRef(0);
56791
+ reactExports.useEffect(() => {
56792
+ if (!enabled || !containerRef.current) {
56793
+ return;
56794
+ }
56795
+ const container = containerRef.current;
56796
+ const checkScrollPosition = () => {
56797
+ const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight;
56798
+ shouldScrollRef.current = distanceFromBottom < threshold;
56799
+ };
56800
+ const handleScroll = () => {
56801
+ checkScrollPosition();
56802
+ };
56803
+ container.addEventListener("scroll", handleScroll, {
56804
+ passive: true
56805
+ });
56806
+ checkScrollPosition();
56807
+ const scrollToBottom = () => {
56808
+ if (shouldScrollRef.current && container) {
56809
+ container.scrollTo({
56810
+ top: container.scrollHeight,
56811
+ behavior
56812
+ });
56813
+ }
56814
+ };
56815
+ const timeoutId = setTimeout(scrollToBottom, delay);
56816
+ return () => {
56817
+ container.removeEventListener("scroll", handleScroll);
56818
+ clearTimeout(timeoutId);
56819
+ };
56820
+ }, [containerRef, enabled, threshold, behavior, delay, ...dependencies]);
56821
+ }
56822
+
55997
56823
  const DEFAULT_AGENT_BUBBLE_COLOR = "#ffffff";
55998
56824
  const DEFAULT_USER_MESSAGE_COLOR = "#f5f5f5";
55999
56825
  const DEFAULT_TEXT_COLOR = "#000000";
@@ -56039,23 +56865,38 @@
56039
56865
  quickQuestionsLayout = "vertical",
56040
56866
  agentMessageBubbleColor,
56041
56867
  userMessageBoxColor,
56868
+ assistantTextColor,
56869
+ userTextColor,
56042
56870
  fontFamily = "Inter",
56043
56871
  fontSize = "14px",
56044
- defaultLanguage = "en"
56872
+ defaultLanguage = "en",
56873
+ onDecision,
56874
+ headerTextBold = false,
56875
+ headerTextItalic = false,
56876
+ enableVoiceInteraction = false,
56877
+ isVoiceSessionActive = false,
56878
+ voiceStatus = "idle",
56879
+ voiceError = null,
56880
+ onVoiceToggle,
56881
+ onBidiSubmit,
56882
+ disclaimerText,
56883
+ disclaimerPosition = "top",
56884
+ apiBaseUrl,
56885
+ apiKey,
56886
+ organizationId
56045
56887
  } = _ref;
56046
56888
  useGoogleFont(fontFamily);
56889
+ const messagesContainerRef = reactExports.useRef(null);
56890
+
56891
+ // Auto-scroll hook
56892
+ useAutoScroll(messagesContainerRef, [messages, isLoading], {
56893
+ enabled: true,
56894
+ threshold: 30,
56895
+ behavior: "smooth",
56896
+ delay: 0
56897
+ });
56047
56898
  const defaultLanguageCode = defaultLanguage === null || defaultLanguage === void 0 || (_defaultLanguage$toLo = defaultLanguage.toLowerCase) === null || _defaultLanguage$toLo === void 0 ? void 0 : _defaultLanguage$toLo.call(defaultLanguage);
56048
56899
  const isRtlLanguage = Boolean(defaultLanguageCode && defaultLanguageCode.startsWith("ar"));
56049
- const basePrimaryColor = primaryColor || "#2563eb";
56050
- const containerStyle = reactExports.useMemo(() => {
56051
- if (isDark) {
56052
- return undefined;
56053
- }
56054
- return {
56055
- backgroundColor: basePrimaryColor
56056
- // borderColor: basePrimaryColor,
56057
- };
56058
- }, [basePrimaryColor, isDark]);
56059
56900
  const resolvedAgentBubbleColor = reactExports.useMemo(() => {
56060
56901
  if (isDark) {
56061
56902
  if (isDefaultColor(agentMessageBubbleColor, DEFAULT_AGENT_BUBBLE_COLOR)) {
@@ -56090,42 +56931,57 @@
56090
56931
  return null;
56091
56932
  }
56092
56933
  return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
56093
- className: "mb-4 ".concat(isDark ? "bg-gray-900 border-gray-700" : "border-transparent", " rounded-2xl shadow-2xl border transition-all duration-300 ").concat(isMinimized ? "w-80" : "w-[380px] h-[650px]", " flex flex-col overflow-hidden min-h-0"),
56094
- style: containerStyle,
56095
- children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
56096
- className: "flex-shrink-0",
56097
- children: /*#__PURE__*/jsxRuntimeExports.jsx(ChatHeader, {
56098
- conciergeName: conciergeName,
56099
- companyName: companyName,
56100
- companyLogo: companyLogo,
56101
- primaryColor: primaryColor,
56102
- isDark: isDark,
56103
- isMinimized: isMinimized,
56104
- textColor: resolvedTextColor,
56105
- fontFamily: fontFamily,
56106
- fontSize: fontSize,
56107
- onToggleTheme: onToggleTheme,
56108
- onMinimize: onMinimize,
56109
- onClose: onClose
56110
- })
56111
- }), !isMinimized && /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
56112
- className: "flex-1 flex flex-col ".concat(isDark ? "bg-gray-900" : "bg-white", " min-h-0"),
56113
- children: [/*#__PURE__*/jsxRuntimeExports.jsx(MessageList, {
56114
- messages: messages,
56115
- isDark: isDark,
56116
- primaryColor: primaryColor,
56117
- isLoading: isLoading,
56118
- agentMessageBubbleColor: resolvedAgentBubbleColor,
56119
- userMessageBoxColor: resolvedUserMessageColor,
56120
- textColor: resolvedTextColor,
56121
- fontFamily: fontFamily,
56122
- fontSize: fontSize,
56123
- formatTime: formatTime,
56124
- isRtl: isRtlLanguage,
56125
- quickQuestions: quickQuestions,
56126
- shouldShowQuickQuestions: shouldShowQuickQuestions,
56127
- onQuickQuestion: onQuickQuestion !== null && onQuickQuestion !== void 0 ? onQuickQuestion : onDirectSend,
56128
- quickQuestionsLayout: quickQuestionsLayout
56934
+ className: "".concat(isMinimized ? "w-80" : "w-[380px]", " max-w-[92vw] flex-shrink-0 border rounded-2xl shadow-2xl bg-white border-gray-200 flex flex-col ").concat(isMinimized ? "h-auto" : "h-[650px] max-h-[85vh]", " overflow-hidden z-50 ").concat(isDark ? "bg-gray-900 border-gray-700" : ""),
56935
+ children: [/*#__PURE__*/jsxRuntimeExports.jsx(ChatHeader, {
56936
+ conciergeName: conciergeName,
56937
+ companyName: companyName,
56938
+ companyLogo: companyLogo,
56939
+ primaryColor: primaryColor,
56940
+ isDark: isDark,
56941
+ isMinimized: isMinimized,
56942
+ textColor: resolvedTextColor,
56943
+ fontFamily: fontFamily,
56944
+ fontSize: fontSize,
56945
+ onToggleTheme: onToggleTheme,
56946
+ onMinimize: onMinimize,
56947
+ onClose: onClose,
56948
+ headerTextBold: headerTextBold,
56949
+ headerTextItalic: headerTextItalic
56950
+ }), !isMinimized && /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
56951
+ children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
56952
+ ref: messagesContainerRef,
56953
+ className: "chat-messages flex-1 overflow-y-auto px-5 py-4 space-y-4 ".concat(isDark ? "bg-gray-900" : "bg-gradient-to-b from-gray-50/50 to-white", " break-words"),
56954
+ children: /*#__PURE__*/jsxRuntimeExports.jsx(MessageList, {
56955
+ messages: messages,
56956
+ isDark: isDark,
56957
+ primaryColor: primaryColor,
56958
+ isLoading: isLoading,
56959
+ agentMessageBubbleColor: agentMessageBubbleColor,
56960
+ userMessageBoxColor: userMessageBoxColor,
56961
+ textColor: textColor,
56962
+ assistantTextColor: assistantTextColor,
56963
+ userTextColor: userTextColor,
56964
+ fontFamily: fontFamily,
56965
+ fontSize: fontSize,
56966
+ formatTime: formatTime,
56967
+ isRtl: isRtlLanguage,
56968
+ quickQuestions: quickQuestions,
56969
+ shouldShowQuickQuestions: shouldShowQuickQuestions,
56970
+ onQuickQuestion: onQuickQuestion !== null && onQuickQuestion !== void 0 ? onQuickQuestion : onDirectSend,
56971
+ quickQuestionsLayout: quickQuestionsLayout,
56972
+ onDecision: onDecision,
56973
+ disclaimerText: disclaimerText,
56974
+ disclaimerPosition: disclaimerPosition,
56975
+ resolvedAgentBubbleColor: resolvedAgentBubbleColor,
56976
+ resolvedUserMessageColor: resolvedUserMessageColor,
56977
+ resolvedTextColor: resolvedTextColor,
56978
+ isVoiceSessionActive: isVoiceSessionActive,
56979
+ voiceStatus: voiceStatus,
56980
+ messagesContainerRef: messagesContainerRef,
56981
+ companyLogo: companyLogo,
56982
+ conciergeName: conciergeName,
56983
+ companyName: companyName
56984
+ })
56129
56985
  }), /*#__PURE__*/jsxRuntimeExports.jsx(ChatInput, {
56130
56986
  inputValue: inputValue,
56131
56987
  setInputValue: setInputValue,
@@ -56139,7 +56995,15 @@
56139
56995
  textColor: resolvedTextColor,
56140
56996
  fontFamily: fontFamily,
56141
56997
  fontSize: fontSize,
56142
- isRtl: isRtlLanguage
56998
+ isRtl: isRtlLanguage,
56999
+ enableVoiceInteraction: enableVoiceInteraction,
57000
+ isVoiceSessionActive: isVoiceSessionActive,
57001
+ voiceStatus: voiceStatus,
57002
+ voiceError: voiceError,
57003
+ onVoiceToggle: onVoiceToggle,
57004
+ onBidiSubmit: onBidiSubmit,
57005
+ disclaimerText: disclaimerText,
57006
+ disclaimerPosition: disclaimerPosition
56143
57007
  })]
56144
57008
  })]
56145
57009
  });
@@ -56150,7 +57014,8 @@
56150
57014
  isOpen,
56151
57015
  isDark,
56152
57016
  primaryColor,
56153
- onToggle
57017
+ onToggle,
57018
+ textColor
56154
57019
  } = _ref;
56155
57020
  return /*#__PURE__*/jsxRuntimeExports.jsxs("button", {
56156
57021
  onClick: onToggle,
@@ -56168,7 +57033,10 @@
56168
57033
  className: "w-7 h-7"
56169
57034
  }) : /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
56170
57035
  children: [/*#__PURE__*/jsxRuntimeExports.jsx(MessageCircle, {
56171
- className: "w-7 h-7"
57036
+ className: "w-7 h-7",
57037
+ style: {
57038
+ color: textColor
57039
+ }
56172
57040
  }), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
56173
57041
  className: "absolute -top-1 -right-1 w-5 h-5 bg-red-500 rounded-full flex items-center justify-center text-[10px] font-bold border-2 border-white animate-pulse",
56174
57042
  children: "1"
@@ -56192,6 +57060,8 @@
56192
57060
  textColor = "#000000",
56193
57061
  agentMessageBubbleColor,
56194
57062
  userMessageBoxColor,
57063
+ assistantTextColor,
57064
+ userTextColor,
56195
57065
  fontFamily = "Inter",
56196
57066
  fontSize = "14px",
56197
57067
  defaultLanguage = "en",
@@ -56201,7 +57071,12 @@
56201
57071
  autoOpen = false,
56202
57072
  openDelay = 0,
56203
57073
  locale = "en",
56204
- className = ""
57074
+ className = "",
57075
+ headerTextBold = false,
57076
+ headerTextItalic = false,
57077
+ enableVoiceInteraction = false,
57078
+ disclaimerText,
57079
+ disclaimerPosition = "top"
56205
57080
  } = _ref;
56206
57081
  const {
56207
57082
  isOpen,
@@ -56218,7 +57093,13 @@
56218
57093
  toggleChat,
56219
57094
  toggleTheme,
56220
57095
  toggleMinimize,
56221
- closeChat
57096
+ closeChat,
57097
+ handleDecision,
57098
+ isVoiceSessionActive,
57099
+ voiceStatus,
57100
+ voiceError,
57101
+ handleVoiceToggle,
57102
+ sendBidiTextMessage
56222
57103
  } = useChatState({
56223
57104
  welcomeMessage,
56224
57105
  quickQuestions,
@@ -56227,7 +57108,8 @@
56227
57108
  organizationId,
56228
57109
  autoOpen,
56229
57110
  openDelay,
56230
- darkMode
57111
+ darkMode,
57112
+ enableVoiceInteraction
56231
57113
  });
56232
57114
 
56233
57115
  // Set CSS variables for theming
@@ -56274,14 +57156,31 @@
56274
57156
  quickQuestionsLayout: quickQuestionsLayout,
56275
57157
  agentMessageBubbleColor: agentMessageBubbleColor,
56276
57158
  userMessageBoxColor: userMessageBoxColor,
57159
+ assistantTextColor: assistantTextColor,
57160
+ userTextColor: userTextColor,
56277
57161
  fontFamily: fontFamily,
56278
57162
  fontSize: fontSize,
56279
- defaultLanguage: defaultLanguage || locale
56280
- }), /*#__PURE__*/jsxRuntimeExports.jsx(ToggleButton, {
57163
+ defaultLanguage: defaultLanguage || locale,
57164
+ onDecision: handleDecision,
57165
+ headerTextBold: headerTextBold,
57166
+ headerTextItalic: headerTextItalic,
57167
+ enableVoiceInteraction: enableVoiceInteraction,
57168
+ isVoiceSessionActive: isVoiceSessionActive,
57169
+ voiceStatus: voiceStatus,
57170
+ voiceError: voiceError,
57171
+ onVoiceToggle: handleVoiceToggle,
57172
+ onBidiSubmit: () => sendBidiTextMessage(inputValue),
57173
+ disclaimerText: disclaimerText,
57174
+ disclaimerPosition: disclaimerPosition,
57175
+ apiBaseUrl: apiBaseUrl,
57176
+ apiKey: apiKey,
57177
+ organizationId: organizationId
57178
+ }), !isOpen && /*#__PURE__*/jsxRuntimeExports.jsx(ToggleButton, {
56281
57179
  isOpen: isOpen,
56282
57180
  isDark: isDark,
56283
57181
  primaryColor: primaryColor,
56284
- onToggle: toggleChat
57182
+ onToggle: toggleChat,
57183
+ textColor: textColor
56285
57184
  })]
56286
57185
  });
56287
57186
  };
@@ -56301,9 +57200,11 @@
56301
57200
  welcomeMessage: 'Hi! How can we help?',
56302
57201
  quickQuestions: [],
56303
57202
  quickQuestionsLayout: 'vertical',
56304
- textColor: '#000000',
57203
+ textColor: '#fcfcfc',
56305
57204
  agentMessageBubbleColor: undefined,
56306
57205
  userMessageBoxColor: undefined,
57206
+ assistantTextColor: undefined,
57207
+ userTextColor: undefined,
56307
57208
  fontFamily: 'Inter',
56308
57209
  fontSize: '14px',
56309
57210
  defaultLanguage: 'en',
@@ -56311,18 +57212,24 @@
56311
57212
  openDelay: 0,
56312
57213
  apiBaseUrl: null,
56313
57214
  apiKey: null,
57215
+ organizationId: null,
56314
57216
  sessionUrl: null,
56315
57217
  userId: null,
56316
57218
  userName: null,
56317
57219
  userEmail: null,
56318
57220
  locale: 'en',
57221
+ headerTextBold: false,
57222
+ headerTextItalic: false,
57223
+ enableVoiceInteraction: false,
57224
+ disclaimerText: undefined,
57225
+ disclaimerPosition: 'top',
56319
57226
  onOpen: null,
56320
57227
  onClose: null
56321
57228
  };
56322
57229
  const API = {
56323
- /**
56324
- * Initialize the chat widget
56325
- * @param {Object} options - Configuration options
57230
+ /**
57231
+ * Initialize the chat widget
57232
+ * @param {Object} options - Configuration options
56326
57233
  */
56327
57234
  init: async function () {
56328
57235
  let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
@@ -56362,17 +57269,17 @@
56362
57269
  }
56363
57270
  return API;
56364
57271
  },
56365
- /**
56366
- * Update configuration
56367
- * @param {Object} newConfig - New configuration options
57272
+ /**
57273
+ * Update configuration
57274
+ * @param {Object} newConfig - New configuration options
56368
57275
  */
56369
57276
  updateConfig: function (newConfig) {
56370
57277
  config = _objectSpread2(_objectSpread2({}, config), newConfig);
56371
57278
  this.init(config);
56372
57279
  return API;
56373
57280
  },
56374
- /**
56375
- * Open the chat widget
57281
+ /**
57282
+ * Open the chat widget
56376
57283
  */
56377
57284
  open: function () {
56378
57285
  // Trigger open by updating config
@@ -56383,8 +57290,8 @@
56383
57290
  if (config.onOpen) config.onOpen();
56384
57291
  return API;
56385
57292
  },
56386
- /**
56387
- * Close the chat widget
57293
+ /**
57294
+ * Close the chat widget
56388
57295
  */
56389
57296
  close: function () {
56390
57297
  this.updateConfig({
@@ -56393,8 +57300,8 @@
56393
57300
  if (config.onClose) config.onClose();
56394
57301
  return API;
56395
57302
  },
56396
- /**
56397
- * Toggle dark mode
57303
+ /**
57304
+ * Toggle dark mode
56398
57305
  */
56399
57306
  toggleTheme: function () {
56400
57307
  config.darkMode = !config.darkMode;
@@ -56403,8 +57310,8 @@
56403
57310
  });
56404
57311
  return API;
56405
57312
  },
56406
- /**
56407
- * Destroy the widget
57313
+ /**
57314
+ * Destroy the widget
56408
57315
  */
56409
57316
  destroy: function () {
56410
57317
  if (root) {
@@ -56419,8 +57326,8 @@
56419
57326
  config = {};
56420
57327
  return API;
56421
57328
  },
56422
- /**
56423
- * Get current configuration
57329
+ /**
57330
+ * Get current configuration
56424
57331
  */
56425
57332
  getConfig: function () {
56426
57333
  return _objectSpread2({}, config);