@unctad-ai/voice-agent-ui 5.2.5 → 5.3.0

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-RZHUDZVZ.js";
8
+ } from "./chunk-SS2HS7NJ.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-6QTJRFZ6.js.map
17
+ //# sourceMappingURL=VoiceSettingsView-JUZMLSHG.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.5" })
1906
+ /* @__PURE__ */ jsx3("span", { style: { fontWeight: 500, color: "#6b7280" }, children: "5.3.0" })
1907
1907
  ] })
1908
1908
  ] }) })
1909
1909
  ]
@@ -1995,4 +1995,4 @@ export {
1995
1995
  SettingsSection,
1996
1996
  Divider
1997
1997
  };
1998
- //# sourceMappingURL=chunk-RZHUDZVZ.js.map
1998
+ //# sourceMappingURL=chunk-SS2HS7NJ.js.map
package/dist/index.d.ts CHANGED
@@ -227,8 +227,12 @@ 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;
232
+ /** Portrait image URL for empty state avatar */
233
+ portraitSrc?: string;
230
234
  }
231
- declare function VoiceTranscript({ messages, isTyping, variant, voiceError, voiceState, onStartMic, onSwitchToKeyboard, onReport, feedbackSentTurns, }: VoiceTranscriptProps): react_jsx_runtime.JSX.Element;
235
+ declare function VoiceTranscript({ messages, isTyping, variant, voiceError, voiceState, onStartMic, onSwitchToKeyboard, onReport, feedbackSentTurns, onTextSubmit, portraitSrc, }: VoiceTranscriptProps): react_jsx_runtime.JSX.Element;
232
236
 
233
237
  interface VoiceWaveformCanvasProps {
234
238
  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-RZHUDZVZ.js";
11
+ } from "./chunk-SS2HS7NJ.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,14 @@ function VoiceTranscript({
917
917
  onStartMic,
918
918
  onSwitchToKeyboard,
919
919
  onReport,
920
- feedbackSentTurns
920
+ feedbackSentTurns,
921
+ onTextSubmit,
922
+ portraitSrc
921
923
  }) {
922
924
  const config = useSiteConfig3();
923
925
  const fontFamily = config.fontFamily ?? DEFAULT_FONT_FAMILY;
924
926
  const assistantLabel = config.copilotName || "Assistant";
927
+ const { colors } = config;
925
928
  const containerRef = useRef3(null);
926
929
  const isPanel = variant === "panel";
927
930
  const maxVisible = isPanel ? PANEL_MAX_VISIBLE_MESSAGES : MAX_VISIBLE_MESSAGES;
@@ -1074,12 +1077,16 @@ function VoiceTranscript({
1074
1077
  "div",
1075
1078
  {
1076
1079
  style: {
1077
- ...isAI ? {} : {
1078
- backgroundColor: "rgba(219,33,41,0.07)",
1079
- border: "1px solid rgba(219,33,41,0.12)",
1080
+ ...isAI ? {
1081
+ backgroundColor: `${colors.primary}0D`,
1082
+ borderRadius: "14px 14px 14px 4px",
1083
+ padding: "10px 14px",
1084
+ maxWidth: "85%"
1085
+ } : {
1086
+ backgroundColor: "rgba(0,0,0,0.04)",
1080
1087
  borderRadius: "14px 14px 4px 14px",
1081
1088
  padding: "10px 14px",
1082
- maxWidth: "88%"
1089
+ maxWidth: "85%"
1083
1090
  }
1084
1091
  },
1085
1092
  children: isAI && isLast && isTyping ? /* @__PURE__ */ jsx4(
@@ -1198,7 +1205,7 @@ function VoiceTranscript({
1198
1205
  )
1199
1206
  ]
1200
1207
  }
1201
- ) : /* @__PURE__ */ jsx4("div", { style: { paddingTop: 40 }, children: /* @__PURE__ */ jsx4(EmptyStateGraphic, { primaryColor: config.colors.primary }) })),
1208
+ ) : /* @__PURE__ */ jsx4("div", { style: { paddingTop: 40 }, children: /* @__PURE__ */ jsx4(EmptyStateGraphic, { primaryColor: config.colors.primary, onTextSubmit, portraitSrc }) })),
1202
1209
  isTyping && visible.length === 0 && /* @__PURE__ */ jsx4(
1203
1210
  motion.p,
1204
1211
  {
@@ -1320,7 +1327,9 @@ function VoiceTranscript({
1320
1327
  primaryColor: config.colors.primary,
1321
1328
  voiceState,
1322
1329
  onStartMic,
1323
- onSwitchToKeyboard
1330
+ onSwitchToKeyboard,
1331
+ onTextSubmit,
1332
+ portraitSrc
1324
1333
  }
1325
1334
  ),
1326
1335
  isTyping && visible.length === 0 && /* @__PURE__ */ jsx4(
@@ -1337,8 +1346,12 @@ function VoiceTranscript({
1337
1346
  }
1338
1347
  );
1339
1348
  }
1340
- function EmptyStateGraphic({ primaryColor, voiceState, onStartMic, onSwitchToKeyboard }) {
1349
+ function EmptyStateGraphic({ primaryColor, voiceState, onStartMic, onSwitchToKeyboard, onTextSubmit, portraitSrc }) {
1350
+ const config = useSiteConfig3();
1341
1351
  const isListening = voiceState === "LISTENING" || voiceState === "USER_SPEAKING";
1352
+ const greeting = config.greetingMessage || "How can I help you today?";
1353
+ const prompts = config.suggestedPrompts ?? ["What services are available?", "Help me with an application"];
1354
+ const sentRef = useRef3(false);
1342
1355
  if (isListening) {
1343
1356
  return /* @__PURE__ */ jsxs3(
1344
1357
  motion.div,
@@ -1355,7 +1368,7 @@ function EmptyStateGraphic({ primaryColor, voiceState, onStartMic, onSwitchToKey
1355
1368
  paddingTop: 60
1356
1369
  },
1357
1370
  children: [
1358
- /* @__PURE__ */ jsx4("p", { style: { fontSize: 16, fontWeight: 500, color: primaryColor, margin: 0, opacity: 0.7 }, children: "Listening..." }),
1371
+ /* @__PURE__ */ jsx4("p", { style: { fontSize: 16, fontWeight: 500, color: primaryColor, margin: 0, opacity: 0.7 }, children: "I'm listening..." }),
1359
1372
  /* @__PURE__ */ jsx4("p", { style: { fontSize: 12, color: "rgba(0,0,0,0.3)", margin: 0 }, children: "Go ahead, I can hear you" })
1360
1373
  ]
1361
1374
  }
@@ -1372,75 +1385,66 @@ function EmptyStateGraphic({ primaryColor, voiceState, onStartMic, onSwitchToKey
1372
1385
  flexDirection: "column",
1373
1386
  alignItems: "center",
1374
1387
  justifyContent: "center",
1375
- gap: 16,
1376
- paddingTop: 60
1388
+ gap: 20,
1389
+ paddingTop: 48
1377
1390
  },
1378
1391
  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
- ] })
1392
+ /* @__PURE__ */ jsx4("p", { style: { fontSize: 17, fontWeight: 500, color: primaryColor, margin: 0, opacity: 0.6, textAlign: "center", lineHeight: 1.4 }, children: greeting }),
1393
+ /* @__PURE__ */ jsx4("div", { style: { display: "flex", flexWrap: "wrap", gap: 8, justifyContent: "center", maxWidth: 320 }, children: prompts.map((prompt) => /* @__PURE__ */ jsx4(
1394
+ "button",
1395
+ {
1396
+ onClick: () => {
1397
+ if (sentRef.current) return;
1398
+ sentRef.current = true;
1399
+ onTextSubmit?.(prompt);
1400
+ },
1401
+ style: {
1402
+ padding: "8px 16px",
1403
+ borderRadius: 18,
1404
+ border: "1px solid rgba(0,0,0,0.1)",
1405
+ backgroundColor: "transparent",
1406
+ cursor: "pointer",
1407
+ fontFamily: "inherit",
1408
+ fontSize: 13,
1409
+ color: "rgba(0,0,0,0.55)",
1410
+ transition: "background-color 0.15s, border-color 0.15s",
1411
+ lineHeight: 1.3
1412
+ },
1413
+ onMouseEnter: (e) => {
1414
+ e.currentTarget.style.backgroundColor = `${primaryColor}0A`;
1415
+ e.currentTarget.style.borderColor = `${primaryColor}33`;
1416
+ },
1417
+ onMouseLeave: (e) => {
1418
+ e.currentTarget.style.backgroundColor = "transparent";
1419
+ e.currentTarget.style.borderColor = "rgba(0,0,0,0.1)";
1420
+ },
1421
+ children: prompt
1422
+ },
1423
+ prompt
1424
+ )) }),
1425
+ /* @__PURE__ */ jsx4("div", { style: { display: "flex", gap: 12, marginTop: 4 }, children: onStartMic && /* @__PURE__ */ jsxs3(
1426
+ "button",
1427
+ {
1428
+ onClick: onStartMic,
1429
+ style: {
1430
+ display: "flex",
1431
+ alignItems: "center",
1432
+ gap: 6,
1433
+ padding: "6px 14px",
1434
+ borderRadius: 16,
1435
+ border: "none",
1436
+ backgroundColor: `${primaryColor}0A`,
1437
+ cursor: "pointer",
1438
+ fontFamily: "inherit",
1439
+ fontSize: 12,
1440
+ color: "rgba(0,0,0,0.4)"
1441
+ },
1442
+ children: [
1443
+ /* @__PURE__ */ jsx4(Mic, { style: { width: 12, height: 12, opacity: 0.5 } }),
1444
+ "or speak"
1445
+ ]
1446
+ }
1447
+ ) })
1444
1448
  ]
1445
1449
  }
1446
1450
  );
@@ -1764,7 +1768,7 @@ function PipelineMetricsBar({
1764
1768
 
1765
1769
  // src/components/GlassCopilotPanel.tsx
1766
1770
  import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1767
- var VoiceSettingsView2 = lazy(() => import("./VoiceSettingsView-6QTJRFZ6.js"));
1771
+ var VoiceSettingsView2 = lazy(() => import("./VoiceSettingsView-JUZMLSHG.js"));
1768
1772
  var RETRY_INITIAL_MS = 3e3;
1769
1773
  var RETRY_MAX_MS = 3e4;
1770
1774
  var STATE_LABELS = {
@@ -2021,7 +2025,8 @@ function CollapsedBar({
2021
2025
  onMicToggle,
2022
2026
  ttsEnabled = true,
2023
2027
  copilotName,
2024
- portraitSrc
2028
+ portraitSrc,
2029
+ lastMessage
2025
2030
  }) {
2026
2031
  const { colors } = useSiteConfig4();
2027
2032
  const isOffline = voiceError === "network_error";
@@ -2119,7 +2124,7 @@ function CollapsedBar({
2119
2124
  )
2120
2125
  }
2121
2126
  )
2122
- ] }) : micPaused ? "Paused" : STATE_LABELS[voiceState]
2127
+ ] }) : (micPaused || voiceState === "IDLE") && lastMessage ? lastMessage.length > 40 ? lastMessage.slice(0, 40).trimEnd() + "..." : lastMessage : micPaused ? "Tap mic to resume" : STATE_LABELS[voiceState]
2123
2128
  }
2124
2129
  )
2125
2130
  ] }),
@@ -2194,6 +2199,7 @@ function ComposerBar({
2194
2199
  micPaused = false,
2195
2200
  onTextSubmit,
2196
2201
  onMicToggle,
2202
+ onCancel,
2197
2203
  disabled = false,
2198
2204
  switchToTextRef,
2199
2205
  feedbackTarget,
@@ -2203,7 +2209,16 @@ function ComposerBar({
2203
2209
  const { colors } = useSiteConfig4();
2204
2210
  const [mode, setMode] = useState5(disabled ? "text" : "voice");
2205
2211
  const [text, setText] = useState5("");
2212
+ const [showCancelHint, setShowCancelHint] = useState5(false);
2206
2213
  const inputRef = useRef4(null);
2214
+ useEffect6(() => {
2215
+ if (voiceState !== "PROCESSING") {
2216
+ setShowCancelHint(false);
2217
+ return;
2218
+ }
2219
+ const timer = setTimeout(() => setShowCancelHint(true), 2e3);
2220
+ return () => clearTimeout(timer);
2221
+ }, [voiceState]);
2207
2222
  useEffect6(() => {
2208
2223
  if (switchToTextRef) switchToTextRef.current = () => setMode("text");
2209
2224
  }, [switchToTextRef]);
@@ -2300,11 +2315,11 @@ function ComposerBar({
2300
2315
  style: {
2301
2316
  fontSize: "14px",
2302
2317
  fontWeight: 400,
2303
- color: micPaused ? "rgba(0,0,0,0.35)" : voiceState === "LISTENING" || voiceState === "USER_SPEAKING" ? colors.primary : "rgba(0,0,0,0.45)"
2318
+ 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
2319
  },
2305
- children: micPaused ? "Tap mic to resume" : STATE_LABELS[voiceState]
2320
+ children: micPaused ? "Tap mic to resume" : showCancelHint ? "Tap mic to cancel" : STATE_LABELS[voiceState]
2306
2321
  },
2307
- micPaused ? "paused" : voiceState
2322
+ micPaused ? "paused" : showCancelHint ? "cancel-hint" : voiceState
2308
2323
  ) }) }),
2309
2324
  /* @__PURE__ */ jsxs8(
2310
2325
  motion5.button,
@@ -2312,7 +2327,8 @@ function ComposerBar({
2312
2327
  whileHover: { scale: 1.04 },
2313
2328
  whileTap: { scale: 0.96 },
2314
2329
  onClick: () => {
2315
- if (isListening) onMicToggle();
2330
+ if (voiceState === "PROCESSING" || voiceState === "AI_SPEAKING") onCancel?.();
2331
+ else if (isListening) onMicToggle();
2316
2332
  setMode("text");
2317
2333
  },
2318
2334
  className: "shrink-0 flex items-center gap-1.5 cursor-pointer",
@@ -2545,6 +2561,7 @@ function ExpandedContent({
2545
2561
  onClose,
2546
2562
  onTextSubmit,
2547
2563
  onMicToggle,
2564
+ onCancel,
2548
2565
  micPaused = false,
2549
2566
  onToolDismiss,
2550
2567
  onInteraction,
@@ -2646,7 +2663,7 @@ function ExpandedContent({
2646
2663
  }
2647
2664
  ),
2648
2665
  /* @__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 }) }),
2666
+ /* @__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, portraitSrc }) }),
2650
2667
  /* @__PURE__ */ jsxs8("div", { style: { flexShrink: 0 }, children: [
2651
2668
  /* @__PURE__ */ jsx9(PipelineMetricsBar, { timings: lastTimings ?? null, show: showPipelineMetrics, autoHideMs: pipelineMetricsAutoHideMs }),
2652
2669
  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 +2674,7 @@ function ExpandedContent({
2657
2674
  /* @__PURE__ */ jsx9("div", { style: { padding: "0 16px 8px" }, children: /* @__PURE__ */ jsx9(VoiceToolCard, { result: toolResult, onDismiss: onToolDismiss, variant: "capsule" }) })
2658
2675
  ] })
2659
2676
  ] }),
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 }) })
2677
+ /* @__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
2678
  ]
2662
2679
  }
2663
2680
  );
@@ -2839,6 +2856,13 @@ function WiredPanelInner({
2839
2856
  const bumpActivity = useCallback3(() => {
2840
2857
  setActivity((c) => c + 1);
2841
2858
  }, []);
2859
+ const handleCancel = useCallback3(() => {
2860
+ if (state === "PROCESSING" || state === "AI_SPEAKING") {
2861
+ stop();
2862
+ return true;
2863
+ }
2864
+ return false;
2865
+ }, [state, stop]);
2842
2866
  const handleMicToggle = useCallback3(() => {
2843
2867
  setMicPaused(false);
2844
2868
  bumpActivity();
@@ -2846,8 +2870,10 @@ function WiredPanelInner({
2846
2870
  stop();
2847
2871
  } else if (state === "IDLE") {
2848
2872
  start();
2873
+ } else if (handleCancel()) {
2874
+ start();
2849
2875
  }
2850
- }, [state, start, stop, bumpActivity]);
2876
+ }, [state, start, stop, bumpActivity, handleCancel]);
2851
2877
  useEffect6(() => {
2852
2878
  if (panelState === "hidden") stopRef.current(true);
2853
2879
  }, [panelState]);
@@ -2910,7 +2936,7 @@ function WiredPanelInner({
2910
2936
  timings: lastTimings ?? void 0,
2911
2937
  route: window.location.pathname,
2912
2938
  copilotName: config.copilotName,
2913
- kitVersion: "5.2.5"
2939
+ kitVersion: "5.3.0"
2914
2940
  })
2915
2941
  });
2916
2942
  const body = await res.json().catch(() => ({ ticketId: void 0 }));
@@ -2971,10 +2997,11 @@ function WiredPanelInner({
2971
2997
  }
2972
2998
  }, [showSettings]);
2973
2999
  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 });
3000
+ const lastAssistantMsg = messages.slice().reverse().find((m) => m.role === "assistant")?.text;
3001
+ 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
3002
  }
2976
3003
  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 }),
3004
+ /* @__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
3005
  /* @__PURE__ */ jsx9(AnimatePresence5, { children: showSettings && /* @__PURE__ */ jsx9(Suspense, { fallback: null, children: /* @__PURE__ */ jsx9(VoiceSettingsView2, { onBack: toggleSettings, onVolumeChange: applyVolume }) }) })
2979
3006
  ] });
2980
3007
  }