@unctad-ai/voice-agent-ui 5.2.6 → 5.3.1

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.
@@ -5,7 +5,7 @@ import {
5
5
  SliderSetting,
6
6
  ToggleSetting,
7
7
  VoiceSettingsView
8
- } from "./chunk-3NIMUSO2.js";
8
+ } from "./chunk-QXFECZAT.js";
9
9
  export {
10
10
  Divider,
11
11
  SelectSetting,
@@ -14,4 +14,4 @@ export {
14
14
  ToggleSetting,
15
15
  VoiceSettingsView as default
16
16
  };
17
- //# sourceMappingURL=VoiceSettingsView-FD5HKUJU.js.map
17
+ //# sourceMappingURL=VoiceSettingsView-U7O5H5PC.js.map
@@ -1903,7 +1903,7 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1903
1903
  ) : /* @__PURE__ */ jsx3("span", {}),
1904
1904
  /* @__PURE__ */ jsxs2("span", { children: [
1905
1905
  "Kit v",
1906
- /* @__PURE__ */ jsx3("span", { style: { fontWeight: 500, color: "#6b7280" }, children: "5.2.6" })
1906
+ /* @__PURE__ */ jsx3("span", { style: { fontWeight: 500, color: "#6b7280" }, children: "5.3.1" })
1907
1907
  ] })
1908
1908
  ] }) })
1909
1909
  ]
@@ -1995,4 +1995,4 @@ export {
1995
1995
  SettingsSection,
1996
1996
  Divider
1997
1997
  };
1998
- //# sourceMappingURL=chunk-3NIMUSO2.js.map
1998
+ //# sourceMappingURL=chunk-QXFECZAT.js.map
package/dist/index.d.ts CHANGED
@@ -227,8 +227,10 @@ interface VoiceTranscriptProps {
227
227
  onReport?: (turnNumber: number, assistantMessage: string, userMessage?: string) => void;
228
228
  /** Map of turn numbers to ticket IDs for sent feedback */
229
229
  feedbackSentTurns?: Record<number, string>;
230
+ /** Callback to submit a text message (for suggested prompt chips) */
231
+ onTextSubmit?: (text: string) => void;
230
232
  }
231
- declare function VoiceTranscript({ messages, isTyping, variant, voiceError, voiceState, onStartMic, onSwitchToKeyboard, onReport, feedbackSentTurns, }: VoiceTranscriptProps): react_jsx_runtime.JSX.Element;
233
+ declare function VoiceTranscript({ messages, isTyping, variant, voiceError, voiceState, onStartMic, onSwitchToKeyboard, onReport, feedbackSentTurns, onTextSubmit, }: VoiceTranscriptProps): react_jsx_runtime.JSX.Element;
232
234
 
233
235
  interface VoiceWaveformCanvasProps {
234
236
  analyserNode: AnalyserNode | null;
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  VoiceSettingsProvider,
9
9
  VoiceSettingsView,
10
10
  useVoiceSettings
11
- } from "./chunk-3NIMUSO2.js";
11
+ } from "./chunk-QXFECZAT.js";
12
12
 
13
13
  // src/VoiceAgentProvider.tsx
14
14
  import { SiteConfigProvider } from "@unctad-ai/voice-agent-core";
@@ -665,7 +665,7 @@ import {
665
665
  DEFAULT_FONT_FAMILY,
666
666
  useSiteConfig as useSiteConfig3
667
667
  } from "@unctad-ai/voice-agent-core";
668
- import { ArrowRight, PenLine, MousePointerClick, Search, Info, ChevronDown, Mic, Keyboard, Flag, Copy, Check } from "lucide-react";
668
+ import { ArrowRight, PenLine, MousePointerClick, Search, Info, ChevronDown, Mic, Flag, Copy, Check } from "lucide-react";
669
669
  import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
670
670
  function cleanForDisplay(text) {
671
671
  return text.replace(/\[(laugh|chuckle|sigh|gasp|cough|clear throat|sniff|groan|shush)\]/gi, "").replace(/\*\*(.*?)\*\*/g, "$1").replace(/^\s*\*\s+/gm, "- ").replace(/\*(.*?)\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/^#{1,6}\s+/gm, "").replace(/<br\s*\/?>/gi, "\n").replace(/<[^>]+>/g, "").replace(/\|[-:\s|]+\|/g, "").replace(/\|/g, "\n").replace(/\p{Emoji_Presentation}|\p{Extended_Pictographic}/gu, "").replace(/[ \t]{3,}/g, " ").replace(/\n{3,}/g, "\n\n").replace(/^[\s-]{3,}$/gm, "").trim();
@@ -917,11 +917,13 @@ function VoiceTranscript({
917
917
  onStartMic,
918
918
  onSwitchToKeyboard,
919
919
  onReport,
920
- feedbackSentTurns
920
+ feedbackSentTurns,
921
+ onTextSubmit
921
922
  }) {
922
923
  const config = useSiteConfig3();
923
924
  const fontFamily = config.fontFamily ?? DEFAULT_FONT_FAMILY;
924
925
  const assistantLabel = config.copilotName || "Assistant";
926
+ const { colors } = config;
925
927
  const containerRef = useRef3(null);
926
928
  const isPanel = variant === "panel";
927
929
  const maxVisible = isPanel ? PANEL_MAX_VISIBLE_MESSAGES : MAX_VISIBLE_MESSAGES;
@@ -1074,12 +1076,16 @@ function VoiceTranscript({
1074
1076
  "div",
1075
1077
  {
1076
1078
  style: {
1077
- ...isAI ? {} : {
1078
- backgroundColor: "rgba(219,33,41,0.07)",
1079
- border: "1px solid rgba(219,33,41,0.12)",
1079
+ ...isAI ? {
1080
+ backgroundColor: `${colors.primary}0D`,
1081
+ borderRadius: "14px 14px 14px 4px",
1082
+ padding: "10px 14px",
1083
+ maxWidth: "85%"
1084
+ } : {
1085
+ backgroundColor: "rgba(0,0,0,0.04)",
1080
1086
  borderRadius: "14px 14px 4px 14px",
1081
1087
  padding: "10px 14px",
1082
- maxWidth: "88%"
1088
+ maxWidth: "85%"
1083
1089
  }
1084
1090
  },
1085
1091
  children: isAI && isLast && isTyping ? /* @__PURE__ */ jsx4(
@@ -1198,7 +1204,7 @@ function VoiceTranscript({
1198
1204
  )
1199
1205
  ]
1200
1206
  }
1201
- ) : /* @__PURE__ */ jsx4("div", { style: { paddingTop: 40 }, children: /* @__PURE__ */ jsx4(EmptyStateGraphic, { primaryColor: config.colors.primary }) })),
1207
+ ) : /* @__PURE__ */ jsx4("div", { style: { paddingTop: 40 }, children: /* @__PURE__ */ jsx4(EmptyStateGraphic, { primaryColor: config.colors.primary, onTextSubmit }) })),
1202
1208
  isTyping && visible.length === 0 && /* @__PURE__ */ jsx4(
1203
1209
  motion.p,
1204
1210
  {
@@ -1320,7 +1326,8 @@ function VoiceTranscript({
1320
1326
  primaryColor: config.colors.primary,
1321
1327
  voiceState,
1322
1328
  onStartMic,
1323
- onSwitchToKeyboard
1329
+ onSwitchToKeyboard,
1330
+ onTextSubmit
1324
1331
  }
1325
1332
  ),
1326
1333
  isTyping && visible.length === 0 && /* @__PURE__ */ jsx4(
@@ -1337,8 +1344,11 @@ function VoiceTranscript({
1337
1344
  }
1338
1345
  );
1339
1346
  }
1340
- function EmptyStateGraphic({ primaryColor, voiceState, onStartMic, onSwitchToKeyboard }) {
1347
+ function EmptyStateGraphic({ primaryColor, voiceState, onStartMic, onSwitchToKeyboard, onTextSubmit }) {
1348
+ const config = useSiteConfig3();
1341
1349
  const isListening = voiceState === "LISTENING" || voiceState === "USER_SPEAKING";
1350
+ const greeting = config.greetingMessage || "How can I help you today?";
1351
+ const prompts = config.suggestedPrompts ?? ["What services are available?", "Help me with an application"];
1342
1352
  if (isListening) {
1343
1353
  return /* @__PURE__ */ jsxs3(
1344
1354
  motion.div,
@@ -1355,7 +1365,7 @@ function EmptyStateGraphic({ primaryColor, voiceState, onStartMic, onSwitchToKey
1355
1365
  paddingTop: 60
1356
1366
  },
1357
1367
  children: [
1358
- /* @__PURE__ */ jsx4("p", { style: { fontSize: 16, fontWeight: 500, color: primaryColor, margin: 0, opacity: 0.7 }, children: "Listening..." }),
1368
+ /* @__PURE__ */ jsx4("p", { style: { fontSize: 16, fontWeight: 500, color: primaryColor, margin: 0, opacity: 0.7 }, children: "I'm listening..." }),
1359
1369
  /* @__PURE__ */ jsx4("p", { style: { fontSize: 12, color: "rgba(0,0,0,0.3)", margin: 0 }, children: "Go ahead, I can hear you" })
1360
1370
  ]
1361
1371
  }
@@ -1372,75 +1382,62 @@ function EmptyStateGraphic({ primaryColor, voiceState, onStartMic, onSwitchToKey
1372
1382
  flexDirection: "column",
1373
1383
  alignItems: "center",
1374
1384
  justifyContent: "center",
1375
- gap: 16,
1376
- paddingTop: 60
1385
+ gap: 20,
1386
+ paddingTop: 48
1377
1387
  },
1378
1388
  children: [
1379
- /* @__PURE__ */ jsx4("p", { style: { fontSize: 18, fontWeight: 500, color: primaryColor, margin: 0, opacity: 0.6 }, children: "How can I help?" }),
1380
- /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
1381
- onStartMic && /* @__PURE__ */ jsxs3(
1382
- "button",
1383
- {
1384
- onClick: onStartMic,
1385
- style: {
1386
- display: "flex",
1387
- alignItems: "center",
1388
- gap: 8,
1389
- padding: "8px 16px",
1390
- borderRadius: 20,
1391
- border: `1px solid ${primaryColor}22`,
1392
- backgroundColor: `${primaryColor}08`,
1393
- cursor: "pointer",
1394
- fontFamily: "inherit",
1395
- fontSize: 13,
1396
- color: "rgba(0,0,0,0.5)",
1397
- transition: "background-color 0.15s, border-color 0.15s"
1398
- },
1399
- onMouseEnter: (e) => {
1400
- e.currentTarget.style.backgroundColor = `${primaryColor}14`;
1401
- e.currentTarget.style.borderColor = `${primaryColor}33`;
1402
- },
1403
- onMouseLeave: (e) => {
1404
- e.currentTarget.style.backgroundColor = `${primaryColor}08`;
1405
- e.currentTarget.style.borderColor = `${primaryColor}22`;
1406
- },
1407
- children: [
1408
- /* @__PURE__ */ jsx4(Mic, { style: { width: 14, height: 14, color: primaryColor, opacity: 0.7 } }),
1409
- "Start talking"
1410
- ]
1411
- }
1412
- ),
1413
- onSwitchToKeyboard && /* @__PURE__ */ jsxs3(
1414
- "button",
1415
- {
1416
- onClick: onSwitchToKeyboard,
1417
- style: {
1418
- display: "flex",
1419
- alignItems: "center",
1420
- gap: 8,
1421
- padding: "8px 16px",
1422
- borderRadius: 20,
1423
- border: "1px solid rgba(0,0,0,0.06)",
1424
- backgroundColor: "transparent",
1425
- cursor: "pointer",
1426
- fontFamily: "inherit",
1427
- fontSize: 13,
1428
- color: "rgba(0,0,0,0.35)",
1429
- transition: "background-color 0.15s"
1430
- },
1431
- onMouseEnter: (e) => {
1432
- e.currentTarget.style.backgroundColor = "rgba(0,0,0,0.03)";
1433
- },
1434
- onMouseLeave: (e) => {
1435
- e.currentTarget.style.backgroundColor = "transparent";
1436
- },
1437
- children: [
1438
- /* @__PURE__ */ jsx4(Keyboard, { style: { width: 14, height: 14, opacity: 0.5 } }),
1439
- "Type a message"
1440
- ]
1441
- }
1442
- )
1443
- ] })
1389
+ /* @__PURE__ */ jsx4("p", { style: { fontSize: 17, fontWeight: 500, color: primaryColor, margin: 0, opacity: 0.6, textAlign: "center", lineHeight: 1.4 }, children: greeting }),
1390
+ /* @__PURE__ */ jsx4("div", { style: { display: "flex", flexWrap: "wrap", gap: 8, justifyContent: "center", maxWidth: 320 }, children: prompts.map((prompt) => /* @__PURE__ */ jsx4(
1391
+ "button",
1392
+ {
1393
+ onClick: () => onTextSubmit?.(prompt),
1394
+ style: {
1395
+ padding: "8px 16px",
1396
+ borderRadius: 18,
1397
+ border: "1px solid rgba(0,0,0,0.1)",
1398
+ backgroundColor: "transparent",
1399
+ cursor: "pointer",
1400
+ fontFamily: "inherit",
1401
+ fontSize: 13,
1402
+ color: "rgba(0,0,0,0.55)",
1403
+ transition: "background-color 0.15s, border-color 0.15s",
1404
+ lineHeight: 1.3
1405
+ },
1406
+ onMouseEnter: (e) => {
1407
+ e.currentTarget.style.backgroundColor = `${primaryColor}0A`;
1408
+ e.currentTarget.style.borderColor = `${primaryColor}33`;
1409
+ },
1410
+ onMouseLeave: (e) => {
1411
+ e.currentTarget.style.backgroundColor = "transparent";
1412
+ e.currentTarget.style.borderColor = "rgba(0,0,0,0.1)";
1413
+ },
1414
+ children: prompt
1415
+ },
1416
+ prompt
1417
+ )) }),
1418
+ /* @__PURE__ */ jsx4("div", { style: { display: "flex", gap: 12, marginTop: 4 }, children: onStartMic && /* @__PURE__ */ jsxs3(
1419
+ "button",
1420
+ {
1421
+ onClick: onStartMic,
1422
+ style: {
1423
+ display: "flex",
1424
+ alignItems: "center",
1425
+ gap: 6,
1426
+ padding: "6px 14px",
1427
+ borderRadius: 16,
1428
+ border: "none",
1429
+ backgroundColor: `${primaryColor}0A`,
1430
+ cursor: "pointer",
1431
+ fontFamily: "inherit",
1432
+ fontSize: 12,
1433
+ color: "rgba(0,0,0,0.4)"
1434
+ },
1435
+ children: [
1436
+ /* @__PURE__ */ jsx4(Mic, { style: { width: 12, height: 12, opacity: 0.5 } }),
1437
+ "or speak"
1438
+ ]
1439
+ }
1440
+ ) })
1444
1441
  ]
1445
1442
  }
1446
1443
  );
@@ -1764,7 +1761,7 @@ function PipelineMetricsBar({
1764
1761
 
1765
1762
  // src/components/GlassCopilotPanel.tsx
1766
1763
  import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1767
- var VoiceSettingsView2 = lazy(() => import("./VoiceSettingsView-FD5HKUJU.js"));
1764
+ var VoiceSettingsView2 = lazy(() => import("./VoiceSettingsView-U7O5H5PC.js"));
1768
1765
  var RETRY_INITIAL_MS = 3e3;
1769
1766
  var RETRY_MAX_MS = 3e4;
1770
1767
  var STATE_LABELS = {
@@ -2021,7 +2018,8 @@ function CollapsedBar({
2021
2018
  onMicToggle,
2022
2019
  ttsEnabled = true,
2023
2020
  copilotName,
2024
- portraitSrc
2021
+ portraitSrc,
2022
+ lastMessage
2025
2023
  }) {
2026
2024
  const { colors } = useSiteConfig4();
2027
2025
  const isOffline = voiceError === "network_error";
@@ -2119,7 +2117,7 @@ function CollapsedBar({
2119
2117
  )
2120
2118
  }
2121
2119
  )
2122
- ] }) : micPaused ? "Paused" : STATE_LABELS[voiceState]
2120
+ ] }) : (micPaused || voiceState === "IDLE") && lastMessage ? lastMessage.length > 40 ? lastMessage.slice(0, 40).trimEnd() + "..." : lastMessage : micPaused ? "Tap mic to resume" : STATE_LABELS[voiceState]
2123
2121
  }
2124
2122
  )
2125
2123
  ] }),
@@ -2194,6 +2192,7 @@ function ComposerBar({
2194
2192
  micPaused = false,
2195
2193
  onTextSubmit,
2196
2194
  onMicToggle,
2195
+ onCancel,
2197
2196
  disabled = false,
2198
2197
  switchToTextRef,
2199
2198
  feedbackTarget,
@@ -2203,7 +2202,16 @@ function ComposerBar({
2203
2202
  const { colors } = useSiteConfig4();
2204
2203
  const [mode, setMode] = useState5(disabled ? "text" : "voice");
2205
2204
  const [text, setText] = useState5("");
2205
+ const [showCancelHint, setShowCancelHint] = useState5(false);
2206
2206
  const inputRef = useRef4(null);
2207
+ useEffect6(() => {
2208
+ if (voiceState !== "PROCESSING") {
2209
+ setShowCancelHint(false);
2210
+ return;
2211
+ }
2212
+ const timer = setTimeout(() => setShowCancelHint(true), 2e3);
2213
+ return () => clearTimeout(timer);
2214
+ }, [voiceState]);
2207
2215
  useEffect6(() => {
2208
2216
  if (switchToTextRef) switchToTextRef.current = () => setMode("text");
2209
2217
  }, [switchToTextRef]);
@@ -2300,11 +2308,11 @@ function ComposerBar({
2300
2308
  style: {
2301
2309
  fontSize: "14px",
2302
2310
  fontWeight: 400,
2303
- color: micPaused ? "rgba(0,0,0,0.35)" : voiceState === "LISTENING" || voiceState === "USER_SPEAKING" ? colors.primary : "rgba(0,0,0,0.45)"
2311
+ color: micPaused ? "rgba(0,0,0,0.35)" : showCancelHint ? "rgba(0,0,0,0.35)" : voiceState === "LISTENING" || voiceState === "USER_SPEAKING" ? colors.primary : "rgba(0,0,0,0.45)"
2304
2312
  },
2305
- children: micPaused ? "Tap mic to resume" : STATE_LABELS[voiceState]
2313
+ children: micPaused ? "Tap mic to resume" : showCancelHint ? "Tap mic to cancel" : STATE_LABELS[voiceState]
2306
2314
  },
2307
- micPaused ? "paused" : voiceState
2315
+ micPaused ? "paused" : showCancelHint ? "cancel-hint" : voiceState
2308
2316
  ) }) }),
2309
2317
  /* @__PURE__ */ jsxs8(
2310
2318
  motion5.button,
@@ -2312,7 +2320,8 @@ function ComposerBar({
2312
2320
  whileHover: { scale: 1.04 },
2313
2321
  whileTap: { scale: 0.96 },
2314
2322
  onClick: () => {
2315
- if (isListening) onMicToggle();
2323
+ if (voiceState === "PROCESSING" || voiceState === "AI_SPEAKING") onCancel?.();
2324
+ else if (isListening) onMicToggle();
2316
2325
  setMode("text");
2317
2326
  },
2318
2327
  className: "shrink-0 flex items-center gap-1.5 cursor-pointer",
@@ -2545,6 +2554,7 @@ function ExpandedContent({
2545
2554
  onClose,
2546
2555
  onTextSubmit,
2547
2556
  onMicToggle,
2557
+ onCancel,
2548
2558
  micPaused = false,
2549
2559
  onToolDismiss,
2550
2560
  onInteraction,
@@ -2646,7 +2656,7 @@ function ExpandedContent({
2646
2656
  }
2647
2657
  ),
2648
2658
  /* @__PURE__ */ jsxs8("div", { style: { flex: 1, minHeight: 0, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
2649
- /* @__PURE__ */ jsx9("div", { "data-testid": "voice-agent-transcript", style: { flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }, children: /* @__PURE__ */ jsx9(VoiceTranscript, { messages, isTyping, variant: "panel", voiceError, voiceState, onStartMic, onSwitchToKeyboard, onReport, feedbackSentTurns }) }),
2659
+ /* @__PURE__ */ jsx9("div", { "data-testid": "voice-agent-transcript", style: { flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }, children: /* @__PURE__ */ jsx9(VoiceTranscript, { messages, isTyping, variant: "panel", voiceError, voiceState, onStartMic, onSwitchToKeyboard, onReport, feedbackSentTurns, onTextSubmit }) }),
2650
2660
  /* @__PURE__ */ jsxs8("div", { style: { flexShrink: 0 }, children: [
2651
2661
  /* @__PURE__ */ jsx9(PipelineMetricsBar, { timings: lastTimings ?? null, show: showPipelineMetrics, autoHideMs: pipelineMetricsAutoHideMs }),
2652
2662
  isOffline && onRetry && /* @__PURE__ */ jsx9("div", { style: { padding: "0 16px 8px", display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ jsxs8(motion5.button, { whileHover: { scale: 1.04 }, whileTap: { scale: 0.96 }, onClick: onRetry, disabled: isRetrying, className: "inline-flex items-center gap-2 rounded-full cursor-pointer transition-colors", style: { padding: "8px 18px", fontSize: "13px", fontWeight: 500, color: isRetrying ? "rgba(0,0,0,0.35)" : "rgba(220,38,38,0.8)", backgroundColor: isRetrying ? "rgba(0,0,0,0.04)" : "rgba(220,38,38,0.08)", border: "1px solid", borderColor: isRetrying ? "rgba(0,0,0,0.06)" : "rgba(220,38,38,0.15)" }, "aria-label": "Retry connection", children: [
@@ -2657,7 +2667,7 @@ function ExpandedContent({
2657
2667
  /* @__PURE__ */ jsx9("div", { style: { padding: "0 16px 8px" }, children: /* @__PURE__ */ jsx9(VoiceToolCard, { result: toolResult, onDismiss: onToolDismiss, variant: "capsule" }) })
2658
2668
  ] })
2659
2669
  ] }),
2660
- /* @__PURE__ */ jsx9("div", { className: "shrink-0", children: /* @__PURE__ */ jsx9(ComposerBar, { voiceState, isListening, micPaused, onTextSubmit, onMicToggle, disabled: voiceError === "network_error" || voiceError === "stt_failed", switchToTextRef, feedbackTarget, onFeedbackSubmit, onFeedbackCancel }) })
2670
+ /* @__PURE__ */ jsx9("div", { className: "shrink-0", children: /* @__PURE__ */ jsx9(ComposerBar, { voiceState, isListening, micPaused, onTextSubmit, onMicToggle, onCancel, disabled: voiceError === "network_error" || voiceError === "stt_failed", switchToTextRef, feedbackTarget, onFeedbackSubmit, onFeedbackCancel }) })
2661
2671
  ]
2662
2672
  }
2663
2673
  );
@@ -2839,6 +2849,13 @@ function WiredPanelInner({
2839
2849
  const bumpActivity = useCallback3(() => {
2840
2850
  setActivity((c) => c + 1);
2841
2851
  }, []);
2852
+ const handleCancel = useCallback3(() => {
2853
+ if (state === "PROCESSING" || state === "AI_SPEAKING") {
2854
+ stop();
2855
+ return true;
2856
+ }
2857
+ return false;
2858
+ }, [state, stop]);
2842
2859
  const handleMicToggle = useCallback3(() => {
2843
2860
  setMicPaused(false);
2844
2861
  bumpActivity();
@@ -2846,8 +2863,10 @@ function WiredPanelInner({
2846
2863
  stop();
2847
2864
  } else if (state === "IDLE") {
2848
2865
  start();
2866
+ } else if (handleCancel()) {
2867
+ start();
2849
2868
  }
2850
- }, [state, start, stop, bumpActivity]);
2869
+ }, [state, start, stop, bumpActivity, handleCancel]);
2851
2870
  useEffect6(() => {
2852
2871
  if (panelState === "hidden") stopRef.current(true);
2853
2872
  }, [panelState]);
@@ -2910,7 +2929,7 @@ function WiredPanelInner({
2910
2929
  timings: lastTimings ?? void 0,
2911
2930
  route: window.location.pathname,
2912
2931
  copilotName: config.copilotName,
2913
- kitVersion: "5.2.6"
2932
+ kitVersion: "5.3.1"
2914
2933
  })
2915
2934
  });
2916
2935
  const body = await res.json().catch(() => ({ ticketId: void 0 }));
@@ -2971,10 +2990,11 @@ function WiredPanelInner({
2971
2990
  }
2972
2991
  }, [showSettings]);
2973
2992
  if (panelState === "collapsed") {
2974
- return /* @__PURE__ */ jsx9(CollapsedBar, { orbState, getAmplitude, analyser, voiceState: state, onExpand, onClose, onRetry: handleRetryClick, isRetrying, retryCountdown, voiceError: effectiveError, micPaused, onMicToggle: handleMicToggle, ttsEnabled: settings.ttsEnabled, copilotName: config.copilotName, portraitSrc: resolvedPortrait });
2993
+ const lastAssistantMsg = messages.slice().reverse().find((m) => m.role === "assistant")?.text;
2994
+ return /* @__PURE__ */ jsx9(CollapsedBar, { orbState, getAmplitude, analyser, voiceState: state, onExpand, onClose, onRetry: handleRetryClick, isRetrying, retryCountdown, voiceError: effectiveError, micPaused, onMicToggle: handleMicToggle, ttsEnabled: settings.ttsEnabled, copilotName: config.copilotName, portraitSrc: resolvedPortrait, lastMessage: lastAssistantMsg });
2975
2995
  }
2976
2996
  return /* @__PURE__ */ jsxs8("div", { className: "relative h-full", children: [
2977
- /* @__PURE__ */ jsx9(ExpandedContent, { orbState, getAmplitude, analyser, voiceState: state, messages, isTyping, toolResult, voiceError: effectiveError, dismissError, onCollapse, onClose, onTextSubmit: handleTextSubmit, onMicToggle: handleMicToggle, micPaused, onToolDismiss: () => setToolResult(null), onInteraction: bumpActivity, onRetry: handleRetryClick, isRetrying, retryCountdown, lastTimings, showPipelineMetrics: settings.showPipelineMetrics, pipelineMetricsAutoHideMs: settings.pipelineMetricsAutoHideMs, showSettings, onSettingsToggle: toggleSettings, ttsEnabled: settings.ttsEnabled, copilotName: config.copilotName, portraitSrc: resolvedPortrait, onStartMic: handleMicToggle, onSwitchToKeyboard: handleSwitchToKeyboard, switchToTextRef, onReport: handleReport, feedbackSentTurns, feedbackTarget, onFeedbackSubmit: handleFeedbackSubmit, onFeedbackCancel: handleFeedbackCancel }),
2997
+ /* @__PURE__ */ jsx9(ExpandedContent, { orbState, getAmplitude, analyser, voiceState: state, messages, isTyping, toolResult, voiceError: effectiveError, dismissError, onCollapse, onClose, onTextSubmit: handleTextSubmit, onMicToggle: handleMicToggle, onCancel: handleCancel, micPaused, onToolDismiss: () => setToolResult(null), onInteraction: bumpActivity, onRetry: handleRetryClick, isRetrying, retryCountdown, lastTimings, showPipelineMetrics: settings.showPipelineMetrics, pipelineMetricsAutoHideMs: settings.pipelineMetricsAutoHideMs, showSettings, onSettingsToggle: toggleSettings, ttsEnabled: settings.ttsEnabled, copilotName: config.copilotName, portraitSrc: resolvedPortrait, onStartMic: handleMicToggle, onSwitchToKeyboard: handleSwitchToKeyboard, switchToTextRef, onReport: handleReport, feedbackSentTurns, feedbackTarget, onFeedbackSubmit: handleFeedbackSubmit, onFeedbackCancel: handleFeedbackCancel }),
2978
2998
  /* @__PURE__ */ jsx9(AnimatePresence5, { children: showSettings && /* @__PURE__ */ jsx9(Suspense, { fallback: null, children: /* @__PURE__ */ jsx9(VoiceSettingsView2, { onBack: toggleSettings, onVolumeChange: applyVolume }) }) })
2979
2999
  ] });
2980
3000
  }